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