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_cpu.h> 15 #include <cpu.h> 16 #include <kernel.h> 17 #include <ksignal.h> 18 #include <int.h> 19 #include <team.h> 20 #include <thread.h> 21 #include <tls.h> 22 #include <vm/vm_types.h> 23 #include <vm/VMAddressSpace.h> 24 25 #include "paging/X86PagingStructures.h" 26 #include "paging/X86VMTranslationMap.h" 27 #include "x86_syscalls.h" 28 29 30 // from arch_interrupts.S 31 extern "C" void x86_return_to_userland(iframe* frame); 32 33 // from arch_cpu.cpp 34 #ifndef __x86_64__ 35 extern void (*gX86SwapFPUFunc)(void *oldState, const void *newState); 36 #endif 37 38 39 static struct iframe* 40 find_previous_iframe(Thread* thread, addr_t frame) 41 { 42 // iterate backwards through the stack frames, until we hit an iframe 43 while (frame >= thread->kernel_stack_base 44 && frame < thread->kernel_stack_top) { 45 addr_t previousFrame = *(addr_t*)frame; 46 if ((previousFrame & ~(addr_t)IFRAME_TYPE_MASK) == 0) { 47 if (previousFrame == 0) 48 return NULL; 49 return (struct iframe*)frame; 50 } 51 52 frame = previousFrame; 53 } 54 55 return NULL; 56 } 57 58 59 static struct iframe* 60 get_previous_iframe(struct iframe* frame) 61 { 62 if (frame == NULL) 63 return NULL; 64 65 return find_previous_iframe(thread_get_current_thread(), frame->bp); 66 } 67 68 69 /*! 70 Returns the current iframe structure of the running thread. 71 This function must only be called in a context where it's actually 72 sure that such iframe exists; ie. from syscalls, but usually not 73 from standard kernel threads. 74 */ 75 static struct iframe* 76 get_current_iframe(void) 77 { 78 return find_previous_iframe(thread_get_current_thread(), 79 x86_get_stack_frame()); 80 } 81 82 83 /*! 84 \brief Returns the current thread's topmost (i.e. most recent) 85 userland->kernel transition iframe (usually the first one, save for 86 interrupts in signal handlers). 87 \return The iframe, or \c NULL, if there is no such iframe (e.g. when 88 the thread is a kernel thread). 89 */ 90 struct iframe* 91 x86_get_user_iframe(void) 92 { 93 struct iframe* frame = get_current_iframe(); 94 95 while (frame != NULL) { 96 if (IFRAME_IS_USER(frame)) 97 return frame; 98 frame = get_previous_iframe(frame); 99 } 100 101 return NULL; 102 } 103 104 105 /*! \brief Like x86_get_user_iframe(), just for the given thread. 106 The thread must not be running and the threads spinlock must be held. 107 */ 108 struct iframe* 109 x86_get_thread_user_iframe(Thread *thread) 110 { 111 if (thread->state == B_THREAD_RUNNING) 112 return NULL; 113 114 // find the user iframe 115 struct iframe* frame = find_previous_iframe(thread, 116 thread->arch_info.GetFramePointer()); 117 118 while (frame != NULL) { 119 if (IFRAME_IS_USER(frame)) 120 return frame; 121 frame = get_previous_iframe(frame); 122 } 123 124 return NULL; 125 } 126 127 128 struct iframe* 129 x86_get_current_iframe(void) 130 { 131 return get_current_iframe(); 132 } 133 134 135 phys_addr_t 136 x86_next_page_directory(Thread* from, Thread* to) 137 { 138 VMAddressSpace* toAddressSpace = to->team->address_space; 139 if (from->team->address_space == toAddressSpace) { 140 // don't change the pgdir, same address space 141 return 0; 142 } 143 144 if (toAddressSpace == NULL) 145 toAddressSpace = VMAddressSpace::Kernel(); 146 147 return static_cast<X86VMTranslationMap*>(toAddressSpace->TranslationMap()) 148 ->PagingStructures()->pgdir_phys; 149 } 150 151 152 /*! Returns to the userland environment given by \a frame for a thread not 153 having been userland before. 154 155 Before returning to userland all potentially necessary kernel exit work is 156 done. 157 158 \param thread The current thread. 159 \param frame The iframe defining the userland environment. Must point to a 160 location somewhere on the caller's stack (e.g. a local variable). 161 */ 162 void 163 x86_initial_return_to_userland(Thread* thread, iframe* frame) 164 { 165 // disable interrupts and set up CPU specifics for this thread 166 disable_interrupts(); 167 168 get_cpu_struct()->arch.tss.sp0 = thread->kernel_stack_top; 169 x86_set_tls_context(thread); 170 x86_set_syscall_stack(thread->kernel_stack_top); 171 172 // return to userland 173 x86_return_to_userland(frame); 174 } 175 176 177 // #pragma mark - 178 179 180 status_t 181 arch_team_init_team_struct(Team* p, bool kernel) 182 { 183 return B_OK; 184 } 185 186 187 /*! Initializes the user-space TLS local storage pointer in 188 the thread structure, and the reserved TLS slots. 189 190 Is called from _create_user_thread_kentry(). 191 */ 192 status_t 193 arch_thread_init_tls(Thread* thread) 194 { 195 addr_t tls[TLS_FIRST_FREE_SLOT]; 196 197 thread->user_local_storage = thread->user_stack_base 198 + thread->user_stack_size; 199 200 // initialize default TLS fields 201 memset(tls, 0, sizeof(tls)); 202 tls[TLS_BASE_ADDRESS_SLOT] = thread->user_local_storage; 203 tls[TLS_THREAD_ID_SLOT] = thread->id; 204 tls[TLS_USER_THREAD_SLOT] = (addr_t)thread->user_thread; 205 206 return user_memcpy((void*)thread->user_local_storage, tls, sizeof(tls)); 207 } 208 209 210 void 211 arch_thread_context_switch(Thread* from, Thread* to) 212 { 213 cpu_ent* cpuData = to->cpu; 214 215 cpuData->arch.tss.sp0 = to->kernel_stack_top; 216 x86_set_syscall_stack(to->kernel_stack_top); 217 218 // set TLS GDT entry to the current thread - since this action is 219 // dependent on the current CPU, we have to do it here 220 if (to->user_local_storage != 0) 221 x86_set_tls_context(to); 222 223 X86PagingStructures* activePagingStructures 224 = cpuData->arch.active_paging_structures; 225 VMAddressSpace* toAddressSpace = to->team->address_space; 226 227 X86PagingStructures* toPagingStructures; 228 if (toAddressSpace != NULL 229 && (toPagingStructures = static_cast<X86VMTranslationMap*>( 230 toAddressSpace->TranslationMap())->PagingStructures()) 231 != activePagingStructures) { 232 // update on which CPUs the address space is used 233 int cpu = cpuData->cpu_num; 234 activePagingStructures->active_on_cpus.ClearBitAtomic(cpu); 235 toPagingStructures->active_on_cpus.SetBitAtomic(cpu); 236 237 // assign the new paging structures to the CPU 238 toPagingStructures->AddReference(); 239 cpuData->arch.active_paging_structures = toPagingStructures; 240 241 // set the page directory, if it changes 242 addr_t newPageDirectory = toPagingStructures->pgdir_phys; 243 if (newPageDirectory != activePagingStructures->pgdir_phys) 244 x86_swap_pgdir(newPageDirectory); 245 246 // This CPU no longer uses the previous paging structures. 247 activePagingStructures->RemoveReference(); 248 } 249 250 #ifndef __x86_64__ 251 gX86SwapFPUFunc(from->arch_info.fpu_state, to->arch_info.fpu_state); 252 #endif 253 x86_context_switch(&from->arch_info, &to->arch_info); 254 } 255 256 257 bool 258 arch_on_signal_stack(Thread *thread) 259 { 260 struct iframe* frame = get_current_iframe(); 261 262 return frame->user_sp >= thread->signal_stack_base 263 && frame->user_sp < thread->signal_stack_base 264 + thread->signal_stack_size; 265 } 266 267 268 /*! Saves everything needed to restore the frame in the child fork in the 269 arch_fork_arg structure to be passed to arch_restore_fork_frame(). 270 Also makes sure to return the right value. 271 */ 272 void 273 arch_store_fork_frame(struct arch_fork_arg* arg) 274 { 275 struct iframe* frame = x86_get_current_iframe(); 276 277 // we need to copy the threads current iframe 278 arg->iframe = *frame; 279 280 // we also want fork() to return 0 for the child 281 arg->iframe.ax = 0; 282 } 283 284 285 /*! Restores the frame from a forked team as specified by the provided 286 arch_fork_arg structure. 287 Needs to be called from within the child team, i.e. instead of 288 arch_thread_enter_userspace() as thread "starter". 289 This function does not return to the caller, but will enter userland 290 in the child team at the same position where the parent team left of. 291 292 \param arg The architecture specific fork arguments including the 293 environment to restore. Must point to a location somewhere on the 294 caller's stack. 295 */ 296 void 297 arch_restore_fork_frame(struct arch_fork_arg* arg) 298 { 299 x86_initial_return_to_userland(thread_get_current_thread(), &arg->iframe); 300 } 301