xref: /haiku/src/system/kernel/arch/x86/32/thread.cpp (revision fc7456e9b1ec38c941134ed6d01c438cf289381e)
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 
46 namespace SyscallTracing {
47 
48 class 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
71 extern bool gHasSSE;
72 
73 static 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 
77 static inline void
78 set_fs_register(uint32 segment)
79 {
80 	asm("movl %0,%%fs" :: "r" (segment));
81 }
82 
83 
84 void
85 x86_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 
102 void
103 x86_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 
112 static addr_t
113 arch_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 
124 static uint8*
125 get_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 
146 status_t
147 arch_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 
162 status_t
163 arch_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 */
179 void
180 arch_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 = (uint32*)stackTop;
204 	thread->arch_info.current_stack.ss = (uint32*)KERNEL_DATA_SELECTOR;
205 }
206 
207 
208 void
209 arch_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 */
221 status_t
222 arch_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 */
292 status_t
293 arch_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 
368 int64
369 arch_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 
399 void
400 arch_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