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