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