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
22extern "C" void x86_signal_frame_function_beos(signal_frame_data* frameData);
23
24
25extern "C" void
26x86_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
76static void
77register_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
102void
103x86_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
117addr_t
118x86_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