|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Copyright (c) 1990,1991,1992 The University of Utah and ! 27: * the Center for Software Science (CSS). All rights reserved. ! 28: * ! 29: * Permission to use, copy, modify and distribute this software is hereby ! 30: * granted provided that (1) source code retains these copyright, permission, ! 31: * and disclaimer notices, and (2) redistributions including binaries ! 32: * reproduce the notices in supporting documentation, and (3) all advertising ! 33: * materials mentioning features or use of this software display the following ! 34: * acknowledgement: ``This product includes software developed by the Center ! 35: * for Software Science at the University of Utah.'' ! 36: * ! 37: * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS ! 38: * IS" CONDITION. THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF ! 39: * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 40: * ! 41: * CSS requests users of this software to return to [email protected] any ! 42: * improvements that they make and grant CSS redistribution rights. ! 43: * ! 44: * Utah $Hdr: pcb.c 1.23 92/06/27$ ! 45: */ ! 46: ! 47: #include <cpus.h> ! 48: #include <debug.h> ! 49: ! 50: #include <types.h> ! 51: #include <kern/task.h> ! 52: #include <kern/thread.h> ! 53: #include <kern/thread_act.h> ! 54: #include <kern/thread_swap.h> ! 55: #include <mach/thread_status.h> ! 56: #include <vm/vm_kern.h> ! 57: #include <kern/mach_param.h> ! 58: ! 59: #include <kern/misc_protos.h> ! 60: #include <ppc/misc_protos.h> ! 61: #include <ppc/fpu_protos.h> ! 62: #include <ppc/exception.h> ! 63: #include <ppc/proc_reg.h> ! 64: #include <kern/spl.h> ! 65: #include <ppc/pmap.h> ! 66: #include <ppc/trap.h> ! 67: #include <ppc/mappings.h> ! 68: #include <ppc/savearea.h> ! 69: #include <ppc/Firmware.h> ! 70: #include <ppc/asm.h> ! 71: #include <ppc/thread_act.h> ! 72: ! 73: #include <sys/kdebug.h> ! 74: ! 75: extern int real_ncpus; /* Number of actual CPUs */ ! 76: extern struct Saveanchor saveanchor; /* Aliged savearea anchor */ ! 77: ! 78: /* ! 79: * These constants are dumb. They should not be in asm.h! ! 80: */ ! 81: ! 82: #define KF_SIZE (FM_SIZE+ARG_SIZE+FM_REDZONE) ! 83: ! 84: #if DEBUG ! 85: int fpu_trap_count = 0; ! 86: int fpu_switch_count = 0; ! 87: int vec_trap_count = 0; ! 88: int vec_switch_count = 0; ! 89: #endif ! 90: ! 91: extern struct thread_shuttle *Switch_context( ! 92: struct thread_shuttle *old, ! 93: void (*cont)(void), ! 94: struct thread_shuttle *new); ! 95: ! 96: ! 97: #if MACH_LDEBUG || MACH_KDB ! 98: void log_thread_action (char *, long, long, long); ! 99: #endif ! 100: ! 101: ! 102: /* ! 103: * consider_machine_collect: try to collect machine-dependent pages ! 104: */ ! 105: void ! 106: consider_machine_collect() ! 107: { ! 108: /* ! 109: * none currently available ! 110: */ ! 111: return; ! 112: } ! 113: ! 114: /* ! 115: * stack_attach: Attach a kernel stack to a thread. ! 116: */ ! 117: void ! 118: machine_kernel_stack_init( ! 119: struct thread_shuttle *thread, ! 120: void (*continuation)(void)) ! 121: { ! 122: vm_offset_t stack; ! 123: unsigned int *kss; ! 124: struct savearea *sv; ! 125: ! 126: assert(thread->top_act->mact.pcb); ! 127: assert(thread->kernel_stack); ! 128: stack = thread->kernel_stack; ! 129: ! 130: #if MACH_ASSERT ! 131: if (watchacts & WA_PCB) ! 132: printf("machine_kernel_stack_init(thr=%x,stk=%x,cont=%x)\n", thread,stack,continuation); ! 133: #endif /* MACH_ASSERT */ ! 134: ! 135: kss = (unsigned int *)STACK_IKS(stack); ! 136: sv=(savearea *)(thread->top_act->mact.pcb); /* This for the sake of C */ ! 137: ! 138: sv->save_lr = (unsigned int) continuation; /* Set up the execution address */ ! 139: sv->save_srr0 = (unsigned int) continuation; /* Here too */ ! 140: sv->save_srr1 = MSR_SUPERVISOR_INT_ON; /* Set the normal running MSR */ ! 141: sv->save_r1 = (vm_offset_t) ((int)kss - KF_SIZE); /* Point to the top frame on the stack */ ! 142: ! 143: *((int *)sv->save_r1) = 0; /* Zero the frame backpointer */ ! 144: thread->top_act->mact.ksp = 0; /* Show that the kernel stack is in use already */ ! 145: ! 146: } ! 147: ! 148: /* ! 149: * switch_context: Switch from one thread to another, needed for ! 150: * switching of space ! 151: * ! 152: */ ! 153: struct thread_shuttle* ! 154: switch_context( ! 155: struct thread_shuttle *old, ! 156: void (*continuation)(void), ! 157: struct thread_shuttle *new) ! 158: { ! 159: register thread_act_t old_act = old->top_act, new_act = new->top_act; ! 160: register struct thread_shuttle* retval; ! 161: pmap_t new_pmap; ! 162: #if MACH_LDEBUG || MACH_KDB ! 163: log_thread_action("switch", ! 164: (long)old, ! 165: (long)new, ! 166: (long)__builtin_return_address(0)); ! 167: #endif ! 168: assert(old_act->kernel_loaded || ! 169: active_stacks[cpu_number()] == old_act->thread->kernel_stack); ! 170: assert (get_preemption_level() == 1); ! 171: check_simple_locks(); ! 172: ! 173: /* Our context might wake up on another processor, so we must ! 174: * not keep hot state in our FPU, it must go back to the pcb ! 175: * so that it can be found by the other if needed ! 176: */ ! 177: if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ ! 178: fpu_save(); /* Save floating point if used */ ! 179: vec_save(); /* Save vector if used */ ! 180: } ! 181: ! 182: #if DEBUG ! 183: if (watchacts & WA_PCB) { ! 184: printf("switch_context(0x%08x, 0x%x, 0x%08x)\n", ! 185: old,continuation,new); ! 186: } ! 187: #endif /* DEBUG */ ! 188: ! 189: /* ! 190: * We do not have to worry about the PMAP module, so switch. ! 191: * ! 192: * We must not use top_act->map since this may not be the actual ! 193: * task map, but the map being used for a klcopyin/out. ! 194: */ ! 195: ! 196: new_pmap = new_act->task->map->pmap; ! 197: if (old_act->task->map->pmap != new_pmap) { ! 198: pmap_switch(new_pmap); ! 199: } ! 200: ! 201: /* Sanity check - is the stack pointer inside the stack that ! 202: * we're about to switch to? Is the execution address within ! 203: * the kernel's VM space?? ! 204: */ ! 205: #if 0 ! 206: printf("************* stack=%08X; R1=%08X; LR=%08X; old=%08X; cont=%08X; new=%08X\n", ! 207: new->kernel_stack, new_act->mact.pcb->ss.r1, ! 208: new_act->mact.pcb->ss.lr, old, continuation, new); /* (TEST/DEBUG) */ ! 209: assert((new->kernel_stack < new_act->mact.pcb->ss.r1) && ! 210: ((unsigned int)STACK_IKS(new->kernel_stack) > ! 211: new_act->mact.pcb->ss.r1)); ! 212: assert(new_act->mact.pcb->ss.lr < VM_MAX_KERNEL_ADDRESS); ! 213: #endif ! 214: ! 215: ! 216: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE, ! 217: (int)old, (int)new, old->sched_pri, new->sched_pri, 0); ! 218: ! 219: ! 220: retval = Switch_context(old, continuation, new); ! 221: assert(retval != (struct thread_shuttle*)NULL); ! 222: ! 223: /* We've returned from having switched context, so we should be ! 224: * back in the original context. ! 225: */ ! 226: ! 227: return retval; ! 228: } ! 229: ! 230: /* ! 231: * Alter the thread's state so that a following thread_exception_return ! 232: * will make the thread return 'retval' from a syscall. ! 233: */ ! 234: void ! 235: thread_set_syscall_return( ! 236: struct thread_shuttle *thread, ! 237: kern_return_t retval) ! 238: { ! 239: struct ppc_saved_state *ssp = &thread->top_act->mact.pcb->ss; ! 240: ! 241: #if MACH_ASSERT ! 242: if (watchacts & WA_PCB) ! 243: printf("thread_set_syscall_return(thr=%x,retval=%d)\n", thread,retval); ! 244: #endif /* MACH_ASSERT */ ! 245: ! 246: ssp->r3 = retval; ! 247: } ! 248: ! 249: /* ! 250: * Initialize the machine-dependent state for a new thread. ! 251: */ ! 252: kern_return_t ! 253: thread_machine_create( ! 254: struct thread_shuttle *thread, ! 255: thread_act_t thr_act, ! 256: void (*start_pos)(void)) ! 257: { ! 258: ! 259: savearea *sv; /* Pointer to newly allocated savearea */ ! 260: unsigned int *CIsTooLimited, i; ! 261: ! 262: ! 263: #if MACH_ASSERT ! 264: if (watchacts & WA_PCB) ! 265: printf("thread_machine_create(thr=%x,thr_act=%x,st=%x)\n", thread, thr_act, start_pos); ! 266: #endif /* MACH_ASSERT */ ! 267: ! 268: hw_atomic_add(&saveanchor.saveneed, 4); /* Account for the number of saveareas we think we "need" ! 269: for this activation */ ! 270: assert(thr_act->mact.pcb == (pcb_t)0); /* Make sure there was no previous savearea */ ! 271: ! 272: sv = save_alloc(); /* Go get us a savearea */ ! 273: ! 274: bzero((char *) sv, sizeof(struct pcb)); /* Clear out the whole shebang */ ! 275: ! 276: sv->save_act = thr_act; /* Set who owns it */ ! 277: /* XXX: TO BE REMOVED WA for AltiVec compiler bug */ ! 278: sv->save_vrsave = 0xffffffff; ! 279: thr_act->mact.pcb = (pcb_t)sv; /* Point to the save area */ ! 280: ! 281: thread->kernel_stack = (int)stack_alloc(thread,start_pos); /* Allocate our kernel stack */ ! 282: assert(thread->kernel_stack); /* Make sure we got it */ ! 283: ! 284: #if MACH_ASSERT ! 285: if (watchacts & WA_PCB) ! 286: printf("pcb_init(%x) pcb=%x\n", thr_act, sv); ! 287: #endif /* MACH_ASSERT */ ! 288: /* ! 289: * User threads will pull their context from the pcb when first ! 290: * returning to user mode, so fill in all the necessary values. ! 291: * Kernel threads are initialized from the save state structure ! 292: * at the base of the kernel stack (see stack_attach()). ! 293: */ ! 294: ! 295: sv->save_srr1 = MSR_EXPORT_MASK_SET; /* Set the default user MSR */ ! 296: ! 297: CIsTooLimited = (unsigned int *)(&sv->save_sr0); /* Make a pointer 'cause C can't cast on the left */ ! 298: for(i=0; i<16; i++) { /* Initialize all SRs */ ! 299: CIsTooLimited[i] = SEG_REG_PROT | (i << 20) | thr_act->task->map->pmap->space; /* Set the SR value */ ! 300: } ! 301: sv->save_sr_copyin = SEG_REG_PROT | (SR_COPYIN_NUM<<20) | thr_act->task->map->pmap->space; /* Default the copyin */ ! 302: ! 303: return(KERN_SUCCESS); ! 304: } ! 305: ! 306: /* ! 307: * Machine-dependent cleanup prior to destroying a thread ! 308: */ ! 309: void ! 310: thread_machine_destroy( thread_t thread ) ! 311: { ! 312: spl_t s; ! 313: ! 314: assert(thread->kernel_stack); ! 315: s = splsched(); ! 316: stack_free(thread); ! 317: splx(s); ! 318: } ! 319: ! 320: /* ! 321: * flush out any lazily evaluated HW state in the ! 322: * owning thread's context, before termination. ! 323: */ ! 324: void ! 325: thread_machine_flush( thread_act_t cur_act ) ! 326: { ! 327: } ! 328: ! 329: /* ! 330: * Number of times we needed to swap an activation back in before ! 331: * switching to it. ! 332: */ ! 333: int switch_act_swapins = 0; ! 334: ! 335: /* ! 336: * machine_switch_act ! 337: * ! 338: * Machine-dependent details of activation switching. Called with ! 339: * RPC locks held and preemption disabled. ! 340: */ ! 341: void ! 342: machine_switch_act( ! 343: thread_t thread, ! 344: thread_act_t old, ! 345: thread_act_t new, ! 346: int cpu) ! 347: { ! 348: pmap_t new_pmap; ! 349: ! 350: /* Our context might wake up on another processor, so we must ! 351: * not keep hot state in our FPU, it must go back to the pcb ! 352: * so that it can be found by the other if needed ! 353: */ ! 354: if(real_ncpus > 1) { /* This is potentially slow, so only do when actually SMP */ ! 355: fpu_save(); /* Save floating point if used */ ! 356: vec_save(); /* Save vector if used */ ! 357: } ! 358: ! 359: active_stacks[cpu] = thread->kernel_stack; ! 360: ! 361: ast_context(new, cpu); ! 362: ! 363: /* Activations might have different pmaps ! 364: * (process->kernel->server, for example). ! 365: * Change space if needed ! 366: */ ! 367: new_pmap = new->task->map->pmap; ! 368: if (old->task->map->pmap != new_pmap) { ! 369: pmap_switch(new_pmap); ! 370: } ! 371: } ! 372: ! 373: void ! 374: pcb_user_to_kernel(thread_act_t act) ! 375: { ! 376: ! 377: return; /* Not needed, I hope... */ ! 378: } ! 379: ! 380: ! 381: /* ! 382: * act_machine_sv_free ! 383: * release saveareas associated with an act. if flag is true, release ! 384: * user level savearea(s) too, else don't ! 385: * ! 386: * this code cannot block so we call the proper save area free routine ! 387: */ ! 388: void ! 389: act_machine_sv_free(thread_act_t act) ! 390: { ! 391: register pcb_t pcb,userpcb,npcb; ! 392: register savearea *svp; ! 393: register int i; ! 394: ! 395: /* ! 396: * This next bit insures that any live facility context for this thread is discarded on every processor ! 397: * that may have it. We go through all per-processor blocks and zero the facility owner if ! 398: * it is the thread being destroyed. This needs to be done via a compare-and-swap because ! 399: * some other processor could change the owner while we are clearing it. It turns out that ! 400: * this is the only place where we need the interlock, normal use of the owner field is cpu-local ! 401: * and doesn't need the interlock. Because we are called during termintation, and a thread ! 402: * terminates itself, the context on other processors has been saved (because we save it as ! 403: * part of the context switch), even if it is still considered live. Since the dead thread is ! 404: * not running elsewhere, and the context is saved, any other processor looking at the owner ! 405: * field will not attempt to save context again, meaning that it doesn't matter if the owner ! 406: * changes out from under it. ! 407: */ ! 408: ! 409: /* ! 410: * free VMX and FPU saveareas. do not free user save areas. ! 411: * user VMX and FPU saveareas, if any, i'm told are last in ! 412: * the chain so we just stop if we find them ! 413: * we identify user VMX and FPU saveareas when we find a pcb ! 414: * with a save level of 0. we identify user regular save ! 415: * areas when we find one with MSR_PR set ! 416: */ ! 417: ! 418: pcb = act->mact.VMX_pcb; /* Get the top vector savearea */ ! 419: while(pcb) { /* Any VMX saved state? */ ! 420: svp = (savearea *)pcb; /* save lots of casting later */ ! 421: if (svp->save_level_vec == 0) break; /* done when hit user if any */ ! 422: pcb = (pcb_t)svp->save_prev_vector; /* Get one underneath our's */ ! 423: svp->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ ! 424: if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */ ! 425: ! 426: save_ret(svp); /* release it */ ! 427: } ! 428: } ! 429: act->mact.VMX_pcb = pcb; ! 430: if (act->mact.VMX_lvl != 0) { ! 431: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ ! 432: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */ ! 433: } ! 434: } ! 435: ! 436: pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */ ! 437: while(pcb) { /* Any floating point saved state? */ ! 438: svp = (savearea *)pcb; ! 439: if (svp->save_level_fp == 0) break; /* done when hit user if any */ ! 440: pcb = (pcb_t)svp->save_prev_float; /* Get one underneath our's */ ! 441: svp->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ ! 442: if(!(svp->save_flags & SAVinuse)) { /* Anyone left with this one? */ ! 443: save_ret(svp); /* Nope, release it */ ! 444: } ! 445: } ! 446: act->mact.FPU_pcb = pcb; ! 447: if (act->mact.FPU_lvl != 0) { ! 448: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ ! 449: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ ! 450: } ! 451: } ! 452: ! 453: /* ! 454: * free all regular saveareas except a user savearea, if any ! 455: */ ! 456: ! 457: pcb = act->mact.pcb; ! 458: userpcb = (pcb_t)0; ! 459: while(pcb) { ! 460: svp = (savearea *)pcb; ! 461: if ((svp->save_srr1 & MASK(MSR_PR))) { ! 462: assert(userpcb == (pcb_t)0); ! 463: userpcb = pcb; ! 464: svp = (savearea *)userpcb; ! 465: npcb = (pcb_t)svp->save_prev; ! 466: svp->save_prev = (struct savearea *)0; ! 467: } else { ! 468: svp->save_flags = 0; ! 469: npcb = (pcb_t)svp->save_prev; ! 470: save_ret(svp); ! 471: } ! 472: pcb = npcb; ! 473: } ! 474: act->mact.pcb = userpcb; ! 475: ! 476: } ! 477: ! 478: /* ! 479: * act_machine_destroy: Shutdown any state associated with a thread pcb. ! 480: */ ! 481: void ! 482: act_machine_destroy(thread_act_t act) ! 483: { ! 484: register pcb_t pcb, opcb; ! 485: int i; ! 486: ! 487: #if MACH_ASSERT ! 488: if (watchacts & WA_PCB) ! 489: printf("act_machine_destroy(0x%x)\n", act); ! 490: #endif /* MACH_ASSERT */ ! 491: ! 492: if(act->mact.bbDescAddr) { /* Check if the Blue box assist is active */ ! 493: (void) vm_map_unwire(act->map, /* Unwire the descriptor in user's address space */ ! 494: (vm_offset_t)act->mact.bbUserDA, ! 495: (vm_offset_t)act->mact.bbUserDA + PAGE_SIZE, ! 496: FALSE); ! 497: ! 498: kmem_free(kernel_map, (vm_offset_t)act->mact.bbDescAddr, PAGE_SIZE); /* Release the page */ ! 499: ! 500: act->mact.bbDescAddr = 0; /* Clear kernel pointer to it */ ! 501: act->mact.bbUserDA = 0; /* Clear user pointer to it */ ! 502: act->mact.bbTableStart = 0; /* Clear start of table address */ ! 503: ! 504: } ! 505: ! 506: /* ! 507: * This next bit insures that any live facility context for this thread is discarded on every processor ! 508: * that may have it. We go through all per-processor blocks and zero the facility owner if ! 509: * it is the thread being destroyed. This needs to be done via a compare-and-swap because ! 510: * some other processor could change the owner while we are clearing it. It turns out that ! 511: * this is the only place where we need the interlock, normal use of the owner field is cpu-local ! 512: * and doesn't need the interlock. Because we are called during termintation, and a thread ! 513: * terminates itself, the context on other processors has been saved (because we save it as ! 514: * part of the context switch), even if it is still considered live. Since the dead thread is ! 515: * not running elsewhere, and the context is saved, any other processor looking at the owner ! 516: * field will not attempt to save context again, meaning that it doesn't matter if the owner ! 517: * changes out from under it. ! 518: */ ! 519: ! 520: for(i=0; i < real_ncpus; i++) { /* Cycle through processors */ ! 521: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].FPU_thread); /* Clear if ours */ ! 522: (void)hw_compare_and_store((unsigned int)act, 0, &per_proc_info[i].VMX_thread); /* Clear if ours */ ! 523: } ! 524: ! 525: pcb = act->mact.VMX_pcb; /* Get the top vector savearea */ ! 526: while(pcb) { /* Any VMX saved state? */ ! 527: opcb = pcb; /* Save current savearea address */ ! 528: pcb = (pcb_t)(((savearea *)pcb)->save_prev_vector); /* Get one underneath our's */ ! 529: ((savearea *)opcb)->save_flags &= ~SAVvmxvalid; /* Clear the VMX flag */ ! 530: ! 531: if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */ ! 532: save_release((savearea *)opcb); /* Nope, release it */ ! 533: } ! 534: } ! 535: act->mact.VMX_pcb = (pcb_t)0; /* Clear pointer */ ! 536: ! 537: pcb = act->mact.FPU_pcb; /* Get the top floating point savearea */ ! 538: while(pcb) { /* Any floating point saved state? */ ! 539: opcb = pcb; /* Save current savearea address */ ! 540: pcb = (pcb_t)(((savearea *)pcb)->save_prev_float); /* Get one underneath our's */ ! 541: ((savearea *)opcb)->save_flags &= ~SAVfpuvalid; /* Clear the floating point flag */ ! 542: ! 543: if(!(((savearea *)opcb)->save_flags & SAVinuse)) { /* Anyone left with this one? */ ! 544: save_release((savearea *)opcb); /* Nope, release it */ ! 545: } ! 546: } ! 547: act->mact.FPU_pcb = (pcb_t)0; /* Clear pointer */ ! 548: ! 549: pcb = act->mact.pcb; /* Get the top normal savearea */ ! 550: act->mact.pcb = (pcb_t)0; /* Clear pointer */ ! 551: ! 552: while(pcb) { /* Any normal saved state left? */ ! 553: opcb = pcb; /* Keep track of what we're working on */ ! 554: pcb = (pcb_t)(((savearea *)pcb)->save_prev); /* Get one underneath our's */ ! 555: ! 556: ((savearea *)opcb)->save_flags = 0; /* Clear all flags since we release this in any case */ ! 557: save_release((savearea *)opcb); /* Release this one */ ! 558: } ! 559: ! 560: hw_atomic_sub(&saveanchor.saveneed, 4); /* Unaccount for the number of saveareas we think we "need" ! 561: for this activation */ ! 562: } ! 563: ! 564: kern_return_t ! 565: act_machine_create(task_t task, thread_act_t thr_act) ! 566: { ! 567: /* ! 568: * Clear & Init the pcb (sets up user-mode s regs) ! 569: * We don't use this anymore. ! 570: */ ! 571: ! 572: register pcb_t pcb; ! 573: register int i; ! 574: unsigned int *CIsTooLimited; ! 575: pmap_t pmap; ! 576: ! 577: return KERN_SUCCESS; ! 578: } ! 579: ! 580: void act_machine_init() ! 581: { ! 582: #if MACH_ASSERT ! 583: if (watchacts & WA_PCB) ! 584: printf("act_machine_init()\n"); ! 585: #endif /* MACH_ASSERT */ ! 586: ! 587: /* Good to verify these once */ ! 588: assert( THREAD_MACHINE_STATE_MAX <= THREAD_STATE_MAX ); ! 589: ! 590: assert( THREAD_STATE_MAX >= PPC_THREAD_STATE_COUNT ); ! 591: assert( THREAD_STATE_MAX >= PPC_EXCEPTION_STATE_COUNT ); ! 592: assert( THREAD_STATE_MAX >= PPC_FLOAT_STATE_COUNT ); ! 593: assert( THREAD_STATE_MAX >= sizeof(struct ppc_saved_state)/sizeof(int)); ! 594: ! 595: /* ! 596: * If we start using kernel activations, ! 597: * would normally create kernel_thread_pool here, ! 598: * populating it from the act_zone ! 599: */ ! 600: } ! 601: ! 602: void ! 603: act_machine_return(int code) ! 604: { ! 605: thread_act_t thr_act = current_act(); ! 606: thread_act_t cur_act; ! 607: thread_t cur_thread = current_thread(); ! 608: struct ipc_port *iplock; ! 609: ! 610: #if MACH_ASSERT ! 611: if (watchacts & WA_EXIT) ! 612: printf("act_machine_return(0x%x) cur_act=%x(%d) thr=%x(%d)\n", ! 613: code, thr_act, thr_act->ref_count, ! 614: thr_act->thread, thr_act->thread ! 615: ? thr_act->thread->ref_count : 0); ! 616: #endif /* MACH_ASSERT */ ! 617: ! 618: ! 619: /* ! 620: * This code is called with nothing locked. ! 621: * It also returns with nothing locked, if it returns. ! 622: * ! 623: * This routine terminates the current thread activation. ! 624: * If this is the only activation associated with its ! 625: * thread shuttle, then the entire thread (shuttle plus ! 626: * activation) is terminated. ! 627: */ ! 628: assert( code == KERN_TERMINATED ); ! 629: assert( thr_act ); ! 630: ! 631: act_lock_thread(thr_act); ! 632: ! 633: #ifdef CALLOUT_RPC_MODEL ! 634: /* ! 635: * JMM - This needs to get cleaned up to work under the much simpler ! 636: * return (instead of callout model). ! 637: */ ! 638: if (thr_act->thread->top_act != thr_act) { ! 639: /* ! 640: * this is not the top activation; ! 641: * if possible, we should clone the shuttle so that ! 642: * both the root RPC-chain and the soon-to-be-orphaned ! 643: * RPC-chain have shuttles ! 644: * ! 645: * JMM - Cloning is a horrible idea! Instead we should alert ! 646: * the pieces upstream to return the shuttle. We will use ! 647: * alerts for this. ! 648: */ ! 649: act_unlock_thread(thr_act); ! 650: panic("act_machine_return: ORPHAN CASE NOT YET IMPLEMENTED"); ! 651: } ! 652: ! 653: if (thr_act->lower != THR_ACT_NULL) { ! 654: /* terminate the entire thread (shuttle plus activation) */ ! 655: /* terminate only this activation, send an appropriate */ ! 656: /* return code back to the activation that invoked us. */ ! 657: iplock = thr_act->pool_port; /* remember for unlock call */ ! 658: thr_act->lower->alerts |= SERVER_TERMINATED; ! 659: install_special_handler(thr_act->lower); ! 660: ! 661: /* Return to previous act with error code */ ! 662: ! 663: act_locked_act_reference(thr_act); /* keep it around */ ! 664: act_switch_swapcheck(cur_thread, (ipc_port_t)0); ! 665: ! 666: (void) switch_act(THR_ACT_NULL); ! 667: /* assert(thr_act->ref_count == 0); */ /* XXX */ ! 668: cur_act = cur_thread->top_act; ! 669: MACH_RPC_RET(cur_act) = KERN_RPC_SERVER_TERMINATED; ! 670: machine_kernel_stack_init(cur_thread, ! 671: (void (*)(void)) mach_rpc_return_error); ! 672: /* ! 673: * The following unlocks must be done separately since fields ! 674: * used by `act_unlock_thread()' have been cleared, meaning ! 675: * that it would not release all of the appropriate locks. ! 676: */ ! 677: rpc_unlock(cur_thread); ! 678: if (iplock) ip_unlock(iplock); /* must be done separately */ ! 679: act_unlock(thr_act); ! 680: act_deallocate(thr_act); /* free it */ ! 681: Load_context(cur_thread); ! 682: /*NOTREACHED*/ ! 683: ! 684: panic("act_machine_return: TALKING ZOMBIE! (2)"); ! 685: } ! 686: ! 687: #endif /* CALLOUT_RPC_MODEL */ ! 688: ! 689: /* This is the only activation attached to the shuttle... */ ! 690: ! 691: assert(thr_act->thread->top_act == thr_act); ! 692: act_unlock_thread(thr_act); ! 693: thread_terminate_self(); ! 694: ! 695: /*NOTREACHED*/ ! 696: panic("act_machine_return: TALKING ZOMBIE! (1)"); ! 697: } ! 698: ! 699: void ! 700: thread_machine_set_current(struct thread_shuttle *thread) ! 701: { ! 702: register int my_cpu = cpu_number(); ! 703: ! 704: cpu_data[my_cpu].active_thread = thread; ! 705: ! 706: active_kloaded[my_cpu] = thread->top_act->kernel_loaded ? thread->top_act : THR_ACT_NULL; ! 707: } ! 708: ! 709: void ! 710: thread_machine_init(void) ! 711: { ! 712: #ifdef MACHINE_STACK ! 713: #if KERNEL_STACK_SIZE > PPC_PGBYTES ! 714: panic("KERNEL_STACK_SIZE can't be greater than PPC_PGBYTES\n"); ! 715: #endif ! 716: #endif ! 717: } ! 718: ! 719: #if MACH_ASSERT ! 720: void ! 721: dump_pcb(pcb_t pcb) ! 722: { ! 723: printf("pcb @ %8.8x:\n", pcb); ! 724: #if DEBUG ! 725: regDump(&pcb->ss); ! 726: #endif /* DEBUG */ ! 727: } ! 728: ! 729: void ! 730: dump_thread(thread_t th) ! 731: { ! 732: printf(" thread @ 0x%x:\n", th); ! 733: } ! 734: ! 735: int ! 736: dump_act(thread_act_t thr_act) ! 737: { ! 738: if (!thr_act) ! 739: return(0); ! 740: ! 741: printf("thr_act(0x%x)(%d): thread=%x(%d) task=%x(%d)\n", ! 742: thr_act, thr_act->ref_count, ! 743: thr_act->thread, thr_act->thread ? thr_act->thread->ref_count:0, ! 744: thr_act->task, thr_act->task ? thr_act->task->ref_count : 0); ! 745: ! 746: printf("\talerts=%x mask=%x susp=%x active=%x hi=%x lo=%x\n", ! 747: thr_act->alerts, thr_act->alert_mask, ! 748: thr_act->suspend_count, thr_act->active, ! 749: thr_act->higher, thr_act->lower); ! 750: ! 751: return((int)thr_act); ! 752: } ! 753: ! 754: #endif ! 755: ! 756: unsigned int ! 757: get_useraddr() ! 758: { ! 759: ! 760: thread_act_t thr_act = current_act(); ! 761: ! 762: return(thr_act->mact.pcb->ss.srr0); ! 763: } ! 764: ! 765: /* ! 766: * detach and return a kernel stack from a thread ! 767: */ ! 768: ! 769: vm_offset_t ! 770: stack_detach(thread_t thread) ! 771: { ! 772: vm_offset_t stack; ! 773: ! 774: #ifdef KDEBUG ! 775: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH), ! 776: thread, thread->priority, ! 777: thread->sched_pri, 0, ! 778: 0); ! 779: #endif ! 780: stack = thread->kernel_stack; ! 781: thread->kernel_stack = 0; ! 782: return(stack); ! 783: } ! 784: ! 785: /* ! 786: * attach a kernel stack to a thread and initialize it ! 787: * ! 788: * attaches a stack to a thread. if there is no save ! 789: * area we allocate one. the top save area is then ! 790: * loaded with the pc (continuation address), the initial ! 791: * stack pointer, and a std kernel MSR. if the top ! 792: * save area is the user save area bad things will ! 793: * happen ! 794: * ! 795: */ ! 796: ! 797: void ! 798: stack_attach(struct thread_shuttle *thread, ! 799: vm_offset_t stack, ! 800: void (*continuation)(void)) ! 801: { ! 802: thread_act_t thr_act; ! 803: unsigned int *kss; ! 804: struct savearea *sv; ! 805: ! 806: #ifdef KDEBUG ! 807: KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH), ! 808: thread, thread->priority, ! 809: thread->sched_pri, continuation, ! 810: 0); ! 811: #endif ! 812: ! 813: assert(stack); ! 814: kss = (unsigned int *)STACK_IKS(stack); ! 815: thread->kernel_stack = stack; ! 816: ! 817: /* during initialization we sometimes do not have an ! 818: activation. in that case do not do anything */ ! 819: if ((thr_act = thread->top_act) != 0) { ! 820: sv = save_get(); /* cannot block */ ! 821: // bzero((char *) sv, sizeof(struct pcb)); ! 822: sv->save_act = thr_act; ! 823: sv->save_prev = (struct savearea *)thr_act->mact.pcb; ! 824: thr_act->mact.pcb = (pcb_t)sv; ! 825: ! 826: sv->save_srr0 = (unsigned int) continuation; ! 827: /* sv->save_r3 = ARG ? */ ! 828: sv->save_r1 = (vm_offset_t)((int)kss - KF_SIZE); ! 829: sv->save_srr1 = MSR_SUPERVISOR_INT_ON; ! 830: *((int *)sv->save_r1) = 0; ! 831: thr_act->mact.ksp = 0; ! 832: } ! 833: ! 834: return; ! 835: } ! 836: ! 837: /* ! 838: * move a stack from old to new thread ! 839: */ ! 840: ! 841: void ! 842: stack_handoff(thread_t old, ! 843: thread_t new) ! 844: { ! 845: ! 846: vm_offset_t stack; ! 847: pmap_t new_pmap; ! 848: ! 849: assert(new->top_act); ! 850: assert(old->top_act); ! 851: ! 852: stack = stack_detach(old); ! 853: new->kernel_stack = stack; ! 854: ! 855: #if NCPUS > 1 ! 856: if (real_ncpus > 1) { ! 857: fpu_save(); ! 858: vec_save(); ! 859: } ! 860: #endif ! 861: ! 862: KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE, ! 863: (int)old, (int)new, old->sched_pri, new->sched_pri, 0); ! 864: ! 865: new_pmap = new->top_act->task->map->pmap; ! 866: if (old->top_act->task->map->pmap != new_pmap) { ! 867: pmap_switch(new_pmap); ! 868: } ! 869: ! 870: thread_machine_set_current(new); ! 871: active_stacks[cpu_number()] = new->kernel_stack; ! 872: per_proc_info[cpu_number()].Uassist = new->top_act->mact.cthread_self; ! 873: return; ! 874: } ! 875: ! 876: /* ! 877: * clean and initialize the current kernel stack and go to ! 878: * the given continuation routine ! 879: */ ! 880: ! 881: void ! 882: call_continuation(void (*continuation)(void) ) ! 883: { ! 884: ! 885: unsigned int *kss; ! 886: vm_offset_t tsp; ! 887: ! 888: assert(current_thread()->kernel_stack); ! 889: kss = (unsigned int *)STACK_IKS(current_thread()->kernel_stack); ! 890: assert(continuation); ! 891: ! 892: tsp = (vm_offset_t)((int)kss - KF_SIZE); ! 893: assert(tsp); ! 894: *((int *)tsp) = 0; ! 895: ! 896: Call_continuation(continuation, tsp); ! 897: ! 898: return; ! 899: } ! 900: ! 901: void ! 902: thread_swapin_mach_alloc(thread_t thread) ! 903: { ! 904: struct savearea *sv; ! 905: ! 906: assert(thread->top_act->mact.pcb == 0); ! 907: ! 908: sv = save_alloc(); ! 909: assert(sv); ! 910: // bzero((char *) sv, sizeof(struct pcb)); ! 911: sv->save_act = thread->top_act; ! 912: thread->top_act->mact.pcb = (pcb_t)sv; ! 913: ! 914: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.