X-Git-Url: http://repo.macrolet.net/gitweb/?a=blobdiff_plain;f=src%2Fruntime%2Fx86-64-darwin-os.c;h=6378d7b018d918d37617158b00980c5a2a656c5a;hb=bf40ae88bc289fd765a33861cc4bc0853ed483ba;hp=20cbce1340f73c24e74b8843c56b300835416385;hpb=0f234877047c56ca945fe54e9e77a9cc2c8141cb;p=sbcl.git diff --git a/src/runtime/x86-64-darwin-os.c b/src/runtime/x86-64-darwin-os.c index 20cbce1..6378d7b 100644 --- a/src/runtime/x86-64-darwin-os.c +++ b/src/runtime/x86-64-darwin-os.c @@ -1,4 +1,3 @@ - #ifdef LISP_FEATURE_SB_THREAD #include #include @@ -25,29 +24,56 @@ #include #include +#if __DARWIN_UNIX03 +#include +#endif + +#if __DARWIN_UNIX03 + +typedef struct __darwin_ucontext darwin_ucontext; +typedef struct __darwin_mcontext64 darwin_mcontext; + +#define rip __rip +#define rsp __rsp +#define rbp __rbp +#define rax __rax +#define rbx __rbx +#define rcx __rcx +#define rdx __rdx +#define rsi __rsi +#define rdi __rdi +#define r8 __r8 +#define r9 __r9 +#define faultvaddr __faultvaddr +#define ss __ss +#define es __es +#define fs __fs + +#define fpu_fcw __fpu_fcw +#define fpu_mxcsr __fpu_mxcsr + +#else + +typedef struct ucontext darwin_ucontext; +typedef struct mcontext darwin_mcontext; + +#endif + #ifdef LISP_FEATURE_SB_THREAD pthread_mutex_t mach_exception_lock = PTHREAD_MUTEX_INITIALIZER; #endif #ifdef LISP_FEATURE_MACH_EXCEPTION_HANDLER -kern_return_t mach_thread_init(mach_port_t thread_exception_port); - -void sigill_handler(int signal, siginfo_t *siginfo, void *void_context); -void sigtrap_handler(int signal, siginfo_t *siginfo, void *void_context); -void memory_fault_handler(int signal, siginfo_t *siginfo, void *void_context); - -/* exc_server handles mach exception messages from the kernel and - * calls catch exception raise. We use the system-provided - * mach_msg_server, which, I assume, calls exc_server in a loop. - * - */ -extern boolean_t exc_server(); +void sigill_handler(int signal, siginfo_t *siginfo, os_context_t *context); +void sigtrap_handler(int signal, siginfo_t *siginfo, os_context_t *context); +void memory_fault_handler(int signal, siginfo_t *siginfo, + os_context_t *context); /* This executes in the faulting thread as part of the signal * emulation. It is passed a context with the uc_mcontext field * pointing to a valid block of memory. */ -void build_fake_signal_context(struct ucontext *context, +void build_fake_signal_context(darwin_ucontext *context, x86_thread_state64_t *thread_state, x86_float_state64_t *float_state) { pthread_sigmask(0, NULL, &context->uc_sigmask); @@ -59,7 +85,7 @@ void build_fake_signal_context(struct ucontext *context, * emulation. It is effectively the inverse operation from above. */ void update_thread_state_from_context(x86_thread_state64_t *thread_state, x86_float_state64_t *float_state, - struct ucontext *context) { + darwin_ucontext *context) { *thread_state = context->uc_mcontext->ss; *float_state = context->uc_mcontext->fs; pthread_sigmask(SIG_SETMASK, &context->uc_sigmask, NULL); @@ -87,8 +113,18 @@ void align_context_stack(x86_thread_state64_t *context) * the old ESP value and other register state when activated. The * first part of this is the recovery trampoline, which loads ESP from * EBP, pops EBP, and returns. */ -asm(".globl _stack_allocation_recover; .align 4; _stack_allocation_recover: mov %rbp, %rsp; pop %rsi; pop %rdi; pop \ -%rdx; pop %rcx; pop %r8; pop %r9; pop %rbp; ret;"); +asm(".globl _stack_allocation_recover; \ + .align 4; \ + _stack_allocation_recover: \ + lea -48(%rbp), %rsp; \ + pop %rsi; \ + pop %rdi; \ + pop %rdx; \ + pop %rcx; \ + pop %r8; \ + pop %r9; \ + pop %rbp; \ + ret;"); void open_stack_allocation(x86_thread_state64_t *context) { @@ -96,6 +132,7 @@ void open_stack_allocation(x86_thread_state64_t *context) push_context(context->rip, context); push_context(context->rbp, context); + context->rbp = context->rsp; push_context(context->r9, context); push_context(context->r8, context); @@ -104,7 +141,6 @@ void open_stack_allocation(x86_thread_state64_t *context) push_context(context->rsi, context); push_context(context->rdi, context); - context->rbp = context->rsp; context->rip = (u64) stack_allocation_recover; align_context_stack(context); @@ -184,11 +220,11 @@ void signal_emulation_wrapper(x86_thread_state64_t *thread_state, * context (and regs just for symmetry). */ - struct ucontext *context; - struct mcontext *regs; + darwin_ucontext *context; + darwin_mcontext *regs; - context = (struct ucontext*) os_validate(0, sizeof(struct ucontext)); - regs = (struct mcontext*) os_validate(0, sizeof(struct mcontext)); + context = (darwin_ucontext *) os_validate(0, sizeof(darwin_ucontext)); + regs = (darwin_mcontext*) os_validate(0, sizeof(darwin_mcontext)); context->uc_mcontext = regs; /* when BSD signals are fired, they mask they signals in sa_mask @@ -201,18 +237,18 @@ void signal_emulation_wrapper(x86_thread_state64_t *thread_state, build_fake_signal_context(context, thread_state, float_state); - block_blockable_signals(); + block_blockable_signals(0, 0); handler(signal, siginfo, context); update_thread_state_from_context(thread_state, float_state, context); - os_invalidate((os_vm_address_t)context, sizeof(struct ucontext)); - os_invalidate((os_vm_address_t)regs, sizeof(struct mcontext)); + os_invalidate((os_vm_address_t)context, sizeof(darwin_ucontext)); + os_invalidate((os_vm_address_t)regs, sizeof(darwin_mcontext)); /* Trap to restore the signal context. */ - asm volatile ("mov %0, %%rax; mov %1, %%rbx; .quad 0xffffffffffff0b0f" - : : "r" (thread_state), "r" (float_state)); + asm volatile (".quad 0xffffffffffff0b0f" + : : "a" (thread_state), "b" (float_state)); } #if defined DUMP_CONTEXT @@ -245,19 +281,17 @@ void dump_context(x86_thread_state64_t *context) #endif void -control_stack_exhausted_handler(int signal, siginfo_t *siginfo, void *void_context) { - os_context_t *context = arch_os_get_context(&void_context); - +control_stack_exhausted_handler(int signal, siginfo_t *siginfo, + os_context_t *context) { + unblock_signals_in_context_and_maybe_warn(context); arrange_return_to_lisp_function - (context, SymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR)); + (context, StaticSymbolFunction(CONTROL_STACK_EXHAUSTED_ERROR)); } void -undefined_alien_handler(int signal, siginfo_t *siginfo, void *void_context) { - os_context_t *context = arch_os_get_context(&void_context); - +undefined_alien_handler(int signal, siginfo_t *siginfo, os_context_t *context) { arrange_return_to_lisp_function - (context, SymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR)); + (context, StaticSymbolFunction(UNDEFINED_ALIEN_VARIABLE_ERROR)); } kern_return_t @@ -268,7 +302,7 @@ catch_exception_raise(mach_port_t exception_port, exception_data_t code_vector, mach_msg_type_number_t code_count) { - kern_return_t ret; + kern_return_t ret, dealloc_ret; int signal; siginfo_t* siginfo; @@ -291,9 +325,10 @@ catch_exception_raise(mach_port_t exception_port, os_vm_address_t addr; - struct thread *th = (struct thread*) exception_port; + struct thread *th; FSHOW((stderr,"/entering catch_exception_raise with exception: %d\n", exception)); + th = *(struct thread**)exception_port; switch (exception) { @@ -312,8 +347,6 @@ catch_exception_raise(mach_port_t exception_port, (thread_state_t)&exception_state, &exception_state_count); addr = (void*)exception_state.faultvaddr; - - /* note the os_context hackery here. When the signal handler returns, * it won't go back to what it was doing ... */ if(addr >= CONTROL_STACK_GUARD_PAGE(th) && @@ -322,11 +355,14 @@ catch_exception_raise(mach_port_t exception_port, * protection so the error handler has some headroom, protect the * previous page so that we can catch returns from the guard page * and restore it. */ - protect_control_stack_guard_page_thread(0, th); - protect_control_stack_return_guard_page_thread(1, th); + lower_thread_control_stack_guard_page(th); backup_thread_state = thread_state; open_stack_allocation(&thread_state); + /* Reserve a 256 byte zone for signal handlers + * to use on the interrupted thread stack. + */ + stack_allocate(&thread_state, 256); /* Save thread state */ target_thread_state = @@ -360,13 +396,13 @@ catch_exception_raise(mach_port_t exception_port, * unprotect this one. This works even if we somehow missed * the return-guard-page, and hit it on our way to new * exhaustion instead. */ - protect_control_stack_guard_page_thread(1, th); - protect_control_stack_return_guard_page_thread(0, th); + reset_thread_control_stack_guard_page(th); } else if (addr >= undefined_alien_address && addr < undefined_alien_address + os_vm_page_size) { backup_thread_state = thread_state; open_stack_allocation(&thread_state); + stack_allocate(&thread_state, 256); /* Save thread state */ target_thread_state = @@ -396,6 +432,7 @@ catch_exception_raise(mach_port_t exception_port, backup_thread_state = thread_state; open_stack_allocation(&thread_state); + stack_allocate(&thread_state, 256); /* Save thread state */ target_thread_state = @@ -434,7 +471,8 @@ catch_exception_raise(mach_port_t exception_port, #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif - return KERN_SUCCESS; + ret = KERN_SUCCESS; + break; case EXC_BAD_INSTRUCTION: @@ -472,6 +510,7 @@ catch_exception_raise(mach_port_t exception_port, backup_thread_state = thread_state; open_stack_allocation(&thread_state); + stack_allocate(&thread_state, 256); /* Save thread state */ target_thread_state = @@ -525,120 +564,42 @@ catch_exception_raise(mach_port_t exception_port, #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif - return KERN_SUCCESS; + ret = KERN_SUCCESS; + break; default: #ifdef LISP_FEATURE_SB_THREAD thread_mutex_unlock(&mach_exception_lock); #endif - return KERN_INVALID_RIGHT; + ret = KERN_INVALID_RIGHT; } -} - -void * -mach_exception_handler(void *port) -{ - mach_msg_server(exc_server, 2048, (mach_port_t) port, 0); - /* mach_msg_server should never return, but it should dispatch mach - * exceptions to our catch_exception_raise function - */ - abort(); -} -/* Sets up the thread that will listen for mach exceptions. note that - the exception handlers will be run on this thread. This is - different from the BSD-style signal handling situation in which the - signal handlers run in the relevant thread directly. */ - -mach_port_t mach_exception_handler_port_set = MACH_PORT_NULL; - -pthread_t -setup_mach_exception_handling_thread() -{ - kern_return_t ret; - pthread_t mach_exception_handling_thread = NULL; - pthread_attr_t attr; - - /* allocate a mach_port for this process */ - ret = mach_port_allocate(mach_task_self(), - MACH_PORT_RIGHT_PORT_SET, - &mach_exception_handler_port_set); - - /* create the thread that will receive the mach exceptions */ - - FSHOW((stderr, "Creating mach_exception_handler thread!\n")); - - pthread_attr_init(&attr); - pthread_create(&mach_exception_handling_thread, - &attr, - mach_exception_handler, - (void*) mach_exception_handler_port_set); - pthread_attr_destroy(&attr); - - return mach_exception_handling_thread; -} - -/* tell the kernel that we want EXC_BAD_ACCESS exceptions sent to the - exception port (which is being listened to do by the mach - exception handling thread). */ -kern_return_t -mach_thread_init(mach_port_t thread_exception_port) -{ - kern_return_t ret; - /* allocate a named port for the thread */ - - FSHOW((stderr, "Allocating mach port %x\n", thread_exception_port)); - - ret = mach_port_allocate_name(mach_task_self(), - MACH_PORT_RIGHT_RECEIVE, - thread_exception_port); - if (ret) { - lose("mach_port_allocate_name failed with return_code %d\n", ret); + dealloc_ret = mach_port_deallocate (current_mach_task, thread); + if (dealloc_ret) { + lose("mach_port_deallocate (thread) failed with return_code %d\n", dealloc_ret); } - /* establish the right for the thread_exception_port to send messages */ - ret = mach_port_insert_right(mach_task_self(), - thread_exception_port, - thread_exception_port, - MACH_MSG_TYPE_MAKE_SEND); - if (ret) { - lose("mach_port_insert_right failed with return_code %d\n", ret); - } - - ret = thread_set_exception_ports(mach_thread_self(), - EXC_MASK_BAD_ACCESS | EXC_MASK_BAD_INSTRUCTION, - thread_exception_port, - EXCEPTION_DEFAULT, - THREAD_STATE_NONE); - if (ret) { - lose("thread_set_exception_port failed with return_code %d\n", ret); - } - - ret = mach_port_move_member(mach_task_self(), - thread_exception_port, - mach_exception_handler_port_set); - if (ret) { - lose("mach_port_ failed with return_code %d\n", ret); + dealloc_ret = mach_port_deallocate (current_mach_task, task); + if (dealloc_ret) { + lose("mach_port_deallocate (task) failed with return_code %d\n", dealloc_ret); } return ret; } void -setup_mach_exceptions() { - setup_mach_exception_handling_thread(); - mach_thread_init(THREAD_STRUCT_TO_EXCEPTION_PORT(all_threads)); -} - -pid_t -mach_fork() { - pid_t pid = fork(); - if (pid == 0) { - setup_mach_exceptions(); - return pid; - } else { - return pid; - } +os_restore_fp_control(os_context_t *context) +{ + /* KLUDGE: The x87 FPU control word is some nasty bitfield struct + * thing. Rather than deal with that, just grab it as a 16-bit + * integer. */ + unsigned short fpu_control_word = + *((unsigned short *)&context->uc_mcontext->fs.fpu_fcw); + /* reset exception flags and restore control flags on SSE2 FPU */ + unsigned int temp = (context->uc_mcontext->fs.fpu_mxcsr) & ~0x3F; + asm ("ldmxcsr %0" : : "m" (temp)); + /* same for x87 FPU. */ + asm ("fldcw %0" : : "m" (fpu_control_word)); } #endif