Annotation of kernel/machdep/i386/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:  * Copyright (c) 1992 NeXT Computer, Inc.
        !            27:  *
        !            28:  * Intel386 Family:    Hardware page mapping.
        !            29:  *
        !            30:  * HISTORY
        !            31:  *
        !            32:  * 9 April 1992 ? at NeXT
        !            33:  *     Created.
        !            34:  */
        !            35:  
        !            36: #import <cpus.h>
        !            37: 
        !            38: #import <mach/mach_types.h>
        !            39: 
        !            40: #import <vm/vm_kern.h>
        !            41: #import <vm/vm_page.h>
        !            42: 
        !            43: #import <machdep/i386/pmap_private.h>
        !            44: #import <machdep/i386/pmap_inline.h>
        !            45: #import <machdep/i386/cpu_inline.h>
        !            46: 
        !            47: /*
        !            48:  * Setup structures to map from mach vm_prot_t
        !            49:  * to machine protections.
        !            50:  */
        !            51: unsigned int                   user_prot_codes[8];
        !            52: unsigned int                   kernel_prot_codes[8];
        !            53: #define kernel_pmap_prot(x)    (kernel_prot_codes[(x)])
        !            54: 
        !            55: static
        !            56: void
        !            57: pte_prot_init(
        !            58:     void
        !            59: )
        !            60: {
        !            61:     unsigned int       *kp, *up;
        !            62:     int                        prot;
        !            63: 
        !            64:     kp = kernel_prot_codes;
        !            65:     up = user_prot_codes;
        !            66:     for (prot = 0; prot < 8; prot++) {
        !            67:        switch ((vm_prot_t)prot) {
        !            68:        case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE:
        !            69:            *kp++ = 0;
        !            70:            *up++ = 0;
        !            71:            break;
        !            72:        case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE:
        !            73:        case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE:
        !            74:        case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE:
        !            75:            *kp++ = PT_PROT_KR;
        !            76:            *up++ = PT_PROT_UR;
        !            77:            break;
        !            78:        case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE:
        !            79:        case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE:
        !            80:        case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE:
        !            81:        case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE:
        !            82:            *kp++ = PT_PROT_KRW;
        !            83:            *up++ = PT_PROT_URW;
        !            84:            break;
        !            85:        }
        !            86:     }
        !            87: }
        !            88: 
        !            89: /*
        !            90:  * Given a map and a machine independent protection code,
        !            91:  * set the protection code in the given pte
        !            92:  */
        !            93: static inline
        !            94: void
        !            95: pte_prot(
        !            96:     pmap_t             pmap,
        !            97:     vm_prot_t          prot,
        !            98:     int                        valid,          /* valid bit for pte */
        !            99:     pt_entry_t *       pte             /* IN/OUT */
        !           100: )
        !           101: {
        !           102:     if (pmap == kernel_pmap)
        !           103:        pte->prot = kernel_prot_codes[prot];
        !           104:     else
        !           105:        pte->prot = user_prot_codes[prot];
        !           106: 
        !           107:     pte->valid = valid;
        !           108: }
        !           109: 
        !           110: /*
        !           111:  * Return a ptr to the page
        !           112:  * table entry at the indicated
        !           113:  * offset in the pmap.  Return
        !           114:  * PT_ENTRY_NULL if the page table
        !           115:  * does not exist.
        !           116:  */
        !           117: inline
        !           118: pt_entry_t *
        !           119: pmap_pt_entry(
        !           120:     pmap_t             pmap,
        !           121:     vm_offset_t                va
        !           122: )
        !           123: {
        !           124:     pd_entry_t *       pde;
        !           125:     
        !           126:     pde = pd_to_pd_entry(pmap->root, va);
        !           127:     
        !           128:     if (!pde->valid)
        !           129:        return (PT_ENTRY_NULL);
        !           130:        
        !           131:     return (pd_entry_to_pt_entry(pde, va));
        !           132: }
        !           133: 
        !           134: /*
        !           135:  * Return a ptr to the page
        !           136:  * directory entry at the indicated
        !           137:  * offset in the pmap.
        !           138:  */
        !           139: inline
        !           140: pd_entry_t *
        !           141: pmap_pd_entry(
        !           142:     pmap_t             pmap,
        !           143:     vm_offset_t                va
        !           144: )
        !           145: {
        !           146:     return (pd_to_pd_entry(pmap->root, va));
        !           147: }
        !           148: 
        !           149: /*
        !           150:  * Return the physical address
        !           151:  * corresponding to the indicated
        !           152:  * offset in the pmap.  Only used
        !           153:  * internally since no locking is
        !           154:  * done.
        !           155:  */
        !           156: static inline
        !           157: unsigned int
        !           158: pmap_phys(
        !           159:     pmap_t             pmap,
        !           160:     vm_offset_t                va
        !           161: )
        !           162: {
        !           163:     pt_entry_t         *pte;
        !           164:     
        !           165:     pte = pmap_pt_entry(pmap, va);
        !           166:     if (pte == PT_ENTRY_NULL || !pte->valid)
        !           167:        return (0);
        !           168:            
        !           169:     return (pfn_to_phys(pte->pfn) + page_offset(va));
        !           170: }
        !           171: 
        !           172: static inline
        !           173: void
        !           174: pmap_update_tlbs(
        !           175:     pmap_t             pmap,
        !           176:     vm_offset_t                start,
        !           177:     vm_offset_t                end
        !           178: )
        !           179: {
        !           180:     if (pmap == kernel_pmap || pmap->cpus_using) {
        !           181:        tlb_stat.total++;
        !           182:        if (end - start > PAGE_SIZE)
        !           183:            flush_tlb();
        !           184:        else {
        !           185:            for (; start < end; start += I386_PGBYTES)
        !           186:                invlpg(start, pmap == kernel_pmap);
        !           187:          
        !           188:            tlb_stat.single++;
        !           189:        }
        !           190:     }
        !           191: }
        !           192: 
        !           193: /*
        !           194:  * Allocate a new page table
        !           195:  * in the kernel pmap at the
        !           196:  * given offset when one does
        !           197:  * not already exist.
        !           198:  */
        !           199: static
        !           200: void
        !           201: pmap_kernel_pt_alloc(
        !           202:     vm_offset_t                addr
        !           203: )
        !           204: {
        !           205:     pd_entry_t         template, *pde;
        !           206:     vm_offset_t                pt;
        !           207:     unsigned int       phys;
        !           208:     int                        i;
        !           209:     
        !           210:     pde = pmap_pd_entry(kernel_pmap, trunc_section(addr));
        !           211:     if (pde->valid)
        !           212:        panic("pmap_kernel_pt_alloc");
        !           213:        
        !           214:     if (!pmap_initialized) {
        !           215:        pt = alloc_pages(PAGE_SIZE);
        !           216:        if (!pt)
        !           217:            panic("pmap_kernel_pt_alloc 2");
        !           218: 
        !           219:        bzero(pt, PAGE_SIZE);
        !           220: 
        !           221:        phys = pt - VM_MIN_KERNEL_ADDRESS;      
        !           222:     }
        !           223:     else {
        !           224:        if (kmem_alloc_wired(kernel_map, &pt, PAGE_SIZE) != KERN_SUCCESS)
        !           225:            panic("pmap_kernel_pt_alloc 3");
        !           226:            
        !           227:        phys = pmap_phys(kernel_pmap, pt);
        !           228:     }
        !           229:     
        !           230:     template = (pd_entry_t) { 0 };
        !           231:     template.valid = 1;
        !           232:     template.prot = PT_PROT_KRW;
        !           233:     template.pfn = phys_to_pfn(phys);
        !           234:     
        !           235:     for (i = ptes_per_vm_page; i-- > 0; pde++) {
        !           236:        *pde = template;
        !           237:        template.pfn++;
        !           238:     }
        !           239: }
        !           240: 
        !           241: /*
        !           242:  * Map memory at initialization.  The physical addresses being
        !           243:  * mapped are not managed and are never unmapped.
        !           244:  */
        !           245: vm_offset_t
        !           246: pmap_map(
        !           247:     vm_offset_t                virt,
        !           248:     vm_offset_t                start,
        !           249:     vm_offset_t                end,
        !           250:     vm_prot_t          prot
        !           251: )
        !           252: {
        !           253:     pt_entry_t         template, *pte;
        !           254:     
        !           255:     template = (pt_entry_t) { 0 };
        !           256: 
        !           257:     if (prot != VM_PROT_NONE) {
        !           258:        template.valid = 1;
        !           259:        template.prot =  kernel_pmap_prot(prot);
        !           260:        template.pfn = phys_to_pfn(start);
        !           261:     }
        !           262: 
        !           263:     while (start < end) {
        !           264:        pte = pmap_pt_entry(kernel_pmap, virt);
        !           265:        if (pte == PT_ENTRY_NULL) {
        !           266:            pmap_kernel_pt_alloc(virt);
        !           267:            pte = pmap_pt_entry(kernel_pmap, virt);
        !           268:        }
        !           269: 
        !           270:        /*
        !           271:         * Is this necessary ??
        !           272:         */     
        !           273:        if (    start >= (640 * 1024) &&
        !           274:                start < (1024 * 1024))
        !           275:            template.cachewrt = 1;
        !           276:        else
        !           277:            template.cachewrt = 0;
        !           278:        
        !           279:        *pte = template;
        !           280:        if (prot != VM_PROT_NONE)
        !           281:            template.pfn++;
        !           282: 
        !           283:        virt += I386_PGBYTES;
        !           284:        start += I386_PGBYTES;
        !           285:     }
        !           286: 
        !           287:     flush_tlb();
        !           288: 
        !           289:     return (virt);
        !           290: }
        !           291: 
        !           292: static
        !           293: void
        !           294: pmap_enable_pg(
        !           295:     vm_offset_t                kernel_pd
        !           296: )
        !           297: {
        !           298:     pd_entry_t         *kpde, *end_kpde;
        !           299:     pd_entry_t         *pde;
        !           300:     cr0_t              _cr0 = cr0();
        !           301: 
        !           302:     /*
        !           303:      * Double map the kernel memory
        !           304:      * into the low end of the kernel
        !           305:      * pmap linear space.  This is
        !           306:      * necessary in order to enable
        !           307:      * paging.
        !           308:      */
        !           309:     pde = (pd_entry_t *)kernel_pd;
        !           310: 
        !           311:     kpde =
        !           312:        pmap_pd_entry(kernel_pmap,
        !           313:                        VM_MIN_KERNEL_ADDRESS);
        !           314:     end_kpde =
        !           315:        pmap_pd_entry(kernel_pmap,
        !           316:                        VM_MAX_KERNEL_ADDRESS);
        !           317:                        
        !           318:     while (kpde < end_kpde)
        !           319:        *pde++ = *kpde++;
        !           320: 
        !           321:     /*
        !           322:      * Use the kernel pmap
        !           323:      * as our initial translation
        !           324:      * tree.
        !           325:      */ 
        !           326:     kernel_pmap->cr3 =
        !           327:            pmap_phys(kernel_pmap, kernel_pd);
        !           328:     
        !           329:     set_cr3(kernel_pmap->cr3);
        !           330: 
        !           331:     /*
        !           332:      * Now, enable paging by
        !           333:      * turning on the PG bit
        !           334:      * in CR0.  Also turn on
        !           335:      * the WP bit to allow
        !           336:      * the write protecting of
        !           337:      * memory with repect to
        !           338:      * the kernel.
        !           339:      */ 
        !           340:     _cr0.pg = _cr0.wp = TRUE;
        !           341:     set_cr0(_cr0);
        !           342: }
        !           343: 
        !           344: /*
        !           345:  */
        !           346: void
        !           347: pmap_bootstrap(
        !           348:     mem_region_t       mem_region,
        !           349:     int                        num_regions,
        !           350:     vm_offset_t *      virt_avail,     /* OUT */
        !           351:     vm_offset_t *      virt_end        /* OUT */
        !           352: )
        !           353: {
        !           354:     vm_offset_t                va;
        !           355:     unsigned int       phys_end = mem_region[0].last_phys_addr;
        !           356:     vm_offset_t                kernel_pd;
        !           357:     
        !           358:     /*
        !           359:      * Setup section_size variable.
        !           360:      */
        !           361:     section_size = SECTION_SIZE;
        !           362:        
        !           363:     /*
        !           364:      * Set ptes_per_vm_page for general use.
        !           365:      */
        !           366:     ptes_per_vm_page = PAGE_SIZE / I386_PGBYTES;
        !           367: 
        !           368:     /*
        !           369:      * Initialize pte protection arrays.
        !           370:      */
        !           371:     pte_prot_init();
        !           372: 
        !           373:     /*
        !           374:      * The kernel's pmap is statically allocated so we don't
        !           375:      * have to use pmap_create, which does not work
        !           376:      * correctly at this part of the boot sequence.
        !           377:      */
        !           378:     kernel_pmap = &kernel_pmap_store;
        !           379: 
        !           380:     simple_lock_init(&kernel_pmap->lock);
        !           381: 
        !           382:     /*
        !           383:      * Allocate a page directory for the
        !           384:      * kernel pmap.
        !           385:      */
        !           386:     (vm_offset_t)kernel_pmap->root =
        !           387:            kernel_pd = alloc_cnvmem(I386_PGBYTES, I386_PGBYTES);
        !           388: 
        !           389:     bzero((vm_offset_t)kernel_pmap->root, I386_PGBYTES);
        !           390: 
        !           391:     kernel_pmap->ref_count = 1;
        !           392: 
        !           393:     kernel_pmap->root +=
        !           394:        (KERNEL_LINEAR_BASE - VM_MIN_KERNEL_ADDRESS) / I386_SECTBYTES;
        !           395:     
        !           396:     /*
        !           397:      * Map all physical memory V == P.
        !           398:      */
        !           399:     va = pmap_map(VM_MIN_KERNEL_ADDRESS,
        !           400:                  0,
        !           401:                  phys_end,
        !           402:                  VM_PROT_READ | VM_PROT_WRITE);
        !           403: 
        !           404:     /*
        !           405:      * Allocate additional kernel page tables
        !           406:      * needed for allocating kernel virtual memory later.
        !           407:      */
        !           408:     *virt_avail = va;
        !           409:      va = pmap_map(va,
        !           410:                   0,
        !           411:                   64*1024*1024 +       /* base size */
        !           412:                   zone_map_sizer() +   /* zone allocator */
        !           413:                   buffer_map_sizer(),  /* buffer cache */
        !           414:                   VM_PROT_NONE);
        !           415:                   
        !           416:     *virt_end = va;
        !           417: 
        !           418:     /*
        !           419:      * Finish initialization
        !           420:      * of the kernel pmap, and
        !           421:      * then enable paging.
        !           422:      */
        !           423:     pmap_enable_pg(kernel_pd);
        !           424: }
        !           425: 
        !           426: /*
        !           427:  * Initialize the pmap module.
        !           428:  * Called by vm_init, to initialize any structures that the pmap
        !           429:  * system needs to map virtual memory.
        !           430:  */
        !           431: void
        !           432: pmap_init(
        !           433:     mem_region_t       mem_region,
        !           434:     int                        num_regions
        !           435: )
        !           436: {
        !           437:     unsigned int       phys_start, phys_end;
        !           438:     int                        npages;
        !           439:     vm_size_t          s;
        !           440: 
        !           441:     phys_start = mem_region[0].first_phys_addr;
        !           442:     phys_end   = mem_region[0].last_phys_addr;
        !           443: 
        !           444:     npages     = mem_region[0].num_pages;
        !           445: 
        !           446:     /*
        !           447:      * Allocate memory for the page descriptor
        !           448:      * table.
        !           449:      */
        !           450:     s = sizeof(struct pg_desc) * npages;
        !           451:     (void) kmem_alloc_wired(kernel_map, (vm_offset_t *)&pg_desc_tbl, s);
        !           452:     pg_first_phys = phys_start;
        !           453: 
        !           454:     /*
        !           455:      * Create the zone of physical maps,
        !           456:      * and of the physical-to-virtual entries.
        !           457:      */
        !           458:     s = sizeof (struct pmap);
        !           459:     pmap_zone = zinit(s, 400*s, 0, FALSE, "pmap");             /* XXX */
        !           460: 
        !           461:     s = sizeof (struct pv_entry);
        !           462:     pv_entry_zone = zinit(s, 10000*s, 0, FALSE, "pv_entry");   /* XXX */
        !           463:     
        !           464:     /*
        !           465:      * Create the zone of page
        !           466:      * extensions.
        !           467:      */
        !           468:     s = sizeof (struct pg_exten);
        !           469:     pg_exten_zone = zinit(s, npages*s, 0, FALSE, "pg_exten");
        !           470: 
        !           471:     /*
        !           472:      * Initialize the queues of active and
        !           473:      * free page tables and free page directories.
        !           474:      */        
        !           475:     queue_init(&pt_active_queue);
        !           476:     queue_init(&pt_free_queue);
        !           477:     queue_init(&pd_free_queue);
        !           478: 
        !           479:     /*
        !           480:      * Only now, when all of the data structures are allocated,
        !           481:      * can we set vm_first_phys and vm_last_phys.  If we set them
        !           482:      * too soon, the kmem_alloc above will try to use these
        !           483:      * data structures and blow up.
        !           484:      */
        !           485: 
        !           486:     vm_first_phys      = phys_start;
        !           487:     vm_last_phys       = phys_end;
        !           488: 
        !           489:     pmap_initialized = TRUE;
        !           490: }
        !           491: 
        !           492: static
        !           493: pg_exten_t *
        !           494: pg_exten_alloc(
        !           495:     vm_offset_t                page
        !           496: )
        !           497: {
        !           498:     pg_exten_t         *pe;
        !           499:     pg_desc_t          *pd;
        !           500:         
        !           501:     (vm_offset_t)pe = zalloc(pg_exten_zone);
        !           502:     
        !           503:     pe->phys = pmap_phys(kernel_pmap, page);
        !           504:     
        !           505:     pd = pg_desc(pe->phys);
        !           506: 
        !           507:     pd->pg_exten = pe; pe->pg_desc = pd;
        !           508:     
        !           509:     pe->alloc_count = pe->wired_count = pe->unrefd_age = pe->alloc_bmap = 0;
        !           510:     
        !           511:     return (pe);
        !           512: }
        !           513: 
        !           514: static
        !           515: void
        !           516: pg_exten_free(
        !           517:     pg_exten_t         *pe
        !           518: )
        !           519: {
        !           520:     pe->pg_desc->pg_exten = PG_EXTEN_NULL;
        !           521:     
        !           522:     zfree(pg_exten_zone, (vm_offset_t)pe);
        !           523: }
        !           524: 
        !           525: static
        !           526: void
        !           527: pmap_alloc_pd(
        !           528:     pmap_t             pmap
        !           529: )
        !           530: {
        !           531:     pg_exten_t         *pe;
        !           532:     int                        i;
        !           533:    
        !           534:     if (pe = pd_free_obtain()) {
        !           535:        if (++pe->alloc_count == ptes_per_vm_page)
        !           536:            pd_free_remove(pe);
        !           537: 
        !           538:        i = ffs(~pe->alloc_bmap) - 1;
        !           539:        pe->alloc_bmap |= (1 << i);
        !           540: 
        !           541:        (vm_offset_t)pmap->root = pe->pg_desc->pv_list.va + (I386_PGBYTES * i);
        !           542:     }
        !           543:     else {
        !           544:        if (kmem_alloc_wired(kernel_map,
        !           545:                        (vm_offset_t *)&pmap->root, PAGE_SIZE) != KERN_SUCCESS)
        !           546:            panic("pmap_alloc_pd");
        !           547: 
        !           548:        pd_alloc_count++;
        !           549:        
        !           550:        pe = pg_exten_alloc((vm_offset_t)pmap->root);
        !           551: 
        !           552:        if (++pe->alloc_count < ptes_per_vm_page)
        !           553:            pd_free_add(pe);
        !           554: 
        !           555:        pe->alloc_bmap |= 1;
        !           556:     }
        !           557: }
        !           558: 
        !           559: static
        !           560: void
        !           561: pmap_free_pd(
        !           562:     pmap_t             pmap
        !           563: )
        !           564: {
        !           565:     pg_exten_t         *pe;
        !           566:     pg_desc_t          *pd;
        !           567:     int                        i;
        !           568:     
        !           569:     pd = pg_desc(pmap_phys(kernel_pmap, (vm_offset_t)pmap->root));
        !           570:     
        !           571:     pe = pd->pg_exten;
        !           572: 
        !           573:     if (pe->alloc_count-- == ptes_per_vm_page)
        !           574:        pd_free_add(pe);
        !           575: 
        !           576:     i = ((vm_offset_t)pmap->root - pd->pv_list.va) / I386_PGBYTES;
        !           577: 
        !           578:     pe->alloc_bmap &= ~(1 << i);
        !           579: }
        !           580: 
        !           581: /*
        !           582:  * Allocate and setup the page directory
        !           583:  * for a new pmap.  The pd_entries that
        !           584:  * correspond to the kernel address space
        !           585:  * are initialized by copying them from
        !           586:  * the kernel pmap.  This works correctly
        !           587:  * since we never expand the kernel pmap.
        !           588:  */
        !           589: static
        !           590: void
        !           591: pmap_create_pd(
        !           592:     pmap_t             pmap
        !           593: )
        !           594: {
        !           595:     pd_entry_t         *pde;
        !           596:     pd_entry_t         *kpde, *end_kpde;
        !           597:     
        !           598:     pmap_alloc_pd(pmap);
        !           599:     
        !           600:     if (pmap->root == PD_ENTRY_NULL)
        !           601:        panic("pmap_create_page_directory");
        !           602:     
        !           603:     if (i386_trunc_page(pmap->root) != (vm_offset_t)pmap->root)
        !           604:        panic("pmap_create_page_directory 1");
        !           605:     
        !           606:     pmap->cr3 = pmap_phys(kernel_pmap, (vm_offset_t)pmap->root);
        !           607:        
        !           608:     kpde =
        !           609:        pmap_pd_entry(kernel_pmap,
        !           610:                        VM_MIN_KERNEL_ADDRESS);
        !           611:     end_kpde =
        !           612:        pmap_pd_entry(kernel_pmap,
        !           613:                        VM_MAX_KERNEL_ADDRESS);
        !           614:                    
        !           615:     pde = pmap_pd_entry(pmap, KERNEL_LINEAR_BASE);
        !           616:     
        !           617:     while (kpde < end_kpde)
        !           618:        *pde++ = *kpde++;
        !           619: }
        !           620: 
        !           621: /*
        !           622:  * Create and return a physical map.
        !           623:  *
        !           624:  * If the size specified for the map
        !           625:  * is zero, the map is an actual physical
        !           626:  * map, and may be referenced by the
        !           627:  * hardware.
        !           628:  *
        !           629:  * If the size specified is non-zero,
        !           630:  * the map will be used in software only, and
        !           631:  * is bounded by that size.
        !           632:  */
        !           633: pmap_t
        !           634: pmap_create(
        !           635:     vm_size_t          size
        !           636: )
        !           637: {
        !           638:     pmap_t             pmap;
        !           639: 
        !           640:     /*
        !           641:      * A software use-only map doesn't even need a pmap.
        !           642:      */
        !           643:     if (size != 0)
        !           644:        return (PMAP_NULL);
        !           645: 
        !           646:     /*
        !           647:      * Allocate a pmap struct from the pmap_zone.
        !           648:      */
        !           649:     pmap = (pmap_t) zalloc(pmap_zone);
        !           650:     if (pmap == PMAP_NULL)
        !           651:        panic("pmap_create pmap");
        !           652: 
        !           653:     bzero((vm_offset_t)pmap, sizeof (struct pmap));
        !           654: 
        !           655:     /*
        !           656:      * Create the page directory.
        !           657:      */
        !           658:     pmap_create_pd(pmap);
        !           659: 
        !           660:     pmap->ref_count = 1;
        !           661: 
        !           662:     simple_lock_init(&pmap->lock);
        !           663:        
        !           664:     return (pmap);
        !           665: }
        !           666: 
        !           667: /*
        !           668:  * Retire the given physical map from service.
        !           669:  * Should only be called if the map contains
        !           670:  * no valid mappings.
        !           671:  */
        !           672: void
        !           673: pmap_destroy(
        !           674:     pmap_t             pmap
        !           675: )
        !           676: {
        !           677:     int                        c, s;
        !           678: 
        !           679:     if (pmap == PMAP_NULL)
        !           680:        return;
        !           681: 
        !           682:     SPLVM(s);
        !           683:     simple_lock(&pmap->lock);
        !           684: 
        !           685:     c = --pmap->ref_count;
        !           686: 
        !           687:     simple_unlock(&pmap->lock);
        !           688:     SPLX(s);
        !           689: 
        !           690:     if (c != 0)
        !           691:        return;
        !           692: 
        !           693:     pmap_free_pd(pmap);
        !           694: 
        !           695:     zfree(pmap_zone, (vm_offset_t)pmap);
        !           696: }
        !           697: 
        !           698: /*
        !           699:  *     Add a reference to the specified pmap.
        !           700:  */
        !           701: 
        !           702: void
        !           703: pmap_reference(
        !           704:     pmap_t             pmap
        !           705: )
        !           706: {
        !           707:     int                        s;
        !           708: 
        !           709:     if (pmap != PMAP_NULL) {
        !           710:        SPLVM(s);
        !           711:        simple_lock(&pmap->lock);
        !           712: 
        !           713:        pmap->ref_count++;
        !           714: 
        !           715:        simple_unlock(&pmap->lock);
        !           716:        SPLX(s);
        !           717:     }
        !           718: }
        !           719: 
        !           720: /*
        !           721:  * Remove a range of mappings from
        !           722:  * a pmap.  The indicated range must
        !           723:  * lie completely within one section,
        !           724:  * i.e. the ptes must be within one
        !           725:  * page table.
        !           726:  */
        !           727: static
        !           728: void
        !           729: pmap_remove_range(
        !           730:     pmap_t             pmap,
        !           731:     vm_offset_t                start,
        !           732:     vm_offset_t                end,
        !           733:     boolean_t          free_table
        !           734: )
        !           735: {
        !           736:     pt_entry_t         *pte, *epte;
        !           737:     pg_desc_t          *pd;
        !           738:     pv_entry_t         pv_h;
        !           739:     pv_entry_t         cur, prev;
        !           740:     unsigned int       pa;
        !           741:     vm_offset_t                va = start;
        !           742:     int                        i, num_removed = 0, num_unwired = 0;
        !           743:     
        !           744:     if ((pte = pmap_pt_entry(pmap, start)) == PT_ENTRY_NULL)
        !           745:        return;
        !           746:        
        !           747:     epte = pmap_pt_entry(pmap, end);
        !           748:     if (trunc_page(pte) != trunc_page(epte))
        !           749:        epte = (pt_entry_t *)round_page(pte + ptes_per_vm_page);
        !           750:     
        !           751:     for (; pte < epte; va += PAGE_SIZE) {
        !           752:        if (!pte->valid) {
        !           753:            pte += ptes_per_vm_page;
        !           754:            continue;
        !           755:        }
        !           756:            
        !           757:        num_removed++;
        !           758:        if (pte->wired)
        !           759:            num_unwired++;
        !           760:            
        !           761:        pa = pfn_to_phys(pte->pfn);
        !           762:        if (!managed_page(pa)) {
        !           763:            for (i = ptes_per_vm_page; i-- > 0; pte++)
        !           764:                *pte = (pt_entry_t) { 0 };
        !           765:            continue;
        !           766:        }
        !           767:            
        !           768:        pd = pg_desc(pa);
        !           769:        LOCK_PVH(pd);
        !           770:        
        !           771:        /*
        !           772:         * Collect the referenced & dirty bits
        !           773:         * and clear the mapping.
        !           774:         */
        !           775:        for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !           776:            if (pte->dirty) {
        !           777:                vm_page_t       m = PHYS_TO_VM_PAGE(pa);
        !           778:                
        !           779:                vm_page_set_modified(m);
        !           780:                pd->page_attrib |= PG_DIRTY;
        !           781:            }
        !           782:            
        !           783:            if (pte->refer)
        !           784:                pd->page_attrib |= PG_REFER;
        !           785:                
        !           786:            *pte = (pt_entry_t) { 0 };
        !           787:        }
        !           788: 
        !           789:        /*
        !           790:         * Remove the mapping from the pvlist for
        !           791:         * this physical page.
        !           792:         */
        !           793:        pv_h = pg_desc_pvh(pd);
        !           794:        if (pv_h->pmap == PMAP_NULL)
        !           795:            panic("pmap_remove_range");
        !           796: 
        !           797:        if (pv_h->va == va && pv_h->pmap == pmap) {
        !           798:            /*
        !           799:             * Header is the pv_entry.  Copy the next one
        !           800:             * to header and free the next one (we can't
        !           801:             * free the header)
        !           802:             */
        !           803:            cur = pv_h->next;
        !           804:            if (cur != PV_ENTRY_NULL) {
        !           805:                *pv_h = *cur;
        !           806:                zfree(pv_entry_zone, (vm_offset_t) cur);
        !           807:            }
        !           808:            else
        !           809:                pv_h->pmap = PMAP_NULL;
        !           810:        }
        !           811:        else {
        !           812:            prev = pv_h;
        !           813:            while ((cur = prev->next) != PV_ENTRY_NULL) {
        !           814:                if (cur->va == va && cur->pmap == pmap)
        !           815:                    break;
        !           816:                prev = cur;
        !           817:            }
        !           818:            if (cur == PV_ENTRY_NULL)
        !           819:                panic("pmap_remove_range 2");
        !           820: 
        !           821:            prev->next = cur->next;
        !           822:            zfree(pv_entry_zone, (vm_offset_t) cur);
        !           823:        }
        !           824:        
        !           825:        UNLOCK_PVH(pd);
        !           826:     }
        !           827: 
        !           828:     /*
        !           829:      * Free the mappings from the page table.
        !           830:      */        
        !           831:     pmap_deallocate_mappings(
        !           832:                            pmap, start,
        !           833:                            num_removed, num_unwired, free_table);
        !           834: }
        !           835: 
        !           836: /*
        !           837:  * Remove the given range of addresses
        !           838:  * from the specified pmap.
        !           839:  *
        !           840:  * It is assumed that the start and end are properly
        !           841:  * rounded to the page size.
        !           842:  */
        !           843: void
        !           844: pmap_remove(
        !           845:     pmap_t             pmap,
        !           846:     vm_offset_t                start,
        !           847:     vm_offset_t                end
        !           848: )
        !           849: {
        !           850:     vm_offset_t                sect_end;
        !           851:     int                        s;
        !           852: 
        !           853:     if (pmap == PMAP_NULL)
        !           854:        return;
        !           855: 
        !           856:     PMAP_READ_LOCK(pmap, s);
        !           857: 
        !           858:     /*
        !           859:      * Invalidate the translation buffer first
        !           860:      */
        !           861:     PMAP_UPDATE_TLBS(pmap, start, end);
        !           862:     
        !           863:     while (start < end) {
        !           864:        sect_end = round_section(start + PAGE_SIZE);
        !           865:        if (sect_end > end)
        !           866:            sect_end = end;
        !           867: 
        !           868:        pmap_remove_range(pmap, start, sect_end, TRUE);
        !           869:        start = sect_end;
        !           870:     }
        !           871: 
        !           872:     PMAP_READ_UNLOCK(pmap, s);
        !           873: }
        !           874: 
        !           875: /*
        !           876:  * Remove all references to 
        !           877:  * the indicated page from
        !           878:  * all pmaps.
        !           879:  */
        !           880: void
        !           881: pmap_remove_all(
        !           882:     unsigned int       pa
        !           883: )
        !           884: {
        !           885:     pt_entry_t         *pte;
        !           886:     pv_entry_t         pv_h, cur;
        !           887:     pg_desc_t          *pd;
        !           888:     vm_offset_t                va;
        !           889:     pmap_t             pmap;
        !           890:     int                        s, i;
        !           891:     
        !           892:     if (!managed_page(pa))
        !           893:        return;
        !           894: 
        !           895:     /*
        !           896:      * Lock the pmap system first, since we will be changing
        !           897:      * several pmaps.
        !           898:      */
        !           899:     PMAP_WRITE_LOCK(s);
        !           900:     
        !           901:     /*
        !           902:      * Walk down PV list, removing all mappings.
        !           903:      * We have to do the same work as in pmap_remove_range
        !           904:      * since that routine locks the pv_head.  We don't have
        !           905:      * to lock the pv_head, since we have the entire pmap system.
        !           906:      */
        !           907:     pd = pg_desc(pa);
        !           908:     pv_h = pg_desc_pvh(pd);
        !           909:     
        !           910:     while ((pmap = pv_h->pmap) != PMAP_NULL) {
        !           911:        va = pv_h->va;
        !           912: 
        !           913:        simple_lock(&pmap->lock);
        !           914: 
        !           915:        pte = pmap_pt_entry(pmap, va);
        !           916:        if (pte == PT_ENTRY_NULL || !pte->valid)
        !           917:            panic("pmap_remove_all");
        !           918:            
        !           919:        if (pfn_to_phys(pte->pfn) != pa)
        !           920:            panic("pmap_remove_all 2");
        !           921:            
        !           922:        if (pte->wired)
        !           923:            panic("pmap_remove_all 3");
        !           924:        
        !           925:        /*
        !           926:         * Tell CPU using pmap to invalidate its TLB
        !           927:         */
        !           928:        PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !           929: 
        !           930:        if ((cur = pv_h->next) != PV_ENTRY_NULL) {
        !           931:            *pv_h = *cur;
        !           932:            zfree(pv_entry_zone, (vm_offset_t) cur);
        !           933:        }
        !           934:        else
        !           935:            pv_h->pmap = PMAP_NULL;     
        !           936:        
        !           937:        /*
        !           938:         * Collect the referenced & dirty bits
        !           939:         * and clear the mapping.
        !           940:         */
        !           941:        for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !           942:            if (pte->dirty) {
        !           943:                vm_page_t       m = PHYS_TO_VM_PAGE(pa);
        !           944:                
        !           945:                vm_page_set_modified(m);
        !           946:                pd->page_attrib |= PG_DIRTY;
        !           947:            }
        !           948:            
        !           949:            if (pte->refer)
        !           950:                pd->page_attrib |= PG_REFER;
        !           951:                
        !           952:            *pte = (pt_entry_t) { 0 };
        !           953:        }
        !           954:        
        !           955:        pmap_deallocate_mappings(pmap, va, 1, 0, TRUE);
        !           956:        
        !           957:        simple_unlock(&pmap->lock);
        !           958:     }
        !           959:     
        !           960:     PMAP_WRITE_UNLOCK(s);
        !           961: }
        !           962: 
        !           963: /*
        !           964:  * Remove write access to the
        !           965:  * indicated page from all pmaps.
        !           966:  */
        !           967: void
        !           968: pmap_copy_on_write(
        !           969:     unsigned int       pa
        !           970: )
        !           971: {
        !           972:     pt_entry_t         *pte;
        !           973:     pv_entry_t         pv_e;
        !           974:     int                        i, s;
        !           975: 
        !           976:     if (!managed_page(pa))
        !           977:        return;
        !           978:        
        !           979:     /*
        !           980:      * Lock the entire pmap system, since we may be changing
        !           981:      * several maps.
        !           982:      */
        !           983:     PMAP_WRITE_LOCK(s);
        !           984:     
        !           985:     pv_e = pg_desc_pvh(pg_desc(pa));
        !           986:     if (pv_e->pmap == PMAP_NULL) {
        !           987:        PMAP_WRITE_UNLOCK(s);
        !           988:        return;
        !           989:     }    
        !           990: 
        !           991:     /*
        !           992:      * Run down the list of mappings to this physical page,
        !           993:      * disabling write privileges on each one.
        !           994:      */
        !           995:     while (pv_e != PV_ENTRY_NULL) {
        !           996:        pmap_t          pmap;
        !           997:        vm_offset_t     va;
        !           998: 
        !           999:        pmap = pv_e->pmap;
        !          1000:        va = pv_e->va;
        !          1001: 
        !          1002:        simple_lock(&pmap->lock);
        !          1003:        
        !          1004:        pte = pmap_pt_entry(pmap, va);
        !          1005:        
        !          1006:        if (pte == PT_ENTRY_NULL || !pte->valid)
        !          1007:            panic("pmap_copy_on_write");
        !          1008: 
        !          1009:        /*
        !          1010:         * Ask cpus using pmap to invalidate their TLBs
        !          1011:         */
        !          1012:        PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          1013:        
        !          1014:        if (pte->prot == PT_PROT_URW || pte->prot == PT_PROT_KRW)
        !          1015:            for (i = ptes_per_vm_page; i-- > 0; pte++)
        !          1016:                pte_prot(pmap, VM_PROT_READ, pte->valid, pte);
        !          1017:            
        !          1018:        simple_unlock(&pmap->lock);
        !          1019:        
        !          1020:        pv_e = pv_e->next;
        !          1021:     }
        !          1022:     
        !          1023:     PMAP_WRITE_UNLOCK(s);
        !          1024: }
        !          1025: 
        !          1026: /*
        !          1027:  * Change the page protection
        !          1028:  * on a range of addresses in
        !          1029:  * the indicated pmap.  If protect
        !          1030:  * is being changed to VM_PROT_NONE,
        !          1031:  * remove the mappings.
        !          1032:  */
        !          1033: void
        !          1034: pmap_protect(
        !          1035:     pmap_t             pmap,
        !          1036:     vm_offset_t                start,
        !          1037:     vm_offset_t                end,
        !          1038:     vm_prot_t          prot
        !          1039: )
        !          1040: {
        !          1041:     pt_entry_t         *pte, *epte;
        !          1042:     vm_offset_t                sect_end;
        !          1043:     int                        i, s;
        !          1044:     
        !          1045:     if (pmap == PMAP_NULL)
        !          1046:        return;
        !          1047:        
        !          1048:     if (prot == VM_PROT_NONE) {
        !          1049:        pmap_remove(pmap, start, end);
        !          1050:        return;
        !          1051:     }
        !          1052:     
        !          1053:     SPLVM(s);
        !          1054:     simple_lock(&pmap->lock);
        !          1055: 
        !          1056:     /*
        !          1057:      * Invalidate the translation buffer first
        !          1058:      */
        !          1059:     PMAP_UPDATE_TLBS(pmap, start, end);    
        !          1060:     
        !          1061:     while (start < end) {
        !          1062:        sect_end = round_section(start + PAGE_SIZE);
        !          1063:        if (sect_end > end)
        !          1064:            sect_end = end;
        !          1065:            
        !          1066:        pte = pmap_pt_entry(pmap, start);
        !          1067:        if (pte != PT_ENTRY_NULL) {
        !          1068:            epte = pmap_pt_entry(pmap, sect_end);
        !          1069:            if (trunc_page(pte) != trunc_page(epte))
        !          1070:                epte = (pt_entry_t *)round_page(pte + ptes_per_vm_page);
        !          1071:                
        !          1072:            while (pte < epte) {
        !          1073:                if (!pte->valid) {
        !          1074:                    pte += ptes_per_vm_page;
        !          1075:                    continue;
        !          1076:                }
        !          1077:                
        !          1078:                for (i = ptes_per_vm_page; i-- > 0; pte++)
        !          1079:                    pte_prot(pmap, prot, pte->valid, pte);
        !          1080:            }
        !          1081:        }
        !          1082: 
        !          1083:        start = sect_end;
        !          1084:     }
        !          1085:     
        !          1086:     simple_unlock(&pmap->lock);
        !          1087:     SPLX(s);
        !          1088: }
        !          1089: 
        !          1090: /*
        !          1091:  * Insert the given physical page (p) at
        !          1092:  * the specified virtual address (v) in the
        !          1093:  * target physical map with the protection requested.
        !          1094:  *
        !          1095:  * If specified, the page will be wired down, meaning
        !          1096:  * that the related pte can not be reclaimed.
        !          1097:  *
        !          1098:  * NB:  This is the only routine which MAY NOT lazy-evaluate
        !          1099:  * or lose information.  That is, this routine must actually
        !          1100:  * insert this page into the given map NOW.
        !          1101:  */
        !          1102: void inline
        !          1103: pmap_enter_cache_spec(
        !          1104:     pmap_t             pmap,
        !          1105:     vm_offset_t                va,
        !          1106:     vm_offset_t                pa,
        !          1107:     vm_prot_t          prot,
        !          1108:     boolean_t          wired,
        !          1109:     cache_spec_t       caching
        !          1110: )
        !          1111: {
        !          1112:     pt_entry_t         *pte;
        !          1113:     pv_entry_t         pv_h;
        !          1114:     pg_desc_t          *pd;
        !          1115:     int                        i, s;
        !          1116:     pv_entry_t         pv_e;
        !          1117:     pt_entry_t         template;
        !          1118:     vm_offset_t                old_pa;
        !          1119:     
        !          1120:     if (pmap == PMAP_NULL)
        !          1121:        return;
        !          1122:        
        !          1123:     if (prot == VM_PROT_NONE) {
        !          1124:        pmap_remove(pmap, va, va + PAGE_SIZE);
        !          1125:        return;
        !          1126:     }
        !          1127: 
        !          1128:     /*
        !          1129:      * Must allocate a new pvlist entry while we're unlocked;
        !          1130:      * zalloc may cause pageout (which will lock the pmap system).
        !          1131:      * If we determine we need a pvlist entry, we will unlock
        !          1132:      * and allocate one.  Then we will retry, throwing away
        !          1133:      * the allocated entry later (if we no longer need it).
        !          1134:      */
        !          1135:     pv_e = PV_ENTRY_NULL;
        !          1136:     template = (pt_entry_t) { 0 };
        !          1137: 
        !          1138: Retry:
        !          1139:     PMAP_READ_LOCK(pmap, s);
        !          1140: 
        !          1141:     /*
        !          1142:      * Expand pmap to include this pte.  Assume that
        !          1143:      * pmap is always expanded to include enough
        !          1144:      * pages to map one VM page.
        !          1145:      */
        !          1146:     while ((pte = pmap_pt_entry(pmap, va)) == PT_ENTRY_NULL) {
        !          1147:        /*
        !          1148:         * Must unlock to expand the pmap.
        !          1149:         */
        !          1150:        PMAP_READ_UNLOCK(pmap, s);
        !          1151: 
        !          1152:        pmap_expand(pmap, va);
        !          1153: 
        !          1154:        PMAP_READ_LOCK(pmap, s);
        !          1155:     }
        !          1156: 
        !          1157:     /*
        !          1158:      * Special case if the physical page is already mapped
        !          1159:      * at this address.
        !          1160:      */
        !          1161:     old_pa = pfn_to_phys(pte->pfn);
        !          1162:     if (pte->valid && old_pa == pa) {
        !          1163:        /*
        !          1164:         * May be changing its wired attribute or protection
        !          1165:         */
        !          1166:        if (wired && !pte->wired)
        !          1167:            pmap_wire_mapping(pmap, va);
        !          1168:        else
        !          1169:        if (!wired && pte->wired)
        !          1170:            pmap_unwire_mapping(pmap, va);
        !          1171: 
        !          1172:        pte_prot(pmap, prot, 1, &template);
        !          1173:        template.pfn = phys_to_pfn(pa);
        !          1174:        if (wired)
        !          1175:            template.wired = 1;
        !          1176:            
        !          1177:        if (caching == cache_disable)
        !          1178:            template.cachedis = 1;
        !          1179:        else
        !          1180:        if (caching == cache_writethrough)
        !          1181:            template.cachewrt = 1;
        !          1182: 
        !          1183:        PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          1184:        
        !          1185:        for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !          1186:            if (pte->dirty)
        !          1187:                template.dirty = 1;
        !          1188:            *pte = template;
        !          1189:            template.pfn++;
        !          1190:        }
        !          1191:     }
        !          1192:     else {
        !          1193: 
        !          1194:        /*
        !          1195:         * Remove old mapping from the PV list if necessary.
        !          1196:         */
        !          1197:        if (pte->valid) {
        !          1198:            /*
        !          1199:             * Invalidate the translation buffer,
        !          1200:             * then remove the mapping.
        !          1201:             */
        !          1202:            PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          1203:            
        !          1204:            pmap_remove_range(pmap, va, va + PAGE_SIZE, FALSE);
        !          1205:        }
        !          1206:        
        !          1207:        if (managed_page(pa)) {
        !          1208: 
        !          1209:            /*
        !          1210:             * Enter the mapping in the PV list for this
        !          1211:             * physical page.
        !          1212:             */
        !          1213:            pd = pg_desc(pa);
        !          1214:            LOCK_PVH(pd);
        !          1215:            pv_h = pg_desc_pvh(pd);
        !          1216: 
        !          1217:            if (pv_h->pmap == PMAP_NULL) {
        !          1218: 
        !          1219:                /*
        !          1220:                 * No mappings yet
        !          1221:                 */
        !          1222:                pv_h->va = va;
        !          1223:                pv_h->pmap = pmap;
        !          1224:                pv_h->next = PV_ENTRY_NULL;
        !          1225:            }
        !          1226:            else {
        !          1227:                    
        !          1228:                /*
        !          1229:                 * Add new pv_entry after header.
        !          1230:                 */
        !          1231:                if (pv_e == PV_ENTRY_NULL) {
        !          1232:                    UNLOCK_PVH(pd);
        !          1233:                    PMAP_READ_UNLOCK(pmap, s);
        !          1234:                    pv_e = (pv_entry_t) zalloc(pv_entry_zone);
        !          1235:                    goto Retry;
        !          1236:                }
        !          1237:                pv_e->va = va;
        !          1238:                pv_e->pmap = pmap;
        !          1239:                pv_e->next = pv_h->next;
        !          1240:                pv_h->next = pv_e;
        !          1241:                /*
        !          1242:                 * Remember that we used the pvlist entry.
        !          1243:                 */
        !          1244:                pv_e = PV_ENTRY_NULL;
        !          1245:            }
        !          1246:            
        !          1247:            UNLOCK_PVH(pd);
        !          1248:        }
        !          1249:            
        !          1250:        pmap_allocate_mapping(pmap, va, wired);
        !          1251: 
        !          1252:        /*
        !          1253:         * Build a template to speed up entering -
        !          1254:         * only the pfn changes.
        !          1255:         */
        !          1256:        pte_prot(pmap, prot, 1, &template);
        !          1257:        template.pfn = phys_to_pfn(pa);
        !          1258:        if (wired)
        !          1259:            template.wired = 1;
        !          1260:            
        !          1261:        if (caching == cache_disable)
        !          1262:            template.cachedis = 1;
        !          1263:        else
        !          1264:        if (caching == cache_writethrough)
        !          1265:            template.cachewrt = 1;
        !          1266:        
        !          1267:        for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !          1268:            *pte = template;
        !          1269:            template.pfn++;
        !          1270:        }
        !          1271:     }
        !          1272: 
        !          1273:     PMAP_READ_UNLOCK(pmap, s);
        !          1274: 
        !          1275:     if (pv_e != PV_ENTRY_NULL)
        !          1276:        zfree(pv_entry_zone, (vm_offset_t) pv_e);
        !          1277: }
        !          1278: 
        !          1279: void
        !          1280: pmap_enter(
        !          1281:     pmap_t             pmap,
        !          1282:     vm_offset_t                va,
        !          1283:     vm_offset_t                pa,
        !          1284:     vm_prot_t          prot,
        !          1285:     boolean_t          wired
        !          1286: )
        !          1287: {
        !          1288:     pmap_enter_cache_spec(
        !          1289:                        pmap,
        !          1290:                        va,
        !          1291:                        pa,
        !          1292:                        prot,
        !          1293:                        wired,
        !          1294:                        cache_default);
        !          1295: }
        !          1296: 
        !          1297: void
        !          1298: pmap_enter_shared_range(
        !          1299:     pmap_t             pmap,
        !          1300:     vm_offset_t                va,
        !          1301:     vm_size_t          size,
        !          1302:     vm_offset_t                kern
        !          1303: )
        !          1304: {
        !          1305:     vm_offset_t                end = round_page(va + size);
        !          1306:     
        !          1307:     while (va < end) {
        !          1308:        pmap_enter(
        !          1309:                    pmap,
        !          1310:                    va,
        !          1311:                    pmap_resident_extract(kernel_pmap, kern),
        !          1312:                    VM_PROT_READ|VM_PROT_WRITE,
        !          1313:                    TRUE);
        !          1314:                    
        !          1315:        va += PAGE_SIZE; kern += PAGE_SIZE;
        !          1316:     }
        !          1317: }
        !          1318: 
        !          1319: /*
        !          1320:  * Change the wiring attribute for a
        !          1321:  * pmap/virtual-address        pair.
        !          1322:  *
        !          1323:  * The mapping must already exist in the pmap.
        !          1324:  */
        !          1325: void
        !          1326: pmap_change_wiring(
        !          1327:     pmap_t             pmap,
        !          1328:     vm_offset_t                va,
        !          1329:     boolean_t          wired
        !          1330: )
        !          1331: {
        !          1332:     pt_entry_t         *pte;
        !          1333:     int                        i, s;
        !          1334:     
        !          1335:     /*
        !          1336:      * We must grab the pmap system lock because we may
        !          1337:      * change a pte_page queue.
        !          1338:      */
        !          1339:     PMAP_READ_LOCK(pmap, s);
        !          1340:     
        !          1341:     if ((pte = pmap_pt_entry(pmap, va)) == PT_ENTRY_NULL)
        !          1342:        panic("pmap_change_wiring");
        !          1343: 
        !          1344:     if (wired && !pte->wired) {
        !          1345:        /*
        !          1346:         * wiring down mapping
        !          1347:         */
        !          1348:        pmap_wire_mapping(pmap, va);
        !          1349:     }
        !          1350:     else
        !          1351:     if (!wired && pte->wired) {
        !          1352:        /*
        !          1353:         * unwiring mapping
        !          1354:         */
        !          1355:        pmap_unwire_mapping(pmap, va);
        !          1356:     }
        !          1357:     
        !          1358:     for (i = ptes_per_vm_page; i-- > 0; pte++)
        !          1359:        pte->wired = wired;
        !          1360: 
        !          1361:     PMAP_READ_UNLOCK(map, s);
        !          1362: }
        !          1363: 
        !          1364: vm_offset_t
        !          1365: pmap_extract(
        !          1366:     pmap_t             pmap,
        !          1367:     vm_offset_t                va
        !          1368: )
        !          1369: {
        !          1370:     vm_offset_t                pa;
        !          1371:     int                        s;
        !          1372:     
        !          1373:     SPLVM(s);
        !          1374:     simple_lock(&pmap->lock);
        !          1375:     
        !          1376:     pa = pmap_phys(pmap, va);
        !          1377:     
        !          1378:     simple_unlock(&pmap->lock);
        !          1379:     SPLX(s);
        !          1380:     
        !          1381:     return (pa);
        !          1382: }
        !          1383: 
        !          1384: vm_offset_t
        !          1385: pmap_resident_extract(
        !          1386:     pmap_t             pmap,
        !          1387:     vm_offset_t                va
        !          1388: )
        !          1389: {
        !          1390:     return ((vm_offset_t) pmap_phys(pmap, va));
        !          1391: }
        !          1392: 
        !          1393: /*
        !          1394:  * Expand a pmap to be able to map the
        !          1395:  * specified virtual address by allocating
        !          1396:  * a single page table either from the list 
        !          1397:  * of free page tables or directly from kernel
        !          1398:  * memory.
        !          1399:  */
        !          1400: static
        !          1401: void
        !          1402: pmap_expand(
        !          1403:     pmap_t             pmap,
        !          1404:     vm_offset_t                va
        !          1405: )
        !          1406: {
        !          1407:     pd_entry_t         template, *pde;
        !          1408:     pg_exten_t         *pe;
        !          1409:     vm_offset_t                pt;
        !          1410:     int                        i, s;
        !          1411: 
        !          1412:     if (pmap == kernel_pmap)
        !          1413:        panic("pmap_expand");
        !          1414:            
        !          1415:     if (pe = pt_free_obtain())
        !          1416:        pt = pe->pg_desc->pv_list.va;
        !          1417:     else {
        !          1418:        if (kmem_alloc_wired(kernel_map, &pt, PAGE_SIZE) != KERN_SUCCESS)
        !          1419:            return;
        !          1420: 
        !          1421:        pt_alloc_count++;
        !          1422:        
        !          1423:        pe = pg_exten_alloc(pt);
        !          1424:     }
        !          1425: 
        !          1426:     PMAP_READ_LOCK(pmap, s);   
        !          1427: 
        !          1428:     /*
        !          1429:      * See if someone else expanded us first.
        !          1430:      */
        !          1431:     if (pmap_pt_entry(pmap, va) != PT_ENTRY_NULL) {
        !          1432:        PMAP_READ_UNLOCK(pmap, s);
        !          1433:        
        !          1434:        pg_exten_free(pe);
        !          1435: 
        !          1436:        kmem_free(kernel_map, pt, PAGE_SIZE);
        !          1437:        
        !          1438:        pt_alloc_count--;
        !          1439: 
        !          1440:        return;
        !          1441:     }
        !          1442: 
        !          1443:     /*
        !          1444:      * What virtual memory does this
        !          1445:      * page table map ?
        !          1446:      */
        !          1447:     pe->offset = trunc_section(va);
        !          1448:     pe->pmap = pmap;
        !          1449: 
        !          1450:     /*
        !          1451:      * Clear the reference aging
        !          1452:      * tick count.
        !          1453:      */
        !          1454:     pe->unrefd_age = 0;
        !          1455: 
        !          1456:     /*
        !          1457:      * Add this page table
        !          1458:      * to the active queue.
        !          1459:      */        
        !          1460:     pt_active_add(pe);
        !          1461: 
        !          1462:     /*
        !          1463:      * Setup entry template.
        !          1464:      */
        !          1465:     template = (pd_entry_t) { 0 };
        !          1466:     template.valid = 1;
        !          1467:     template.prot = PT_PROT_URW;
        !          1468:     template.pfn = phys_to_pfn(pe->phys);
        !          1469: 
        !          1470:     /*
        !          1471:      * Set the page directory entries for this page table
        !          1472:      */
        !          1473:     pde = pmap_pd_entry(pmap, pe->offset);
        !          1474:     for (i = ptes_per_vm_page; i-- > 0; pde++) {
        !          1475:        *pde = template;
        !          1476:        template.pfn++;
        !          1477:     }
        !          1478:     
        !          1479:     PMAP_READ_UNLOCK(pmap, s);
        !          1480: }
        !          1481: 
        !          1482: /*
        !          1483:  * Allocate one additional mapping
        !          1484:  * in a page table.  Note: pmap is
        !          1485:  * already locked.
        !          1486:  */
        !          1487: static
        !          1488: void
        !          1489: pmap_allocate_mapping(
        !          1490:     pmap_t             pmap,
        !          1491:     vm_offset_t                va,
        !          1492:     boolean_t          wired
        !          1493: )
        !          1494: {
        !          1495:     pd_entry_t         *pde;
        !          1496:     pg_exten_t         *pe;
        !          1497:     
        !          1498:     pmap->stats.resident_count++;
        !          1499:     if (wired)
        !          1500:        pmap->stats.wired_count++;
        !          1501:     
        !          1502:     if (pmap == kernel_pmap)
        !          1503:        return;
        !          1504:        
        !          1505:     pde = pmap_pd_entry(pmap, trunc_section(va));
        !          1506:     if (pde->valid) {
        !          1507:        pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten;
        !          1508:        pe->alloc_count++;
        !          1509:        if (wired)
        !          1510:            pe->wired_count++;
        !          1511:     }
        !          1512: }
        !          1513: 
        !          1514: /*
        !          1515:  * Deallocate one or more mappings
        !          1516:  * in a page table.  The page table
        !          1517:  * is freed if no mappings remain.
        !          1518:  * Note: pmap is already locked.
        !          1519:  */
        !          1520: static
        !          1521: void
        !          1522: pmap_deallocate_mappings(
        !          1523:     pmap_t             pmap,
        !          1524:     vm_offset_t                va,
        !          1525:     int                        count,
        !          1526:     int                        unwire_count,
        !          1527:     boolean_t          free_table
        !          1528: )
        !          1529: {
        !          1530:     pd_entry_t         *pde;
        !          1531:     pg_exten_t         *pe;
        !          1532:     int                        i;
        !          1533:     
        !          1534:     pmap->stats.wired_count -= unwire_count;
        !          1535:     pmap->stats.resident_count -= count;
        !          1536: 
        !          1537:     if (pmap == kernel_pmap)
        !          1538:        return;
        !          1539:        
        !          1540:     pde = pmap_pd_entry(pmap, trunc_section(va));
        !          1541:     if (pde->valid) {  
        !          1542:        pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten;
        !          1543:        if (pe->wired_count < unwire_count)
        !          1544:            panic("pmap_deallocate_mappings unwire");
        !          1545:        pe->wired_count -= unwire_count;
        !          1546:        if (pe->alloc_count < count)
        !          1547:            panic("pmap_deallocate_mappings");
        !          1548:        pe->alloc_count -= count;
        !          1549: 
        !          1550:        if (free_table && pe->alloc_count == 0) {
        !          1551:            for (i = ptes_per_vm_page; i-- > 0; pde++)
        !          1552:                pde->valid = 0;
        !          1553:                
        !          1554:            pt_active_remove(pe);
        !          1555:            
        !          1556:            pt_free_add(pe);
        !          1557:        }
        !          1558:     }
        !          1559: }
        !          1560: 
        !          1561: static
        !          1562: void
        !          1563: pmap_wire_mapping(
        !          1564:     pmap_t             pmap,
        !          1565:     vm_offset_t                va
        !          1566: )
        !          1567: {
        !          1568:     pd_entry_t         *pde;
        !          1569:     pg_exten_t         *pe;
        !          1570:     
        !          1571:     pmap->stats.wired_count++;
        !          1572:     
        !          1573:     if (pmap == kernel_pmap)
        !          1574:        return;
        !          1575:        
        !          1576:     pde = pmap_pd_entry(pmap, trunc_section(va));
        !          1577:     if (pde->valid) {
        !          1578:        pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten;
        !          1579:        pe->wired_count++;
        !          1580:     }
        !          1581: }
        !          1582: 
        !          1583: static
        !          1584: void
        !          1585: pmap_unwire_mapping(
        !          1586:     pmap_t             pmap,
        !          1587:     vm_offset_t                va
        !          1588: )
        !          1589: {
        !          1590:     pd_entry_t         *pde;
        !          1591:     pg_exten_t         *pe;
        !          1592:     
        !          1593:     pmap->stats.wired_count--;
        !          1594:     
        !          1595:     if (pmap == kernel_pmap)
        !          1596:        return;
        !          1597:        
        !          1598:     pde = pmap_pd_entry(pmap, trunc_section(va));
        !          1599:     if (pde->valid) {
        !          1600:        pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten;
        !          1601:        pe->wired_count--;
        !          1602:     }
        !          1603: }
        !          1604: 
        !          1605: /*
        !          1606:  * Copy the range specified by src_addr/len
        !          1607:  * from the source map to the range dst_addr/len
        !          1608:  * in the destination map.
        !          1609:  *
        !          1610:  * This routine is only advisory and need not do anything.
        !          1611:  */
        !          1612: void
        !          1613: pmap_copy(
        !          1614:     pmap_t             dst_pmap,
        !          1615:     pmap_t             src_pmap,
        !          1616:     vm_offset_t                dst_addr,
        !          1617:     vm_size_t          len,
        !          1618:     vm_offset_t                src_addr
        !          1619: )
        !          1620: {
        !          1621:     /* OPTIONAL */
        !          1622: }
        !          1623: 
        !          1624: /*
        !          1625:  * Require that all active physical maps contain no
        !          1626:  * incorrect entries NOW.  [This update includes
        !          1627:  * forcing updates of any address map caching.]
        !          1628:  *
        !          1629:  * Generally used to insure that a thread about
        !          1630:  * to run will see a semantically correct world.
        !          1631:  */
        !          1632: void
        !          1633: pmap_update(
        !          1634:     void
        !          1635: )
        !          1636: {
        !          1637:     pg_exten_t         *pe, *npe;
        !          1638:     vm_offset_t                page;
        !          1639:     pd_entry_t         *pde;
        !          1640:     int                        tick_delta;
        !          1641:     static unsigned int        last_tick;
        !          1642: 
        !          1643:     if (!last_tick)
        !          1644:        last_tick = sched_tick; /* initialization */
        !          1645: 
        !          1646:     tick_delta = sched_tick - last_tick;
        !          1647: 
        !          1648:     if (tick_delta > 1) {
        !          1649:        /*
        !          1650:         * Free all of the pages in
        !          1651:         * the free page table list.
        !          1652:         */     
        !          1653:        while (pe = pt_free_obtain()) {
        !          1654:            page = pe->pg_desc->pv_list.va;
        !          1655:     
        !          1656:            pg_exten_free(pe);
        !          1657:     
        !          1658:            kmem_free(kernel_map, page, PAGE_SIZE);
        !          1659:            pt_alloc_count--;
        !          1660:        }
        !          1661: 
        !          1662:        /*
        !          1663:         * Run through the page directory
        !          1664:         * free list, freeing any that are
        !          1665:         * not in use.
        !          1666:         */
        !          1667:        (queue_entry_t)pe = queue_first(&pd_free_queue);
        !          1668:        while (!queue_end(&pd_free_queue, (queue_entry_t)pe)) {
        !          1669:            if (pe->alloc_count == 0) {
        !          1670:                remqueue(&pd_free_queue, (queue_entry_t)pe);
        !          1671:                
        !          1672:                pd_free_count--;
        !          1673:                
        !          1674:                page = pe->pg_desc->pv_list.va;
        !          1675:                
        !          1676:                pg_exten_free(pe);
        !          1677:                
        !          1678:                kmem_free(kernel_map, page, PAGE_SIZE);
        !          1679:                pd_alloc_count--;
        !          1680:                
        !          1681:                (queue_entry_t)pe = queue_first(&pd_free_queue);
        !          1682:            }
        !          1683:            else
        !          1684:                (queue_entry_t)pe = queue_next((queue_entry_t)pe);
        !          1685:        }
        !          1686:     }
        !          1687: 
        !          1688:     /*
        !          1689:      * Age the active page tables.  Remove
        !          1690:      * all of the mappings from the tables
        !          1691:      * which have not been used for address
        !          1692:      * translation recently (excluding those
        !          1693:      * with wired mappings).  Removing all of
        !          1694:      * a table's mappings causes the table to
        !          1695:      * be removed from the pmap and added to
        !          1696:      * the free page table list.
        !          1697:      */
        !          1698:     {
        !          1699:        static int      pt_aging_k[] = { 8, 12, 16, 24, 32 },
        !          1700:                        pt_aging_n = sizeof pt_aging_k / sizeof pt_aging_k[0];
        !          1701:        int             tick_age;
        !          1702:        
        !          1703:        tick_age = ((tick_age = tick_delta >> 3) > (pt_aging_n - 1)) ?
        !          1704:                                                pt_aging_k[pt_aging_n - 1] :
        !          1705:                                                pt_aging_k[tick_age];       
        !          1706: 
        !          1707:        (queue_entry_t)pe = queue_first(&pt_active_queue);
        !          1708:        while (!queue_end(&pt_active_queue, (queue_entry_t)pe)) {
        !          1709:            pde = pmap_pd_entry(pe->pmap, pe->offset);
        !          1710:            if (pe->wired_count == 0 && pde->valid) {
        !          1711:                (queue_entry_t)npe = queue_next((queue_entry_t)pe);
        !          1712:     
        !          1713:                if (tick_delta > 0 && !pde->refer) {
        !          1714:                    int         old_age = pe->unrefd_age;
        !          1715:     
        !          1716:                    pe->unrefd_age += tick_delta;
        !          1717:                    if (old_age > pe->unrefd_age || pe->unrefd_age > tick_age)
        !          1718:                        pmap_remove(
        !          1719:                                pe->pmap,
        !          1720:                                pe->offset,
        !          1721:                                pe->offset + section_size);
        !          1722:                }
        !          1723:                else if (pde->refer) {
        !          1724:                    pde->refer = FALSE;
        !          1725:                    pe->unrefd_age = 0;
        !          1726:                }
        !          1727:                    
        !          1728:                pe = npe;
        !          1729:            }
        !          1730:            else {
        !          1731:                pe->unrefd_age = 0;
        !          1732:                (queue_entry_t)pe = queue_next((queue_entry_t)pe);
        !          1733:            }
        !          1734:        }
        !          1735:     }
        !          1736: 
        !          1737:     last_tick += tick_delta;
        !          1738: }
        !          1739: 
        !          1740: /*
        !          1741:  * Garbage collects the physical map system for
        !          1742:  * pages which are no longer used.
        !          1743:  * Success need not be guaranteed -- that is, there
        !          1744:  * may well be pages which are not referenced, but
        !          1745:  * others may be collected.
        !          1746:  *
        !          1747:  * Called by the pageout daemon when pages are scarce.
        !          1748:  */
        !          1749: void
        !          1750: pmap_collect(
        !          1751:     pmap_t             pmap
        !          1752: )
        !          1753: {
        !          1754:     /* OPTIONAL */
        !          1755: }
        !          1756: 
        !          1757: /*
        !          1758:  * Bind the given pmap to the given
        !          1759:  * processor.
        !          1760:  */
        !          1761: void
        !          1762: pmap_activate(
        !          1763:     pmap_t             pmap,
        !          1764:     thread_t           thread,
        !          1765:     int                        cpu
        !          1766: )
        !          1767: {
        !          1768:     PMAP_ACTIVATE(pmap, thread, cpu);
        !          1769: }
        !          1770: 
        !          1771: 
        !          1772: /*
        !          1773:  * Indicates that the given physical map is no longer
        !          1774:  * in use on the specified processor.
        !          1775:  */
        !          1776: void
        !          1777: pmap_deactivate(
        !          1778:     pmap_t             pmap,
        !          1779:     thread_t           thread,
        !          1780:     int                        cpu
        !          1781: )
        !          1782: {
        !          1783:     PMAP_DEACTIVATE(pmap, thread, cpu);
        !          1784: }
        !          1785: 
        !          1786: /*
        !          1787:  * Return the pmap handle for the kernel.
        !          1788:  */
        !          1789: pmap_t
        !          1790: pmap_kernel(
        !          1791:     void
        !          1792: )
        !          1793: {
        !          1794:     return (kernel_pmap);
        !          1795: }
        !          1796: 
        !          1797: /*
        !          1798:  * pmap_zero_page zeros the specified (machine independent)
        !          1799:  * page.
        !          1800:  */
        !          1801: void
        !          1802: pmap_zero_page(
        !          1803:     vm_offset_t                pa
        !          1804: )
        !          1805: {
        !          1806:     page_set(pmap_phys_to_kern(pa), 0, PAGE_SIZE);
        !          1807: }
        !          1808: 
        !          1809: /*
        !          1810:  * pmap_copy_page copies the specified (machine independent)
        !          1811:  * pages.
        !          1812:  */
        !          1813: void
        !          1814: pmap_copy_page(
        !          1815:     vm_offset_t                src,
        !          1816:     vm_offset_t                dst
        !          1817: )
        !          1818: {
        !          1819:     page_copy(pmap_phys_to_kern(dst), pmap_phys_to_kern(src), PAGE_SIZE);
        !          1820: }
        !          1821: 
        !          1822: void
        !          1823: copy_to_phys(
        !          1824:     vm_offset_t                src,
        !          1825:     vm_offset_t                dst,
        !          1826:     vm_size_t          count
        !          1827: )
        !          1828: {
        !          1829:     bcopy(src, pmap_phys_to_kern(dst), count);
        !          1830: }
        !          1831: 
        !          1832: void
        !          1833: copy_from_phys(
        !          1834:     vm_offset_t                src,
        !          1835:     vm_offset_t                dst,
        !          1836:     vm_size_t          count
        !          1837: )
        !          1838: {
        !          1839:     bcopy(pmap_phys_to_kern(src), dst, count);
        !          1840: }
        !          1841: 
        !          1842: /*
        !          1843:  * Make the specified pages (by pmap, offset)
        !          1844:  * pageable (or not) as requested.
        !          1845:  *
        !          1846:  * A page which is not pageable may not take
        !          1847:  * a fault; therefore, its page table entry
        !          1848:  * must remain valid for the duration.
        !          1849:  *
        !          1850:  * This routine is merely advisory; pmap_enter
        !          1851:  * will specify that these pages are to be wired
        !          1852:  * down (or not) as appropriate.
        !          1853:  */
        !          1854: pmap_pageable(
        !          1855:     pmap_t             pmap,
        !          1856:     vm_offset_t                start,
        !          1857:     vm_offset_t                end,
        !          1858:     boolean_t          pageable
        !          1859: )
        !          1860: {
        !          1861:     /* OPTIONAL */
        !          1862: }
        !          1863: 
        !          1864: kern_return_t
        !          1865: pmap_attribute(
        !          1866:     pmap_t                     pmap,
        !          1867:     vm_offset_t                        address,
        !          1868:     vm_size_t                  size,
        !          1869:     vm_machine_attribute_t     attribute,
        !          1870:     vm_machine_attribute_val_t *value
        !          1871: )
        !          1872: {
        !          1873:        kern_return_t ret;
        !          1874: 
        !          1875:        if (attribute != MATTR_CACHE)
        !          1876:                return KERN_INVALID_ARGUMENT;
        !          1877: 
        !          1878:        /*
        !          1879:        ** We can't get the caching attribute for more than one page
        !          1880:        ** at a time
        !          1881:        */
        !          1882:        if ((*value == MATTR_VAL_GET) &&
        !          1883:            (trunc_page(address) != trunc_page(address+size-1)))
        !          1884:                return KERN_INVALID_ARGUMENT;
        !          1885: 
        !          1886:        if (pmap == PMAP_NULL)
        !          1887:                return KERN_SUCCESS;
        !          1888: 
        !          1889:        ret = KERN_SUCCESS;
        !          1890: 
        !          1891:         simple_lock(&pmap->lock);
        !          1892: 
        !          1893:        switch (*value) {
        !          1894:        case MATTR_VAL_CACHE_FLUSH:     /* flush from all caches */
        !          1895:        case MATTR_VAL_DCACHE_FLUSH:    /* flush from data cache(s) */
        !          1896:        case MATTR_VAL_ICACHE_FLUSH:    /* flush from instr cache(s) */
        !          1897:                break;
        !          1898: 
        !          1899:        case MATTR_VAL_GET:             /* return current value */
        !          1900:        case MATTR_VAL_OFF:             /* turn attribute off */
        !          1901:        case MATTR_VAL_ON:              /* turn attribute on */
        !          1902:        default:
        !          1903:                ret = KERN_INVALID_ARGUMENT;
        !          1904:                break;
        !          1905:        }
        !          1906:        simple_unlock(&pmap->lock);
        !          1907: 
        !          1908:        return ret;
        !          1909: 
        !          1910: }
        !          1911: 
        !          1912: /*
        !          1913:  * Clear the modify bits on the specified physical page.
        !          1914:  */
        !          1915: void
        !          1916: pmap_clear_modify(
        !          1917:     vm_offset_t                pa
        !          1918: )
        !          1919: {
        !          1920:     if (managed_page(pa))
        !          1921:        pmap_clear_page_attrib(pa, PG_DIRTY);
        !          1922: }
        !          1923: 
        !          1924: /*
        !          1925:  * Return whether or not the specified physical page is modified
        !          1926:  * by any pmaps.
        !          1927:  */
        !          1928: boolean_t
        !          1929: pmap_is_modified(
        !          1930:     vm_offset_t                pa
        !          1931: )
        !          1932: {
        !          1933:     if (managed_page(pa))
        !          1934:        return (pmap_check_page_attrib(pa, PG_DIRTY));
        !          1935:     else
        !          1936:        return (FALSE);
        !          1937: }
        !          1938: 
        !          1939: /*
        !          1940:  * Clear the reference bit on the specified physical page.
        !          1941:  */
        !          1942: void
        !          1943: pmap_clear_reference(
        !          1944:     vm_offset_t                pa
        !          1945: )
        !          1946: {
        !          1947:     if (managed_page(pa))
        !          1948:        pmap_clear_page_attrib(pa, PG_REFER);
        !          1949: }
        !          1950: 
        !          1951: /*
        !          1952:  * Return whether or not the specified physical page is referenced
        !          1953:  * by any physical maps.
        !          1954:  */
        !          1955: boolean_t
        !          1956: pmap_is_referenced(
        !          1957:     vm_offset_t                pa
        !          1958: )
        !          1959: {
        !          1960:     if (managed_page(pa))
        !          1961:        return (pmap_check_page_attrib(pa, PG_REFER));
        !          1962:     else
        !          1963:        return (FALSE);
        !          1964: }
        !          1965: 
        !          1966: /*
        !          1967:  * Clear the specified page attributes both in the
        !          1968:  * pmap_page_attributes table and the address translation
        !          1969:  * tables.  Note that we DO have to flush the entries from
        !          1970:  * the TLB since the processor uses the bits in the TLB to
        !          1971:  * determine whether it has to write the bits out to memory.
        !          1972:  */
        !          1973: static
        !          1974: void
        !          1975: pmap_clear_page_attrib(
        !          1976:     vm_offset_t                        pa,
        !          1977:     int                                attrib
        !          1978: )
        !          1979: {
        !          1980:     pt_entry_t                 *pte;
        !          1981:     pv_entry_t                 pv_h;
        !          1982:     pmap_t                     pmap;
        !          1983:     vm_offset_t                        va;
        !          1984:     pg_desc_t                  *pd;
        !          1985:     int                                i, s;
        !          1986: 
        !          1987:     pd = pg_desc(pa);
        !          1988: 
        !          1989:     PMAP_WRITE_LOCK(s);
        !          1990: 
        !          1991:     pd->page_attrib &= ~attrib;
        !          1992: 
        !          1993:     pv_h = pg_desc_pvh(pd);
        !          1994: 
        !          1995:     while ((pmap = pv_h->pmap) != PMAP_NULL) {
        !          1996:        va = pv_h->va;
        !          1997: 
        !          1998:        simple_lock(&pmap->lock);
        !          1999: 
        !          2000:        PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          2001: 
        !          2002:        pte = pmap_pt_entry(pmap, va);
        !          2003:        if (pte != PT_ENTRY_NULL) {
        !          2004:            for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !          2005:                if (attrib & PG_DIRTY)
        !          2006:                    pte->dirty = 0;
        !          2007:                if (attrib & PG_REFER)
        !          2008:                    pte->refer = 0;
        !          2009:            }
        !          2010:        }
        !          2011: 
        !          2012:        simple_unlock(&pmap->lock);
        !          2013: 
        !          2014:        if ((pv_h = pv_h->next) == PV_ENTRY_NULL)
        !          2015:            break;
        !          2016:     }
        !          2017: 
        !          2018:     PMAP_WRITE_UNLOCK(s);
        !          2019: }
        !          2020: 
        !          2021: /*
        !          2022:  * Check for the specified attributes for the
        !          2023:  * physical page.  if all bits are true in
        !          2024:  * the pmap_page_attributes table, we can trust
        !          2025:  * it.  otherwise, we must check the address
        !          2026:  * translation tables ourselves.  Note that we
        !          2027:  * DO NOT have to flush the entry from the TLB
        !          2028:  * before looking at the address translation
        !          2029:  * table since the TLB is write-through for the bits.
        !          2030:  */
        !          2031: static
        !          2032: boolean_t
        !          2033: pmap_check_page_attrib(
        !          2034:     vm_offset_t                        pa,
        !          2035:     int                                attrib
        !          2036: )
        !          2037: {
        !          2038:     pt_entry_t                 *pte;
        !          2039:     pv_entry_t                 pv_h;
        !          2040:     pmap_t                     pmap;
        !          2041:     vm_offset_t                        va;
        !          2042:     pg_desc_t                  *pd;
        !          2043:     int                                i, s;
        !          2044: 
        !          2045:     pd = pg_desc(pa);
        !          2046: 
        !          2047:     if ((pd->page_attrib & attrib) == attrib)
        !          2048:        return (TRUE);
        !          2049: 
        !          2050:     pv_h = pg_desc_pvh(pd);
        !          2051: 
        !          2052:     PMAP_WRITE_LOCK(s);
        !          2053: 
        !          2054:     while ((pmap = pv_h->pmap) != PMAP_NULL) {
        !          2055:        va = pv_h->va;
        !          2056: 
        !          2057:        simple_lock(&pmap->lock);
        !          2058: 
        !          2059:        pte = pmap_pt_entry(pmap, va);
        !          2060:        if (pte != PT_ENTRY_NULL) {
        !          2061:            for (i = ptes_per_vm_page; i-- > 0; pte++) {
        !          2062:                if (pte->dirty)
        !          2063:                    pd->page_attrib |= PG_DIRTY;
        !          2064:                if (pte->refer)
        !          2065:                    pd->page_attrib |= PG_REFER;
        !          2066:            }
        !          2067: 
        !          2068:            if ((pd->page_attrib & attrib) == attrib) {
        !          2069:                simple_unlock(&pmap->lock);
        !          2070: 
        !          2071:                PMAP_WRITE_UNLOCK(s);
        !          2072: 
        !          2073:                return (TRUE);
        !          2074:            }
        !          2075:        }
        !          2076: 
        !          2077:        simple_unlock(&pmap->lock);
        !          2078: 
        !          2079:        if ((pv_h = pv_h->next) == PV_ENTRY_NULL)
        !          2080:            break;
        !          2081:     }
        !          2082: 
        !          2083:     PMAP_WRITE_UNLOCK(s);
        !          2084: 
        !          2085:     return (FALSE);
        !          2086: }
        !          2087: 
        !          2088: /*
        !          2089:  * Dummy routine to satisfy external reference.
        !          2090:  */
        !          2091: void
        !          2092: pmap_update_interrupt(
        !          2093:     void
        !          2094: )
        !          2095: {
        !          2096:     /* should never be called. */
        !          2097:     panic("pmap_update_interrupt");
        !          2098: }
        !          2099: 
        !          2100: /*
        !          2101:  * Lower the permission for all mappings to a given page.
        !          2102:  */
        !          2103: void
        !          2104: pmap_page_protect(
        !          2105:     vm_offset_t                        pa,
        !          2106:     vm_prot_t                  prot
        !          2107: )
        !          2108: {
        !          2109:     switch (prot) {
        !          2110:        case VM_PROT_READ:
        !          2111:        case VM_PROT_READ|VM_PROT_EXECUTE:
        !          2112:            pmap_copy_on_write(pa);
        !          2113:            break;
        !          2114: 
        !          2115:        case VM_PROT_ALL:
        !          2116:            break;
        !          2117: 
        !          2118:        default:
        !          2119:            pmap_remove_all(pa);
        !          2120:            break;
        !          2121:     }
        !          2122: }

unix.superglobalmegacorp.com

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