]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/thread-ux.cpp
update
[l4.git] / kernel / fiasco / src / kern / ux / thread-ux.cpp
1 INTERFACE [ux]:
2
3 #include <sys/types.h>
4
5 class Trap_state;
6
7 EXTENSION class Thread
8 {
9 private:
10   static int (*int3_handler)(Trap_state*);
11 };
12
13 IMPLEMENTATION [ux]:
14
15 #include <cstdio>
16 #include <csignal>
17 #include "boot_info.h"
18 #include "config.h"             // for page sizes
19 #include "emulation.h"
20 #include "kdb_ke.h"
21 #include "lock_guard.h"
22 #include "panic.h"
23 #include "per_cpu_data.h"
24 #include "utcb_init.h"
25
26 int      (*Thread::int3_handler)(Trap_state*);
27 Per_cpu<Thread::Dbg_stack> DEFINE_PER_CPU Thread::dbg_stack;
28
29
30 IMPLEMENT static inline NEEDS ["emulation.h"]
31 Mword
32 Thread::exception_cs()
33 {
34   return Emulation::kernel_cs();
35 }
36
37 /**
38  * The ux specific part of the thread constructor.
39  */
40 PRIVATE inline
41 void
42 Thread::arch_init()
43 {
44   // Allocate FPU state now because it indirectly calls current()
45   // save_state runs on a signal stack and current() doesn't work there.
46   if (space())
47     // FIXME, space()==0 for sigma0 (or even more)
48     Fpu_alloc::alloc_state(space()->ram_quota(), fpu_state());
49   else
50     Fpu_alloc::alloc_state(Ram_quota::root, fpu_state());
51   
52   // clear out user regs that can be returned from the thread_ex_regs
53   // system call to prevent covert channel
54   Entry_frame *r = regs();
55   r->sp(0);
56   r->ip(0);
57   r->cs(Emulation::kernel_cs() & ~1);                   // force iret trap
58   r->ss(Emulation::kernel_ss());
59
60   if(Config::enable_io_protection)
61     r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);
62   else
63     r->flags(EFLAGS_IOPL_U | EFLAGS_IF | 2);            // XXX iopl=kernel
64 }
65
66 PUBLIC static inline
67 void
68 Thread::set_int3_handler(int (*handler)(Trap_state *ts))
69 {
70   int3_handler = handler;
71 }
72
73 PRIVATE inline bool Thread::check_trap13_kernel (Trap_state *)
74 { return 1; }
75
76 PRIVATE inline void Thread::check_f00f_bug (Trap_state *)
77 {}
78
79 PRIVATE inline 
80 unsigned
81 Thread::check_io_bitmap_delimiter_fault(Trap_state *)
82 { return 1; }
83
84 PRIVATE inline bool Thread::handle_sysenter_trap (Trap_state *, Address, bool)
85 { return true; }
86
87 PRIVATE inline bool Thread::trap_is_privileged (Trap_state *)
88 { return true; }
89
90 PRIVATE inline
91 void
92 Thread::do_wrmsr_in_kernel (Trap_state *)
93 {
94   // do "wrmsr (msr[ecx], edx:eax)" in kernel
95   kdb_ke("wrmsr not supported");
96 }
97
98 PRIVATE inline
99 void
100 Thread::do_rdmsr_in_kernel (Trap_state *)
101 {
102   // do "rdmsr (msr[ecx], edx:eax)" in kernel
103   kdb_ke("rdmsr not supported");
104 }
105
106 PRIVATE inline
107 int
108 Thread::handle_not_nested_trap (Trap_state *)
109 { return -1; }
110
111 PRIVATE
112 int
113 Thread::call_nested_trap_handler (Trap_state *ts)
114 {
115   // run the nested trap handler on a separate stack
116   // equiv of: return nested_trap_handler(ts) == 0 ? true : false;
117
118   //static char nested_handler_stack [Config::PAGE_SIZE];
119   unsigned phys_cpu = Cpu::phys_id_direct();
120   unsigned log_cpu = Cpu::p2l(phys_cpu);
121
122   if (log_cpu == ~0U)
123     {
124       printf("Trap on unknown CPU host-thread=%x\n", phys_cpu);
125       log_cpu = 0;
126     }
127
128   unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
129
130   //printf("%s: lcpu%u sp=%p t=%lu nested_trap_recover=%ld handler=%p\n",
131   //    __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno,
132   //    ntr, nested_trap_handler);
133
134   int ret;
135   void *stack = 0;
136
137   if (!ntr)
138     stack = dbg_stack.cpu(log_cpu).stack_top;
139
140   unsigned dummy1, dummy2, dummy3;
141
142   asm volatile
143     ("movl   %%esp,%[d2]        \n\t"
144      "cmpl   $0, (%[ntrp])      \n\t"
145      "jne    1f                 \n\t"
146      "movl   %[stack],%%esp     \n\t"
147      "1:                        \n\t"
148      "incl   (%[ntrp])          \n\t"
149      "pushl  %[d2]              \n\t"
150      "pushl  %[ntrp]            \n\t"
151      "call   *%[handler]        \n\t"
152      "popl   %[ntrp]            \n\t"
153      "popl   %%esp              \n\t"
154      "cmpl   $0,(%[ntrp])       \n\t"
155      "je     1f                 \n\t"
156      "decl   (%[ntrp])          \n\t"
157      "1:                        \n\t"
158      : [ret] "=a" (ret),
159        [d1]  "=&c" (dummy1),
160        [d2]  "=&r" (dummy2),
161              "=d"  (dummy3)
162      : [ts]      "a"(ts),
163        [cpu]     "d" (log_cpu),
164        [ntrp]    "r" (&ntr),
165        [stack]   "r" (stack),
166        [handler] "m" (nested_trap_handler)
167      : "memory");
168
169   assert (_magic == magic);
170
171   // Do shutdown by switching to idle loop, unless we're already there
172   if (!running && current() != kernel_thread)
173     current()->switch_to_locked (kernel_thread);
174
175   return ret == 0 ? 0 : -1;
176 }
177
178 PUBLIC inline
179 void
180 Thread::spill_fpu()
181 {}
182
183
184 // The "FPU not available" trap entry point
185 extern "C" void thread_handle_fputrap (void) { panic ("fpu trap"); }
186
187 extern "C" void thread_timer_interrupt_stop() {}
188 extern "C" void thread_timer_interrupt_slow() {}
189
190 IMPLEMENT
191 void
192 Thread::user_invoke()
193 {
194     {
195       Mword dummy;
196       asm volatile
197         ("  movl %%ds ,  %0         \n\t"
198          "  movl %0,     %%es   \n\t"
199          : "=r"(dummy));
200     }
201
202   Cpu::set_gs(Utcb_init::gs_value());
203
204   user_invoke_generic();
205
206   asm volatile
207     ("  movl %%eax , %%esp      \n\t"
208      "  xorl %%ebx , %%ebx      \n\t"
209      "  xorl %%edx , %%edx      \n\t"
210      "  xorl %%esi , %%esi      \n\t"     // clean out user regs
211      "  xorl %%edi , %%edi      \n\t"
212      "  xorl %%ebp , %%ebp      \n\t"
213      "  xorl %%eax , %%eax      \n\t"
214      "  iret                    \n\t"
215      : // no output
216      : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
217        "c" (current()->space() == sigma0_task // only Sigma0 gets the KIP
218             ? Kmem::virt_to_phys(Kip::k()) : 0));
219 }
220
221 PROTECTED inline
222 int
223 Thread::sys_control_arch(Utcb *utcb)
224 {
225   if (utcb->values[0] & Ctl_ux_native)
226     _is_native = utcb->values[4] & Ctl_ux_native;
227   return 0;
228 }
229
230 //---------------------------------------------------------------------------
231 IMPLEMENTATION [ux]:
232
233 #include "gdt.h"
234 #include <feature.h>
235
236 KIP_KERNEL_FEATURE("segments");
237
238 PROTECTED inline
239 bool
240 Thread::invoke_arch(L4_msg_tag &tag, Utcb *utcb)
241 {
242 #ifndef GDT_ENTRY_TLS_MIN
243 #define GDT_ENTRY_TLS_MIN 6
244 #endif
245   switch (utcb->values[0] & Opcode_mask)
246     {
247       case Op_gdt_x86: // Gdt operation
248
249       // if no words given then return the first gdt entry
250       if (tag.words() == 1)
251         {
252           utcb->values[0] = GDT_ENTRY_TLS_MIN;
253           tag = commit_result(0, 1);
254           return true;
255         }
256
257         {
258           unsigned entry_number = utcb->values[1];
259           unsigned idx = 2;
260           Mword  *trampoline_page = (Mword *) Kmem::phys_to_virt
261                                               (Mem_layout::Trampoline_frame);
262
263
264           for (; entry_number < Gdt_user_entries
265                  && idx < tag.words()
266                ; idx += 2, ++entry_number)
267             {
268               Gdt_entry *d = (Gdt_entry *)&utcb->values[idx];
269               if (!d->limit())
270                 continue;
271
272               Ldt_user_desc info;
273               info.entry_number    =  entry_number + GDT_ENTRY_TLS_MIN;
274               info.base_addr       =  d->base();
275               info.limit           =  d->limit();
276               info.seg_32bit       =  d->seg32();
277               info.contents        =  d->contents();
278               info.read_exec_only  = !d->writable();
279               info.limit_in_pages  =  d->granularity();
280               info.seg_not_present = !d->present();
281               info.useable         =  d->avl();
282
283               // Remember descriptor for reload on thread switch
284               memcpy(&_gdt_user_entries[entry_number], &info,
285                      sizeof(_gdt_user_entries[0]));
286
287               // Set up data on trampoline
288               memcpy(trampoline_page + 1, &info, sizeof(info));
289
290               // Call set_thread_area for given user process
291               Trampoline::syscall(space()->pid(), 243 /* __NR_set_thread_area */,
292                                   Mem_layout::Trampoline_page + sizeof(Mword));
293
294               // Also set this for the fiasco kernel so that
295               // segment registers can be set, this is necessary for signal
296               // handling, esp. for sigreturn to work in the Fiasco kernel
297               // with the context of the client (gs/fs values).
298               Emulation::thread_area_host(entry_number + GDT_ENTRY_TLS_MIN);
299
300             }
301
302           if (this == current_thread())
303             switch_gdt_user_entries(this);
304
305           tag = commit_result(0);
306           return true;
307         }
308
309     default:
310       return false;
311     };
312 }