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