1 IMPLEMENTATION[ia32 || ux]:
5 Thread::fast_return_to_user(Mword ip, Mword sp, bool = true)
7 assert_kdb(cpu_lock.test());
8 assert_kdb(current() == this);
16 : "r" (static_cast<Return_frame*>(regs()))
23 Thread::user_sp() const
24 { return regs()->sp(); }
28 Thread::user_sp(Mword sp)
33 Thread::do_trigger_exception(Entry_frame *r, void *ret_handler)
35 if (!exception_triggered())
37 _exc_cont.activate(r, ret_handler);
40 // else ignore change of IP because triggered exception already pending
47 Thread::restore_exc_state()
49 assert (cpu_lock.test());
50 _exc_cont.restore(regs());
54 r->cs (exception_cs() & ~1);
56 r->cs (exception_cs());
59 r->flags (_exc_flags);
64 IMPLEMENTATION[(ia32 || ux) && segments]:
68 Thread::copy_utcb_to_ts_reset_segments(Thread *rcv)
69 { rcv->_gs = rcv->_fs = 0; }
71 IMPLEMENTATION[(ia32 || ux) && !segments]:
75 Thread::copy_utcb_to_ts_reset_segments(Thread *)
78 IMPLEMENTATION[ia32 || ux]:
82 Thread::trap_state_to_rf(Trap_state *ts)
84 char *im = reinterpret_cast<char*>(ts + 1);
85 return reinterpret_cast<Return_frame*>(im)-1;
88 PRIVATE static inline NEEDS[Thread::copy_utcb_to_ts_reset_segments,
89 Thread::trap_is_privileged,
90 Thread::trap_state_to_rf]
91 bool FIASCO_WARN_RESULT
92 Thread::copy_utcb_to_ts(L4_msg_tag const &tag, Thread *snd, Thread *rcv,
95 Trap_state *ts = (Trap_state*)rcv->_utcb_handler;
96 Mword s = tag.words();
97 Unsigned32 cs = ts->cs();
98 Utcb *snd_utcb = snd->access_utcb();
100 // XXX: check that gs and fs point to valid user_entry only, for gdt and
102 if (EXPECT_FALSE(rcv->exception_triggered()))
104 // triggered exception pending
105 Mem::memcpy_mwords(&ts->_gs, snd_utcb->values, s > 12 ? 12 : s);
106 if (EXPECT_TRUE(s > 15))
108 Continuation::User_return_frame const *s
109 = reinterpret_cast<Continuation::User_return_frame const *>((char*)&snd_utcb->values[12]);
111 rcv->_exc_cont.set(trap_state_to_rf(ts), s);
115 Mem::memcpy_mwords (&ts->_gs, snd_utcb->values, s > 16 ? 16 : s);
117 copy_utcb_to_ts_reset_segments(rcv);
119 if (tag.transfer_fpu() && (rights & L4_fpage::W))
120 snd->transfer_fpu(rcv);
123 if (!rcv->trap_is_privileged(0))
124 ts->flags((ts->flags() & ~(EFLAGS_IOPL | EFLAGS_NT)) | EFLAGS_IF);
126 // don't allow to overwrite the code selector!
129 bool ret = transfer_msg_items(tag, snd, snd_utcb,
130 rcv, rcv->access_utcb(), rights);
132 rcv->state_del(Thread_in_exception);
136 PRIVATE static inline
137 bool FIASCO_WARN_RESULT
138 Thread::copy_ts_to_utcb(L4_msg_tag const &, Thread *snd, Thread *rcv,
139 unsigned char rights)
141 Utcb *rcv_utcb = rcv->utcb();
142 Trap_state *ts = (Trap_state*)snd->_utcb_handler;
143 Mword r = Utcb::Max_words;
146 Lock_guard <Cpu_lock> guard (&cpu_lock);
147 if (EXPECT_FALSE(snd->exception_triggered()))
149 Mem::memcpy_mwords (rcv_utcb->values, &ts->_gs, r > 12 ? 12 : r);
150 Continuation::User_return_frame *d
151 = reinterpret_cast<Continuation::User_return_frame *>((char*)&rcv_utcb->values[12]);
153 snd->_exc_cont.get(d, trap_state_to_rf(ts));
156 Mem::memcpy_mwords (rcv_utcb->values, &ts->_gs, r > 16 ? 16 : r);
158 if (rcv_utcb->inherit_fpu() && (rights & L4_fpage::W))
159 snd->transfer_fpu(rcv);
165 //----------------------------------------------------------------------------
166 IMPLEMENTATION [ia32 && !ux]:
168 IMPLEMENT inline NEEDS[Thread::exception_triggered]
170 Thread::user_ip(Mword ip)
172 if (exception_triggered())
181 Thread::check_trap13_kernel(Trap_state *ts)
183 if (EXPECT_FALSE(ts->_trapno == 13 && (ts->_err & 3) == 0))
185 // First check if user loaded a segment register with 0 because the
186 // resulting exception #13 can be raised from user _and_ kernel. If
187 // the user tried to load another segment selector, the thread gets
189 // XXX Should we emulate this too? Michael Hohmuth: Yes, we should.
190 if (EXPECT_FALSE(!(ts->_ds & 0xffff)))
192 Cpu::set_ds(Gdt::data_segment());
195 if (EXPECT_FALSE(!(ts->_es & 0xffff)))
197 Cpu::set_es(Gdt::data_segment());
200 if (EXPECT_FALSE(!(ts->_fs & 0xffff)))
202 ts->_fs = Utcb_init::utcb_segment();
205 if (EXPECT_FALSE(!(ts->_gs & 0xffff)))
207 ts->_gs = Utcb_init::utcb_segment();
210 if (EXPECT_FALSE(ts->_ds & 0xfff8) == Gdt::gdt_code_user)
212 WARN("%p eip=%08lx: code selector ds=%04lx",
213 this, ts->ip(), ts->_ds & 0xffff);
214 Cpu::set_ds(Gdt::data_segment());
217 if (EXPECT_FALSE(ts->_es & 0xfff8) == Gdt::gdt_code_user)
219 WARN("%p eip=%08lx: code selector es=%04lx",
220 this, ts->ip(), ts->_es & 0xffff);
221 Cpu::set_es(Gdt::data_segment());
224 if (EXPECT_FALSE(ts->_fs & 0xfff8) == Gdt::gdt_code_user)
226 WARN("%p eip=%08lx: code selector fs=%04lx",
227 this, ts->ip(), ts->_fs & 0xffff);
228 ts->_fs = Utcb_init::utcb_segment();
231 if (EXPECT_FALSE(ts->_gs & 0xfff8) == Gdt::gdt_code_user)
233 WARN("%p eip=%08lx: code selector gs=%04lx",
234 this, ts->ip(), ts->_gs & 0xffff);
235 ts->_gs = Utcb_init::utcb_segment();
246 Thread::user_invoke()
248 user_invoke_generic();
251 (" movl %%eax,%%esp \n" // set stack pointer to regs structure
252 " movl %%ecx,%%es \n"
253 " movl %%ecx,%%ds \n"
254 " xorl %%eax,%%eax \n" // clean out user regs
255 " xorl %%ecx,%%ecx \n"
256 " xorl %%edx,%%edx \n"
257 " xorl %%esi,%%esi \n"
258 " xorl %%edi,%%edi \n"
259 " xorl %%ebx,%%ebx \n"
260 " xorl %%ebp,%%ebp \n"
263 : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
264 "c" (Gdt::gdt_data_user | Gdt::Selector_user)
267 // never returns here
270 //---------------------------------------------------------------------------
271 IMPLEMENTATION [ia32 & segments]:
274 KIP_KERNEL_FEATURE("segments");
278 Thread::invoke_arch(L4_msg_tag &tag, Utcb *utcb)
280 switch (utcb->values[0] & Opcode_mask)
284 // if no words given then return the first gdt entry
285 if (EXPECT_FALSE(tag.words() == 1))
287 utcb->values[0] = Gdt::gdt_user_entry1 >> 3;
288 tag = commit_result(0, 1);
293 unsigned entry_number = utcb->values[1];
296 for (; entry_number < Gdt_user_entries
298 ; idx += 2, ++entry_number)
300 Gdt_entry *d = (Gdt_entry *)&utcb->values[idx];
302 _gdt_user_entries[entry_number] = *d;
305 if (this == current_thread())
306 switch_gdt_user_entries(this);
308 tag = commit_result(0);
317 //---------------------------------------------------------------------------
318 IMPLEMENTATION [ia32 && !segments]:
322 Thread::invoke_arch(L4_msg_tag &tag, Utcb *utcb)
324 (void)tag; (void)utcb;
325 return false; // not our business
328 //---------------------------------------------------------------------------
329 IMPLEMENTATION [ia32 & (debug | kdb)]:
332 #include "kernel_task.h"
334 /** Call the nested trap handler (either Jdb::enter_kdebugger() or the
335 * gdb stub. Setup our own stack frame */
338 Thread::call_nested_trap_handler(Trap_state *ts)
340 unsigned long phys_cpu = Cpu::phys_id_direct();
341 unsigned log_cpu = Cpu::p2l(phys_cpu);
344 printf("Trap on unknown CPU phys_id=%lx\n", phys_cpu);
348 unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
351 printf("%s: lcpu%u sp=%p t=%u nested_trap_recover=%ld\n",
352 __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno,
358 unsigned dummy1, dummy2, dummy3;
363 int (*handler)(Trap_state*, unsigned int);
368 p.stack = dbg_stack.cpu(log_cpu).stack_top;
372 p.pdir = Kernel_task::kernel_task()->mem_space()->virt_to_phys((Address)Kmem::dir());
373 p.handler = nested_trap_handler;
376 // don't set %esp if gdb fault recovery to ensure that exceptions inside
377 // kdb/jdb don't overwrite the stack
379 ("mov %%esp,%[d2] \n\t"
380 "cmpl $0,(%[ntr]) \n\t"
382 "mov 8(%[p]),%%esp \n\t"
385 "mov %%cr3, %[d1] \n\t"
389 "mov (%[p]), %[d1] \n\t"
390 "mov %[d1], %%cr3 \n\t"
393 "mov %[d1], %%cr3 \n\t"
396 "cmpl $0,(%[ntr]) \n\t"
411 return ret == 0 ? 0 : -1;