1 IMPLEMENTATION[ia32 || ux]:
3 PUBLIC template<typename T> inline
5 Thread::fast_return_to_user(Mword ip, Mword sp, T arg)
7 assert_kdb(cpu_lock.test());
8 assert_kdb(current() == this);
9 assert_kdb(Config::Is_ux || (regs()->cs() & 3 == 3));
13 regs()->flags(EFLAGS_IF);
18 : "r" (static_cast<Return_frame*>(regs())), "a" (arg)
25 Thread::user_sp() const
26 { return regs()->sp(); }
30 Thread::user_sp(Mword sp)
35 Thread::do_trigger_exception(Entry_frame *r, void *ret_handler)
37 if (!exception_triggered())
39 _exc_cont.activate(r, ret_handler);
42 // else ignore change of IP because triggered exception already pending
49 Thread::restore_exc_state()
51 assert (cpu_lock.test());
52 _exc_cont.restore(regs());
56 r->cs (exception_cs() & ~1);
58 r->cs (exception_cs());
61 r->flags (_exc_flags);
68 Thread::trap_state_to_rf(Trap_state *ts)
70 char *im = reinterpret_cast<char*>(ts + 1);
71 return reinterpret_cast<Return_frame*>(im)-1;
74 PRIVATE static inline NEEDS[Thread::trap_state_to_rf]
75 bool FIASCO_WARN_RESULT
76 Thread::copy_utcb_to_ts(L4_msg_tag const &tag, Thread *snd, Thread *rcv,
79 Trap_state *ts = (Trap_state*)rcv->_utcb_handler;
80 Mword s = tag.words();
81 Unsigned32 cs = ts->cs();
82 Utcb *snd_utcb = snd->utcb().access();
84 // XXX: check that gs and fs point to valid user_entry only, for gdt and
86 if (EXPECT_FALSE(rcv->exception_triggered()))
88 // triggered exception pending
89 Mem::memcpy_mwords(&ts->_gs, snd_utcb->values, s > 12 ? 12 : s);
90 if (EXPECT_TRUE(s > 15))
92 Continuation::User_return_frame const *s
93 = reinterpret_cast<Continuation::User_return_frame const *>((char*)&snd_utcb->values[12]);
95 rcv->_exc_cont.set(trap_state_to_rf(ts), s);
99 Mem::memcpy_mwords (&ts->_gs, snd_utcb->values, s > 16 ? 16 : s);
102 rcv->_gs = rcv->_fs = 0;
104 if (tag.transfer_fpu() && (rights & L4_fpage::W))
105 snd->transfer_fpu(rcv);
108 ts->flags((ts->flags() & ~(EFLAGS_IOPL | EFLAGS_NT)) | EFLAGS_IF);
110 // don't allow to overwrite the code selector!
113 bool ret = transfer_msg_items(tag, snd, snd_utcb,
114 rcv, rcv->utcb().access(), rights);
116 rcv->state_del(Thread_in_exception);
120 PRIVATE static inline
121 bool FIASCO_WARN_RESULT
122 Thread::copy_ts_to_utcb(L4_msg_tag const &, Thread *snd, Thread *rcv,
123 unsigned char rights)
125 Utcb *rcv_utcb = rcv->utcb().access();
126 Trap_state *ts = (Trap_state*)snd->_utcb_handler;
127 Mword r = Utcb::Max_words;
130 auto guard = lock_guard(cpu_lock);
131 if (EXPECT_FALSE(snd->exception_triggered()))
133 Mem::memcpy_mwords (rcv_utcb->values, &ts->_gs, r > 12 ? 12 : r);
134 Continuation::User_return_frame *d
135 = reinterpret_cast<Continuation::User_return_frame *>((char*)&rcv_utcb->values[12]);
137 snd->_exc_cont.get(d, trap_state_to_rf(ts));
140 Mem::memcpy_mwords (rcv_utcb->values, &ts->_gs, r > 16 ? 16 : r);
142 if (rcv_utcb->inherit_fpu() && (rights & L4_fpage::W))
143 snd->transfer_fpu(rcv);
149 //----------------------------------------------------------------------------
150 IMPLEMENTATION [ia32 && !ux]:
152 IMPLEMENT inline NEEDS[Thread::exception_triggered]
154 Thread::user_ip(Mword ip)
156 if (exception_triggered())
165 Thread::check_trap13_kernel(Trap_state *ts)
167 if (EXPECT_FALSE(ts->_trapno == 13 && (ts->_err & 3) == 0))
169 // First check if user loaded a segment register with 0 because the
170 // resulting exception #13 can be raised from user _and_ kernel. If
171 // the user tried to load another segment selector, the thread gets
173 // XXX Should we emulate this too? Michael Hohmuth: Yes, we should.
174 if (EXPECT_FALSE(!(ts->_ds & 0xffff)))
176 Cpu::set_ds(Gdt::data_segment());
179 if (EXPECT_FALSE(!(ts->_es & 0xffff)))
181 Cpu::set_es(Gdt::data_segment());
184 if (EXPECT_FALSE(ts->_ds & 0xfff8) == Gdt::gdt_code_user)
186 WARN("%p eip=%08lx: code selector ds=%04lx",
187 this, ts->ip(), ts->_ds & 0xffff);
188 Cpu::set_ds(Gdt::data_segment());
191 if (EXPECT_FALSE(ts->_es & 0xfff8) == Gdt::gdt_code_user)
193 WARN("%p eip=%08lx: code selector es=%04lx",
194 this, ts->ip(), ts->_es & 0xffff);
195 Cpu::set_es(Gdt::data_segment());
198 if (EXPECT_FALSE(ts->_fs & 0xfff8) == Gdt::gdt_code_user)
200 WARN("%p eip=%08lx: code selector fs=%04lx",
201 this, ts->ip(), ts->_fs & 0xffff);
205 if (EXPECT_FALSE(ts->_gs & 0xfff8) == Gdt::gdt_code_user)
207 WARN("%p eip=%08lx: code selector gs=%04lx",
208 this, ts->ip(), ts->_gs & 0xffff);
220 Thread::user_invoke()
222 user_invoke_generic();
225 (" movl %%eax,%%esp \n" // set stack pointer to regs structure
226 " movl %%ecx,%%es \n"
227 " movl %%ecx,%%ds \n"
228 " xorl %%eax,%%eax \n" // clean out user regs
229 " xorl %%ecx,%%ecx \n"
230 " xorl %%edx,%%edx \n"
231 " xorl %%esi,%%esi \n"
232 " xorl %%edi,%%edi \n"
233 " xorl %%ebx,%%ebx \n"
234 " xorl %%ebp,%%ebp \n"
237 : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
238 "c" (Gdt::gdt_data_user | Gdt::Selector_user)
241 // never returns here
244 //---------------------------------------------------------------------------
245 IMPLEMENTATION [ia32]:
248 KIP_KERNEL_FEATURE("segments");
252 Thread::invoke_arch(L4_msg_tag tag, Utcb *utcb)
254 switch (utcb->values[0] & Opcode_mask)
258 // if no words given then return the first gdt entry
259 if (EXPECT_FALSE(tag.words() == 1))
261 utcb->values[0] = Gdt::gdt_user_entry1 >> 3;
262 return Kobject_iface::commit_result(0, 1);
266 unsigned entry_number = utcb->values[1];
269 for (; entry_number < Gdt_user_entries
271 ; idx += 2, ++entry_number)
273 Gdt_entry *d = (Gdt_entry *)&utcb->values[idx];
275 _gdt_user_entries[entry_number] = *d;
278 if (this == current_thread())
279 switch_gdt_user_entries(this);
281 return Kobject_iface::commit_result((utcb->values[1] << 3) + Gdt::gdt_user_entry1 + 3);
285 return commit_result(-L4_err::ENosys);
289 //---------------------------------------------------------------------------
290 IMPLEMENTATION [ia32 & (debug | kdb)]:
292 #include "kernel_task.h"
294 /** Call the nested trap handler (either Jdb::enter_kdebugger() or the
295 * gdb stub. Setup our own stack frame */
298 Thread::call_nested_trap_handler(Trap_state *ts)
300 unsigned log_cpu = dbg_find_cpu();
301 unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
304 printf("%s: lcpu%u sp=%p t=%lu nested_trap_recover=%ld\n",
305 __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno, ntr);
310 unsigned dummy1, dummy2, dummy3;
315 FIASCO_FASTCALL int (*handler)(Trap_state*, unsigned);
320 p.stack = dbg_stack.cpu(log_cpu).stack_top;
324 p.pdir = Kernel_task::kernel_task()->virt_to_phys((Address)Kmem::dir());
325 p.handler = nested_trap_handler;
328 // don't set %esp if gdb fault recovery to ensure that exceptions inside
329 // kdb/jdb don't overwrite the stack
331 ("mov %%esp,%[d2] \n\t"
332 "cmpl $0,(%[ntr]) \n\t"
334 "mov 8(%[p]),%%esp \n\t"
337 "mov %%cr3, %[d1] \n\t"
341 "mov (%[p]), %[d1] \n\t"
342 "mov %[d1], %%cr3 \n\t"
345 "mov %[d1], %%cr3 \n\t"
348 "cmpl $0,(%[ntr]) \n\t"
363 return ret == 0 ? 0 : -1;