xref: /haiku/src/system/kernel/arch/x86/32/thread.cpp (revision 2510baa4685f8f570c607ceedfd73473d69342c4)
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 
44 namespace SyscallTracing {
45 
46 class 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
69 extern bool gHasSSE;
70 extern segment_descriptor* gGDT;
71 
72 static 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 
76 static inline void
77 set_fs_register(uint32 segment)
78 {
79 	asm("movl %0,%%fs" :: "r" (segment));
80 }
81 
82 
83 void
84 x86_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 
101 void
102 x86_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 
111 static uint8*
112 get_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 
130 status_t
131 arch_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 
146 status_t
147 arch_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 */
163 void
164 arch_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 
192 void
193 arch_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 */
205 status_t
206 arch_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 */
280 status_t
281 arch_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 
354 int64
355 arch_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 
385 void
386 arch_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