1 /* 2 * Copyright 2011, Ingo Weinhold, ingo_weinhold@gmx.de. 3 * Distributed under the terms of the MIT License. 4 */ 5 6 7 #include "x86_signals.h" 8 9 #include <string.h> 10 11 #include <KernelExport.h> 12 13 #include <commpage.h> 14 #include <cpu.h> 15 #include <elf.h> 16 #include <smp.h> 17 18 #include "syscall_numbers.h" 19 20 21 // implemented in assembly 22 extern "C" void x86_signal_frame_function_beos(signal_frame_data* frameData); 23 24 25 extern "C" void 26 x86_signal_frame_function(signal_frame_data* frameData) 27 { 28 // Note: This function is copied to the commpage. Hence it needs to be 29 // position independent. We don't build this source file with the respective 30 // flags, but the code the compiler generates for this function is position 31 // independent anyway. It simply doesn't contain constructs that could 32 // result in position dependent code. The potentially problematic jumps 33 // needed due to the "if" statement are all harmless relative jumps. 34 35 if (frameData->siginfo_handler) { 36 // SA_SIGINFO style handler function -- we additionally pass the user 37 // data pointer 38 void (*handler)(int, siginfo_t*, void*, void*) 39 = (void (*)(int, siginfo_t*, void*, void*))frameData->handler; 40 handler(frameData->info.si_signo, &frameData->info, 41 &frameData->context, frameData->user_data); 42 } else { 43 // Simple handler function -- we call it with additional user data 44 // pointer and vregs parameters. Note that unlike in BeOS the last 45 // parameter is a pointer to a vregs structure, while in BeOS the 46 // structure was passed be value. For setting up a BeOS binary 47 // compatible signal handler call x86_signal_frame_function_beos() is 48 // used instead. 49 void (*handler)(int, void*, vregs*) 50 = (void (*)(int, void*, vregs*))frameData->handler; 51 handler(frameData->info.si_signo, frameData->user_data, 52 &frameData->context.uc_mcontext); 53 } 54 55 #define TO_STRING_LITERAL_HELPER(number) #number 56 #define TO_STRING_LITERAL(number) TO_STRING_LITERAL_HELPER(number) 57 58 // call the restore_signal_frame() syscall -- does not return (here) 59 asm volatile( 60 // push frameData -- the parameter to restore_signal_frame() 61 "pushl %0;" 62 // push a dummy return value 63 "pushl $0;" 64 // syscall number to eax 65 "movl $" TO_STRING_LITERAL(SYSCALL_RESTORE_SIGNAL_FRAME) ", %%eax;" 66 // syscall 67 "int $99;" 68 :: "r"(frameData) 69 ); 70 71 #undef TO_STRING_LITERAL_HELPER 72 #undef TO_STRING_LITERAL 73 } 74 75 76 static void 77 register_signal_handler_function(const char* functionName, int32 commpageIndex, 78 const char* commpageSymbolName, addr_t expectedAddress) 79 { 80 // look up the x86_signal_frame_function() symbol -- we have its address, 81 // but also need its size 82 elf_symbol_info symbolInfo; 83 if (elf_lookup_kernel_symbol(functionName, &symbolInfo) 84 != B_OK) { 85 panic("x86_initialize_commpage_signal_handler(): Failed to find " 86 "signal frame function \"%s\"!", functionName); 87 } 88 89 ASSERT(expectedAddress == symbolInfo.address); 90 91 // fill in the commpage table entry 92 addr_t position = fill_commpage_entry(commpageIndex, 93 (void*)symbolInfo.address, symbolInfo.size); 94 95 // add symbol to the commpage image 96 image_id image = get_commpage_image(); 97 elf_add_memory_image_symbol(image, commpageSymbolName, position, 98 symbolInfo.size, B_SYMBOL_TYPE_TEXT); 99 } 100 101 102 void 103 x86_initialize_commpage_signal_handler() 104 { 105 // standard handler 106 register_signal_handler_function("x86_signal_frame_function", 107 COMMPAGE_ENTRY_X86_SIGNAL_HANDLER, "commpage_signal_handler", 108 (addr_t)&x86_signal_frame_function); 109 110 // handler for BeOS backwards compatibility 111 register_signal_handler_function("x86_signal_frame_function_beos", 112 COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS, "commpage_signal_handler_beos", 113 (addr_t)&x86_signal_frame_function_beos); 114 } 115 116 117 addr_t 118 x86_get_user_signal_handler_wrapper(bool beosHandler, void* commPageAdddress) 119 { 120 int32 index = beosHandler 121 ? COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS 122 : COMMPAGE_ENTRY_X86_SIGNAL_HANDLER; 123 return ((addr_t*)commPageAdddress)[index] + (addr_t)commPageAdddress; 124 } 125