Annotation of XNU/osfmk/ppc/mappings.c, revision 1.1.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:  *     This file is used to maintain the virtual to real mappings for a PowerPC machine.
                     24:  *     The code herein is primarily used to bridge between the pmap layer and the hardware layer.
                     25:  *     Currently, some of the function of this module is contained within pmap.c.  We may want to move
                     26:  *     all of this into it (or most anyway) for the sake of performance.  We shall see as we write it.
                     27:  *
                     28:  *     We also depend upon the structure of the phys_entry control block.  We do put some processor 
                     29:  *     specific stuff in there.
                     30:  *
                     31:  */
                     32: 
                     33: #include <cpus.h>
                     34: #include <debug.h>
                     35: #include <mach_kgdb.h>
                     36: #include <mach_vm_debug.h>
                     37: #include <db_machine_commands.h>
                     38: 
                     39: #include <kern/thread.h>
                     40: #include <kern/thread_act.h>
                     41: #include <mach/vm_attributes.h>
                     42: #include <mach/vm_param.h>
                     43: #include <vm/vm_kern.h>
                     44: #include <vm/vm_map.h>
                     45: #include <vm/vm_page.h>
                     46: #include <kern/spl.h>
                     47: 
                     48: #include <kern/misc_protos.h>
                     49: #include <ppc/misc_protos.h>
                     50: #include <ppc/proc_reg.h>
                     51: 
                     52: #include <vm/pmap.h>
                     53: #include <ppc/pmap.h>
                     54: #include <ppc/pmap_internals.h>
                     55: #include <ppc/mem.h>
                     56: 
                     57: #include <ppc/new_screen.h>
                     58: #include <ppc/Firmware.h>
                     59: #include <ppc/mappings.h>
                     60: #include <ppc/miscserv.h>
                     61: #include <ddb/db_output.h>
                     62: 
                     63: #define PERFTIMES 0
                     64: 
                     65: #if PERFTIMES && DEBUG
                     66: #define debugLog2(a, b, c) dbgLog2(a, b, c)
                     67: #else
                     68: #define debugLog2(a, b, c)
                     69: #endif
                     70: 
                     71: autogenblok            *AutoGenList;                                                                   /* Anchor for the autogeb list */
                     72: space_t                        curr_spaceID = 0;                                                               /* Highest used space ID */
                     73: unsigned int   incrVSID = 0;                                                                   /* VSID increment value */
                     74: unsigned int   mappingdeb0 = 0;                                                
                     75: extern unsigned int    hash_table_size;                                                
                     76: extern unsigned int    debsave0;                                               
                     77: extern unsigned int dbdbdb;                                                                            /* (TEST/DEBUG) */
                     78: extern vm_offset_t mem_size;
                     79: /*
                     80:  *     ppc_prot translates from the mach representation of protections to the PPC version.
                     81:  *     Calculation of it like this saves a memory reference - and maybe a couple of microseconds.
                     82:  *     It eliminates the used of this table.
                     83:  *     unsigned char ppc_prot[8] = { 0, 3, 2, 2, 3, 3, 2, 2 };
                     84:  */
                     85: 
                     86: #define ppc_prot(p) ((0xAFAC >> (p << 1)) & 3)
                     87: 
                     88: /*
                     89:  *             mapping_space();
                     90:  *                     This function is called to generate an address space ID. This space ID must be unique within
                     91:  *                     the system.  For the PowerPC, it is used to build the VSID.  We build a VSID in the following
                     92:  *                     way:  space ID << 4 | segment.  Since a VSID is 24 bits, and out of that, we reserve the last
                     93:  *                     4, so, we can have 2^20 (2M) unique IDs.  Each pmap has a unique space ID, so we should be able
                     94:  *                     to have 2M pmaps at a time, which we couldn't, we'd run out of memory way before then.  The 
                     95:  *                     problem is that only a certain number of pmaps are kept in a free list and if that is full,
                     96:  *                     they are release.  This causes us to lose track of what space IDs are free to be reused.
                     97:  *                     We can do 4 things: 1) not worry about it, 2) keep all free pmaps, 3) rebuild all mappings
                     98:  *                     when the space ID wraps, or 4) scan the list of pmaps and find a free one.
                     99:  *
                    100:  *                     Yet another consideration is the hardware use of the VSID.  It is used as part of the hash
                    101:  *                     calculation for virtual address lookup.  An improperly chosen value could potentially cause
                    102:  *                     too many hashes to hit the same bucket, causing PTEG overflows.  The actual hash function
                    103:  *                     is (page index XOR vsid) mod number of ptegs. For a 32MB machine, using the suggested
                    104:  *                     hash table size, there are 2^12 (8192) PTEGs.  Remember, though, that the bottom 4 bits
                    105:  *                     are reserved for the segment number, which means that we really have 2^(12-4) 512 space IDs
                    106:  *                     before we start hashing to the same buckets with the same vaddrs. Also, within a space ID,
                    107:  *                     every 8192 pages (32MB) within a segment will hash to the same bucket.  That's 8 collisions
                    108:  *                     per segment.  So, a scan of every page for 256MB would fill 32 PTEGs completely, but
                    109:  *                     with no overflow.  I don't think that this is a problem.
                    110:  *
                    111:  *                     There may be a problem with the space ID, though. A new space ID is generate (mainly) 
                    112:  *                     whenever there is a fork.  There shouldn't really be any problem because (for a 32MB
                    113:  *                     machine) we can have 512 pmaps and still not have hash collisions for the same address.
                    114:  *                     The potential problem, though, is if we get long-term pmaps that have space IDs that are
                    115:  *                     the same modulo 512.  We can reduce this problem by having the segment number be bits
                    116:  *                     0-3 of the space ID rather than 20-23.  Doing this means that, in effect, corresponding
                    117:  *                     vaddrs in different segments hash to the same PTEG. While this is somewhat of a problem,
                    118:  *                     I don't think that it is as signifigant as the other, so, I'll make the space ID
                    119:  *                     with segment first.
                    120:  *
                    121:  *                     The final, and biggest problem is the wrap, which will happen every 2^20 space IDs.
                    122:  *                     While this is a problem that should only happen in periods counted in weeks, it can and
                    123:  *                     will happen.  This is assuming a monotonically increasing space ID. If we were to search
                    124:  *                     for an inactive space ID, there could not be a wrap until there was 2^20 concurrent space IDs.
                    125:  *                     That's pretty unlikely to happen.  There couldn't be enough storage to support a million tasks.
                    126:  *                     Another potential solution is to monitor for the wrap, and reorganize the space IDs when it happens.
                    127:  *                     This is rather severe, and would have user-perceivable performance impact.  It would be necessary
                    128:  *                     to quiese all other processors, invalidate and purge the entire hash table, and then to reassign
                    129:  *                     all space IDs in active pmaps.  It may be better to amortize the problem by keeping pmaps in sorted
                    130:  *                     order and keeping track of the lowest unused space ID.  I'll think on this one and do a panic
                    131:  *                     until I got it sussed.
                    132:  */
                    133: 
                    134: space_t mapping_space(void) {                                                                  /* Generate a unique space ID */
                    135: 
                    136:        register space_t        currSID, nextSID;                                       
                    137:        
                    138:        while(1) {                                                                                                      /* Keep trying until something happens */
                    139:                currSID=curr_spaceID;                                                                   /* Get a copy of the current ID */
                    140:                if(!(nextSID = ((currSID + incrVSID) & SID_MAX))) {             /* Get the next one and check if we wrapped */
                    141:                        panic("Address space ID wrapped;  Temporarily fatal system error.  Add more code here...\n");   /* Die */
                    142:                }
                    143:                if(hw_compare_and_store(currSID, nextSID, &curr_spaceID)) {     /* Have we found a good one yet? */
                    144:                        debugLog2(0, nextSID, 0);                                                       /* Log mapping_space call */
                    145:                        return (nextSID);                                                                       /* Yeah, return it... */
                    146:                }                                                                                                               /* save the new  and exit if not, */
                    147:        }
                    148: }
                    149: 
                    150: 
                    151: /*
                    152:  *             mapping_init();
                    153:  *                     Do anything that needs to be done before the mapping system can be used.
                    154:  *                     Hash table must be initialized before we call this.
                    155:  *
                    156:  *                     Calculate the SID increment.  Currently we use size^(1/2) + size^(1/4) + 1;
                    157:  */
                    158: 
                    159: void mapping_init(void) {
                    160: 
                    161:        unsigned int tmp;
                    162:        
                    163:        __asm__ volatile("cntlzw %0, %1" : "=r" (tmp) : "r" (hash_table_size)); /* Get number of leading 0s */
                    164: 
                    165:        incrVSID = 1 << ((32 - tmp + 1) >> 1);                                          /* Get ceiling of sqrt of table size */
                    166:        incrVSID |= 1 << ((32 - tmp + 1) >> 2);                                         /* Get ceiling of quadroot of table size */
                    167:        incrVSID |= 1;                                                                                          /* Set bit and add 1 */
                    168:        return;
                    169: 
                    170: }
                    171: 
                    172: 
                    173: /*
                    174:  *             mapping_remove(space_t space, vm_offset_t va);
                    175:  *                     Given a space ID and virtual address, this routine finds the mapping and removes if from
                    176:  *                     both its PTEG hash list and the physical entry list.  The mapping block will be added to
                    177:  *                     the free list.  If the free list threshold is reached, garbage collection will happen.
                    178:  *                     We also kick back a return code to say whether or not we had one to remove.
                    179:  *
                    180:  *                     We have a strict ordering here:  the mapping must be removed from the PTEG hash list before
                    181:  *                     it can be removed from the physical entry list.  This allows us to get by with only the PTEG
                    182:  *                     hash lock at page fault time. The physical entry lock must be held while we remove the mapping 
                    183:  *                     from both lists. The PTEG lock is one of the lowest level locks.  No PTE fault, interruptions,
                    184:  *                     losing control, getting other locks, etc., are allowed when you hold it. You do, and you die.
                    185:  *                     It's just that simple!
                    186:  *
                    187:  *                     When the phys_entry lock is held, the mappings chained to that one are guaranteed to stay around.
                    188:  *                     However, a mapping's order on the PTEG hash chain is not.  The interrupt handler uses the PTEG
                    189:  *                     lock to control the hash cahin and may move the position of the mapping for MRU calculations.
                    190:  *
                    191:  *                     Note that mappings do not need to point to a physical entry. When they don't, it indicates 
                    192:  *                     the mapping is outside of physical memory and usually refers to a memory mapped device of
                    193:  *                     some sort.  Naturally, we can't lock what we don't have, so the phys entry lock and unlock
                    194:  *                     routines return normally, but don't do anything.
                    195:  */
                    196: 
                    197: boolean_t mapping_remove(space_t space, vm_offset_t va) {              /* Remove a single mapping for this VADDR 
                    198:                                                                                                                                   Returns TRUE if a mapping was found to remove */
                    199: 
                    200:        mapping         *mp, *mpv;
                    201:        spl_t           s;
                    202:        
                    203:        debugLog2(1, va, space);                                                                        /* start mapping_remove */
                    204:        s=splhigh();                                                                                            /* Don't bother me */
                    205:        
                    206:        mp = hw_lock_phys_vir(space, va);                                                       /* Lock the physical entry for this mapping */
                    207: 
                    208:        if(!mp) {                                                                                                       /* Did we find one? */
                    209:                splx(s);                                                                                                /* Restore the interrupt level */
                    210:                debugLog2(2, 0, 0);                                                                             /* end mapping_remove */
                    211:                return FALSE;                                                                                   /* Didn't find any, return FALSE... */
                    212:        }
                    213:        if((unsigned int)mp&1) {                                                                        /* Did we timeout? */
                    214:                panic("mapping_remove: timeout locking physical entry\n");      /* Yeah, scream about it! */
                    215:                splx(s);                                                                                                /* Restore the interrupt level */
                    216:                return FALSE;                                                                                   /* Bad hair day, return FALSE... */
                    217:        }
                    218:        
                    219:        mpv = hw_cpv(mp);                                                                                       /* Get virtual address of mapping */
                    220:        if(mpv->pmap) {                                                                                         /* Check for a pmap */
                    221: #if DEBUG
                    222:                if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n");
                    223: #else
                    224:                (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1);       /* Decrement the resident page count */
                    225: #endif
                    226:        }
                    227:        
                    228:        hw_rem_map(mp);                                                                                         /* Remove the corresponding mapping */
                    229:        
                    230:        if(mpv->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK);     /* Unlock physical entry associated with mapping */
                    231:        
                    232:        splx(s);                                                                                                        /* Was there something you needed? */
                    233:                
                    234:        mapping_free(mpv);                                                                                      /* Add mapping to the free list */
                    235:        debugLog2(2, 1, 0);                                                                                     /* end mapping_remove */
                    236:        return TRUE;                                                                                            /* Tell them we did it */
                    237: }
                    238: 
                    239: /*
                    240:  *             mapping_purge(struct phys_entry *pp) - release all mappings for this physent to the free list 
                    241:  *
                    242:  *             This guy releases any mappings that exist for a physical page.
                    243:  *             We get the lock on the phys_entry, and hold it through out this whole routine.
                    244:  *             That way, no one can change the queue out from underneath us.  We keep fetching
                    245:  *             the physents mapping anchor until it is null, then we're done.  
                    246:  *
                    247:  *             For each mapping, we call the remove routine to remove it from the PTEG hash list and 
                    248:  *             decriment the pmap's residency count.  Then we release the mapping back to the free list.
                    249:  *
                    250:  */
                    251:  
                    252: void mapping_purge(struct phys_entry *pp) {                                            /* Remove all mappings for this physent */
                    253: 
                    254:        mapping         *mp, *mpv;
                    255:        spl_t           s;
                    256:                
                    257:        s=splhigh();                                                                                            /* Don't bother me */
                    258:        debugLog2(3, pp->pte1, 0);                                                                      /* start mapping_purge */
                    259:        
                    260:        if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {              /* Lock the physical entry */
                    261:                panic("\nmapping_purge: Timeout attempting to lock physical entry at %08X: %08X %08X\n", 
                    262:                        pp, pp->phys_link, pp->pte1);   /* Complain about timeout */
                    263:        }
                    264:        
                    265:        while(mp = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS)) {    /* Keep going so long as there's another */
                    266: 
                    267:                mpv = hw_cpv(mp);                                                                               /* Get the virtual address */
                    268:                if(mpv->pmap) {                                                                                 /* See if there is a pmap to worry about */
                    269: #if DEBUG
                    270:                        if(hw_atomic_sub(&mpv->pmap->stats.resident_count, 1) < 0) panic("pmap resident count went negative\n");
                    271: #else
                    272:                        (void)hw_atomic_sub(&mpv->pmap->stats.resident_count, 1);       /* Decrement the resident page count */
                    273: #endif
                    274:                }
                    275:        
                    276:                hw_rem_map(mp);                                                                                 /* Remove the mapping */
                    277:                mapping_free(mpv);                                                                              /* Add mapping to the free list */
                    278:        }
                    279:                
                    280:        hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK);       /* We're done, unlock the physical entry */
                    281:        
                    282:        debugLog2(4, pp->pte1, 0);                                                                      /* end mapping_purge */
                    283:        splx(s);                                                                                                        /* Was there something you needed? */
                    284:        return;                                                                                                         /* Tell them we did it */
                    285: }
                    286: 
                    287: 
                    288: /*
                    289:  *             mapping_make(pmap, space, pp, va, spa, prot, attr) - map a virtual address to a real one 
                    290:  *
                    291:  *             This routine takes the given parameters, builds a mapping block, and queues it into the 
                    292:  *             correct lists.
                    293:  *             
                    294:  *             The pmap and pp parameters can be null.  This allows us to make a mapping that is not
                    295:  *             associated with any physical page or pmap.  We may need this for certain I/O areas.
                    296:  *
                    297:  *             If the pmap is null, we don't diddle with it, i.e., the residency counts.
                    298:  *             If the phys_entry address is null, we neither lock or chain into it.
                    299:  */
                    300:  
                    301: mapping *mapping_make(pmap_t pmap, space_t space, struct phys_entry *pp, vm_offset_t va, vm_offset_t pa, vm_prot_t prot, int attr) {   /* Make an address mapping */
                    302: 
                    303:        register mapping *mp, *mpv;
                    304:        spl_t           s;
                    305:        
                    306:        debugLog2(5, va, pa);                                                                           /* start mapping_purge */
                    307:        mpv = mapping_alloc();                                                                          /* Get a spare mapping block */
                    308:        
                    309:        mpv->pmap = pmap;                                                                                       /* Initialize the pmap pointer */
                    310:        mpv->physent = pp;                                                                                      /* Initialize the pointer to the physical entry */
                    311:        mpv->PTEr = ((unsigned int)pa & ~(PAGE_SIZE - 1)) | attr<<3 | ppc_prot(prot);   /* Build the real portion of the PTE */
                    312:        mpv->PTEv = (((unsigned int)va >> 1) & 0x78000000) | (space << 7) | (((unsigned int)va >> 22) & 0x0000003F);    /* Build the VSID */
                    313: 
                    314:        s=splhigh();                                                                                            /* Don't bother from now on */
                    315:        
                    316:        mp = hw_cvp(mpv);                                                                                       /* Get the physical address of this */
                    317: 
                    318:        if(pp) {                                                                                                        /* Is there a physical entry? */
                    319:                if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {      /* Lock the physical entry */
                    320:                        panic("\nmapping_make: Timeout attempting to lock physical entry at %08X: %08X %08X\n", 
                    321:                                pp, pp->phys_link, pp->pte1);                                   /* Complain about timeout */
                    322:                }
                    323:                
                    324:                mpv->next = (mapping *)((unsigned int)pp->phys_link & ~PHYS_FLAGS);             /* Move the old anchor to the new mappings forward */
                    325:                pp->phys_link = (mapping *)((unsigned int)mp | (unsigned int)pp->phys_link & PHYS_FLAGS);       /* Point the anchor at us.  Now we're on the list (keep the flags) */
                    326:        }
                    327:        
                    328:        hw_add_map(mp, space, va);                                                                      /* Stick it on the PTEG hash list */
                    329:        
                    330:        if(pmap) {                                                                                                      /* If there is a pmap, adjust the residency count */
                    331:                (void)hw_atomic_add(&mpv->pmap->stats.resident_count, 1);       /* Increment the resident page count */
                    332:        }
                    333:        
                    334:        if(pp)hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK); /* If we have one, unlock the physical entry */
                    335:                
                    336:        splx(s);                                                                                                        /* Ok for interruptions now */
                    337:        debugLog2(6, space, prot);                                                                      /* end mapping_purge */
                    338:        return mpv;                                                                                                     /* Leave... */
                    339: }
                    340: 
                    341: 
                    342: /*
                    343:  *             mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) - remap a physical address to a different virtual address
                    344:  *
                    345:  *             This routine takes the given parameters, finds the mapping for the "from" address
                    346:  *             and removes it.  Then it modifies the virtual address and adds it back.
                    347:  *             
                    348:  *             It returns failure if the "from" address is not mapped.
                    349:  */
                    350:  
                    351: int    mapping_remap(space_t space, vm_offset_t from, vm_offset_t to) {        /* Remap an address mapping */
                    352: 
                    353:        register mapping *mp, *mpv;
                    354:        spl_t           s;
                    355:        
                    356:        s=splhigh();                                                                                            /* Don't bother from now on */
                    357:        
                    358:        mp = hw_lock_phys_vir(space, from);                                                     /* Lock the physical entry for this mapping */
                    359:        debugLog2(7, from, to);                                                                         /* start remap */
                    360:        if(!mp) {                                                                                                       /* Did we find one? */
                    361:                splx(s);                                                                                                /* Restore the interrupt level */
                    362:                return FALSE;                                                                                   /* Didn't find source, return FALSE... */
                    363:        }
                    364:        if((unsigned int)mp&1) {                                                                        /* Did we timeout? */
                    365:                panic("mapping_remap: timeout locking physical entry\n");       /* Yeah, scream about it! */
                    366:                splx(s);                                                                                                /* Restore the interrupt level */
                    367:                return FALSE;                                                                                   /* Bad hair day, return FALSE... */
                    368:        }
                    369:        
                    370:        hw_rem_map(mp);                                                                                         /* Remove from the old address. Removes from both PTEG and physent lists */     
                    371: 
                    372:        mpv = hw_cpv(mp);                                                                                       /* Convert to virtual address */
                    373: 
                    374:        mpv->PTEv = (((unsigned int)to >> 1) & 0x78000000) | 
                    375:                (space << 7) | (((unsigned int)to >> 22) & 0x0000003F); /* Rebuild the VSID */
                    376:        
                    377:        if(mpv->physent) {                                                                                      /* Is there a physical entry? */                
                    378:                mpv->next = (mapping *)((unsigned int)mpv->physent->phys_link & ~PHYS_FLAGS);   /* Move the old anchor to the new mappings forward */
                    379:                mpv->physent->phys_link = (mapping *)((unsigned int)mp | ((unsigned int)mpv->physent->phys_link & PHYS_FLAGS)); /* Point the anchor at us.  Now we're back on the list (keep the flags) */
                    380:        }
                    381:        
                    382:        hw_add_map(mp, space, to);                                                                      /* Map it to the new one */
                    383:        
                    384:        if(mp->physent)hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK);      /* Unlock physical entry associated with mapping */
                    385:                
                    386:        debugLog2(8, space, 0);                                                                         /* end remap */
                    387:        splx(s);                                                                                                        /* Ok for interruptions now */
                    388:        return TRUE;                                                                                            /* Leave... */
                    389: }
                    390: 
                    391: 
                    392: /*
                    393:  *             void mapping_protect(phys_entry *pp, vm_prot_t prot, boolean_t locked) - change the protection of a physical page
                    394:  *
                    395:  *             This routine takes a physical entry and runs through all mappings attached to it and changes
                    396:  *             the protection.  If there are PTEs associated with the mappings, they will be invalidated before
                    397:  *             the protection is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    398:  *             either (I don't think, maybe I'll change my mind later).  There is no limitation on changes, e.g., 
                    399:  *             higher to lower, lower to higher.
                    400:  *
                    401:  *             If locked is true, the physent is already locked and should not be unlocked at exit.
                    402:  *
                    403:  *             Interruptions should be disabled at entry.
                    404:  */
                    405: 
                    406: void mapping_protect(struct phys_entry *pp, vm_prot_t prot, boolean_t locked) {        /* Change protection of all mappings to page */
                    407: 
                    408:        debugLog2(9, pp->pte1, prot);                                                           /* end remap */
                    409:        if(!locked) {                                                                                           /* Do we need to lock the physent? */
                    410:                if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {      /* Lock the physical entry */
                    411:                        panic("\nmapping_protect: Timeout attempting to lock physical entry at %08X: %08X %08X\n", 
                    412:                                pp, pp->phys_link, pp->pte1);                                   /* Complain about timeout */
                    413:                }
                    414:        }       
                    415: 
                    416:        hw_prot(pp, ppc_prot(prot));                                                            /* Go set the protection on this physical page */
                    417: 
                    418:        if(!locked) hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK);           /* We're done, unlock the physical entry */
                    419:        debugLog2(10, pp->pte1, 0);                                                                     /* end remap */
                    420:        
                    421:        return;                                                                                                         /* Leave... */
                    422: }
                    423: 
                    424: /*
                    425:  *             mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) Sets the default physical page attributes
                    426:  *
                    427:  *             This routine takes a physical entry and sets the physical attributes.  There can be no mappings
                    428:  *             associated with this page when we do it.
                    429:  */
                    430: 
                    431: void mapping_phys_attr(struct phys_entry *pp, vm_prot_t prot, unsigned int wimg) {     /* Sets the default physical page attributes */
                    432: 
                    433:        debugLog2(11, pp->pte1, prot);                                                          /* end remap */
                    434: 
                    435:        if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {      /* Lock the physical entry */
                    436:                panic("\nmapping_phys_attr: Timeout attempting to lock physical entry at %08X: %08X %08X\n", 
                    437:                        pp, pp->phys_link, pp->pte1);                                           /* Complain about timeout */
                    438:        }
                    439: 
                    440: //     if(pp->phys_link) panic("\nmapping_phys_attr: attempt to change default attributes when mappings exist!\n");
                    441: 
                    442:        hw_phys_attr(pp, ppc_prot(prot), wimg);                                         /* Go set the default WIMG and protection */
                    443: 
                    444:        hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK);       /* We're done, unlock the physical entry */
                    445:        debugLog2(12, pp->pte1, wimg);                                                          /* end remap */
                    446:        
                    447:        return;                                                                                                         /* Leave... */
                    448: }
                    449: 
                    450: /*
                    451:  *             void mapping_invall(phys_entry *pp) - invalidates all ptes associated with a page
                    452:  *
                    453:  *             This routine takes a physical entry and runs through all mappings attached to it and invalidates
                    454:  *             any PTEs it finds.
                    455:  *
                    456:  *             Interruptions must be disabled and the physical entry locked at entry.
                    457:  */
                    458: 
                    459: void mapping_invall(struct phys_entry *pp) {                                   /* Clear all PTEs pointing to a physical page */
                    460: 
                    461:        hw_inv_all(pp);                                                                                         /* Go set the change bit of a physical page */
                    462:        
                    463:        return;                                                                                                         /* Leave... */
                    464: }
                    465: 
                    466: 
                    467: /*
                    468:  *             void mapping_clr_mod(phys_entry *pp) - clears the change bit of a physical page
                    469:  *
                    470:  *             This routine takes a physical entry and runs through all mappings attached to it and turns
                    471:  *             off the change bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    472:  *             the change bit is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    473:  *             either (I don't think, maybe I'll change my mind later).
                    474:  *
                    475:  *             Interruptions must be disabled and the physical entry locked at entry.
                    476:  */
                    477: 
                    478: void mapping_clr_mod(struct phys_entry *pp) {                                  /* Clears the change bit of a physical page */
                    479: 
                    480:        hw_clr_mod(pp);                                                                                         /* Go clear the change bit of a physical page */
                    481:        return;                                                                                                         /* Leave... */
                    482: }
                    483: 
                    484: 
                    485: /*
                    486:  *             void mapping_set_mod(phys_entry *pp) - set the change bit of a physical page
                    487:  *
                    488:  *             This routine takes a physical entry and runs through all mappings attached to it and turns
                    489:  *             on the change bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    490:  *             the change bit is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    491:  *             either (I don't think, maybe I'll change my mind later).
                    492:  *
                    493:  *             Interruptions must be disabled and the physical entry locked at entry.
                    494:  */
                    495: 
                    496: void mapping_set_mod(struct phys_entry *pp) {                                  /* Sets the change bit of a physical page */
                    497: 
                    498:        hw_set_mod(pp);                                                                                         /* Go set the change bit of a physical page */
                    499:        return;                                                                                                         /* Leave... */
                    500: }
                    501: 
                    502: 
                    503: /*
                    504:  *             void mapping_clr_ref(struct phys_entry *pp) - clears the reference bit of a physical page
                    505:  *
                    506:  *             This routine takes a physical entry and runs through all mappings attached to it and turns
                    507:  *             off the reference bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    508:  *             the reference bit is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    509:  *             either (I don't think, maybe I'll change my mind later).
                    510:  *
                    511:  *             Interruptions must be disabled at entry.
                    512:  */
                    513: 
                    514: void mapping_clr_ref(struct phys_entry *pp) {                                  /* Clears the reference bit of a physical page */
                    515: 
                    516:        mapping *mp;
                    517: 
                    518:        debugLog2(13, pp->pte1, 0);                                                                     /* end remap */
                    519:        if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {      /* Lock the physical entry for this mapping */
                    520:                panic("Lock timeout getting lock on physical entry\n"); /* Just die... */
                    521:        }
                    522:        hw_clr_ref(pp);                                                                                         /* Go clear the reference bit of a physical page */
                    523:        hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK);       /* Unlock physical entry */
                    524:        debugLog2(14, pp->pte1, 0);                                                                     /* end remap */
                    525:        return;                                                                                                         /* Leave... */
                    526: }
                    527: 
                    528: 
                    529: /*
                    530:  *             void mapping_set_ref(phys_entry *pp) - set the reference bit of a physical page
                    531:  *
                    532:  *             This routine takes a physical entry and runs through all mappings attached to it and turns
                    533:  *             on the reference bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    534:  *             the reference bit is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    535:  *             either (I don't think, maybe I'll change my mind later).
                    536:  *
                    537:  *             Interruptions must be disabled and the physical entry locked at entry.
                    538:  */
                    539: 
                    540: void mapping_set_ref(struct phys_entry *pp) {                                  /* Sets the reference bit of a physical page */
                    541: 
                    542:        hw_set_ref(pp);                                                                                         /* Go set the reference bit of a physical page */
                    543:        return;                                                                                                         /* Leave... */
                    544: }
                    545: 
                    546: 
                    547: /*
                    548:  *             void mapping_tst_mod(phys_entry *pp) - test the change bit of a physical page
                    549:  *
                    550:  *             This routine takes a physical entry and runs through all mappings attached to it and tests
                    551:  *             the changed bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    552:  *             the changed bit is tested.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    553:  *             either (I don't think, maybe I'll change my mind later).
                    554:  *
                    555:  *             Interruptions must be disabled and the physical entry locked at entry.
                    556:  */
                    557: 
                    558: boolean_t mapping_tst_mod(struct phys_entry *pp) {                             /* Tests the change bit of a physical page */
                    559: 
                    560:        return(hw_tst_mod(pp));                                                                         /* Go test the change bit of a physical page */
                    561: }
                    562: 
                    563: 
                    564: /*
                    565:  *             void mapping_tst_ref(phys_entry *pp) - tests the reference bit of a physical page
                    566:  *
                    567:  *             This routine takes a physical entry and runs through all mappings attached to it and tests
                    568:  *             the reference bit.  If there are PTEs associated with the mappings, they will be invalidated before
                    569:  *             the reference bit is changed.  We don't try to save the PTE.  We won't worry about the LRU calculations
                    570:  *             either (I don't think, maybe I'll change my mind later).
                    571:  *
                    572:  *             Interruptions must be disabled and the physical entry locked at entry.
                    573:  */
                    574: 
                    575: boolean_t mapping_tst_ref(struct phys_entry *pp) {                             /* Tests the reference bit of a physical page */
                    576: 
                    577:        return(hw_tst_ref(pp));                                                                         /* Go test the reference bit of a physical page */
                    578: }
                    579: 
                    580: 
                    581: /*
                    582:  *             void mapping_phys_init(physent, wimg) - fills in the default processor dependent areas of the phys ent
                    583:  *
                    584:  *             Currently, this sets the default word 1 of the PTE.  The only bits set are the WIMG bits
                    585:  */
                    586: 
                    587: void mapping_phys_init(struct phys_entry *pp, unsigned int pa, unsigned int wimg) {            /* Initializes hw specific storage attributes */
                    588: 
                    589:        pp->pte1 = (pa & -PAGE_SIZE) | ((wimg << 3) & 0x00000078);      /* Set the WIMG and phys addr in the default PTE1 */
                    590: 
                    591:        return;                                                                                                         /* Leave... */
                    592: }
                    593: 
                    594: 
                    595: /*
                    596:  *             mapping_adjust(void) - Releases free mapping blocks and/or allocates new ones 
                    597:  *
                    598:  *             This routine frees any mapping blocks queued to mapCtl.mapcrel. It also checks
                    599:  *             the number of free mappings remaining, and if below a threshold, replenishes them.
                    600:  *             The list will be replenshed from mapCtl.mapcrel if there are enough.  Otherwise,
                    601:  *             a new one is allocated.
                    602:  *
                    603:  *             This routine allocates and/or memory and must be called from a safe place. 
                    604:  *             Currently, vm_pageout_scan is the safest place. We insure that the 
                    605:  */
                    606: 
                    607: thread_call_t                          mapping_adjust_call;
                    608: static thread_call_data_t      mapping_adjust_call_data;
                    609: 
                    610: void mapping_adjust(void) {                                                                            /* Adjust free mappings */
                    611: 
                    612:        kern_return_t   retr;
                    613:        mappingblok     *mb, *mbn;
                    614:        spl_t                   s;
                    615:        int                             allocsize, i;
                    616: 
                    617:        if(mapCtl.mapcmin <= MAPPERBLOK) {                                                      /* Do the first time only */
                    618:                mapCtl.mapcmin = mem_size >> 12;                                                /* Make sure we have enough for all of physical memory */
                    619: #if DEBUG
                    620:                kprintf("mapping_adjust: minimum entries rqrd = %08X\n", mapCtl.mapcmin);
                    621:                kprintf("mapping_adjust: free = %08X; in use = %08X; release = %08X\n",
                    622:                  mapCtl.mapcfree, mapCtl.mapcinuse, mapCtl.mapcreln);
                    623: #endif
                    624:        }
                    625: 
                    626:        s = splhigh();                                                                                          /* Don't bother from now on */
                    627:        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {     /* Lock the control header */ 
                    628:                panic("mapping_adjust - timeout getting control lock (1)\n");   /* Tell all and die */
                    629:        }
                    630:        
                    631:        if (mapping_adjust_call == NULL) {
                    632:                thread_call_setup(&mapping_adjust_call_data, mapping_adjust, NULL);
                    633:                mapping_adjust_call = &mapping_adjust_call_data;
                    634:        }
                    635: 
                    636:        while(1) {                                                                                                      /* Keep going until we've got enough */
                    637:                
                    638:                allocsize = mapCtl.mapcmin - mapCtl.mapcfree;                   /* Figure out how much we need */
                    639:                if(allocsize < 1) break;                                                                /* Leave if we have all we need */
                    640:                
                    641:                if((unsigned int)(mbn = mapCtl.mapcrel)) {                              /* Can we rescue a free one? */
                    642:                        mapCtl.mapcrel = mbn->nextblok;                                         /* Dequeue it */
                    643:                        mapCtl.mapcreln--;                                                                      /* Back off the count */
                    644:                        allocsize = MAPPERBLOK;                                                         /* Show we allocated one block */                       
                    645:                }
                    646:                else {                                                                                                  /* No free ones, try to get it */
                    647:                        
                    648:                        allocsize = (allocsize + MAPPERBLOK - 1) / MAPPERBLOK;  /* Get the number of pages we need */
                    649:                        if(allocsize > (mapCtl.mapcfree / 2)) allocsize = (mapCtl.mapcfree / 2);        /* Don't try for anything that we can't comfortably map */
                    650:                        
                    651:                        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);            /* Unlock our stuff */
                    652:                        splx(s);                                                                                        /* Restore 'rupts */
                    653: 
                    654:                        for(; allocsize > 0; allocsize >>= 1) {                         /* Try allocating in descending halves */ 
                    655:                                retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE * allocsize);        /* Find a virtual address to use */
                    656:                                if((retr != KERN_SUCCESS) && (allocsize == 1)) {        /* Did we find any memory at all? */
                    657:                                        panic("Whoops...  Not a bit of wired memory left for anyone\n");
                    658:                                }
                    659:                                if(retr == KERN_SUCCESS) break;                                 /* We got some memory, bail out... */
                    660:                        }
                    661:                
                    662:                        allocsize = allocsize * MAPPERBLOK;                                     /* Convert pages to number of maps allocated */
                    663:                        s = splhigh();                                                                          /* Don't bother from now on */
                    664:                        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {     /* Lock the control header */ 
                    665:                                panic("mapping_adjust - timeout getting control lock (2)\n");   /* Tell all and die */
                    666:                        }
                    667:                }
                    668:                for(; allocsize > 0; allocsize -= MAPPERBLOK) {                 /* Release one block at a time */
                    669:                        mapping_free_init((vm_offset_t)mbn, 0, 1);                      /* Initialize a non-permanent block */
                    670:                        mbn = (mappingblok *)((unsigned int)mbn + PAGE_SIZE);   /* Point to the next slot */
                    671:                }
                    672:        }
                    673: 
                    674:        if(mapCtl.mapcholdoff) {                                                                        /* Should we hold off this release? */
                    675:                mapCtl.mapcrecurse = 0;                                                                 /* We are done now */
                    676:                hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                    /* Unlock our stuff */
                    677:                splx(s);                                                                                                /* Restore 'rupts */
                    678:                return;                                                                                                 /* Return... */
                    679:        }
                    680: 
                    681:        mbn = mapCtl.mapcrel;                                                                           /* Get first pending release block */
                    682:        mapCtl.mapcrel = 0;                                                                                     /* Dequeue them */
                    683:        mapCtl.mapcreln = 0;                                                                            /* Set count to 0 */
                    684: 
                    685:        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                            /* Unlock our stuff */
                    686:        splx(s);                                                                                                        /* Restore 'rupts */
                    687: 
                    688:        while((unsigned int)mbn) {                                                                      /* Toss 'em all */
                    689:                mb = mbn->nextblok;                                                                             /* Get the next */
                    690:                kmem_free(kernel_map, (vm_offset_t) mbn, PAGE_SIZE);    /* Release this mapping block */
                    691:                mbn = mb;                                                                                               /* Chain to the next */
                    692:        }
                    693: 
                    694:        __asm__ volatile("sync");                                                                       /* Make sure all is well */
                    695:        mapCtl.mapcrecurse = 0;                                                                         /* We are done now */
                    696:        return;
                    697: }
                    698: 
                    699: /*
                    700:  *             mapping_free(mapping *mp) - release a mapping to the free list 
                    701:  *
                    702:  *             This routine takes a mapping and adds it to the free list.
                    703:  *             If this mapping make the block non-empty, we queue it to the free block list.
                    704:  *             NOTE: we might want to queue it to the end to keep quelch the pathalogical
                    705:  *             case when we get a mapping and free it repeatedly causing the block to chain and unchain.
                    706:  *             If this release fills a block and we are above the threshold, we release the block
                    707:  */
                    708: 
                    709: void mapping_free(struct mapping *mp) {                                                        /* Release a mapping */
                    710: 
                    711:        mappingblok     *mb, *mbn;
                    712:        spl_t                   s;
                    713:        unsigned int    full, mindx;
                    714: 
                    715:        mindx = ((unsigned int)mp & (PAGE_SIZE - 1)) >> 5;                      /* Get index to mapping */
                    716:        mb = (mappingblok *)((unsigned int)mp & -PAGE_SIZE);            /* Point to the mapping block */
                    717: 
                    718:        s = splhigh();                                                                                          /* Don't bother from now on */
                    719:        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {     /* Lock the control header */ 
                    720:                panic("mapping_free - timeout getting control lock\n"); /* Tell all and die */
                    721:        }
                    722:        
                    723:        full = !(mb->mapblokfree[0] | mb->mapblokfree[1] | mb->mapblokfree[2] | mb->mapblokfree[3]);    /* See if full now */ 
                    724:        mb->mapblokfree[mindx >> 5] |= (0x80000000 >> (mindx & 31));    /* Flip on the free bit */
                    725:        
                    726:        if(full) {                                                                                                      /* If it was full before this: */
                    727:                mb->nextblok = mapCtl.mapcnext;                                                 /* Move head of list to us */
                    728:                mapCtl.mapcnext = mb;                                                                   /* Chain us to the head of the list */
                    729:        }
                    730: 
                    731:        mapCtl.mapcfree++;                                                                                      /* Bump free count */
                    732:        mapCtl.mapcinuse--;                                                                                     /* Decriment in use count */
                    733:        
                    734:        mapCtl.mapcfreec++;                                                                                     /* Count total calls */
                    735: 
                    736:        if(mapCtl.mapcfree > mapCtl.mapcmin) {                                          /* Should we consider releasing this? */
                    737:                if(((mb->mapblokfree[0] | 0x80000000) & mb->mapblokfree[1] & mb->mapblokfree[2] & mb->mapblokfree[3]) 
                    738:                   == 0xFFFFFFFF) {                                                                             /* See if empty now */ 
                    739: 
                    740:                        if(mapCtl.mapcnext == mb) {                                                     /* Are we first on the list? */
                    741:                                mapCtl.mapcnext = mb->nextblok;                                 /* Unchain us */
                    742:                                if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0;       /* If last, remove last */
                    743:                        }
                    744:                        else {                                                                                          /* We're not first */
                    745:                                for(mbn = mapCtl.mapcnext; mbn != 0; mbn = mbn->nextblok) {     /* Search for our block */
                    746:                                        if(mbn->nextblok == mb) break;                          /* Is the next one our's? */
                    747:                                }
                    748:                                if(!mbn) panic("mapping_free: attempt to release mapping block (%08X) not on list\n", mp);
                    749:                                mbn->nextblok = mb->nextblok;                                   /* Dequeue us */
                    750:                                if(mapCtl.mapclast == mb) mapCtl.mapclast = mbn;        /* If last, make our predecessor last */
                    751:                        }
                    752:                        
                    753:                        if(mb->mapblokflags & mbPerm) {                                         /* Is this permanently assigned? */
                    754:                                mb->nextblok = mapCtl.mapcnext;                                 /* Move chain head to us */
                    755:                                mapCtl.mapcnext = mb;                                                   /* Chain us to the head */
                    756:                                if(!((unsigned int)mb->nextblok)) mapCtl.mapclast = mb; /* If last, make us so */
                    757:                        }
                    758:                        else {
                    759:                                mapCtl.mapcfree -= MAPPERBLOK;                                  /* Remove the block from the free count */
                    760:                                mapCtl.mapcreln++;                                                              /* Count on release list */
                    761:                                mb->nextblok = mapCtl.mapcrel;                                  /* Move pointer */
                    762:                                mapCtl.mapcrel = mb;                                                    /* Chain us in front */
                    763:                        }
                    764:                }
                    765:        }
                    766: 
                    767:        if(mapCtl.mapcreln > MAPFRTHRSH) {                                                      /* Do we have way too many releasable mappings? */
                    768:                if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) {   /* Make sure we aren't recursing */
                    769:                        thread_call_enter(mapping_adjust_call);                 /* Go toss some */
                    770:                }
                    771:        }
                    772:        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                            /* Unlock our stuff */
                    773:        splx(s);                                                                                                        /* Restore 'rupts */
                    774: 
                    775:        return;                                                                                                         /* Bye, dude... */
                    776: }
                    777: 
                    778: 
                    779: /*
                    780:  *             mapping_alloc(void) - obtain a mapping from the free list 
                    781:  *
                    782:  *             This routine takes a mapping off of the free list and returns it's address.
                    783:  *
                    784:  *             We do this by finding a free entry in the first block and allocating it.
                    785:  *             If this allocation empties the block, we remove it from the free list.
                    786:  *             If this allocation drops the total number of free entries below a threshold,
                    787:  *             we allocate a new block.
                    788:  *
                    789:  */
                    790: 
                    791: mapping *mapping_alloc(void) {                                                                 /* Obtain a mapping */
                    792: 
                    793:        register mapping *mp;
                    794:        mappingblok     *mb, *mbn;
                    795:        spl_t                   s;
                    796:        int                             mindx;
                    797:        kern_return_t   retr;
                    798: 
                    799:        s = splhigh();                                                                                          /* Don't bother from now on */
                    800:        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {     /* Lock the control header */ 
                    801:                panic("mapping_alloc - timeout getting control lock\n");        /* Tell all and die */
                    802:        }
                    803: 
                    804:        if(!(mb = mapCtl.mapcnext)) {                                                           /* Get the first block entry */
                    805:                panic("mapping_alloc - free mappings exhausted\n");             /* Whine and moan */
                    806:        }
                    807:        
                    808: 
                    809:        if(!(mindx = mapalc(mb))) {                                                                     /* Allocate a slot */
                    810:                panic("mapping_alloc - empty mapping block detected at %08X\n", mb);    /* Not allowed to find none */
                    811:        }
                    812:        
                    813:        if(mindx < 0) {                                                                                         /* Did we just take the last one */
                    814:                mindx = -mindx;                                                                                 /* Make positive */
                    815:                mapCtl.mapcnext = mb->nextblok;                                                 /* Remove us from the list */
                    816:                if(!((unsigned int)mapCtl.mapcnext)) mapCtl.mapclast = 0;       /* Removed the last one */
                    817:        }
                    818:        
                    819:        mapCtl.mapcfree--;                                                                                      /* Decrement free count */
                    820:        mapCtl.mapcinuse++;                                                                                     /* Bump in use count */
                    821:        
                    822:        mapCtl.mapcallocc++;                                                                            /* Count total calls */
                    823: 
                    824: /*
                    825:  *     Note: in the following code, we will attempt to rescue blocks only one at a time.
                    826:  *     Eventually, after a few more mapping_alloc calls, we will catch up.  If there are none
                    827:  *     rescueable, we will kick the misc scan who will allocate some for us.  We only do this
                    828:  *     if we haven't already done it.
                    829:  *     For early boot, we are set up to only rescue one block at a time.  This is because we prime
                    830:  *     the release list with as much as we need until threads start.
                    831:  */
                    832:        if(mapCtl.mapcfree < mapCtl.mapcmin) {                                          /* See if we need to replenish */
                    833:                if(mbn = mapCtl.mapcrel) {                                                              /* Try to rescue a block from impending doom */
                    834:                        mapCtl.mapcrel = mbn->nextblok;                                         /* Pop the queue */
                    835:                        mapCtl.mapcreln--;                                                                      /* Back off the count */
                    836:                        mapping_free_init((vm_offset_t)mbn, 0, 1);                      /* Initialize a non-permanent block */
                    837:                }
                    838:                else {                                                                                                  /* We need to replenish */
                    839:                        if(hw_compare_and_store(0, 1, &mapCtl.mapcrecurse)) {   /* Make sure we aren't recursing */
                    840:                                thread_call_enter(mapping_adjust_call);         /* Go allocate some more */
                    841:                        }
                    842:                }
                    843:        }
                    844: 
                    845:        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                            /* Unlock our stuff */
                    846:        splx(s);                                                                                                        /* Restore 'rupts */
                    847:        
                    848:        mp = &((mapping *)mb)[mindx];                                                           /* Point to the allocated mapping */
                    849:     __asm__ volatile("dcbz 0,%0" : : "r" (mp));                                        /* Clean it up */
                    850:        return mp;                                                                                                      /* Send it back... */
                    851: }
                    852: 
                    853: 
                    854: /*
                    855:  *             void mapping_free_init(mb, perm) - Adds a block of storage to the free mapping list
                    856:  *
                    857:  *             The mapping block is a page size area on a page boundary.  It contains 1 header and 127
                    858:  *             mappings.  This call adds and initializes a block for use.
                    859:  *     
                    860:  *             The header contains a chain link, bit maps, a virtual to real translation mask, and
                    861:  *             some statistics. Bit maps map each slot on the page (bit 0 is not used because it 
                    862:  *             corresponds to the header).  The translation mask is the XOR of the virtual and real
                    863:  *             addresses (needless to say, the block must be wired).
                    864:  *
                    865:  *             We handle these mappings the same way as saveareas: the block is only on the chain so
                    866:  *             long as there are free entries in it.
                    867:  *
                    868:  *             Empty blocks are garbage collected when there are at least mapCtl.mapcmin pages worth of free 
                    869:  *             mappings. Blocks marked PERM won't ever be released.
                    870:  *
                    871:  *             If perm is negative, the mapping is initialized, but immediately queued to the mapCtl.mapcrel
                    872:  *             list.  We do this only at start up time. This is done because we only allocate blocks 
                    873:  *             in the pageout scan and it doesn't start up until after we run out of the initial mappings.
                    874:  *             Therefore, we need to preallocate a bunch, but we don't want them to be permanent.  If we put
                    875:  *             them on the release queue, the allocate routine will rescue them.  Then when the
                    876:  *             pageout scan starts, all extra ones will be released.
                    877:  *
                    878:  */
                    879: 
                    880: 
                    881: void mapping_free_init(vm_offset_t mbl, int perm, boolean_t locked) {          
                    882:                                                                                                                        /* Set's start and end of a block of mappings
                    883:                                                                                                                           perm indicates if the block can be released 
                    884:                                                                                                                           or goes straight to the release queue .
                    885:                                                                                                                           locked indicates if the lock is held already */
                    886:                                                                                                                   
                    887:        mappingblok     *mb;
                    888:        spl_t           s;
                    889:        int                     i;
                    890:        unsigned int    raddr;
                    891: 
                    892:        mb = (mappingblok *)mbl;                                                                /* Start of area */
                    893:        
                    894:        
                    895:        if(perm >= 0) {                                                                                 /* See if we need to initialize the block */
                    896:                if(perm) {
                    897:                        raddr = (unsigned int)mbl;                                              /* Perm means V=R */
                    898:                        mb->mapblokflags = mbPerm;                                              /* Set perm */
                    899:                }
                    900:                else {
                    901:                        raddr = kvtophys(mbl);                                                  /* Get real address */
                    902:                        mb->mapblokflags = 0;                                                   /* Set not perm */
                    903:                }
                    904:                
                    905:                mb->mapblokvrswap = raddr ^ (unsigned int)mbl;          /* Form translation mask */
                    906:                
                    907:                mb->mapblokfree[0] = 0x7FFFFFFF;                                        /* Set first 32 (minus 1) free */
                    908:                mb->mapblokfree[1] = 0xFFFFFFFF;                                        /* Set next 32 free */
                    909:                mb->mapblokfree[2] = 0xFFFFFFFF;                                        /* Set next 32 free */
                    910:                mb->mapblokfree[3] = 0xFFFFFFFF;                                        /* Set next 32 free */
                    911:        }
                    912:        
                    913:        s = splhigh();                                                                                  /* Don't bother from now on */
                    914:        if(!locked) {                                                                                   /* Do we need the lock? */
                    915:                if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {             /* Lock the control header */ 
                    916:                        panic("mapping_free_init - timeout getting control lock\n");    /* Tell all and die */
                    917:                }
                    918:        }
                    919:        
                    920:        if(perm < 0) {                                                                                  /* Direct to release queue? */
                    921:                mb->nextblok = mapCtl.mapcrel;                                          /* Move forward pointer */
                    922:                mapCtl.mapcrel = mb;                                                            /* Queue us on in */
                    923:                mapCtl.mapcreln++;                                                                      /* Count the free block */
                    924:        }
                    925:        else {                                                                                                  /* Add to the free list */
                    926:                
                    927:                mb->nextblok = 0;                                                                       /* We always add to the end */
                    928:                mapCtl.mapcfree += MAPPERBLOK;                                          /* Bump count */
                    929:                
                    930:                if(!((unsigned int)mapCtl.mapcnext)) {                          /* First entry on list? */
                    931:                        mapCtl.mapcnext = mapCtl.mapclast = mb;                 /* Chain to us */
                    932:                }
                    933:                else {                                                                                          /* We are not the first */
                    934:                        mapCtl.mapclast->nextblok = mb;                                 /* Point the last to us */
                    935:                        mapCtl.mapclast = mb;                                                   /* We are now last */
                    936:                }
                    937:        }
                    938:                
                    939:        if(!locked) {                                                                                   /* Do we need to unlock? */
                    940:                hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);            /* Unlock our stuff */
                    941:        }
                    942:                splx(s);                                                                                        /* Restore 'rupts */
                    943:        return;                                                                                                 /* All done, leave... */
                    944: }
                    945: 
                    946: 
                    947: /*
                    948:  *             void mapping_prealloc(unsigned int) - Preallocates mapppings for large request
                    949:  *     
                    950:  *             No locks can be held, because we allocate memory here.
                    951:  *             This routine needs a corresponding mapping_relpre call to remove the
                    952:  *             hold off flag so that the adjust routine will free the extra mapping
                    953:  *             blocks on the release list.  I don't like this, but I don't know
                    954:  *             how else to do this for now...
                    955:  *
                    956:  */
                    957: 
                    958: void mapping_prealloc(unsigned int size) {                                     /* Preallocates mapppings for large request */
                    959: 
                    960:        int     nmapb, i;
                    961:        kern_return_t   retr;
                    962:        mappingblok     *mbn;
                    963:        spl_t           s;
                    964: 
                    965:        s = splhigh();                                                                                  /* Don't bother from now on */
                    966:        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {             /* Lock the control header */ 
                    967:                panic("mapping_prealloc - timeout getting control lock\n");     /* Tell all and die */
                    968:        }
                    969: 
                    970:        nmapb = (size >> 12) + mapCtl.mapcmin;                                  /* Get number of entries needed for this and the minimum */
                    971:        
                    972:        mapCtl.mapcholdoff++;                                                                   /* Bump the hold off count */
                    973:        
                    974:        if((nmapb = (nmapb - mapCtl.mapcfree)) <= 0) {                  /* Do we already have enough? */
                    975:                hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);            /* Unlock our stuff */
                    976:                splx(s);                                                                                        /* Restore 'rupts */
                    977:                return;
                    978:        }
                    979: 
                    980:        nmapb = (nmapb + MAPPERBLOK - 1) / MAPPERBLOK;                  /* Get number of blocks to get */
                    981:        
                    982:        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                    /* Unlock our stuff */
                    983:        splx(s);                                                                                                /* Restore 'rupts */
                    984:        
                    985:        for(i = 0; i < nmapb; i++) {                                                    /* Allocate 'em all */
                    986:                retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE);    /* Find a virtual address to use */
                    987:                if(retr != KERN_SUCCESS) {                                                      /* Did we get some memory? */
                    988:                        panic("Whoops...  Not a bit of wired memory left for anyone\n");
                    989:                }
                    990:                mapping_free_init((vm_offset_t)mbn, -1, 0);                     /* Initialize on to the release queue */
                    991:        }
                    992: }
                    993: 
                    994: /*
                    995:  *             void mapping_relpre(void) - Releases preallocation release hold off
                    996:  *     
                    997:  *             This routine removes the
                    998:  *             hold off flag so that the adjust routine will free the extra mapping
                    999:  *             blocks on the release list.  I don't like this, but I don't know
                   1000:  *             how else to do this for now...
                   1001:  *
                   1002:  */
                   1003: 
                   1004: void mapping_relpre(void) {                                                                    /* Releases release hold off */
                   1005: 
                   1006:        spl_t           s;
                   1007: 
                   1008:        s = splhigh();                                                                                  /* Don't bother from now on */
                   1009:        if(!hw_lock_to((hw_lock_t)&mapCtl.mapclock, LockTimeOut)) {             /* Lock the control header */ 
                   1010:                panic("mapping_relpre - timeout getting control lock\n");       /* Tell all and die */
                   1011:        }
                   1012:        if(--mapCtl.mapcholdoff < 0) {                                                  /* Back down the hold off count */
                   1013:                panic("mapping_relpre: hold-off count went negative\n");
                   1014:        }
                   1015: 
                   1016:        hw_lock_unlock((hw_lock_t)&mapCtl.mapclock);                    /* Unlock our stuff */
                   1017:        splx(s);                                                                                                /* Restore 'rupts */
                   1018: }
                   1019: 
                   1020: /*
                   1021:  *             void mapping_free_prime(void) - Primes the mapping block release list
                   1022:  *
                   1023:  *             See mapping_free_init.
                   1024:  *             No locks can be held, because we allocate memory here.
                   1025:  *             One processor running only.
                   1026:  *
                   1027:  */
                   1028: 
                   1029: void mapping_free_prime(void) {                                                                        /* Primes the mapping block release list */
                   1030: 
                   1031:        int     nmapb, i;
                   1032:        kern_return_t   retr;
                   1033:        mappingblok     *mbn;
                   1034:        
                   1035:        nmapb = (mapCtl.mapcfree + mapCtl.mapcinuse + MAPPERBLOK - 1) / MAPPERBLOK;     /* Get permanent allocation */
                   1036:        nmapb = nmapb * 4;                                                                                      /* Get 4 times our initial allocation */
                   1037: 
                   1038: #if DEBUG
                   1039:        kprintf("mapping_free_prime: free = %08X; in use = %08X; priming = %08X\n", 
                   1040:          mapCtl.mapcfree, mapCtl.mapcinuse, nmapb);
                   1041: #endif
                   1042:        
                   1043:        for(i = 0; i < nmapb; i++) {                                                            /* Allocate 'em all */
                   1044:                retr = kmem_alloc_wired(kernel_map, (vm_offset_t *)&mbn, PAGE_SIZE);    /* Find a virtual address to use */
                   1045:                if(retr != KERN_SUCCESS) {                                                              /* Did we get some memory? */
                   1046:                        panic("Whoops...  Not a bit of wired memory left for anyone\n");
                   1047:                }
                   1048:                mapping_free_init((vm_offset_t)mbn, -1, 0);                             /* Initialize onto release queue */
                   1049:        }
                   1050: }
                   1051: 
                   1052: /*
                   1053:  *             vm_offset_t     mapping_p2v(space_t space, phys_entry *pp) - Finds first virtual mapping of a physical page in a space
                   1054:  *
                   1055:  *             Gets a lock on the physical entry.  Then it searches the list of attached mappings for one with
                   1056:  *             the same space.  If it finds it, it returns the virtual address.
                   1057:  */
                   1058: 
                   1059: vm_offset_t    mapping_p2v(space_t space, struct phys_entry *pp) {             /* Finds first virtual mapping of a physical page in a space */
                   1060: 
                   1061:        spl_t                           s;
                   1062:        register mapping        *mp, *mpv;
                   1063:        vm_offset_t                     va;
                   1064: 
                   1065:        if(!hw_lock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK, LockTimeOut)) {      /* Try to get the lock on the physical entry */
                   1066:                splx(s);                                                                                        /* Restore 'rupts */
                   1067:                panic("mapping_p2v: timeout getting lock on physent\n");                        /* Arrrgghhhh! */
                   1068:                return(0);                                                                                      /* Should die before here */
                   1069:        }
                   1070:        
                   1071:        va = 0;                                                                                                 /* Assume failure */
                   1072:        
                   1073:        for(mpv = hw_cpv(pp->phys_link); mpv; mp = hw_cpv(mp->next)) {  /* Scan 'em all */
                   1074:                
                   1075:                if(!(((mpv->PTEv >> 7) & 0x000FFFFF) == space)) continue;       /* Skip all the rest if this is not the right space... */ 
                   1076:                
                   1077:                va = ((((unsigned int)mpv->PTEhash & -64) << 5) ^ (space  << 12)) & 0x003FF000; /* Backward hash to the wrapped VADDR */
                   1078:                va = va | ((mpv->PTEv << 8) & 0xF0000000);                      /* Move in the segment number */
                   1079:                va = va | ((mpv->PTEv << 22) & 0x0FC00000);                     /* Add in the API for the top of the address */
                   1080:                break;                                                                                          /* We're done now, pass virtual address back */
                   1081:        }
                   1082:        
                   1083:        hw_unlock_bit((unsigned int *)&pp->phys_link, PHYS_LOCK);                               /* Unlock the physical entry */
                   1084:        splx(s);                                                                                                /* Restore 'rupts */
                   1085:        return(va);                                                                                             /* Return the result or 0... */
                   1086: }
                   1087: 
                   1088: /*
                   1089:  *     kvtophys(addr)
                   1090:  *
                   1091:  *     Convert a kernel virtual address to a physical address
                   1092:  */
                   1093: vm_offset_t kvtophys(vm_offset_t va) {
                   1094: 
                   1095:        register mapping                *mp, *mpv;
                   1096:        register vm_offset_t    pa;
                   1097:        spl_t                           s;
                   1098:        
                   1099:        s=splhigh();                                                                                    /* Don't bother from now on */
                   1100:        mp = hw_lock_phys_vir(PPC_SID_KERNEL, va);                              /* Find mapping and lock the physical entry for this mapping */
                   1101: 
                   1102:        if((unsigned int)mp&1) {                                                                /* Did the lock on the phys entry time out? */
                   1103:                splx(s);                                                                                        /* Restore 'rupts */
                   1104:                panic("kvtophys: timeout obtaining lock on physical entry (vaddr=%08X)\n", va); /* Scream bloody murder! */
                   1105:                return 0;
                   1106:        }
                   1107: 
                   1108:        if(!mp) {                                                                                               /* If it was not found, or no physical entry */
                   1109:                splx(s);                                                                                        /* Restore 'rupts */
                   1110:                return 0;                                                                                       /* Return 0 */
                   1111:        }
                   1112: 
                   1113:        mpv = hw_cpv(mp);                                                                               /* Convert to virtual addressing */
                   1114:        
                   1115:        if(!mpv->physent) {                                                                             /* Was there a physical entry? */
                   1116:                pa = (vm_offset_t)((mpv->PTEr & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1)));      /* Get physical address from physent */
                   1117:        }
                   1118:        else {
                   1119:                pa = (vm_offset_t)((mpv->physent->pte1 & -PAGE_SIZE) | ((unsigned int)va & (PAGE_SIZE-1)));     /* Get physical address from physent */
                   1120:                hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK);     /* Unlock the physical entry */
                   1121:        }
                   1122:        
                   1123:        splx(s);                                                                                                /* Restore 'rupts */
                   1124:        return pa;                                                                                              /* Return the physical address... */
                   1125: }
                   1126: 
                   1127: /*
                   1128:  *     phystokv(addr)
                   1129:  *
                   1130:  *     Convert a physical address to a kernel virtual address if
                   1131:  *     there is a mapping, otherwise return NULL
                   1132:  */
                   1133: 
                   1134: vm_offset_t phystokv(vm_offset_t pa) {
                   1135: 
                   1136:        struct phys_entry       *pp;
                   1137:        vm_offset_t                     va;
                   1138: 
                   1139:        pp = pmap_find_physentry(pa);                                                   /* Find the physical entry */
                   1140:        if (PHYS_NULL == pp) {
                   1141:                return (vm_offset_t)NULL;                                                       /* If none, return null */
                   1142:        }
                   1143:        if(!(va=mapping_p2v(PPC_SID_KERNEL, pp))) {
                   1144:                return 0;                                                                                       /* Can't find it, return 0... */
                   1145:        }
                   1146:        return (va | (pa & (PAGE_SIZE-1)));                                             /* Build and return VADDR... */
                   1147: 
                   1148: }
                   1149: 
                   1150: /*
                   1151:  *             Enters translations into the autogen maps.
                   1152:  *
                   1153:  *             Not implemented yet, just stubbed out...
                   1154:  */
                   1155:  
                   1156: boolean_t      autogen_map(space_t space, vm_offset_t va, vm_offset_t spa, vm_offset_t epa, vm_prot_t prot, int attr) { /* Build an autogen area */
                   1157: 
                   1158:                return(0);                                                                              /* Just return false for now */
                   1159: }
                   1160: 
                   1161: 
                   1162: /*
                   1163:  *             Dumps out the mapping stuff associated with a virtual address
                   1164:  */
                   1165: void dumpaddr(space_t space, vm_offset_t va) {
                   1166: 
                   1167:        mapping         *mp, *mpv;
                   1168:        vm_offset_t     pa;
                   1169:        spl_t           s;
                   1170: 
                   1171:        s=splhigh();                                                                                    /* Don't bother me */
                   1172: 
                   1173:        mp = hw_lock_phys_vir(space, va);                                               /* Lock the physical entry for this mapping */
                   1174:        if(!mp) {                                                                                               /* Did we find one? */
                   1175:                splx(s);                                                                                        /* Restore the interrupt level */
                   1176:                printf("dumpaddr: virtual address (%08X) not mapped\n", va);    
                   1177:                return;                                                                                         /* Didn't find any, return FALSE... */
                   1178:        }
                   1179:        if((unsigned int)mp&1) {                                                                /* Did we timeout? */
                   1180:                panic("dumpaddr: timeout locking physical entry for virtual address (%08X)\n", va);     /* Yeah, scream about it! */
                   1181:                splx(s);                                                                                        /* Restore the interrupt level */
                   1182:                return;                                                                                         /* Bad hair day, return FALSE... */
                   1183:        }
                   1184:        printf("dumpaddr: space=%08X; vaddr=%08X\n", space, va);        /* Say what address were dumping */
                   1185:        mpv = hw_cpv(mp);                                                                               /* Get virtual address of mapping */
                   1186:        dumpmapping(mpv);
                   1187:        if(mpv->physent) {
                   1188:                dumppca(mpv);
                   1189:                hw_unlock_bit((unsigned int *)&mpv->physent->phys_link, PHYS_LOCK);     /* Unlock physical entry associated with mapping */
                   1190:        }
                   1191:        splx(s);                                                                                                /* Was there something you needed? */
                   1192:        return;                                                                                                 /* Tell them we did it */
                   1193: }
                   1194: 
                   1195: 
                   1196: 
                   1197: /*
                   1198:  *             Prints out a mapping control block
                   1199:  *
                   1200:  */
                   1201:  
                   1202: void dumpmapping(struct mapping *mp) {                                                 /* Dump out a mapping */
                   1203: 
                   1204:        printf("Dump of mapping block: %08X\n", mp);                    /* Header */
                   1205:        printf("                 next: %08X\n", mp->next);                 
                   1206:        printf("             hashnext: %08X\n", mp->hashnext);                 
                   1207:        printf("              PTEhash: %08X\n", mp->PTEhash);                 
                   1208:        printf("               PTEent: %08X\n", mp->PTEent);                 
                   1209:        printf("              physent: %08X\n", mp->physent);                 
                   1210:        printf("                 PTEv: %08X\n", mp->PTEv);                 
                   1211:        printf("                 PTEr: %08X\n", mp->PTEr);                 
                   1212:        printf("                 pmap: %08X\n", mp->pmap);
                   1213:        
                   1214:        if(mp->physent) {                                                                       /* Print physent if it exists */
                   1215:                printf("Associated physical entry: %08X %08X\n", mp->physent->phys_link, mp->physent->pte1);
                   1216:        }
                   1217:        else {
                   1218:                printf("Associated physical entry: none\n");
                   1219:        }
                   1220:        
                   1221:        dumppca(mp);                                                                            /* Dump out the PCA information */
                   1222:        
                   1223:        return;
                   1224: }
                   1225: 
                   1226: /*
                   1227:  *             Prints out a PTEG control area
                   1228:  *
                   1229:  */
                   1230:  
                   1231: void dumppca(struct mapping *mp) {                                             /* PCA */
                   1232: 
                   1233:        PCA                             *pca;
                   1234:        unsigned int    *pteg;
                   1235:        
                   1236:        pca = (PCA *)((unsigned int)mp->PTEhash&-64);           /* Back up to the start of the PCA */
                   1237:        pteg=(unsigned int *)((unsigned int)pca-(((hash_table_base&0x0000FFFF)+1)<<16));
                   1238:        printf(" Dump of PCA: %08X\n", pca);            /* Header */
                   1239:        printf("     PCAlock: %08X\n", pca->PCAlock);                 
                   1240:        printf("     PCAallo: %08X\n", pca->flgs.PCAallo);                 
                   1241:        printf("     PCAhash: %08X %08X %08X %08X\n", pca->PCAhash[0], pca->PCAhash[1], pca->PCAhash[2], pca->PCAhash[3]);                 
                   1242:        printf("              %08X %08X %08X %08X\n", pca->PCAhash[4], pca->PCAhash[5], pca->PCAhash[6], pca->PCAhash[7]);                 
                   1243:        printf("Dump of PTEG: %08X\n", pteg);           /* Header */
                   1244:        printf("              %08X %08X %08X %08X\n", pteg[0], pteg[1], pteg[2], pteg[3]);                 
                   1245:        printf("              %08X %08X %08X %08X\n", pteg[4], pteg[5], pteg[6], pteg[7]);                 
                   1246:        printf("              %08X %08X %08X %08X\n", pteg[8], pteg[9], pteg[10], pteg[11]);                 
                   1247:        printf("              %08X %08X %08X %08X\n", pteg[12], pteg[13], pteg[14], pteg[15]);                 
                   1248:        return;
                   1249: }
                   1250: 
                   1251: /*
                   1252:  *             Dumps starting with a physical entry
                   1253:  */
                   1254:  
                   1255: void dumpphys(struct phys_entry *pp) {                                                 /* Dump from physent */
                   1256: 
                   1257:        mapping                 *mp;
                   1258:        PCA                             *pca;
                   1259:        unsigned int    *pteg;
                   1260: 
                   1261:        printf("Dump from physical entry %08X: %08X %08X\n", pp, pp->phys_link, pp->pte1);
                   1262:        mp = hw_cpv(pp->phys_link);
                   1263:        while(mp) {
                   1264:                dumpmapping(mp);
                   1265:                dumppca(mp);
                   1266:                mp = hw_cpv(mp->next);
                   1267:        }
                   1268:        
                   1269:        return;
                   1270: }
                   1271: 
                   1272: /*
                   1273:  *             void ignore_zero_fault(boolean_t) - Sets up to ignore or honor any fault on 
                   1274:  *             page 0 access for the current thread.
                   1275:  *
                   1276:  *             If parameter is TRUE, faults are ignored
                   1277:  *             If parameter is FALSE, faults are honored
                   1278:  *
                   1279:  */
                   1280: 
                   1281: void ignore_zero_fault(boolean_t type) {               /* Sets up to ignore or honor any fault on page 0 access for the current thread */
                   1282: 
                   1283:        if(type) current_act()->mact.specFlags |= ignoreZeroFault;      /* Ignore faults on page 0 */
                   1284:        else     current_act()->mact.specFlags &= ~ignoreZeroFault;     /* Honor faults on page 0 */
                   1285:        
                   1286:        return;                                                                                         /* Return the result or 0... */
                   1287: }
                   1288: 
                   1289: 
                   1290: 
                   1291: 
                   1292: 
                   1293: 
                   1294: 
                   1295: 

unix.superglobalmegacorp.com

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