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	frame.user_sp = stackTop;
256	frame.user_ss = USER_DATA_SELECTOR;
257
258	// return to userland
259	x86_initial_return_to_userland(thread, &frame);
260
261	return B_OK;
262		// never gets here
263}
264
265
266/*!	Sets up the user iframe for invoking a signal handler.
267
268	The function fills in the remaining fields of the given \a signalFrameData,
269	copies it to the thread's userland stack (the one on which the signal shall
270	be handled), and sets up the user iframe so that when returning to userland
271	a wrapper function is executed that calls the user-defined signal handler.
272	When the signal handler returns, the wrapper function shall call the
273	"restore signal frame" syscall with the (possibly modified) signal frame
274	data.
275
276	The following fields of the \a signalFrameData structure still need to be
277	filled in:
278	- \c context.uc_stack: The stack currently used by the thread.
279	- \c context.uc_mcontext: The current userland state of the registers.
280	- \c syscall_restart_return_value: Architecture specific use. On x86 the
281		value of eax and edx which are overwritten by the syscall return value.
282
283	Furthermore the function needs to set \c thread->user_signal_context to the
284	userland pointer to the \c ucontext_t on the user stack.
285
286	\param thread The current thread.
287	\param action The signal action specified for the signal to be handled.
288	\param signalFrameData A partially initialized structure of all the data
289		that need to be copied to userland.
290	\return \c B_OK on success, another error code, if something goes wrong.
291*/
292status_t
293arch_setup_signal_frame(Thread* thread, struct sigaction* action,
294	struct signal_frame_data* signalFrameData)
295{
296	struct iframe *frame = x86_get_current_iframe();
297	if (!IFRAME_IS_USER(frame)) {
298		panic("arch_setup_signal_frame(): No user iframe!");
299		return B_BAD_VALUE;
300	}
301
302	// In case of a BeOS compatible handler map SIGBUS to SIGSEGV, since they
303	// had the same signal number.
304	if ((action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0
305		&& signalFrameData->info.si_signo == SIGBUS) {
306		signalFrameData->info.si_signo = SIGSEGV;
307	}
308
309	// store the register state in signalFrameData->context.uc_mcontext
310	signalFrameData->context.uc_mcontext.eip = frame->ip;
311	signalFrameData->context.uc_mcontext.eflags = frame->flags;
312	signalFrameData->context.uc_mcontext.eax = frame->ax;
313	signalFrameData->context.uc_mcontext.ecx = frame->cx;
314	signalFrameData->context.uc_mcontext.edx = frame->dx;
315	signalFrameData->context.uc_mcontext.ebp = frame->bp;
316	signalFrameData->context.uc_mcontext.esp = frame->user_sp;
317	signalFrameData->context.uc_mcontext.edi = frame->di;
318	signalFrameData->context.uc_mcontext.esi = frame->si;
319	signalFrameData->context.uc_mcontext.ebx = frame->bx;
320	x86_fnsave((void *)(&signalFrameData->context.uc_mcontext.xregs));
321
322	// Fill in signalFrameData->context.uc_stack
323	signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
324
325	// store orig_eax/orig_edx in syscall_restart_return_value
326	signalFrameData->syscall_restart_return_value
327		= (uint64)frame->orig_edx << 32 | frame->orig_eax;
328
329	// get the stack to use -- that's either the current one or a special signal
330	// stack
331	uint32 stackFrame[2];
332	uint8* userStack = get_signal_stack(thread, frame, action,
333		sizeof(*signalFrameData) + sizeof(stackFrame));
334
335	// copy the signal frame data onto the stack
336	signal_frame_data* userSignalFrameData
337		= (signal_frame_data*)(userStack + sizeof(stackFrame));
338	if (user_memcpy(userSignalFrameData, signalFrameData,
339			sizeof(*signalFrameData)) != B_OK) {
340		return B_BAD_ADDRESS;
341	}
342
343	// prepare the user stack frame for a function call to the signal handler
344	// wrapper function
345	stackFrame[0] = frame->ip;
346	stackFrame[1] = (addr_t)userSignalFrameData;
347		// parameter: pointer to signal frame data
348
349	if (user_memcpy(userStack, stackFrame, sizeof(stackFrame)) != B_OK)
350		return B_BAD_ADDRESS;
351
352	// Update Thread::user_signal_context, now that everything seems to have
353	// gone fine.
354	thread->user_signal_context = &userSignalFrameData->context;
355
356	// Adjust the iframe's esp and eip, so that the thread will continue with
357	// the prepared stack, executing the signal handler wrapper function.
358	frame->user_sp = (addr_t)userStack;
359	frame->ip = x86_get_user_signal_handler_wrapper(
360		(action->sa_flags & SA_BEOS_COMPATIBLE_HANDLER) != 0,
361		thread->team->commpage_address);
362	frame->flags &= ~(X86_EFLAGS_TRAP | X86_EFLAGS_DIRECTION);
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