Annotation of OSKit-Mach/i386/intel/pmap.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Mach Operating System
        !             3:  * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
        !             4:  * All Rights Reserved.
        !             5:  *
        !             6:  * Permission to use, copy, modify and distribute this software and its
        !             7:  * documentation is hereby granted, provided that both the copyright
        !             8:  * notice and this permission notice appear in all copies of the
        !             9:  * software, derivative works or modified versions, and any portions
        !            10:  * thereof, and that both notices appear in supporting documentation.
        !            11:  *
        !            12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
        !            13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
        !            14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            15:  *
        !            16:  * Carnegie Mellon requests users of this software to return to
        !            17:  *
        !            18:  *  Software Distribution Coordinator  or  [email protected]
        !            19:  *  School of Computer Science
        !            20:  *  Carnegie Mellon University
        !            21:  *  Pittsburgh PA 15213-3890
        !            22:  *
        !            23:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            24:  * the rights to redistribute these changes.
        !            25:  */
        !            26: /*
        !            27:  *     File:   pmap.c
        !            28:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            29:  *     (These guys wrote the Vax version)
        !            30:  *
        !            31:  *     Physical Map management code for Intel i386, i486, and i860.
        !            32:  *
        !            33:  *     Manages physical address maps.
        !            34:  *
        !            35:  *     In addition to hardware address maps, this
        !            36:  *     module is called upon to provide software-use-only
        !            37:  *     maps which may or may not be stored in the same
        !            38:  *     form as hardware maps.  These pseudo-maps are
        !            39:  *     used to store intermediate results from copy
        !            40:  *     operations to and from address spaces.
        !            41:  *
        !            42:  *     Since the information managed by this module is
        !            43:  *     also stored by the logical address mapping module,
        !            44:  *     this module may throw away valid virtual-to-physical
        !            45:  *     mappings at almost any time.  However, invalidations
        !            46:  *     of virtual-to-physical mappings must be done as
        !            47:  *     requested.
        !            48:  *
        !            49:  *     In order to cope with hardware architectures which
        !            50:  *     make virtual-to-physical map invalidates expensive,
        !            51:  *     this module may delay invalidate or reduced protection
        !            52:  *     operations until such time as they are actually
        !            53:  *     necessary.  This module is given full information as
        !            54:  *     to which processors are currently using which maps,
        !            55:  *     and to when physical maps must be made correct.
        !            56:  */
        !            57: 
        !            58: #include <cpus.h>
        !            59: 
        !            60: #include <mach/machine/vm_types.h>
        !            61: 
        !            62: #include <mach/boolean.h>
        !            63: #include <kern/thread.h>
        !            64: #include <kern/zalloc.h>
        !            65: 
        !            66: #include <kern/lock.h>
        !            67: 
        !            68: #include <vm/pmap.h>
        !            69: #include <vm/vm_map.h>
        !            70: #include <vm/vm_kern.h>
        !            71: #include "vm_param.h"
        !            72: #include <mach/vm_prot.h>
        !            73: #include <vm/vm_object.h>
        !            74: #include <vm/vm_page.h>
        !            75: #include <vm/vm_user.h>
        !            76: 
        !            77: #include <oskit/x86/physmem.h>
        !            78: #include <oskit/x86/base_cpu.h>
        !            79: 
        !            80: #include <mach/machine/vm_param.h>
        !            81: #include <machine/thread.h>
        !            82: #include "cpu_number.h"
        !            83: #if    i860
        !            84: #include <i860ipsc/nodehw.h>
        !            85: #endif
        !            86: 
        !            87: #ifdef ORC
        !            88: #define        OLIVETTICACHE   1
        !            89: #endif /* ORC */
        !            90: 
        !            91: #ifndef        OLIVETTICACHE
        !            92: #define        WRITE_PTE(pte_p, pte_entry)             *(pte_p) = (pte_entry);
        !            93: #define        WRITE_PTE_FAST(pte_p, pte_entry)        *(pte_p) = (pte_entry);
        !            94: #else  /* OLIVETTICACHE */
        !            95: #error might not work anymore
        !            96: 
        !            97: /* This gross kludgery is needed for Olivetti XP7 & XP9 boxes to get
        !            98:  * around an apparent hardware bug. Other than at startup it doesn't
        !            99:  * affect run-time performacne very much, so we leave it in for all
        !           100:  * machines.
        !           101:  */
        !           102: extern unsigned        *pstart();
        !           103: #define CACHE_LINE     8
        !           104: #define CACHE_SIZE     512
        !           105: #define CACHE_PAGE     0x1000;
        !           106: 
        !           107: #define        WRITE_PTE(pte_p, pte_entry) { write_pte(pte_p, pte_entry); }
        !           108: 
        !           109: write_pte(pte_p, pte_entry)
        !           110: pt_entry_t     *pte_p, pte_entry;
        !           111: {
        !           112:        unsigned long count;
        !           113:        volatile unsigned long hold, *addr1, *addr2;
        !           114: 
        !           115:        if ( pte_entry != *pte_p )
        !           116:                *pte_p = pte_entry;
        !           117:        else {
        !           118:                /* This isn't necessarily the optimal algorithm */
        !           119:                addr1 = (unsigned long *)pstart;
        !           120:                for (count = 0; count < CACHE_SIZE; count++) {
        !           121:                        addr2 = addr1 + CACHE_PAGE;
        !           122:                        hold = *addr1;          /* clear cache bank - A - */
        !           123:                        hold = *addr2;          /* clear cache bank - B - */
        !           124:                        addr1 += CACHE_LINE;
        !           125:                }
        !           126:        }
        !           127: }
        !           128: 
        !           129: #define        WRITE_PTE_FAST(pte_p, pte_entry)*pte_p = pte_entry;
        !           130: 
        !           131: #endif /* OLIVETTICACHE */
        !           132: 
        !           133: /*
        !           134:  *     Private data structures.
        !           135:  */
        !           136: 
        !           137: /*
        !           138:  *     For each vm_page_t, there is a list of all currently
        !           139:  *     valid virtual mappings of that page.  An entry is
        !           140:  *     a pv_entry_t; the list is the pv_table.
        !           141:  */
        !           142: 
        !           143: typedef struct pv_entry {
        !           144:        struct pv_entry *next;          /* next pv_entry */
        !           145:        pmap_t          pmap;           /* pmap where mapping lies */
        !           146:        vm_offset_t     va;             /* virtual address for mapping */
        !           147: } *pv_entry_t;
        !           148: 
        !           149: #define PV_ENTRY_NULL  ((pv_entry_t) 0)
        !           150: 
        !           151: pv_entry_t     pv_head_table;          /* array of entries, one per page */
        !           152: 
        !           153: /*
        !           154:  *     pv_list entries are kept on a list that can only be accessed
        !           155:  *     with the pmap system locked (at SPLVM, not in the cpus_active set).
        !           156:  *     The list is refilled from the pv_list_zone if it becomes empty.
        !           157:  */
        !           158: pv_entry_t     pv_free_list;           /* free list at SPLVM */
        !           159: decl_simple_lock_data(, pv_free_list_lock)
        !           160: 
        !           161: #define        PV_ALLOC(pv_e) { \
        !           162:        simple_lock(&pv_free_list_lock); \
        !           163:        if ((pv_e = pv_free_list) != 0) { \
        !           164:            pv_free_list = pv_e->next; \
        !           165:        } \
        !           166:        simple_unlock(&pv_free_list_lock); \
        !           167: }
        !           168: 
        !           169: #define        PV_FREE(pv_e) { \
        !           170:        simple_lock(&pv_free_list_lock); \
        !           171:        pv_e->next = pv_free_list; \
        !           172:        pv_free_list = pv_e; \
        !           173:        simple_unlock(&pv_free_list_lock); \
        !           174: }
        !           175: 
        !           176: zone_t         pv_list_zone;           /* zone of pv_entry structures */
        !           177: 
        !           178: /*
        !           179:  *     Each entry in the pv_head_table is locked by a bit in the
        !           180:  *     pv_lock_table.  The lock bits are accessed by the physical
        !           181:  *     address of the page they lock.
        !           182:  */
        !           183: 
        !           184: char   *pv_lock_table;         /* pointer to array of bits */
        !           185: #define pv_lock_table_size(n)  (((n)+BYTE_SIZE-1)/BYTE_SIZE)
        !           186: 
        !           187: /* Has pmap_init completed? */
        !           188: boolean_t      pmap_initialized = FALSE;
        !           189: 
        !           190: /*
        !           191:  *     Range of kernel virtual addresses available for kernel memory mapping.
        !           192:  *     Does not include the virtual addresses used to map physical memory 1-1.
        !           193:  *     Initialized by pmap_bootstrap.
        !           194:  */
        !           195: vm_offset_t kernel_virtual_start;
        !           196: vm_offset_t kernel_virtual_end;
        !           197: 
        !           198: /* XXX stupid fixed limit - get rid */
        !           199: vm_size_t morevm = 40 * 1024 * 1024;   /* VM space for kernel map */
        !           200: 
        !           201: /*
        !           202:  *     Index into pv_head table, its lock bits, and the modify/reference
        !           203:  *     bits starting at phys_mem_min.
        !           204:  */
        !           205: #define pa_index(pa)   (atop(pa - phys_mem_min))
        !           206: 
        !           207: #define pai_to_pvh(pai)                (&pv_head_table[pai])
        !           208: #define lock_pvh_pai(pai)      (bit_lock(pai, pv_lock_table))
        !           209: #define unlock_pvh_pai(pai)    (bit_unlock(pai, pv_lock_table))
        !           210: 
        !           211: /*
        !           212:  *     Array of physical page attribites for managed pages.
        !           213:  *     One byte per physical page.
        !           214:  */
        !           215: char   *pmap_phys_attributes;
        !           216: 
        !           217: /*
        !           218:  *     Physical page attributes.  Copy bits from PTE definition.
        !           219:  */
        !           220: #define        PHYS_MODIFIED   INTEL_PTE_MOD   /* page modified */
        !           221: #define        PHYS_REFERENCED INTEL_PTE_REF   /* page referenced */
        !           222: 
        !           223: /*
        !           224:  *     Amount of virtual memory mapped by one
        !           225:  *     page-directory entry.
        !           226:  */
        !           227: #define        PDE_MAPPED_SIZE         (pdenum2lin(1))
        !           228: 
        !           229: /*
        !           230:  *     We allocate page table pages directly from the VM system
        !           231:  *     through this object.  It maps physical memory.
        !           232:  */
        !           233: vm_object_t    pmap_object = VM_OBJECT_NULL;
        !           234: 
        !           235: /*
        !           236:  *     Locking and TLB invalidation
        !           237:  */
        !           238: 
        !           239: /*
        !           240:  *     Locking Protocols:
        !           241:  *
        !           242:  *     There are two structures in the pmap module that need locking:
        !           243:  *     the pmaps themselves, and the per-page pv_lists (which are locked
        !           244:  *     by locking the pv_lock_table entry that corresponds to the pv_head
        !           245:  *     for the list in question.)  Most routines want to lock a pmap and
        !           246:  *     then do operations in it that require pv_list locking -- however
        !           247:  *     pmap_remove_all and pmap_copy_on_write operate on a physical page
        !           248:  *     basis and want to do the locking in the reverse order, i.e. lock
        !           249:  *     a pv_list and then go through all the pmaps referenced by that list.
        !           250:  *     To protect against deadlock between these two cases, the pmap_lock
        !           251:  *     is used.  There are three different locking protocols as a result:
        !           252:  *
        !           253:  *  1.  pmap operations only (pmap_extract, pmap_access, ...)  Lock only
        !           254:  *             the pmap.
        !           255:  *
        !           256:  *  2.  pmap-based operations (pmap_enter, pmap_remove, ...)  Get a read
        !           257:  *             lock on the pmap_lock (shared read), then lock the pmap
        !           258:  *             and finally the pv_lists as needed [i.e. pmap lock before
        !           259:  *             pv_list lock.]
        !           260:  *
        !           261:  *  3.  pv_list-based operations (pmap_remove_all, pmap_copy_on_write, ...)
        !           262:  *             Get a write lock on the pmap_lock (exclusive write); this
        !           263:  *             also guaranteees exclusive access to the pv_lists.  Lock the
        !           264:  *             pmaps as needed.
        !           265:  *
        !           266:  *     At no time may any routine hold more than one pmap lock or more than
        !           267:  *     one pv_list lock.  Because interrupt level routines can allocate
        !           268:  *     mbufs and cause pmap_enter's, the pmap_lock and the lock on the
        !           269:  *     kernel_pmap can only be held at splvm.
        !           270:  */
        !           271: 
        !           272: #if    NCPUS > 1
        !           273: /*
        !           274:  *     We raise the interrupt level to splvm, to block interprocessor
        !           275:  *     interrupts during pmap operations.  We must take the CPU out of
        !           276:  *     the cpus_active set while interrupts are blocked.
        !           277:  */
        !           278: #define SPLVM(spl)     { \
        !           279:        spl = splvm(); \
        !           280:        i_bit_clear(cpu_number(), &cpus_active); \
        !           281: }
        !           282: 
        !           283: #define SPLX(spl)      { \
        !           284:        i_bit_set(cpu_number(), &cpus_active); \
        !           285:        splx(spl); \
        !           286: }
        !           287: 
        !           288: /*
        !           289:  *     Lock on pmap system
        !           290:  */
        !           291: lock_data_t    pmap_system_lock;
        !           292: 
        !           293: #define PMAP_READ_LOCK(pmap, spl) { \
        !           294:        SPLVM(spl); \
        !           295:        lock_read(&pmap_system_lock); \
        !           296:        simple_lock(&(pmap)->lock); \
        !           297: }
        !           298: 
        !           299: #define PMAP_WRITE_LOCK(spl) { \
        !           300:        SPLVM(spl); \
        !           301:        lock_write(&pmap_system_lock); \
        !           302: }
        !           303: 
        !           304: #define PMAP_READ_UNLOCK(pmap, spl) { \
        !           305:        simple_unlock(&(pmap)->lock); \
        !           306:        lock_read_done(&pmap_system_lock); \
        !           307:        SPLX(spl); \
        !           308: }
        !           309: 
        !           310: #define PMAP_WRITE_UNLOCK(spl) { \
        !           311:        lock_write_done(&pmap_system_lock); \
        !           312:        SPLX(spl); \
        !           313: }
        !           314: 
        !           315: #define PMAP_WRITE_TO_READ_LOCK(pmap) { \
        !           316:        simple_lock(&(pmap)->lock); \
        !           317:        lock_write_to_read(&pmap_system_lock); \
        !           318: }
        !           319: 
        !           320: #define LOCK_PVH(index)                (lock_pvh_pai(index))
        !           321: 
        !           322: #define UNLOCK_PVH(index)      (unlock_pvh_pai(index))
        !           323: 
        !           324: #define PMAP_UPDATE_TLBS(pmap, s, e) \
        !           325: { \
        !           326:        cpu_set cpu_mask = 1 << cpu_number(); \
        !           327:        cpu_set users; \
        !           328:  \
        !           329:        /* Since the pmap is locked, other updates are locked */ \
        !           330:        /* out, and any pmap_activate has finished. */ \
        !           331:  \
        !           332:        /* find other cpus using the pmap */ \
        !           333:        users = (pmap)->cpus_using & ~cpu_mask; \
        !           334:        if (users) { \
        !           335:            /* signal them, and wait for them to finish */ \
        !           336:            /* using the pmap */ \
        !           337:            signal_cpus(users, (pmap), (s), (e)); \
        !           338:            while ((pmap)->cpus_using & cpus_active & ~cpu_mask) \
        !           339:                continue; \
        !           340:        } \
        !           341:  \
        !           342:        /* invalidate our own TLB if pmap is in use */ \
        !           343:        if ((pmap)->cpus_using & cpu_mask) { \
        !           344:            INVALIDATE_TLB((s), (e)); \
        !           345:        } \
        !           346: }
        !           347: 
        !           348: #else  /* NCPUS > 1 */
        !           349: 
        !           350: #define SPLVM(spl)
        !           351: #define SPLX(spl)
        !           352: 
        !           353: #define PMAP_READ_LOCK(pmap, spl)      SPLVM(spl)
        !           354: #define PMAP_WRITE_LOCK(spl)           SPLVM(spl)
        !           355: #define PMAP_READ_UNLOCK(pmap, spl)    SPLX(spl)
        !           356: #define PMAP_WRITE_UNLOCK(spl)         SPLX(spl)
        !           357: #define PMAP_WRITE_TO_READ_LOCK(pmap)
        !           358: 
        !           359: #define LOCK_PVH(index)
        !           360: #define UNLOCK_PVH(index)
        !           361: 
        !           362: #define PMAP_UPDATE_TLBS(pmap, s, e) { \
        !           363:        /* invalidate our own TLB if pmap is in use */ \
        !           364:        if ((pmap)->cpus_using) { \
        !           365:            INVALIDATE_TLB((s), (e)); \
        !           366:        } \
        !           367: }
        !           368: 
        !           369: #endif /* NCPUS > 1 */
        !           370: 
        !           371: #define MAX_TBIS_SIZE  32              /* > this -> TBIA */ /* XXX */
        !           372: 
        !           373: static inline void
        !           374: INVALIDATE_TLB(vm_offset_t start, vm_offset_t end)
        !           375: {
        !           376:   if (base_cpuid.family != CPU_FAMILY_386 /* 486 or greater only */
        !           377:       && end - start < VM_MAX_ADDRESS - VM_MIN_ADDRESS)        /* if not whole TLB */
        !           378:     {
        !           379:       /* Later x86 processors can invalidate individual TLB entries
        !           380:         one page at a time.  (We don't bother with this if we are
        !           381:         invalidating the whole TLB anyway.) XXX do this anyway
        !           382:         if we don't have PGE?
        !           383: 
        !           384:         This requires addressing the page in a kernel-mode instruction
        !           385:         here, so we must compute from the linear addresses to kernel
        !           386:         segment offsets.  Our loop then is in addresses relative to the
        !           387:         kernel segmentation, which will start high and wrap around to zero
        !           388:         at VM_MAX_ADDRESS.  So a test of S < E would not work!
        !           389: 
        !           390:         XXX I saw all manner of inexplicable weirdness when I tried to
        !           391:         enable this code.  I even thought I had it reliably working for
        !           392:         a while by inserting some nop's, but then I couldn't reproduce that.
        !           393:         This was on an Intel Pentium (100MHz).  Your mileage may vary. --rm
        !           394:       */
        !           395:       oskit_addr_t s, e;
        !           396:       for (s = lintokv (start), e = lintokv (end);
        !           397:           s != e;              /* note we wrap around zero! */
        !           398:           s += PAGE_SIZE) {
        !           399:        asm volatile ("invlpg %0" : : "m" (*(int *) s));
        !           400:        asm volatile ("invlpg %0" : : "m" (*(int *) kvtolin(s))); /* XXX ??? */
        !           401:       }
        !           402:     }
        !           403:   else
        !           404:     /* This is the only option on the 386, and we use it on later
        !           405:        processors as well when flushing all user-space mappings.
        !           406:        Note that if PGE is supported, this does not flush TLB entries
        !           407:        marked global (kernel-space mappings).  Those mappings must be
        !           408:        flushed with invlpg.  Any kernel-space mapping change will call here
        !           409:        to flush just the affected pages, and hit the invplg case above.  */
        !           410:     inval_tlb ();
        !           411: }
        !           412: 
        !           413: 
        !           414: #if    NCPUS > 1
        !           415: /*
        !           416:  *     Structures to keep track of pending TLB invalidations
        !           417:  */
        !           418: 
        !           419: #define UPDATE_LIST_SIZE       4
        !           420: 
        !           421: struct pmap_update_item {
        !           422:        pmap_t          pmap;           /* pmap to invalidate */
        !           423:        vm_offset_t     start;          /* start address to invalidate */
        !           424:        vm_offset_t     end;            /* end address to invalidate */
        !           425: } ;
        !           426: 
        !           427: typedef        struct pmap_update_item *pmap_update_item_t;
        !           428: 
        !           429: /*
        !           430:  *     List of pmap updates.  If the list overflows,
        !           431:  *     the last entry is changed to invalidate all.
        !           432:  */
        !           433: struct pmap_update_list {
        !           434:        decl_simple_lock_data(, lock)
        !           435:        int                     count;
        !           436:        struct pmap_update_item item[UPDATE_LIST_SIZE];
        !           437: } ;
        !           438: typedef        struct pmap_update_list *pmap_update_list_t;
        !           439: 
        !           440: struct pmap_update_list        cpu_update_list[NCPUS];
        !           441: 
        !           442: #endif /* NCPUS > 1 */
        !           443: 
        !           444: /*
        !           445:  *     Other useful macros.
        !           446:  */
        !           447: #define current_pmap()         (vm_map_pmap(current_thread()->task->map))
        !           448: #define pmap_in_use(pmap, cpu) (((pmap)->cpus_using & (1 << (cpu))) != 0)
        !           449: 
        !           450: struct pmap    kernel_pmap_store;
        !           451: pmap_t         kernel_pmap;
        !           452: 
        !           453: struct zone    *pmap_zone;             /* zone of pmap structures */
        !           454: 
        !           455: int            pmap_debug = 0;         /* flag for debugging prints */
        !           456: 
        !           457: #if 0
        !           458: int            ptes_per_vm_page;       /* number of hardware ptes needed
        !           459:                                           to map one VM page. */
        !           460: #else
        !           461: #define                ptes_per_vm_page        1
        !           462: #endif
        !           463: 
        !           464: unsigned int   inuse_ptepages_count = 0;       /* debugging */
        !           465: 
        !           466: extern char end;
        !           467: 
        !           468: /*
        !           469:  * Pointer to the basic page directory for the kernel.
        !           470:  * Initialized by pmap_bootstrap().
        !           471:  */
        !           472: pt_entry_t *kernel_page_dir;
        !           473: 
        !           474: void pmap_remove_range();      /* forward */
        !           475: #if    NCPUS > 1
        !           476: void signal_cpus();            /* forward */
        !           477: #endif /* NCPUS > 1 */
        !           478: 
        !           479: #if    i860
        !           480: /*
        !           481:  * Paging flag
        !           482:  */
        !           483: int             paging_enabled = 0;
        !           484: #endif
        !           485: 
        !           486: static inline pt_entry_t *
        !           487: pmap_pde(pmap_t pmap, vm_offset_t addr)
        !           488: {
        !           489:        if (pmap == kernel_pmap)
        !           490:                addr = kvtolin(addr);
        !           491:        return &pmap->dirbase[lin2pdenum(addr)];
        !           492: }
        !           493: 
        !           494: /*
        !           495:  *     Given an offset and a map, compute the address of the
        !           496:  *     pte.  If the address is invalid with respect to the map
        !           497:  *     then PT_ENTRY_NULL is returned (and the map may need to grow).
        !           498:  *
        !           499:  *     This is only used internally.
        !           500:  */
        !           501: pt_entry_t *
        !           502: pmap_pte(pmap_t pmap, vm_offset_t addr)
        !           503: {
        !           504:        pt_entry_t      *ptp;
        !           505:        pt_entry_t      pte;
        !           506: 
        !           507:        if (pmap->dirbase == 0)
        !           508:                return(PT_ENTRY_NULL);
        !           509:        pte = *pmap_pde(pmap, addr);
        !           510:        if ((pte & INTEL_PTE_VALID) == 0)
        !           511:                return(PT_ENTRY_NULL);
        !           512:        ptp = (pt_entry_t *)ptetokv(pte);
        !           513:        return(&ptp[ptenum(addr)]);
        !           514: }
        !           515: 
        !           516: #define DEBUG_PTE_PAGE 0
        !           517: 
        !           518: #if    DEBUG_PTE_PAGE
        !           519: void ptep_check(ptep)
        !           520:        ptep_t  ptep;
        !           521: {
        !           522:        register pt_entry_t     *pte, *epte;
        !           523:        int                     ctu, ctw;
        !           524: 
        !           525:        /* check the use and wired counts */
        !           526:        if (ptep == PTE_PAGE_NULL)
        !           527:                return;
        !           528:        pte = pmap_pte(ptep->pmap, ptep->va);
        !           529:        epte = pte + INTEL_PGBYTES/sizeof(pt_entry_t);
        !           530:        ctu = 0;
        !           531:        ctw = 0;
        !           532:        while (pte < epte) {
        !           533:                if (pte->pfn != 0) {
        !           534:                        ctu++;
        !           535:                        if (pte->wired)
        !           536:                                ctw++;
        !           537:                }
        !           538:                pte += ptes_per_vm_page;
        !           539:        }
        !           540: 
        !           541:        if (ctu != ptep->use_count || ctw != ptep->wired_count) {
        !           542:                printf("use %d wired %d - actual use %d wired %d\n",
        !           543:                        ptep->use_count, ptep->wired_count, ctu, ctw);
        !           544:                panic("pte count");
        !           545:        }
        !           546: }
        !           547: #endif /* DEBUG_PTE_PAGE */
        !           548: 
        !           549: /*
        !           550:  *     Map memory at initialization.  The physical addresses being
        !           551:  *     mapped are not managed and are never unmapped.
        !           552:  *
        !           553:  *     For now, VM is already on, we only need to map the
        !           554:  *     specified memory.
        !           555:  */
        !           556: vm_offset_t pmap_map(virt, start, end, prot)
        !           557:        register vm_offset_t    virt;
        !           558:        register vm_offset_t    start;
        !           559:        register vm_offset_t    end;
        !           560:        register int            prot;
        !           561: {
        !           562:        register int            ps;
        !           563: 
        !           564:        ps = PAGE_SIZE;
        !           565:        while (start < end) {
        !           566:                pmap_enter(kernel_pmap, virt, start, prot, FALSE);
        !           567:                virt += ps;
        !           568:                start += ps;
        !           569:        }
        !           570:        return(virt);
        !           571: }
        !           572: 
        !           573: /*
        !           574:  *     Back-door routine for mapping kernel VM at initialization.
        !           575:  *     Useful for mapping memory outside the range
        !           576:  *     [phys_mem_min, phys_mem_max) (i.e., devices).
        !           577:  *     Otherwise like pmap_map.
        !           578: #if    i860
        !           579:  *      Sets no-cache bit.
        !           580: #endif
        !           581:  */
        !           582: vm_offset_t pmap_map_bd(virt, start, end, prot)
        !           583:        register vm_offset_t    virt;
        !           584:        register vm_offset_t    start;
        !           585:        register vm_offset_t    end;
        !           586:        vm_prot_t               prot;
        !           587: {
        !           588:        register pt_entry_t     template;
        !           589:        register pt_entry_t     *pte;
        !           590: 
        !           591:        template = pa_to_pte(start)
        !           592: #if    i860
        !           593:                | INTEL_PTE_NCACHE
        !           594: #endif
        !           595:                | INTEL_PTE_VALID;
        !           596:        if (prot & VM_PROT_WRITE)
        !           597:            template |= INTEL_PTE_WRITE;
        !           598: 
        !           599:        while (start < end) {
        !           600:                pte = pmap_pte(kernel_pmap, virt);
        !           601:                if (pte == PT_ENTRY_NULL)
        !           602:                        panic("pmap_map_bd: Invalid kernel address\n");
        !           603:                WRITE_PTE_FAST(pte, template)
        !           604:                pte_increment_pa(template);
        !           605:                virt += PAGE_SIZE;
        !           606:                start += PAGE_SIZE;
        !           607:        }
        !           608:        return(virt);
        !           609: }
        !           610: 
        !           611: static pt_entry_t kernel_pte_global;
        !           612: 
        !           613: /*
        !           614:  *     Bootstrap the system enough to run with virtual memory.
        !           615:  *     Allocate the kernel page directory and page tables,
        !           616:  *     and direct-map all physical memory.
        !           617:  *     Called with mapping off.
        !           618:  */
        !           619: void pmap_bootstrap()
        !           620: {
        !           621:        /*
        !           622:         * Mapping is turned off; we must reference only physical addresses.
        !           623:         * The load image of the system is to be mapped 1-1 physical = virtual.
        !           624:         */
        !           625: 
        !           626:        /*
        !           627:         *      Set ptes_per_vm_page for general use.
        !           628:         */
        !           629: #if 0
        !           630:        ptes_per_vm_page = PAGE_SIZE / INTEL_PGBYTES;
        !           631: #endif
        !           632: 
        !           633:        /*
        !           634:         *      The kernel's pmap is statically allocated so we don't
        !           635:         *      have to use pmap_create, which is unlikely to work
        !           636:         *      correctly at this part of the boot sequence.
        !           637:         */
        !           638: 
        !           639:        kernel_pmap = &kernel_pmap_store;
        !           640: 
        !           641: #if    NCPUS > 1
        !           642:        lock_init(&pmap_system_lock, FALSE);    /* NOT a sleep lock */
        !           643: #endif /* NCPUS > 1 */
        !           644: 
        !           645:        simple_lock_init(&kernel_pmap->lock);
        !           646: 
        !           647:        kernel_pmap->ref_count = 1;
        !           648: 
        !           649:        /*
        !           650:         * Determine the kernel virtual address range.
        !           651:         * It starts at the end of the physical memory
        !           652:         * mapped into the kernel address space,
        !           653:         * and extends to a stupid arbitrary limit beyond that.
        !           654:         */
        !           655:        kernel_virtual_start = phys_mem_max;
        !           656:        kernel_virtual_end = phys_mem_max + morevm;
        !           657: 
        !           658:        /*
        !           659:         * Allocate and clear a kernel page directory.
        !           660:         */
        !           661:        kernel_pmap->dirbase = kernel_page_dir = (pt_entry_t*)pmap_grab_page();
        !           662:        {
        !           663:                int i;
        !           664:                for (i = 0; i < NPDES; i++)
        !           665:                        kernel_pmap->dirbase[i] = 0;
        !           666:        }
        !           667: 
        !           668:        if (base_cpuid.feature_flags & CPUF_PAGE_GLOBAL_EXT) {
        !           669:          /*
        !           670:           * The processor supports the "global" bit to avoid flushing
        !           671:           * kernel TLB entries, if we turn it on.
        !           672:           */
        !           673:          kernel_pte_global = INTEL_PTE_GLOBAL;
        !           674:        }
        !           675: 
        !           676:        /*
        !           677:         * Allocate and set up the kernel page tables.
        !           678:         */
        !           679:        {
        !           680:                vm_offset_t va;
        !           681: 
        !           682:                /*
        !           683:                 * Map virtual memory for all known physical memory, 1-1,
        !           684:                 * from phys_mem_min to phys_mem_max.
        !           685:                 * Make any mappings completely in the kernel's text segment read-only.
        !           686:                 *
        !           687:                 * Also allocate some additional all-null page tables afterwards
        !           688:                 * for kernel virtual memory allocation,
        !           689:                 * because this PMAP module is too stupid
        !           690:                 * to allocate new kernel page tables later.
        !           691:                 * XX fix this
        !           692:                 */
        !           693:                for (va = phys_mem_min; va < phys_mem_max + morevm; )
        !           694:                {
        !           695:                        pt_entry_t *pde = kernel_page_dir + lin2pdenum(kvtolin(va));
        !           696:                        pt_entry_t *ptable = (pt_entry_t*)pmap_grab_page();
        !           697:                        pt_entry_t *pte;
        !           698:                        vm_offset_t pteva;
        !           699: 
        !           700:                        /* Initialize the page directory entry.  */
        !           701:                        *pde = (pa_to_pte((vm_offset_t)ptable)
        !           702:                                | INTEL_PTE_VALID | INTEL_PTE_WRITE
        !           703:                                | kernel_pte_global);
        !           704: 
        !           705:                        /* Initialize the page table.  */
        !           706:                        for (pte = ptable; (va < phys_mem_max) && (pte < ptable+NPTES); pte++)
        !           707:                        {
        !           708:                          pt_entry_t entry = kernel_pte_global;
        !           709:                          if ((pte - ptable) < ptenum(va))
        !           710:                            entry |= 0; /* nada */
        !           711:                          else
        !           712:                            {
        !           713:                              extern char _start[], etext[];
        !           714: 
        !           715:                              entry |= pa_to_pte(va) | INTEL_PTE_VALID;
        !           716:                              if ((va < (vm_offset_t)_start)
        !           717:                                  || (va + INTEL_PGBYTES > (vm_offset_t)etext))
        !           718:                                entry |= INTEL_PTE_WRITE;
        !           719:                              va += INTEL_PGBYTES;
        !           720:                            }
        !           721:                          WRITE_PTE_FAST(pte, entry);
        !           722:                        }
        !           723:                        for (; pte < ptable+NPTES; pte++)
        !           724:                        {
        !           725:                                WRITE_PTE_FAST(pte, kernel_pte_global);
        !           726:                                va += INTEL_PGBYTES;
        !           727:                        }
        !           728:                }
        !           729:        }
        !           730: 
        !           731: #if    i860
        !           732: #error probably doesnt work anymore
        !           733:        XXX move to architecture-specific code just after the pmap_bootstrap call.
        !           734: 
        !           735:        /* kvtophys should now work in phys range */
        !           736: 
        !           737:        /*
        !           738:         * Mark page table pages non-cacheable
        !           739:         */
        !           740: 
        !           741:        pt_pte = (pt_entry_t *)pte_to_pa(*(kpde + pdenum(sva))) + ptenum(sva);
        !           742: 
        !           743:        for (va = load_start; va < tva; va += INTEL_PGBYTES*NPTES) {
        !           744:                /* Mark page table non-cacheable */
        !           745:                *pt_pte |= INTEL_PTE_NCACHE;
        !           746:                pt_pte++;
        !           747:        }
        !           748: 
        !           749:        /*
        !           750:         * Map I/O space
        !           751:         */
        !           752: 
        !           753:        ppde = kpde;
        !           754:        ppde += pdenum(IO_BASE);
        !           755: 
        !           756:        if (pte_to_pa(*ppde) == 0) {
        !           757:                /* This pte has not been allocated */
        !           758:                ppte = (pt_entry_t *)kvtophys(virtual_avail);
        !           759:                ptend = ppte + NPTES;
        !           760:                virtual_avail = phystokv((vm_offset_t)ptend);
        !           761:                *ppde = pa_to_pte((vm_offset_t)ppte)
        !           762:                        | INTEL_PTE_VALID
        !           763:                        | INTEL_PTE_WRITE;
        !           764:                pte = ptend;
        !           765: 
        !           766:                /* Mark page table non-cacheable */
        !           767:                *pt_pte |= INTEL_PTE_NCACHE;
        !           768:                pt_pte++;
        !           769: 
        !           770:                bzero((char *)ppte, INTEL_PGBYTES);
        !           771:        } else {
        !           772:                ppte = (pt_entry_t *)(*ppde);   /* first pte of page */
        !           773:        }
        !           774:        *ppde |= INTEL_PTE_USER;
        !           775: 
        !           776: 
        !           777:        WRITE_PTE(ppte + ptenum(FIFO_ADDR),
        !           778:                  pa_to_pte(FIFO_ADDR_PH)
        !           779:                | INTEL_PTE_VALID | INTEL_PTE_WRITE | INTEL_PTE_NCACHE);
        !           780: 
        !           781:        WRITE_PTE(ppte + ptenum(FIFO_ADDR + XEOD_OFF),
        !           782:                  pa_to_pte(FIFO_ADDR_PH + XEOD_OFF_PH)
        !           783:                | INTEL_PTE_VALID | INTEL_PTE_WRITE | INTEL_PTE_NCACHE);
        !           784: 
        !           785: /* XXX Allowed user access to control reg - cfj */
        !           786:        WRITE_PTE(ppte + ptenum(CSR_ADDR),
        !           787:                  pa_to_pte(CSR_ADDR_PH)
        !           788:                | INTEL_PTE_VALID | INTEL_PTE_WRITE | INTEL_PTE_NCACHE | INTEL_PTE_USER);
        !           789: 
        !           790: /* XXX Allowed user access to perf reg - cfj */
        !           791:        WRITE_PTE(ppte + ptenum(PERFCNT_ADDR),
        !           792:                  pa_to_pte(PERFCNT_ADDR_PH)
        !           793:                | INTEL_PTE_VALID | INTEL_PTE_USER | INTEL_PTE_NCACHE | INTEL_PTE_USER);
        !           794: 
        !           795:        WRITE_PTE(ppte + ptenum(UART_ADDR),
        !           796:                  pa_to_pte(UART_ADDR_PH)
        !           797:                | INTEL_PTE_VALID | INTEL_PTE_WRITE | INTEL_PTE_NCACHE);
        !           798: 
        !           799:        WRITE_PTE(ppte + ptenum(0xFFFFF000),
        !           800:                  pa_to_pte(avail_end)
        !           801:                | INTEL_PTE_VALID | INTEL_PTE_WRITE);
        !           802:        avail_start = kvtophys(virtual_avail);
        !           803: 
        !           804: /*
        !           805:  *     Turn on mapping
        !           806:  */
        !           807: 
        !           808:        flush_and_ctxsw(kernel_pmap->dirbase);
        !           809:        paging_enabled = 1;
        !           810: 
        !           811:        printf("Paging enabled.\n");
        !           812: #endif
        !           813: 
        !           814:        /* Architecture-specific code will turn on paging
        !           815:           soon after we return from here.  */
        !           816: }
        !           817: 
        !           818: void pmap_virtual_space(startp, endp)
        !           819:        vm_offset_t *startp;
        !           820:        vm_offset_t *endp;
        !           821: {
        !           822:        *startp = kernel_virtual_start;
        !           823:        *endp = kernel_virtual_end;
        !           824: }
        !           825: 
        !           826: /*
        !           827:  *     Initialize the pmap module.
        !           828:  *     Called by vm_init, to initialize any structures that the pmap
        !           829:  *     system needs to map virtual memory.
        !           830:  */
        !           831: void pmap_init()
        !           832: {
        !           833:        register long           npages;
        !           834:        vm_offset_t             addr;
        !           835:        register vm_size_t      s;
        !           836:        int                     i;
        !           837: 
        !           838:        /*
        !           839:         *      Allocate memory for the pv_head_table and its lock bits,
        !           840:         *      the modify bit array, and the pte_page table.
        !           841:         */
        !           842: 
        !           843:        npages = atop(phys_mem_max - phys_mem_min);
        !           844:        s = (vm_size_t) (sizeof(struct pv_entry) * npages
        !           845:                                + pv_lock_table_size(npages)
        !           846:                                + npages);
        !           847: 
        !           848:        s = round_page(s);
        !           849:        if (kmem_alloc_wired(kernel_map, &addr, s) != KERN_SUCCESS)
        !           850:                panic("pmap_init");
        !           851:        bzero((char *) addr, s);
        !           852: 
        !           853:        /*
        !           854:         *      Allocate the structures first to preserve word-alignment.
        !           855:         */
        !           856:        pv_head_table = (pv_entry_t) addr;
        !           857:        addr = (vm_offset_t) (pv_head_table + npages);
        !           858: 
        !           859:        pv_lock_table = (char *) addr;
        !           860:        addr = (vm_offset_t) (pv_lock_table + pv_lock_table_size(npages));
        !           861: 
        !           862:        pmap_phys_attributes = (char *) addr;
        !           863: 
        !           864:        /*
        !           865:         *      Create the zone of physical maps,
        !           866:         *      and of the physical-to-virtual entries.
        !           867:         */
        !           868:        s = (vm_size_t) sizeof(struct pmap);
        !           869:        pmap_zone = zinit(s, 400*s, 4096, 0, "pmap"); /* XXX */
        !           870:        s = (vm_size_t) sizeof(struct pv_entry);
        !           871:        pv_list_zone = zinit(s, 10000*s, 4096, 0, "pv_list"); /* XXX */
        !           872: 
        !           873: #if    NCPUS > 1
        !           874:        /*
        !           875:         *      Set up the pmap request lists
        !           876:         */
        !           877:        for (i = 0; i < NCPUS; i++) {
        !           878:            pmap_update_list_t  up = &cpu_update_list[i];
        !           879: 
        !           880:            simple_lock_init(&up->lock);
        !           881:            up->count = 0;
        !           882:        }
        !           883: #endif /* NCPUS > 1 */
        !           884: 
        !           885:        /*
        !           886:         * Indicate that the PMAP module is now fully initialized.
        !           887:         */
        !           888:        pmap_initialized = TRUE;
        !           889: }
        !           890: 
        !           891: #define valid_page(x) (pmap_initialized && pmap_valid_page(x))
        !           892: 
        !           893: boolean_t pmap_verify_free(phys)
        !           894:        vm_offset_t     phys;
        !           895: {
        !           896:        pv_entry_t      pv_h;
        !           897:        int             pai;
        !           898:        int             spl;
        !           899:        boolean_t       result;
        !           900: 
        !           901:        assert(phys != vm_page_fictitious_addr);
        !           902:        if (!pmap_initialized)
        !           903:                return(TRUE);
        !           904: 
        !           905:        if (!pmap_valid_page(phys))
        !           906:                return(FALSE);
        !           907: 
        !           908:        PMAP_WRITE_LOCK(spl);
        !           909: 
        !           910:        pai = pa_index(phys);
        !           911:        pv_h = pai_to_pvh(pai);
        !           912: 
        !           913:        result = (pv_h->pmap == PMAP_NULL);
        !           914:        PMAP_WRITE_UNLOCK(spl);
        !           915: 
        !           916:        return(result);
        !           917: }
        !           918: 
        !           919: /*
        !           920:  *     Routine:        pmap_page_table_page_alloc
        !           921:  *
        !           922:  *     Allocates a new physical page to be used as a page-table page.
        !           923:  *
        !           924:  *     Must be called with the pmap system and the pmap unlocked,
        !           925:  *     since these must be unlocked to use vm_page_grab.
        !           926:  */
        !           927: vm_offset_t
        !           928: pmap_page_table_page_alloc()
        !           929: {
        !           930:        register vm_page_t      m;
        !           931:        register vm_offset_t    pa;
        !           932: 
        !           933:        check_simple_locks();
        !           934: 
        !           935:        /*
        !           936:         *      We cannot allocate the pmap_object in pmap_init,
        !           937:         *      because it is called before the zone package is up.
        !           938:         *      Allocate it now if it is missing.
        !           939:         */
        !           940:        if (pmap_object == VM_OBJECT_NULL)
        !           941:            pmap_object = vm_object_allocate(phys_mem_max - phys_mem_min);
        !           942: 
        !           943:        /*
        !           944:         *      Allocate a VM page for the level 2 page table entries.
        !           945:         */
        !           946:        while ((m = vm_page_grab(FALSE)) == VM_PAGE_NULL)
        !           947:                VM_PAGE_WAIT((void (*)()) 0);
        !           948: 
        !           949:        /*
        !           950:         *      Map the page to its physical address so that it
        !           951:         *      can be found later.
        !           952:         */
        !           953:        pa = m->phys_addr;
        !           954: debug_unprotect_page(pa);
        !           955:        vm_object_lock(pmap_object);
        !           956:        vm_page_insert(m, pmap_object, pa);
        !           957:        vm_page_lock_queues();
        !           958:        vm_page_wire(m);
        !           959:        inuse_ptepages_count++;
        !           960:        vm_page_unlock_queues();
        !           961:        vm_object_unlock(pmap_object);
        !           962: 
        !           963: #if    i860
        !           964:        /*
        !           965:         *      Mark the page table page(s) non-cacheable.
        !           966:         */
        !           967:        {
        !           968:            int         i = ptes_per_vm_page;
        !           969:            pt_entry_t  *pdp;
        !           970: 
        !           971:            pdp = pmap_pte(kernel_pmap, pa);
        !           972:            do {
        !           973:                *pdp |= INTEL_PTE_NCACHE;
        !           974:                pdp++;
        !           975:            } while (--i > 0);
        !           976:        }
        !           977: #endif
        !           978:        return pa;
        !           979: }
        !           980: 
        !           981: /*
        !           982:  *     Deallocate a page-table page.
        !           983:  *     The page-table page must have all mappings removed,
        !           984:  *     and be removed from its page directory.
        !           985:  */
        !           986: void
        !           987: pmap_page_table_page_dealloc(pa)
        !           988:        vm_offset_t     pa;
        !           989: {
        !           990:        vm_page_t       m;
        !           991: 
        !           992:        vm_object_lock(pmap_object);
        !           993:        m = vm_page_lookup(pmap_object, pa);
        !           994:        vm_page_lock_queues();
        !           995:        vm_page_free(m);
        !           996:        inuse_ptepages_count--;
        !           997:        vm_page_unlock_queues();
        !           998:        vm_object_unlock(pmap_object);
        !           999: }
        !          1000: 
        !          1001: /*
        !          1002:  *     Create and return a physical map.
        !          1003:  *
        !          1004:  *     If the size specified for the map
        !          1005:  *     is zero, the map is an actual physical
        !          1006:  *     map, and may be referenced by the
        !          1007:  *     hardware.
        !          1008:  *
        !          1009:  *     If the size specified is non-zero,
        !          1010:  *     the map will be used in software only, and
        !          1011:  *     is bounded by that size.
        !          1012:  */
        !          1013: pmap_t pmap_create(size)
        !          1014:        vm_size_t       size;
        !          1015: {
        !          1016:        register pmap_t                 p;
        !          1017:        register pmap_statistics_t      stats;
        !          1018: 
        !          1019:        /*
        !          1020:         *      A software use-only map doesn't even need a map.
        !          1021:         */
        !          1022: 
        !          1023:        if (size != 0) {
        !          1024:                return(PMAP_NULL);
        !          1025:        }
        !          1026: 
        !          1027: /*
        !          1028:  *     Allocate a pmap struct from the pmap_zone.  Then allocate
        !          1029:  *     the page descriptor table from the pd_zone.
        !          1030:  */
        !          1031: 
        !          1032:        p = (pmap_t) zalloc(pmap_zone);
        !          1033:        if (p == PMAP_NULL)
        !          1034:                panic("pmap_create");
        !          1035: 
        !          1036:        /* This gets a physical page with a direct-mapped address,
        !          1037:           rather than assigning a new kernel virtual address.
        !          1038:           This saves us having to do the translation at task-switch time.  */
        !          1039:        p->dirbase = (pt_entry_t *) phystokv(pmap_page_table_page_alloc());
        !          1040: #if 0
        !          1041:        if (kmem_alloc_wired(kernel_map,
        !          1042:                             (vm_offset_t *)&p->dirbase, INTEL_PGBYTES)
        !          1043:                                                        != KERN_SUCCESS)
        !          1044:                panic("pmap_create");
        !          1045: #endif
        !          1046: 
        !          1047:        bcopy(kernel_page_dir, p->dirbase, INTEL_PGBYTES);
        !          1048:        p->ref_count = 1;
        !          1049: 
        !          1050:        simple_lock_init(&p->lock);
        !          1051:        p->cpus_using = 0;
        !          1052: 
        !          1053:        /*
        !          1054:         *      Initialize statistics.
        !          1055:         */
        !          1056: 
        !          1057:        stats = &p->stats;
        !          1058:        stats->resident_count = 0;
        !          1059:        stats->wired_count = 0;
        !          1060: 
        !          1061:        return(p);
        !          1062: }
        !          1063: 
        !          1064: /*
        !          1065:  *     Retire the given physical map from service.
        !          1066:  *     Should only be called if the map contains
        !          1067:  *     no valid mappings.
        !          1068:  */
        !          1069: 
        !          1070: void pmap_destroy(p)
        !          1071:        register pmap_t p;
        !          1072: {
        !          1073:        register pt_entry_t     *pdep;
        !          1074:        register vm_offset_t    pa;
        !          1075:        register int            c, s;
        !          1076:        register vm_page_t      m;
        !          1077: 
        !          1078:        if (p == PMAP_NULL)
        !          1079:                return;
        !          1080: 
        !          1081:        SPLVM(s);
        !          1082:        simple_lock(&p->lock);
        !          1083:        c = --p->ref_count;
        !          1084:        simple_unlock(&p->lock);
        !          1085:        SPLX(s);
        !          1086: 
        !          1087:        if (c != 0) {
        !          1088:            return;     /* still in use */
        !          1089:        }
        !          1090: 
        !          1091:        /*
        !          1092:         *      Free the memory maps, then the
        !          1093:         *      pmap structure.
        !          1094:         */
        !          1095:        for (pdep = p->dirbase;
        !          1096:             pdep < &p->dirbase[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
        !          1097:             pdep += ptes_per_vm_page) {
        !          1098:            if (*pdep & INTEL_PTE_VALID) {
        !          1099:                pa = pte_to_pa(*pdep);
        !          1100:                vm_object_lock(pmap_object);
        !          1101:                m = vm_page_lookup(pmap_object, pa);
        !          1102:                if (m == VM_PAGE_NULL)
        !          1103:                    panic("pmap_destroy: pte page not in object");
        !          1104:                vm_page_lock_queues();
        !          1105:                vm_page_free(m);
        !          1106:                inuse_ptepages_count--;
        !          1107:                vm_page_unlock_queues();
        !          1108:                vm_object_unlock(pmap_object);
        !          1109:            }
        !          1110:        }
        !          1111:        /* See comment in pmap_create.  */
        !          1112:        pmap_page_table_page_dealloc(kvtophys(p->dirbase));
        !          1113: #if 0
        !          1114:        kmem_free(kernel_map, p->dirbase, INTEL_PGBYTES);
        !          1115: #endif
        !          1116:        zfree(pmap_zone, (vm_offset_t) p);
        !          1117: }
        !          1118: 
        !          1119: /*
        !          1120:  *     Add a reference to the specified pmap.
        !          1121:  */
        !          1122: 
        !          1123: void pmap_reference(p)
        !          1124:        register pmap_t p;
        !          1125: {
        !          1126:        int     s;
        !          1127:        if (p != PMAP_NULL) {
        !          1128:                SPLVM(s);
        !          1129:                simple_lock(&p->lock);
        !          1130:                p->ref_count++;
        !          1131:                simple_unlock(&p->lock);
        !          1132:                SPLX(s);
        !          1133:        }
        !          1134: }
        !          1135: 
        !          1136: /*
        !          1137:  *     Remove a range of hardware page-table entries.
        !          1138:  *     The entries given are the first (inclusive)
        !          1139:  *     and last (exclusive) entries for the VM pages.
        !          1140:  *     The virtual address is the va for the first pte.
        !          1141:  *
        !          1142:  *     The pmap must be locked.
        !          1143:  *     If the pmap is not the kernel pmap, the range must lie
        !          1144:  *     entirely within one pte-page.  This is NOT checked.
        !          1145:  *     Assumes that the pte-page exists.
        !          1146:  */
        !          1147: 
        !          1148: /* static */
        !          1149: void pmap_remove_range(pmap, va, spte, epte)
        !          1150:        pmap_t                  pmap;
        !          1151:        vm_offset_t             va;
        !          1152:        pt_entry_t              *spte;
        !          1153:        pt_entry_t              *epte;
        !          1154: {
        !          1155:        register pt_entry_t     *cpte;
        !          1156:        int                     num_removed, num_unwired;
        !          1157:        int                     pai;
        !          1158:        vm_offset_t             pa;
        !          1159: 
        !          1160: #if    DEBUG_PTE_PAGE
        !          1161:        if (pmap != kernel_pmap)
        !          1162:                ptep_check(get_pte_page(spte));
        !          1163: #endif /* DEBUG_PTE_PAGE */
        !          1164:        num_removed = 0;
        !          1165:        num_unwired = 0;
        !          1166: 
        !          1167:        for (cpte = spte; cpte < epte;
        !          1168:             cpte += ptes_per_vm_page, va += PAGE_SIZE) {
        !          1169: 
        !          1170:            if (*cpte == 0)
        !          1171:                continue;
        !          1172:            pa = pte_to_pa(*cpte);
        !          1173: 
        !          1174:            num_removed++;
        !          1175:            if (*cpte & INTEL_PTE_WIRED)
        !          1176:                num_unwired++;
        !          1177: 
        !          1178:            if (!valid_page(pa)) {
        !          1179: 
        !          1180:                /*
        !          1181:                 *      Outside range of managed physical memory.
        !          1182:                 *      Just remove the mappings.
        !          1183:                 */
        !          1184:                register int    i = ptes_per_vm_page;
        !          1185:                register pt_entry_t     *lpte = cpte;
        !          1186:                do {
        !          1187:                    *lpte = 0;
        !          1188:                    lpte++;
        !          1189:                } while (--i > 0);
        !          1190:                continue;
        !          1191:            }
        !          1192: 
        !          1193:            pai = pa_index(pa);
        !          1194:            LOCK_PVH(pai);
        !          1195: 
        !          1196:            /*
        !          1197:             *  Get the modify and reference bits.
        !          1198:             */
        !          1199:            {
        !          1200:                register int            i;
        !          1201:                register pt_entry_t     *lpte;
        !          1202: 
        !          1203:                i = ptes_per_vm_page;
        !          1204:                lpte = cpte;
        !          1205:                do {
        !          1206:                    pmap_phys_attributes[pai] |=
        !          1207:                        *lpte & (PHYS_MODIFIED|PHYS_REFERENCED);
        !          1208:                    *lpte = 0;
        !          1209:                    lpte++;
        !          1210:                } while (--i > 0);
        !          1211:            }
        !          1212: 
        !          1213:            /*
        !          1214:             *  Remove the mapping from the pvlist for
        !          1215:             *  this physical page.
        !          1216:             */
        !          1217:            {
        !          1218:                register pv_entry_t     pv_h, prev, cur;
        !          1219: 
        !          1220:                pv_h = pai_to_pvh(pai);
        !          1221:                if (pv_h->pmap == PMAP_NULL) {
        !          1222:                    panic("pmap_remove: null pv_list!");
        !          1223:                }
        !          1224:                if (pv_h->va == va && pv_h->pmap == pmap) {
        !          1225:                    /*
        !          1226:                     * Header is the pv_entry.  Copy the next one
        !          1227:                     * to header and free the next one (we cannot
        !          1228:                     * free the header)
        !          1229:                     */
        !          1230:                    cur = pv_h->next;
        !          1231:                    if (cur != PV_ENTRY_NULL) {
        !          1232:                        *pv_h = *cur;
        !          1233:                        PV_FREE(cur);
        !          1234:                    }
        !          1235:                    else {
        !          1236:                        pv_h->pmap = PMAP_NULL;
        !          1237:                    }
        !          1238:                }
        !          1239:                else {
        !          1240:                    cur = pv_h;
        !          1241:                    do {
        !          1242:                        prev = cur;
        !          1243:                        if ((cur = prev->next) == PV_ENTRY_NULL) {
        !          1244:                            panic("pmap-remove: mapping not in pv_list!");
        !          1245:                        }
        !          1246:                    } while (cur->va != va || cur->pmap != pmap);
        !          1247:                    prev->next = cur->next;
        !          1248:                    PV_FREE(cur);
        !          1249:                }
        !          1250:                UNLOCK_PVH(pai);
        !          1251:            }
        !          1252:        }
        !          1253: 
        !          1254:        /*
        !          1255:         *      Update the counts
        !          1256:         */
        !          1257:        pmap->stats.resident_count -= num_removed;
        !          1258:        pmap->stats.wired_count -= num_unwired;
        !          1259: }
        !          1260: 
        !          1261: /*
        !          1262:  *     Remove the given range of addresses
        !          1263:  *     from the specified map.
        !          1264:  *
        !          1265:  *     It is assumed that the start and end are properly
        !          1266:  *     rounded to the hardware page size.
        !          1267:  */
        !          1268: 
        !          1269: void pmap_remove(map, s, e)
        !          1270:        pmap_t          map;
        !          1271:        vm_offset_t     s, e;
        !          1272: {
        !          1273:        int                     spl;
        !          1274:        register pt_entry_t     *pde;
        !          1275:        register pt_entry_t     *spte, *epte;
        !          1276:        vm_offset_t             l;
        !          1277: 
        !          1278:        if (map == PMAP_NULL)
        !          1279:                return;
        !          1280: 
        !          1281:        PMAP_READ_LOCK(map, spl);
        !          1282: 
        !          1283:        /*
        !          1284:         *      Invalidate the translation buffer first
        !          1285:         */
        !          1286:        PMAP_UPDATE_TLBS(map, s, e);
        !          1287: 
        !          1288:        pde = pmap_pde(map, s);
        !          1289:        while (s < e) {
        !          1290:            l = (s + PDE_MAPPED_SIZE) & ~(PDE_MAPPED_SIZE-1);
        !          1291:            if (l > e)
        !          1292:                l = e;
        !          1293:            if (*pde & INTEL_PTE_VALID) {
        !          1294:                spte = (pt_entry_t *)ptetokv(*pde);
        !          1295:                spte = &spte[ptenum(s)];
        !          1296:                epte = &spte[intel_btop(l-s)];
        !          1297:                pmap_remove_range(map, s, spte, epte);
        !          1298:            }
        !          1299:            s = l;
        !          1300:            pde++;
        !          1301:        }
        !          1302: 
        !          1303:        PMAP_READ_UNLOCK(map, spl);
        !          1304: }
        !          1305: 
        !          1306: /*
        !          1307:  *     Routine:        pmap_page_protect
        !          1308:  *
        !          1309:  *     Function:
        !          1310:  *             Lower the permission for all mappings to a given
        !          1311:  *             page.
        !          1312:  */
        !          1313: void pmap_page_protect(phys, prot)
        !          1314:        vm_offset_t     phys;
        !          1315:        vm_prot_t       prot;
        !          1316: {
        !          1317:        pv_entry_t              pv_h, prev;
        !          1318:        register pv_entry_t     pv_e;
        !          1319:        register pt_entry_t     *pte;
        !          1320:        int                     pai;
        !          1321:        register pmap_t         pmap;
        !          1322:        int                     spl;
        !          1323:        boolean_t               remove;
        !          1324: 
        !          1325:        assert(phys != vm_page_fictitious_addr);
        !          1326:        if (!valid_page(phys)) {
        !          1327:            /*
        !          1328:             *  Not a managed page.
        !          1329:             */
        !          1330:            return;
        !          1331:        }
        !          1332: 
        !          1333:        /*
        !          1334:         * Determine the new protection.
        !          1335:         */
        !          1336:        switch (prot) {
        !          1337:            case VM_PROT_READ:
        !          1338:            case VM_PROT_READ|VM_PROT_EXECUTE:
        !          1339:                remove = FALSE;
        !          1340:                break;
        !          1341:            case VM_PROT_ALL:
        !          1342:                return; /* nothing to do */
        !          1343:            default:
        !          1344:                remove = TRUE;
        !          1345:                break;
        !          1346:        }
        !          1347: 
        !          1348:        /*
        !          1349:         *      Lock the pmap system first, since we will be changing
        !          1350:         *      several pmaps.
        !          1351:         */
        !          1352: 
        !          1353:        PMAP_WRITE_LOCK(spl);
        !          1354: 
        !          1355:        pai = pa_index(phys);
        !          1356:        pv_h = pai_to_pvh(pai);
        !          1357: 
        !          1358:        /*
        !          1359:         * Walk down PV list, changing or removing all mappings.
        !          1360:         * We do not have to lock the pv_list because we have
        !          1361:         * the entire pmap system locked.
        !          1362:         */
        !          1363:        if (pv_h->pmap != PMAP_NULL) {
        !          1364: 
        !          1365:            prev = pv_e = pv_h;
        !          1366:            do {
        !          1367:                pmap = pv_e->pmap;
        !          1368:                /*
        !          1369:                 * Lock the pmap to block pmap_extract and similar routines.
        !          1370:                 */
        !          1371:                simple_lock(&pmap->lock);
        !          1372: 
        !          1373:                {
        !          1374:                    register vm_offset_t va;
        !          1375: 
        !          1376:                    va = pv_e->va;
        !          1377:                    pte = pmap_pte(pmap, va);
        !          1378: 
        !          1379:                    /*
        !          1380:                     * Consistency checks.
        !          1381:                     */
        !          1382:                    /* assert(*pte & INTEL_PTE_VALID); XXX */
        !          1383:                    /* assert(pte_to_phys(*pte) == phys); */
        !          1384: 
        !          1385:                    /*
        !          1386:                     * Invalidate TLBs for all CPUs using this mapping.
        !          1387:                     */
        !          1388:                    PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          1389:                }
        !          1390: 
        !          1391:                /*
        !          1392:                 * Remove the mapping if new protection is NONE
        !          1393:                 * or if write-protecting a kernel mapping.
        !          1394:                 */
        !          1395:                if (remove || pmap == kernel_pmap) {
        !          1396:                    /*
        !          1397:                     * Remove the mapping, collecting any modify bits.
        !          1398:                     */
        !          1399:                    if (*pte & INTEL_PTE_WIRED)
        !          1400:                        panic("pmap_remove_all removing a wired page");
        !          1401: 
        !          1402:                    {
        !          1403:                        register int    i = ptes_per_vm_page;
        !          1404: 
        !          1405:                        do {
        !          1406:                            pmap_phys_attributes[pai] |=
        !          1407:                                *pte & (PHYS_MODIFIED|PHYS_REFERENCED);
        !          1408:                            *pte++ = 0;
        !          1409:                        } while (--i > 0);
        !          1410:                    }
        !          1411: 
        !          1412:                    pmap->stats.resident_count--;
        !          1413: 
        !          1414:                    /*
        !          1415:                     * Remove the pv_entry.
        !          1416:                     */
        !          1417:                    if (pv_e == pv_h) {
        !          1418:                        /*
        !          1419:                         * Fix up head later.
        !          1420:                         */
        !          1421:                        pv_h->pmap = PMAP_NULL;
        !          1422:                    }
        !          1423:                    else {
        !          1424:                        /*
        !          1425:                         * Delete this entry.
        !          1426:                         */
        !          1427:                        prev->next = pv_e->next;
        !          1428:                        PV_FREE(pv_e);
        !          1429:                    }
        !          1430:                }
        !          1431:                else {
        !          1432:                    /*
        !          1433:                     * Write-protect.
        !          1434:                     */
        !          1435:                    register int i = ptes_per_vm_page;
        !          1436: 
        !          1437:                    do {
        !          1438:                        *pte &= ~INTEL_PTE_WRITE;
        !          1439:                        pte++;
        !          1440:                    } while (--i > 0);
        !          1441: 
        !          1442:                    /*
        !          1443:                     * Advance prev.
        !          1444:                     */
        !          1445:                    prev = pv_e;
        !          1446:                }
        !          1447: 
        !          1448:                simple_unlock(&pmap->lock);
        !          1449: 
        !          1450:            } while ((pv_e = prev->next) != PV_ENTRY_NULL);
        !          1451: 
        !          1452:            /*
        !          1453:             * If pv_head mapping was removed, fix it up.
        !          1454:             */
        !          1455:            if (pv_h->pmap == PMAP_NULL) {
        !          1456:                pv_e = pv_h->next;
        !          1457:                if (pv_e != PV_ENTRY_NULL) {
        !          1458:                    *pv_h = *pv_e;
        !          1459:                    PV_FREE(pv_e);
        !          1460:                }
        !          1461:            }
        !          1462:        }
        !          1463: 
        !          1464:        PMAP_WRITE_UNLOCK(spl);
        !          1465: }
        !          1466: 
        !          1467: /*
        !          1468:  *     Set the physical protection on the
        !          1469:  *     specified range of this map as requested.
        !          1470:  *     Will not increase permissions.
        !          1471:  */
        !          1472: void pmap_protect(map, s, e, prot)
        !          1473:        pmap_t          map;
        !          1474:        vm_offset_t     s, e;
        !          1475:        vm_prot_t       prot;
        !          1476: {
        !          1477:        register pt_entry_t     *pde;
        !          1478:        register pt_entry_t     *spte, *epte;
        !          1479:        vm_offset_t             l;
        !          1480:        int             spl;
        !          1481: 
        !          1482:        if (map == PMAP_NULL)
        !          1483:                return;
        !          1484: 
        !          1485:        /*
        !          1486:         * Determine the new protection.
        !          1487:         */
        !          1488:        switch (prot) {
        !          1489:            case VM_PROT_READ:
        !          1490:            case VM_PROT_READ|VM_PROT_EXECUTE:
        !          1491:                break;
        !          1492:            case VM_PROT_READ|VM_PROT_WRITE:
        !          1493:            case VM_PROT_ALL:
        !          1494:                return; /* nothing to do */
        !          1495:            default:
        !          1496:                pmap_remove(map, s, e);
        !          1497:                return;
        !          1498:        }
        !          1499: 
        !          1500:        /*
        !          1501:         * If write-protecting in the kernel pmap,
        !          1502:         * remove the mappings; the i386 ignores
        !          1503:         * the write-permission bit in kernel mode.
        !          1504:         *
        !          1505:         * XXX should be #if'd for i386
        !          1506:         */
        !          1507:        if (map == kernel_pmap) {
        !          1508:            pmap_remove(map, s, e);
        !          1509:            return;
        !          1510:        }
        !          1511: 
        !          1512:        SPLVM(spl);
        !          1513:        simple_lock(&map->lock);
        !          1514: 
        !          1515:        /*
        !          1516:         *      Invalidate the translation buffer first
        !          1517:         */
        !          1518:        PMAP_UPDATE_TLBS(map, s, e);
        !          1519: 
        !          1520:        pde = pmap_pde(map, s);
        !          1521:        while (s < e) {
        !          1522:            l = (s + PDE_MAPPED_SIZE) & ~(PDE_MAPPED_SIZE-1);
        !          1523:            if (l > e)
        !          1524:                l = e;
        !          1525:            if (*pde & INTEL_PTE_VALID) {
        !          1526:                spte = (pt_entry_t *)ptetokv(*pde);
        !          1527:                spte = &spte[ptenum(s)];
        !          1528:                epte = &spte[intel_btop(l-s)];
        !          1529: 
        !          1530:                while (spte < epte) {
        !          1531:                    if (*spte & INTEL_PTE_VALID)
        !          1532:                        *spte &= ~INTEL_PTE_WRITE;
        !          1533:                    spte++;
        !          1534:                }
        !          1535:            }
        !          1536:            s = l;
        !          1537:            pde++;
        !          1538:        }
        !          1539: 
        !          1540:        simple_unlock(&map->lock);
        !          1541:        SPLX(spl);
        !          1542: }
        !          1543: 
        !          1544: /*
        !          1545:  *     Insert the given physical page (p) at
        !          1546:  *     the specified virtual address (v) in the
        !          1547:  *     target physical map with the protection requested.
        !          1548:  *
        !          1549:  *     If specified, the page will be wired down, meaning
        !          1550:  *     that the related pte can not be reclaimed.
        !          1551:  *
        !          1552:  *     NB:  This is the only routine which MAY NOT lazy-evaluate
        !          1553:  *     or lose information.  That is, this routine must actually
        !          1554:  *     insert this page into the given map NOW.
        !          1555:  */
        !          1556: void pmap_enter(pmap, v, pa, prot, wired)
        !          1557:        register pmap_t         pmap;
        !          1558:        vm_offset_t             v;
        !          1559:        register vm_offset_t    pa;
        !          1560:        vm_prot_t               prot;
        !          1561:        boolean_t               wired;
        !          1562: {
        !          1563:        register pt_entry_t     *pte;
        !          1564:        register pv_entry_t     pv_h;
        !          1565:        register int            i, pai;
        !          1566:        pv_entry_t              pv_e;
        !          1567:        pt_entry_t              template;
        !          1568:        int                     spl;
        !          1569:        vm_offset_t             old_pa;
        !          1570: 
        !          1571:        assert(pa != vm_page_fictitious_addr);
        !          1572: if (pmap_debug) printf("pmap(%x, %x)\n", v, pa);
        !          1573:        if (pmap == PMAP_NULL)
        !          1574:                return;
        !          1575: 
        !          1576:        if (pmap == kernel_pmap && (prot & VM_PROT_WRITE) == 0
        !          1577:            && !wired /* hack for io_wire */ ) {
        !          1578:            /*
        !          1579:             *  Because the 386 ignores write protection in kernel mode,
        !          1580:             *  we cannot enter a read-only kernel mapping, and must
        !          1581:             *  remove an existing mapping if changing it.
        !          1582:             *
        !          1583:             *  XXX should be #if'd for i386
        !          1584:             */
        !          1585:            PMAP_READ_LOCK(pmap, spl);
        !          1586: 
        !          1587:            pte = pmap_pte(pmap, v);
        !          1588:            if (pte != PT_ENTRY_NULL && *pte != 0) {
        !          1589:                /*
        !          1590:                 *      Invalidate the translation buffer,
        !          1591:                 *      then remove the mapping.
        !          1592:                 */
        !          1593:                PMAP_UPDATE_TLBS(pmap, v, v + PAGE_SIZE);
        !          1594:                pmap_remove_range(pmap, v, pte,
        !          1595:                                  pte + ptes_per_vm_page);
        !          1596:            }
        !          1597:            PMAP_READ_UNLOCK(pmap, spl);
        !          1598:            return;
        !          1599:        }
        !          1600: 
        !          1601:        /*
        !          1602:         *      Must allocate a new pvlist entry while we're unlocked;
        !          1603:         *      zalloc may cause pageout (which will lock the pmap system).
        !          1604:         *      If we determine we need a pvlist entry, we will unlock
        !          1605:         *      and allocate one.  Then we will retry, throughing away
        !          1606:         *      the allocated entry later (if we no longer need it).
        !          1607:         */
        !          1608:        pv_e = PV_ENTRY_NULL;
        !          1609: Retry:
        !          1610:        PMAP_READ_LOCK(pmap, spl);
        !          1611: 
        !          1612:        /*
        !          1613:         *      Expand pmap to include this pte.  Assume that
        !          1614:         *      pmap is always expanded to include enough hardware
        !          1615:         *      pages to map one VM page.
        !          1616:         */
        !          1617: 
        !          1618:        while ((pte = pmap_pte(pmap, v)) == PT_ENTRY_NULL) {
        !          1619:            /*
        !          1620:             * Need to allocate a new page-table page.
        !          1621:             */
        !          1622:            vm_offset_t ptp;
        !          1623:            pt_entry_t  *pdp;
        !          1624:            int         i;
        !          1625: 
        !          1626:            if (pmap == kernel_pmap) {
        !          1627:                /*
        !          1628:                 * Would have to enter the new page-table page in
        !          1629:                 * EVERY pmap.
        !          1630:                 */
        !          1631:                panic("pmap_expand kernel pmap to %#x", v);
        !          1632:            }
        !          1633: 
        !          1634:            /*
        !          1635:             * Unlock the pmap and allocate a new page-table page.
        !          1636:             */
        !          1637:            PMAP_READ_UNLOCK(pmap, spl);
        !          1638: 
        !          1639:            ptp = pmap_page_table_page_alloc();
        !          1640:            /*
        !          1641:             *  Zero the page.
        !          1642:             */
        !          1643:            bzero(phystokv(ptp), PAGE_SIZE);
        !          1644: 
        !          1645:            /*
        !          1646:             * Re-lock the pmap and check that another thread has
        !          1647:             * not already allocated the page-table page.  If it
        !          1648:             * has, discard the new page-table page (and try
        !          1649:             * again to make sure).
        !          1650:             */
        !          1651:            PMAP_READ_LOCK(pmap, spl);
        !          1652: 
        !          1653:            if (pmap_pte(pmap, v) != PT_ENTRY_NULL) {
        !          1654:                /*
        !          1655:                 * Oops...
        !          1656:                 */
        !          1657:                PMAP_READ_UNLOCK(pmap, spl);
        !          1658:                pmap_page_table_page_dealloc(ptp);
        !          1659:                PMAP_READ_LOCK(pmap, spl);
        !          1660:                continue;
        !          1661:            }
        !          1662: 
        !          1663:            /*
        !          1664:             * Enter the new page table page in the page directory.
        !          1665:             */
        !          1666:            i = ptes_per_vm_page;
        !          1667:            /*XX pdp = &pmap->dirbase[pdenum(v) & ~(i-1)];*/
        !          1668:            pdp = pmap_pde(pmap, v);
        !          1669:            do {
        !          1670:                *pdp = pa_to_pte(ptp) | INTEL_PTE_VALID
        !          1671:                                      | INTEL_PTE_USER
        !          1672:                                      | INTEL_PTE_WRITE;
        !          1673:                pdp++;
        !          1674:                ptp += INTEL_PGBYTES;
        !          1675:            } while (--i > 0);
        !          1676: #if    i860
        !          1677:            /*
        !          1678:             * Flush the data cache.
        !          1679:             */
        !          1680:            flush();
        !          1681: #endif /* i860 */
        !          1682: 
        !          1683:            /*
        !          1684:             * Now, get the address of the page-table entry.
        !          1685:             */
        !          1686:            continue;
        !          1687:        }
        !          1688: 
        !          1689:        template = pmap == kernel_pmap ? kernel_pte_global : 0;
        !          1690: 
        !          1691:        /*
        !          1692:         *      Special case if the physical page is already mapped
        !          1693:         *      at this address.
        !          1694:         */
        !          1695:        old_pa = pte_to_pa(*pte);
        !          1696:        if (*pte && old_pa == pa) {
        !          1697:            /*
        !          1698:             *  May be changing its wired attribute or protection
        !          1699:             */
        !          1700: 
        !          1701:            if (wired && !(*pte & INTEL_PTE_WIRED))
        !          1702:                pmap->stats.wired_count++;
        !          1703:            else if (!wired && (*pte & INTEL_PTE_WIRED))
        !          1704:                pmap->stats.wired_count--;
        !          1705: 
        !          1706:            template |= pa_to_pte(pa) | INTEL_PTE_VALID;
        !          1707:            if (pmap != kernel_pmap)
        !          1708:                template |= INTEL_PTE_USER;
        !          1709:            if (prot & VM_PROT_WRITE)
        !          1710:                template |= INTEL_PTE_WRITE;
        !          1711:            if (wired)
        !          1712:                template |= INTEL_PTE_WIRED;
        !          1713:            PMAP_UPDATE_TLBS(pmap, v, v + PAGE_SIZE);
        !          1714:            i = ptes_per_vm_page;
        !          1715:            do {
        !          1716:                if (*pte & INTEL_PTE_MOD)
        !          1717:                    template |= INTEL_PTE_MOD;
        !          1718:                WRITE_PTE(pte, template)
        !          1719:                pte++;
        !          1720:                pte_increment_pa(template);
        !          1721:            } while (--i > 0);
        !          1722:        }
        !          1723:        else {
        !          1724: 
        !          1725:            /*
        !          1726:             *  Remove old mapping from the PV list if necessary.
        !          1727:             */
        !          1728:            if (*pte) {
        !          1729:                /*
        !          1730:                 *      Invalidate the translation buffer,
        !          1731:                 *      then remove the mapping.
        !          1732:                 */
        !          1733:                PMAP_UPDATE_TLBS(pmap, v, v + PAGE_SIZE);
        !          1734: 
        !          1735:                /*
        !          1736:                 *      Don't free the pte page if removing last
        !          1737:                 *      mapping - we will immediately replace it.
        !          1738:                 */
        !          1739:                pmap_remove_range(pmap, v, pte,
        !          1740:                                  pte + ptes_per_vm_page);
        !          1741:            }
        !          1742: 
        !          1743:            if (valid_page(pa)) {
        !          1744: 
        !          1745:                /*
        !          1746:                 *      Enter the mapping in the PV list for this
        !          1747:                 *      physical page.
        !          1748:                 */
        !          1749: 
        !          1750:                pai = pa_index(pa);
        !          1751:                LOCK_PVH(pai);
        !          1752:                pv_h = pai_to_pvh(pai);
        !          1753: 
        !          1754:                if (pv_h->pmap == PMAP_NULL) {
        !          1755:                    /*
        !          1756:                     *  No mappings yet
        !          1757:                     */
        !          1758:                    pv_h->va = v;
        !          1759:                    pv_h->pmap = pmap;
        !          1760:                    pv_h->next = PV_ENTRY_NULL;
        !          1761:                }
        !          1762:                else {
        !          1763: #if    DEBUG
        !          1764:                    {
        !          1765:                        /* check that this mapping is not already there */
        !          1766:                        pv_entry_t      e = pv_h;
        !          1767:                        while (e != PV_ENTRY_NULL) {
        !          1768:                            if (e->pmap == pmap && e->va == v)
        !          1769:                                panic("pmap_enter: already in pv_list");
        !          1770:                            e = e->next;
        !          1771:                        }
        !          1772:                    }
        !          1773: #endif /* DEBUG */
        !          1774: 
        !          1775:                    /*
        !          1776:                     *  Add new pv_entry after header.
        !          1777:                     */
        !          1778:                    if (pv_e == PV_ENTRY_NULL) {
        !          1779:                        PV_ALLOC(pv_e);
        !          1780:                        if (pv_e == PV_ENTRY_NULL) {
        !          1781:                            UNLOCK_PVH(pai);
        !          1782:                            PMAP_READ_UNLOCK(pmap, spl);
        !          1783: 
        !          1784:                            /*
        !          1785:                             * Refill from zone.
        !          1786:                             */
        !          1787:                            pv_e = (pv_entry_t) zalloc(pv_list_zone);
        !          1788:                            goto Retry;
        !          1789:                        }
        !          1790:                    }
        !          1791:                    pv_e->va = v;
        !          1792:                    pv_e->pmap = pmap;
        !          1793:                    pv_e->next = pv_h->next;
        !          1794:                    pv_h->next = pv_e;
        !          1795:                    /*
        !          1796:                     *  Remember that we used the pvlist entry.
        !          1797:                     */
        !          1798:                    pv_e = PV_ENTRY_NULL;
        !          1799:                }
        !          1800:                UNLOCK_PVH(pai);
        !          1801:            }
        !          1802: 
        !          1803:            /*
        !          1804:             *  And count the mapping.
        !          1805:             */
        !          1806: 
        !          1807:            pmap->stats.resident_count++;
        !          1808:            if (wired)
        !          1809:                pmap->stats.wired_count++;
        !          1810: 
        !          1811:            /*
        !          1812:             *  Build a template to speed up entering -
        !          1813:             *  only the pfn changes.
        !          1814:             */
        !          1815:            template |= pa_to_pte(pa) | INTEL_PTE_VALID;
        !          1816:            if (pmap != kernel_pmap)
        !          1817:                template |= INTEL_PTE_USER;
        !          1818:            if (prot & VM_PROT_WRITE)
        !          1819:                template |= INTEL_PTE_WRITE;
        !          1820:            if (wired)
        !          1821:                template |= INTEL_PTE_WIRED;
        !          1822:            i = ptes_per_vm_page;
        !          1823:            do {
        !          1824:                WRITE_PTE(pte, template)
        !          1825:                pte++;
        !          1826:                pte_increment_pa(template);
        !          1827:            } while (--i > 0);
        !          1828:        }
        !          1829: 
        !          1830:        if (pv_e != PV_ENTRY_NULL) {
        !          1831:            PV_FREE(pv_e);
        !          1832:        }
        !          1833: 
        !          1834:        PMAP_READ_UNLOCK(pmap, spl);
        !          1835: }
        !          1836: 
        !          1837: /*
        !          1838:  *     Routine:        pmap_change_wiring
        !          1839:  *     Function:       Change the wiring attribute for a map/virtual-address
        !          1840:  *                     pair.
        !          1841:  *     In/out conditions:
        !          1842:  *                     The mapping must already exist in the pmap.
        !          1843:  */
        !          1844: void pmap_change_wiring(map, v, wired)
        !          1845:        register pmap_t map;
        !          1846:        vm_offset_t     v;
        !          1847:        boolean_t       wired;
        !          1848: {
        !          1849:        register pt_entry_t     *pte;
        !          1850:        register int            i;
        !          1851:        int                     spl;
        !          1852: 
        !          1853:        /*
        !          1854:         *      We must grab the pmap system lock because we may
        !          1855:         *      change a pte_page queue.
        !          1856:         */
        !          1857:        PMAP_READ_LOCK(map, spl);
        !          1858: 
        !          1859:        if ((pte = pmap_pte(map, v)) == PT_ENTRY_NULL)
        !          1860:                panic("pmap_change_wiring: pte missing");
        !          1861: 
        !          1862:        if (wired && !(*pte & INTEL_PTE_WIRED)) {
        !          1863:            /*
        !          1864:             *  wiring down mapping
        !          1865:             */
        !          1866:            map->stats.wired_count++;
        !          1867:            i = ptes_per_vm_page;
        !          1868:            do {
        !          1869:                *pte++ |= INTEL_PTE_WIRED;
        !          1870:            } while (--i > 0);
        !          1871:        }
        !          1872:        else if (!wired && (*pte & INTEL_PTE_WIRED)) {
        !          1873:            /*
        !          1874:             *  unwiring mapping
        !          1875:             */
        !          1876:            map->stats.wired_count--;
        !          1877:            i = ptes_per_vm_page;
        !          1878:            do {
        !          1879:                *pte &= ~INTEL_PTE_WIRED;
        !          1880:            } while (--i > 0);
        !          1881:        }
        !          1882: 
        !          1883:        PMAP_READ_UNLOCK(map, spl);
        !          1884: }
        !          1885: 
        !          1886: /*
        !          1887:  *     Routine:        pmap_extract
        !          1888:  *     Function:
        !          1889:  *             Extract the physical page address associated
        !          1890:  *             with the given map/virtual_address pair.
        !          1891:  */
        !          1892: 
        !          1893: vm_offset_t pmap_extract(pmap, va)
        !          1894:        register pmap_t pmap;
        !          1895:        vm_offset_t     va;
        !          1896: {
        !          1897:        register pt_entry_t     *pte;
        !          1898:        register vm_offset_t    pa;
        !          1899:        int                     spl;
        !          1900: 
        !          1901:        SPLVM(spl);
        !          1902:        simple_lock(&pmap->lock);
        !          1903:        if ((pte = pmap_pte(pmap, va)) == PT_ENTRY_NULL)
        !          1904:            pa = (vm_offset_t) 0;
        !          1905:        else if (!(*pte & INTEL_PTE_VALID))
        !          1906:            pa = (vm_offset_t) 0;
        !          1907:        else
        !          1908:            pa = pte_to_pa(*pte) + (va & INTEL_OFFMASK);
        !          1909:        simple_unlock(&pmap->lock);
        !          1910:        SPLX(spl);
        !          1911:        return(pa);
        !          1912: }
        !          1913: 
        !          1914: /*
        !          1915:  *     Copy the range specified by src_addr/len
        !          1916:  *     from the source map to the range dst_addr/len
        !          1917:  *     in the destination map.
        !          1918:  *
        !          1919:  *     This routine is only advisory and need not do anything.
        !          1920:  */
        !          1921: #if    0
        !          1922: void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
        !          1923:        pmap_t          dst_pmap;
        !          1924:        pmap_t          src_pmap;
        !          1925:        vm_offset_t     dst_addr;
        !          1926:        vm_size_t       len;
        !          1927:        vm_offset_t     src_addr;
        !          1928: {
        !          1929: #ifdef lint
        !          1930:        dst_pmap++; src_pmap++; dst_addr++; len++; src_addr++;
        !          1931: #endif /* lint */
        !          1932: }
        !          1933: #endif /* 0 */
        !          1934: 
        !          1935: /*
        !          1936:  *     Routine:        pmap_collect
        !          1937:  *     Function:
        !          1938:  *             Garbage collects the physical map system for
        !          1939:  *             pages which are no longer used.
        !          1940:  *             Success need not be guaranteed -- that is, there
        !          1941:  *             may well be pages which are not referenced, but
        !          1942:  *             others may be collected.
        !          1943:  *     Usage:
        !          1944:  *             Called by the pageout daemon when pages are scarce.
        !          1945:  */
        !          1946: void pmap_collect(p)
        !          1947:        pmap_t          p;
        !          1948: {
        !          1949:        register pt_entry_t     *pdp, *ptp;
        !          1950:        pt_entry_t              *eptp;
        !          1951:        vm_offset_t             pa;
        !          1952:        int                     spl, wired;
        !          1953: 
        !          1954:        if (p == PMAP_NULL)
        !          1955:                return;
        !          1956: 
        !          1957:        if (p == kernel_pmap)
        !          1958:                return;
        !          1959: 
        !          1960:        /*
        !          1961:         *      Garbage collect map.
        !          1962:         */
        !          1963:        PMAP_READ_LOCK(p, spl);
        !          1964:        PMAP_UPDATE_TLBS(p, VM_MIN_ADDRESS, VM_MAX_ADDRESS);
        !          1965: 
        !          1966:        for (pdp = p->dirbase;
        !          1967:             pdp < &p->dirbase[lin2pdenum(LINEAR_MIN_KERNEL_ADDRESS)];
        !          1968:             pdp += ptes_per_vm_page)
        !          1969:        {
        !          1970:            if (*pdp & INTEL_PTE_VALID) {
        !          1971: 
        !          1972:                pa = pte_to_pa(*pdp);
        !          1973:                ptp = (pt_entry_t *)phystokv(pa);
        !          1974:                eptp = ptp + NPTES*ptes_per_vm_page;
        !          1975: 
        !          1976:                /*
        !          1977:                 * If the pte page has any wired mappings, we cannot
        !          1978:                 * free it.
        !          1979:                 */
        !          1980:                wired = 0;
        !          1981:                {
        !          1982:                    register pt_entry_t *ptep;
        !          1983:                    for (ptep = ptp; ptep < eptp; ptep++) {
        !          1984:                        if (*ptep & INTEL_PTE_WIRED) {
        !          1985:                            wired = 1;
        !          1986:                            break;
        !          1987:                        }
        !          1988:                    }
        !          1989:                }
        !          1990:                if (!wired) {
        !          1991:                    /*
        !          1992:                     * Remove the virtual addresses mapped by this pte page.
        !          1993:                     */
        !          1994:                    { /*XXX big hack*/
        !          1995:                    vm_offset_t va = pdenum2lin(pdp - p->dirbase);
        !          1996:                    if (p == kernel_pmap)
        !          1997:                        va = lintokv(va);
        !          1998:                    pmap_remove_range(p,
        !          1999:                                va,
        !          2000:                                ptp,
        !          2001:                                eptp);
        !          2002:                    }
        !          2003: 
        !          2004:                    /*
        !          2005:                     * Invalidate the page directory pointer.
        !          2006:                     */
        !          2007:                    {
        !          2008:                        register int i = ptes_per_vm_page;
        !          2009:                        register pt_entry_t *pdep = pdp;
        !          2010:                        do {
        !          2011:                            *pdep++ = 0;
        !          2012:                        } while (--i > 0);
        !          2013:                    }
        !          2014: 
        !          2015:                    PMAP_READ_UNLOCK(p, spl);
        !          2016: 
        !          2017:                    /*
        !          2018:                     * And free the pte page itself.
        !          2019:                     */
        !          2020:                    {
        !          2021:                        register vm_page_t m;
        !          2022: 
        !          2023:                        vm_object_lock(pmap_object);
        !          2024:                        m = vm_page_lookup(pmap_object, pa);
        !          2025:                        if (m == VM_PAGE_NULL)
        !          2026:                            panic("pmap_collect: pte page not in object");
        !          2027:                        vm_page_lock_queues();
        !          2028:                        vm_page_free(m);
        !          2029:                        inuse_ptepages_count--;
        !          2030:                        vm_page_unlock_queues();
        !          2031:                        vm_object_unlock(pmap_object);
        !          2032:                    }
        !          2033: 
        !          2034:                    PMAP_READ_LOCK(p, spl);
        !          2035:                }
        !          2036:            }
        !          2037:        }
        !          2038:        PMAP_READ_UNLOCK(p, spl);
        !          2039:        return;
        !          2040: 
        !          2041: }
        !          2042: 
        !          2043: /*
        !          2044:  *     Routine:        pmap_activate
        !          2045:  *     Function:
        !          2046:  *             Binds the given physical map to the given
        !          2047:  *             processor, and returns a hardware map description.
        !          2048:  */
        !          2049: #if    0
        !          2050: void pmap_activate(my_pmap, th, my_cpu)
        !          2051:        register pmap_t my_pmap;
        !          2052:        thread_t        th;
        !          2053:        int             my_cpu;
        !          2054: {
        !          2055:        PMAP_ACTIVATE(my_pmap, th, my_cpu);
        !          2056: }
        !          2057: #endif /* 0 */
        !          2058: 
        !          2059: /*
        !          2060:  *     Routine:        pmap_deactivate
        !          2061:  *     Function:
        !          2062:  *             Indicates that the given physical map is no longer
        !          2063:  *             in use on the specified processor.  (This is a macro
        !          2064:  *             in pmap.h)
        !          2065:  */
        !          2066: #if    0
        !          2067: void pmap_deactivate(pmap, th, which_cpu)
        !          2068:        pmap_t          pmap;
        !          2069:        thread_t        th;
        !          2070:        int             which_cpu;
        !          2071: {
        !          2072: #ifdef lint
        !          2073:        pmap++; th++; which_cpu++;
        !          2074: #endif /* lint */
        !          2075:        PMAP_DEACTIVATE(pmap, th, which_cpu);
        !          2076: }
        !          2077: #endif /* 0 */
        !          2078: 
        !          2079: /*
        !          2080:  *     Routine:        pmap_kernel
        !          2081:  *     Function:
        !          2082:  *             Returns the physical map handle for the kernel.
        !          2083:  */
        !          2084: #if    0
        !          2085: pmap_t pmap_kernel()
        !          2086: {
        !          2087:        return (kernel_pmap);
        !          2088: }
        !          2089: #endif /* 0 */
        !          2090: 
        !          2091: /*
        !          2092:  *     pmap_zero_page zeros the specified (machine independent) page.
        !          2093:  *     See machine/phys.c or machine/phys.s for implementation.
        !          2094:  */
        !          2095: #if    0
        !          2096: pmap_zero_page(phys)
        !          2097:        register vm_offset_t    phys;
        !          2098: {
        !          2099:        register int    i;
        !          2100: 
        !          2101:        assert(phys != vm_page_fictitious_addr);
        !          2102:        i = PAGE_SIZE / INTEL_PGBYTES;
        !          2103:        phys = intel_pfn(phys);
        !          2104: 
        !          2105:        while (i--)
        !          2106:                zero_phys(phys++);
        !          2107: }
        !          2108: #endif /* 0 */
        !          2109: 
        !          2110: /*
        !          2111:  *     pmap_copy_page copies the specified (machine independent) page.
        !          2112:  *     See machine/phys.c or machine/phys.s for implementation.
        !          2113:  */
        !          2114: #if    0
        !          2115: pmap_copy_page(src, dst)
        !          2116:        vm_offset_t     src, dst;
        !          2117: {
        !          2118:        int     i;
        !          2119: 
        !          2120:        assert(src != vm_page_fictitious_addr);
        !          2121:        assert(dst != vm_page_fictitious_addr);
        !          2122:        i = PAGE_SIZE / INTEL_PGBYTES;
        !          2123: 
        !          2124:        while (i--) {
        !          2125:                copy_phys(intel_pfn(src), intel_pfn(dst));
        !          2126:                src += INTEL_PGBYTES;
        !          2127:                dst += INTEL_PGBYTES;
        !          2128:        }
        !          2129: }
        !          2130: #endif /* 0 */
        !          2131: 
        !          2132: /*
        !          2133:  *     Routine:        pmap_pageable
        !          2134:  *     Function:
        !          2135:  *             Make the specified pages (by pmap, offset)
        !          2136:  *             pageable (or not) as requested.
        !          2137:  *
        !          2138:  *             A page which is not pageable may not take
        !          2139:  *             a fault; therefore, its page table entry
        !          2140:  *             must remain valid for the duration.
        !          2141:  *
        !          2142:  *             This routine is merely advisory; pmap_enter
        !          2143:  *             will specify that these pages are to be wired
        !          2144:  *             down (or not) as appropriate.
        !          2145:  */
        !          2146: pmap_pageable(pmap, start, end, pageable)
        !          2147:        pmap_t          pmap;
        !          2148:        vm_offset_t     start;
        !          2149:        vm_offset_t     end;
        !          2150:        boolean_t       pageable;
        !          2151: {
        !          2152: #ifdef lint
        !          2153:        pmap++; start++; end++; pageable++;
        !          2154: #endif /* lint */
        !          2155: }
        !          2156: 
        !          2157: /*
        !          2158:  *     Clear specified attribute bits.
        !          2159:  */
        !          2160: void
        !          2161: phys_attribute_clear(phys, bits)
        !          2162:        vm_offset_t     phys;
        !          2163:        int             bits;
        !          2164: {
        !          2165:        pv_entry_t              pv_h;
        !          2166:        register pv_entry_t     pv_e;
        !          2167:        register pt_entry_t     *pte;
        !          2168:        int                     pai;
        !          2169:        register pmap_t         pmap;
        !          2170:        int                     spl;
        !          2171: 
        !          2172:        assert(phys != vm_page_fictitious_addr);
        !          2173:        if (!valid_page(phys)) {
        !          2174:            /*
        !          2175:             *  Not a managed page.
        !          2176:             */
        !          2177:            return;
        !          2178:        }
        !          2179: 
        !          2180:        /*
        !          2181:         *      Lock the pmap system first, since we will be changing
        !          2182:         *      several pmaps.
        !          2183:         */
        !          2184: 
        !          2185:        PMAP_WRITE_LOCK(spl);
        !          2186: 
        !          2187:        pai = pa_index(phys);
        !          2188:        pv_h = pai_to_pvh(pai);
        !          2189: 
        !          2190:        /*
        !          2191:         * Walk down PV list, clearing all modify or reference bits.
        !          2192:         * We do not have to lock the pv_list because we have
        !          2193:         * the entire pmap system locked.
        !          2194:         */
        !          2195:        if (pv_h->pmap != PMAP_NULL) {
        !          2196:            /*
        !          2197:             * There are some mappings.
        !          2198:             */
        !          2199:            for (pv_e = pv_h; pv_e != PV_ENTRY_NULL; pv_e = pv_e->next) {
        !          2200: 
        !          2201:                pmap = pv_e->pmap;
        !          2202:                /*
        !          2203:                 * Lock the pmap to block pmap_extract and similar routines.
        !          2204:                 */
        !          2205:                simple_lock(&pmap->lock);
        !          2206: 
        !          2207:                {
        !          2208:                    register vm_offset_t va;
        !          2209: 
        !          2210:                    va = pv_e->va;
        !          2211:                    pte = pmap_pte(pmap, va);
        !          2212: 
        !          2213: #if    0
        !          2214:                    /*
        !          2215:                     * Consistency checks.
        !          2216:                     */
        !          2217:                    assert(*pte & INTEL_PTE_VALID);
        !          2218:                    /* assert(pte_to_phys(*pte) == phys); */
        !          2219: #endif
        !          2220: 
        !          2221:                    /*
        !          2222:                     * Invalidate TLBs for all CPUs using this mapping.
        !          2223:                     */
        !          2224:                    PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE);
        !          2225:                }
        !          2226: 
        !          2227:                /*
        !          2228:                 * Clear modify or reference bits.
        !          2229:                 */
        !          2230:                {
        !          2231:                    register int        i = ptes_per_vm_page;
        !          2232:                    do {
        !          2233:                        *pte &= ~bits;
        !          2234:                    } while (--i > 0);
        !          2235:                }
        !          2236:                simple_unlock(&pmap->lock);
        !          2237:            }
        !          2238:        }
        !          2239: 
        !          2240:        pmap_phys_attributes[pai] &= ~bits;
        !          2241: 
        !          2242:        PMAP_WRITE_UNLOCK(spl);
        !          2243: }
        !          2244: 
        !          2245: /*
        !          2246:  *     Check specified attribute bits.
        !          2247:  */
        !          2248: boolean_t
        !          2249: phys_attribute_test(phys, bits)
        !          2250:        vm_offset_t     phys;
        !          2251:        int             bits;
        !          2252: {
        !          2253:        pv_entry_t              pv_h;
        !          2254:        register pv_entry_t     pv_e;
        !          2255:        register pt_entry_t     *pte;
        !          2256:        int                     pai;
        !          2257:        register pmap_t         pmap;
        !          2258:        int                     spl;
        !          2259: 
        !          2260:        assert(phys != vm_page_fictitious_addr);
        !          2261:        if (!valid_page(phys)) {
        !          2262:            /*
        !          2263:             *  Not a managed page.
        !          2264:             */
        !          2265:            return (FALSE);
        !          2266:        }
        !          2267: 
        !          2268:        /*
        !          2269:         *      Lock the pmap system first, since we will be checking
        !          2270:         *      several pmaps.
        !          2271:         */
        !          2272: 
        !          2273:        PMAP_WRITE_LOCK(spl);
        !          2274: 
        !          2275:        pai = pa_index(phys);
        !          2276:        pv_h = pai_to_pvh(pai);
        !          2277: 
        !          2278:        if (pmap_phys_attributes[pai] & bits) {
        !          2279:            PMAP_WRITE_UNLOCK(spl);
        !          2280:            return (TRUE);
        !          2281:        }
        !          2282: 
        !          2283:        /*
        !          2284:         * Walk down PV list, checking all mappings.
        !          2285:         * We do not have to lock the pv_list because we have
        !          2286:         * the entire pmap system locked.
        !          2287:         */
        !          2288:        if (pv_h->pmap != PMAP_NULL) {
        !          2289:            /*
        !          2290:             * There are some mappings.
        !          2291:             */
        !          2292:            for (pv_e = pv_h; pv_e != PV_ENTRY_NULL; pv_e = pv_e->next) {
        !          2293: 
        !          2294:                pmap = pv_e->pmap;
        !          2295:                /*
        !          2296:                 * Lock the pmap to block pmap_extract and similar routines.
        !          2297:                 */
        !          2298:                simple_lock(&pmap->lock);
        !          2299: 
        !          2300:                {
        !          2301:                    register vm_offset_t va;
        !          2302: 
        !          2303:                    va = pv_e->va;
        !          2304:                    pte = pmap_pte(pmap, va);
        !          2305: 
        !          2306: #if    0
        !          2307:                    /*
        !          2308:                     * Consistency checks.
        !          2309:                     */
        !          2310:                    assert(*pte & INTEL_PTE_VALID);
        !          2311:                    /* assert(pte_to_phys(*pte) == phys); */
        !          2312: #endif
        !          2313:                }
        !          2314: 
        !          2315:                /*
        !          2316:                 * Check modify or reference bits.
        !          2317:                 */
        !          2318:                {
        !          2319:                    register int        i = ptes_per_vm_page;
        !          2320: 
        !          2321:                    do {
        !          2322:                        if (*pte & bits) {
        !          2323:                            simple_unlock(&pmap->lock);
        !          2324:                            PMAP_WRITE_UNLOCK(spl);
        !          2325:                            return (TRUE);
        !          2326:                        }
        !          2327:                    } while (--i > 0);
        !          2328:                }
        !          2329:                simple_unlock(&pmap->lock);
        !          2330:            }
        !          2331:        }
        !          2332:        PMAP_WRITE_UNLOCK(spl);
        !          2333:        return (FALSE);
        !          2334: }
        !          2335: 
        !          2336: /*
        !          2337:  *     Clear the modify bits on the specified physical page.
        !          2338:  */
        !          2339: 
        !          2340: void pmap_clear_modify(phys)
        !          2341:        register vm_offset_t    phys;
        !          2342: {
        !          2343:        phys_attribute_clear(phys, PHYS_MODIFIED);
        !          2344: }
        !          2345: 
        !          2346: /*
        !          2347:  *     pmap_is_modified:
        !          2348:  *
        !          2349:  *     Return whether or not the specified physical page is modified
        !          2350:  *     by any physical maps.
        !          2351:  */
        !          2352: 
        !          2353: boolean_t pmap_is_modified(phys)
        !          2354:        register vm_offset_t    phys;
        !          2355: {
        !          2356:        return (phys_attribute_test(phys, PHYS_MODIFIED));
        !          2357: }
        !          2358: 
        !          2359: /*
        !          2360:  *     pmap_clear_reference:
        !          2361:  *
        !          2362:  *     Clear the reference bit on the specified physical page.
        !          2363:  */
        !          2364: 
        !          2365: void pmap_clear_reference(phys)
        !          2366:        vm_offset_t     phys;
        !          2367: {
        !          2368:        phys_attribute_clear(phys, PHYS_REFERENCED);
        !          2369: }
        !          2370: 
        !          2371: /*
        !          2372:  *     pmap_is_referenced:
        !          2373:  *
        !          2374:  *     Return whether or not the specified physical page is referenced
        !          2375:  *     by any physical maps.
        !          2376:  */
        !          2377: 
        !          2378: boolean_t pmap_is_referenced(phys)
        !          2379:        vm_offset_t     phys;
        !          2380: {
        !          2381:        return (phys_attribute_test(phys, PHYS_REFERENCED));
        !          2382: }
        !          2383: 
        !          2384: #if    NCPUS > 1
        !          2385: /*
        !          2386: *          TLB Coherence Code (TLB "shootdown" code)
        !          2387: *
        !          2388: * Threads that belong to the same task share the same address space and
        !          2389: * hence share a pmap.  However, they  may run on distinct cpus and thus
        !          2390: * have distinct TLBs that cache page table entries. In order to guarantee
        !          2391: * the TLBs are consistent, whenever a pmap is changed, all threads that
        !          2392: * are active in that pmap must have their TLB updated. To keep track of
        !          2393: * this information, the set of cpus that are currently using a pmap is
        !          2394: * maintained within each pmap structure (cpus_using). Pmap_activate() and
        !          2395: * pmap_deactivate add and remove, respectively, a cpu from this set.
        !          2396: * Since the TLBs are not addressable over the bus, each processor must
        !          2397: * flush its own TLB; a processor that needs to invalidate another TLB
        !          2398: * needs to interrupt the processor that owns that TLB to signal the
        !          2399: * update.
        !          2400: *
        !          2401: * Whenever a pmap is updated, the lock on that pmap is locked, and all
        !          2402: * cpus using the pmap are signaled to invalidate. All threads that need
        !          2403: * to activate a pmap must wait for the lock to clear to await any updates
        !          2404: * in progress before using the pmap. They must ACQUIRE the lock to add
        !          2405: * their cpu to the cpus_using set. An implicit assumption made
        !          2406: * throughout the TLB code is that all kernel code that runs at or higher
        !          2407: * than splvm blocks out update interrupts, and that such code does not
        !          2408: * touch pageable pages.
        !          2409: *
        !          2410: * A shootdown interrupt serves another function besides signaling a
        !          2411: * processor to invalidate. The interrupt routine (pmap_update_interrupt)
        !          2412: * waits for the both the pmap lock (and the kernel pmap lock) to clear,
        !          2413: * preventing user code from making implicit pmap updates while the
        !          2414: * sending processor is performing its update. (This could happen via a
        !          2415: * user data write reference that turns on the modify bit in the page
        !          2416: * table). It must wait for any kernel updates that may have started
        !          2417: * concurrently with a user pmap update because the IPC code
        !          2418: * changes mappings.
        !          2419: * Spinning on the VALUES of the locks is sufficient (rather than
        !          2420: * having to acquire the locks) because any updates that occur subsequent
        !          2421: * to finding the lock unlocked will be signaled via another interrupt.
        !          2422: * (This assumes the interrupt is cleared before the low level interrupt code
        !          2423: * calls pmap_update_interrupt()).
        !          2424: *
        !          2425: * The signaling processor must wait for any implicit updates in progress
        !          2426: * to terminate before continuing with its update. Thus it must wait for an
        !          2427: * acknowledgement of the interrupt from each processor for which such
        !          2428: * references could be made. For maintaining this information, a set
        !          2429: * cpus_active is used. A cpu is in this set if and only if it can
        !          2430: * use a pmap. When pmap_update_interrupt() is entered, a cpu is removed from
        !          2431: * this set; when all such cpus are removed, it is safe to update.
        !          2432: *
        !          2433: * Before attempting to acquire the update lock on a pmap, a cpu (A) must
        !          2434: * be at least at the priority of the interprocessor interrupt
        !          2435: * (splip<=splvm). Otherwise, A could grab a lock and be interrupted by a
        !          2436: * kernel update; it would spin forever in pmap_update_interrupt() trying
        !          2437: * to acquire the user pmap lock it had already acquired. Furthermore A
        !          2438: * must remove itself from cpus_active.  Otherwise, another cpu holding
        !          2439: * the lock (B) could be in the process of sending an update signal to A,
        !          2440: * and thus be waiting for A to remove itself from cpus_active. If A is
        !          2441: * spinning on the lock at priority this will never happen and a deadlock
        !          2442: * will result.
        !          2443: */
        !          2444: 
        !          2445: /*
        !          2446:  *     Signal another CPU that it must flush its TLB
        !          2447:  */
        !          2448: void    signal_cpus(use_list, pmap, start, end)
        !          2449:        cpu_set         use_list;
        !          2450:        pmap_t          pmap;
        !          2451:        vm_offset_t     start, end;
        !          2452: {
        !          2453:        register int            which_cpu, j;
        !          2454:        register pmap_update_list_t     update_list_p;
        !          2455: 
        !          2456:        while ((which_cpu = ffs(use_list)) != 0) {
        !          2457:            which_cpu -= 1;     /* convert to 0 origin */
        !          2458: 
        !          2459:            update_list_p = &cpu_update_list[which_cpu];
        !          2460:            simple_lock(&update_list_p->lock);
        !          2461: 
        !          2462:            j = update_list_p->count;
        !          2463:            if (j >= UPDATE_LIST_SIZE) {
        !          2464:                /*
        !          2465:                 *      list overflowed.  Change last item to
        !          2466:                 *      indicate overflow.
        !          2467:                 */
        !          2468:                update_list_p->item[UPDATE_LIST_SIZE-1].pmap  = kernel_pmap;
        !          2469:                update_list_p->item[UPDATE_LIST_SIZE-1].start = VM_MIN_ADDRESS;
        !          2470:                update_list_p->item[UPDATE_LIST_SIZE-1].end   = VM_MAX_KERNEL_ADDRESS;
        !          2471:            }
        !          2472:            else {
        !          2473:                update_list_p->item[j].pmap  = pmap;
        !          2474:                update_list_p->item[j].start = start;
        !          2475:                update_list_p->item[j].end   = end;
        !          2476:                update_list_p->count = j+1;
        !          2477:            }
        !          2478:            cpu_update_needed[which_cpu] = TRUE;
        !          2479:            simple_unlock(&update_list_p->lock);
        !          2480: 
        !          2481:            if ((cpus_idle & (1 << which_cpu)) == 0)
        !          2482:                interrupt_processor(which_cpu);
        !          2483:            use_list &= ~(1 << which_cpu);
        !          2484:        }
        !          2485: }
        !          2486: 
        !          2487: void process_pmap_updates(my_pmap)
        !          2488:        register pmap_t         my_pmap;
        !          2489: {
        !          2490:        register int            my_cpu = cpu_number();
        !          2491:        register pmap_update_list_t     update_list_p;
        !          2492:        register int            j;
        !          2493:        register pmap_t         pmap;
        !          2494: 
        !          2495:        update_list_p = &cpu_update_list[my_cpu];
        !          2496:        simple_lock(&update_list_p->lock);
        !          2497: 
        !          2498:        for (j = 0; j < update_list_p->count; j++) {
        !          2499:            pmap = update_list_p->item[j].pmap;
        !          2500:            if (pmap == my_pmap ||
        !          2501:                pmap == kernel_pmap) {
        !          2502: 
        !          2503:                INVALIDATE_TLB(update_list_p->item[j].start,
        !          2504:                                update_list_p->item[j].end);
        !          2505:            }
        !          2506:        }
        !          2507:        update_list_p->count = 0;
        !          2508:        cpu_update_needed[my_cpu] = FALSE;
        !          2509:        simple_unlock(&update_list_p->lock);
        !          2510: }
        !          2511: 
        !          2512: /*
        !          2513:  *     Interrupt routine for TBIA requested from other processor.
        !          2514:  */
        !          2515: void pmap_update_interrupt()
        !          2516: {
        !          2517:        register int            my_cpu;
        !          2518:        register pmap_t         my_pmap;
        !          2519:        int                     s;
        !          2520: 
        !          2521:        my_cpu = cpu_number();
        !          2522: 
        !          2523:        /*
        !          2524:         *      Exit now if we're idle.  We'll pick up the update request
        !          2525:         *      when we go active, and we must not put ourselves back in
        !          2526:         *      the active set because we'll never process the interrupt
        !          2527:         *      while we're idle (thus hanging the system).
        !          2528:         */
        !          2529:        if (cpus_idle & (1 << my_cpu))
        !          2530:            return;
        !          2531: 
        !          2532:        if (current_thread() == THREAD_NULL)
        !          2533:            my_pmap = kernel_pmap;
        !          2534:        else {
        !          2535:            my_pmap = current_pmap();
        !          2536:            if (!pmap_in_use(my_pmap, my_cpu))
        !          2537:                my_pmap = kernel_pmap;
        !          2538:        }
        !          2539: 
        !          2540:        /*
        !          2541:         *      Raise spl to splvm (above splip) to block out pmap_extract
        !          2542:         *      from IO code (which would put this cpu back in the active
        !          2543:         *      set).
        !          2544:         */
        !          2545:        s = splvm();
        !          2546: 
        !          2547:        do {
        !          2548: 
        !          2549:            /*
        !          2550:             *  Indicate that we're not using either user or kernel
        !          2551:             *  pmap.
        !          2552:             */
        !          2553:            i_bit_clear(my_cpu, &cpus_active);
        !          2554: 
        !          2555:            /*
        !          2556:             *  Wait for any pmap updates in progress, on either user
        !          2557:             *  or kernel pmap.
        !          2558:             */
        !          2559:            while (*(volatile int *)&my_pmap->lock.lock_data ||
        !          2560:                   *(volatile int *)&kernel_pmap->lock.lock_data)
        !          2561:                continue;
        !          2562: 
        !          2563:            process_pmap_updates(my_pmap);
        !          2564: 
        !          2565:            i_bit_set(my_cpu, &cpus_active);
        !          2566: 
        !          2567:        } while (cpu_update_needed[my_cpu]);
        !          2568: 
        !          2569:        splx(s);
        !          2570: }
        !          2571: #else  /* NCPUS > 1 */
        !          2572: /*
        !          2573:  *     Dummy routine to satisfy external reference.
        !          2574:  */
        !          2575: void pmap_update_interrupt()
        !          2576: {
        !          2577:        /* should never be called. */
        !          2578: }
        !          2579: #endif /* NCPUS > 1 */
        !          2580: 
        !          2581: #if    i860    /* akp */
        !          2582: void set_dirbase(dirbase)
        !          2583:        register vm_offset_t    dirbase;
        !          2584: {
        !          2585:        /*flush();*/
        !          2586:        /*flush_tlb();*/
        !          2587:        flush_and_ctxsw(dirbase);
        !          2588: }
        !          2589: #endif /* i860 */
        !          2590: 
        !          2591: #ifdef i386
        !          2592: /* Unmap page 0 to trap NULL references.  */
        !          2593: void
        !          2594: pmap_unmap_page_zero ()
        !          2595: {
        !          2596:   int *pte;
        !          2597: 
        !          2598:   pte = (int *) pmap_pte (kernel_pmap, 0);
        !          2599:   assert (pte);
        !          2600:   *pte = 0;
        !          2601:   inval_tlb ();
        !          2602: }
        !          2603: #endif /* i386 */

unix.superglobalmegacorp.com

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