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