btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / arch / x86 / 64 / thread.cpp
blob9e535fefbeb067501732529286c453713e63d185
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.
6 * Copyright 2001, Travis Geiselbrecht. All rights reserved.
7 * Distributed under the terms of the NewOS License.
8 */
11 #include <arch/thread.h>
13 #include <string.h>
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>
29 #include "paging/X86PagingStructures.h"
30 #include "paging/X86VMTranslationMap.h"
33 //#define TRACE_ARCH_THREAD
34 #ifdef TRACE_ARCH_THREAD
35 # define TRACE(x...) dprintf(x)
36 #else
37 # define TRACE(x...) ;
38 #endif
41 #ifdef SYSCALL_TRACING
43 namespace SyscallTracing {
45 class RestartSyscall : public AbstractTraceEntry {
46 public:
47 RestartSyscall()
49 Initialized();
52 virtual void AddDump(TraceOutput& out)
54 out.Print("syscall restart");
60 # define TSYSCALL(x) new(std::nothrow) SyscallTracing::x
62 #else
63 # define TSYSCALL(x)
64 #endif // SYSCALL_TRACING
67 extern "C" void x86_64_thread_entry();
69 // Initial thread saved state.
70 static arch_thread sInitialState;
73 void
74 x86_restart_syscall(iframe* frame)
76 Thread* thread = thread_get_current_thread();
78 atomic_and(&thread->flags, ~THREAD_FLAGS_RESTART_SYSCALL);
79 atomic_or(&thread->flags, THREAD_FLAGS_SYSCALL_RESTARTED);
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;
86 TSYSCALL(RestartSyscall());
90 void
91 x86_set_tls_context(Thread* thread)
93 // Set FS segment base address to the TLS segment.
94 x86_write_msr(IA32_MSR_FS_BASE, thread->user_local_storage);
98 static addr_t
99 arch_randomize_stack_pointer(addr_t value)
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);
108 static uint8*
109 get_signal_stack(Thread* thread, iframe* frame, struct sigaction* action)
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);
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);
129 // #pragma mark -
132 status_t
133 arch_thread_init(kernel_args* args)
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;
147 status_t
148 arch_thread_init_thread_struct(Thread* thread)
150 // Copy the initial saved FPU state to the new thread.
151 memcpy(&thread->arch_info, &sInitialState, sizeof(arch_thread));
153 // Initialise the current thread pointer.
154 thread->arch_info.thread = thread;
156 return B_OK;
160 /*! Prepares the given thread's kernel stack for executing its entry function.
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.
168 void
169 arch_thread_init_kthread_stack(Thread* thread, void* _stack, void* _stackTop,
170 void (*function)(void*), const void* data)
172 uintptr_t* stackTop = static_cast<uintptr_t*>(_stackTop);
174 TRACE("arch_thread_init_kthread_stack: stack top %p, function %p, data: "
175 "%p\n", _stackTop, function, data);
177 // Save the stack top for system call entry.
178 thread->arch_info.syscall_rsp = (uint64*)thread->kernel_stack_top;
180 thread->arch_info.instruction_pointer
181 = reinterpret_cast<uintptr_t>(x86_64_thread_entry);
183 *--stackTop = uintptr_t(data);
184 *--stackTop = uintptr_t(function);
186 // Save the stack position.
187 thread->arch_info.current_stack = stackTop;
191 void
192 arch_thread_dump_info(void* info)
194 arch_thread* thread = (arch_thread*)info;
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);
203 /*! Sets up initial thread context and enters user space
205 status_t
206 arch_thread_enter_userspace(Thread* thread, addr_t entry, void* args1,
207 void* args2)
209 addr_t stackTop = thread->user_stack_base + thread->user_stack_size;
211 TRACE("arch_thread_enter_userspace: entry %#lx, args %p %p, "
212 "stackTop %#lx\n", entry, args1, args2, stackTop);
214 stackTop = arch_randomize_stack_pointer(stackTop);
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;
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;
239 // Return to userland. Never returns.
240 x86_initial_return_to_userland(thread, &frame);
242 return B_OK;
246 /*! Sets up the user iframe for invoking a signal handler.
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.
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.
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.
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.
272 status_t
273 arch_setup_signal_frame(Thread* thread, struct sigaction* action,
274 struct signal_frame_data* signalFrameData)
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;
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;
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));
311 // Fill in signalFrameData->context.uc_stack.
312 signal_get_user_stack(frame->user_sp, &signalFrameData->context.uc_stack);
314 // Store syscall_restart_return_value.
315 signalFrameData->syscall_restart_return_value = frame->orig_rax;
317 // Get the stack to use and copy the frame data to it.
318 uint8* userStack = get_signal_stack(thread, frame, action);
320 userStack -= sizeof(*signalFrameData);
321 signal_frame_data* userSignalFrameData = (signal_frame_data*)userStack;
323 if (user_memcpy(userSignalFrameData, signalFrameData,
324 sizeof(*signalFrameData)) != B_OK) {
325 return B_BAD_ADDRESS;
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;
333 // Update Thread::user_signal_context, now that everything seems to have
334 // gone fine.
335 thread->user_signal_context = &userSignalFrameData->context;
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;
345 return B_OK;
349 int64
350 arch_restore_signal_frame(struct signal_frame_data* signalFrameData)
352 iframe* frame = x86_get_current_iframe();
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);
375 Thread* thread = thread_get_current_thread();
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;
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;