1 /* 2 * Copyright 2003-2010, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Authors: 6 * Axel Dörfler <axeld@pinc-software.de> 7 * Ingo Weinhold <bonefish@cs.tu-berlin.de> 8 * 9 * Copyright 2001, Travis Geiselbrecht. All rights reserved. 10 * Distributed under the terms of the NewOS License. 11 */ 12 13 14 #include <arch_thread.h> 15 16 #include <arch_cpu.h> 17 #include <arch/thread.h> 18 #include <boot/stage2.h> 19 #include <kernel.h> 20 #include <thread.h> 21 #include <vm/vm_types.h> 22 #include <vm/VMAddressSpace.h> 23 //#include <arch/vm_translation_map.h> 24 25 #include <string.h> 26 27 // Valid initial arch_thread state. We just memcpy() it when initializing 28 // a new thread structure. 29 static struct arch_thread sInitialState; 30 31 // Helper function for thread creation, defined in arch_asm.S. 32 extern "C" void ppc_kernel_thread_root(); 33 34 35 void 36 ppc_push_iframe(struct iframe_stack *stack, struct iframe *frame) 37 { 38 ASSERT(stack->index < IFRAME_TRACE_DEPTH); 39 stack->frames[stack->index++] = frame; 40 } 41 42 43 void 44 ppc_pop_iframe(struct iframe_stack *stack) 45 { 46 ASSERT(stack->index > 0); 47 stack->index--; 48 } 49 50 51 /** Returns the current iframe structure of the running thread. 52 * This function must only be called in a context where it's actually 53 * sure that such iframe exists; ie. from syscalls, but usually not 54 * from standard kernel threads. 55 */ 56 static struct iframe * 57 ppc_get_current_iframe(void) 58 { 59 struct thread *thread = thread_get_current_thread(); 60 61 ASSERT(thread->arch_info.iframes.index >= 0); 62 return thread->arch_info.iframes.frames[thread->arch_info.iframes.index - 1]; 63 } 64 65 66 /** \brief Returns the current thread's topmost (i.e. most recent) 67 * userland->kernel transition iframe (usually the first one, save for 68 * interrupts in signal handlers). 69 * \return The iframe, or \c NULL, if there is no such iframe (e.g. when 70 * the thread is a kernel thread). 71 */ 72 struct iframe * 73 ppc_get_user_iframe(void) 74 { 75 struct thread *thread = thread_get_current_thread(); 76 int i; 77 78 for (i = thread->arch_info.iframes.index - 1; i >= 0; i--) { 79 struct iframe *frame = thread->arch_info.iframes.frames[i]; 80 if (frame->srr1 & MSR_PRIVILEGE_LEVEL) 81 return frame; 82 } 83 84 return NULL; 85 } 86 87 88 // #pragma mark - 89 90 91 status_t 92 arch_thread_init(struct kernel_args *args) 93 { 94 // Initialize the static initial arch_thread state (sInitialState). 95 // Currently nothing to do, i.e. zero initialized is just fine. 96 97 return B_OK; 98 } 99 100 101 status_t 102 arch_team_init_team_struct(struct team *team, bool kernel) 103 { 104 // Nothing to do. The structure is empty. 105 return B_OK; 106 } 107 108 109 status_t 110 arch_thread_init_thread_struct(struct thread *thread) 111 { 112 // set up an initial state (stack & fpu) 113 memcpy(&thread->arch_info, &sInitialState, sizeof(struct arch_thread)); 114 115 return B_OK; 116 } 117 118 119 status_t 120 arch_thread_init_kthread_stack(struct thread *t, int (*start_func)(void), 121 void (*entry_func)(void), void (*exit_func)(void)) 122 { 123 addr_t *kstack = (addr_t *)t->kernel_stack_base; 124 addr_t *kstackTop = (addr_t *)t->kernel_stack_top; 125 126 // clear the kernel stack 127 #ifdef DEBUG_KERNEL_STACKS 128 # ifdef STACK_GROWS_DOWNWARDS 129 memset((void *)((addr_t)kstack + KERNEL_STACK_GUARD_PAGES * B_PAGE_SIZE), 0, 130 KERNEL_STACK_SIZE); 131 # else 132 memset(kstack, 0, KERNEL_STACK_SIZE); 133 # endif 134 #else 135 memset(kstack, 0, KERNEL_STACK_SIZE); 136 #endif 137 138 // space for frame pointer and return address, and stack frames must be 139 // 16 byte aligned 140 kstackTop -= 2; 141 kstackTop = (addr_t*)((addr_t)kstackTop & ~0xf); 142 143 // LR, CR, r2, r13-r31, f13-f31, as pushed by ppc_context_switch() 144 kstackTop -= 22 + 2 * 19; 145 146 // let LR point to ppc_kernel_thread_root() 147 kstackTop[0] = (addr_t)&ppc_kernel_thread_root; 148 149 // the arguments of ppc_kernel_thread_root() are the functions to call, 150 // provided in registers r13-r15 151 kstackTop[3] = (addr_t)entry_func; 152 kstackTop[4] = (addr_t)start_func; 153 kstackTop[5] = (addr_t)exit_func; 154 155 // save this stack position 156 t->arch_info.sp = (void *)kstackTop; 157 158 return B_OK; 159 } 160 161 162 status_t 163 arch_thread_init_tls(struct thread *thread) 164 { 165 // TODO: Implement! 166 return B_OK; 167 } 168 169 170 void 171 arch_thread_context_switch(struct thread *t_from, struct thread *t_to) 172 { 173 // set the new kernel stack in the EAR register. 174 // this is used in the exception handler code to decide what kernel stack to 175 // switch to if the exception had happened when the processor was in user mode 176 asm("mtear %0" :: "g"(t_to->kernel_stack_top - 8)); 177 178 // switch the asids if we need to 179 if (t_to->team->address_space != NULL) { 180 // the target thread has is user space 181 if (t_from->team != t_to->team) { 182 // switching to a new address space 183 ppc_translation_map_change_asid( 184 t_to->team->address_space->TranslationMap()); 185 } 186 } 187 188 ppc_context_switch(&t_from->arch_info.sp, t_to->arch_info.sp); 189 } 190 191 192 void 193 arch_thread_dump_info(void *info) 194 { 195 struct arch_thread *at = (struct arch_thread *)info; 196 197 dprintf("\tsp: %p\n", at->sp); 198 } 199 200 201 status_t 202 arch_thread_enter_userspace(struct thread *thread, addr_t entry, void *arg1, void *arg2) 203 { 204 panic("arch_thread_enter_uspace(): not yet implemented\n"); 205 return B_ERROR; 206 } 207 208 209 bool 210 arch_on_signal_stack(struct thread *thread) 211 { 212 return false; 213 } 214 215 216 status_t 217 arch_setup_signal_frame(struct thread *thread, struct sigaction *sa, int sig, int sigMask) 218 { 219 return B_ERROR; 220 } 221 222 223 int64 224 arch_restore_signal_frame(void) 225 { 226 return 0; 227 } 228 229 230 231 /** Saves everything needed to restore the frame in the child fork in the 232 * arch_fork_arg structure to be passed to arch_restore_fork_frame(). 233 * Also makes sure to return the right value. 234 */ 235 236 void 237 arch_store_fork_frame(struct arch_fork_arg *arg) 238 { 239 } 240 241 242 /** Restores the frame from a forked team as specified by the provided 243 * arch_fork_arg structure. 244 * Needs to be called from within the child team, ie. instead of 245 * arch_thread_enter_uspace() as thread "starter". 246 * This function does not return to the caller, but will enter userland 247 * in the child team at the same position where the parent team left of. 248 */ 249 250 void 251 arch_restore_fork_frame(struct arch_fork_arg *arg) 252 { 253 } 254 255