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