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