xref: /haiku/src/system/kernel/arch/x86/32/signals.cpp (revision b617a7b410c05275effb95f4b2f5608359d9b7b9)
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