1/*
2 * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
3 * Distributed under the terms of the MIT License.
4 *
5 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
8
9
10#include <arch/thread.h>
11
12#include <string.h>
13
14#include <arch/user_debugger.h>
15#include <arch_cpu.h>
16#include <commpage.h>
17#include <cpu.h>
18#include <debug.h>
19#include <kernel.h>
20#include <ksignal.h>
21#include <int.h>
22#include <team.h>
23#include <thread.h>
24#include <tls.h>
25#include <tracing.h>
26#include <util/AutoLock.h>
27#include <util/Random.h>
28#include <vm/vm_types.h>
29#include <vm/VMAddressSpace.h>
30
31#include "paging/X86PagingStructures.h"
32#include "paging/X86VMTranslationMap.h"
33#include "x86_signals.h"
34
35
36//#define TRACE_ARCH_THREAD
37#ifdef TRACE_ARCH_THREAD
38#	define TRACE(x) dprintf x
39#else
40#	define TRACE(x) ;
41#endif
42
43
44#ifdef SYSCALL_TRACING
45
46namespace SyscallTracing {
47
48class RestartSyscall : public AbstractTraceEntry {
49	public:
50		RestartSyscall()
51		{
52			Initialized();
53		}
54
55		virtual void AddDump(TraceOutput& out)
56		{
57			out.Print("syscall restart");
58		}
59};
60
61}
62
63#	define TSYSCALL(x)	new(std::nothrow) SyscallTracing::x
64
65#else
66#	define TSYSCALL(x)
67#endif	// SYSCALL_TRACING
68
69
70// from arch_cpu.cpp
71extern bool gHasSSE;
72
73static struct arch_thread sInitialState _ALIGNED(16);
74	// the fpu_state must be aligned on a 16 byte boundary, so that fxsave can use it
75
76
77static inline void
78set_fs_register(uint32 segment)
79{
80	asm("movl %0,%%fs" :: "r" (segment));
81}
82
83
84void
85x86_restart_syscall(struct iframe* frame)
86{
87	Thread* thread = thread_get_current_thread();
88
89	atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
90	atomic_or(&thread->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
91
92	frame->ax = frame->orig_eax;
93	frame->dx = frame->orig_edx;
94	frame->ip -= 2;
95		// undoes the "int $99"/"sysenter"/"syscall" instruction
96		// (so that it'll be executed again)
97
98	TSYSCALL(RestartSyscall());
99}
100
101
102void
103x86_set_tls_context(Thread *thread)
104{
105	segment_descriptor* gdt = get_gdt(smp_get_current_cpu());
106	set_segment_descriptor_base(&gdt[USER_TLS_SEGMENT],
107		thread->user_local_storage);
108	set_fs_register((USER_TLS_SEGMENT << 3) | DPL_USER);
109}
110
111
112static addr_t
113arch_randomize_stack_pointer(addr_t value)
114{
115	STATIC_ASSERT(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1);
116	value -= random_value() & (B_PAGE_SIZE - 1);
117	return (value & ~addr_t(0xf)) - 4;
118		// This means, result % 16 == 12, which is what esp should adhere to
119		// when a function is entered for the stack to be considered aligned to
120		// 16 byte.
121}
122
123
124static uint8*
125get_signal_stack(Thread* thread, struct iframe* frame, struct sigaction* action,
126	size_t spaceNeeded)
127{
128	// use the alternate signal stack if we should and can
129	if (thread->signal_stack_enabled
130		&& (action->sa_flags & SA_ONSTACK) != 0
131		&& (frame->user_sp < thread->signal_stack_base
132			|| frame->user_sp >= thread->signal_stack_base
133				+ thread->signal_stack_size)) {
134		addr_t stackTop = thread->signal_stack_base + thread->signal_stack_size;
135		return (uint8*)arch_randomize_stack_pointer(stackTop - spaceNeeded);
136	}
137
138	return (uint8*)((frame->user_sp - spaceNeeded) & ~addr_t(0xf)) - 4;
139		// align stack pointer (cf. arch_randomize_stack_pointer())
140}
141
142
143//	#pragma mark -
144
145
146status_t
147arch_thread_init(struct kernel_args *args)
148{
149	// save one global valid FPU state; it will be copied in the arch dependent
150	// part of each new thread
151
152	asm volatile ("clts; fninit; fnclex;");
153	if (gHasSSE)
154		x86_fxsave(sInitialState.fpu_state);
155	else
156		x86_fnsave(sInitialState.fpu_state);
157
158	return B_OK;
159}
160
161
162status_t
163arch_thread_init_thread_struct(Thread *thread)
164{
165	// set up an initial state (stack & fpu)
166	memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread));
167	return B_OK;
168}
169
170
171/*!	Prepares the given thread's kernel stack for executing its entry function.
172
173	\param thread The thread.
174	\param stack The usable bottom of the thread's kernel stack.
175	\param stackTop The usable top of the thread's kernel stack.
176	\param function The entry function the thread shall execute.
177	\param data Pointer to be passed to the entry function.
178*/
179void
180arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
181	void (*function)(void*), const void* data)
182{
183	addr_t* stackTop = (addr_t*)_stackTop;
184
185	TRACE(("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
186		"%p\n", stackTop, function, data));
187
188	// push the function argument, a pointer to the data
189	*--stackTop = (addr_t)data;
190
191	// push a dummy return address for the function
192	*--stackTop = 0;
193
194	// push the function address -- that's the return address used after the
195	// context switch
196	*--stackTop = (addr_t)function;
197
198	// simulate pushad as done by x86_context_switch()
199	for (int i = 0; i < 8; i++)
200		*--stackTop = 0;
201
202	// save the stack position
203	thread->arch_info.current_stack.esp = stackTop;
204	thread->arch_info.current_stack.ss = (addr_t*)KERNEL_DATA_SELECTOR;
205}
206
207
208void
209arch_thread_dump_info(void *info)
210{
211	struct arch_thread *at = (struct arch_thread *)info;
212
213	kprintf("\tesp: %p\n", at->current_stack.esp);
214	kprintf("\tss: %p\n", at->current_stack.ss);
215	kprintf("\tfpu_state at %p\n", at->fpu_state);
216}
217
218
219/*!	Sets up initial thread context and enters user space
220*/
221status_t
222arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
223	void* args2)
224{
225	addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
226	uint32 args[3];
227
228	TRACE(("arch_thread_enter_userspace: entry 0x%lx, args %p %p, "
229		"ustack_top 0x%lx\n", entry, args1, args2, stackTop));
230
231	stackTop = arch_randomize_stack_pointer(stackTop - sizeof(args));
232
233	// Copy the address of the stub that calls exit_thread() when the thread
234	// entry function returns to the top of the stack to act as the return
235	// address. The stub is inside commpage.
236	addr_t commPageAddress = (addr_t)thread->team->commpage_address;
237	args[0] = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
238		+ commPageAddress;
239	args[1] = (uint32)args1;
240	args[2] = (uint32)args2;
241
242	if (user_memcpy((void *)stackTop, args, sizeof(args)) < B_OK)
243		return B_BAD_ADDRESS;
244
245	// prepare the user iframe
246	iframe frame = {};
247	frame.type = IFRAME_TYPE_SYSCALL;
248	frame.gs = USER_DATA_SELECTOR;
249	// frame.fs not used, we call x86_set_tls_context() on context switch
250	frame.es = USER_DATA_SELECTOR;
251	frame.ds = USER_DATA_SELECTOR;
252	frame.ip = entry;
253	frame.cs = USER_CODE_SELECTOR;
254	frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
255		| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
256	frame.user_sp = stackTop;
257	frame.user_ss = USER_DATA_SELECTOR;
258
259	// return to userland
260	x86_initial_return_to_userland(thread, &frame);
261
262	return B_OK;
263		// never gets here
264}
265
266
267/*!	Sets up the user iframe for invoking a signal handler.
268
269	The function fills in the remaining fields of the given \a signalFrameData,
270	copies it to the thread's userland stack (the one on which the signal shall
271	be handled), and sets up the user iframe so that when returning to userland
272	a wrapper function is executed that calls the user-defined signal handler.
273	When the signal handler returns, the wrapper function shall call the
274	"restore signal frame" syscall with the (possibly modified) signal frame
275	data.
276
277	The following fields of the \a signalFrameData structure still need to be
278	filled in:
279	- \c context.uc_stack: The stack currently used by the thread.
280	- \c context.uc_mcontext: The current userland state of the registers.
281	- \c syscall_restart_return_value: Architecture specific use. On x86 the
282		value of eax and edx which are overwritten by the syscall return value.
283
284	Furthermore the function needs to set \c thread->user_signal_context to the
285	userland pointer to the \c ucontext_t on the user stack.
286
287	\param thread The current thread.
288	\param action The signal action specified for the signal to be handled.
289	\param signalFrameData A partially initialized structure of all the data
290		that need to be copied to userland.
291	\return \c B_OK on success, another error code, if something goes wrong.
292*/
293status_t
294arch_setup_signal_frame(Thread* thread, struct sigaction* action,
295	struct signal_frame_data* signalFrameData)
296{
297	struct iframe *frame = x86_get_current_iframe();
298	if (!IFRAME_IS_USER(frame)) {
299		panic("arch_setup_signal_frame(): No user iframe!");
300		return B_BAD_VALUE;
301	}
302
303	// In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
304	// had the same signal number.
305	if ((action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0
306		&& signalFrameData->info.si_signo == SIGBUS) {
307		signalFrameData->info.si_signo = SIGSEGV;
308	}
309
310	// store the register state in signalFrameData->context.uc_mcontext
311	signalFrameData->context.uc_mcontext.eip = frame->ip;
312	signalFrameData->context.uc_mcontext.eflags = frame->flags;
313	signalFrameData->context.uc_mcontext.eax = frame->ax;
314	signalFrameData->context.uc_mcontext.ecx = frame->cx;
315	signalFrameData->context.uc_mcontext.edx = frame->dx;
316	signalFrameData->context.uc_mcontext.ebp = frame->bp;
317	signalFrameData->context.uc_mcontext.esp = frame->user_sp;
318	signalFrameData->context.uc_mcontext.edi = frame->di;
319	signalFrameData->context.uc_mcontext.esi = frame->si;
320	signalFrameData->context.uc_mcontext.ebx = frame->bx;
321	x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
322
323	// Fill in signalFrameData->context.uc_stack
324	signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
325
326	// store orig_eax/orig_edx in syscall_restart_return_value
327	signalFrameData->syscall_restart_return_value
328		= (uint64)frame->orig_edx << 32 | frame->orig_eax;
329
330	// get the stack to use -- that's either the current one or a special signal
331	// stack
332	uint32 stackFrame[2];
333	uint8* userStack = get_signal_stack(thread, frame, action,
334		sizeof(*signalFrameData) + sizeof(stackFrame));
335
336	// copy the signal frame data onto the stack
337	signal_frame_data* userSignalFrameData
338		= (signal_frame_data*)(userStack + sizeof(stackFrame));
339	if (user_memcpy(userSignalFrameData, signalFrameData,
340			sizeof(*signalFrameData)) != B_OK) {
341		return B_BAD_ADDRESS;
342	}
343
344	// prepare the user stack frame for a function call to the signal handler
345	// wrapper function
346	stackFrame[0] = frame->ip;
347	stackFrame[1] = (addr_t)userSignalFrameData;
348		// parameter: pointer to signal frame data
349
350	if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
351		return B_BAD_ADDRESS;
352
353	// Update Thread::user_signal_context, now that everything seems to have
354	// gone fine.
355	thread->user_signal_context = &userSignalFrameData->context;
356
357	// Adjust the iframe's esp and eip, so that the thread will continue with
358	// the prepared stack, executing the signal handler wrapper function.
359	frame->user_sp = (addr_t)userStack;
360	frame->ip = x86_get_user_signal_handler_wrapper(
361		(action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0,
362		thread->team->commpage_address);
363
364	return B_OK;
365}
366
367
368int64
369arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
370{
371	struct iframe* frame = x86_get_current_iframe();
372
373	TRACE(("### arch_restore_signal_frame: entry\n"));
374
375	frame->orig_eax = (uint32)signalFrameData->syscall_restart_return_value;
376	frame->orig_edx
377		= (uint32)(signalFrameData->syscall_restart_return_value >> 32);
378
379	frame->ip = signalFrameData->context.uc_mcontext.eip;
380	frame->flags = (frame->flags & ~(uint32)X86_EFLAGS_USER_FLAGS)
381		| (signalFrameData->context.uc_mcontext.eflags & X86_EFLAGS_USER_FLAGS);
382	frame->ax = signalFrameData->context.uc_mcontext.eax;
383	frame->cx = signalFrameData->context.uc_mcontext.ecx;
384	frame->dx = signalFrameData->context.uc_mcontext.edx;
385	frame->bp = signalFrameData->context.uc_mcontext.ebp;
386	frame->user_sp = signalFrameData->context.uc_mcontext.esp;
387	frame->di = signalFrameData->context.uc_mcontext.edi;
388	frame->si = signalFrameData->context.uc_mcontext.esi;
389	frame->bx = signalFrameData->context.uc_mcontext.ebx;
390
391	x86_frstor((void*)(&signalFrameData->context.uc_mcontext.xregs));
392
393	TRACE(("### arch_restore_signal_frame: exit\n"));
394
395	return (int64)frame->ax | ((int64)frame->dx << 32);
396}
397
398
399void
400arch_syscall_64_bit_return_value(void)
401{
402	Thread* thread = thread_get_current_thread();
403	atomic_or(&thread->flags, THREAD_FLAGS_64_BIT_SYSCALL_RETURN);
404}
405