xref: /haiku/src/system/kernel/arch/x86/64/thread.cpp (revision bf57c148f7787f0df15980976997c6dfb70ee067)
1 /*
2  * Copyright 2012, Alex Smith, alex@alex-smith.me.uk.
3  * Copyright 2002-2008, Axel Dörfler, axeld@pinc-software.de.
4  * Distributed under the terms of the MIT License.
5  *
6  * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7  * Distributed under the terms of the NewOS License.
8  */
9 
10 
11 #include <arch/thread.h>
12 
13 #include <string.h>
14 
15 #include <commpage.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/Random.h>
26 #include <vm/vm_types.h>
27 #include <vm/VMAddressSpace.h>
28 
29 #include "paging/X86PagingStructures.h"
30 #include "paging/X86VMTranslationMap.h"
31 
32 
33 //#define TRACE_ARCH_THREAD
34 #ifdef TRACE_ARCH_THREAD
35 #	define TRACE(x...) dprintf(x)
36 #else
37 #	define TRACE(x...) ;
38 #endif
39 
40 
41 #ifdef SYSCALL_TRACING
42 
43 namespace SyscallTracing {
44 
45 class RestartSyscall : public AbstractTraceEntry {
46 	public:
47 		RestartSyscall()
48 		{
49 			Initialized();
50 		}
51 
52 		virtual void AddDump(TraceOutput& out)
53 		{
54 			out.Print("syscall restart");
55 		}
56 };
57 
58 }
59 
60 #	define TSYSCALL(x)	new(std::nothrow) SyscallTracing::x
61 
62 #else
63 #	define TSYSCALL(x)
64 #endif	// SYSCALL_TRACING
65 
66 
67 extern "C" void x86_64_thread_entry();
68 
69 // Initial thread saved state.
70 static arch_thread sInitialState;
71 
72 
73 void
74 x86_restart_syscall(iframe* frame)
75 {
76 	Thread* thread = thread_get_current_thread();
77 
78 	atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
79 	atomic_or(&thread->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
80 
81 	// Get back the original system call number and modify the frame to
82 	// re-execute the syscall instruction.
83 	frame->ax = frame->orig_rax;
84 	frame->ip -= 2;
85 
86 	TSYSCALL(RestartSyscall());
87 }
88 
89 
90 void
91 x86_set_tls_context(Thread* thread)
92 {
93 	// Set FS segment base address to the TLS segment.
94 	x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
95 }
96 
97 
98 static addr_t
99 arch_randomize_stack_pointer(addr_t value)
100 {
101 	static_assert(MAX_RANDOM_VALUE >= B_PAGE_SIZE - 1,
102 		"randomization range is too big");
103 	value -= random_value() & (B_PAGE_SIZE - 1);
104 	return value & ~addr_t(0xf);
105 }
106 
107 
108 static uint8*
109 get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action)
110 {
111 	// Use the alternate signal stack if we should and can.
112 	if (thread->signal_stack_enabled
113 			&& (action->sa_flags & SA_ONSTACK) != 0
114 			&& (frame->user_sp < thread->signal_stack_base
115 				|| frame->user_sp >= thread->signal_stack_base
116 					+ thread->signal_stack_size)) {
117 		addr_t stackTop = thread->signal_stack_base + thread->signal_stack_size;
118 		return (uint8*)arch_randomize_stack_pointer(stackTop);
119 	}
120 
121 	// We are going to use the stack that we are already on. We must not touch
122 	// the red zone (128 byte area below the stack pointer, reserved for use
123 	// by functions to store temporary data and guaranteed not to be modified
124 	// by signal handlers).
125 	return (uint8*)(frame->user_sp - 128);
126 }
127 
128 
129 //	#pragma mark -
130 
131 
132 status_t
133 arch_thread_init(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 	asm volatile (
138 		"clts;"		\
139 		"fninit;"	\
140 		"fnclex;"	\
141 		"fxsave %0;"
142 		: "=m" (sInitialState.fpu_state));
143 	return B_OK;
144 }
145 
146 
147 status_t
148 arch_thread_init_thread_struct(Thread* thread)
149 {
150 	// Copy the initial saved FPU state to the new thread.
151 	memcpy(&thread->arch_info, &sInitialState, sizeof(arch_thread));
152 
153 	// Initialise the current thread pointer.
154 	thread->arch_info.thread = thread;
155 
156 	return B_OK;
157 }
158 
159 
160 /*!	Prepares the given thread's kernel stack for executing its entry function.
161 
162 	\param thread The thread.
163 	\param stack The usable bottom of the thread's kernel stack.
164 	\param stackTop The usable top of the thread's kernel stack.
165 	\param function The entry function the thread shall execute.
166 	\param data Pointer to be passed to the entry function.
167 */
168 void
169 arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
170 	void (*function)(void*), const void* data)
171 {
172 	uintptr_t* stackTop = static_cast<uintptr_t*>(_stackTop);
173 
174 	TRACE("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
175 		"%p\n", _stackTop, function, data);
176 
177 	// Save the stack top for system call entry.
178 	thread->arch_info.syscall_rsp = (uint64*)thread->kernel_stack_top;
179 
180 	thread->arch_info.instruction_pointer
181 		= reinterpret_cast<uintptr_t>(x86_64_thread_entry);
182 
183 	*--stackTop = uintptr_t(data);
184 	*--stackTop = uintptr_t(function);
185 
186 	// Save the stack position.
187 	thread->arch_info.current_stack = stackTop;
188 }
189 
190 
191 void
192 arch_thread_dump_info(void* info)
193 {
194 	arch_thread* thread = (arch_thread*)info;
195 
196 	kprintf("\trsp: %p\n", thread->current_stack);
197 	kprintf("\tsyscall_rsp: %p\n", thread->syscall_rsp);
198 	kprintf("\tuser_rsp: %p\n", thread->user_rsp);
199 	kprintf("\tfpu_state at %p\n", thread->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 
211 	TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
212 		"stackTop %#lx\n", entry, args1, args2, stackTop);
213 
214 	stackTop = arch_randomize_stack_pointer(stackTop);
215 
216 	// Copy the address of the stub that calls exit_thread() when the thread
217 	// entry function returns to the top of the stack to act as the return
218 	// address. The stub is inside commpage.
219 	addr_t commPageAddress = (addr_t)thread->team->commpage_address;
220 	addr_t codeAddr = ((addr_t*)commPageAddress)[COMMPAGE_ENTRY_X86_THREAD_EXIT]
221 		+ commPageAddress;
222 	stackTop -= sizeof(codeAddr);
223 	if (user_memcpy((void*)stackTop, (const void*)&codeAddr, sizeof(codeAddr))
224 			!= B_OK)
225 		return B_BAD_ADDRESS;
226 
227 	// Prepare the user iframe.
228 	iframe frame = {};
229 	frame.type = IFRAME_TYPE_SYSCALL;
230 	frame.si = (uint64)args2;
231 	frame.di = (uint64)args1;
232 	frame.ip = entry;
233 	frame.cs = USER_CODE_SELECTOR;
234 	frame.flags = X86_EFLAGS_RESERVED1 | X86_EFLAGS_INTERRUPT
235 		| (3 << X86_EFLAGS_IO_PRIVILEG_LEVEL_SHIFT);
236 	frame.sp = stackTop;
237 	frame.ss = USER_DATA_SELECTOR;
238 
239 	// Return to userland. Never returns.
240 	x86_initial_return_to_userland(thread, &frame);
241 
242 	return B_OK;
243 }
244 
245 
246 /*!	Sets up the user iframe for invoking a signal handler.
247 
248 	The function fills in the remaining fields of the given \a signalFrameData,
249 	copies it to the thread's userland stack (the one on which the signal shall
250 	be handled), and sets up the user iframe so that when returning to userland
251 	a wrapper function is executed that calls the user-defined signal handler.
252 	When the signal handler returns, the wrapper function shall call the
253 	"restore signal frame" syscall with the (possibly modified) signal frame
254 	data.
255 
256 	The following fields of the \a signalFrameData structure still need to be
257 	filled in:
258 	- \c context.uc_stack: The stack currently used by the thread.
259 	- \c context.uc_mcontext: The current userland state of the registers.
260 	- \c syscall_restart_return_value: Architecture specific use. On x86_64 the
261 		value of rax which is overwritten by the syscall return value.
262 
263 	Furthermore the function needs to set \c thread->user_signal_context to the
264 	userland pointer to the \c ucontext_t on the user stack.
265 
266 	\param thread The current thread.
267 	\param action The signal action specified for the signal to be handled.
268 	\param signalFrameData A partially initialized structure of all the data
269 		that need to be copied to userland.
270 	\return \c B_OK on success, another error code, if something goes wrong.
271 */
272 status_t
273 arch_setup_signal_frame(Thread* thread, struct sigaction* action,
274 	struct signal_frame_data* signalFrameData)
275 {
276 	iframe* frame = x86_get_current_iframe();
277 	if (!IFRAME_IS_USER(frame)) {
278 		panic("arch_setup_signal_frame(): No user iframe!");
279 		return B_BAD_VALUE;
280 	}
281 
282 	// Store the register state.
283 	signalFrameData->context.uc_mcontext.rax = frame->ax;
284 	signalFrameData->context.uc_mcontext.rbx = frame->bx;
285 	signalFrameData->context.uc_mcontext.rcx = frame->cx;
286 	signalFrameData->context.uc_mcontext.rdx = frame->dx;
287 	signalFrameData->context.uc_mcontext.rdi = frame->di;
288 	signalFrameData->context.uc_mcontext.rsi = frame->si;
289 	signalFrameData->context.uc_mcontext.rbp = frame->bp;
290 	signalFrameData->context.uc_mcontext.r8 = frame->r8;
291 	signalFrameData->context.uc_mcontext.r9 = frame->r9;
292 	signalFrameData->context.uc_mcontext.r10 = frame->r10;
293 	signalFrameData->context.uc_mcontext.r11 = frame->r11;
294 	signalFrameData->context.uc_mcontext.r12 = frame->r12;
295 	signalFrameData->context.uc_mcontext.r13 = frame->r13;
296 	signalFrameData->context.uc_mcontext.r14 = frame->r14;
297 	signalFrameData->context.uc_mcontext.r15 = frame->r15;
298 	signalFrameData->context.uc_mcontext.rsp = frame->user_sp;
299 	signalFrameData->context.uc_mcontext.rip = frame->ip;
300 	signalFrameData->context.uc_mcontext.rflags = frame->flags;
301 
302 	if (frame->fpu != nullptr) {
303 		memcpy((void*)&signalFrameData->context.uc_mcontext.fpu, frame->fpu,
304 			sizeof(signalFrameData->context.uc_mcontext.fpu));
305 	} else {
306 		memcpy((void*)&signalFrameData->context.uc_mcontext.fpu,
307 			sInitialState.fpu_state,
308 			sizeof(signalFrameData->context.uc_mcontext.fpu));
309 	}
310 
311 	// Fill in signalFrameData->context.uc_stack.
312 	signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
313 
314 	// Store syscall_restart_return_value.
315 	signalFrameData->syscall_restart_return_value = frame->orig_rax;
316 
317 	// Get the stack to use and copy the frame data to it.
318 	uint8* userStack = get_signal_stack(thread, frame, action);
319 
320 	userStack -= sizeof(*signalFrameData);
321 	signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
322 
323 	if (user_memcpy(userSignalFrameData, signalFrameData,
324 			sizeof(*signalFrameData)) != B_OK) {
325 		return B_BAD_ADDRESS;
326 	}
327 
328 	// Copy a return address to the stack so that backtraces will be correct.
329 	userStack -= sizeof(frame->ip);
330 	if (user_memcpy(userStack, &frame->ip, sizeof(frame->ip)) != B_OK)
331 		return B_BAD_ADDRESS;
332 
333 	// Update Thread::user_signal_context, now that everything seems to have
334 	// gone fine.
335 	thread->user_signal_context = &userSignalFrameData->context;
336 
337 	// Set up the iframe to execute the signal handler wrapper on our prepared
338 	// stack. First argument points to the frame data.
339 	addr_t* commPageAddress = (addr_t*)thread->team->commpage_address;
340 	frame->user_sp = (addr_t)userStack;
341 	frame->ip = commPageAddress[COMMPAGE_ENTRY_X86_SIGNAL_HANDLER]
342 		+ (addr_t)commPageAddress;
343 	frame->di = (addr_t)userSignalFrameData;
344 
345 	return B_OK;
346 }
347 
348 
349 int64
350 arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
351 {
352 	iframe* frame = x86_get_current_iframe();
353 
354 	frame->orig_rax = signalFrameData->syscall_restart_return_value;
355 	frame->ax = signalFrameData->context.uc_mcontext.rax;
356 	frame->bx = signalFrameData->context.uc_mcontext.rbx;
357 	frame->cx = signalFrameData->context.uc_mcontext.rcx;
358 	frame->dx = signalFrameData->context.uc_mcontext.rdx;
359 	frame->di = signalFrameData->context.uc_mcontext.rdi;
360 	frame->si = signalFrameData->context.uc_mcontext.rsi;
361 	frame->bp = signalFrameData->context.uc_mcontext.rbp;
362 	frame->r8 = signalFrameData->context.uc_mcontext.r8;
363 	frame->r9 = signalFrameData->context.uc_mcontext.r9;
364 	frame->r10 = signalFrameData->context.uc_mcontext.r10;
365 	frame->r11 = signalFrameData->context.uc_mcontext.r11;
366 	frame->r12 = signalFrameData->context.uc_mcontext.r12;
367 	frame->r13 = signalFrameData->context.uc_mcontext.r13;
368 	frame->r14 = signalFrameData->context.uc_mcontext.r14;
369 	frame->r15 = signalFrameData->context.uc_mcontext.r15;
370 	frame->user_sp = signalFrameData->context.uc_mcontext.rsp;
371 	frame->ip = signalFrameData->context.uc_mcontext.rip;
372 	frame->flags = (frame->flags & ~(uint64)X86_EFLAGS_USER_FLAGS)
373 		| (signalFrameData->context.uc_mcontext.rflags & X86_EFLAGS_USER_FLAGS);
374 
375 	Thread* thread = thread_get_current_thread();
376 
377 	memcpy(thread->arch_info.fpu_state,
378 		(void*)&signalFrameData->context.uc_mcontext.fpu,
379 		sizeof(thread->arch_info.fpu_state));
380 	frame->fpu = &thread->arch_info.fpu_state;
381 
382 	// The syscall return code overwrites frame->ax with the return value of
383 	// the syscall, need to return it here to ensure the correct value is
384 	// restored.
385 	return frame->ax;
386 }
387