1/* 2 * Copyright 2013, winocm. <winocm@icloud.com> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without modification, 6 * are permitted provided that the following conditions are met: 7 * 8 * Redistributions of source code must retain the above copyright notice, this 9 * list of conditions and the following disclaimer. 10 * 11 * Redistributions in binary form must reproduce the above copyright notice, this 12 * list of conditions and the following disclaimer in the documentation and/or 13 * other materials provided with the distribution. 14 * 15 * If you are going to use this software in any form that does not involve 16 * releasing the source to this project or improving it, let me know beforehand. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND 19 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 20 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 21 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR 22 * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES 23 * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 24 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 25 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS 27 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30/* 31 * ARM thread support 32 */ 33 34/* 35 * this is not smp safe at /all/. 36 */ 37 38#include <mach/mach_types.h> 39#include <mach/vm_param.h> 40#include <kern/debug.h> 41#include <arm/cpu_data.h> 42#include <kern/thread.h> 43#include <arm/misc_protos.h> 44#include <kern/kalloc.h> 45#include <vm/vm_kern.h> 46#include <vm/vm_map.h> 47 48thread_t CurrentThread; 49 50/* 51 * Maps state flavor to number of words in the state: 52 */ 53uint32_t _MachineStateCount[] = { 54 /* FLAVOR_LIST */ 55 0, 56 ARM_THREAD_STATE_COUNT, 57 ARM_VFP_STATE_COUNT, 58 ARM_EXCEPTION_STATE_COUNT, 59 ARM_DEBUG_STATE_COUNT, 60}; 61 62/* etimer is *still* broken and so are threads. :| */ 63#define kprintf(args...) 64 65/* 66 * These are defined in ctxswitch.s. 67 */ 68thread_t Switch_context(thread_t old_thread, thread_continue_t continuation, 69 thread_t new_thread); 70void Call_continuation(thread_continue_t continuation, void *parameter, 71 wait_result_t wresult, vm_offset_t stack); 72 73static void save_vfp_context(thread_t thread); 74 75/** 76 * arm_set_threadpid_user_readonly 77 * 78 * Set current thread identifier to the cthread identifier. 79 */ 80void arm_set_threadpid_user_readonly(uint32_t * address) 81{ 82 __asm__ __volatile__("mcr p15, 0, %0, c13, c0, 3"::"r"(address)); 83} 84 85/** 86 * arm_set_threadpid_priv_readwrite 87 * 88 * Set current thread identifier to the specified thread_t. 89 */ 90void arm_set_threadpid_priv_readwrite(uint32_t * address) 91{ 92 __asm__ __volatile__("mcr p15, 0, %0, c13, c0, 4"::"r"(address)); 93} 94 95/** 96 * machine_set_current_thread 97 * 98 * Set current thread to the specified thread_t. 99 */ 100void machine_set_current_thread(thread_t thread) 101{ 102 /* 103 * Set the current thread. 104 */ 105 CurrentThread = thread; 106 107 arm_set_threadpid_user_readonly((uint32_t *) thread->machine.cthread_self); 108 arm_set_threadpid_priv_readwrite((uint32_t *) thread); 109} 110 111void thread_set_cthread_self(uint32_t cthr) 112{ 113 thread_t curthr = current_thread(); 114 assert(curthr); 115 curthr->machine.cthread_self = cthr; 116 arm_set_threadpid_user_readonly((uint32_t *) curthr->machine.cthread_self); 117} 118 119uint64_t thread_get_cthread_self(void) 120{ 121 thread_t curthr = current_thread(); 122 assert(curthr); 123 return curthr->machine.cthread_self; 124} 125 126/** 127 * machine_thread_inherit_taskwide 128 */ 129kern_return_t machine_thread_inherit_taskwide(thread_t thread, task_t parent_task) 130{ 131 return KERN_FAILURE; 132} 133 134/** 135 * machine_thread_create 136 * 137 * Do machine-dependent initialization for a thread. 138 */ 139kern_return_t machine_thread_create(thread_t thread, task_t task) 140{ 141 arm_saved_state_t *sv = NULL; 142 143 /* 144 * Create a thread and set the members in the pcb. 145 */ 146 assert(thread != NULL); 147 assert(thread->machine.iss == NULL); 148 149 /* 150 * Zero out the register save areas. 151 */ 152 bzero(&thread->machine.vfp_regs, sizeof(arm_vfp_state_t)); 153 bzero(&thread->machine.user_regs, sizeof(arm_saved_state_t)); 154 155 /* 156 * Set the members now. 157 */ 158 thread->machine.preempt_count = 0; 159 thread->machine.cpu_data = cpu_datap(cpu_number()); 160 thread->machine.vfp_enable = 0; 161 thread->machine.vfp_dirty = 0; 162 163 /* 164 * Also kernel threads 165 */ 166 thread->machine.uss = &thread->machine.user_regs; 167 168 return KERN_SUCCESS; 169} 170 171/** 172 * machine_switch_context 173 * 174 * Switch the current executing machine context to a new one. 175 */ 176thread_t machine_switch_context(thread_t old, thread_continue_t continuation, 177 thread_t new) 178{ 179 pmap_t new_pmap; 180 cpu_data_t *datap; 181 register thread_t retval; 182 183 kprintf("machine_switch_context: %p -> %p (cont: %p)\n", old, new, continuation); 184 185 if (old == new) 186 panic("machine_switch_context: old = new thread (%p %p)", old, new); 187 188 datap = cpu_datap(cpu_number()); 189 assert(datap != NULL); 190 191 datap->old_thread = old; 192 193 save_vfp_context(old); 194 195 new_pmap = new->map->pmap; 196 if ((old->map->pmap != new_pmap)) { 197 if (new_pmap != NULL) { 198 pmap_switch(new_pmap); 199 } 200 } 201 202 /* 203 * VFP save needed 204 */ 205 206 retval = Switch_context(old, continuation, new); 207 assert(retval != NULL); 208 209 return retval; 210} 211 212void machine_stack_handoff(thread_t old, thread_t new) 213{ 214 vm_offset_t stack; 215 pmap_t new_pmap; 216 217 assert(new); 218 assert(old); 219 220 if (old == new) 221 panic("machine_stack_handoff"); 222 223 kprintf("machine_stack_handoff: %p = old, %p = new\n", old, new); 224 225 save_vfp_context(old); 226 227 stack = machine_stack_detach(old); 228 new->kernel_stack = stack; 229 230 uint32_t *kstack = (uint32_t *) STACK_IKS(stack); 231 new->machine.iss = (arm_saved_state_t *) kstack; 232 new->machine.iss->sp = (uint32_t) kstack - sizeof(arm_saved_state_t); 233 234 old->machine.iss = 0; 235 236 if (stack == old->reserved_stack) { 237 assert(new->reserved_stack); 238 old->reserved_stack = new->reserved_stack; 239 new->reserved_stack = stack; 240 } 241 242 /* 243 * A full call to machine_stack_attach() is unnecessry 244 * because old stack is already initialized. 245 */ 246 247 new_pmap = new->map->pmap; 248 if ((old->map->pmap != new_pmap)) { 249 if (new_pmap != NULL) { 250 pmap_switch(new_pmap); 251 } 252 } 253 254 machine_set_current_thread(new); 255 256 return; 257} 258 259/** 260 * machine_thread_init 261 */ 262void machine_thread_init(void) 263{ 264 return; 265} 266 267/** 268 * save_vfp_context 269 * 270 * Saves current vfp context into thread state. 271 */ 272static void save_vfp_context(thread_t thread) 273{ 274 if (thread->machine.vfp_enable && !thread->machine.vfp_dirty) { 275 vfp_context_save(&thread->machine.vfp_regs); 276 vfp_enable_exception(FALSE); 277 thread->machine.vfp_enable = FALSE; 278 } 279} 280 281/** 282 * machine_stack_attach 283 * 284 * Attach a stack to a thread and populate its members. 285 */ 286void machine_stack_attach(thread_t thread, vm_offset_t stack) 287{ 288 assert(stack != NULL); 289 assert(thread != NULL); 290 291 kprintf("machine_stack_attach: setting stack %p for thread %p\n", stack, thread); 292 293 uint32_t *kstack = (uint32_t *) STACK_IKS(stack); 294 295 thread->kernel_stack = stack; 296 thread->machine.iss = (arm_saved_state_t *) kstack; 297 thread->machine.iss->r[0] = (uint32_t) thread; 298 thread->machine.iss->lr = (uint32_t) thread_continue; 299 thread->machine.iss->sp = (uint32_t) kstack - sizeof(arm_saved_state_t); 300 301 return; 302} 303 304/** 305 * machine_stack_detach 306 * 307 * Kill the current stack. 308 */ 309vm_offset_t machine_stack_detach(thread_t thread) 310{ 311 vm_offset_t stack; 312 313 assert(thread != NULL); 314 315 kprintf("machine_stack_detach: killing stack for thread %p\n", thread); 316 317 stack = thread->kernel_stack; 318 thread->kernel_stack = 0; 319 320 return stack; 321} 322 323/* 324 * Only one real processor. 325 */ 326processor_t machine_choose_processor(processor_set_t pset, processor_t preferred) 327{ 328 return preferred; 329} 330 331/** 332 * call_continuation. 333 * 334 * Call the continuation routine for a thread, really is a shim for the 335 * assembly routine. 336 */ 337void call_continuation(thread_continue_t continuation, void *parameter, 338 wait_result_t wresult) 339{ 340 thread_t self = current_thread(); 341 342 assert(self->machine.iss != NULL); 343 assert(self->kernel_stack); 344 assert(continuation); 345 346 kprintf("call_continuation: calling continuation on thread %p\n", self); 347 348 uint32_t kss; 349 kss = (uint32_t) STACK_IKS(self->kernel_stack); 350 351 Call_continuation(continuation, parameter, wresult, kss); 352 353 return; 354} 355 356/** 357 * machine_thread_destroy 358 * 359 * Destroy the machine specific thread context block. 360 */ 361void machine_thread_destroy(thread_t thread) 362{ 363 return; 364} 365 366/* 367 * This is where registers that are not normally specified by the mach-o 368 * file on an execve would be nullified, perhaps to avoid a covert channel. 369 */ 370kern_return_t machine_thread_state_initialize(thread_t thread) 371{ 372 return KERN_SUCCESS; 373} 374 375/* 376 * This is called when a task is terminated, and also on exec(). 377 * Clear machine-dependent state that is stored on the task. 378 */ 379void machine_task_terminate(task_t task) 380{ 381 return; 382} 383 384void *find_user_regs(thread_t thread) 385{ 386 assert(thread->machine.uss == &thread->machine.user_regs); 387 return (void *) thread->machine.uss; 388} 389 390kern_return_t machine_thread_dup(thread_t self, thread_t target) 391{ 392 /* 393 * Copy user registers. 394 */ 395 bcopy(self->machine.uss, target->machine.uss, sizeof(arm_saved_state_t)); 396 397 /* 398 * Save FP registers and copy. 399 */ 400 save_vfp_context(self); 401 bcopy(&self->machine.vfp_regs, &target->machine.vfp_regs, sizeof(arm_vfp_state_t)); 402 target->machine.cthread_self = self->machine.cthread_self; 403 return KERN_SUCCESS; 404} 405 406/* 407 * consider_machine_collect: 408 * 409 * Try to collect machine-dependent pages 410 */ 411void consider_machine_collect(void) 412{ 413} 414 415void consider_machine_adjust(void) 416{ 417} 418 419unsigned int get_useraddr(void) 420{ 421 thread_t thr_act = current_thread(); 422 423 return (thr_act->machine.iss->pc); 424} 425