1 IMPLEMENTATION[ia32 || ux]:
5 Thread::fast_return_to_user(Mword ip, Mword sp)
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);
66 Thread::trap_state_to_rf(Trap_state *ts)
68 char *im = reinterpret_cast<char*>(ts + 1);
69 return reinterpret_cast<Return_frame*>(im)-1;
72 PRIVATE static inline NEEDS[Thread::trap_is_privileged,
73 Thread::trap_state_to_rf]
74 bool FIASCO_WARN_RESULT
75 Thread::copy_utcb_to_ts(L4_msg_tag const &tag, Thread *snd, Thread *rcv,
78 Trap_state *ts = (Trap_state*)rcv->_utcb_handler;
79 Mword s = tag.words();
80 Unsigned32 cs = ts->cs();
81 Utcb *snd_utcb = snd->access_utcb();
83 // XXX: check that gs and fs point to valid user_entry only, for gdt and
85 if (EXPECT_FALSE(rcv->exception_triggered()))
87 // triggered exception pending
88 Mem::memcpy_mwords(&ts->_gs, snd_utcb->values, s > 12 ? 12 : s);
89 if (EXPECT_TRUE(s > 15))
91 Continuation::User_return_frame const *s
92 = reinterpret_cast<Continuation::User_return_frame const *>((char*)&snd_utcb->values[12]);
94 rcv->_exc_cont.set(trap_state_to_rf(ts), s);
98 Mem::memcpy_mwords (&ts->_gs, snd_utcb->values, s > 16 ? 16 : s);
101 rcv->_gs = rcv->_fs = 0;
103 if (tag.transfer_fpu() && (rights & L4_fpage::W))
104 snd->transfer_fpu(rcv);
107 if (!rcv->trap_is_privileged(0))
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->access_utcb(), 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();
126 Trap_state *ts = (Trap_state*)snd->_utcb_handler;
127 Mword r = Utcb::Max_words;
130 Lock_guard <Cpu_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->_fs & 0xffff)))
186 ts->_fs = Utcb_init::utcb_segment();
189 if (EXPECT_FALSE(!(ts->_gs & 0xffff)))
191 ts->_gs = Utcb_init::utcb_segment();
194 if (EXPECT_FALSE(ts->_ds & 0xfff8) == Gdt::gdt_code_user)
196 WARN("%p eip=%08lx: code selector ds=%04lx",
197 this, ts->ip(), ts->_ds & 0xffff);
198 Cpu::set_ds(Gdt::data_segment());
201 if (EXPECT_FALSE(ts->_es & 0xfff8) == Gdt::gdt_code_user)
203 WARN("%p eip=%08lx: code selector es=%04lx",
204 this, ts->ip(), ts->_es & 0xffff);
205 Cpu::set_es(Gdt::data_segment());
208 if (EXPECT_FALSE(ts->_fs & 0xfff8) == Gdt::gdt_code_user)
210 WARN("%p eip=%08lx: code selector fs=%04lx",
211 this, ts->ip(), ts->_fs & 0xffff);
212 ts->_fs = Utcb_init::utcb_segment();
215 if (EXPECT_FALSE(ts->_gs & 0xfff8) == Gdt::gdt_code_user)
217 WARN("%p eip=%08lx: code selector gs=%04lx",
218 this, ts->ip(), ts->_gs & 0xffff);
219 ts->_gs = Utcb_init::utcb_segment();
230 Thread::user_invoke()
232 user_invoke_generic();
235 (" movl %%eax,%%esp \n" // set stack pointer to regs structure
236 " movl %%ecx,%%es \n"
237 " movl %%ecx,%%ds \n"
238 " xorl %%eax,%%eax \n" // clean out user regs
239 " xorl %%ecx,%%ecx \n"
240 " xorl %%edx,%%edx \n"
241 " xorl %%esi,%%esi \n"
242 " xorl %%edi,%%edi \n"
243 " xorl %%ebx,%%ebx \n"
244 " xorl %%ebp,%%ebp \n"
247 : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
248 "c" (Gdt::gdt_data_user | Gdt::Selector_user)
251 // never returns here
254 //---------------------------------------------------------------------------
255 IMPLEMENTATION [ia32]:
258 KIP_KERNEL_FEATURE("segments");
262 Thread::invoke_arch(L4_msg_tag &tag, Utcb *utcb)
264 switch (utcb->values[0] & Opcode_mask)
268 // if no words given then return the first gdt entry
269 if (EXPECT_FALSE(tag.words() == 1))
271 utcb->values[0] = Gdt::gdt_user_entry1 >> 3;
272 tag = commit_result(0, 1);
277 unsigned entry_number = utcb->values[1];
280 for (; entry_number < Gdt_user_entries
282 ; idx += 2, ++entry_number)
284 Gdt_entry *d = (Gdt_entry *)&utcb->values[idx];
286 _gdt_user_entries[entry_number] = *d;
289 if (this == current_thread())
290 switch_gdt_user_entries(this);
292 tag = commit_result(0);
301 //---------------------------------------------------------------------------
302 IMPLEMENTATION [ia32 & (debug | kdb)]:
305 #include "kernel_task.h"
307 /** Call the nested trap handler (either Jdb::enter_kdebugger() or the
308 * gdb stub. Setup our own stack frame */
311 Thread::call_nested_trap_handler(Trap_state *ts)
313 unsigned long phys_cpu = Cpu::phys_id_direct();
314 unsigned log_cpu = Cpu::p2l(phys_cpu);
317 printf("Trap on unknown CPU phys_id=%lx\n", phys_cpu);
321 unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
324 printf("%s: lcpu%u sp=%p t=%lu nested_trap_recover=%ld\n",
325 __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno, ntr);
330 unsigned dummy1, dummy2, dummy3;
335 FIASCO_FASTCALL int (*handler)(Trap_state*, unsigned);
340 p.stack = dbg_stack.cpu(log_cpu).stack_top;
344 p.pdir = Kernel_task::kernel_task()->mem_space()->virt_to_phys((Address)Kmem::dir());
345 p.handler = nested_trap_handler;
348 // don't set %esp if gdb fault recovery to ensure that exceptions inside
349 // kdb/jdb don't overwrite the stack
351 ("mov %%esp,%[d2] \n\t"
352 "cmpl $0,(%[ntr]) \n\t"
354 "mov 8(%[p]),%%esp \n\t"
357 "mov %%cr3, %[d1] \n\t"
361 "mov (%[p]), %[d1] \n\t"
362 "mov %[d1], %%cr3 \n\t"
365 "mov %[d1], %%cr3 \n\t"
368 "cmpl $0,(%[ntr]) \n\t"
383 return ret == 0 ? 0 : -1;