Annotation of kernel/machdep/ppc/pmap.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 1999 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * Portions Copyright (c) 1999 Apple Computer, Inc.  All Rights
        !             7:  * Reserved.  This file contains Original Code and/or Modifications of
        !             8:  * Original Code as defined in and that are subject to the Apple Public
        !             9:  * Source License Version 1.1 (the "License").  You may not use this file
        !            10:  * except in compliance with the License.  Please obtain a copy of the
        !            11:  * License at http://www.apple.com/publicsource and read it before using
        !            12:  * this file.
        !            13:  * 
        !            14:  * The Original Code and all software distributed under the License are
        !            15:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            16:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            17:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            18:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            19:  * License for the specific language governing rights and limitations
        !            20:  * under the License.
        !            21:  * 
        !            22:  * @APPLE_LICENSE_HEADER_END@
        !            23:  */
        !            24: 
        !            25: /*
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1990,1991,1992 The University of Utah and
        !            28:  * the Center for Software Science (CSS).
        !            29:  * Copyright (c) 1991,1987 Carnegie Mellon University.
        !            30:  * All rights reserved.
        !            31:  *
        !            32:  * Permission to use, copy, modify and distribute this software and its
        !            33:  * documentation is hereby granted, provided that both the copyright
        !            34:  * notice and this permission notice appear in all copies of the
        !            35:  * software, derivative works or modified versions, and any portions
        !            36:  * thereof, and that both notices appear in supporting documentation,
        !            37:  * and that all advertising materials mentioning features or use of
        !            38:  * this software display the following acknowledgement: ``This product
        !            39:  * includes software developed by the Center for Software Science at
        !            40:  * the University of Utah.''
        !            41:  *
        !            42:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF
        !            43:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
        !            44:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
        !            45:  * THIS SOFTWARE.
        !            46:  *
        !            47:  * CSS requests users of this software to return to [email protected] any
        !            48:  * improvements that they make and grant CSS redistribution rights.
        !            49:  *
        !            50:  * Carnegie Mellon requests users of this software to return to
        !            51:  *  Software Distribution Coordinator  or  [email protected]
        !            52:  *  School of Computer Science
        !            53:  *  Carnegie Mellon University
        !            54:  *  Pittsburgh PA 15213-3890
        !            55:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            56:  * the rights to redistribute these changes.
        !            57:  *
        !            58:  *     Utah $Hdr: pmap.c 1.28 92/06/23$
        !            59:  *     Author: Mike Hibler, Bob Wheeler, University of Utah CSS, 10/90
        !            60:  */
        !            61:  
        !            62: /*
        !            63:  *     Manages physical address maps for powerpc.
        !            64:  *
        !            65:  *     In addition to hardware address maps, this
        !            66:  *     module is called upon to provide software-use-only
        !            67:  *     maps which may or may not be stored in the same
        !            68:  *     form as hardware maps.  These pseudo-maps are
        !            69:  *     used to store intermediate results from copy
        !            70:  *     operations to and from address spaces.
        !            71:  *
        !            72:  *     Since the information managed by this module is
        !            73:  *     also stored by the logical address mapping module,
        !            74:  *     this module may throw away valid virtual-to-physical
        !            75:  *     mappings at almost any time.  However, invalidations
        !            76:  *     of virtual-to-physical mappings must be done as
        !            77:  *     requested.
        !            78:  *
        !            79:  *     In order to cope with hardware architectures which
        !            80:  *     make virtual-to-physical map invalidates expensive,
        !            81:  *     this module may delay invalidate or reduced protection
        !            82:  *     operations until such time as they are actually
        !            83:  *     necessary.  This module is given full information to
        !            84:  *     when physical maps must be made correct.
        !            85:  *     
        !            86:  */
        !            87: 
        !            88: /*
        !            89:  * CAVAETS:
        !            90:  *
        !            91:  *     Needs more work for MP support
        !            92:  */
        !            93: 
        !            94: #include <debug.h>
        !            95: #include <mach_vm_debug.h>
        !            96: 
        !            97: #include <kern/thread.h>
        !            98: #include <mach/vm_attributes.h>
        !            99: #include <mach/vm_param.h>
        !           100: #include <kernserv/machine/spl.h>
        !           101: 
        !           102: #include <machdep/ppc/proc_reg.h>
        !           103: #include <machdep/ppc/mem.h>
        !           104: #include <machdep/ppc/pmap.h>
        !           105: #include <machdep/ppc/pmap_internals.h>
        !           106: #include <machdep/ppc/powermac.h>
        !           107: 
        !           108: 
        !           109: #define NULL 0
        !           110: #define DPRINTF(x) if(0) {kprintf("%s : ", __FUNCTION__);kprintf x;}
        !           111: 
        !           112: /* forward */
        !           113: void pmap_activate(pmap_t pmap, thread_t th, int which_cpu);
        !           114: void pmap_deactivate(pmap_t pmap, thread_t th, int which_cpu);
        !           115: void copy_to_phys(vm_offset_t sva, vm_offset_t dpa, int bytecount);
        !           116: 
        !           117: static struct mapping *pmap_find_mapping(space_t space, vm_offset_t offset);
        !           118: 
        !           119: static void pmap_free_mapping(register struct mapping *mp);
        !           120: 
        !           121: static void pmap_reap_mappings(void);
        !           122: 
        !           123: static struct mapping *pmap_enter_mapping(pmap_t pmap,
        !           124:                                          space_t space,
        !           125:                                          vm_offset_t va,
        !           126:                                          vm_offset_t pa,
        !           127:                                          pte_t *pte,
        !           128:                                          unsigned prot,
        !           129:                                          struct phys_entry *pp);
        !           130: 
        !           131: #if DEBUG
        !           132: #define PDB_USER       0x01    /* exported functions */
        !           133: #define PDB_MAPPING    0x02    /* low-level mapping routines */
        !           134: #define PDB_ENTER      0x04    /* pmap_enter specifics */
        !           135: #define PDB_COPY       0x08    /* copy page debugging */
        !           136: #define PDB_ZERO       0x10    /* zero page debugging */
        !           137: #define PDB_WIRED      0x20    /* things concerning wired entries */
        !           138: #define PDB_PTEG       0x40    /* PTEG overflows */
        !           139: #define PDB_MASSIVE    0x80    /* Massive costly assert checks */
        !           140: #define PDB_IO         0x100   /* Improper use of WIMG_IO checks - PCI machines */
        !           141: int pmdebug = 0;
        !           142: 
        !           143: #define PCI_BASE       0x80000000
        !           144: #endif
        !           145: 
        !           146: struct pmap    kernel_pmap_store;
        !           147: pmap_t         kernel_pmap;
        !           148: struct zone    *pmap_zone;             /* zone of pmap structures */
        !           149: boolean_t      pmap_initialized = FALSE;
        !           150: 
        !           151: #define                HASH_TABLE_FACTLOG2     0
        !           152: int            hash_table_factlog2 = HASH_TABLE_FACTLOG2;
        !           153: 
        !           154: /*
        !           155:  * Physical-to-virtual translations are handled by inverted page table
        !           156:  * structures, phys_tables.  Multiple mappings of a single page are handled
        !           157:  * by linking the affected mapping structures. We initialise one region
        !           158:  * for phys_tables of the physical memory we know about, but more may be
        !           159:  * added as it is discovered (eg. by drivers).
        !           160:  */
        !           161: struct phys_entry *phys_table; /* For debugging */
        !           162: 
        !           163: /*
        !           164:  * XXX use mpqueue_head_t's??
        !           165:  * (no one else does, are they coming or going?)
        !           166:  */
        !           167: queue_head_t           free_mapping;      /* list of free mapping structs */
        !           168: decl_simple_lock_data(,free_mapping_lock) /* and lock */
        !           169: 
        !           170: pmap_t                 free_pmap;         /* list of free pmaps */
        !           171: decl_simple_lock_data(,free_pmap_lock)   /* and lock */
        !           172: 
        !           173: decl_simple_lock_data(,pmap_lock)         /* XXX this is all broken */
        !           174: 
        !           175: unsigned       prot_bits[8];
        !           176: 
        !           177: /*
        !           178:  * This is the master space ID counter, initially set to the kernel's
        !           179:  * SID. The counter is incremented (though not necessarily by one)
        !           180:  * whenever a new space ID is required. For PPC, the SID ranges from
        !           181:  * to 2**20 - 1.
        !           182:  */
        !           183: int            sid_counter=PPC_SID_KERNEL;     /* seed for SID generator */
        !           184: 
        !           185: 
        !           186: 
        !           187: /*
        !           188:  * pmap_find_physentry(pa)
        !           189:  *
        !           190:  * Function to get index into phys_table for a given physical address
        !           191:  */
        !           192: struct phys_entry *
        !           193: pmap_find_physentry(
        !           194:        vm_offset_t pa)
        !           195: {
        !           196:        int i;
        !           197:        struct phys_entry *entry;
        !           198: 
        !           199:        for (i = pmap_mem_regions_count-1; i >= 0; i--) {
        !           200:                if (pa < pmap_mem_regions[i].start)
        !           201:                        continue;
        !           202:                if (pa >= pmap_mem_regions[i].end)
        !           203:                {
        !           204:                        return PHYS_NULL;
        !           205:                }
        !           206:                
        !           207:                entry = &pmap_mem_regions[i].
        !           208:                    phys_table[(pa -
        !           209:                                pmap_mem_regions[i].start) >> PPC_PGSHIFT];
        !           210:                return entry;
        !           211:        }
        !           212:        DPRINTF(("NMGS DEBUG : pmap_find_physentry 0x%08x out of range\n",pa));
        !           213:        return (struct phys_entry *)PHYS_NULL;
        !           214: }
        !           215: 
        !           216: 
        !           217: 
        !           218: /*
        !           219:  * kern_return_t
        !           220:  * pmap_add_physical_memory(vm_offset_t spa, vm_offset_t epa,
        !           221:  *                          boolean_t available, unsigned int attr)
        !           222:  *     Allocate some extra physentries for the physical addresses given,
        !           223:  *     specifying some default attribute that on the powerpc specifies
        !           224:  *      the default cachability for any mappings using these addresses
        !           225:  *     If the memory is marked as available, it is added to the general
        !           226:  *     VM pool, otherwise it is not (it is reserved for card IO etc).
        !           227:  */
        !           228: kern_return_t
        !           229: pmap_add_physical_memory(
        !           230:        vm_offset_t spa,
        !           231:        vm_offset_t epa,
        !           232:        boolean_t available,
        !           233:        unsigned int attr)
        !           234: {
        !           235:        int i,j;
        !           236:        spl_t s;
        !           237:        struct phys_entry *phys_table;
        !           238: 
        !           239:        /* Only map whole pages */
        !           240: 
        !           241:        spa = trunc_page(spa);
        !           242:        epa = round_page(epa);
        !           243: 
        !           244:        /* First check that the region doesn't already exist */
        !           245: 
        !           246:        assert (epa >= spa);
        !           247:        for (i = 0; i < pmap_mem_regions_count; i++) {
        !           248:                /* If we're below the next region, then no conflict */
        !           249:                if (epa <= pmap_mem_regions[i].start)
        !           250:                        break;
        !           251:                if (spa < pmap_mem_regions[i].end) {
        !           252: #if DEBUG
        !           253:                        DPRINTF(("(0x%08x,0x%08x,0x%08x) - memory already present\n",spa,epa,attr));
        !           254: #endif /* DEBUG */
        !           255:                        return KERN_NO_SPACE;
        !           256:                }
        !           257:        }
        !           258: 
        !           259:        /* Check that we've got enough space for another region */
        !           260:        if (pmap_mem_regions_count == MEM_REGION_MAX)
        !           261:                return KERN_RESOURCE_SHORTAGE;
        !           262: 
        !           263:        /* Once here, i points to the mem_region above ours in physical mem */
        !           264: 
        !           265:        /* allocate a new phys_table for this new region */
        !           266: 
        !           267:        phys_table =  (struct phys_entry *)
        !           268:                kalloc(sizeof(struct phys_entry) * atop(epa-spa));
        !           269: 
        !           270:        /* Initialise the new phys_table entries */
        !           271:        for (j = 0; j < atop(epa-spa); j++) {
        !           272:                queue_init(&phys_table[j].phys_link);
        !           273:                /* We currently only support these two attributes */
        !           274:                assert((attr == PTE_WIMG_DEFAULT) ||
        !           275:                       (attr == PTE_WIMG_IO));
        !           276:                phys_table[j].pte1.bits.wimg = attr;
        !           277:        }
        !           278:        s = splhigh();
        !           279:        
        !           280:        /* Move all the phys_table entries up some to make room in
        !           281:         * the ordered list.
        !           282:         */
        !           283:        for (j = pmap_mem_regions_count; j > i ; j--)
        !           284:                pmap_mem_regions[j] = pmap_mem_regions[j-1];
        !           285: 
        !           286:        /* Insert a new entry with some memory to back it */
        !           287: 
        !           288:        pmap_mem_regions[i].start            = spa;
        !           289:        pmap_mem_regions[i].end           = epa;
        !           290:        pmap_mem_regions[i].phys_table    = phys_table;
        !           291: 
        !           292:        pmap_mem_regions_count++;
        !           293:        splx(s);
        !           294: 
        !           295:        if (available) {
        !           296:                DPRINTF(("warning : pmap_add_physical_mem() "
        !           297:                       "available not yet supported\n"));
        !           298:        }
        !           299: 
        !           300:        return KERN_SUCCESS;
        !           301: }
        !           302: 
        !           303: 
        !           304: 
        !           305: /*
        !           306:  * ppc_protection_init()
        !           307:  *     Initialise the user/kern_prot_codes[] arrays which are 
        !           308:  *     used to translate machine independent protection codes
        !           309:  *     to powerpc protection codes. The PowerPc can only provide
        !           310:  *      [no rights, read-only, read-write]. Read implies execute.
        !           311:  * See PowerPC 601 User's Manual Table 6.9
        !           312:  */
        !           313: void
        !           314: ppc_protection_init(void)
        !           315: {
        !           316:        prot_bits[VM_PROT_NONE | VM_PROT_NONE  | VM_PROT_NONE]     = 0;
        !           317:        prot_bits[VM_PROT_READ | VM_PROT_NONE  | VM_PROT_NONE]     = 3;
        !           318:        prot_bits[VM_PROT_READ | VM_PROT_NONE  | VM_PROT_EXECUTE]  = 3;
        !           319:        prot_bits[VM_PROT_NONE | VM_PROT_NONE  | VM_PROT_EXECUTE]  = 3;
        !           320:        prot_bits[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE]     = 2;
        !           321:        prot_bits[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE]     = 2;
        !           322:        prot_bits[VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE]  = 2;
        !           323:        prot_bits[VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE]  = 2;
        !           324: }
        !           325: 
        !           326: 
        !           327: 
        !           328: /*
        !           329:  * pmap_map(va, spa, epa, prot)
        !           330:  *     is called during boot to map memory in the kernel's address map.
        !           331:  *     A virtual address range starting at "va" is mapped to the physical
        !           332:  *     address range "spa" to "epa" with machine independent protection
        !           333:  *     "prot".
        !           334:  *
        !           335:  *     "va", "spa", and "epa" are byte addresses and must be on machine
        !           336:  *     independent page boundaries.
        !           337:  */
        !           338: vm_offset_t
        !           339: pmap_map(
        !           340:        vm_offset_t va,
        !           341:        vm_offset_t spa,
        !           342:        vm_offset_t epa,
        !           343:        vm_prot_t prot)
        !           344: {
        !           345: 
        !           346:        if (spa == epa)
        !           347:                return(va);
        !           348: 
        !           349:        assert(epa > spa);
        !           350: 
        !           351:        while (spa < epa) {
        !           352:                pmap_enter(kernel_pmap, va, spa, prot, TRUE);
        !           353: 
        !           354:                va += PAGE_SIZE;
        !           355:                spa += PAGE_SIZE;
        !           356:        }
        !           357:        return(va);
        !           358: }
        !           359: 
        !           360: 
        !           361: 
        !           362: /*
        !           363:  * pmap_map_bd(va, spa, epa, prot)
        !           364:  *     Back-door routine for mapping kernel VM at initialisation.
        !           365:  *     Used for mapping memory outside the known physical memory
        !           366:  *      space, with caching disabled. Designed for use by device probes.
        !           367:  * 
        !           368:  *     A virtual address range starting at "va" is mapped to the physical
        !           369:  *     address range "spa" to "epa" with machine independent protection
        !           370:  *     "prot".
        !           371:  *
        !           372:  *     "va", "spa", and "epa" are byte addresses and must be on machine
        !           373:  *     independent page boundaries.
        !           374:  *
        !           375:  * WARNING: The current version of memcpy() can use the dcbz instruction
        !           376:  * on the destination addresses.  This will cause an alignment exception
        !           377:  * and consequent overhead if the destination is caching-disabled.  So
        !           378:  * avoid memcpy()ing into the memory mapped by this function.
        !           379:  *
        !           380:  * also, many other pmap_ routines will misbehave if you try and change
        !           381:  * protections or remove these mappings, they are designed to be permanent.
        !           382:  */
        !           383: vm_offset_t
        !           384: pmap_map_bd(
        !           385:        vm_offset_t va,
        !           386:        vm_offset_t spa,
        !           387:        vm_offset_t epa,
        !           388:        vm_prot_t prot)
        !           389: {
        !           390:        pte_t  *pte;
        !           391:        struct phys_entry* pp;
        !           392:        struct mapping *mp;
        !           393:        spl_t s;
        !           394: 
        !           395:        if (spa == epa)
        !           396:                return(va);
        !           397: 
        !           398:        assert(epa > spa);
        !           399: 
        !           400: #if DEBUG
        !           401:        DPRINTF(("va=0x%08X, spa=0x%08X, epa=0x%08X, prot=0x%x\n\n",va,spa,epa,prot));
        !           402: #endif
        !           403:        s = splhigh();
        !           404:        while (spa < epa) {
        !           405:                
        !           406:                pte = find_or_allocate_pte(PPC_SID_KERNEL, va, TRUE);
        !           407: 
        !           408:                assert(pte != PTE_NULL);
        !           409: 
        !           410:                /* remapping of already-mapped addresses is OK, we just
        !           411:                 * trample on the PTE, but make sure we're mapped to same
        !           412:                 * address
        !           413:                 */
        !           414:                if (pte->pte0.bits.valid)
        !           415:                        assert(trunc_page(pte->pte1.word) == spa);
        !           416: 
        !           417:                /*      Perform a general case PTE update designed to work
        !           418:                        in SMP configurations. TODO - locks and tlbsync
        !           419:                */
        !           420:                assert(pte->pte0.bits.valid == TRUE);
        !           421:                pte->pte0.bits.valid = FALSE;   /* Invalidate pte entry */
        !           422:                sync();                 /* Force updates to complete */
        !           423:                tlbie(va);              /* Wipe out this virtual address */
        !           424:                eieio();                /* Enforce ordering of v bit */
        !           425:                tlbsync();
        !           426:                sync();
        !           427: 
        !           428:                /*      Allowable early PTE updates: RPN,R,C,WIMG,PP
        !           429:                 */
        !           430:                pte->pte1.bits.protection = prot_bits[prot];
        !           431:                pte->pte1.bits.phys_page = spa >> PPC_PGSHIFT;
        !           432:                pte->pte1.bits.wimg       = PTE_WIMG_IO;
        !           433:                eieio();
        !           434: 
        !           435:                /*      Post tlbie updates: VSID,H,API,V
        !           436:                */
        !           437:                pte->pte0.bits.valid = TRUE;    /* Validate pte entry */
        !           438:                sync();
        !           439: 
        !           440: 
        !           441:                /* If memory is mappable (is in phys table) then set
        !           442:                 * default cach attributes to non-cached and verify
        !           443:                 * that there aren't any non-cached mappings which would
        !           444:                 * break the processor spec (and hang the machine).
        !           445:                 */
        !           446:                pp = pmap_find_physentry(spa);
        !           447:                if (pp != PHYS_NULL) {
        !           448:                        /* Set the default mapping type */
        !           449:                        pp->pte1.bits.wimg = PTE_WIMG_IO;
        !           450: #if DEBUG
        !           451:                        /* Belt and braces check on mappings */
        !           452:                        queue_iterate(&pp->phys_link, mp,
        !           453:                                      struct mapping *, phys_link) {
        !           454:                                assert(mp->pte->pte1.bits.wimg ==
        !           455:                                       PTE_WIMG_IO);
        !           456:                        }
        !           457: #endif /* DEBUG */
        !           458:                }
        !           459:                va += PAGE_SIZE;
        !           460:                spa += PAGE_SIZE;
        !           461:        }
        !           462:        splx(s);
        !           463:        return(va);
        !           464: }
        !           465: 
        !           466: 
        !           467: 
        !           468: /*
        !           469:  *     Bootstrap the system enough to run with virtual memory.
        !           470:  *     Map the kernel's code and data, and allocate the system page table.
        !           471:  *     Called with mapping done by BATs. Page_size must already be set.
        !           472:  *
        !           473:  *     Parameters:
        !           474:  *     first_avail     PA of address where we can allocate structures.
        !           475:  */
        !           476: void
        !           477: pmap_bootstrap(
        !           478:        unsigned int mem_size,
        !           479:        vm_offset_t *first_avail)
        !           480: {
        !           481:        struct mapping          *mp;
        !           482:        vm_offset_t             struct_addr;
        !           483:        vm_size_t               struct_size, hash_table_align, phys_table_size,
        !           484:                                        mapping_table_size;
        !           485:        unsigned int            mapping_table_num, phys_pages_num;
        !           486:        int                     i;
        !           487: 
        !           488:        *first_avail = round_page(*first_avail);
        !           489: 
        !           490:        assert(PAGE_SIZE == PPC_PGBYTES);
        !           491: 
        !           492:        ppc_protection_init();
        !           493: 
        !           494:        /*
        !           495:         * Initialize kernel pmap
        !           496:         */
        !           497:        kernel_pmap = &kernel_pmap_store;
        !           498: #if    NCPUS > 1
        !           499:        lock_init(&pmap_lock, FALSE, ETAP_VM_PMAP_SYS, ETAP_VM_PMAP_SYS_I);
        !           500: #endif /* NCPUS > 1 */
        !           501:        simple_lock_init(&kernel_pmap->lock);
        !           502:        simple_lock_init(&free_pmap_lock);
        !           503: 
        !           504:        kernel_pmap->ref_count = 1;
        !           505:        kernel_pmap->space = PPC_SID_KERNEL;
        !           506:        kernel_pmap->next = PMAP_NULL;
        !           507: 
        !           508:        /*
        !           509:         * Allocate: (from first_avail up)
        !           510:         *      aligned to its own size:
        !           511:          *        hash table (for mem size 2**x, allocate 2**(x-10) entries)
        !           512:         *      physical page entries (1 per physical page)
        !           513:         *      physical -> virtual mappings (for multi phys->virt mappings)
        !           514:         */
        !           515: 
        !           516:        /*
        !           517:         * Table 7-21 on page 7-52 of the PowerPC Programming
        !           518:         * Environments book (32-bit) doesn't tell you how to
        !           519:         * size the hashed page table for strange memory sizes
        !           520:         * (i.e. not a power of 2).  It has been empirically
        !           521:         * determined that splitting the difference and rounding
        !           522:         * can be used effectively in these circumstances.
        !           523:         */
        !           524:        {
        !           525:            vm_size_t   rounded_mem_size;
        !           526:            int         factor;
        !           527: 
        !           528:            /*
        !           529:             * The minimum size for the hash table is 64K
        !           530:             * and is bounded by a memory size of 8MB.
        !           531:             */
        !           532:            hash_table_size = 64*1024; rounded_mem_size = 8*1024*1024;
        !           533:            while (hash_table_size < 32*1024*104 &&
        !           534:                   rounded_mem_size < mem_size) {
        !           535:                hash_table_size *= 2; rounded_mem_size *= 2;
        !           536:            }
        !           537: 
        !           538:            /*
        !           539:             * If we need to allocate more than a minimum
        !           540:             * sized hash table and our memory size is not
        !           541:             * a power of 2
        !           542:             *
        !           543:             * AND
        !           544:             *
        !           545:             * if we are less than half way to next higher
        !           546:             * power of 2, then use the next lower value.
        !           547:             */
        !           548:            if (hash_table_size > 64*1024 && rounded_mem_size != mem_size) {
        !           549:                if (
        !           550:                    /*
        !           551:                     * Special case for mem_size
        !           552:                     * greater than 2G since
        !           553:                     * rounded_mem_size is zero
        !           554:                     * in this case.
        !           555:                     */
        !           556:                    (mem_size > 2*1024*1024*1024UL &&
        !           557:                     mem_size < 3*1024*1024*1024UL)
        !           558:                    ||
        !           559:                    (mem_size < ((rounded_mem_size / 2) +
        !           560:                                 (rounded_mem_size / 4)))
        !           561:                    ) hash_table_size /= 2;
        !           562:            }
        !           563: 
        !           564: #ifdef notdef
        !           565:            printf("rounded_mem_size %x\n", rounded_mem_size);
        !           566: #endif
        !           567: 
        !           568:            /*
        !           569:             * Determine the value of any additional
        !           570:             * factor to apply to the size of the
        !           571:             * hash table.
        !           572:             */
        !           573:            if (hash_table_factlog2 < 0)
        !           574:                factor = -1;
        !           575:            else
        !           576:                factor = 1;
        !           577:            
        !           578:            hash_table_factlog2 *= factor;
        !           579: 
        !           580:            while (hash_table_factlog2 > 0) {
        !           581:                factor *= 2; hash_table_factlog2--;
        !           582:            }
        !           583: 
        !           584:            if (factor > 0)
        !           585:                printf("hash table factor is %d\n", factor);
        !           586:            else
        !           587:                printf("hash table factor is 1/%d\n", -factor);
        !           588: 
        !           589:            /*
        !           590:             * Apply the factor, and catch out
        !           591:             * of bound sizes.
        !           592:             */
        !           593:            if (factor > 1) {
        !           594:                hash_table_size *= factor;
        !           595: 
        !           596:                if (hash_table_size < 64*1024)
        !           597:                    hash_table_size = 64*1024;
        !           598:            }
        !           599:            else if (factor < -1) {
        !           600:                hash_table_size /= -factor;
        !           601: 
        !           602:                if (hash_table_size > 32*1024*1024 || hash_table_size == 0)
        !           603:                    hash_table_size = 32*1024*1024;
        !           604:            }
        !           605: 
        !           606:            /*
        !           607:             * Notice a bit of handwaving here: since we
        !           608:             * use a BAT to statically map the kernel,
        !           609:             * the hashed page table and the ancillary
        !           610:             * mapping structures, using mem_size is a
        !           611:             * bit generous.  However, we do need to allow
        !           612:             * for some extra mappings for I/O regions, so
        !           613:             * we'll just call it even.
        !           614:             */
        !           615:        }
        !           616: 
        !           617:        /* HASH TABLE MUST BE aligned to its size */
        !           618: 
        !           619:        struct_addr = (*first_avail + (hash_table_size - 1)) &~
        !           620:                                                (hash_table_size - 1);
        !           621: 
        !           622:        hash_table_align = struct_addr - *first_avail;
        !           623: 
        !           624:        if (round_page(*first_avail) + PPC_PGBYTES < round_page(struct_addr)) {
        !           625:                free_regions[free_regions_count].start = 
        !           626:                        round_page(*first_avail) + PPC_PGBYTES;
        !           627:                free_regions[free_regions_count].end = round_page(struct_addr);
        !           628:                free_regions_count++;
        !           629:        }
        !           630: 
        !           631:        phys_pages_num = atop(mem_size);
        !           632: 
        !           633:        phys_table_size = sizeof(struct phys_entry) * phys_pages_num;
        !           634:        mapping_table_size =
        !           635:            sizeof(struct mapping) * (hash_table_size/sizeof(pte_t));
        !           636: 
        !           637:        /* size of all structures that we're going to allocate */
        !           638: 
        !           639:        struct_size = (vm_size_t) (hash_table_size +
        !           640:                                   phys_table_size +
        !           641:                                   mapping_table_size);
        !           642: 
        !           643: #ifdef notdef
        !           644:        printf("pmap static allocation:\n");
        !           645:        printf("hash table: %x (alignment) + %x (size) +\n",
        !           646:               hash_table_align, hash_table_size);
        !           647:        printf("ptov table: %x (phys entries) + %x (mappings) =\n",
        !           648:               phys_table_size, mapping_table_size);
        !           649:        printf("total: %x\n", hash_table_align + struct_size);
        !           650: #endif
        !           651: 
        !           652:        struct_size = round_page(struct_size);
        !           653: 
        !           654:        /* Zero everything - this also invalidates the hash table entries */
        !           655:        bzero((char *)struct_addr, struct_size);
        !           656: 
        !           657:        /* Set up some pointers to our new structures */
        !           658:        
        !           659:        /*
        !           660:         * Set up hash table address, keeping alignment. These
        !           661:         * mappings are 1-1.
        !           662:         */
        !           663:        hash_table_base = struct_addr;
        !           664:        struct_addr += hash_table_size;
        !           665: 
        !           666:        /*
        !           667:         * phys_table is static to help debugging,
        !           668:         * this variable is no longer actually used
        !           669:         * outside of this scope
        !           670:         */
        !           671:        phys_table = (struct phys_entry *) struct_addr;
        !           672: 
        !           673:        for (i = 0; i < pmap_mem_regions_count; i++) {
        !           674:                pmap_mem_regions[i].phys_table = phys_table;
        !           675:                phys_table = phys_table +
        !           676:                        atop(pmap_mem_regions[i].end -
        !           677:                             pmap_mem_regions[i].start);
        !           678:        }
        !           679: 
        !           680:        /* restore phys_table for debug */
        !           681:        phys_table = (struct phys_entry *) struct_addr;
        !           682:        struct_addr += phys_table_size;
        !           683: 
        !           684:        /* Initialise the registers necessary for supporting the hashtable */
        !           685:        hash_table_init(hash_table_base, hash_table_size);
        !           686: 
        !           687:        /* Initialise the physical table mappings */ 
        !           688:        for (i = 0; i < phys_pages_num; i++) {
        !           689:                queue_init(&phys_table[i].phys_link);
        !           690:                phys_table[i].pte1.bits.wimg = PTE_WIMG_DEFAULT;
        !           691:        }
        !           692: 
        !           693:        /*
        !           694:         * Remaining space is for mapping entries.  Chain them
        !           695:         * together (XXX can't use a zone
        !           696:         * since zone package hasn't been initialized yet).
        !           697:         */
        !           698:        mapping_table_num = mapping_table_size /
        !           699:                sizeof(struct mapping);
        !           700: 
        !           701:        mp = (struct mapping *) struct_addr;
        !           702: 
        !           703:        queue_init(&free_mapping);
        !           704:        simple_lock_init(&free_mapping_lock);
        !           705: 
        !           706:        while (mapping_table_num-- > 0) {
        !           707:                queue_enter(&free_mapping, mp, struct mapping *, phys_link);
        !           708:                mp++;
        !           709:        }
        !           710: 
        !           711:        *first_avail = round_page(mp);
        !           712: 
        !           713:        /* All the rest of memory is free - add it to the free
        !           714:         * regions so that it can be allocated by pmap_steal
        !           715:         */
        !           716:        free_regions[free_regions_count].start = *first_avail;
        !           717:        free_regions[free_regions_count].end = pmap_mem_regions[0].end;
        !           718:        free_regions_count++;
        !           719: }
        !           720: 
        !           721: 
        !           722: 
        !           723: /*
        !           724:  * pmap_init()
        !           725:  *     finishes the initialization of the pmap module.
        !           726:  *     This procedure is called from vm_mem_init() in vm/vm_init.c
        !           727:  *     to initialize any remaining data structures that the pmap module
        !           728:  *     needs to map virtual memory (VM is already ON).
        !           729:  */
        !           730: /*ARGSUSED*/
        !           731: void
        !           732: pmap_init(void)
        !           733: {
        !           734:        vm_size_t s;
        !           735: 
        !           736:        s = sizeof(struct pmap);
        !           737:        pmap_zone = zinit(s, 400*s, 4096, FALSE, "pmap");       /* XXX */
        !           738: 
        !           739:        pmap_initialized = TRUE;
        !           740: }
        !           741: 
        !           742: 
        !           743: /*
        !           744:  * pmap_create
        !           745:  *
        !           746:  * Create and return a physical map.
        !           747:  *
        !           748:  * If the size specified for the map is zero, the map is an actual physical
        !           749:  * map, and may be referenced by the hardware.
        !           750:  *
        !           751:  * If the size specified is non-zero, the map will be used in software 
        !           752:  * only, and is bounded by that size.
        !           753:  */
        !           754: pmap_t
        !           755: pmap_create(
        !           756:        vm_size_t size)
        !           757: {
        !           758:        pmap_t pmap;
        !           759:        spl_t s;
        !           760: 
        !           761: #if DEBUG
        !           762:        if (pmdebug & PDB_USER)
        !           763:                DPRINTF(("(size=%x)%c", size, size ? '\n' : ' '));
        !           764: #endif
        !           765: 
        !           766:        /*
        !           767:         * A software use-only map doesn't even need a pmap structure.
        !           768:         */
        !           769:        if (size)
        !           770:                return(PMAP_NULL);
        !           771: 
        !           772:        /* 
        !           773:         * If there is a pmap in the pmap free list, reuse it. 
        !           774:         */
        !           775:        s = splhigh();
        !           776:        simple_lock(&free_pmap_lock);
        !           777:        if (free_pmap != PMAP_NULL) {
        !           778:                pmap = free_pmap;
        !           779:                free_pmap = pmap->next;
        !           780:        } else
        !           781:                pmap = PMAP_NULL;
        !           782:        simple_unlock(&free_pmap_lock);
        !           783: 
        !           784:        /*
        !           785:         * Couldn't find a pmap on the free list, try to allocate a new one.
        !           786:         */
        !           787:        if (pmap == PMAP_NULL) {
        !           788:                pmap = (pmap_t) zalloc(pmap_zone);
        !           789:                if (pmap == PMAP_NULL)
        !           790:                {
        !           791:                        splx(s);
        !           792:                        return(PMAP_NULL);
        !           793:                }
        !           794: 
        !           795:                /*
        !           796:                 * Allocate space IDs for the pmap.
        !           797:                 * If all are allocated, there is nothing we can do.
        !           798:                 */
        !           799: 
        !           800:                /* If sid_counter == MAX_SID, we've allocated
        !           801:                 * all the possible SIDs and they're all live,
        !           802:                 * we can't carry on, but this is HUGE, so don't
        !           803:                 * expect it in normal operation.
        !           804:                 */
        !           805:                assert(sid_counter != SID_MAX);
        !           806: 
        !           807:                /* Try to spread out the sid's through the possible
        !           808:                 * name space to improve the hashing heuristics
        !           809:                 */
        !           810: #warning Get a better VSID allocation algorithm from the AIX folks.
        !           811: /*             sid_counter = (sid_counter + PPC_SID_PRIME) & PPC_SID_MASK; */
        !           812:                sid_counter ++; /* Replaced by a simpler algorithm */
        !           813: 
        !           814: 
        !           815:                /* 
        !           816:                 * Initialize the sids
        !           817:                 */
        !           818:                pmap->space = sid_counter;
        !           819:                simple_lock_init(&pmap->lock);
        !           820:        }
        !           821:        pmap->ref_count = 1;
        !           822:        pmap->next = PMAP_NULL;
        !           823:        pmap->stats.resident_count = 0;
        !           824:        pmap->stats.wired_count = 0;
        !           825: #if DEBUG
        !           826:        if (pmdebug & PDB_USER)
        !           827:                DPRINTF(("-> %x, space id = %d\n", pmap, pmap->space));
        !           828: #endif
        !           829:        splx(s);
        !           830:        return(pmap);
        !           831: }
        !           832: 
        !           833: 
        !           834: 
        !           835: /* 
        !           836:  * pmap_destroy
        !           837:  * 
        !           838:  * Gives up a reference to the specified pmap.  When the reference count 
        !           839:  * reaches zero the pmap structure is added to the pmap free list.
        !           840:  *
        !           841:  * Should only be called if the map contains no valid mappings.
        !           842:  */
        !           843: void
        !           844: pmap_destroy(
        !           845:        pmap_t pmap)
        !           846: {
        !           847:        int ref_count;
        !           848:        spl_t s;
        !           849: 
        !           850: #if DEBUG
        !           851:        if (pmdebug & PDB_USER)
        !           852:                DPRINTF(("(pmap=%x)\n", pmap));
        !           853: #endif
        !           854: 
        !           855:        if (pmap == PMAP_NULL)
        !           856:                return;
        !           857: 
        !           858:        s = splhigh();
        !           859:        simple_lock(&pmap->lock);
        !           860:        ref_count = --pmap->ref_count;
        !           861:        simple_unlock(&pmap->lock);
        !           862: 
        !           863:        if (ref_count < 0)
        !           864:                panic("pmap_destroy(): ref_count < 0");
        !           865:        if (ref_count > 0)
        !           866:        {
        !           867:                splx(s);
        !           868:                return;
        !           869:        }
        !           870: 
        !           871: #if DEBUG
        !           872:        if (pmap->stats.resident_count != 0 || pmap->stats.wired_count != 0) {
        !           873:                kprintf("pmap_destroy: non_empty pmap\n");
        !           874:        }
        !           875: #endif /* DEBUG */
        !           876: 
        !           877:        /* 
        !           878:         * Add the pmap to the pmap free list. 
        !           879:         */
        !           880:        simple_lock(&free_pmap_lock);
        !           881:        pmap->next = free_pmap;
        !           882:        free_pmap = pmap;
        !           883:        simple_unlock(&free_pmap_lock);
        !           884:        splx(s);
        !           885: }
        !           886: 
        !           887: 
        !           888: 
        !           889: /*
        !           890:  * pmap_reference(pmap)
        !           891:  *
        !           892:  *     gains a reference to the specified pmap.
        !           893:  *
        !           894:  *     This is used to indicate that the pmap is in use by multiple
        !           895:  *     machine-independent maps and will prevent early deallocation
        !           896:  *     of the pmap.
        !           897:  */
        !           898: void
        !           899: pmap_reference(
        !           900:        pmap_t pmap)
        !           901: {
        !           902:        spl_t s;
        !           903: 
        !           904: #if DEBUG
        !           905:        if (pmdebug & PDB_USER)
        !           906:                DPRINTF(("(pmap=%x)\n", pmap));
        !           907: #endif
        !           908: 
        !           909:        if (pmap != PMAP_NULL) {
        !           910:                s = splhigh();
        !           911:                simple_lock(&pmap->lock);
        !           912:                pmap->ref_count++;
        !           913:                simple_unlock(&pmap->lock);
        !           914:                splx(s);
        !           915:        }
        !           916: }
        !           917: 
        !           918: /*
        !           919:  * pmap_remove(pmap, s, e)
        !           920:  *     unmaps all virtual addresses v in the virtual address
        !           921:  *     range determined by [s, e) and pmap.
        !           922:  *     s and e must be on machine independent page boundaries and
        !           923:  *     s must be less than or equal to e.
        !           924:  */
        !           925: void
        !           926: pmap_remove(
        !           927:        pmap_t pmap,
        !           928:        vm_offset_t sva,
        !           929:        vm_offset_t eva)
        !           930: {
        !           931:        space_t space;
        !           932:        struct mapping *mp;
        !           933:        spl_t s;
        !           934: 
        !           935: #if DEBUG
        !           936:        if (pmdebug & PDB_USER)
        !           937:                DPRINTF(("(pmap=%x, sva=%x, eva=%x)\n",
        !           938:                       pmap, sva, eva));
        !           939: #endif
        !           940: 
        !           941:        if (pmap == PMAP_NULL)
        !           942:                return;
        !           943: 
        !           944:        s = splhigh();
        !           945:        space = pmap->space;
        !           946: 
        !           947:        /* It is just possible that eva might have wrapped around to zero,
        !           948:         * and sometimes we get asked to liberate something of size zero
        !           949:         * even though it's dumb (eg. after zero length read_overwrites)
        !           950:         */
        !           951:        assert(eva >= sva);
        !           952: 
        !           953:        /* We liberate addresses from high to low, since the stack grows
        !           954:         * down. This means that we won't need to test addresses below
        !           955:         * the limit of stack growth
        !           956:         */
        !           957:        while ((pmap->stats.resident_count > 0) && (eva > sva)) {
        !           958:                eva -= PAGE_SIZE;
        !           959:                if ((mp = pmap_find_mapping(space, eva)) != MAPPING_NULL) {
        !           960:                        pmap->stats.resident_count--;
        !           961:                        pmap_free_mapping(mp);
        !           962:                }
        !           963:        }
        !           964:        splx(s);
        !           965: }
        !           966: 
        !           967: 
        !           968: 
        !           969: /*
        !           970:  *     Routine:
        !           971:  *             pmap_page_protect
        !           972:  *
        !           973:  *     Function:
        !           974:  *             Lower the permission for all mappings to a given page.
        !           975:  */
        !           976: void
        !           977: pmap_page_protect(
        !           978:        vm_offset_t pa,
        !           979:        vm_prot_t prot)
        !           980: {
        !           981:        register struct phys_entry *pp;
        !           982:        register struct mapping *mp;
        !           983:        register struct mapping *mp2;
        !           984:        unsigned pteprot;
        !           985:        boolean_t remove;
        !           986:        spl_t s;
        !           987: 
        !           988: #if DEBUG
        !           989:        if (pmdebug & PDB_USER)
        !           990:                DPRINTF(("(pa=%x, prot=%x)\n", pa, prot));
        !           991: #endif
        !           992: 
        !           993:        switch (prot) 
        !           994:        {
        !           995:        case VM_PROT_READ:
        !           996:        case VM_PROT_READ|VM_PROT_EXECUTE:
        !           997:                remove = FALSE;
        !           998:                break;
        !           999:        case VM_PROT_ALL:
        !          1000:                return;
        !          1001:        default:
        !          1002:                remove = TRUE;
        !          1003:                break;
        !          1004:        }
        !          1005: 
        !          1006:        pp = pmap_find_physentry(pa);
        !          1007:        if (pp == PHYS_NULL)
        !          1008:                return;
        !          1009: 
        !          1010:        s = splhigh();
        !          1011:        if (remove) 
        !          1012:        {
        !          1013:                mp2 = MAPPING_NULL;
        !          1014:                while (!queue_empty(&pp->phys_link)) 
        !          1015:                {
        !          1016:                        mp = (struct mapping *) queue_first(&pp->phys_link);
        !          1017:                        if (mp->vm_info.bits.phys) 
        !          1018:                        {
        !          1019:                                // Don't zap the phys page
        !          1020:                                mp2 = mp;
        !          1021:                                queue_remove(&pp->phys_link, mp2, struct mapping *, phys_link);
        !          1022:                        } else 
        !          1023:                        {
        !          1024:                                mp->pmap->stats.resident_count--;
        !          1025: #if    DEBUG
        !          1026:                                if (mp->vm_info.bits.wired) 
        !          1027:                                {
        !          1028:                                        DPRINTF((": removing WIRED page!!\n"));
        !          1029:                                }
        !          1030: #endif /* DEBUG */
        !          1031:                                pmap_free_mapping(mp);
        !          1032:                        }
        !          1033:                }
        !          1034: #if    DEBUG
        !          1035:                if (queue_empty(&pp->phys_link) && (mp2 == MAPPING_NULL))
        !          1036:                {
        !          1037:                        DPRINTF(("WHOOPS! removed and entire map\n"));
        !          1038:                }
        !          1039: #endif /* DEBUG */
        !          1040: 
        !          1041:                if (mp2 != MAPPING_NULL) 
        !          1042:                {
        !          1043:                    // Restore the phys page
        !          1044:                    queue_enter_first(&pp->phys_link, mp2, struct mapping *, phys_link);
        !          1045:                }
        !          1046:                splx(s);
        !          1047:                return;
        !          1048:        }
        !          1049:        
        !          1050:        /*
        !          1051:         * Modify mappings if necessary.
        !          1052:         */
        !          1053:        queue_iterate(&pp->phys_link, mp, struct mapping *, phys_link) 
        !          1054:        {
        !          1055:                /*      Compare the new protection bits with the old
        !          1056:                        one to see if anything needs to be changed.
        !          1057:                        Note: In mach 2.5, we must not reduce the 
        !          1058:                        protection status of the static logical mapping
        !          1059:                        (the phys page), but we *do* want to record RC
        !          1060:                        bits.
        !          1061:                */
        !          1062:                if (mp->vm_info.bits.phys) 
        !          1063:                {
        !          1064:                        // Phys page mapping - don't alter protection
        !          1065:                        // Do not merge RC bits into pp.
        !          1066:                        continue;
        !          1067:                }
        !          1068: 
        !          1069:                pteprot = prot_bits[prot];
        !          1070:                if ((mp->pte->pte1.bits.protection) != pteprot)
        !          1071:                {
        !          1072:                        /*
        !          1073:                         * Perform a sync to force saving
        !          1074:                         * of change/reference bits, followed by a
        !          1075:                         * fault and reload with the new protection.
        !          1076:                         */
        !          1077:                        assert(mp->pte->pte0.bits.valid == TRUE);
        !          1078:                        mp->pte->pte0.bits.valid        = FALSE;
        !          1079:                        sync();
        !          1080:                        tlbie(mp->vm_info.bits.page << PPC_PGSHIFT);
        !          1081:                        eieio();
        !          1082:                        tlbsync();
        !          1083:                        sync();
        !          1084: 
        !          1085:                        mp->pte->pte1.bits.protection = pteprot;
        !          1086:                        eieio();
        !          1087: 
        !          1088:                        mp->pte->pte0.bits.valid        = TRUE;
        !          1089:                        sync();
        !          1090:                }
        !          1091:                //pp->pte1.word |= mp->pte->pte1.word;
        !          1092:                pp->pte1.bits.protection |= mp->pte->pte1.bits.protection;
        !          1093:        }
        !          1094:        splx(s);
        !          1095: }
        !          1096: 
        !          1097: 
        !          1098: 
        !          1099: /*
        !          1100:  * pmap_protect(pmap, s, e, prot)
        !          1101:  *     changes the protection on all virtual addresses v in the 
        !          1102:  *     virtual address range determined by [s, e] and pmap to prot.
        !          1103:  *     s and e must be on machine independent page boundaries and
        !          1104:  *     s must be less than or equal to e.
        !          1105:  */
        !          1106: void
        !          1107: pmap_protect(
        !          1108:        pmap_t pmap,
        !          1109:        vm_offset_t sva, 
        !          1110:        vm_offset_t eva,
        !          1111:        vm_prot_t prot)
        !          1112: {
        !          1113:        register struct mapping *mp;
        !          1114:        pte_t  *pte;
        !          1115:        unsigned pteprot;
        !          1116:        space_t space;
        !          1117:        spl_t s;
        !          1118: 
        !          1119: #if DEBUG
        !          1120:        if (pmdebug & PDB_USER)
        !          1121:                DPRINTF(("(pmap=%x, sva=%x, eva=%x, prot=%x)\n",
        !          1122:                       pmap, sva, eva, prot));
        !          1123: #endif
        !          1124: 
        !          1125:        if (pmap == PMAP_NULL)
        !          1126:                return;
        !          1127: 
        !          1128:        assert(sva <= eva);
        !          1129: 
        !          1130:        if (prot == VM_PROT_NONE) {
        !          1131:                pmap_remove(pmap, sva, eva);
        !          1132:                return;
        !          1133:        }
        !          1134: #if MACH_30
        !          1135:        if (prot & VM_PROT_WRITE)
        !          1136:                return;
        !          1137: #endif
        !          1138: 
        !          1139:        s = splhigh();
        !          1140:        space = pmap->space;
        !          1141:        for ( ; sva < eva; sva += PAGE_SIZE) {
        !          1142:                mp = pmap_find_mapping(space, sva);
        !          1143:                if (mp == MAPPING_NULL)
        !          1144:                        continue;
        !          1145: #if DEBUG
        !          1146:                if (pmap != mp->pmap)
        !          1147:                        panic("protect: pmap mismatch");
        !          1148: #endif
        !          1149:                /*
        !          1150:                 * Determine if mapping is changing.
        !          1151:                 * If not, nothing to do.
        !          1152:                 */
        !          1153:                pte     = mp->pte;
        !          1154:                pteprot = prot_bits[prot];
        !          1155:                if (pte->pte1.bits.protection == pteprot)
        !          1156:                        continue;
        !          1157:                
        !          1158:                /*
        !          1159:                 * Purge the current TLB entry (if any) to force
        !          1160:                 * any modifications to changed/referenced bits, and so
        !          1161:                 * that future references will fault and reload with the
        !          1162:                 * new protection.
        !          1163:                 */
        !          1164: 
        !          1165:                /*      Perform a general case PTE update designed to work
        !          1166:                        in SMP configurations. TODO - locks
        !          1167:                */
        !          1168:                assert(pte->pte0.bits.valid == TRUE);
        !          1169:                pte->pte0.bits.valid = FALSE;   /* Invalidate pte entry */
        !          1170:                sync();                         /* Force updates to complete */
        !          1171:                tlbie(sva);
        !          1172:                eieio();
        !          1173:                tlbsync();
        !          1174:                sync();
        !          1175: 
        !          1176:                /*      Allowable early PTE updates: RPN,R,C,WIMG,PP
        !          1177:                */
        !          1178:                pte->pte1.bits.protection = pteprot;    /* Change just the protection */
        !          1179:                eieio();
        !          1180: 
        !          1181:                /*      Post tlbie updates: VSID,H,API,V
        !          1182:                */
        !          1183:                pte->pte0.bits.valid = TRUE;    /* Validate pte entry */
        !          1184:                sync();
        !          1185: 
        !          1186:        }
        !          1187:        splx(s);
        !          1188: }
        !          1189: 
        !          1190: 
        !          1191: 
        !          1192: void
        !          1193: pmap_enter_phys_page(
        !          1194:        vm_offset_t pa,
        !          1195:        vm_offset_t va)
        !          1196: {
        !          1197:     struct mapping *mp;
        !          1198: 
        !          1199:     pmap_enter(kernel_pmap, va, pa, VM_PROT_READ|VM_PROT_WRITE, TRUE);
        !          1200: 
        !          1201:     if (mp = pmap_find_mapping(kernel_pmap->space, va)) {
        !          1202:        mp->vm_info.bits.phys = TRUE;
        !          1203:     }
        !          1204: #if    DEBUG
        !          1205:     else
        !          1206:     {
        !          1207:        DPRINTF(("pmap_enter_phys_page: mp == NULL\n"));
        !          1208:        DPRINTF(("pmap_enter_phys_page: mp == NULL\n"));
        !          1209:        panic("pmap_enter_phys_page: can't find mapping entry");
        !          1210:     }
        !          1211: #endif /* DEBUG */
        !          1212: }
        !          1213: 
        !          1214: 
        !          1215: 
        !          1216: int pmap_enter_cnt = 0;
        !          1217: int pmap_enter_valid_cnt = 0;
        !          1218: int pmap_enter_invalid_cnt = 0;
        !          1219: /*
        !          1220:  * pmap_enter
        !          1221:  *
        !          1222:  * Create a translation for the virtual address (virt) to the physical
        !          1223:  * address (phys) in the pmap with the protection requested. If the
        !          1224:  * translation is wired then we can not allow a page fault to occur
        !          1225:  * for this mapping.
        !          1226:  *
        !          1227:  * NB: This is the only routine which MAY NOT lazy-evaluate
        !          1228:  *     or lose information.  That is, this routine must actually
        !          1229:  *     insert this page into the given map NOW.
        !          1230:  */
        !          1231: void
        !          1232: pmap_enter(
        !          1233:        pmap_t pmap,
        !          1234:        vm_offset_t va,
        !          1235:        vm_offset_t pa,
        !          1236:        vm_prot_t prot,
        !          1237:        boolean_t wired)
        !          1238: {
        !          1239:        register struct mapping *mp;
        !          1240:        struct phys_entry *pp,*old_pp;
        !          1241:        pte_t *pte;
        !          1242:        space_t space;
        !          1243:        boolean_t was_wired;
        !          1244:        spl_t s;
        !          1245: 
        !          1246: #if DEBUG
        !          1247:        if ((wired && (pmdebug & (PDB_WIRED))) ||
        !          1248:             ((pmdebug & (PDB_USER|PDB_ENTER)) == (PDB_USER | PDB_ENTER)))
        !          1249:                DPRINTF(("(pmap=%x, va=%x, pa=%x, prot=%x, wire=%x)\n", pmap, va, pa, prot, wired));
        !          1250:        pmap_enter_cnt++;
        !          1251: #endif
        !          1252:         if (pmap == PMAP_NULL)
        !          1253:                 return;
        !          1254: #if DEBUG
        !          1255:        if (prot == VM_PROT_NONE) {
        !          1256:                pmap_remove(pmap, va, va + PAGE_SIZE);
        !          1257:                return;
        !          1258:        }
        !          1259: #endif /* DEBUG */
        !          1260: 
        !          1261:        /* TODO NMGS - take lock on physentry? */
        !          1262:        pp = pmap_find_physentry(pa);
        !          1263:        if (pp == PHYS_NULL)
        !          1264:                return;
        !          1265: 
        !          1266:        /* Find the pte associated with the virtual address/space ID */
        !          1267:        space = pmap->space;
        !          1268: 
        !          1269:        /* TODO NMGS - take lock on pte?! */
        !          1270:        pte = find_or_allocate_pte(space,va,TRUE);
        !          1271: 
        !          1272:        assert(pte != PTE_NULL);
        !          1273:        /* Even if the pte is new, pte0 should be set up for the new mapping,
        !          1274:         * but with the valid bit set to FALSE
        !          1275:         */
        !          1276:        assert((pte->pte0.word & 0x7fffffff) != PTE_EMPTY);
        !          1277: 
        !          1278:        s = splhigh();
        !          1279:        if (pte->pte0.bits.valid == TRUE) {
        !          1280: 
        !          1281:                /* mapping is already valid, thus virtual address was
        !          1282:                 * already mapped somewhere...
        !          1283:                 */
        !          1284: 
        !          1285: #if    DEBUG
        !          1286:                pmap_enter_valid_cnt++;
        !          1287: #endif /* DEBUG */
        !          1288:                /*
        !          1289:                **  invalidate tlb for previous mapping 
        !          1290:                */
        !          1291:                pte->pte0.bits.valid = FALSE;/* Invalidate pte entry */
        !          1292:                sync();         /* Force updates to complete */
        !          1293:                tlbie(va);      /* Wipe out this virtual address */
        !          1294:                eieio();        /* Enforce ordering of v bit */
        !          1295:                tlbsync();
        !          1296:                sync();
        !          1297: 
        !          1298:                if (((physical_addr_t *) &pa)->bits.page_no !=
        !          1299:                    pte->pte1.bits.phys_page) {
        !          1300: 
        !          1301:                        /* The current mapping is to a different
        !          1302:                         * physical addr - release the mapping
        !          1303:                         * before mapping the new address. 
        !          1304:                         */
        !          1305: 
        !          1306: #if DEBUG
        !          1307:                        if ((pmdebug & (PDB_USER|PDB_ENTER)) == (PDB_USER|PDB_ENTER))
        !          1308:                                DPRINTF(("Virt 0x%08x was mapped to different address 0x%08x, changing mapping\n",va,((physical_addr_t *) &pa)->bits.page_no * PPC_PGBYTES));
        !          1309: #endif
        !          1310: 
        !          1311:                        /* Take advantage of the fact that pte1 can be
        !          1312:                         * considered as a pointer to an address in
        !          1313:                         * the physical page when looking for physentry.
        !          1314:                         */
        !          1315: 
        !          1316:                        old_pp = pmap_find_physentry(
        !          1317:                                             (vm_offset_t)(pte->pte1.word));
        !          1318: 
        !          1319:                        queue_iterate(&old_pp->phys_link, mp,
        !          1320:                                      struct mapping *, phys_link) {
        !          1321:                                if (mp->pte == pte)
        !          1322:                                        break;
        !          1323:                        }
        !          1324: 
        !          1325:                        /* pte entry must have good reverse mapping */
        !          1326:                        assert(mp != NULL);
        !          1327:                        assert(mp->pte == pte);
        !          1328:                        assert(((mp->vm_info.bits.page >> 10) & 0x3f) ==
        !          1329:                               mp->pte->pte0.bits.page_index);
        !          1330: 
        !          1331:                        /* Wired/not wired is taken care of later on
        !          1332:                         * in this function. We can remove wired mappings.
        !          1333:                         */
        !          1334: 
        !          1335:                        /* Do the equivalent of pmap_free_mapping followed
        !          1336:                         * by a pmap_enter_mapping, recycling the pte and
        !          1337:                         * the mapping
        !          1338:                         */
        !          1339: 
        !          1340:                        /* keep track of changed and referenced at old
        !          1341:                         * address
        !          1342:                         */
        !          1343:                        old_pp->pte1.word |= mp->pte->pte1.word;
        !          1344: 
        !          1345:                        queue_remove(&old_pp->phys_link, mp,
        !          1346:                                     struct mapping *, phys_link);
        !          1347: 
        !          1348:                        mp->vm_info.bits.page  = (va >> PPC_PGSHIFT);
        !          1349: 
        !          1350:                        assert(mp->pte == pte);
        !          1351: 
        !          1352:                        queue_enter_first(&pp->phys_link, mp,
        !          1353:                                          struct mapping *, phys_link);
        !          1354: 
        !          1355: 
        !          1356:                        assert(mp->pmap == pmap);
        !          1357: 
        !          1358:                        /* Set up pte as it would have been done by
        !          1359:                         * find_or_allocate_pte() + pmap_enter_mapping()
        !          1360:                         */
        !          1361: 
        !          1362:                        /*      Allowable early PTE updates: RPN,R,C,WIMG,PP
        !          1363:                        */
        !          1364:                        pte->pte1.word = 0;
        !          1365:                        pte->pte1.bits.phys_page  = pa >> PPC_PGSHIFT;
        !          1366:                        pte->pte1.bits.wimg       = pp->pte1.bits.wimg; /* default */
        !          1367: 
        !          1368:        
        !          1369:                        /*      Post tlbie updates: VSID,H,API,V
        !          1370:                        */
        !          1371:                        pte->pte0.bits.segment_id = (space << 4) | (va >> 28);
        !          1372:                        pte->pte0.bits.page_index = ((va_abbrev_t *)&va)->page_index;
        !          1373:                        eieio();
        !          1374: 
        !          1375: 
        !          1376:                } else {
        !          1377:                        /* The current mapping is the same as the one
        !          1378:                         * we're being asked to make, find the mapping
        !          1379:                         * structure that goes along with it.
        !          1380:                         */
        !          1381:                        queue_iterate(&pp->phys_link, mp,
        !          1382:                                      struct mapping *, phys_link) {
        !          1383:                                if (mp->pte == pte)
        !          1384:                                        break;
        !          1385:                        }
        !          1386:                        /* mapping struct must exist */
        !          1387:                        assert(mp != NULL);
        !          1388:                        assert(mp->pte == pte);
        !          1389: 
        !          1390: 
        !          1391: #if DEBUG
        !          1392: 
        !          1393: 
        !          1394:                        if ((wired && (pmdebug & (PDB_WIRED))) ||
        !          1395:                            ((pmdebug & (PDB_USER|PDB_ENTER)) == (PDB_USER|PDB_ENTER))) {
        !          1396:                                DPRINTF(("address already mapped, changing prots or wiring\n"));
        !          1397:                                if (pte->pte1.bits.protection !=
        !          1398:                                    prot_bits[prot])
        !          1399:                                        DPRINTF(("Changing PROTS\n"));
        !          1400:                                if (wired != mp->vm_info.bits.wired)
        !          1401:                                       DPRINTF(("changing WIRING\n"));
        !          1402:                        }
        !          1403: #endif
        !          1404:                }
        !          1405:        } else {
        !          1406: 
        !          1407: #if DEBUG
        !          1408:                pmap_enter_invalid_cnt++;
        !          1409: #endif /* DEBUG */
        !          1410: 
        !          1411:                /* There was no pte match, a new entry was created
        !          1412:                  * (marked as invalid). We make sure that a new mapping
        !          1413:                 * structure is allocated as it's partner.
        !          1414:                 */
        !          1415:                mp = MAPPING_NULL;
        !          1416:                assert(pte->pte0.word != PTE_EMPTY);
        !          1417:                sync();         /* Force updates to complete */
        !          1418:                tlbie(va);      /* Wipe out this virtual address */
        !          1419:                eieio();        /* Enforce ordering of v bit */
        !          1420:                tlbsync();
        !          1421:                sync();
        !          1422: 
        !          1423:                pte->pte1.bits.protection = prot_bits[prot];
        !          1424:                eieio();
        !          1425:        }
        !          1426: 
        !          1427:        /* Once here, pte contains a valid pointer to a structure
        !          1428:         * that we may use to map the virtual address (which may
        !          1429:         * already map this (and be valid) or something else (invalid)
        !          1430:         * and mp contains either MAPPING_NULL (new mapping) or
        !          1431:         * a pointer to the old mapping which may need it's
        !          1432:         * privileges modified.
        !          1433:         */
        !          1434: 
        !          1435:        /* set up the protection bits on new mapping
        !          1436:         */
        !          1437: 
        !          1438: 
        !          1439:        if (mp == MAPPING_NULL) {
        !          1440:                /*
        !          1441:                 * Mapping for this virtual address doesn't exist.
        !          1442:                 * Get a mapping structure and, and fill it in,
        !          1443:                 * updating the pte that we already have, and
        !          1444:                 * making it valid
        !          1445:                 */
        !          1446:                mp = pmap_enter_mapping(pmap, space, va, pa, pte, prot, pp);
        !          1447:                pmap->stats.resident_count++;
        !          1448:                was_wired = FALSE;/* indicate that page was never wired */
        !          1449:        } else {
        !          1450:                
        !          1451:                /*
        !          1452:                 * We are just changing the protection of a current mapping.
        !          1453:                 */
        !          1454:                was_wired = mp->vm_info.bits.wired;
        !          1455: 
        !          1456:                /*
        !          1457:                 * This is the pte that came in valid
        !          1458:                 */
        !          1459:                pte->pte1.bits.protection = prot_bits[prot];
        !          1460:                eieio();
        !          1461:                pte->pte0.bits.valid = TRUE;            /* !!! */
        !          1462:                sync();
        !          1463:        }
        !          1464: 
        !          1465:        assert(pte->pte0.bits.valid == TRUE);
        !          1466: 
        !          1467:        /* if wired status has changed, update stats and change bit */
        !          1468:        if (was_wired != wired) {
        !          1469:                pmap->stats.wired_count += wired ? 1 : -1;
        !          1470:                mp->vm_info.bits.wired = wired;
        !          1471: #if DEBUG
        !          1472:                if (pmdebug & (PDB_WIRED))
        !          1473:                        DPRINTF(("changing wired status to : %s\n",
        !          1474:                               wired ? "TRUE" : "FALSE"));
        !          1475: #endif /* DEBUG */
        !          1476:        }
        !          1477: 
        !          1478: 
        !          1479:        /* Belt and braces check to make sure we didn't give a bogus map,
        !          1480:         * this map is given once when mapping the kernel
        !          1481:         */
        !          1482:        assert((pte->pte1.bits.phys_page != 0) ||
        !          1483:               (kgdb_kernel_in_pmap == FALSE));
        !          1484:        
        !          1485: #if DEBUG
        !          1486: 
        !          1487:        /*      Assert a PTE of type WIMG_IO is not mapped to general RAM.
        !          1488:        */
        !          1489:        if (pmdebug & PDB_IO    &&
        !          1490:            pte->pte1.bits.wimg == PTE_WIMG_IO)
        !          1491:                assert (((unsigned) pa) >= PCI_BASE)
        !          1492: 
        !          1493:        /* Assert that there are no other mappings with different
        !          1494:         * cachability information, as this can freeze the machine
        !          1495:         */
        !          1496:        {
        !          1497:                struct mapping *mp2;
        !          1498:                queue_iterate(&pp->phys_link, mp2,
        !          1499:                              struct mapping *, phys_link) {
        !          1500:                        assert(mp2->pte->pte1.bits.wimg ==
        !          1501:                               pte->pte1.bits.wimg);
        !          1502:                }
        !          1503:        }
        !          1504: 
        !          1505:        if (pmdebug & PDB_MASSIVE) {
        !          1506:                register struct mapping *mp2;
        !          1507:                queue_iterate(&free_mapping, mp2,
        !          1508:                              struct mapping *, phys_link) {
        !          1509:                        assert(mp2->phys_link.next != NULL);
        !          1510:                }
        !          1511:        }
        !          1512: #endif /* DEBUG */     
        !          1513:        splx(s);
        !          1514: #if DEBUG
        !          1515:        if ((pmdebug & (PDB_USER|PDB_ENTER)) == (PDB_USER | PDB_ENTER))
        !          1516:                DPRINTF(("leaving pmap_enter\n"));
        !          1517: #endif
        !          1518: }
        !          1519: 
        !          1520: 
        !          1521: 
        !          1522: /*
        !          1523:  *     Routine:        pmap_change_wiring
        !          1524:  *     Function:       Change the wiring attribute for a map/virtual-address
        !          1525:  *                     pair.
        !          1526:  *     In/out conditions:
        !          1527:  *                     The mapping must already exist in the pmap.
        !          1528:  *
        !          1529:  * Change the wiring for a given virtual page. This routine currently is 
        !          1530:  * only used to unwire pages and hence the mapping entry will exist.
        !          1531:  */
        !          1532: void
        !          1533: pmap_change_wiring(
        !          1534:        register pmap_t pmap,
        !          1535:        vm_offset_t     va,
        !          1536:        boolean_t       wired)
        !          1537: {
        !          1538:        register struct mapping *mp;
        !          1539:        boolean_t waswired;
        !          1540:        spl_t s;
        !          1541: 
        !          1542: #if DEBUG
        !          1543:        if ((pmdebug & (PDB_USER | PDB_WIRED)) == (PDB_USER|PDB_WIRED))
        !          1544:                DPRINTF(("(pmap=%x, va=%x, wire=%x)\n",
        !          1545:                       pmap, va, wired));
        !          1546: #endif
        !          1547:        if (pmap == PMAP_NULL)
        !          1548:                return;
        !          1549: 
        !          1550:        s = splhigh();
        !          1551:        if ((mp = pmap_find_mapping(pmap->space, va)) == MAPPING_NULL)
        !          1552:                panic("pmap_change_wiring: can't find mapping entry");
        !          1553: 
        !          1554:        waswired = mp->vm_info.bits.wired;
        !          1555:        if (wired && !waswired) {
        !          1556:                mp->vm_info.bits.wired = TRUE;
        !          1557:                pmap->stats.wired_count++;
        !          1558:        } else if (!wired && waswired) {
        !          1559:                mp->vm_info.bits.wired = FALSE;
        !          1560:                pmap->stats.wired_count--;
        !          1561:        }
        !          1562:        splx(s);
        !          1563: }
        !          1564: 
        !          1565: 
        !          1566: 
        !          1567: /*
        !          1568:  * pmap_extract(pmap, va)
        !          1569:  *     returns the physical address corrsponding to the 
        !          1570:  *     virtual address specified by pmap and va if the
        !          1571:  *     virtual address is mapped and 0 if it is not.
        !          1572:  */
        !          1573: vm_offset_t
        !          1574: pmap_extract(
        !          1575:        pmap_t pmap,
        !          1576:        vm_offset_t va)
        !          1577: {
        !          1578:        pte_t *pte;
        !          1579:        spl_t s;
        !          1580: 
        !          1581: #if DEBUG
        !          1582:        if (pmdebug & PDB_USER)
        !          1583:                DPRINTF(("(pmap=%x, va=%x)\n", pmap, va));
        !          1584: #endif
        !          1585: 
        !          1586:        if (pmap == PMAP_NULL)
        !          1587:        {
        !          1588:                DPRINTF((": pmap == PMAP_NULL\n"));
        !          1589:                return 0;
        !          1590:        }
        !          1591: 
        !          1592:        if (pmap == kernel_pmap) {
        !          1593:            extern vm_offset_t virtual_avail;
        !          1594: 
        !          1595:            if (va < virtual_avail)
        !          1596:                return va;
        !          1597:        }
        !          1598: 
        !          1599:        s = splhigh();
        !          1600:        pte = find_or_allocate_pte(pmap->space, trunc_page(va), FALSE);
        !          1601:        if (pte == NULL)
        !          1602:        {
        !          1603:                splx(s);
        !          1604:                return(0);
        !          1605:        }
        !          1606:        splx(s);
        !          1607:        return trunc_page(pte->pte1.word) | (va & page_mask);
        !          1608: }
        !          1609: 
        !          1610: 
        !          1611: 
        !          1612: /*
        !          1613:  *     pmap_attributes:
        !          1614:  *
        !          1615:  *     Set/Get special memory attributes
        !          1616:  *
        !          1617:  */
        !          1618: kern_return_t
        !          1619: pmap_attribute(
        !          1620:        pmap_t          pmap,
        !          1621:        vm_offset_t     address,
        !          1622:        vm_size_t       size,
        !          1623:        vm_machine_attribute_t  attribute,
        !          1624:        vm_machine_attribute_val_t* value)      
        !          1625: {
        !          1626:        vm_offset_t     sva, eva;
        !          1627:        vm_offset_t     addr;
        !          1628:        kern_return_t   ret;
        !          1629: 
        !          1630:        if (attribute != MATTR_CACHE)
        !          1631:                return KERN_INVALID_ARGUMENT;
        !          1632: 
        !          1633:        /* We can't get the caching attribute for more than one page
        !          1634:         * at a time
        !          1635:         */
        !          1636:        if ((*value == MATTR_VAL_GET) &&
        !          1637:            (trunc_page(address) != trunc_page(address+size-1)))
        !          1638:                return KERN_INVALID_ARGUMENT;
        !          1639: 
        !          1640:        if (pmap == PMAP_NULL)
        !          1641:                return KERN_SUCCESS;
        !          1642: 
        !          1643:        sva = trunc_page(address);
        !          1644:        eva = round_page(address + size);
        !          1645:        ret = KERN_SUCCESS;
        !          1646: 
        !          1647:        simple_lock(&pmap->lock);
        !          1648: 
        !          1649:        switch (*value) {
        !          1650:        case MATTR_VAL_CACHE_FLUSH:     /* flush from all caches */
        !          1651:        case MATTR_VAL_DCACHE_FLUSH:    /* flush from data cache(s) */
        !          1652:        case MATTR_VAL_ICACHE_FLUSH:    /* flush from instr cache(s) */
        !          1653:                sva = trunc_page(sva);
        !          1654:                for (; sva < eva; sva += PAGE_SIZE) {
        !          1655:                        if ((addr = pmap_extract(pmap, sva)) == 0)
        !          1656:                                continue;
        !          1657:                        flush_cache(addr, PAGE_SIZE);
        !          1658:                }
        !          1659:                break;
        !          1660: 
        !          1661:        case MATTR_VAL_GET:             /* return current value */
        !          1662:        case MATTR_VAL_OFF:             /* turn attribute off */
        !          1663:        case MATTR_VAL_ON:              /* turn attribute on */
        !          1664:        default:
        !          1665:                ret = KERN_INVALID_ARGUMENT;
        !          1666:                break;
        !          1667:        }
        !          1668:        simple_unlock(&pmap->lock);
        !          1669: 
        !          1670:        return ret;
        !          1671: }
        !          1672: 
        !          1673: 
        !          1674: 
        !          1675: /*
        !          1676:  * pmap_collect
        !          1677:  * 
        !          1678:  * Garbage collects the physical map system for pages that are no longer used.
        !          1679:  */
        !          1680: /* ARGSUSED */
        !          1681: void
        !          1682: pmap_collect(
        !          1683:        pmap_t pmap)
        !          1684: {
        !          1685: #if DEBUG
        !          1686:        if (pmdebug & PDB_USER)
        !          1687:                DPRINTF(("(pmap=%x)\n", pmap));
        !          1688: #endif
        !          1689: }
        !          1690: 
        !          1691: 
        !          1692: 
        !          1693: /*
        !          1694:  *     Routine:        pmap_activate
        !          1695:  *     Function:
        !          1696:  *             Binds the given physical map to the given
        !          1697:  *             processor, and returns a hardware map description.
        !          1698:  */
        !          1699: /* ARGSUSED */
        !          1700: void
        !          1701: pmap_activate(
        !          1702:        pmap_t pmap,
        !          1703:        thread_t th,
        !          1704:        int which_cpu)
        !          1705: {
        !          1706: #if DEBUG
        !          1707:        if (pmdebug & PDB_USER)
        !          1708:                DPRINTF(("(pmap=%x, th=%x, cpu=%x)\n",
        !          1709:                       pmap, th, which_cpu));
        !          1710: #endif
        !          1711: }
        !          1712: 
        !          1713: 
        !          1714: 
        !          1715: /* ARGSUSED */
        !          1716: void
        !          1717: pmap_deactivate(
        !          1718:        pmap_t pmap,
        !          1719:        thread_t th,
        !          1720:        int which_cpu)
        !          1721: {
        !          1722: #if DEBUG
        !          1723:        if (pmdebug & PDB_USER)
        !          1724:                DPRINTF(("(pmap=%x, th=%x, cpu=%x)\n",
        !          1725:                       pmap, th, which_cpu));
        !          1726: #endif
        !          1727: }
        !          1728: 
        !          1729: 
        !          1730: 
        !          1731: #if DEBUG
        !          1732: 
        !          1733: /*
        !          1734:  * pmap_zero_page
        !          1735:  * pmap_copy_page
        !          1736:  * 
        !          1737:  * are implemented in movc.s, these
        !          1738:  * are just wrappers to help debugging
        !          1739:  */
        !          1740: 
        !          1741: extern void pmap_zero_page_assembler(vm_offset_t p);
        !          1742: extern void pmap_copy_page_assembler(vm_offset_t src, vm_offset_t dst);
        !          1743: 
        !          1744: 
        !          1745: 
        !          1746: /*
        !          1747:  * pmap_zero_page(pa)
        !          1748:  *
        !          1749:  * pmap_zero_page zeros the specified (machine independent) page pa.
        !          1750:  */
        !          1751: void
        !          1752: pmap_zero_page(
        !          1753:        vm_offset_t p)
        !          1754: {
        !          1755: 
        !          1756:        if ((pmdebug & (PDB_USER|PDB_ZERO)) == (PDB_USER|PDB_ZERO))
        !          1757:                DPRINTF(("(pa=%x)\n", p));
        !          1758: 
        !          1759:        /*
        !          1760:         * XXX can these happen?
        !          1761:         */
        !          1762:        if (pmap_find_physentry(p) == PHYS_NULL)
        !          1763:                panic("zero_page: physaddr out of range");
        !          1764: 
        !          1765:        /* TODO NMGS optimisation - if page has no mappings, set bit in
        !          1766:         * physentry to indicate 'needs zeroing', then zero page in
        !          1767:         * pmap_enter or pmap_copy_page if bit is set. This keeps the
        !          1768:         * cache 'hot'.
        !          1769:         */
        !          1770: 
        !          1771:        assert((p & 0xFFF) == 0);
        !          1772:        pmap_zero_page_assembler(p);
        !          1773: }
        !          1774: 
        !          1775: 
        !          1776: 
        !          1777: /*
        !          1778:  * pmap_copy_page(src, dst)
        !          1779:  *
        !          1780:  * pmap_copy_page copies the specified (machine independent)
        !          1781:  * page from physical address src to physical address dst.
        !          1782:  *
        !          1783:  * We need to invalidate the cache for address dst before
        !          1784:  * we do the copy. Apparently there won't be any mappings
        !          1785:  * to the dst address normally.
        !          1786:  */
        !          1787: void
        !          1788: pmap_copy_page(
        !          1789:        vm_offset_t src,
        !          1790:        vm_offset_t dst)
        !          1791: {
        !          1792: 
        !          1793:        if ((pmdebug & (PDB_USER|PDB_COPY)) == (PDB_USER|PDB_COPY))
        !          1794:                DPRINTF(("(spa=%x, dpa=%x)\n", src, dst));
        !          1795:        if (pmdebug & PDB_COPY)
        !          1796:                DPRINTF((": phys_copy(%x, %x, %x)\n",
        !          1797:                       src, dst, PAGE_SIZE));
        !          1798: 
        !          1799:        assert((src & 0xFFF) == 0);
        !          1800:        assert((dst & 0xFFF) == 0);
        !          1801:        pmap_copy_page_assembler(src, dst);
        !          1802: }
        !          1803: #endif /* DEBUG */
        !          1804: 
        !          1805: 
        !          1806: 
        !          1807: /*
        !          1808:  * pmap_pageable(pmap, s, e, pageable)
        !          1809:  *     Make the specified pages (by pmap, offset)
        !          1810:  *     pageable (or not) as requested.
        !          1811:  *
        !          1812:  *     A page which is not pageable may not take
        !          1813:  *     a fault; therefore, its page table entry
        !          1814:  *     must remain valid for the duration.
        !          1815:  *
        !          1816:  *     This routine is merely advisory; pmap_enter()
        !          1817:  *     will specify that these pages are to be wired
        !          1818:  *     down (or not) as appropriate.
        !          1819:  *
        !          1820:  *     (called from vm/vm_fault.c).
        !          1821:  */
        !          1822: /* ARGSUSED */
        !          1823: void
        !          1824: pmap_pageable(
        !          1825:        pmap_t          pmap,
        !          1826:        vm_offset_t     start,
        !          1827:        vm_offset_t     end,
        !          1828:        boolean_t       pageable)
        !          1829: {
        !          1830: #if DEBUG
        !          1831:        if ((pmdebug & (PDB_USER | PDB_WIRED)) == (PDB_USER|PDB_WIRED))
        !          1832:                DPRINTF(("(pmap=%x, sva=%x, eva=%x, pageable=%s)\n",
        !          1833:                       pmap, start, end, pageable ? "TRUE" : "FALSE"));
        !          1834: #endif
        !          1835: }
        !          1836: 
        !          1837: 
        !          1838: 
        !          1839: /*
        !          1840:  * pmap_clear_modify(phys)
        !          1841:  *     clears the hardware modified ("dirty") bit for one
        !          1842:  *     machine independant page starting at the given
        !          1843:  *     physical address.  phys must be aligned on a machine
        !          1844:  *     independant page boundary.
        !          1845:  */
        !          1846: void
        !          1847: pmap_clear_modify(
        !          1848:        vm_offset_t pa)
        !          1849: {
        !          1850:        register struct phys_entry *pp;
        !          1851:        register struct mapping *mp;
        !          1852:        pte_t   *pte;
        !          1853:        register vm_offset_t offset;
        !          1854:        spl_t s;
        !          1855:        boolean_t was_valid;
        !          1856: 
        !          1857: #if DEBUG
        !          1858:        if (pmdebug & PDB_USER)
        !          1859:                DPRINTF(("(pa=%x)\n", pa));
        !          1860: #endif
        !          1861: 
        !          1862:        pp = pmap_find_physentry(pa);
        !          1863:        if (pp == PHYS_NULL)
        !          1864:                return;
        !          1865: 
        !          1866:        s = splhigh();
        !          1867:        /*
        !          1868:         * invalidate any pte entries and remove them from tlb
        !          1869:         * TODO might it be faster to wipe all tlb entries outside loop? NO, rav.
        !          1870:         */
        !          1871: 
        !          1872:        /* Remove any reference to modified to the physical page */
        !          1873:        pp->pte1.bits.changed = FALSE;
        !          1874: 
        !          1875:        /* mark PTE entries as having no modifies, and flush tlbs */
        !          1876:        queue_iterate(&pp->phys_link, mp,
        !          1877:                      struct mapping *, phys_link) {
        !          1878:                pte     = mp->pte;
        !          1879:                offset  = mp->vm_info.bits.page << PPC_PGSHIFT;
        !          1880: 
        !          1881:                was_valid = FALSE;
        !          1882:                if (pte->pte0.bits.valid == TRUE)       {
        !          1883:                        /* Perform a general case PTE update designed to work
        !          1884:                        ** in SMP configurations. TODO - locks and tlbsync
        !          1885:                        */
        !          1886:                        pte->pte0.bits.valid = FALSE;   /* Invalidate PTE */
        !          1887:                        was_valid = TRUE;
        !          1888:                }
        !          1889:                sync();         /* Force updates to complete */
        !          1890:                tlbie(offset);  /* Wipe out this virtual address */
        !          1891:                eieio();        /* Enforce ordering of v bit */
        !          1892:                tlbsync();
        !          1893:                sync();
        !          1894:        
        !          1895:                /*      Allowable early PTE updates: RPN,R,C,WIMG,PP
        !          1896:                */
        !          1897:                pte->pte1.bits.changed = FALSE;
        !          1898:                eieio();
        !          1899: 
        !          1900:                /*      Post tlbie updates: VSID,H,API,V
        !          1901:                */
        !          1902:                if (was_valid == TRUE)
        !          1903:                {
        !          1904:                        pte->pte0.bits.valid = TRUE;    /* Validate pte entry */
        !          1905:                }
        !          1906:                sync();
        !          1907:        }
        !          1908: 
        !          1909: #if    DEBUG
        !          1910:        /* Assert that there are no other mappings with different
        !          1911:         * cachability information, as this can freeze the machine
        !          1912:         */
        !          1913:        {
        !          1914:                struct mapping *mp2;
        !          1915:                queue_iterate(&pp->phys_link, mp2,
        !          1916:                              struct mapping *, phys_link) {
        !          1917:                        assert(mp2->pte->pte1.bits.wimg ==
        !          1918:                               pte->pte1.bits.wimg);
        !          1919:                }
        !          1920:        }
        !          1921: #endif /* DEBUG */
        !          1922: 
        !          1923:        splx(s);
        !          1924: }
        !          1925: 
        !          1926: 
        !          1927: 
        !          1928: /*
        !          1929:  * pmap_is_modified(phys)
        !          1930:  *     returns TRUE if the given physical page has been modified 
        !          1931:  *     since the last call to pmap_clear_modify().
        !          1932:  */
        !          1933: boolean_t
        !          1934: pmap_is_modified(
        !          1935:        vm_offset_t pa)
        !          1936: {
        !          1937:        struct phys_entry *pp;
        !          1938:        struct mapping *mp;
        !          1939:        spl_t s;
        !          1940: 
        !          1941: #if DEBUG
        !          1942:        if (pmdebug & PDB_USER)
        !          1943:                DPRINTF(("(pa=%x)\n", pa));
        !          1944: #endif
        !          1945:        pp = pmap_find_physentry(pa);
        !          1946:        if (pp == PHYS_NULL)
        !          1947:                return(FALSE);
        !          1948: 
        !          1949:        /* Check to see if we've already noted this as modified */
        !          1950:        if (pp->pte1.bits.changed)
        !          1951:                return(TRUE);
        !          1952: 
        !          1953:        s = splhigh();
        !          1954:        /*      Make sure all TLB -> PTE updates have completed.
        !          1955:        */
        !          1956:        sync();
        !          1957: 
        !          1958:        queue_iterate(&pp->phys_link, mp,
        !          1959:                      struct mapping *, phys_link) {
        !          1960: 
        !          1961:                /*      Find the first changed page mapping but
        !          1962:                        do not include the phys page mapping.
        !          1963:                */
        !          1964:                if (!mp->vm_info.bits.phys      && 
        !          1965:                     mp->pte->pte1.bits.changed) 
        !          1966:                {
        !          1967:                        pp->pte1.bits.changed = TRUE;
        !          1968:                        splx(s);
        !          1969:                        return TRUE;
        !          1970:                }
        !          1971:        }
        !          1972:        
        !          1973:        splx(s);
        !          1974:        return(FALSE);
        !          1975: }
        !          1976: 
        !          1977: 
        !          1978: 
        !          1979: /*
        !          1980:  * pmap_clear_reference(phys)
        !          1981:  *     clears the hardware referenced bit in the given machine
        !          1982:  *     independant physical page.  
        !          1983:  *
        !          1984:  */
        !          1985: void
        !          1986: pmap_clear_reference(
        !          1987:        vm_offset_t pa)
        !          1988: {
        !          1989:        register struct phys_entry *pp;
        !          1990:        register struct mapping *mp;
        !          1991:        spl_t s;
        !          1992:        boolean_t was_valid;
        !          1993: 
        !          1994: #if DEBUG
        !          1995:        if (pmdebug & PDB_USER)
        !          1996:                DPRINTF(("(pa=%x)\n", pa));
        !          1997: #endif
        !          1998: 
        !          1999:        pp = pmap_find_physentry(pa);
        !          2000:        if (pp == PHYS_NULL)
        !          2001:                return;
        !          2002: 
        !          2003:        s = splhigh();
        !          2004:        /*      Run through all the virtual mappings to clear the reference
        !          2005:                bit in each PTE. Because the reference bit does not have to be
        !          2006:                maintained exactly, we can avoid issuing syncs but once.        
        !          2007:         */
        !          2008:        queue_iterate(&pp->phys_link, mp,
        !          2009:                      struct mapping *, phys_link) {
        !          2010: 
        !          2011:                was_valid = FALSE;
        !          2012:                if (mp->pte->pte0.bits.valid == TRUE) {
        !          2013:                        mp->pte->pte0.bits.valid = FALSE;
        !          2014:                        was_valid = TRUE;
        !          2015:                }
        !          2016:                /*
        !          2017:                ** Make sure there is no entry in the TBL, it is assumed
        !          2018:                ** that if there is an entry that the page has been referenced
        !          2019:                */
        !          2020:                sync();
        !          2021:                tlbie(mp->vm_info.bits.page << PPC_PGSHIFT);
        !          2022:                eieio();
        !          2023:                tlbsync();
        !          2024:                sync();
        !          2025: 
        !          2026:                /*
        !          2027:                ** Gotta drop both bits or the chip gets hosed!
        !          2028:                **      See section 7.5.3
        !          2029:                **
        !          2030:                ** Thanks Rene!
        !          2031:                */
        !          2032:                pp->pte1.bits.changed |=
        !          2033:                        mp->pte->pte1.bits.changed;
        !          2034:                mp->pte->pte1.bits.changed = FALSE;
        !          2035:                mp->pte->pte1.bits.referenced = FALSE;
        !          2036:                eieio();
        !          2037:                if (was_valid == TRUE)
        !          2038:                {
        !          2039:                        mp->pte->pte0.bits.valid = TRUE;
        !          2040:                }
        !          2041:                sync();
        !          2042:        }
        !          2043: 
        !          2044:        /*      Mark the physical entry shadow copy as non-referenced too.
        !          2045:        */
        !          2046:        pp->pte1.bits.referenced = FALSE;
        !          2047: 
        !          2048:        splx(s);
        !          2049: }
        !          2050: 
        !          2051: 
        !          2052: 
        !          2053: /*
        !          2054:  * pmap_is_referenced(phys)
        !          2055:  *     returns TRUE if the given physical page has been referenced 
        !          2056:  *     since the last call to pmap_clear_reference().
        !          2057:  */
        !          2058: boolean_t
        !          2059: pmap_is_referenced(
        !          2060:        vm_offset_t pa)
        !          2061: {
        !          2062:        struct phys_entry *pp;
        !          2063:        register struct mapping *mp;
        !          2064:        spl_t s;
        !          2065: 
        !          2066: #if DEBUG
        !          2067:        if (pmdebug & PDB_USER)
        !          2068:                DPRINTF(("(pa=%x)\n", pa));
        !          2069: #endif
        !          2070:        pp = pmap_find_physentry(pa);
        !          2071:        if (pp == PHYS_NULL)
        !          2072:                return(FALSE);
        !          2073: 
        !          2074:        if (pp->pte1.bits.referenced)
        !          2075:                return (TRUE);
        !          2076: 
        !          2077: 
        !          2078:        s = splhigh();
        !          2079:        /*      Make sure all TLB -> PTE updates have completed.
        !          2080:        */
        !          2081:        sync();
        !          2082: 
        !          2083:        /*      Check all the mappings to see if any one of them
        !          2084:                have recorded a reference to this physical page.
        !          2085:        */
        !          2086:        queue_iterate(&pp->phys_link, mp,
        !          2087:                      struct mapping *, phys_link) {
        !          2088: 
        !          2089:                /*      Find the first referenced page mapping but
        !          2090:                        do not include the phys page mapping.
        !          2091:                */
        !          2092:                if (!mp->vm_info.bits.phys      && 
        !          2093:                     mp->pte->pte1.bits.referenced) 
        !          2094:                {
        !          2095:                        pp->pte1.bits.referenced = TRUE;
        !          2096:                        splx(s);
        !          2097:                        return (TRUE);
        !          2098:                }
        !          2099:        }
        !          2100:        splx(s);
        !          2101:        return(FALSE);
        !          2102: }
        !          2103: 
        !          2104: 
        !          2105: 
        !          2106: /*
        !          2107:  * Auxilliary routines for manipulating mappings
        !          2108:  */
        !          2109: 
        !          2110: static struct mapping *
        !          2111: pmap_enter_mapping(
        !          2112:        pmap_t  pmap,
        !          2113:        space_t space,
        !          2114:        vm_offset_t     va,
        !          2115:        vm_offset_t     pa,
        !          2116:        pte_t   *pte,
        !          2117:        unsigned        prot,
        !          2118:        struct phys_entry *pp)
        !          2119: {
        !          2120:        register struct mapping *mp;
        !          2121:        spl_t s;
        !          2122: 
        !          2123: #if DEBUG
        !          2124:        if (pmdebug & PDB_MAPPING)
        !          2125:                DPRINTF(("(pmap=%x, sp=%x, off=%x, &pte=%x, prot=%x)",
        !          2126:                       pmap, space, va, pte, prot));
        !          2127: #endif /* DEBUG */
        !          2128: 
        !          2129:        s = splhigh();
        !          2130:        simple_lock(&free_mapping_lock);
        !          2131:        if (queue_empty(&free_mapping))
        !          2132:                pmap_reap_mappings();
        !          2133:        queue_remove_first(&free_mapping, mp, struct mapping *, phys_link);
        !          2134: 
        !          2135:        simple_unlock(&free_mapping_lock);
        !          2136:        assert(mp != MAPPING_NULL);
        !          2137: 
        !          2138:        mp->pmap = pmap;
        !          2139:        mp->vm_info.bits.phys   = FALSE;
        !          2140:        mp->vm_info.bits.wired  = FALSE;
        !          2141:        mp->vm_info.bits.page  = (va >> PPC_PGSHIFT);
        !          2142:        mp->pte                 = pte;
        !          2143: 
        !          2144:        /* Set up pte -
        !          2145:         *   pte0 already contains everything except the valid bit.
        !          2146:         *   pte1 already contains the protection information.
        !          2147:         */
        !          2148: 
        !          2149:        assert(pte->pte0.word != PTE_EMPTY);
        !          2150: 
        !          2151:        assert(pte->pte0.bits.valid == FALSE);
        !          2152: 
        !          2153:        sync();
        !          2154:        tlbie(mp->vm_info.bits.page << PPC_PGSHIFT);
        !          2155:        eieio();
        !          2156:        tlbsync();
        !          2157:        sync();
        !          2158: 
        !          2159:        pte->pte1.bits.phys_page = pa >> PPC_PGSHIFT;
        !          2160:        pte->pte1.bits.wimg = pp->pte1.bits.wimg; /* Set default cachability*/
        !          2161: 
        !          2162:        /*      Make sure those pte1 writes are ordered ahead of
        !          2163:                of the v bit.
        !          2164:        */
        !          2165:        eieio();
        !          2166: 
        !          2167: 
        !          2168:        pte->pte0.bits.valid = TRUE;            /* Validate pte entry */
        !          2169:        sync();
        !          2170: 
        !          2171:        queue_enter_first(&pp->phys_link, mp, struct mapping *, phys_link);
        !          2172: 
        !          2173: #if    DEBUG
        !          2174:        /*      Assert a PTE of type WIMG_IO is not mapped to general RAM.
        !          2175:        */
        !          2176:        if (pmdebug & PDB_IO    &&
        !          2177:            pte->pte1.bits.wimg == PTE_WIMG_IO)
        !          2178:                assert (((unsigned) pa) >= PCI_BASE)
        !          2179: 
        !          2180:        /* Assert that there are no other mappings with different
        !          2181:         * cachability information, as this can freeze the machine
        !          2182:         */
        !          2183:        {
        !          2184:                struct mapping *mp2;
        !          2185:                queue_iterate(&pp->phys_link, mp2,
        !          2186:                              struct mapping *, phys_link) {
        !          2187:                        assert(mp2->pte->pte1.bits.wimg ==
        !          2188:                               pte->pte1.bits.wimg);
        !          2189:                }
        !          2190:        }
        !          2191: #endif /* DEBUG */
        !          2192: #if DEBUG
        !          2193:        if (pmdebug & PDB_MAPPING)
        !          2194:                DPRINTF((" -> %x\n"));
        !          2195: #endif
        !          2196: #if DEBUG
        !          2197:        if (pmdebug & PDB_MASSIVE) {
        !          2198:                register struct mapping *mp2;
        !          2199:                queue_iterate(&free_mapping, mp2,
        !          2200:                              struct mapping *, phys_link) {
        !          2201:                        assert(mp2->phys_link.next != NULL);
        !          2202:                }
        !          2203:        }
        !          2204: #endif /* DEBUG */     
        !          2205:        splx(s);
        !          2206:        return(mp);
        !          2207: }
        !          2208: 
        !          2209: 
        !          2210: 
        !          2211: /*
        !          2212:  * pmap_find_mapping(space, offset)
        !          2213:  *     Lookup the virtual address <space,offset> in the mapping "table".
        !          2214:  *     Returns a pointer to the mapping or NULL if none.
        !          2215:  *
        !          2216:  *     XXX what about MP locking?
        !          2217:  */
        !          2218: static struct mapping *
        !          2219: pmap_find_mapping(
        !          2220:        register space_t space,
        !          2221:        vm_offset_t offset)
        !          2222: {
        !          2223:        register struct mapping *mp;
        !          2224:        register struct phys_entry *pp;
        !          2225:        register pte_t *pte;
        !          2226:        spl_t s;
        !          2227: 
        !          2228: #if DEBUG
        !          2229:        if (pmdebug & PDB_MAPPING)
        !          2230:                DPRINTF(("(sp=%x, off=%x) -> ", space, offset));
        !          2231: #endif
        !          2232:        offset = trunc_page(offset);
        !          2233: 
        !          2234:        /* Locate the pte but don't allocate a new one if not found */
        !          2235:        pte = find_or_allocate_pte(space, offset, FALSE);
        !          2236: 
        !          2237:        if (pte == NULL) {
        !          2238: #if DEBUG
        !          2239:                if (pmdebug & PDB_MAPPING)
        !          2240:                        DPRINTF(("MAPPING_NULL\n"));
        !          2241: #endif /* DEBUG */
        !          2242:                return MAPPING_NULL;
        !          2243:        }
        !          2244: 
        !          2245:        s = splhigh();
        !          2246:        /* Take advantage of the fact that pte1 can be
        !          2247:         * considered as a pointer to an address in
        !          2248:         * the physical page when looking for physentry.
        !          2249:         */
        !          2250: 
        !          2251:        pp = pmap_find_physentry((vm_offset_t)(pte->pte1.word));
        !          2252: 
        !          2253:        queue_iterate(&pp->phys_link, mp,
        !          2254:                      struct mapping *, phys_link) {
        !          2255:                if (mp->pte == pte)
        !          2256:                        break;
        !          2257:        }
        !          2258:        assert(mp != MAPPING_NULL);     /* There must be mapping for a pte */
        !          2259:        assert(mp->pte == pte);
        !          2260:        assert(((mp->vm_info.bits.page >> 10) & 0x3f) ==
        !          2261:               mp->pte->pte0.bits.page_index);
        !          2262: 
        !          2263: #if DEBUG
        !          2264:        if (pmdebug & PDB_MAPPING)
        !          2265:                DPRINTF(("%x\n", mp));
        !          2266: #endif
        !          2267:        splx(s);
        !          2268:        return(mp);
        !          2269: }
        !          2270: 
        !          2271: 
        !          2272: 
        !          2273: static void
        !          2274: pmap_free_mapping(
        !          2275:        register struct mapping *mp)
        !          2276: {
        !          2277:        register vm_offset_t offset;
        !          2278:        struct phys_entry *pp;
        !          2279:        spl_t s;
        !          2280: 
        !          2281: #if DEBUG
        !          2282:        if (pmdebug & PDB_MAPPING)
        !          2283:                DPRINTF(("(mp=%x), pte at 0x%x (0x%08x,0x%08x)\n",
        !          2284:                       mp, mp->pte, mp->pte->pte0.word,mp->pte->pte1.word));
        !          2285: #endif
        !          2286: 
        !          2287:        s = splhigh();
        !          2288: 
        !          2289:        offset = mp->vm_info.bits.page << PPC_PGSHIFT;
        !          2290: 
        !          2291:        pp = pmap_find_physentry((vm_offset_t)mp->pte->pte1.word);
        !          2292:        assert(pp != PHYS_NULL);
        !          2293: 
        !          2294:        /*      Perform a general case PTE update designed to work
        !          2295:                in SMP configurations. TODO - locks and tlbsync
        !          2296:        */
        !          2297:        mp->pte->pte0.bits.valid = FALSE;               /* Invalidate PTE */
        !          2298:        sync();                         /* Force updates to complete */
        !          2299:        tlbie(offset);                  /* Wipe out this virtual address */
        !          2300:        eieio();
        !          2301:        tlbsync();
        !          2302:        sync();                         /* force completion */
        !          2303: 
        !          2304:        /* Reflect back the modify and reference bits for the pager */
        !          2305:        if (!mp->vm_info.bits.phys) 
        !          2306:                pp->pte1.word |= mp->pte->pte1.word;
        !          2307: 
        !          2308:        /*
        !          2309:         * Now remove from the PTOV/VTOP lists and return to the free list.
        !          2310:         * Note that we must block interrupts since they might cause TLB
        !          2311:         * misses which would search (potentially inconsistant) lists.
        !          2312:         */
        !          2313: 
        !          2314: 
        !          2315:        /* for now, just remove the mapping */
        !          2316:        mp->pte->pte0.word = PTE_EMPTY; /* Remove pte (v->p) lookup */
        !          2317: #if DEBUG
        !          2318:        mp->pte->pte1.word = 0;
        !          2319: #endif 
        !          2320: 
        !          2321:        queue_remove(&pp->phys_link, mp, struct mapping *, phys_link);
        !          2322: 
        !          2323:        simple_lock(&free_mapping_lock);
        !          2324:        queue_enter(&free_mapping, mp, struct mapping *, phys_link);
        !          2325:        simple_unlock(&free_mapping_lock);
        !          2326: #if DEBUG
        !          2327:        if (pmdebug & PDB_MASSIVE) {
        !          2328:                register struct mapping *mp2;
        !          2329:                queue_iterate(&free_mapping, mp2,
        !          2330:                              struct mapping *, phys_link) {
        !          2331:                        assert(mp2->phys_link.next != NULL);
        !          2332:                }
        !          2333:        }
        !          2334: #endif /* DEBUG */     
        !          2335:        splx(s);
        !          2336: }
        !          2337: 
        !          2338: 
        !          2339: 
        !          2340: /*
        !          2341:  * Deal with a hash-table pteg overflow. pmap_pteg_overflow is upcalled from
        !          2342:  * find_or_allocate_pte(), and assumes knowledge of the pteg hashing
        !          2343:  * structure
        !          2344:  */
        !          2345: 
        !          2346: static int pteg_overflow_counter=0;
        !          2347: 
        !          2348: static pte_t *pteg_pte_exchange(pte_t *pteg, pte0_t match);
        !          2349: pte_t *
        !          2350: pmap_pteg_overflow(
        !          2351:        pte_t *primary_hash,
        !          2352:        pte0_t primary_match,
        !          2353:        pte_t *secondary_hash,
        !          2354:        pte0_t secondary_match)
        !          2355: {
        !          2356:        pte_t *pte;
        !          2357: #if DEBUG
        !          2358:        int i;
        !          2359:        if (pmdebug & PDB_PTEG) {
        !          2360:                kprintf("pteg overflow for ptegs 0x%08x and 0x%08x\n",
        !          2361:                       primary_hash,secondary_hash);
        !          2362:                kprintf("PRIMARY\t\t\t\t\tSECONDARY\n");
        !          2363:                for (i=0; i<8; i++) {
        !          2364:                        kprintf("0x%08x : (0x%08x,0x%08x)\t"
        !          2365:                               "0x%08x : (0x%08x,0x%08x)\n",
        !          2366:                               &primary_hash[i],
        !          2367:                               primary_hash[i].pte0.word,
        !          2368:                               primary_hash[i].pte1.word,
        !          2369:                               &secondary_hash[i],
        !          2370:                               secondary_hash[i].pte0.word,
        !          2371:                               secondary_hash[i].pte1.word);
        !          2372:                        assert(primary_hash[i].pte0.word != PTE_EMPTY);
        !          2373:                        assert(secondary_hash[i].pte0.word != PTE_EMPTY);
        !          2374:                }
        !          2375:        }
        !          2376: #endif
        !          2377:        /* First try to replace an entry in the primary PTEG */
        !          2378:        pte = pteg_pte_exchange(primary_hash, primary_match);
        !          2379:        if (pte != PTE_NULL)
        !          2380:                return pte;
        !          2381:        pte = pteg_pte_exchange(secondary_hash, secondary_match);
        !          2382:        if (pte != PTE_NULL)
        !          2383:                return pte;
        !          2384: 
        !          2385:        panic("both ptegs are completely wired down\n");
        !          2386:        return PTE_NULL;
        !          2387: }
        !          2388: 
        !          2389: 
        !          2390:                        
        !          2391: /*
        !          2392:  * Used by the pmap_pteg_overflow function to scan through a pteg
        !          2393: */
        !          2394: static pte_t *
        !          2395: pteg_pte_exchange(
        !          2396:        pte_t *pteg,
        !          2397:        pte0_t match)
        !          2398: {
        !          2399:        /* Try and replace an entry in a pteg */
        !          2400: 
        !          2401:        int i;
        !          2402:        register struct phys_entry *pp;
        !          2403:        register struct mapping *mp;
        !          2404:        pte_t *pte;
        !          2405: 
        !          2406:        /* TODO NMGS pteg overflow algorithm needs working on!
        !          2407:         * currently we just loop around the PTEGs rejecting
        !          2408:         * the first available entry.
        !          2409:         */
        !          2410: 
        !          2411:        for (i=0; i < 8; i++) {
        !          2412: 
        !          2413:                pte = &pteg[pteg_overflow_counter];
        !          2414:                pteg_overflow_counter = (pteg_overflow_counter+1) % 8;
        !          2415: 
        !          2416:                /* all mappings must be valid otherwise we wouldn't be here */
        !          2417:                assert(pte->pte0.bits.valid == TRUE);
        !          2418: 
        !          2419:                /* Take advantage of the fact that pte1 can be
        !          2420:                 * considered as a pointer to an address in
        !          2421:                 * the physical page when looking for physentry.
        !          2422:                 */
        !          2423:                pp = pmap_find_physentry(pte->pte1.word);
        !          2424: 
        !          2425:                /* pte entry must have reverse mapping, otherwise we
        !          2426:                 * cannot remove it (it was entered by pmap_map_bd)
        !          2427:                 */
        !          2428:                if (pp == PHYS_NULL)
        !          2429:                        continue;
        !          2430: 
        !          2431:                queue_iterate(&pp->phys_link, mp,
        !          2432:                              struct mapping *, phys_link) {
        !          2433:                        if (mp->pte == pte)
        !          2434:                                break;
        !          2435:                }
        !          2436:                assert(mp != NULL);
        !          2437:                assert(mp->pte == pte);
        !          2438: 
        !          2439:                /* if this entry isn't wired, isn't in the kernel space,
        !          2440:                 * and it doesn't have any special cachability attributes
        !          2441:                 * we can remove mapping without losing any information.
        !          2442:                 * XXX kernel space mustn't be touched as we may be doing
        !          2443:                 * XXX an I/O on a non-wired page, and we must not take
        !          2444:                 * XXX a page fault in an interrupt handler.
        !          2445:                 */
        !          2446:                /* TODO better implementation for cache info? */
        !          2447:                if (!mp->vm_info.bits.wired &&
        !          2448:                    mp->pmap != kernel_pmap &&
        !          2449:                    mp->pte->pte1.bits.wimg == PTE_WIMG_DEFAULT) {
        !          2450: #if DEBUG
        !          2451:                        if (pmdebug & PDB_PTEG) {
        !          2452:                                kprintf("entry chosen at 0x%08x in %s PTEG\n",
        !          2453:                                       pte,
        !          2454:                                       pte->pte0.bits.hash_id ?
        !          2455:                                        "SECONDARY" : "PRIMARY");
        !          2456:                                kprintf("throwing away mapping from sp 0x%x, "
        !          2457:                                       "virtual 0x%08x to physical 0x%08x\n",
        !          2458:                                       mp->pmap->space,
        !          2459:                                       mp->vm_info.bits.page << PPC_PGSHIFT,
        !          2460:                                       trunc_page(mp->pte->pte1.word));
        !          2461:                                kprintf("pteg_overflow_counter=%d\n",
        !          2462:                                       pteg_overflow_counter);
        !          2463:                                kprintf("pte0.vsid=0x%08x\n",
        !          2464:                                       pte->pte0.bits.segment_id);
        !          2465:                        }
        !          2466: #endif /* DEBUG */
        !          2467:                        mp->pmap->stats.resident_count--;
        !          2468: 
        !          2469:                        /* release mapping structure and PTE, keeping
        !          2470:                         * track of changed and referenced bits
        !          2471:                         */
        !          2472:                        pmap_free_mapping(mp);
        !          2473: 
        !          2474:                        /* Replace the pte entry by the new one */
        !          2475: 
        !          2476:                        match.bits.valid = FALSE;
        !          2477:                        sync();
        !          2478:                        pte->pte0 = match;
        !          2479:                        sync();
        !          2480: 
        !          2481:                        return pte;
        !          2482:                }
        !          2483:        }
        !          2484:        return PTE_NULL;
        !          2485: }
        !          2486: 
        !          2487: 
        !          2488: 
        !          2489: /*
        !          2490:  * Collect un-wired mappings. How best to do this??
        !          2491:  */
        !          2492: static void
        !          2493: pmap_reap_mappings(void)
        !          2494: {
        !          2495: #if DEBUG
        !          2496:        if (pmdebug & PDB_MAPPING)
        !          2497:                DPRINTF(("pmap_reap_mappings()\n"));
        !          2498: #endif
        !          2499: 
        !          2500:        panic("out of mapping structs");
        !          2501: }
        !          2502: 
        !          2503: 
        !          2504: /*
        !          2505:  *     kvtophys(addr)
        !          2506:  *
        !          2507:  *     Convert a kernel virtual address to a physical address
        !          2508:  */
        !          2509: vm_offset_t
        !          2510: kvtophys(
        !          2511:        vm_offset_t va)
        !          2512: {
        !          2513:        pte_t *pte;
        !          2514:        extern vm_offset_t virtual_avail;
        !          2515: 
        !          2516:        if (va < virtual_avail)
        !          2517:            return va;
        !          2518:        
        !          2519:        pte = find_or_allocate_pte(PPC_SID_KERNEL, trunc_page(va), FALSE);
        !          2520:        if (pte == NULL)
        !          2521:                return(0);
        !          2522:        return trunc_page(pte->pte1.word) | (va & page_mask);
        !          2523: }
        !          2524: 
        !          2525: 
        !          2526: 
        !          2527: /*
        !          2528:  * pmap_remove_all - Remove translations by physical address.
        !          2529:  *
        !          2530:  * This routine walks the pv_entry chain for the given va, and 
        !          2531:  * removes all translations.  It records modify bits.
        !          2532:  *
        !          2533:  * for 2.5vm <--> 3.0pmap this mapped to pmap_page_protect()
        !          2534:  */
        !          2535: void
        !          2536: pmap_remove_all(
        !          2537:        vm_offset_t phys)
        !          2538: {
        !          2539:        pmap_page_protect(phys, VM_PROT_NONE);
        !          2540: }
        !          2541: 
        !          2542: 
        !          2543: 
        !          2544: /*
        !          2545:  * pmap_copy_on_write - Ready region for copy-on-write handling.
        !          2546:  *
        !          2547:  * This routine removes write privleges from all physical maps
        !          2548:  * for a given physical page.
        !          2549:  *
        !          2550:  * for 2.5vm <--> 3.0pmap this mapped to pmap_page_protect()
        !          2551:  *
        !          2552:  */
        !          2553: void
        !          2554: pmap_copy_on_write(
        !          2555:        vm_offset_t phys)
        !          2556: {
        !          2557:        pmap_page_protect(phys, VM_PROT_READ);
        !          2558: }
        !          2559: 
        !          2560: 
        !          2561: 
        !          2562: /*
        !          2563:  * pmap_move_page - Move pages from one kernel vaddr to another.
        !          2564:  *
        !          2565:  * Parameters:
        !          2566:  *      from    - Original kernel va    (Mach. indep. page boundary)
        !          2567:  *      to      - New kernel va         (Mach. indep. page boundary)
        !          2568:  *      size    - Bytes to move.        (Mach. indep. pages)
        !          2569:  *
        !          2570:  * Returns:
        !          2571:  *      Nothing.
        !          2572:  */
        !          2573: static void
        !          2574: pmap_move_page(
        !          2575:        unsigned long from,
        !          2576:        unsigned long to,
        !          2577:        vm_size_t size)
        !          2578: {
        !          2579:         spl_t s;
        !          2580:         pte_t *pte;
        !          2581:                struct phys_entry *pp;
        !          2582:                struct mapping *mp;
        !          2583:         vm_prot_t prot;
        !          2584:                boolean_t wired;
        !          2585:                int ppn;
        !          2586: 
        !          2587:         s = splhigh();
        !          2588:         if ((size & page_mask) != 0) {
        !          2589:                 panic("pmap_move_page: partial mach indep page");
        !          2590:         }
        !          2591:         for (; size != (unsigned) 0; size -= PAGE_SIZE, from += PAGE_SIZE, to += PAGE_SIZE) {
        !          2592:                if ((pte = find_or_allocate_pte(kernel_pmap->space, trunc_page(from), FALSE)) == PTE_NULL) {
        !          2593:                         panic("pmap_move_page: from not mapped");
        !          2594:                 }
        !          2595:                /*
        !          2596:                 * Make sure the damn thing is valid.
        !          2597:                 */
        !          2598:                if (pte->pte0.bits.valid == FALSE) {
        !          2599:                        panic("pmap_move_page: invalid pte!");
        !          2600:                }
        !          2601:                 switch (pte->pte1.bits.protection) {
        !          2602:                 case 3:
        !          2603:                         prot = VM_PROT_READ;
        !          2604:                         break;
        !          2605:                 default:
        !          2606:                         prot = VM_PROT_READ|VM_PROT_WRITE;
        !          2607:                         break;
        !          2608:                 }
        !          2609: 
        !          2610:                ppn = pte->pte1.bits.phys_page;
        !          2611:                pp = pmap_find_physentry((vm_offset_t)(pte->pte1.word));
        !          2612:                queue_iterate(&pp->phys_link, mp,
        !          2613:                                struct mapping *, phys_link) {
        !          2614:                        if (mp->pte == pte)
        !          2615:                                break;
        !          2616:                }
        !          2617:                assert(mp != MAPPING_NULL);
        !          2618:                assert(mp->pte == pte);
        !          2619:                assert(((mp->vm_info.bits.page >> 10) & 0x3f) ==
        !          2620:                        mp->pte->pte0.bits.page_index);
        !          2621:                wired = mp->vm_info.bits.wired;
        !          2622: 
        !          2623:                /*
        !          2624:                 * Remove old mapping first (avoid aliasing)
        !          2625:                 */
        !          2626:                 pmap_remove(kernel_pmap, from, from + PAGE_SIZE);
        !          2627:                 pmap_enter(kernel_pmap, to, PMAP_PTOB(ppn), prot, wired);
        !          2628:         }
        !          2629:         splx(s);
        !          2630: }
        !          2631: 
        !          2632: 
        !          2633: 
        !          2634: /*
        !          2635:  * Move pages from one kernel virtual address to another.
        !          2636:  * Both addresses are assumed to reside in the Sysmap,
        !          2637:  * and size must be a multiple of the page size.
        !          2638:  */
        !          2639: void
        !          2640: pagemove(
        !          2641:        register caddr_t from,
        !          2642:        register caddr_t to,
        !          2643:        int size)
        !          2644: {
        !          2645:        pmap_move_page((unsigned long)from, (unsigned long)to, (vm_size_t)size);
        !          2646: }
        !          2647: 
        !          2648: 
        !          2649: 
        !          2650: #if DEBUG
        !          2651: /* This function is included to test compiler functionality, it does
        !          2652:  * a simple slide through the bitfields of a pte to check
        !          2653:  * minimally correct bitfield behaviour. We need bitfields to work!
        !          2654:  */
        !          2655: #define TEST(PTE0,PTE1)                                                        \
        !          2656:        if ((pte.pte0.word != (unsigned int)PTE0) ||                    \
        !          2657:            (pte.pte1.word != (unsigned int)PTE1)) {                    \
        !          2658:                DPRINTF(("BITFIELD TEST FAILED AT LINE %d\n",__LINE__));        \
        !          2659:                DPRINTF(("EXPECTING 0x%08x and 0x%08x\n",                       \
        !          2660:                       (unsigned int)PTE0,(unsigned int)PTE1));         \
        !          2661:                DPRINTF(("GOT       0x%08x and 0x%08x\n",                       \
        !          2662:                       pte.pte0.word,pte.pte1.word));                   \
        !          2663:                return 1;                                               \
        !          2664:        }
        !          2665: 
        !          2666: extern int pmap_test_bitfields(void); /* Prototyped also in go.c */
        !          2667: int pmap_test_bitfields(void)
        !          2668: {
        !          2669:        pte_t   pte;
        !          2670:        pte.pte0.word = 0;
        !          2671:        pte.pte1.word = 0;
        !          2672: 
        !          2673:        pte.pte0.bits.segment_id = 0x103; TEST(0x103 << 7, 0);
        !          2674:        pte.pte0.bits.valid = 1;
        !          2675:        TEST((unsigned int)(0x80000000U| 0x103<<7), 0);
        !          2676:        pte.pte0.bits.hash_id = 1;
        !          2677:        TEST((unsigned int)(0x80000000U | 0x103 << 7 | 1<<6), 0);
        !          2678:        pte.pte0.bits.page_index = 3;
        !          2679:        TEST((unsigned int)(0x80000000U|0x103<<7|1<<6|3), 0);
        !          2680: 
        !          2681:        pte.pte0.bits.segment_id = 0;
        !          2682:        TEST((unsigned int)(0x80000000U|1<<6|3), 0);
        !          2683:        pte.pte0.bits.page_index = 0;
        !          2684:        TEST((unsigned int)(0x80000000U|1<<6), 0);
        !          2685:        pte.pte0.bits.valid = 0;
        !          2686:        TEST(1<<6, 0);
        !          2687: 
        !          2688:        pte.pte1.bits.referenced = 1; TEST(1<<6, 1<<8);
        !          2689:        pte.pte1.bits.protection = 3; TEST(1<<6, (unsigned int)(1<<8 | 3));
        !          2690:        pte.pte1.bits.changed = 1; TEST(1<<6,(unsigned int)(1<<8|1<<7|3));
        !          2691:        pte.pte1.bits.phys_page = 0xfffff;
        !          2692:        TEST(1<<6,(unsigned int)(0xfffff000U|1<<8|1<<7|3));
        !          2693: 
        !          2694:        pte.pte1.bits.changed = 0;
        !          2695:        TEST(1<<6,(unsigned int)(0xfffff000U|1<<8|3));
        !          2696: 
        !          2697:        return 0;
        !          2698: }
        !          2699: #endif /* DEBUG */
        !          2700: 
        !          2701: 
        !          2702: 
        !          2703: void 
        !          2704: pmap_enter_cache_spec(
        !          2705:     pmap_t             pmap,
        !          2706:     vm_offset_t                va,
        !          2707:     vm_offset_t                pa,
        !          2708:     vm_prot_t          prot,
        !          2709:     boolean_t          wired,
        !          2710:     cache_spec_t       caching
        !          2711: )
        !          2712: {
        !          2713:     if (pmap == PMAP_NULL)
        !          2714:        return;
        !          2715: 
        !          2716:        pmap_enter(pmap, va, pa, prot, wired);
        !          2717:        
        !          2718: }
        !          2719: 
        !          2720: 
        !          2721: 
        !          2722: void
        !          2723: pmap_update( void )
        !          2724: {
        !          2725: #if DEBUG
        !          2726:        if (pmdebug & PDB_USER)
        !          2727:                DPRINTF(("()\n"));
        !          2728: #endif
        !          2729: }

unix.superglobalmegacorp.com

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