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	fill_commpage_entry(commpageIndex, (void*)symbolInfo.address,
93		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,
98		((addr_t*)USER_COMMPAGE_ADDR)[commpageIndex], symbolInfo.size,
99		B_SYMBOL_TYPE_TEXT);
100}
101
102
103void
104x86_initialize_commpage_signal_handler()
105{
106	// standard handler
107	register_signal_handler_function("x86_signal_frame_function",
108		COMMPAGE_ENTRY_X86_SIGNAL_HANDLER, "commpage_signal_handler",
109		(addr_t)&x86_signal_frame_function);
110
111	// handler for BeOS backwards compatibility
112	register_signal_handler_function("x86_signal_frame_function_beos",
113		COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS, "commpage_signal_handler_beos",
114		(addr_t)&x86_signal_frame_function_beos);
115}
116
117
118addr_t
119x86_get_user_signal_handler_wrapper(bool beosHandler)
120{
121	int32 index = beosHandler
122		? COMMPAGE_ENTRY_X86_SIGNAL_HANDLER_BEOS
123		: COMMPAGE_ENTRY_X86_SIGNAL_HANDLER;
124	return ((addr_t*)USER_COMMPAGE_ADDR)[index];
125}
126