]> 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 "lock_guard.h"
21 #include "panic.h"
22 #include "per_cpu_data.h"
23 #include "utcb_init.h"
24
25 int (*Thread::int3_handler)(Trap_state*);
26 DEFINE_PER_CPU Per_cpu<Thread::Dbg_stack> Thread::dbg_stack;
27
28
29 IMPLEMENT static inline NEEDS ["emulation.h"]
30 Mword
31 Thread::exception_cs()
32 {
33   return Emulation::kernel_cs();
34 }
35
36 /**
37  * The ux specific part of the thread constructor.
38  */
39 PRIVATE inline
40 void
41 Thread::arch_init()
42 {
43   // Allocate FPU state now because it indirectly calls current()
44   // save_state runs on a signal stack and current() doesn't work there.
45   if (space())
46     // FIXME, space()==0 for sigma0 (or even more)
47     Fpu_alloc::alloc_state(space()->ram_quota(), fpu_state());
48   else
49     Fpu_alloc::alloc_state(Ram_quota::root, fpu_state());
50
51   // clear out user regs that can be returned from the thread_ex_regs
52   // system call to prevent covert channel
53   Entry_frame *r = regs();
54   r->sp(0);
55   r->ip(0);
56   r->cs(Emulation::kernel_cs() & ~1);                   // force iret trap
57   r->ss(Emulation::kernel_ss());
58   r->flags(EFLAGS_IOPL_K | EFLAGS_IF | 2);
59 }
60
61 PUBLIC static inline
62 void
63 Thread::set_int3_handler(int (*handler)(Trap_state *ts))
64 {
65   int3_handler = handler;
66 }
67
68 PRIVATE inline bool Thread::check_trap13_kernel(Trap_state *)
69 { return 1; }
70
71 PRIVATE inline void Thread::check_f00f_bug(Trap_state *)
72 {}
73
74 PRIVATE inline 
75 unsigned
76 Thread::check_io_bitmap_delimiter_fault(Trap_state *)
77 { return 1; }
78
79 PRIVATE inline bool Thread::handle_sysenter_trap(Trap_state *, Address, bool)
80 { return true; }
81
82 PRIVATE inline
83 int
84 Thread::handle_not_nested_trap(Trap_state *)
85 { return -1; }
86
87 PRIVATE
88 int
89 Thread::call_nested_trap_handler(Trap_state *ts)
90 {
91   // run the nested trap handler on a separate stack
92   // equiv of: return nested_trap_handler(ts) == 0 ? true : false;
93
94   //static char nested_handler_stack [Config::PAGE_SIZE];
95   Cpu_phys_id phys_cpu = Cpu::phys_id_direct();
96   Cpu_number log_cpu = Cpu::cpus.find_cpu(Cpu::By_phys_id(phys_cpu));
97
98   if (log_cpu == Cpu_number::nil())
99     {
100       printf("Trap on unknown CPU host-thread=%x\n",
101              cxx::int_value<Cpu_phys_id>(phys_cpu));
102       log_cpu = Cpu_number::boot_cpu();
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             load_gdt_user_entries();
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 }