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/PseudoKernel.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 Apple Computer, Inc. All rights reserved.
    3  *
    4  * @APPLE_LICENSE_HEADER_START@
    5  * 
    6  * Copyright (c) 1999-2003 Apple Computer, Inc.  All Rights Reserved.
    7  * 
    8  * This file contains Original Code and/or Modifications of Original Code
    9  * as defined in and that are subject to the Apple Public Source License
   10  * Version 2.0 (the 'License'). You may not use this file except in
   11  * compliance with the License. Please obtain a copy of the License at
   12  * http://www.opensource.apple.com/apsl/ and read it before using this
   13  * file.
   14  * 
   15  * The Original Code and all software distributed under the License are
   16  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
   17  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
   18  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
   19  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
   20  * Please see the License for the specific language governing rights and
   21  * limitations under the License.
   22  * 
   23  * @APPLE_LICENSE_HEADER_END@
   24  */
   25 /*
   26         File:           PseudoKernel.c
   27 
   28         Contains:       BlueBox PseudoKernel calls
   29         Written by:     Mark Gorlinsky
   30                                 Bill Angell
   31 
   32         Copyright:      1997 by Apple Computer, Inc., all rights reserved
   33 
   34 */
   35 
   36 #include <mach/mach_types.h>
   37 #include <mach/kern_return.h>
   38 #include <kern/host.h>
   39 #include <kern/task.h>
   40 #include <kern/thread.h>
   41 #include <ppc/PseudoKernel.h>
   42 #include <ppc/exception.h>
   43 #include <ppc/misc_protos.h>
   44 #include <ppc/proc_reg.h>
   45 #include <vm/vm_kern.h>
   46 
   47 void bbSetRupt(ReturnHandler *rh, thread_act_t ct);
   48 
   49 /*
   50 ** Function:    NotifyInterruption
   51 **
   52 ** Inputs:
   53 **              ppcInterrupHandler      - interrupt handler to execute
   54 **              interruptStatePtr       - current interrupt state
   55 **
   56 ** Outputs:
   57 **
   58 ** Notes:
   59 **
   60 */
   61 kern_return_t syscall_notify_interrupt ( void ) {
   62   
   63     UInt32                      interruptState; 
   64     task_t                      task;
   65         thread_act_t    act, fact;
   66         thread_t                thread;
   67         bbRupt                  *bbr;
   68         BTTD_t                  *bttd;
   69         int                             i;
   70 
   71         task = current_task();                                                  /* Figure out who our task is */
   72 
   73         task_lock(task);                                                /* Lock our task */
   74         
   75         fact = (thread_act_t)task->threads.next;                /* Get the first activation on task */
   76         act = 0;                                                                                /* Pretend we didn't find it yet */
   77         
   78         for(i = 0; i < task->thread_count; i++) {               /* Scan the whole list */
   79                 if(fact->mact.bbDescAddr) {                                     /* Is this a Blue thread? */
   80                         bttd = (BTTD_t *)(fact->mact.bbDescAddr & -PAGE_SIZE);
   81                         if(bttd->InterruptVector) {                             /* Is this the Blue interrupt thread? */
   82                                 act = fact;                                                     /* Yeah... */
   83                                 break;                                                          /* Found it, Bail the loop... */
   84                         }
   85                 }
   86                 fact = (thread_act_t)fact->task_threads.next;   /* Go to the next one */
   87         }
   88 
   89         if(!act) {                                                              /* Couldn't find a bluebox */
   90                 task_unlock(task);                                      /* Release task lock */
   91                 return KERN_FAILURE;                            /* No tickie, no shirtee... */
   92         }
   93         
   94         act_lock_thread(act);                                                   /* Make sure this stays 'round */
   95         task_unlock(task);                                                              /* Safe to release now */
   96 
   97         /* if the calling thread is the BlueBox thread that handles interrupts
   98          * we know that we are in the PsuedoKernel and we can short circuit 
   99          * setting up the asynchronous task by setting a pending interrupt.
  100          */
  101         
  102         if ( (unsigned int)act == (unsigned int)current_act() ) {               
  103                 bttd->InterruptControlWord = bttd->InterruptControlWord | 
  104                         ((bttd->postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
  105                                 
  106                 act_unlock_thread(act);                                         /* Unlock the activation */
  107                 return KERN_SUCCESS;
  108         }
  109 
  110         if(act->mact.emPendRupts >= 16) {                               /* Have we hit the arbitrary maximum? */
  111                 act_unlock_thread(act);                                         /* Unlock the activation */
  112                 return KERN_RESOURCE_SHORTAGE;                          /* Too many pending right now */
  113         }
  114         
  115         if(!(bbr = (bbRupt *)kalloc(sizeof(bbRupt)))) { /* Get a return handler control block */
  116                 act_unlock_thread(act);                                         /* Unlock the activation */
  117                 return KERN_RESOURCE_SHORTAGE;                          /* No storage... */
  118         }
  119         
  120         (void)hw_atomic_add(&act->mact.emPendRupts, 1); /* Count this 'rupt */
  121         bbr->rh.handler = bbSetRupt;                                    /* Set interruption routine */
  122 
  123         bbr->rh.next = act->handlers;                                   /* Put our interrupt at the start of the list */
  124         act->handlers = &bbr->rh;
  125 
  126         act_set_apc(act);                                                               /* Set an APC AST */
  127 
  128         act_unlock_thread(act);                                                 /* Unlock the activation */
  129         return KERN_SUCCESS;                                                    /* We're done... */
  130 }
  131 
  132 /* 
  133  *      This guy is fired off asynchronously to actually do the 'rupt.
  134  *      We will find the user state savearea and modify it.  If we can't,
  135  *      we just leave after releasing our work area
  136  */
  137 
  138 void bbSetRupt(ReturnHandler *rh, thread_act_t act) {
  139 
  140         savearea        *sv;
  141         BTTD_t          *bttd;
  142         bbRupt          *bbr;
  143         UInt32          interruptState;
  144         
  145         bbr = (bbRupt *)rh;                                                             /* Make our area convenient */
  146 
  147         if(!(act->mact.bbDescAddr)) {                                   /* Is BlueBox still enabled? */
  148                 kfree((vm_offset_t)bbr, sizeof(bbRupt));        /* No, release the control block */
  149                 return;
  150         }
  151 
  152         (void)hw_atomic_sub(&act->mact.emPendRupts, 1); /* Uncount this 'rupt */
  153 
  154         if(!(sv = find_user_regs(act))) {                               /* Find the user state registers */
  155                 kfree((vm_offset_t)bbr, sizeof(bbRupt));        /* Couldn't find 'em, release the control block */
  156                 return;
  157         }
  158 
  159         bttd = (BTTD_t *)(act->mact.bbDescAddr & -PAGE_SIZE);
  160                 
  161     interruptState = (bttd->InterruptControlWord & kInterruptStateMask) >> kInterruptStateShift; 
  162 
  163     switch (interruptState) {
  164                 
  165                 case kInSystemContext:
  166                         sv->save_cr |= bttd->postIntMask;               /* post int in CR2 */
  167                         break;
  168                         
  169                 case kInAlternateContext:
  170                         bttd->InterruptControlWord = (bttd->InterruptControlWord & ~kInterruptStateMask) | 
  171                                 (kInPseudoKernel << kInterruptStateShift);
  172                                 
  173                         bttd->exceptionInfo.srr0 = (unsigned int)sv->save_srr0;         /* Save the current PC */
  174                         sv->save_srr0 = (uint64_t)act->mact.bbInterrupt;        /* Set the new PC */
  175                         bttd->exceptionInfo.sprg1 = (unsigned int)sv->save_r1;          /* Save the original R1 */
  176                         sv->save_r1 = (uint64_t)bttd->exceptionInfo.sprg0;      /* Set the new R1 */
  177                         bttd->exceptionInfo.srr1 = (unsigned int)sv->save_srr1;         /* Save the original MSR */
  178                         sv->save_srr1 &= ~(MASK(MSR_BE)|MASK(MSR_SE));  /* Clear SE|BE bits in MSR */
  179                         act->mact.specFlags &= ~bbNoMachSC;                             /* reactivate Mach SCs */ 
  180                         disable_preemption();                                                   /* Don't move us around */
  181                         per_proc_info[cpu_number()].spcFlags = act->mact.specFlags;     /* Copy the flags */
  182                         enable_preemption();                                                    /* Ok to move us around */
  183                         /* drop through to post int in backup CR2 in ICW */
  184 
  185                 case kInExceptionHandler:
  186                 case kInPseudoKernel:
  187                 case kOutsideBlue:
  188                         bttd->InterruptControlWord = bttd->InterruptControlWord | 
  189                                 ((bttd->postIntMask >> kCR2ToBackupShift) & kBackupCR2Mask);
  190                         break;
  191                                 
  192                 default:
  193                         break;
  194         }
  195 
  196         kfree((vm_offset_t)bbr, sizeof(bbRupt));        /* Release the control block */
  197         return;
  198 
  199 }
  200 
  201 /*
  202  * This function is used to enable the firmware assist code for bluebox traps, system calls
  203  * and interrupts.
  204  *
  205  * The assist code can be called from two types of threads.  The blue thread, which handles 
  206  * traps, system calls and interrupts and preemptive threads that only issue system calls.
  207  *
  208  */ 
  209 
  210 kern_return_t enable_bluebox(
  211       host_t host,
  212           void *taskID,                                                         /* opaque task ID */
  213           void *TWI_TableStart,                                         /* Start of TWI table */
  214           char *Desc_TableStart                                         /* Start of descriptor table */
  215          ) {
  216         
  217         thread_t                th;
  218         vm_offset_t             kerndescaddr, origdescoffset;
  219         kern_return_t   ret;
  220         ppnum_t                 physdescpage;
  221         BTTD_t                  *bttd;
  222         
  223         th = current_thread();                                                                  /* Get our thread */                                    
  224 
  225         if ( host == HOST_NULL ) return KERN_INVALID_HOST;
  226         if ( ! is_suser() ) return KERN_FAILURE;                                                /* We will only do this for the superuser */
  227         if ( th->top_act->mact.bbDescAddr ) return KERN_FAILURE;                /* Bail if already authorized... */
  228         if ( ! (unsigned int) Desc_TableStart ) return KERN_FAILURE;    /* There has to be a descriptor page */ 
  229         if ( ! TWI_TableStart ) return KERN_FAILURE;                                    /* There has to be a TWI table */ 
  230 
  231         /* Get the page offset of the descriptor */
  232         origdescoffset = (vm_offset_t)Desc_TableStart & (PAGE_SIZE - 1);
  233 
  234         /* Align the descriptor to a page */
  235         Desc_TableStart = (char *)((vm_offset_t)Desc_TableStart & -PAGE_SIZE);
  236 
  237         ret = vm_map_wire(th->top_act->map,                                     /* Kernel wire the descriptor in the user's map */
  238                 (vm_offset_t)Desc_TableStart,
  239                 (vm_offset_t)Desc_TableStart + PAGE_SIZE,
  240                 VM_PROT_READ | VM_PROT_WRITE,
  241                 FALSE);                                                                                                                 
  242                 
  243         if(ret != KERN_SUCCESS) {                                                               /* Couldn't wire it, spit on 'em... */
  244                 return KERN_FAILURE;    
  245         }
  246                 
  247         physdescpage =                                                                                  /* Get the physical page number of the page */
  248                 pmap_find_phys(th->top_act->map->pmap, (addr64_t)Desc_TableStart);
  249 
  250         ret =  kmem_alloc_pageable(kernel_map, &kerndescaddr, PAGE_SIZE);       /* Find a virtual address to use */
  251         if(ret != KERN_SUCCESS) {                                                               /* Could we get an address? */
  252                 (void) vm_map_unwire(th->top_act->map,                          /* No, unwire the descriptor */
  253                         (vm_offset_t)Desc_TableStart,
  254                         (vm_offset_t)Desc_TableStart + PAGE_SIZE,
  255                         TRUE);
  256                 return KERN_FAILURE;                                                            /* Split... */
  257         }
  258         
  259         (void) pmap_enter(kernel_pmap,                                                  /* Map this into the kernel */
  260                 kerndescaddr, physdescpage, VM_PROT_READ|VM_PROT_WRITE, 
  261                 VM_WIMG_USE_DEFAULT, TRUE);
  262         
  263         bttd = (BTTD_t *)kerndescaddr;                                                  /* Get the address in a convienient spot */ 
  264         
  265         th->top_act->mact.bbDescAddr = (unsigned int)kerndescaddr+origdescoffset;       /* Set kernel address of the table */
  266         th->top_act->mact.bbUserDA = (unsigned int)Desc_TableStart;     /* Set user address of the table */
  267         th->top_act->mact.bbTableStart = (unsigned int)TWI_TableStart;  /* Set address of the trap table */
  268         th->top_act->mact.bbTaskID = (unsigned int)taskID;              /* Assign opaque task ID */
  269         th->top_act->mact.bbTaskEnv = 0;                                                /* Clean task environment data */
  270         th->top_act->mact.emPendRupts = 0;                                              /* Clean pending 'rupt count */
  271         th->top_act->mact.bbTrap = bttd->TrapVector;                    /* Remember trap vector */
  272         th->top_act->mact.bbSysCall = bttd->SysCallVector;              /* Remember syscall vector */
  273         th->top_act->mact.bbInterrupt = bttd->InterruptVector;  /* Remember interrupt vector */
  274         th->top_act->mact.bbPending = bttd->PendingIntVector;   /* Remember pending vector */
  275         th->top_act->mact.specFlags &= ~(bbNoMachSC | bbPreemptive);    /* Make sure mach SCs are enabled and we are not marked preemptive */
  276         th->top_act->mact.specFlags |= bbThread;                                /* Set that we are Classic thread */
  277                 
  278         if(!(bttd->InterruptVector)) {                                                  /* See if this is a preemptive (MP) BlueBox thread */
  279                 th->top_act->mact.specFlags |= bbPreemptive;            /* Yes, remember it */
  280         }
  281                 
  282         disable_preemption();                                                                   /* Don't move us around */
  283         per_proc_info[cpu_number()].spcFlags = th->top_act->mact.specFlags;     /* Copy the flags */
  284         enable_preemption();                                                                    /* Ok to move us around */
  285                 
  286         {
  287                 /* mark the proc to indicate that this is a TBE proc */
  288                 extern void tbeproc(void *proc);
  289 
  290                 tbeproc(th->top_act->task->bsd_info);
  291         }
  292 
  293         return KERN_SUCCESS;
  294 }
  295 
  296 kern_return_t disable_bluebox( host_t host ) {                          /* User call to terminate bluebox */
  297         
  298         thread_act_t    act;
  299         
  300         act = current_act();                                                                    /* Get our thread */                                    
  301 
  302         if (host == HOST_NULL) return KERN_INVALID_HOST;
  303         
  304         if(!is_suser()) return KERN_FAILURE;                                    /* We will only do this for the superuser */
  305         if(!act->mact.bbDescAddr) return KERN_FAILURE;                  /* Bail if not authorized... */
  306 
  307         disable_bluebox_internal(act);                                                  /* Clean it all up */
  308         return KERN_SUCCESS;                                                                    /* Leave */
  309 }
  310 
  311 void disable_bluebox_internal(thread_act_t act) {                       /* Terminate bluebox */
  312                 
  313         (void) vm_map_unwire(act->map,                                                  /* Unwire the descriptor in user's address space */
  314                 (vm_offset_t)act->mact.bbUserDA,
  315                 (vm_offset_t)act->mact.bbUserDA + PAGE_SIZE,
  316                 FALSE);
  317                 
  318         kmem_free(kernel_map, (vm_offset_t)act->mact.bbDescAddr & -PAGE_SIZE, PAGE_SIZE);       /* Release the page */
  319         
  320         act->mact.bbDescAddr = 0;                                                               /* Clear kernel pointer to it */
  321         act->mact.bbUserDA = 0;                                                                 /* Clear user pointer to it */
  322         act->mact.bbTableStart = 0;                                                             /* Clear user pointer to TWI table */
  323         act->mact.bbTaskID = 0;                                                                 /* Clear opaque task ID */
  324         act->mact.bbTaskEnv = 0;                                                                /* Clean task environment data */
  325         act->mact.emPendRupts = 0;                                                              /* Clean pending 'rupt count */
  326         act->mact.specFlags &= ~(bbNoMachSC | bbPreemptive | bbThread); /* Clean up Blue Box enables */
  327         disable_preemption();                                                           /* Don't move us around */
  328         per_proc_info[cpu_number()].spcFlags = act->mact.specFlags;     /* Copy the flags */
  329         enable_preemption();                                                            /* Ok to move us around */
  330         return;
  331 }
  332 
  333 /*
  334  * Use the new PPCcall method to enable blue box threads
  335  *
  336  *      save->r3 = taskID
  337  *      save->r4 = TWI_TableStart
  338  *      save->r5 = Desc_TableStart
  339  *
  340  */
  341 int bb_enable_bluebox( struct savearea *save )
  342 {
  343         kern_return_t rc;
  344 
  345         rc = enable_bluebox( (host_t)0xFFFFFFFF, (void *)save->save_r3, (void *)save->save_r4, (char *)save->save_r5 );
  346         save->save_r3 = rc;
  347         return 1;                                                                               /* Return with normal AST checking */
  348 }
  349 
  350 /*
  351  * Use the new PPCcall method to disable blue box threads
  352  *
  353  */
  354 int bb_disable_bluebox( struct savearea *save )
  355 {
  356         kern_return_t rc;
  357 
  358         rc = disable_bluebox( (host_t)0xFFFFFFFF );
  359         save->save_r3 = rc;
  360         return 1;                                                                               /* Return with normal AST checking */
  361 }
  362 
  363 /*
  364  * Search through the list of threads to find the matching taskIDs, then
  365  * set the task environment pointer.  A task in this case is a preemptive thread
  366  * in MacOS 9.
  367  *
  368  *      save->r3 = taskID
  369  *      save->r4 = taskEnv
  370  */
  371 
  372 int bb_settaskenv( struct savearea *save )
  373 {
  374         int                             i;
  375     task_t                      task;
  376         thread_act_t    act, fact;
  377 
  378 
  379         task = current_task();                                                  /* Figure out who our task is */
  380 
  381         task_lock(task);                                                                /* Lock our task */
  382         fact = (thread_act_t)task->threads.next;                /* Get the first activation on task */
  383         act = 0;                                                                                /* Pretend we didn't find it yet */
  384         
  385         for(i = 0; i < task->thread_count; i++) {               /* Scan the whole list */
  386                 if(fact->mact.bbDescAddr) {                                     /* Is this a Blue thread? */
  387                         if ( fact->mact.bbTaskID == save->save_r3 ) {   /* Is this the task we are looking for? */
  388                                 act = fact;                                                     /* Yeah... */
  389                                 break;                                                          /* Found it, Bail the loop... */
  390                         }
  391                 }
  392                 fact = (thread_act_t)fact->task_threads.next;   /* Go to the next one */
  393         }
  394 
  395         if ( !act || !act->active) {
  396                 task_unlock(task);                                                      /* Release task lock */
  397                 goto failure;
  398         }
  399 
  400         act_lock_thread(act);                                                   /* Make sure this stays 'round */
  401         task_unlock(task);                                                              /* Safe to release now */
  402 
  403         act->mact.bbTaskEnv = save->save_r4;
  404         if(act == current_act()) {                                              /* Are we setting our own? */
  405                 disable_preemption();                                           /* Don't move us around */
  406                 per_proc_info[cpu_number()].ppbbTaskEnv = act->mact.bbTaskEnv;  /* Remember the environment */
  407                 enable_preemption();                                            /* Ok to move us around */
  408         }
  409 
  410         act_unlock_thread(act);                                                 /* Unlock the activation */
  411         save->save_r3 = 0;
  412         return 1;
  413 
  414 failure:
  415         save->save_r3 = -1;                                                             /* we failed to find the taskID */
  416         return 1;
  417 }

Cache object: d817039fbd7cf6051581304115e46aa1


[ 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.