The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/osfmk/ppc/pcb.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*
    2  * Copyright (c) 2000-2004 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 css-dist@cs.utah.edu 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 <debug.h>
   48 
   49 #include <types.h>
   50 
   51 #include <mach/mach_types.h>
   52 #include <mach/thread_status.h>
   53 
   54 #include <kern/kern_types.h>
   55 #include <kern/task.h>
   56 #include <kern/thread.h>
   57 #include <kern/misc_protos.h>
   58 #include <kern/mach_param.h>
   59 #include <kern/spl.h>
   60 
   61 #include <vm/vm_map.h>
   62 #include <vm/vm_kern.h>
   63 
   64 #include <ppc/misc_protos.h>
   65 #include <ppc/cpu_internal.h>
   66 #include <ppc/exception.h>
   67 #include <ppc/proc_reg.h>
   68 #include <ppc/pmap.h>
   69 #include <ppc/trap.h>
   70 #include <ppc/mappings.h>
   71 #include <ppc/savearea.h>
   72 #include <ppc/Firmware.h>
   73 #include <ppc/asm.h>
   74 #include <ppc/thread.h>
   75 #include <ppc/vmachmon.h>
   76 #include <ppc/low_trace.h>
   77 #include <ppc/lowglobals.h>
   78 
   79 #include <sys/kdebug.h>
   80 
   81 void    machine_act_terminate(thread_t);
   82 
   83 /*
   84  * These constants are dumb. They should not be in asm.h!
   85  */
   86 
   87 #define KF_SIZE         (FM_SIZE+ARG_SIZE+FM_REDZONE)
   88 
   89 #if DEBUG
   90 int   fpu_trap_count = 0;
   91 int   fpu_switch_count = 0;
   92 int   vec_trap_count = 0;
   93 int   vec_switch_count = 0;
   94 #endif
   95 
   96 /*
   97  * consider_machine_collect: try to collect machine-dependent pages
   98  */
   99 void
  100 consider_machine_collect()
  101 {
  102     /*
  103      * none currently available
  104      */
  105         return;
  106 }
  107 
  108 void
  109 consider_machine_adjust()
  110 {
  111         consider_mapping_adjust();
  112 }
  113 
  114 /*
  115  * switch_context: Switch from one thread to another, needed for
  116  *                 switching of space
  117  * 
  118  */
  119 thread_t
  120 machine_switch_context(
  121         thread_t                        old,
  122         thread_continue_t       continuation,
  123         thread_t                        new)
  124 {
  125         register thread_t retval;
  126         pmap_t  new_pmap;
  127         facility_context *fowner;
  128         struct per_proc_info *ppinfo;
  129 
  130         if (old == new)
  131                 panic("machine_switch_context");
  132 
  133         ppinfo = getPerProc();                                                          /* Get our processor block */
  134 
  135         ppinfo->old_thread = (unsigned int)old;
  136         ppinfo->cpu_flags &= ~traceBE;                                           /* disable branch tracing if on */
  137                
  138         /* Our context might wake up on another processor, so we must
  139          * not keep hot state in our FPU, it must go back to the pcb
  140          * so that it can be found by the other if needed
  141          */
  142         if(real_ncpus > 1) {                                                            /* This is potentially slow, so only do when actually SMP */
  143                 fowner = ppinfo->FPU_owner;                                             /* Cache this because it may change */
  144                 if(fowner) {                                                                    /* Is there any live context? */
  145                         if(fowner->facAct == old) {             /* Is it for us? */
  146                                 fpu_save(fowner);                                               /* Yes, save it */
  147                         }
  148                 }
  149                 fowner = ppinfo->VMX_owner;                                             /* Cache this because it may change */
  150                 if(fowner) {                                                                    /* Is there any live context? */
  151                         if(fowner->facAct == old) {             /* Is it for us? */
  152                                 vec_save(fowner);                                               /* Yes, save it */
  153                         }
  154                 }
  155         }
  156 
  157         /*
  158          * If old thread is running VM, save per proc userProtKey and FamVMmode spcFlags bits in the thread spcFlags
  159          * This bits can be modified in the per proc without updating the thread spcFlags
  160          */
  161         if(old->machine.specFlags & runningVM) {
  162                 old->machine.specFlags &=  ~(userProtKey|FamVMmode);
  163                 old->machine.specFlags |= (ppinfo->spcFlags) & (userProtKey|FamVMmode);
  164         }
  165         old->machine.specFlags &= ~OnProc;
  166         new->machine.specFlags |= OnProc;
  167 
  168         /*
  169          * We do not have to worry about the PMAP module, so switch.
  170          *
  171          * We must not use thread->map since this may not be the actual
  172          * task map, but the map being used for a klcopyin/out.
  173          */
  174 
  175         if(new->machine.specFlags & runningVM) {                        /* Is the new guy running a VM? */
  176                 pmap_switch(new->machine.vmmCEntry->vmmPmap);   /* Switch to the VM's pmap */
  177                 ppinfo->VMMareaPhys = new->machine.vmmCEntry->vmmContextPhys;
  178                 ppinfo->VMMXAFlgs = new->machine.vmmCEntry->vmmXAFlgs;
  179                 ppinfo->FAMintercept = new->machine.vmmCEntry->vmmFAMintercept;
  180         }
  181         else {                                                                                          /* otherwise, we use the task's pmap */
  182                 new_pmap = new->task->map->pmap;
  183                 if ((old->task->map->pmap != new_pmap) || (old->machine.specFlags & runningVM)) {
  184                         pmap_switch(new_pmap);                                          /* Switch if there is a change */
  185                 }
  186         }
  187 
  188         if(old->machine.umwSpace != invalSpace) {                       /* Does our old guy have an active window? */
  189                 old->machine.umwSpace |= umwSwitchAway;                 /* Show we switched away from this guy */
  190                 hw_blow_seg(lowGlo.lgUMWvaddr);                                 /* Blow off the first segment */
  191                 hw_blow_seg(lowGlo.lgUMWvaddr + 0x10000000ULL); /* Blow off the second segment */
  192         }
  193 
  194         KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_SCHED) | DBG_FUNC_NONE,
  195                      old->reason, (int)new, old->sched_pri, new->sched_pri, 0);
  196 
  197         retval = Switch_context(old, continuation, new);
  198         assert(retval != NULL);
  199 
  200         if (branch_tracing_enabled()) {
  201                 ppinfo = getPerProc();                                                  /* Get our processor block */
  202                 ppinfo->cpu_flags |= traceBE;                                   /* restore branch tracing */
  203         }
  204 
  205         /* We've returned from having switched context, so we should be
  206          * back in the original context.
  207          */
  208 
  209         return retval;
  210 }
  211 
  212 /*
  213  * Initialize the machine-dependent state for a new thread.
  214  */
  215 kern_return_t
  216 machine_thread_create(
  217         thread_t                thread,
  218         task_t                  task)
  219 {
  220         savearea                *sv;                                                                    /* Pointer to newly allocated savearea */
  221         unsigned int    *CIsTooLimited, i;
  222 
  223         hw_atomic_add((uint32_t *)&saveanchor.savetarget, 4);   /* Account for the number of saveareas we think we "need"
  224                                                                                                                            for this activation */
  225         assert(thread->machine.pcb == (savearea *)0);                           /* Make sure there was no previous savearea */
  226         
  227         sv = save_alloc();                                                                              /* Go get us a savearea */
  228                 
  229         bzero((char *)((unsigned int)sv + sizeof(savearea_comm)), (sizeof(savearea) - sizeof(savearea_comm)));  /* Clear it */
  230                 
  231         sv->save_hdr.save_prev = 0;                                                             /* Clear the back pointer */
  232         sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft);   /* Mark as in use */
  233         sv->save_hdr.save_act = thread; /* Set who owns it */
  234         thread->machine.pcb = sv;                                                                       /* Point to the save area */
  235         thread->machine.curctx = &thread->machine.facctx;                       /* Initialize facility context */
  236         thread->machine.facctx.facAct = thread;                                         /* Initialize facility context pointer to activation */
  237         thread->machine.umwSpace = invalSpace;                                          /* Initialize user memory window space to invalid */
  238         thread->machine.preemption_count = 0;                                           /* Initialize preemption counter */
  239 
  240         /*
  241          * User threads will pull their context from the pcb when first
  242          * returning to user mode, so fill in all the necessary values.
  243          * Kernel threads are initialized from the save state structure 
  244          * at the base of the kernel stack (see stack_attach()).
  245          */
  246 
  247         thread->machine.upcb = sv;                                                              /* Set user pcb */
  248         sv->save_srr1 = (uint64_t)MSR_EXPORT_MASK_SET;                  /* Set the default user MSR */
  249         if(task_has_64BitAddr(task)) sv->save_srr1 |= (uint64_t)MASK32(MSR_SF) << 32;   /* If 64-bit task, force 64-bit mode */
  250         sv->save_fpscr = 0;                                                                             /* Clear all floating point exceptions */
  251         sv->save_vrsave = 0;                                                                    /* Set the vector save state */
  252         sv->save_vscr[0] = 0x00000000;                                  
  253         sv->save_vscr[1] = 0x00000000;                                  
  254         sv->save_vscr[2] = 0x00000000;                                  
  255         sv->save_vscr[3] = 0x00010000;                                                  /* Disable java mode and clear saturated */
  256         
  257     return(KERN_SUCCESS);
  258 }
  259 
  260 /*
  261  * Machine-dependent cleanup prior to destroying a thread
  262  */
  263 void
  264 machine_thread_destroy(
  265         thread_t                thread)
  266 {
  267         register savearea *pcb, *ppsv;
  268         register savearea_vec *vsv, *vpsv;
  269         register savearea_fpu *fsv, *fpsv;
  270         register savearea *svp;
  271         register int i;
  272         boolean_t intr;
  273 
  274 /*
  275  *      This function will release all context.
  276  */
  277 
  278         machine_act_terminate(thread);                                                  /* Make sure all virtual machines are dead first */
  279  
  280 /*
  281  *
  282  *      Walk through and release all floating point and vector contexts. Also kill live context.
  283  *
  284  */
  285 
  286         intr = ml_set_interrupts_enabled(FALSE);                                /* Disable for interruptions */
  287  
  288         toss_live_vec(thread->machine.curctx);                                  /* Dump live vectors */
  289 
  290         vsv = thread->machine.curctx->VMXsave;                                  /* Get the top vector savearea */
  291         
  292         while(vsv) {                                                                                    /* Any VMX saved state? */
  293                 vpsv = vsv;                                                                                     /* Remember so we can toss this */
  294                 vsv = CAST_DOWN(savearea_vec *, vsv->save_hdr.save_prev);  /* Get one underneath our's */
  295                 save_release((savearea *)vpsv);                                         /* Release it */
  296         }
  297         
  298         thread->machine.curctx->VMXsave = 0;                                    /* Kill chain */
  299  
  300         toss_live_fpu(thread->machine.curctx);                                  /* Dump live float */
  301 
  302         fsv = thread->machine.curctx->FPUsave;                                  /* Get the top float savearea */
  303         
  304         while(fsv) {                                                                                    /* Any float saved state? */
  305                 fpsv = fsv;                                                                                     /* Remember so we can toss this */
  306                 fsv = CAST_DOWN(savearea_fpu *, fsv->save_hdr.save_prev);   /* Get one underneath our's */
  307                 save_release((savearea *)fpsv);                                         /* Release it */
  308         }
  309         
  310         thread->machine.curctx->FPUsave = 0;                                    /* Kill chain */
  311 
  312 /*
  313  * free all regular saveareas.
  314  */
  315 
  316         pcb = thread->machine.pcb;                                                              /* Get the general savearea */
  317         
  318         while(pcb) {                                                                                    /* Any float saved state? */
  319                 ppsv = pcb;                                                                                     /* Remember so we can toss this */
  320                 pcb = CAST_DOWN(savearea *, pcb->save_hdr.save_prev);  /* Get one underneath our's */ 
  321                 save_release(ppsv);                                                                     /* Release it */
  322         }
  323         
  324         hw_atomic_sub((uint32_t *)&saveanchor.savetarget, 4);   /* Unaccount for the number of saveareas we think we "need" */
  325 
  326         (void) ml_set_interrupts_enabled(intr);                                 /* Restore interrupts if enabled */
  327 
  328 }
  329 
  330 /*
  331  * act_machine_sv_free
  332  * release saveareas associated with an act. if flag is true, release
  333  * user level savearea(s) too, else don't
  334  *
  335  * This code must run with interruptions disabled because an interrupt handler could use
  336  * floating point and/or vectors.  If this happens and the thread we are blowing off owns
  337  * the facility, we can deadlock.
  338  */
  339 void
  340 act_machine_sv_free(thread_t act)
  341 {
  342         register savearea *pcb, *userpcb;
  343         register savearea_vec *vsv, *vpst, *vsvt;
  344         register savearea_fpu *fsv, *fpst, *fsvt;
  345         register savearea *svp;
  346         register int i;
  347         boolean_t intr;
  348 
  349 /*
  350  *      This function will release all non-user state context.
  351  */
  352  
  353 /*
  354  *
  355  *      Walk through and release all floating point and vector contexts that are not
  356  *      user state.  We will also blow away live context if it belongs to non-user state.
  357  *      Note that the level can not change while we are in this code.  Nor can another
  358  *      context be pushed on the stack.
  359  *
  360  *      We do nothing here if the current level is user.  Otherwise,
  361  *      the live context is cleared.  Then we find the user saved context.
  362  *      Next,  we take the sync lock (to keep us from munging things in *_switch).
  363  *      The level is set to 0 and all stacked context other than user is dequeued.
  364  *      Then we unlock.  Next, all of the old kernel contexts are released.
  365  *
  366  */
  367 
  368         intr = ml_set_interrupts_enabled(FALSE);                                /* Disable for interruptions */
  369 
  370         if(act->machine.curctx->VMXlevel) {                                             /* Is the current level user state? */
  371                 
  372                 toss_live_vec(act->machine.curctx);                                     /* Dump live vectors if is not user */
  373                 
  374                 if(!hw_lock_to((hw_lock_t)&act->machine.curctx->VMXsync, LockTimeOut)) {        /* Get the sync lock */ 
  375                         panic("act_machine_sv_free - timeout getting VMX sync lock\n"); /* Tell all and die */
  376                 }
  377         
  378                 vsv = act->machine.curctx->VMXsave;                                     /* Get the top vector savearea */
  379                 while(vsv && vsv->save_hdr.save_level) vsv = (savearea_vec *)vsv->save_hdr.save_prev;   /* Find user context if any */
  380                 
  381                 vsvt = act->machine.curctx->VMXsave;                            /* Get the top of the chain */
  382                 act->machine.curctx->VMXsave = vsv;                                     /* Point to the user context */
  383                 act->machine.curctx->VMXlevel = 0;                                      /* Set the level to user */
  384                 hw_lock_unlock((hw_lock_t)&act->machine.curctx->VMXsync);       /* Unlock */
  385                 
  386                 while(vsvt) {                                                                           /* Clear any VMX saved state */
  387                         if (vsvt == vsv) break;                                                 /* Done when hit user if any */
  388                         vpst = vsvt;                                                                    /* Remember so we can toss this */
  389                         vsvt = (savearea_vec *)vsvt->save_hdr.save_prev;        /* Get one underneath our's */          
  390                         save_ret((savearea *)vpst);                                             /* Release it */
  391                 }
  392                 
  393         }
  394  
  395         if(act->machine.curctx->FPUlevel) {                                             /* Is the current level user state? */
  396                 
  397                 toss_live_fpu(act->machine.curctx);                                     /* Dump live floats if is not user */
  398 
  399                 if(!hw_lock_to((hw_lock_t)&act->machine.curctx->FPUsync, LockTimeOut)) {        /* Get the sync lock */ 
  400                         panic("act_machine_sv_free - timeout getting FPU sync lock\n"); /* Tell all and die */
  401                 }
  402                 
  403                 fsv = act->machine.curctx->FPUsave;                                     /* Get the top floats savearea */
  404                 while(fsv && fsv->save_hdr.save_level) fsv = (savearea_fpu *)fsv->save_hdr.save_prev;   /* Find user context if any */
  405                 
  406                 fsvt = act->machine.curctx->FPUsave;                            /* Get the top of the chain */
  407                 act->machine.curctx->FPUsave = fsv;                                     /* Point to the user context */
  408                 act->machine.curctx->FPUlevel = 0;                                      /* Set the level to user */
  409                 hw_lock_unlock((hw_lock_t)&act->machine.curctx->FPUsync);       /* Unlock */
  410                 
  411                 while(fsvt) {                                                                           /* Clear any VMX saved state */
  412                         if (fsvt == fsv) break;                                                 /* Done when hit user if any */
  413                         fpst = fsvt;                                                                    /* Remember so we can toss this */
  414                         fsvt = (savearea_fpu *)fsvt->save_hdr.save_prev;        /* Get one underneath our's */          
  415                         save_ret((savearea *)fpst);                                             /* Release it */
  416                 }
  417                 
  418         }
  419 
  420 /*
  421  * free all regular saveareas except a user savearea, if any
  422  */
  423 
  424         pcb = act->machine.pcb;                                                                 /* Get the general savearea */
  425         userpcb = 0;                                                                                    /* Assume no user context for now */
  426         
  427         while(pcb) {                                                                                    /* Any float saved state? */
  428                 if (pcb->save_srr1 & MASK(MSR_PR)) {                            /* Is this a user savearea? */
  429                         userpcb = pcb;                                                                  /* Remember so we can toss this */
  430                         break;
  431                 }
  432                 svp = pcb;                                                                                      /* Remember this */
  433                 pcb = CAST_DOWN(savearea *, pcb->save_hdr.save_prev);  /* Get one underneath our's */ 
  434                 save_ret(svp);                                                                          /* Release it */
  435         }
  436         
  437         act->machine.pcb = userpcb;                                                             /* Chain in the user if there is one, or 0 if not */
  438         (void) ml_set_interrupts_enabled(intr);                                 /* Restore interrupts if enabled */
  439 
  440 }
  441 
  442 void
  443 machine_act_terminate(
  444         thread_t        act)
  445 {
  446         if(act->machine.bbDescAddr) {                                                   /* Check if the Blue box assist is active */
  447                 disable_bluebox_internal(act);                                          /* Kill off bluebox */
  448         }
  449         
  450         if(act->machine.vmmControl) {                                                   /* Check if VMM is active */
  451                 vmm_tear_down_all(act);                                                         /* Kill off all VMM contexts */
  452         }
  453 }
  454 
  455 void
  456 machine_thread_terminate_self(void)
  457 {
  458         machine_act_terminate(current_thread());
  459 }
  460 
  461 void
  462 machine_thread_init(void)
  463 {
  464 #ifdef  MACHINE_STACK
  465 #if KERNEL_STACK_SIZE > PPC_PGBYTES
  466         panic("KERNEL_STACK_SIZE can't be greater than PPC_PGBYTES\n");
  467 #endif
  468 #endif
  469 }
  470 
  471 #if MACH_ASSERT
  472 
  473 void
  474 dump_thread(thread_t th)
  475 {
  476         printf(" thread @ 0x%x:\n", th);
  477 }
  478 
  479 int
  480     dump_act(thread_t thr_act)
  481 {
  482     if (!thr_act)
  483         return(0);
  484 
  485     printf("thread(0x%x)(%d): task=%x(%d)\n",
  486            thr_act, thr_act->ref_count,
  487            thr_act->task,   thr_act->task   ? thr_act->task->ref_count : 0);
  488 
  489     printf("\tsusp=%x active=%x\n",
  490            thr_act->suspend_count, thr_act->active);
  491 
  492     return((int)thr_act);
  493 }
  494 
  495 #endif
  496 
  497 user_addr_t 
  498 get_useraddr()
  499 {
  500         return(current_thread()->machine.upcb->save_srr0);
  501 }
  502 
  503 /*
  504  * detach and return a kernel stack from a thread
  505  */
  506 
  507 vm_offset_t
  508 machine_stack_detach(
  509         thread_t                thread)
  510 {
  511   vm_offset_t stack;
  512 
  513   KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_DETACH),
  514                                                                                         thread, thread->priority,
  515                                                                                         thread->sched_pri, 0, 0);
  516 
  517   act_machine_sv_free(thread);
  518 
  519   stack = thread->kernel_stack;
  520   thread->kernel_stack = 0;
  521   return(stack);
  522 }
  523 
  524 /*
  525  * attach a kernel stack to a thread and initialize it
  526  *
  527  * attaches a stack to a thread. if there is no save
  528  * area we allocate one.  the top save area is then
  529  * loaded with the pc (continuation address), the initial
  530  * stack pointer, and a std kernel MSR. if the top
  531  * save area is the user save area bad things will 
  532  * happen
  533  *
  534  */
  535 
  536 void
  537 machine_stack_attach(
  538         thread_t                thread,
  539         vm_offset_t             stack)
  540 {
  541   unsigned int *kss;
  542   struct savearea *sv;
  543 
  544         KERNEL_DEBUG(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_ATTACH),
  545             thread, thread->priority,
  546             thread->sched_pri, 0, 0);
  547 
  548   assert(stack);
  549   kss = (unsigned int *)STACK_IKS(stack);
  550   thread->kernel_stack = stack;
  551 
  552   /* during initialization we sometimes do not have an
  553      activation. in that case do not do anything */
  554   sv = save_get();  /* cannot block */
  555   sv->save_hdr.save_flags = (sv->save_hdr.save_flags & ~SAVtype) | (SAVgeneral << SAVtypeshft); /* Mark as in use */
  556   sv->save_hdr.save_act = thread;
  557   sv->save_hdr.save_prev = (addr64_t)((uintptr_t)thread->machine.pcb);
  558   thread->machine.pcb = sv;
  559 
  560   sv->save_srr0 = (unsigned int)thread_continue;
  561   /* sv->save_r3 = ARG ? */
  562   sv->save_r1 = (vm_offset_t)((int)kss - KF_SIZE);
  563   sv->save_srr1 = MSR_SUPERVISOR_INT_OFF;
  564   sv->save_fpscr = 0;                                                                   /* Clear all floating point exceptions */
  565   sv->save_vrsave = 0;                                                          /* Set the vector save state */
  566   sv->save_vscr[3] = 0x00010000;                                                /* Supress java mode */
  567   *(CAST_DOWN(int *, sv->save_r1)) = 0;
  568 
  569   thread->machine.ksp = 0;                            
  570 }
  571 
  572 /*
  573  * move a stack from old to new thread
  574  */
  575 
  576 void
  577 machine_stack_handoff(
  578         thread_t                old,
  579         thread_t                new)
  580 {
  581 
  582         vm_offset_t stack;
  583         pmap_t new_pmap;
  584         facility_context *fowner;
  585         mapping_t *mp;
  586         struct per_proc_info *ppinfo;
  587         
  588         assert(new);
  589         assert(old);
  590 
  591         if (old == new)
  592                 panic("machine_stack_handoff");
  593         
  594         stack = machine_stack_detach(old);
  595         new->kernel_stack = stack;
  596         if (stack == old->reserved_stack) {
  597                 assert(new->reserved_stack);
  598                 old->reserved_stack = new->reserved_stack;
  599                 new->reserved_stack = stack;
  600         }
  601 
  602         ppinfo = getPerProc();                                                          /* Get our processor block */
  603 
  604         ppinfo->cpu_flags &= ~traceBE;                                          /* Turn off special branch trace */
  605 
  606         if(real_ncpus > 1) {                                                            /* This is potentially slow, so only do when actually SMP */
  607                 fowner = ppinfo->FPU_owner;                                             /* Cache this because it may change */
  608                 if(fowner) {                                                                    /* Is there any live context? */
  609                         if(fowner->facAct == old) {             /* Is it for us? */
  610                                 fpu_save(fowner);                                               /* Yes, save it */
  611                         }
  612                 }
  613                 fowner = ppinfo->VMX_owner;                                             /* Cache this because it may change */
  614                 if(fowner) {                                                                    /* Is there any live context? */
  615                         if(fowner->facAct == old) {             /* Is it for us? */
  616                                 vec_save(fowner);                                               /* Yes, save it */
  617                         }
  618                 }
  619         }
  620 
  621         /*
  622          * If old thread is running VM, save per proc userProtKey and FamVMmode spcFlags bits in the thread spcFlags
  623          * This bits can be modified in the per proc without updating the thread spcFlags
  624          */
  625         if(old->machine.specFlags & runningVM) {                        /* Is the current thread running a VM? */
  626                 old->machine.specFlags &= ~(userProtKey|FamVMmode);
  627                 old->machine.specFlags |= (ppinfo->spcFlags) & (userProtKey|FamVMmode);
  628         }
  629         old->machine.specFlags &= ~OnProc;
  630         new->machine.specFlags |= OnProc;
  631 
  632         KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_SCHED,MACH_STACK_HANDOFF) | DBG_FUNC_NONE,
  633                      old->reason, (int)new, old->sched_pri, new->sched_pri, 0);
  634 
  635 
  636         if(new->machine.specFlags & runningVM) {        /* Is the new guy running a VM? */
  637                 pmap_switch(new->machine.vmmCEntry->vmmPmap);   /* Switch to the VM's pmap */
  638                 ppinfo->VMMareaPhys = new->machine.vmmCEntry->vmmContextPhys;
  639                 ppinfo->VMMXAFlgs = new->machine.vmmCEntry->vmmXAFlgs;
  640                 ppinfo->FAMintercept = new->machine.vmmCEntry->vmmFAMintercept;
  641         }
  642         else {                                                                                  /* otherwise, we use the task's pmap */
  643                 new_pmap = new->task->map->pmap;
  644                 if ((old->task->map->pmap != new_pmap) || (old->machine.specFlags & runningVM)) {
  645                         pmap_switch(new_pmap);
  646                 }
  647         }
  648 
  649         machine_set_current_thread(new);
  650         ppinfo->Uassist = new->machine.cthread_self;
  651 
  652         ppinfo->ppbbTaskEnv = new->machine.bbTaskEnv;
  653         ppinfo->spcFlags = new->machine.specFlags;
  654         
  655         old->machine.umwSpace |= umwSwitchAway;                 /* Show we switched away from this guy */
  656         mp = (mapping_t *)&ppinfo->ppUMWmp;
  657         mp->mpSpace = invalSpace;                                               /* Since we can't handoff in the middle of copy in/out, just invalidate */
  658 
  659         if (branch_tracing_enabled()) 
  660                 ppinfo->cpu_flags |= traceBE;
  661     
  662         if(trcWork.traceMask) dbgTrace(0x9903, (unsigned int)old, (unsigned int)new, 0, 0);     /* Cut trace entry if tracing */    
  663     
  664   return;
  665 }
  666 
  667 /*
  668  * clean and initialize the current kernel stack and go to
  669  * the given continuation routine
  670  */
  671 
  672 void
  673 call_continuation(
  674         thread_continue_t       continuation,
  675         void                            *parameter,
  676         wait_result_t           wresult)
  677 {
  678         thread_t                self = current_thread();
  679         unsigned int    *kss;
  680         vm_offset_t             tsp;
  681 
  682         assert(self->kernel_stack);
  683         kss = (unsigned int *)STACK_IKS(self->kernel_stack);
  684         assert(continuation);
  685 
  686         tsp = (vm_offset_t)((int)kss - KF_SIZE);
  687         assert(tsp);
  688         *((int *)tsp) = 0;
  689 
  690         Call_continuation(continuation, parameter, wresult, tsp);
  691 }

Cache object: a5d4db7a935e918e0eff64de34983415


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.