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