Annotation of XNU/osfmk/ppc/pcb.c, revision 1.1

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: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.