]> rtime.felk.cvut.cz Git - l4.git/blob - kernel/fiasco/src/kern/ux/thread-ux.cpp
05a7b15415961f09ab51efe0580ee389c660717c
[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 DEFINE_PER_CPU Per_cpu<Thread::Dbg_stack> 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   r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);
60 }
61
62 PUBLIC static inline
63 void
64 Thread::set_int3_handler(int (*handler)(Trap_state *ts))
65 {
66   int3_handler = handler;
67 }
68
69 PRIVATE inline bool Thread::check_trap13_kernel(Trap_state *)
70 { return 1; }
71
72 PRIVATE inline void Thread::check_f00f_bug(Trap_state *)
73 {}
74
75 PRIVATE inline 
76 unsigned
77 Thread::check_io_bitmap_delimiter_fault(Trap_state *)
78 { return 1; }
79
80 PRIVATE inline bool Thread::handle_sysenter_trap(Trap_state *, Address, bool)
81 { return true; }
82
83 PRIVATE inline
84 int
85 Thread::handle_not_nested_trap(Trap_state *)
86 { return -1; }
87
88 PRIVATE
89 int
90 Thread::call_nested_trap_handler(Trap_state *ts)
91 {
92   // run the nested trap handler on a separate stack
93   // equiv of: return nested_trap_handler(ts) == 0 ? true : false;
94
95   //static char nested_handler_stack [Config::PAGE_SIZE];
96   unsigned phys_cpu = Cpu::phys_id_direct();
97   unsigned log_cpu = Cpu::cpus.find_cpu(Cpu::By_phys_id(phys_cpu));
98
99   if (log_cpu == ~0U)
100     {
101       printf("Trap on unknown CPU host-thread=%x\n", phys_cpu);
102       log_cpu = 0;
103     }
104
105   unsigned long &ntr = nested_trap_recover.cpu(log_cpu);
106
107   //printf("%s: lcpu%u sp=%p t=%lu nested_trap_recover=%ld handler=%p\n",
108   //    __func__, log_cpu, (void*)Proc::stack_pointer(), ts->_trapno,
109   //    ntr, nested_trap_handler);
110
111   int ret;
112   void *stack = 0;
113
114   if (!ntr)
115     stack = dbg_stack.cpu(log_cpu).stack_top;
116
117   unsigned dummy1, dummy2, dummy3;
118
119   asm volatile
120     ("movl   %%esp,%[d2]        \n\t"
121      "cmpl   $0, (%[ntrp])      \n\t"
122      "jne    1f                 \n\t"
123      "movl   %[stack],%%esp     \n\t"
124      "1:                        \n\t"
125      "incl   (%[ntrp])          \n\t"
126      "pushl  %[d2]              \n\t"
127      "pushl  %[ntrp]            \n\t"
128      "call   *%[handler]        \n\t"
129      "popl   %[ntrp]            \n\t"
130      "popl   %%esp              \n\t"
131      "cmpl   $0,(%[ntrp])       \n\t"
132      "je     1f                 \n\t"
133      "decl   (%[ntrp])          \n\t"
134      "1:                        \n\t"
135      : [ret] "=a" (ret),
136        [d1]  "=&c" (dummy1),
137        [d2]  "=&r" (dummy2),
138              "=d"  (dummy3)
139      : [ts]      "a"(ts),
140        [cpu]     "d" (log_cpu),
141        [ntrp]    "r" (&ntr),
142        [stack]   "r" (stack),
143        [handler] "m" (nested_trap_handler)
144      : "memory");
145
146   assert (_magic == magic);
147
148   return ret == 0 ? 0 : -1;
149 }
150
151 // The "FPU not available" trap entry point
152 extern "C" void thread_handle_fputrap (void) { panic ("fpu trap"); }
153
154 extern "C" void thread_timer_interrupt_slow() {}
155
156 IMPLEMENT
157 void
158 Thread::user_invoke()
159 {
160     {
161       Mword dummy;
162       asm volatile
163         ("  movl %%ds ,  %0         \n\t"
164          "  movl %0,     %%es   \n\t"
165          : "=r"(dummy));
166     }
167
168   Cpu::set_gs(Utcb_init::utcb_segment());
169   Cpu::set_fs(Utcb_init::utcb_segment());
170
171   user_invoke_generic();
172
173   asm volatile
174     ("  movl %%eax , %%esp      \n\t"
175      "  xorl %%ebx , %%ebx      \n\t"
176      "  xorl %%edx , %%edx      \n\t"
177      "  xorl %%esi , %%esi      \n\t"     // clean out user regs
178      "  xorl %%edi , %%edi      \n\t"
179      "  xorl %%ebp , %%ebp      \n\t"
180      "  xorl %%eax , %%eax      \n\t"
181      "  iret                    \n\t"
182      : // no output
183      : "a" (nonull_static_cast<Return_frame*>(current()->regs())),
184        "c" (current()->space()->is_sigma0() // only Sigma0 gets the KIP
185             ? Kmem::virt_to_phys(Kip::k()) : 0));
186 }
187
188 PROTECTED inline
189 int
190 Thread::sys_control_arch(Utcb *utcb)
191 {
192   if (utcb->values[0] & Ctl_ux_native)
193     _is_native = utcb->values[4] & Ctl_ux_native;
194   return 0;
195 }
196
197 //---------------------------------------------------------------------------
198 IMPLEMENTATION [ux]:
199
200 #include "gdt.h"
201 #include <feature.h>
202
203 KIP_KERNEL_FEATURE("segments");
204
205 PROTECTED inline
206 L4_msg_tag
207 Thread::invoke_arch(L4_msg_tag tag, Utcb *utcb)
208 {
209   switch (utcb->values[0] & Opcode_mask)
210     {
211       case Op_gdt_x86: // Gdt operation
212
213       // if no words given then return the first gdt entry
214       if (tag.words() == 1)
215         {
216           utcb->values[0] = Emulation::host_tls_base();
217           return commit_result(0, 1);
218         }
219
220         {
221           unsigned entry_number = utcb->values[1];
222           unsigned idx = 2;
223           Mword  *trampoline_page = (Mword *) Kmem::phys_to_virt
224                                               (Mem_layout::Trampoline_frame);
225
226
227           for (; entry_number < Gdt_user_entries
228                  && idx < tag.words()
229                ; idx += 2, ++entry_number)
230             {
231               Gdt_entry *d = (Gdt_entry *)&utcb->values[idx];
232               if (!d->limit())
233                 continue;
234
235               Ldt_user_desc info;
236               info.entry_number    =  entry_number + Emulation::host_tls_base();
237               info.base_addr       =  d->base();
238               info.limit           =  d->limit();
239               info.seg_32bit       =  d->seg32();
240               info.contents        =  d->contents();
241               info.read_exec_only  = !d->writable();
242               info.limit_in_pages  =  d->granularity();
243               info.seg_not_present = !d->present();
244               info.useable         =  d->avl();
245
246               // Remember descriptor for reload on thread switch
247               memcpy(&_gdt_user_entries[entry_number], &info,
248                      sizeof(_gdt_user_entries[0]));
249
250               // Set up data on trampoline
251               memcpy(trampoline_page + 1, &info, sizeof(info));
252
253               // Call set_thread_area for given user process
254               Trampoline::syscall(space()->pid(), 243 /* __NR_set_thread_area */,
255                                   Mem_layout::Trampoline_page + sizeof(Mword));
256
257               // Also set this for the fiasco kernel so that
258               // segment registers can be set, this is necessary for signal
259               // handling, esp. for sigreturn to work in the Fiasco kernel
260               // with the context of the client (gs/fs values).
261               Emulation::thread_area_host(entry_number + Emulation::host_tls_base());
262             }
263
264           if (this == current_thread())
265             switch_gdt_user_entries(this);
266
267           return commit_result(((utcb->values[1] + Emulation::host_tls_base()) << 3) + 3);
268         }
269
270     default:
271       return commit_result(-L4_err::ENosys);
272     };
273 }