Fix inline fixnum LDB on PowerPC for certain bytespecs
[sbcl.git] / src / runtime / x86-darwin-os.c
1 #ifdef LISP_FEATURE_SB_THREAD
2 #include <architecture/i386/table.h>
3 #include <i386/user_ldt.h>
4 #include <mach/mach_init.h>
5 #endif
6
7 #include "thread.h"
8 #include "validate.h"
9 #include "runtime.h"
10 #include "interrupt.h"
11 #include "x86-darwin-os.h"
12 #include "genesis/fdefn.h"
13
14 #include <mach/mach.h>
15 #include <mach/mach_error.h>
16 #include <mach/mach_types.h>
17 #include <mach/sync_policy.h>
18 #include <mach/vm_region.h>
19 #include <mach/machine/thread_state.h>
20 #include <mach/machine/thread_status.h>
21 #include <sys/_types.h>
22 #include <sys/ucontext.h>
23 #include <pthread.h>
24 #include <assert.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27
28 #ifdef LISP_FEATURE_SB_THREAD
29
30 pthread_mutex_t modify_ldt_lock = PTHREAD_MUTEX_INITIALIZER;
31
32 void set_data_desc_size(data_desc_t* desc, unsigned long size)
33 {
34     desc->limit00 = (size - 1) & 0xffff;
35     desc->limit16 = ((size - 1) >> 16) &0xf;
36 }
37
38 void set_data_desc_addr(data_desc_t* desc, void* addr)
39 {
40     desc->base00 = (unsigned int)addr & 0xffff;
41     desc->base16 = ((unsigned int)addr & 0xff0000) >> 16;
42     desc->base24 = ((unsigned int)addr & 0xff000000) >> 24;
43 }
44
45 #endif
46
47 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
48 kern_return_t mach_thread_init(mach_port_t thread_exception_port);
49 #endif
50
51 int arch_os_thread_init(struct thread *thread) {
52 #ifdef LISP_FEATURE_SB_THREAD
53     int n;
54     sel_t sel;
55
56     data_desc_t ldt_entry = { 0, 0, 0, DESC_DATA_WRITE,
57                               3, 1, 0, DESC_DATA_32B, DESC_GRAN_BYTE, 0 };
58
59     set_data_desc_addr(&ldt_entry, thread);
60     set_data_desc_size(&ldt_entry, dynamic_values_bytes);
61
62     thread_mutex_lock(&modify_ldt_lock);
63     n = i386_set_ldt(LDT_AUTO_ALLOC, (union ldt_entry*) &ldt_entry, 1);
64
65     if (n < 0) {
66         perror("i386_set_ldt");
67         lose("unexpected i386_set_ldt(..) failure\n");
68     }
69     thread_mutex_unlock(&modify_ldt_lock);
70
71     FSHOW_SIGNAL((stderr, "/ TLS: Allocated LDT %x\n", n));
72     sel.index = n;
73     sel.rpl = USER_PRIV;
74     sel.ti = SEL_LDT;
75
76     __asm__ __volatile__ ("mov %0, %%fs" : : "r"(sel));
77
78     thread->tls_cookie=n;
79     pthread_setspecific(specials,thread);
80 #endif
81 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
82     mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(thread));
83 #endif
84
85 #ifdef LISP_FEATURE_C_STACK_IS_CONTROL_STACK
86     stack_t sigstack;
87
88     /* Signal handlers are run on the control stack, so if it is exhausted
89      * we had better use an alternate stack for whatever signal tells us
90      * we've exhausted it */
91     sigstack.ss_sp=((void *) thread)+dynamic_values_bytes;
92     sigstack.ss_flags=0;
93     sigstack.ss_size = 32*SIGSTKSZ;
94     sigaltstack(&sigstack,0);
95 #endif
96     return 1;                  /* success */
97 }
98
99 int arch_os_thread_cleanup(struct thread *thread) {
100 #if defined(LISP_FEATURE_SB_THREAD)
101     int n = thread->tls_cookie;
102
103     /* Set the %%fs register back to 0 and free the ldt by setting it
104      * to NULL.
105      */
106     FSHOW_SIGNAL((stderr, "/ TLS: Freeing LDT %x\n", n));
107
108     __asm__ __volatile__ ("mov %0, %%fs" : : "r"(0));
109     thread_mutex_lock(&modify_ldt_lock);
110     i386_set_ldt(n, NULL, 1);
111     thread_mutex_unlock(&modify_ldt_lock);
112 #endif
113     return 1;                  /* success */
114 }
115
116 #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER
117
118 void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context);
119 void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context);
120 void memory_fault_handler(int signal, siginfo_t *siginfo,
121                           os_context_t *context);
122
123 /* This executes in the faulting thread as part of the signal
124  * emulation.  It is passed a context with the uc_mcontext field
125  * pointing to a valid block of memory. */
126 void build_fake_signal_context(os_context_t *context,
127                                x86_thread_state32_t *thread_state,
128                                x86_float_state32_t *float_state) {
129     pthread_sigmask(0, NULL, &context->uc_sigmask);
130     context->uc_mcontext->SS = *thread_state;
131     context->uc_mcontext->FS = *float_state;
132 }
133
134 /* This executes in the faulting thread as part of the signal
135  * emulation.  It is effectively the inverse operation from above. */
136 void update_thread_state_from_context(x86_thread_state32_t *thread_state,
137                                       x86_float_state32_t *float_state,
138                                       os_context_t *context) {
139     *thread_state = context->uc_mcontext->SS;
140     *float_state = context->uc_mcontext->FS;
141     pthread_sigmask(SIG_SETMASK, &context->uc_sigmask, NULL);
142 }
143
144 /* Modify a context to push new data on its stack. */
145 void push_context(u32 data, x86_thread_state32_t *thread_state)
146 {
147     u32 *stack_pointer;
148
149     stack_pointer = (u32*) thread_state->ESP;
150     *(--stack_pointer) = data;
151     thread_state->ESP = (unsigned int) stack_pointer;
152 }
153
154 void align_context_stack(x86_thread_state32_t *thread_state)
155 {
156     /* 16byte align the stack (provided that the stack is, as it
157      * should be, 4byte aligned. */
158     while (thread_state->ESP & 15) push_context(0, thread_state);
159 }
160
161 /* Stack allocation starts with a context that has a mod-4 ESP value
162  * and needs to leave a context with a mod-16 ESP that will restore
163  * the old ESP value and other register state when activated.  The
164  * first part of this is the recovery trampoline, which loads ESP from
165  * EBP, pops EBP, and returns. */
166 asm("_stack_allocation_recover: movl %ebp, %esp; popl %ebp; ret;");
167
168 void open_stack_allocation(x86_thread_state32_t *thread_state)
169 {
170     void stack_allocation_recover(void);
171
172     push_context(thread_state->EIP, thread_state);
173     push_context(thread_state->EBP, thread_state);
174     thread_state->EBP = thread_state->ESP;
175     thread_state->EIP = (unsigned int) stack_allocation_recover;
176
177     align_context_stack(thread_state);
178 }
179
180 /* Stack allocation of data starts with a context with a mod-16 ESP
181  * value and reserves some space on it by manipulating the ESP
182  * register. */
183 void *stack_allocate(x86_thread_state32_t *thread_state, size_t size)
184 {
185     /* round up size to 16byte multiple */
186     size = (size + 15) & -16;
187
188     thread_state->ESP = ((u32)thread_state->ESP) - size;
189
190     return (void *)thread_state->ESP;
191 }
192
193 /* Arranging to invoke a C function is tricky, as we have to assume
194  * cdecl calling conventions (caller removes args) and x86/darwin
195  * alignment requirements.  The simplest way to arrange this,
196  * actually, is to open a new stack allocation.
197  * WARNING!!! THIS DOES NOT PRESERVE REGISTERS! */
198 void call_c_function_in_context(x86_thread_state32_t *thread_state,
199                                 void *function,
200                                 int nargs,
201                                 ...)
202 {
203     va_list ap;
204     int i;
205     u32 *stack_pointer;
206
207     /* Set up to restore stack on exit. */
208     open_stack_allocation(thread_state);
209
210     /* Have to keep stack 16byte aligned on x86/darwin. */
211     for (i = (3 & -nargs); i; i--) {
212         push_context(0, thread_state);
213     }
214
215     thread_state->ESP = ((u32)thread_state->ESP) - nargs * 4;
216     stack_pointer = (u32 *)thread_state->ESP;
217
218     va_start(ap, nargs);
219     for (i = 0; i < nargs; i++) {
220         //push_context(va_arg(ap, u32), thread_state);
221         stack_pointer[i] = va_arg(ap, u32);
222     }
223     va_end(ap);
224
225     push_context(thread_state->EIP, thread_state);
226     thread_state->EIP = (unsigned int) function;
227 }
228
229 void signal_emulation_wrapper(x86_thread_state32_t *thread_state,
230                               x86_float_state32_t *float_state,
231                               int signal,
232                               siginfo_t *siginfo,
233                               void (*handler)(int, siginfo_t *, void *))
234 {
235
236     /* CLH: FIXME **NOTE: HACK ALERT!** Ideally, we would allocate
237      * context and regs on the stack as local variables, but this
238      * causes problems for the lisp debugger. When it walks the stack
239      * for a back trace, it sees the 1) address of the local variable
240      * on the stack and thinks that is a frame pointer to a lisp
241      * frame, and, 2) the address of the sap that we alloc'ed in
242      * dynamic space and thinks that is a return address, so it,
243      * heuristicly (and wrongly), chooses that this should be
244      * interpreted as a lisp frame instead of as a C frame.
245      * We can work around this in this case by os_validating the
246      * context (and regs just for symmetry).
247      */
248
249     os_context_t *context;
250     mcontext_t *regs;
251
252     context = (os_context_t*) os_validate(0, sizeof(os_context_t));
253     regs = (mcontext_t*) os_validate(0, sizeof(mcontext_t));
254     context->uc_mcontext = regs;
255
256     /* when BSD signals are fired, they mask they signals in sa_mask
257        which always seem to be the blockable_sigset, for us, so we
258        need to:
259        1) save the current sigmask
260        2) block blockable signals
261        3) call the signal handler
262        4) restore the sigmask */
263
264     build_fake_signal_context(context, thread_state, float_state);
265
266     block_blockable_signals(0, 0);
267
268     handler(signal, siginfo, context);
269
270     update_thread_state_from_context(thread_state, float_state, context);
271
272     os_invalidate((os_vm_address_t)context, sizeof(os_context_t));
273     os_invalidate((os_vm_address_t)regs, sizeof(mcontext_t));
274
275     /* Trap to restore the signal context. */
276     asm volatile (".long 0xffff0b0f"
277                   : : "a" (thread_state), "c" (float_state));
278 }
279
280 /* Convenience wrapper for the above */
281 void call_handler_on_thread(mach_port_t thread,
282                             x86_thread_state32_t *thread_state,
283                             int signal,
284                             siginfo_t *siginfo,
285                             void (*handler)(int, siginfo_t *, void *))
286 {
287     x86_thread_state32_t new_state;
288     x86_thread_state32_t *save_thread_state;
289     x86_float_state32_t *save_float_state;
290     mach_msg_type_number_t state_count;
291     siginfo_t *save_siginfo;
292     kern_return_t ret;
293     /* Initialize the new state */
294     new_state = *thread_state;
295     open_stack_allocation(&new_state);
296     stack_allocate(&new_state, 256);
297     /* Save old state */
298     save_thread_state = (x86_thread_state32_t *)stack_allocate(&new_state, sizeof(*save_thread_state));
299     *save_thread_state = *thread_state;
300     /* Save float state */
301     save_float_state = (x86_float_state32_t *)stack_allocate(&new_state, sizeof(*save_float_state));
302     state_count = x86_FLOAT_STATE32_COUNT;
303     if ((ret = thread_get_state(thread,
304                                 x86_FLOAT_STATE32,
305                                 (thread_state_t)save_float_state,
306                                 &state_count)) != KERN_SUCCESS)
307         lose("thread_get_state (x86_THREAD_STATE32) failed %d\n", ret);
308     /* Set up siginfo */
309     save_siginfo = stack_allocate(&new_state, sizeof(*siginfo));
310     if (siginfo == NULL)
311         save_siginfo = siginfo;
312     else
313         *save_siginfo = *siginfo;
314     /* Prepare to call */
315     call_c_function_in_context(&new_state,
316                                signal_emulation_wrapper,
317                                5,
318                                save_thread_state,
319                                save_float_state,
320                                signal,
321                                save_siginfo,
322                                handler);
323     /* Update the thread state */
324     state_count = x86_THREAD_STATE32_COUNT;
325     if ((ret = thread_set_state(thread,
326                                 x86_THREAD_STATE32,
327                                 (thread_state_t)&new_state,
328                                 state_count)) != KERN_SUCCESS)
329         lose("thread_set_state (x86_FLOAT_STATE32) failed %d\n", ret);
330
331 }
332
333 #if defined DUMP_CONTEXT
334 void dump_context(x86_thread_state32_t *thread_state)
335 {
336     int i;
337     u32 *stack_pointer;
338
339     printf("eax: %08lx  ecx: %08lx  edx: %08lx  ebx: %08lx\n",
340            thread_state->EAX, thread_state->ECX, thread_state->EDX, thread_state->EAX);
341     printf("esp: %08lx  ebp: %08lx  esi: %08lx  edi: %08lx\n",
342            thread_state->ESP, thread_state->EBP, thread_state->ESI, thread_state->EDI);
343     printf("eip: %08lx  eflags: %08lx\n",
344            thread_state->EIP, thread_state->EFLAGS);
345     printf("cs: %04hx  ds: %04hx  es: %04hx  "
346            "ss: %04hx  fs: %04hx  gs: %04hx\n",
347            thread_state->CS,
348            thread_state->DS,
349            thread_state->ES,
350            thread_state->SS,
351            thread_state->FS,
352            thread_state->GS);
353
354     stack_pointer = (u32 *)thread_state->ESP;
355     for (i = 0; i < 48; i+=4) {
356         printf("%08x:  %08x %08x %08x %08x\n",
357                thread_state->ESP + (i * 4),
358                stack_pointer[i],
359                stack_pointer[i+1],
360                stack_pointer[i+2],
361                stack_pointer[i+3]);
362     }
363 }
364 #endif
365
366 void
367 control_stack_exhausted_handler(int signal, siginfo_t *siginfo,
368                                 os_context_t *context) {
369
370     unblock_signals_in_context_and_maybe_warn(context);
371     arrange_return_to_lisp_function
372         (context, StaticSymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR));
373 }
374
375 void
376 undefined_alien_handler(int signal, siginfo_t *siginfo, os_context_t *context) {
377     arrange_return_to_lisp_function
378         (context, StaticSymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR));
379 }
380
381 kern_return_t
382 catch_exception_raise(mach_port_t exception_port,
383                       mach_port_t thread,
384                       mach_port_t task,
385                       exception_type_t exception,
386                       exception_data_t code_vector,
387                       mach_msg_type_number_t code_count)
388 {
389     struct thread *th = (struct thread*) exception_port;
390     x86_thread_state32_t thread_state;
391     mach_msg_type_number_t state_count;
392     vm_address_t region_addr;
393     vm_size_t region_size;
394     vm_region_basic_info_data_t region_info;
395     mach_msg_type_number_t info_count;
396     mach_port_t region_name;
397     void *addr = NULL;
398     int signal = 0;
399     void (*handler)(int, siginfo_t *, void *) = NULL;
400     siginfo_t siginfo;
401     kern_return_t ret, dealloc_ret;
402
403     /* Get state and info */
404     state_count = x86_THREAD_STATE32_COUNT;
405     if ((ret = thread_get_state(thread,
406                                 x86_THREAD_STATE32,
407                                 (thread_state_t)&thread_state,
408                                 &state_count)) != KERN_SUCCESS)
409         lose("thread_get_state (x86_THREAD_STATE32) failed %d\n", ret);
410     switch (exception) {
411     case EXC_BAD_ACCESS:
412         signal = SIGBUS;
413         /* Check if write protection fault */
414         if ((code_vector[0] & OS_VM_PROT_ALL) == 0) {
415             ret = KERN_INVALID_RIGHT;
416             break;
417         }
418         addr = (void*)code_vector[1];
419         /* Undefined alien */
420         if (os_trunc_to_page(addr) == undefined_alien_address) {
421             handler = undefined_alien_handler;
422             break;
423         }
424         /* At stack guard */
425         if (os_trunc_to_page(addr) == CONTROL_STACK_GUARD_PAGE(th)) {
426             lower_thread_control_stack_guard_page(th);
427             handler = control_stack_exhausted_handler;
428             break;
429         }
430         /* Return from stack guard */
431         if (os_trunc_to_page(addr) == CONTROL_STACK_RETURN_GUARD_PAGE(th)) {
432             reset_thread_control_stack_guard_page(th);
433             break;
434         }
435         /* Regular memory fault */
436         handler = memory_fault_handler;
437         break;
438     case EXC_BAD_INSTRUCTION:
439         signal = SIGTRAP;
440         /* Check if illegal instruction trap */
441         if (code_vector[0] != EXC_I386_INVOP) {
442             ret = KERN_INVALID_RIGHT;
443             break;
444         }
445         /* Check if UD2 instruction */
446         if (*(unsigned short *)thread_state.EIP != 0x0b0f) {
447             /* KLUDGE: There are two ways we could get here:
448              * 1) We're executing data and we've hit some truly
449              *    illegal opcode, of which there are a few, see
450              *    Intel 64 and IA-32 Architectures
451              *    Sofware Developer's Manual
452              *    Volume 3A page 5-34)
453              * 2) The kernel started an unrelated signal handler
454              *    before we got a chance to run. The context that
455              *    caused the exception is saved in a stack frame
456              *    somewhere down below.
457              * In either case we rely on the exception to retrigger,
458              * eventually bailing out if we're spinning on case 2).
459              */
460             static mach_port_t last_thread;
461             static unsigned int last_eip;
462             if (last_thread == thread && last_eip == thread_state.EIP)
463                 ret = KERN_INVALID_RIGHT;
464             else
465                 ret = KERN_SUCCESS;
466             last_thread = thread;
467             last_eip = thread_state.EIP;
468             break;
469         }
470         /* Skip the trap code */
471         thread_state.EIP += 2;
472         /* Return from handler? */
473         if (*(unsigned short *)thread_state.EIP == 0xffff) {
474             if ((ret = thread_set_state(thread,
475                                         x86_THREAD_STATE32,
476                                         (thread_state_t)thread_state.EAX,
477                                         x86_THREAD_STATE32_COUNT)) != KERN_SUCCESS)
478                 lose("thread_set_state (x86_THREAD_STATE32) failed %d\n", ret);
479             if ((ret = thread_set_state(thread,
480                                         x86_FLOAT_STATE32,
481                                         (thread_state_t)thread_state.ECX,
482                                         x86_FLOAT_STATE32_COUNT)) != KERN_SUCCESS)
483                 lose("thread_set_state (x86_FLOAT_STATE32) failed %d\n", ret);
484             break;
485         }
486         /* Trap call */
487         handler = sigtrap_handler;
488         break;
489     default:
490         ret = KERN_INVALID_RIGHT;
491     }
492     /* Call handler */
493     if (handler != 0) {
494       siginfo.si_signo = signal;
495       siginfo.si_addr = addr;
496       call_handler_on_thread(thread, &thread_state, signal, &siginfo, handler);
497     }
498
499     dealloc_ret = mach_port_deallocate (current_mach_task, thread);
500     if (dealloc_ret) {
501       lose("mach_port_deallocate (thread) failed with return_code %d\n", dealloc_ret);
502     }
503
504     dealloc_ret = mach_port_deallocate (current_mach_task, task);
505     if (dealloc_ret) {
506       lose("mach_port_deallocate (task) failed with return_code %d\n", dealloc_ret);
507     }
508
509     return ret;
510 }
511
512 void
513 os_restore_fp_control(os_context_t *context)
514 {
515     /* KLUDGE: The x87 FPU control word is some nasty bitfield struct
516      * thing.  Rather than deal with that, just grab it as a 16-bit
517      * integer. */
518     unsigned short fpu_control_word =
519         *((unsigned short *)&context->uc_mcontext->FS.FPU_FCW);
520     /* reset exception flags and restore control flags on x87 FPU */
521     asm ("fldcw %0" : : "m" (fpu_control_word));
522 }
523
524 #endif