]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ia32/64/thread-ia32-64.cpp
Some minor fixes.
[l4.git] / kernel / fiasco / src / kern / ia32 / 64 / thread-ia32-64.cpp
1 //----------------------------------------------------------------------------
2 IMPLEMENTATION [amd64]:
3
4
5 PUBLIC template<typename T> inline
6 void FIASCO_NORETURN
7 Thread::fast_return_to_user(Mword ip, Mword sp, T arg)
8 {
9   assert(cpu_lock.test());
10   assert(current() == this);
11
12   regs()->ip(ip);
13   regs()->sp(sp);
14   regs()->cs(Gdt::gdt_code_user | Gdt::Selector_user);
15   regs()->flags(EFLAGS_IF);
16   asm volatile
17     ("mov %0, %%rsp \t\n"
18      "iretq         \t\n"
19      :
20      : "r" (static_cast<Return_frame*>(regs())), "D"(arg)
21     );
22   __builtin_trap();
23 }
24
25 PROTECTED inline NEEDS[Thread::sys_gdt_x86]
26 L4_msg_tag
27 Thread::invoke_arch(L4_msg_tag tag, Utcb *utcb)
28 {
29   switch (utcb->values[0] & Opcode_mask)
30     {
31     case Op_gdt_x86: return sys_gdt_x86(tag, utcb);
32     case Op_set_segment_base_amd64:
33       if (tag.words() < 2)
34         return commit_result(-L4_err::EInval);
35       switch (utcb->values[0] >> 16)
36         {
37         case 0:
38           _fs = 0;
39           _fs_base = utcb->values[1];
40           if (current() == this)
41             Cpu::wrmsr(_fs_base, MSR_FS_BASE);
42           break;
43
44         case 1:
45           _gs = 0;
46           _gs_base = utcb->values[1];
47           if (current() == this)
48             Cpu::wrmsr(_gs_base, MSR_GS_BASE);
49           break;
50
51         default: return commit_result(-L4_err::EInval);
52         }
53       return Kobject_iface::commit_result(0);
54     default:
55       return commit_result(-L4_err::ENosys);
56     };
57 }
58
59 IMPLEMENT inline
60 Mword
61 Thread::user_sp() const
62 { return exception_triggered()?_exc_cont.sp(regs()):regs()->sp(); }
63
64 IMPLEMENT inline
65 void
66 Thread::user_sp(Mword sp)
67 {
68   if (exception_triggered())
69     _exc_cont.sp(regs(), sp);
70   else
71     regs()->sp(sp);
72 }
73
74 PROTECTED inline
75 int
76 Thread::do_trigger_exception(Entry_frame *r, void *ret_handler)
77 {
78   if (!exception_triggered())
79     {
80       _exc_cont.activate(r, ret_handler);
81       return 1;
82     }
83   // else ignore change of IP because triggered exception already pending
84   return 0;
85 }
86
87 PUBLIC inline
88 void
89 Thread::restore_exc_state()
90 {
91   _exc_cont.restore(regs());
92 }
93
94 PRIVATE static inline
95 Return_frame *
96 Thread::trap_state_to_rf(Trap_state *ts)
97 {
98   char *im = reinterpret_cast<char*>(ts + 1);
99   return reinterpret_cast<Return_frame*>(im)-1;
100 }
101
102 PRIVATE static inline NEEDS[Thread::trap_state_to_rf, Thread::sanitize_user_flags]
103 bool FIASCO_WARN_RESULT
104 Thread::copy_utcb_to_ts(L4_msg_tag const &tag, Thread *snd, Thread *rcv,
105                         L4_fpage::Rights rights)
106 {
107   if (EXPECT_FALSE(tag.words() < Ts::Reg_words))
108     return true;
109
110   Trap_state *ts = (Trap_state*)rcv->_utcb_handler;
111   Unsigned32  cs = ts->cs();
112   Utcb *snd_utcb = snd->utcb().access();
113
114   if (EXPECT_FALSE(rcv->exception_triggered()))
115     {
116       // triggered exception pending
117       Mem::memcpy_mwords(ts, snd_utcb->values, Ts::Reg_words);
118       Continuation::User_return_frame const *urfp
119         = reinterpret_cast<Continuation::User_return_frame const *>
120             ((char*)&snd_utcb->values[Ts::Iret_offset]);
121
122       Continuation::User_return_frame urf = access_once(urfp);
123
124       // sanitize flags
125       urf.flags(sanitize_user_flags(urf.flags()));
126       rcv->_exc_cont.set(trap_state_to_rf(ts), &urf);
127     }
128   else
129     {
130       Mem::memcpy_mwords(ts, snd_utcb->values, Ts::Words);
131       // sanitize flags
132       ts->flags(sanitize_user_flags(ts->flags()));
133       // don't allow to overwrite the code selector!
134       ts->cs(cs & ~0x80);
135     }
136
137   if (tag.transfer_fpu() && (rights & L4_fpage::Rights::W()))
138     snd->transfer_fpu(rcv);
139
140   bool ret = transfer_msg_items(tag, snd, snd_utcb,
141                                 rcv, rcv->utcb().access(), rights);
142
143   rcv->state_del(Thread_in_exception);
144   return ret;
145 }
146
147 PRIVATE static inline NEEDS[Thread::trap_state_to_rf]
148 bool FIASCO_WARN_RESULT
149 Thread::copy_ts_to_utcb(L4_msg_tag const &, Thread *snd, Thread *rcv,
150                         L4_fpage::Rights rights)
151 {
152   Trap_state *ts = (Trap_state*)snd->_utcb_handler;
153   Utcb *rcv_utcb = rcv->utcb().access();
154   {
155     auto guard = lock_guard(cpu_lock);
156     if (EXPECT_FALSE(snd->exception_triggered()))
157       {
158         Mem::memcpy_mwords(rcv_utcb->values, ts, Ts::Reg_words + Ts::Code_words);
159         Continuation::User_return_frame *d
160           = reinterpret_cast<Continuation::User_return_frame *>
161             ((char*)&rcv_utcb->values[Ts::Iret_offset]);
162
163         snd->_exc_cont.get(d, trap_state_to_rf(ts));
164       }
165     else
166       Mem::memcpy_mwords(rcv_utcb->values, ts, Ts::Words);
167
168     if (rcv_utcb->inherit_fpu() && (rights & L4_fpage::Rights::W()))
169       snd->transfer_fpu(rcv);
170 }
171   return true;
172 }
173
174
175 IMPLEMENT
176 void
177 Thread::user_invoke()
178 {
179   user_invoke_generic();
180
181   Mword di = 0;
182
183   if (current()->space()->is_sigma0())
184     di = Kmem::virt_to_phys(Kip::k());
185
186   asm volatile
187     ("  mov %%rax,%%rsp \n"    // set stack pointer to regs structure
188      "  mov %%ecx,%%es   \n"
189      "  mov %%ecx,%%ds   \n"
190      "  xor %%rax,%%rax \n"
191      "  xor %%rcx,%%rcx \n"     // clean out user regs
192      "  xor %%rdx,%%rdx \n"
193      "  xor %%rsi,%%rsi \n"
194      "  xor %%rbx,%%rbx \n"
195      "  xor %%rbp,%%rbp \n"
196      "  xor %%r8,%%r8   \n"
197      "  xor %%r9,%%r9   \n"
198      "  xor %%r10,%%r10 \n"
199      "  xor %%r11,%%r11 \n"
200      "  xor %%r12,%%r12 \n"
201      "  xor %%r13,%%r13 \n"
202      "  xor %%r14,%%r14 \n"
203      "  xor %%r15,%%r15 \n"
204
205      "  iretq           \n"
206      :                          // no output
207      : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
208        "c" (Gdt::gdt_data_user | Gdt::Selector_user),
209        "D" (di)
210      );
211
212   // never returns here
213 }
214
215 PRIVATE inline
216 int
217 Thread::check_trap13_kernel (Trap_state * /*ts*/)
218 { return 1; }
219
220
221 //----------------------------------------------------------------------------
222 IMPLEMENTATION [amd64 & (debug | kdb)]:
223
224 #include "kernel_task.h"
225
226 /** Call the nested trap handler (either Jdb::enter_kdebugger() or the
227  * gdb stub. Setup our own stack frame */
228 PRIVATE static
229 int
230 Thread::call_nested_trap_handler(Trap_state *ts)
231 {
232   Proc::cli();
233
234   Cpu_number log_cpu = dbg_find_cpu();
235   unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
236
237 #if 0
238   printf("%s: lcpu%u sp=%p t=%u nested_trap_recover=%ld\n",
239       __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno,
240       ntr);
241 #endif
242
243   Unsigned64 ret;
244   void *stack = 0;
245   if (!ntr)
246     stack = dbg_stack.cpu(log_cpu).stack_top;
247
248   Unsigned64 dummy1, dummy2, dummy3;
249
250   // don't set %esp if gdb fault recovery to ensure that exceptions inside
251   // kdb/jdb don't overwrite the stack
252   asm volatile
253     ("mov    %%rsp,%[d2]        \n\t"   // save old stack pointer
254      "cmpq   $0,%[recover]      \n\t"
255      "jne    1f                 \n\t"   // check trap within trap handler
256      "mov    %[stack],%%rsp     \n\t"   // setup clean stack pointer
257      "1:                        \n\t"
258      "incq   %[recover]         \n\t"
259      "mov    %%cr3, %[d1]       \n\t"
260      "push   %[d2]              \n\t"   // save old stack pointer on new stack
261      "push   %[d1]              \n\t"   // save old pdbr
262      "mov    %[pdbr], %%cr3     \n\t"
263      "callq  *%[handler]        \n\t"
264      "pop    %[d1]              \n\t"
265      "mov    %[d1], %%cr3       \n\t"
266      "pop    %%rsp              \n\t"   // restore old stack pointer
267      "cmpq   $0,%[recover]      \n\t"   // check trap within trap handler
268      "je     1f                 \n\t"
269      "decq   %[recover]         \n\t"
270      "1:                        \n\t"
271      : [ret] "=a"(ret), [d2] "=&r"(dummy2), [d1] "=&r"(dummy1), "=D"(dummy3),
272        [recover] "+m" (ntr)
273      : [ts] "D" (ts),
274        [pdbr] "r" (Kernel_task::kernel_task()->virt_to_phys((Address)Kmem::dir())),
275        [cpu] "S" (log_cpu),
276        [stack] "r" (stack),
277        [handler] "m" (nested_trap_handler)
278      : "rdx", "rcx", "r8", "r9", "memory");
279
280   if (!ntr)
281     Cpu_call::handle_global_requests();
282
283   return ret == 0 ? 0 : -1;
284 }
285