[BACK]Return to pmap.c CVS log [TXT][DIR] Up to [local] / sys / arch / m88k / m88k

Annotation of sys/arch/m88k/m88k/pmap.c, Revision 1.1

1.1     ! nbrk        1: /*     $OpenBSD: pmap.c,v 1.31 2007/05/27 20:59:25 miod Exp $  */
        !             2: /*
        !             3:  * Copyright (c) 2001-2004, Miodrag Vallat
        !             4:  * Copyright (c) 1998-2001 Steve Murphree, Jr.
        !             5:  * Copyright (c) 1996 Nivas Madhur
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *      This product includes software developed by Nivas Madhur.
        !            19:  * 4. The name of the author may not be used to endorse or promote products
        !            20:  *    derived from this software without specific prior written permission
        !            21:  *
        !            22:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            23:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            24:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            25:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            26:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            27:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            28:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            29:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            30:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            31:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            32:  *
        !            33:  */
        !            34: /*
        !            35:  * Mach Operating System
        !            36:  * Copyright (c) 1991 Carnegie Mellon University
        !            37:  * Copyright (c) 1991 OMRON Corporation
        !            38:  * All Rights Reserved.
        !            39:  *
        !            40:  * Permission to use, copy, modify and distribute this software and its
        !            41:  * documentation is hereby granted, provided that both the copyright
        !            42:  * notice and this permission notice appear in all copies of the
        !            43:  * software, derivative works or modified versions, and any portions
        !            44:  * thereof, and that both notices appear in supporting documentation.
        !            45:  *
        !            46:  */
        !            47:
        !            48: #include <sys/param.h>
        !            49: #include <sys/systm.h>
        !            50: #include <sys/proc.h>
        !            51: #include <sys/malloc.h>
        !            52: #include <sys/pool.h>
        !            53: #include <sys/msgbuf.h>
        !            54: #include <sys/user.h>
        !            55:
        !            56: #include <machine/asm_macro.h>
        !            57: #include <machine/cmmu.h>
        !            58: #include <machine/cpu.h>
        !            59: #include <machine/lock.h>
        !            60: #include <machine/pmap_table.h>
        !            61: #ifdef M88100
        !            62: #include <machine/m8820x.h>
        !            63: #endif
        !            64:
        !            65: #include <uvm/uvm.h>
        !            66:
        !            67: /*
        !            68:  * VM externals
        !            69:  */
        !            70: extern vaddr_t avail_start;
        !            71: extern vaddr_t virtual_avail, virtual_end;
        !            72: extern vaddr_t last_addr;
        !            73:
        !            74: /*
        !            75:  * Macros to operate pm_cpus field
        !            76:  */
        !            77: #define SETBIT_CPUSET(cpu_number, cpuset) (*(cpuset)) |= (1 << (cpu_number));
        !            78: #define CLRBIT_CPUSET(cpu_number, cpuset) (*(cpuset)) &= ~(1 << (cpu_number));
        !            79:
        !            80: #ifdef DEBUG
        !            81: /*
        !            82:  * Static variables, functions and variables for debugging
        !            83:  */
        !            84:
        !            85: /*
        !            86:  * conditional debugging
        !            87:  */
        !            88: #define CD_FULL                0x02
        !            89:
        !            90: #define CD_ACTIVATE    0x0000004       /* pmap_activate */
        !            91: #define CD_KMAP                0x0000008       /* pmap_expand_kmap */
        !            92: #define CD_MAP         0x0000010       /* pmap_map */
        !            93: #define CD_CACHE       0x0000020       /* pmap_cache_ctrl */
        !            94: #define CD_INIT                0x0000080       /* pmap_init */
        !            95: #define CD_CREAT       0x0000100       /* pmap_create */
        !            96: #define CD_FREE                0x0000200       /* pmap_release */
        !            97: #define CD_DESTR       0x0000400       /* pmap_destroy */
        !            98: #define CD_RM          0x0000800       /* pmap_remove */
        !            99: #define CD_RMAL                0x0001000       /* pmap_remove_all */
        !           100: #define CD_PROT                0x0002000       /* pmap_protect */
        !           101: #define CD_EXP         0x0004000       /* pmap_expand */
        !           102: #define CD_ENT         0x0008000       /* pmap_enter */
        !           103: #define CD_UPD         0x0010000       /* pmap_update */
        !           104: #define CD_COL         0x0020000       /* pmap_collect */
        !           105: #define CD_CBIT                0x0040000       /* pmap_changebit */
        !           106: #define CD_TBIT                0x0080000       /* pmap_testbit */
        !           107: #define CD_USBIT       0x0100000       /* pmap_unsetbit */
        !           108: #define CD_ALL         0x0FFFFFC
        !           109:
        !           110: int pmap_con_dbg = 0;
        !           111:
        !           112: #endif /* DEBUG */
        !           113:
        !           114: struct pool pmappool, pvpool;
        !           115:
        !           116: caddr_t vmmap;
        !           117: pt_entry_t *vmpte, *msgbufmap;
        !           118:
        !           119: struct pmap kernel_pmap_store;
        !           120: pmap_t kernel_pmap = &kernel_pmap_store;
        !           121:
        !           122: typedef struct kpdt_entry *kpdt_entry_t;
        !           123: struct kpdt_entry {
        !           124:        kpdt_entry_t    next;
        !           125:        paddr_t         phys;
        !           126: };
        !           127:
        !           128: kpdt_entry_t   kpdt_free;
        !           129:
        !           130: /*
        !           131:  * Two pages of scratch space per cpu.
        !           132:  * Used in pmap_copy_page() and pmap_zero_page().
        !           133:  */
        !           134: vaddr_t phys_map_vaddr, phys_map_vaddr_end;
        !           135:
        !           136: static pv_entry_t pg_to_pvh(struct vm_page *);
        !           137:
        !           138: static __inline pv_entry_t
        !           139: pg_to_pvh(struct vm_page *pg)
        !           140: {
        !           141:        return &pg->mdpage.pvent;
        !           142: }
        !           143:
        !           144: /*
        !           145:  *     Locking primitives
        !           146:  */
        !           147:
        !           148: #ifdef MULTIPROCESSOR
        !           149: #define        PMAP_LOCK(pmap)         __cpu_simple_lock(&(pmap)->pm_lock)
        !           150: #define        PMAP_UNLOCK(pmap)       __cpu_simple_unlock(&(pmap)->pm_lock)
        !           151: #else
        !           152: #define        PMAP_LOCK(pmap)         do { /* nothing */ } while (0)
        !           153: #define        PMAP_UNLOCK(pmap)       do { /* nothing */ } while (0)
        !           154: #endif
        !           155:
        !           156: vaddr_t kmapva = 0;
        !           157:
        !           158: /*
        !           159:  * Internal routines
        !           160:  */
        !           161: static void flush_atc_entry(pmap_t, vaddr_t);
        !           162: pt_entry_t *pmap_expand_kmap(vaddr_t, vm_prot_t, int);
        !           163: void   pmap_remove_pte(pmap_t, vaddr_t, pt_entry_t *);
        !           164: void   pmap_remove_range(pmap_t, vaddr_t, vaddr_t);
        !           165: void   pmap_expand(pmap_t, vaddr_t);
        !           166: void   pmap_release(pmap_t);
        !           167: vaddr_t        pmap_map(vaddr_t, paddr_t, paddr_t, vm_prot_t, u_int);
        !           168: pt_entry_t *pmap_pte(pmap_t, vaddr_t);
        !           169: void   pmap_remove_all(struct vm_page *);
        !           170: void   pmap_changebit(struct vm_page *, int, int);
        !           171: boolean_t pmap_unsetbit(struct vm_page *, int);
        !           172: boolean_t pmap_testbit(struct vm_page *, int);
        !           173:
        !           174: /*
        !           175:  * quick PTE field checking macros
        !           176:  */
        !           177: #define        pmap_pte_w(pte)         (*(pte) & PG_W)
        !           178: #define        pmap_pte_prot(pte)      (*(pte) & PG_PROT)
        !           179:
        !           180: #define        pmap_pte_w_chg(pte, nw)         ((nw) ^ pmap_pte_w(pte))
        !           181: #define        pmap_pte_prot_chg(pte, np)      ((np) ^ pmap_pte_prot(pte))
        !           182:
        !           183: #define        m88k_protection(prot)   ((prot) & VM_PROT_WRITE ? PG_RW : PG_RO)
        !           184:
        !           185: #define SDTENT(map, va)                ((sdt_entry_t *)((map)->pm_stab + SDTIDX(va)))
        !           186:
        !           187: /*
        !           188:  * Routine:    FLUSH_ATC_ENTRY
        !           189:  *
        !           190:  * Function:
        !           191:  *     Flush atc (TLB) which maps given pmap and virtual address.
        !           192:  *
        !           193:  * Parameters:
        !           194:  *     pmap    affected pmap
        !           195:  *     va      virtual address that should be flushed
        !           196:  */
        !           197: static
        !           198: #ifndef MULTIPROCESSOR
        !           199: __inline__
        !           200: #endif
        !           201: void
        !           202: flush_atc_entry(pmap_t pmap, vaddr_t va)
        !           203: {
        !           204: #ifdef MULTIPROCESSOR
        !           205:        u_int32_t users;
        !           206:        int cpu;
        !           207:        boolean_t kernel;
        !           208:
        !           209:        if ((users = pmap->pm_cpus) == 0)
        !           210:                return;
        !           211:
        !           212:        kernel = pmap == kernel_pmap;
        !           213:        while ((cpu = ff1(users)) != 32) {
        !           214: #ifdef DIAGNOSTIC
        !           215:                if (m88k_cpus[cpu].ci_alive)
        !           216: #endif
        !           217:                        cmmu_flush_tlb(cpu, kernel, va, 1);
        !           218:                users ^= 1 << cpu;
        !           219:        }
        !           220: #else  /* MULTIPROCESSOR */
        !           221:        if (pmap->pm_cpus != 0)
        !           222:                cmmu_flush_tlb(cpu_number(), pmap == kernel_pmap, va, 1);
        !           223: #endif /* MULTIPROCESSOR */
        !           224: }
        !           225:
        !           226: /*
        !           227:  * Routine:    PMAP_PTE
        !           228:  *
        !           229:  * Function:
        !           230:  *     Given a map and a virtual address, compute a (virtual) pointer
        !           231:  *     to the page table entry (PTE) which maps the address .
        !           232:  *     If the page table associated with the address does not
        !           233:  *     exist, NULL is returned (and the map may need to grow).
        !           234:  *
        !           235:  * Parameters:
        !           236:  *     pmap    pointer to pmap structure
        !           237:  *     virt    virtual address for which page table entry is desired
        !           238:  *
        !           239:  *    Otherwise the page table address is extracted from the segment table,
        !           240:  *    the page table index is added, and the result is returned.
        !           241:  */
        !           242:
        !           243: static __inline__
        !           244: pt_entry_t *
        !           245: sdt_pte(sdt_entry_t *sdt, vaddr_t va)
        !           246: {
        !           247:        return ((pt_entry_t *)
        !           248:            (PG_PFNUM(*(sdt + SDT_ENTRIES)) << PDT_SHIFT) + PDTIDX(va));
        !           249: }
        !           250:
        !           251: pt_entry_t *
        !           252: pmap_pte(pmap_t pmap, vaddr_t virt)
        !           253: {
        !           254:        sdt_entry_t *sdt;
        !           255:
        !           256:        sdt = SDTENT(pmap, virt);
        !           257:        /*
        !           258:         * Check whether page table exists.
        !           259:         */
        !           260:        if (!SDT_VALID(sdt))
        !           261:                return (NULL);
        !           262:
        !           263:        return (sdt_pte(sdt, virt));
        !           264: }
        !           265:
        !           266: /*
        !           267:  * Routine:    PMAP_EXPAND_KMAP (internal)
        !           268:  *
        !           269:  * Function:
        !           270:  *    Allocate a page descriptor table (pte_table) and validate associated
        !           271:  * segment table entry, returning pointer to page table entry. This is
        !           272:  * much like 'pmap_expand', except that table space is acquired
        !           273:  * from an area set up by pmap_bootstrap, instead of through
        !           274:  * uvm_km_zalloc. (Obviously, because uvm_km_zalloc uses the kernel map
        !           275:  * for allocation - which we can't do when trying to expand the
        !           276:  * kernel map!) Note that segment tables for the kernel map were
        !           277:  * all allocated at pmap_bootstrap time, so we only need to worry
        !           278:  * about the page table here.
        !           279:  *
        !           280:  * Parameters:
        !           281:  *     virt    VA for which translation tables are needed
        !           282:  *     prot    protection attributes for segment entries
        !           283:  *
        !           284:  * Extern/Global:
        !           285:  *     kpdt_free       kernel page table free queue
        !           286:  *
        !           287:  * This routine simply dequeues a table from the kpdt_free list,
        !           288:  * initializes all its entries (invalidates them), and sets the
        !           289:  * corresponding segment table entry to point to it. If the kpdt_free
        !           290:  * list is empty - we panic (no other places to get memory, sorry). (Such
        !           291:  * a panic indicates that pmap_bootstrap is not allocating enough table
        !           292:  * space for the kernel virtual address space).
        !           293:  *
        !           294:  */
        !           295: pt_entry_t *
        !           296: pmap_expand_kmap(vaddr_t virt, vm_prot_t prot, int canfail)
        !           297: {
        !           298:        sdt_entry_t template, *sdt;
        !           299:        kpdt_entry_t kpdt_ent;
        !           300:
        !           301: #ifdef DEBUG
        !           302:        if ((pmap_con_dbg & (CD_KMAP | CD_FULL)) == (CD_KMAP | CD_FULL))
        !           303:                printf("(pmap_expand_kmap: %x) v %x\n", curproc, virt);
        !           304: #endif
        !           305:
        !           306:        template = m88k_protection(prot) | PG_M | SG_V;
        !           307:
        !           308:        /* segment table entry derivate from map and virt. */
        !           309:        sdt = SDTENT(kernel_pmap, virt);
        !           310: #ifdef DEBUG
        !           311:        if (SDT_VALID(sdt))
        !           312:                panic("pmap_expand_kmap: segment table entry VALID");
        !           313: #endif
        !           314:
        !           315:        kpdt_ent = kpdt_free;
        !           316:        if (kpdt_ent == NULL) {
        !           317:                if (canfail)
        !           318:                        return (NULL);
        !           319:                else
        !           320:                        panic("pmap_expand_kmap: Ran out of kernel pte tables");
        !           321:        }
        !           322:
        !           323:        kpdt_free = kpdt_free->next;
        !           324:        /* physical table */
        !           325:        *sdt = kpdt_ent->phys | template;
        !           326:        /* virtual table */
        !           327:        *(sdt + SDT_ENTRIES) = (vaddr_t)kpdt_ent | template;
        !           328:
        !           329:        /* Reinitialize this kpdt area to zero */
        !           330:        bzero((void *)kpdt_ent, PDT_SIZE);
        !           331:
        !           332:        return (pt_entry_t *)(kpdt_ent) + PDTIDX(virt);
        !           333: }
        !           334:
        !           335: /*
        !           336:  * Routine:    PMAP_MAP
        !           337:  *
        !           338:  * Function:
        !           339:  *    Map memory at initialization. The physical addresses being
        !           340:  * mapped are not managed and are never unmapped.
        !           341:  *
        !           342:  * Parameters:
        !           343:  *     virt    virtual address of range to map
        !           344:  *     start   physical address of range to map
        !           345:  *     end     physical address of end of range
        !           346:  *     prot    protection attributes
        !           347:  *     cmode   cache control attributes
        !           348:  *
        !           349:  * Calls:
        !           350:  *     pmap_pte
        !           351:  *     pmap_expand_kmap
        !           352:  *
        !           353:  * Special Assumptions
        !           354:  *     For now, VM is already on, only need to map the specified
        !           355:  * memory. Used only by pmap_bootstrap() and vm_page_startup().
        !           356:  *
        !           357:  * For each page that needs mapping:
        !           358:  *     pmap_pte is called to obtain the address of the page table
        !           359:  *     table entry (PTE). If the page table does not exist,
        !           360:  *     pmap_expand_kmap is called to allocate it. Finally, the page table
        !           361:  *     entry is set to point to the physical page.
        !           362:  *
        !           363:  *     initialize template with paddr, prot, dt
        !           364:  *     look for number of phys pages in range
        !           365:  *     {
        !           366:  *             pmap_pte(virt)  - expand if necessary
        !           367:  *             stuff pte from template
        !           368:  *             increment virt one page
        !           369:  *             increment template paddr one page
        !           370:  *     }
        !           371:  *
        !           372:  */
        !           373: vaddr_t
        !           374: pmap_map(vaddr_t virt, paddr_t start, paddr_t end, vm_prot_t prot, u_int cmode)
        !           375: {
        !           376:        u_int npages;
        !           377:        u_int num_phys_pages;
        !           378:        pt_entry_t template, *pte;
        !           379:        paddr_t  page;
        !           380:
        !           381: #ifdef DEBUG
        !           382:        if (pmap_con_dbg & CD_MAP)
        !           383:                printf ("(pmap_map: %x) phys address from %x to %x mapped at virtual %x, prot %x cmode %x\n",
        !           384:                        curproc, start, end, virt, prot, cmode);
        !           385: #endif
        !           386:
        !           387: #ifdef DEBUG
        !           388:        /* Check for zero if we map the very end of the address space... */
        !           389:        if (start > end && end != 0) {
        !           390:                panic("pmap_map: start greater than end address");
        !           391:        }
        !           392: #endif
        !           393:
        !           394:        template = m88k_protection(prot) | cmode | PG_V;
        !           395: #ifdef M88110
        !           396:        if (CPU_IS88110 && m88k_protection(prot) != PG_RO)
        !           397:                template |= PG_M;
        !           398: #endif
        !           399:
        !           400:        page = trunc_page(start);
        !           401:        npages = atop(round_page(end) - page);
        !           402:        for (num_phys_pages = npages; num_phys_pages != 0; num_phys_pages--) {
        !           403:                if ((pte = pmap_pte(kernel_pmap, virt)) == NULL)
        !           404:                        pte = pmap_expand_kmap(virt,
        !           405:                            VM_PROT_READ | VM_PROT_WRITE, 0);
        !           406:
        !           407: #ifdef DEBUG
        !           408:                if ((pmap_con_dbg & (CD_MAP | CD_FULL)) == (CD_MAP | CD_FULL))
        !           409:                        if (PDT_VALID(pte))
        !           410:                                printf("(pmap_map: %x) pte @ %p already valid\n", curproc, pte);
        !           411: #endif
        !           412:
        !           413:                *pte = template | page;
        !           414:                virt += PAGE_SIZE;
        !           415:                page += PAGE_SIZE;
        !           416:        }
        !           417:        return virt;
        !           418: }
        !           419:
        !           420: /*
        !           421:  * Routine:    PMAP_CACHE_CONTROL
        !           422:  *
        !           423:  * Function:
        !           424:  *     Set the cache-control bits in the page table entries(PTE) which maps
        !           425:  *     the specified virtual address range.
        !           426:  *
        !           427:  * Parameters:
        !           428:  *     pmap_t          pmap
        !           429:  *     vaddr_t         s
        !           430:  *     vaddr_t         e
        !           431:  *     u_int           mode
        !           432:  *
        !           433:  * Calls:
        !           434:  *     pmap_pte
        !           435:  *     invalidate_pte
        !           436:  *     flush_atc_entry
        !           437:  *
        !           438:  *  This routine sequences through the pages of the specified range.
        !           439:  * For each, it calls pmap_pte to acquire a pointer to the page table
        !           440:  * entry (PTE). If the PTE is invalid, or non-existent, nothing is done.
        !           441:  * Otherwise, the cache-control bits in the PTE's are adjusted as specified.
        !           442:  *
        !           443:  */
        !           444: void
        !           445: pmap_cache_ctrl(pmap_t pmap, vaddr_t s, vaddr_t e, u_int mode)
        !           446: {
        !           447:        int spl;
        !           448:        pt_entry_t opte, *pte;
        !           449:        vaddr_t va;
        !           450:        paddr_t pa;
        !           451:        cpuid_t cpu;
        !           452:
        !           453: #ifdef DEBUG
        !           454:        if ((mode & CACHE_MASK) != mode) {
        !           455:                printf("(cache_ctrl) illegal mode %x\n", mode);
        !           456:                return;
        !           457:        }
        !           458:        if (pmap_con_dbg & CD_CACHE) {
        !           459:                printf("(pmap_cache_ctrl: %x) pmap %x, va %x, mode %x\n", curproc, pmap, s, mode);
        !           460:        }
        !           461:
        !           462:        if (pmap == NULL)
        !           463:                panic("pmap_cache_ctrl: pmap is NULL");
        !           464: #endif /* DEBUG */
        !           465:
        !           466:        spl = splvm();
        !           467:        PMAP_LOCK(pmap);
        !           468:
        !           469:        for (va = s; va != e; va += PAGE_SIZE) {
        !           470:                if ((pte = pmap_pte(pmap, va)) == NULL)
        !           471:                        continue;
        !           472: #ifdef DEBUG
        !           473:                if (pmap_con_dbg & CD_CACHE) {
        !           474:                        printf("(cache_ctrl) pte@%p\n", pte);
        !           475:                }
        !           476: #endif /* DEBUG */
        !           477:                /*
        !           478:                 * Invalidate pte temporarily to avoid being written back
        !           479:                 * the modified bit and/or the reference bit by any other cpu.
        !           480:                 * XXX
        !           481:                 */
        !           482:                opte = invalidate_pte(pte);
        !           483:                *pte = (opte & ~CACHE_MASK) | mode;
        !           484:                flush_atc_entry(pmap, va);
        !           485:
        !           486:                /*
        !           487:                 * Data cache should be copied back and invalidated if
        !           488:                 * the old mapping was cached.
        !           489:                 */
        !           490:                if ((opte & CACHE_INH) == 0) {
        !           491:                        pa = ptoa(PG_PFNUM(opte));
        !           492: #ifdef MULTIPROCESSOR
        !           493:                        for (cpu = 0; cpu < MAX_CPUS; cpu++)
        !           494:                                if (m88k_cpus[cpu].ci_alive != 0)
        !           495: #else
        !           496:                        cpu = cpu_number();
        !           497: #endif
        !           498:                                        cmmu_flush_cache(cpu, pa, PAGE_SIZE);
        !           499:                }
        !           500:        }
        !           501:        PMAP_UNLOCK(pmap);
        !           502:        splx(spl);
        !           503: }
        !           504:
        !           505: /*
        !           506:  * Routine:    PMAP_BOOTSTRAP
        !           507:  *
        !           508:  * Function:
        !           509:  *     Bootstrap the system enough to run with virtual memory.
        !           510:  *     Map the kernel's code and data, allocate the kernel
        !           511:  *     translation table space, and map control registers
        !           512:  *     and other IO addresses.
        !           513:  *
        !           514:  * Parameters:
        !           515:  *     load_start      PA where kernel was loaded
        !           516:  *
        !           517:  * Extern/Global:
        !           518:  *
        !           519:  *     PAGE_SIZE       VM (software) page size
        !           520:  *     etext           end of kernel text
        !           521:  *     phys_map_vaddr  VA of page mapped arbitrarily for debug/IO
        !           522:  *
        !           523:  * Calls:
        !           524:  *     __cpu_simple_lock_init
        !           525:  *     pmap_map
        !           526:  *
        !           527:  *    The physical address 'load_start' is mapped at
        !           528:  * VM_MIN_KERNEL_ADDRESS, which maps the kernel code and data at the
        !           529:  * virtual address for which it was (presumably) linked. Immediately
        !           530:  * following the end of the kernel code/data, sufficient page of
        !           531:  * physical memory are reserved to hold translation tables for the kernel
        !           532:  * address space.
        !           533:  *
        !           534:  *    A pair of virtual pages per cpu are reserved for debugging and
        !           535:  * IO purposes. They are arbitrarily mapped when needed. They are used,
        !           536:  * for example, by pmap_copy_page and pmap_zero_page.
        !           537:  *
        !           538:  *    This implementation also assumes that the space below the kernel
        !           539:  * is reserved (typically from PROM purposes). We should ideally map it
        !           540:  * read only except when invoking its services...
        !           541:  */
        !           542:
        !           543: void
        !           544: pmap_bootstrap(vaddr_t load_start)
        !           545: {
        !           546:        kpdt_entry_t kpdt_virt;
        !           547:        sdt_entry_t *kmap;
        !           548:        vaddr_t vaddr, virt;
        !           549:        paddr_t s_text, e_text, kpdt_phys;
        !           550:        unsigned int kernel_pmap_size, pdt_size;
        !           551:        int i;
        !           552: #ifndef MULTIPROCESSOR
        !           553:        cpuid_t cpu;
        !           554: #endif
        !           555:        pmap_table_t ptable;
        !           556:        extern void *etext;
        !           557:
        !           558: #ifdef MULTIPROCESSOR
        !           559:        __cpu_simple_lock_init(&kernel_pmap->pm_lock);
        !           560: #endif
        !           561:
        !           562:        /*
        !           563:         * Allocate the kernel page table from the front of available
        !           564:         * physical memory, i.e. just after where the kernel image was loaded.
        !           565:         */
        !           566:        /*
        !           567:         * The calling sequence is
        !           568:         *    ...
        !           569:         *  pmap_bootstrap(&kernelstart, ...);
        !           570:         * kernelstart being the first symbol in the load image.
        !           571:         */
        !           572:
        !           573:        avail_start = round_page(avail_start);
        !           574:        virtual_avail = avail_start;
        !           575:
        !           576:        /*
        !           577:         * Initialize kernel_pmap structure
        !           578:         */
        !           579:        kernel_pmap->pm_count = 1;
        !           580:        kernel_pmap->pm_cpus = 0;
        !           581:        kmap = (sdt_entry_t *)(avail_start);
        !           582:        kernel_pmap->pm_stab = (sdt_entry_t *)virtual_avail;
        !           583:        kmapva = virtual_avail;
        !           584:
        !           585:        /*
        !           586:         * Reserve space for segment table entries.
        !           587:         * One for the regular segment table and one for the shadow table
        !           588:         * The shadow table keeps track of the virtual address of page
        !           589:         * tables. This is used in virtual-to-physical address translation
        !           590:         * functions. Remember, MMU cares only for physical addresses of
        !           591:         * segment and page table addresses. For kernel page tables, we
        !           592:         * really don't need this virtual stuff (since the kernel will
        !           593:         * be mapped 1-to-1) but for user page tables, this is required.
        !           594:         * Just to be consistent, we will maintain the shadow table for
        !           595:         * kernel pmap also.
        !           596:         */
        !           597:        kernel_pmap_size = 2 * SDT_SIZE;
        !           598:
        !           599: #ifdef DEBUG
        !           600:        printf("kernel segment table size = 0x%x\n", kernel_pmap_size);
        !           601: #endif
        !           602:        /* init all segment descriptors to zero */
        !           603:        bzero(kernel_pmap->pm_stab, kernel_pmap_size);
        !           604:
        !           605:        avail_start += kernel_pmap_size;
        !           606:        virtual_avail += kernel_pmap_size;
        !           607:
        !           608:        /* make sure page tables are page aligned!! XXX smurph */
        !           609:        avail_start = round_page(avail_start);
        !           610:        virtual_avail = round_page(virtual_avail);
        !           611:
        !           612:        /* save pointers to where page table entries start in physical memory */
        !           613:        kpdt_phys = avail_start;
        !           614:        kpdt_virt = (kpdt_entry_t)virtual_avail;
        !           615:
        !           616:        /* Compute how much space we need for the kernel page table */
        !           617:        pdt_size = atop(VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS)
        !           618:            * sizeof(pt_entry_t);
        !           619:        for (ptable = pmap_table_build(); ptable->size != (vsize_t)-1; ptable++)
        !           620:                pdt_size += atop(ptable->size) * sizeof(pt_entry_t);
        !           621:        pdt_size = round_page(pdt_size);
        !           622:        kernel_pmap_size += pdt_size;
        !           623:        avail_start += pdt_size;
        !           624:        virtual_avail += pdt_size;
        !           625:
        !           626:        /* init all page descriptors to zero */
        !           627:        bzero((void *)kpdt_phys, pdt_size);
        !           628: #ifdef DEBUG
        !           629:        printf("--------------------------------------\n");
        !           630:        printf("        kernel page start = 0x%x\n", kpdt_phys);
        !           631:        printf("   kernel page table size = 0x%x\n", pdt_size);
        !           632:        printf("          kernel page end = 0x%x\n", avail_start);
        !           633:
        !           634:        printf("kpdt_virt = 0x%x\n", kpdt_virt);
        !           635: #endif
        !           636:        /*
        !           637:         * init the kpdt queue
        !           638:         */
        !           639:        kpdt_free = kpdt_virt;
        !           640:        for (i = pdt_size / PDT_SIZE; i != 0; i--) {
        !           641:                kpdt_virt->next = (kpdt_entry_t)((vaddr_t)kpdt_virt + PDT_SIZE);
        !           642:                kpdt_virt->phys = kpdt_phys;
        !           643:                kpdt_virt = kpdt_virt->next;
        !           644:                kpdt_phys += PDT_SIZE;
        !           645:        }
        !           646:        kpdt_virt->next = NULL; /* terminate the list */
        !           647:
        !           648:        /*
        !           649:         * Map the kernel image into virtual space
        !           650:         */
        !           651:
        !           652:        s_text = trunc_page(load_start);        /* paddr of text */
        !           653:        e_text = round_page((vaddr_t)&etext);   /* paddr of end of text */
        !           654:
        !           655:        /* map the PROM area */
        !           656:        vaddr = pmap_map(0, 0, s_text, VM_PROT_WRITE | VM_PROT_READ, CACHE_INH);
        !           657:
        !           658:        /* map the kernel text read only */
        !           659:        vaddr = pmap_map(s_text, s_text, e_text, VM_PROT_READ, 0);
        !           660:
        !           661:        vaddr = pmap_map(vaddr, e_text, (paddr_t)kmap,
        !           662:            VM_PROT_WRITE | VM_PROT_READ, 0);
        !           663:
        !           664:        /*
        !           665:         * Map system segment & page tables - should be cache inhibited?
        !           666:         * 88200 manual says that CI bit is driven on the Mbus while accessing
        !           667:         * the translation tree. I don't think we need to map it CACHE_INH
        !           668:         * here...
        !           669:         */
        !           670:        if (kmapva != vaddr) {
        !           671:                while (vaddr < (virtual_avail - kernel_pmap_size))
        !           672:                        vaddr = round_page(vaddr + 1);
        !           673:        }
        !           674:        vaddr = pmap_map(vaddr, (paddr_t)kmap, avail_start,
        !           675:            VM_PROT_WRITE | VM_PROT_READ, CACHE_INH);
        !           676:
        !           677:        vaddr = pmap_bootstrap_md(vaddr);
        !           678:
        !           679:        virtual_avail = round_page(virtual_avail);
        !           680:        virtual_end = VM_MAX_KERNEL_ADDRESS;
        !           681:
        !           682:        /*
        !           683:         * Map two pages per cpu for copying/zeroing.
        !           684:         */
        !           685:
        !           686:        phys_map_vaddr = virtual_avail;
        !           687:        phys_map_vaddr_end = virtual_avail + 2 * (max_cpus << PAGE_SHIFT);
        !           688:        avail_start += 2 * (max_cpus << PAGE_SHIFT);
        !           689:        virtual_avail += 2 * (max_cpus << PAGE_SHIFT);
        !           690:
        !           691:        /*
        !           692:         * Create all the machine-specific mappings.
        !           693:         */
        !           694:
        !           695:        for (ptable = pmap_table_build(); ptable->size != (vsize_t)-1; ptable++)
        !           696:                if (ptable->size != 0) {
        !           697:                        pmap_map(ptable->virt_start, ptable->phys_start,
        !           698:                            ptable->phys_start + ptable->size,
        !           699:                            ptable->prot, ptable->cacheability);
        !           700:                }
        !           701:
        !           702:        /*
        !           703:         * Allocate all the submaps we need. Note that SYSMAP just allocates
        !           704:         * kernel virtual address with no physical backing memory. The idea
        !           705:         * is physical memory will be mapped at this va before using that va.
        !           706:         * This means that if different physical pages are going to be mapped
        !           707:         * at different times, we better do a tlb flush before using it -
        !           708:         * else we will be referencing the wrong page.
        !           709:         */
        !           710:
        !           711: #define        SYSMAP(c, p, v, n)      \
        !           712: ({ \
        !           713:        v = (c)virt; \
        !           714:        if ((p = pmap_pte(kernel_pmap, virt)) == NULL) \
        !           715:                pmap_expand_kmap(virt, VM_PROT_READ | VM_PROT_WRITE, 0); \
        !           716:        virt += ((n) * PAGE_SIZE); \
        !           717: })
        !           718:
        !           719:        virt = virtual_avail;
        !           720:
        !           721:        SYSMAP(caddr_t, vmpte, vmmap, 1);
        !           722:        invalidate_pte(vmpte);
        !           723:
        !           724:        SYSMAP(struct msgbuf *, msgbufmap, msgbufp, btoc(MSGBUFSIZE));
        !           725:
        !           726:        virtual_avail = virt;
        !           727:
        !           728:        /*
        !           729:         * Switch to using new page tables
        !           730:         */
        !           731:
        !           732:        kernel_pmap->pm_apr = (atop((paddr_t)kmap) << PG_SHIFT) |
        !           733:            CACHE_GLOBAL | CACHE_WT | APR_V;
        !           734:
        !           735:        /* Invalidate entire kernel TLB and get ready for address translation */
        !           736: #ifdef MULTIPROCESSOR
        !           737:        pmap_bootstrap_cpu(cpu_number());
        !           738: #else
        !           739:        cpu = cpu_number();
        !           740:        cmmu_flush_tlb(cpu, TRUE, 0, -1);
        !           741:        /* Load supervisor pointer to segment table. */
        !           742:        cmmu_set_sapr(cpu, kernel_pmap->pm_apr);
        !           743: #ifdef DEBUG
        !           744:        printf("cpu%d: running virtual\n", cpu);
        !           745: #endif
        !           746:        SETBIT_CPUSET(cpu, &kernel_pmap->pm_cpus);
        !           747: #endif /* MULTIPROCESSOR */
        !           748: }
        !           749:
        !           750: #ifdef MULTIPROCESSOR
        !           751: void
        !           752: pmap_bootstrap_cpu(cpuid_t cpu)
        !           753: {
        !           754:        if (cpu != master_cpu) {
        !           755:                cmmu_initialize_cpu(cpu);
        !           756:        } else {
        !           757:                cmmu_flush_tlb(cpu, TRUE, 0, -1);
        !           758:        }
        !           759:        /* Load supervisor pointer to segment table. */
        !           760:        cmmu_set_sapr(cpu, kernel_pmap->pm_apr);
        !           761: #ifdef DEBUG
        !           762:        printf("cpu%d: running virtual\n", cpu);
        !           763: #endif
        !           764:        SETBIT_CPUSET(cpu, &kernel_pmap->pm_cpus);
        !           765: }
        !           766: #endif
        !           767:
        !           768: /*
        !           769:  * Routine:    PMAP_INIT
        !           770:  *
        !           771:  * Function:
        !           772:  *     Initialize the pmap module. It is called by vm_init, to initialize
        !           773:  *     any structures that the pmap system needs to map virtual memory.
        !           774:  *
        !           775:  * Calls:
        !           776:  *     pool_init
        !           777:  *
        !           778:  *   This routine does not really have much to do. It initializes
        !           779:  * pools for pmap structures and pv_entry structures.
        !           780:  */
        !           781: void
        !           782: pmap_init(void)
        !           783: {
        !           784: #ifdef DEBUG
        !           785:        if (pmap_con_dbg & CD_INIT)
        !           786:                printf("pmap_init()\n");
        !           787: #endif
        !           788:
        !           789:        pool_init(&pmappool, sizeof(struct pmap), 0, 0, 0, "pmappl",
        !           790:            &pool_allocator_nointr);
        !           791:        pool_init(&pvpool, sizeof(pv_entry_t), 0, 0, 0, "pvpl", NULL);
        !           792: } /* pmap_init() */
        !           793:
        !           794: /*
        !           795:  * Routine:    PMAP_ZERO_PAGE
        !           796:  *
        !           797:  * Function:
        !           798:  *     Zeroes the specified page.
        !           799:  *
        !           800:  * Parameters:
        !           801:  *     pg              page to zero
        !           802:  *
        !           803:  * Extern/Global:
        !           804:  *     phys_map_vaddr
        !           805:  *
        !           806:  * Special Assumptions:
        !           807:  *     no locking required
        !           808:  *
        !           809:  *     This routine maps the physical pages at the 'phys_map' virtual
        !           810:  * address set up in pmap_bootstrap. It flushes the TLB to make the new
        !           811:  * mappings effective, and zeros all the bits.
        !           812:  */
        !           813: void
        !           814: pmap_zero_page(struct vm_page *pg)
        !           815: {
        !           816:        paddr_t pa = VM_PAGE_TO_PHYS(pg);
        !           817:        vaddr_t va;
        !           818:        int spl;
        !           819:        int cpu = cpu_number();
        !           820:        pt_entry_t *pte;
        !           821:
        !           822:        va = (vaddr_t)(phys_map_vaddr + 2 * (cpu << PAGE_SHIFT));
        !           823:        pte = pmap_pte(kernel_pmap, va);
        !           824:
        !           825:        spl = splvm();
        !           826:
        !           827:        *pte = m88k_protection(VM_PROT_READ | VM_PROT_WRITE) |
        !           828:            PG_M /* 88110 */ | PG_V | pa;
        !           829:
        !           830:        /*
        !           831:         * We don't need the flush_atc_entry() dance, as these pages are
        !           832:         * bound to only one cpu.
        !           833:         */
        !           834:        cmmu_flush_tlb(cpu, TRUE, va, 1);
        !           835:
        !           836:        /*
        !           837:         * The page is likely to be a non-kernel mapping, and as
        !           838:         * such write back. Also, we might have split U/S caches!
        !           839:         * So be sure to have the pa flushed after the filling.
        !           840:         */
        !           841:        bzero((void *)va, PAGE_SIZE);
        !           842:        cmmu_flush_data_page(cpu, pa);
        !           843:
        !           844:        splx(spl);
        !           845: }
        !           846:
        !           847: /*
        !           848:  * Routine:    PMAP_CREATE
        !           849:  *
        !           850:  * Function:
        !           851:  *     Create and return a physical map. If the size specified for the
        !           852:  *     map is zero, the map is an actual physical map, and may be referenced
        !           853:  *     by the hardware. If the size specified is non-zero, the map will be
        !           854:  *     used in software only, and is bounded by that size.
        !           855:  *
        !           856:  *  This routines allocates a pmap structure.
        !           857:  */
        !           858: pmap_t
        !           859: pmap_create(void)
        !           860: {
        !           861:        pmap_t pmap;
        !           862:        sdt_entry_t *segdt;
        !           863:        paddr_t stpa;
        !           864:        u_int s;
        !           865:
        !           866:        pmap = pool_get(&pmappool, PR_WAITOK);
        !           867:        bzero(pmap, sizeof(*pmap));
        !           868:
        !           869:        /*
        !           870:         * Allocate memory for *actual* segment table and *shadow* table.
        !           871:         */
        !           872:        s = round_page(2 * SDT_SIZE);
        !           873: #ifdef DEBUG
        !           874:        if (pmap_con_dbg & CD_CREAT) {
        !           875:                printf("(pmap_create: %x) need %d pages for sdt\n",
        !           876:                    curproc, atop(s));
        !           877:        }
        !           878: #endif
        !           879:
        !           880:        segdt = (sdt_entry_t *)uvm_km_zalloc(kernel_map, s);
        !           881:        if (segdt == NULL)
        !           882:                panic("pmap_create: uvm_km_zalloc failure");
        !           883:
        !           884:        /*
        !           885:         * Initialize pointer to segment table both virtual and physical.
        !           886:         */
        !           887:        pmap->pm_stab = segdt;
        !           888:        if (pmap_extract(kernel_pmap, (vaddr_t)segdt,
        !           889:            (paddr_t *)&stpa) == FALSE)
        !           890:                panic("pmap_create: pmap_extract failed!");
        !           891:        pmap->pm_apr = (atop(stpa) << PG_SHIFT) | CACHE_GLOBAL | APR_V;
        !           892:
        !           893: #ifdef DEBUG
        !           894:        if (stpa & PAGE_MASK)
        !           895:                panic("pmap_create: sdt_table 0x%x not aligned on page boundary",
        !           896:                    (int)stpa);
        !           897:
        !           898:        if (pmap_con_dbg & CD_CREAT) {
        !           899:                printf("(pmap_create: %x) pmap=%p, pm_stab=0x%x (pa 0x%x)\n",
        !           900:                    curproc, pmap, pmap->pm_stab, stpa);
        !           901:        }
        !           902: #endif
        !           903:
        !           904:        /* memory for page tables should not be writeback or local */
        !           905:        pmap_cache_ctrl(kernel_pmap,
        !           906:            (vaddr_t)segdt, (vaddr_t)segdt + s, CACHE_WT);
        !           907:
        !           908:        /*
        !           909:         * Initialize SDT_ENTRIES.
        !           910:         */
        !           911:        /*
        !           912:         * There is no need to clear segment table, since uvm_km_zalloc
        !           913:         * provides us clean pages.
        !           914:         */
        !           915:
        !           916:        /*
        !           917:         * Initialize pmap structure.
        !           918:         */
        !           919:        pmap->pm_count = 1;
        !           920: #ifdef MULTIPROCESSOR
        !           921:        __cpu_simple_lock_init(&pmap->pm_lock);
        !           922: #endif
        !           923:        pmap->pm_cpus = 0;
        !           924:
        !           925:        return pmap;
        !           926: }
        !           927:
        !           928: /*
        !           929:  * Routine:    PMAP_RELEASE
        !           930:  *
        !           931:  *     Internal procedure used by pmap_destroy() to actualy deallocate
        !           932:  *     the tables.
        !           933:  *
        !           934:  * Parameters:
        !           935:  *     pmap            pointer to pmap structure
        !           936:  *
        !           937:  * Calls:
        !           938:  *     pmap_pte
        !           939:  *     uvm_km_free
        !           940:  *
        !           941:  * Special Assumptions:
        !           942:  *     No locking is needed, since this is only called which the
        !           943:  *     pm_count field of the pmap structure goes to zero.
        !           944:  *
        !           945:  * This routine sequences of through the user address space, releasing
        !           946:  * all translation table space back to the system using uvm_km_free.
        !           947:  * The loops are indexed by the virtual address space
        !           948:  * ranges represented by the table group sizes (1 << SDT_SHIFT).
        !           949:  */
        !           950: void
        !           951: pmap_release(pmap_t pmap)
        !           952: {
        !           953:        u_int sdt;              /* outer loop index */
        !           954:        sdt_entry_t *sdttbl;    /* ptr to first entry in the segment table */
        !           955:        pt_entry_t *gdttbl;     /* ptr to first entry in a page table */
        !           956:
        !           957: #ifdef DEBUG
        !           958:        if (pmap_con_dbg & CD_FREE)
        !           959:                printf("(pmap_release: %x) pmap %x\n", curproc, pmap);
        !           960: #endif
        !           961:
        !           962:        /* segment table loop */
        !           963:        for (sdt = VM_MIN_ADDRESS >> SDT_SHIFT;
        !           964:            sdt <= VM_MAX_ADDRESS >> SDT_SHIFT; sdt++) {
        !           965:                if ((gdttbl = pmap_pte(pmap, sdt << SDT_SHIFT)) != NULL) {
        !           966: #ifdef DEBUG
        !           967:                        if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL))
        !           968:                                printf("(pmap_release: %x) free page table = 0x%x\n",
        !           969:                                    curproc, gdttbl);
        !           970: #endif
        !           971:                        uvm_km_free(kernel_map, (vaddr_t)gdttbl, PAGE_SIZE);
        !           972:                }
        !           973:        }
        !           974:
        !           975:        /*
        !           976:         * Freeing both *actual* and *shadow* segment tables
        !           977:         */
        !           978:        sdttbl = pmap->pm_stab;         /* addr of segment table */
        !           979: #ifdef DEBUG
        !           980:        if ((pmap_con_dbg & (CD_FREE | CD_FULL)) == (CD_FREE | CD_FULL))
        !           981:                printf("(pmap_release: %x) free segment table = 0x%x\n",
        !           982:                    curproc, sdttbl);
        !           983: #endif
        !           984:        uvm_km_free(kernel_map, (vaddr_t)sdttbl, round_page(2 * SDT_SIZE));
        !           985:
        !           986: #ifdef DEBUG
        !           987:        if (pmap_con_dbg & CD_FREE)
        !           988:                printf("(pmap_release: %x) pm_count = 0\n", curproc);
        !           989: #endif
        !           990: }
        !           991:
        !           992: /*
        !           993:  * Routine:    PMAP_DESTROY
        !           994:  *
        !           995:  * Function:
        !           996:  *     Retire the given physical map from service. Should only be called
        !           997:  *     if the map contains no valid mappings.
        !           998:  *
        !           999:  * Parameters:
        !          1000:  *     pmap            pointer to pmap structure
        !          1001:  *
        !          1002:  * Calls:
        !          1003:  *     pmap_release
        !          1004:  *     pool_put
        !          1005:  *
        !          1006:  * Special Assumptions:
        !          1007:  *     Map contains no valid mappings.
        !          1008:  *
        !          1009:  *  This routine decrements the reference count in the pmap
        !          1010:  * structure. If it goes to zero, pmap_release is called to release
        !          1011:  * the memory space to the system. Then, call pool_put to free the
        !          1012:  * pmap structure.
        !          1013:  */
        !          1014: void
        !          1015: pmap_destroy(pmap_t pmap)
        !          1016: {
        !          1017:        int count;
        !          1018:
        !          1019: #ifdef DEBUG
        !          1020:        if (pmap == kernel_pmap)
        !          1021:                panic("pmap_destroy: Attempt to destroy kernel pmap");
        !          1022: #endif
        !          1023:
        !          1024:        PMAP_LOCK(pmap);
        !          1025:        count = --pmap->pm_count;
        !          1026:        PMAP_UNLOCK(pmap);
        !          1027:        if (count == 0) {
        !          1028:                pmap_release(pmap);
        !          1029:                pool_put(&pmappool, pmap);
        !          1030:        }
        !          1031: }
        !          1032:
        !          1033:
        !          1034: /*
        !          1035:  * Routine:    PMAP_REFERENCE
        !          1036:  *
        !          1037:  * Function:
        !          1038:  *     Add a reference to the specified pmap.
        !          1039:  *
        !          1040:  * Parameters:
        !          1041:  *     pmap            pointer to pmap structure
        !          1042:  *
        !          1043:  * Under a pmap read lock, the pm_count field of the pmap structure
        !          1044:  * is incremented. The function then returns.
        !          1045:  */
        !          1046: void
        !          1047: pmap_reference(pmap_t pmap)
        !          1048: {
        !          1049:        PMAP_LOCK(pmap);
        !          1050:        pmap->pm_count++;
        !          1051:        PMAP_UNLOCK(pmap);
        !          1052: }
        !          1053:
        !          1054: /*
        !          1055:  * Routine:    PMAP_REMOVE_PTE (internal)
        !          1056:  *
        !          1057:  * Function:
        !          1058:  *     Invalidate a given page table entry associated with the
        !          1059:  *     given virtual address.
        !          1060:  *
        !          1061:  * Parameters:
        !          1062:  *     pmap            pointer to pmap structure
        !          1063:  *     va              virtual address of page to remove
        !          1064:  *     pte             existing pte
        !          1065:  *
        !          1066:  * External/Global:
        !          1067:  *     pv lists
        !          1068:  *
        !          1069:  * Calls:
        !          1070:  *     pool_put
        !          1071:  *     invalidate_pte
        !          1072:  *     flush_atc_entry
        !          1073:  *
        !          1074:  * Special Assumptions:
        !          1075:  *     The pmap must be locked.
        !          1076:  *
        !          1077:  *  If the PTE is valid, the routine must invalidate the entry. The
        !          1078:  * 'modified' bit, if on, is referenced to the VM, and into the appropriate
        !          1079:  * entry in the PV list entry. Next, the function must find the PV
        !          1080:  * list entry associated with this pmap/va (if it doesn't exist - the function
        !          1081:  * panics). The PV list entry is unlinked from the list, and returned to
        !          1082:  * its zone.
        !          1083:  */
        !          1084: void
        !          1085: pmap_remove_pte(pmap_t pmap, vaddr_t va, pt_entry_t *pte)
        !          1086: {
        !          1087:        pt_entry_t opte;
        !          1088:        pv_entry_t prev, cur, pvl;
        !          1089:        struct vm_page *pg;
        !          1090:        paddr_t pa;
        !          1091:
        !          1092: #ifdef DEBUG
        !          1093:        if (pmap_con_dbg & CD_RM) {
        !          1094:                if (pmap == kernel_pmap)
        !          1095:                        printf("(pmap_remove_pte: %x) pmap kernel va %x\n", curproc, va);
        !          1096:                else
        !          1097:                        printf("(pmap_remove_pte: %x) pmap %x va %x\n", curproc, pmap, va);
        !          1098:        }
        !          1099: #endif
        !          1100:
        !          1101:        if (pte == NULL || !PDT_VALID(pte)) {
        !          1102:                return;         /* no page mapping, nothing to do! */
        !          1103:        }
        !          1104:
        !          1105:        /*
        !          1106:         * Update statistics.
        !          1107:         */
        !          1108:        pmap->pm_stats.resident_count--;
        !          1109:        if (pmap_pte_w(pte))
        !          1110:                pmap->pm_stats.wired_count--;
        !          1111:
        !          1112:        pa = ptoa(PG_PFNUM(*pte));
        !          1113:
        !          1114:        /*
        !          1115:         * Invalidate the pte.
        !          1116:         */
        !          1117:
        !          1118:        opte = invalidate_pte(pte) & PG_M_U;
        !          1119:        flush_atc_entry(pmap, va);
        !          1120:
        !          1121:        pg = PHYS_TO_VM_PAGE(pa);
        !          1122:
        !          1123:        /* If this isn't a managed page, just return. */
        !          1124:        if (pg == NULL)
        !          1125:                return;
        !          1126:
        !          1127:        /*
        !          1128:         * Remove the mapping from the pvlist for
        !          1129:         * this physical page.
        !          1130:         */
        !          1131:        pvl = pg_to_pvh(pg);
        !          1132:
        !          1133: #ifdef DIAGNOSTIC
        !          1134:        if (pvl->pv_pmap == NULL)
        !          1135:                panic("pmap_remove_pte: null pv_list");
        !          1136: #endif
        !          1137:
        !          1138:        prev = NULL;
        !          1139:        for (cur = pvl; cur != NULL; cur = cur->pv_next) {
        !          1140:                if (cur->pv_va == va && cur->pv_pmap == pmap)
        !          1141:                        break;
        !          1142:                prev = cur;
        !          1143:        }
        !          1144:        if (cur == NULL) {
        !          1145:                panic("pmap_remove_pte: mapping for va "
        !          1146:                    "0x%lx (pa 0x%lx) not in pv list at %p",
        !          1147:                    va, pa, pvl);
        !          1148:        }
        !          1149:
        !          1150:        if (prev == NULL) {
        !          1151:                /*
        !          1152:                 * Hander is the pv_entry. Copy the next one
        !          1153:                 * to hander and free the next one (we can't
        !          1154:                 * free the hander)
        !          1155:                 */
        !          1156:                cur = cur->pv_next;
        !          1157:                if (cur != NULL) {
        !          1158:                        cur->pv_flags = pvl->pv_flags;
        !          1159:                        *pvl = *cur;
        !          1160:                        pool_put(&pvpool, cur);
        !          1161:                } else {
        !          1162:                        pvl->pv_pmap = NULL;
        !          1163:                }
        !          1164:        } else {
        !          1165:                prev->pv_next = cur->pv_next;
        !          1166:                pool_put(&pvpool, cur);
        !          1167:        }
        !          1168:
        !          1169:        /* Update saved attributes for managed page */
        !          1170:        pvl->pv_flags |= opte;
        !          1171: }
        !          1172:
        !          1173: /*
        !          1174:  * Routine:    PMAP_REMOVE_RANGE (internal)
        !          1175:  *
        !          1176:  * Function:
        !          1177:  *     Invalidate page table entries associated with the
        !          1178:  *     given virtual address range. The entries given are the first
        !          1179:  *     (inclusive) and last (exclusive) entries for the VM pages.
        !          1180:  *
        !          1181:  * Parameters:
        !          1182:  *     pmap            pointer to pmap structure
        !          1183:  *     s               virtual address of start of range to remove
        !          1184:  *     e               virtual address of end of range to remove
        !          1185:  *
        !          1186:  * External/Global:
        !          1187:  *     pv lists
        !          1188:  *
        !          1189:  * Calls:
        !          1190:  *     pmap_pte
        !          1191:  *     pmap_remove_pte
        !          1192:  *
        !          1193:  * Special Assumptions:
        !          1194:  *     The pmap must be locked.
        !          1195:  *
        !          1196:  *   This routine sequences through the pages defined by the given
        !          1197:  * range. For each page, the associated page table entry (PTE) is
        !          1198:  * invalidated via pmap_remove_pte().
        !          1199:  *
        !          1200:  * Empty segments are skipped for performance.
        !          1201:  */
        !          1202: void
        !          1203: pmap_remove_range(pmap_t pmap, vaddr_t s, vaddr_t e)
        !          1204: {
        !          1205:        vaddr_t va, eseg;
        !          1206:
        !          1207: #ifdef DEBUG
        !          1208:        if (pmap_con_dbg & CD_RM) {
        !          1209:                if (pmap == kernel_pmap)
        !          1210:                        printf("(pmap_remove_range: %x) pmap kernel s %x e %x\n", curproc, s, e);
        !          1211:                else
        !          1212:                        printf("(pmap_remove_range: %x) pmap %x s %x e %x\n", curproc, pmap, s, e);
        !          1213:        }
        !          1214: #endif
        !          1215:
        !          1216:        /*
        !          1217:         * Loop through the range in PAGE_SIZE increments.
        !          1218:         */
        !          1219:        va = s;
        !          1220:        while (va != e) {
        !          1221:                sdt_entry_t *sdt;
        !          1222:
        !          1223:                eseg = (va & SDT_MASK) + (1 << SDT_SHIFT);
        !          1224:                if (eseg > e || eseg == 0)
        !          1225:                        eseg = e;
        !          1226:
        !          1227:                sdt = SDTENT(pmap, va);
        !          1228:
        !          1229:                /* If no segment table, skip a whole segment */
        !          1230:                if (!SDT_VALID(sdt))
        !          1231:                        va = eseg;
        !          1232:                else {
        !          1233:                        while (va != eseg) {
        !          1234:                                pmap_remove_pte(pmap, va, sdt_pte(sdt, va));
        !          1235:                                va += PAGE_SIZE;
        !          1236:                        }
        !          1237:                }
        !          1238:        }
        !          1239: }
        !          1240:
        !          1241: /*
        !          1242:  * Routine:    PMAP_REMOVE
        !          1243:  *
        !          1244:  * Function:
        !          1245:  *     Remove the given range of addresses from the specified map.
        !          1246:  *     It is assumed that start and end are properly rounded to the VM page
        !          1247:  *     size.
        !          1248:  *
        !          1249:  * Parameters:
        !          1250:  *     pmap            pointer to pmap structure
        !          1251:  *     s
        !          1252:  *     e
        !          1253:  *
        !          1254:  * Special Assumptions:
        !          1255:  *     Assumes not all entries must be valid in specified range.
        !          1256:  *
        !          1257:  * Calls:
        !          1258:  *     pmap_remove_range
        !          1259:  *
        !          1260:  *  After taking pmap read lock, pmap_remove_range is called to do the
        !          1261:  * real work.
        !          1262:  */
        !          1263: void
        !          1264: pmap_remove(pmap_t pmap, vaddr_t s, vaddr_t e)
        !          1265: {
        !          1266:        int spl;
        !          1267:
        !          1268:        if (pmap == NULL)
        !          1269:                return;
        !          1270:
        !          1271: #ifdef DEBUG
        !          1272:        if (s >= e)
        !          1273:                panic("pmap_remove: start greater than end address");
        !          1274: #endif
        !          1275:
        !          1276:        spl = splvm();
        !          1277:        PMAP_LOCK(pmap);
        !          1278:        pmap_remove_range(pmap, s, e);
        !          1279:        PMAP_UNLOCK(pmap);
        !          1280:        splx(spl);
        !          1281: }
        !          1282:
        !          1283: /*
        !          1284:  * Routine:    PMAP_REMOVE_ALL
        !          1285:  *
        !          1286:  * Function:
        !          1287:  *     Removes this physical page from all physical maps in which it
        !          1288:  *     resides. Reflects back modify bits to the pager.
        !          1289:  *
        !          1290:  * Parameters:
        !          1291:  *     pg              physical pages which is to
        !          1292:  *                     be removed from all maps
        !          1293:  *
        !          1294:  * Extern/Global:
        !          1295:  *     pv lists
        !          1296:  *
        !          1297:  * Calls:
        !          1298:  *     pmap_pte
        !          1299:  *     pool_put
        !          1300:  *
        !          1301:  *  If the page specified by the given address is not a managed page,
        !          1302:  * this routine simply returns. Otherwise, the PV list associated with
        !          1303:  * that page is traversed. For each pmap/va pair pmap_pte is called to
        !          1304:  * obtain a pointer to the page table entry (PTE) associated with the
        !          1305:  * va (the PTE must exist and be valid, otherwise the routine panics).
        !          1306:  * The hardware 'modified' bit in the PTE is examined. If it is on, the
        !          1307:  * corresponding bit in the PV list entry corresponding
        !          1308:  * to the physical page is set to 1.
        !          1309:  * Then, the PTE is invalidated, and the PV list entry is unlinked and
        !          1310:  * freed.
        !          1311:  *
        !          1312:  *  At the end of this function, the PV list for the specified page
        !          1313:  * will be null.
        !          1314:  */
        !          1315: void
        !          1316: pmap_remove_all(struct vm_page *pg)
        !          1317: {
        !          1318:        pt_entry_t *pte;
        !          1319:        pv_entry_t pvl;
        !          1320:        vaddr_t va;
        !          1321:        pmap_t pmap;
        !          1322:        int spl;
        !          1323:
        !          1324:        if (pg == NULL) {
        !          1325:                /* not a managed page. */
        !          1326: #ifdef DEBUG
        !          1327:                if (pmap_con_dbg & CD_RMAL)
        !          1328:                        printf("(pmap_remove_all: %x) vm page 0x%x not a managed page\n", curproc, pg);
        !          1329: #endif
        !          1330:                return;
        !          1331:        }
        !          1332:
        !          1333: #ifdef DEBUG
        !          1334:        if (pmap_con_dbg & CD_RMAL)
        !          1335:                printf("(pmap_remove_all: %x) va %x\n", curproc, pg, pg_to_pvh(pg)->pv_va);
        !          1336: #endif
        !          1337:
        !          1338:        spl = splvm();
        !          1339:        /*
        !          1340:         * Walk down PV list, removing all mappings.
        !          1341:         * We don't have to lock the pv list, since we have the entire pmap
        !          1342:         * system.
        !          1343:         */
        !          1344: #ifdef MULTIPROCESSOR
        !          1345: remove_all_Retry:
        !          1346: #endif
        !          1347:
        !          1348:        pvl = pg_to_pvh(pg);
        !          1349:
        !          1350:        /*
        !          1351:         * Loop for each entry on the pv list
        !          1352:         */
        !          1353:        while (pvl != NULL && (pmap = pvl->pv_pmap) != NULL) {
        !          1354: #ifdef MULTIPROCESSOR
        !          1355:                if (!__cpu_simple_lock_try(&pmap->pm_lock))
        !          1356:                        goto remove_all_Retry;
        !          1357: #endif
        !          1358:
        !          1359:                va = pvl->pv_va;
        !          1360:                pte = pmap_pte(pmap, va);
        !          1361:
        !          1362:                if (pte == NULL || !PDT_VALID(pte)) {
        !          1363:                        pvl = pvl->pv_next;
        !          1364:                        goto next;      /* no page mapping */
        !          1365:                }
        !          1366:                if (pmap_pte_w(pte)) {
        !          1367: #ifdef DEBUG
        !          1368:                        if (pmap_con_dbg & CD_RMAL)
        !          1369:                                printf("pmap_remove_all: wired mapping for %lx not removed\n",
        !          1370:                                    pg);
        !          1371: #endif
        !          1372:                        pvl = pvl->pv_next;
        !          1373:                        goto next;
        !          1374:                }
        !          1375:
        !          1376:                pmap_remove_pte(pmap, va, pte);
        !          1377:
        !          1378:                /*
        !          1379:                 * Do not free any page tables,
        !          1380:                 * leaves that for when VM calls pmap_collect().
        !          1381:                 */
        !          1382: next:
        !          1383:                PMAP_UNLOCK(pmap);
        !          1384:        }
        !          1385:        splx(spl);
        !          1386: }
        !          1387:
        !          1388: /*
        !          1389:  * Routine:    PMAP_PROTECT
        !          1390:  *
        !          1391:  * Function:
        !          1392:  *     Sets the physical protection on the specified range of this map
        !          1393:  *     as requested.
        !          1394:  *
        !          1395:  * Parameters:
        !          1396:  *     pmap            pointer to pmap structure
        !          1397:  *     s               start address of start of range
        !          1398:  *     e               end address of end of range
        !          1399:  *     prot            desired protection attributes
        !          1400:  *
        !          1401:  *     Calls:
        !          1402:  *             PMAP_LOCK, PMAP_UNLOCK
        !          1403:  *             pmap_pte
        !          1404:  *             PDT_VALID
        !          1405:  *
        !          1406:  *  This routine sequences through the pages of the specified range.
        !          1407:  * For each, it calls pmap_pte to acquire a pointer to the page table
        !          1408:  * entry (PTE). If the PTE is invalid, or non-existent, nothing is done.
        !          1409:  * Otherwise, the PTE's protection attributes are adjusted as specified.
        !          1410:  */
        !          1411: void
        !          1412: pmap_protect(pmap_t pmap, vaddr_t s, vaddr_t e, vm_prot_t prot)
        !          1413: {
        !          1414:        int spl;
        !          1415:        pt_entry_t *pte, ap;
        !          1416:        vaddr_t va, eseg;
        !          1417:
        !          1418:        if ((prot & VM_PROT_READ) == 0) {
        !          1419:                pmap_remove(pmap, s, e);
        !          1420:                return;
        !          1421:        }
        !          1422:
        !          1423:        ap = m88k_protection(prot);
        !          1424:
        !          1425:        spl = splvm();
        !          1426:        PMAP_LOCK(pmap);
        !          1427:
        !          1428:        /*
        !          1429:         * Loop through the range in PAGE_SIZE increments.
        !          1430:         */
        !          1431:        va = s;
        !          1432:        while (va != e) {
        !          1433:                sdt_entry_t *sdt;
        !          1434:
        !          1435:                eseg = (va & SDT_MASK) + (1 << SDT_SHIFT);
        !          1436:                if (eseg > e || eseg == 0)
        !          1437:                        eseg = e;
        !          1438:
        !          1439:                sdt = SDTENT(pmap, va);
        !          1440:
        !          1441:                /* If no segment table, skip a whole segment */
        !          1442:                if (!SDT_VALID(sdt))
        !          1443:                        va = eseg;
        !          1444:                else {
        !          1445:                        while (va != eseg) {
        !          1446:                                pte = sdt_pte(sdt, va);
        !          1447:                                if (pte != NULL && PDT_VALID(pte)) {
        !          1448:                                        /*
        !          1449:                                         * Invalidate pte temporarily to avoid
        !          1450:                                         * the modified bit and/or the
        !          1451:                                         * reference bit being written back by
        !          1452:                                         * any other cpu.
        !          1453:                                         */
        !          1454:                                        *pte = ap |
        !          1455:                                            (invalidate_pte(pte) & ~PG_PROT);
        !          1456:                                        flush_atc_entry(pmap, va);
        !          1457:                                }
        !          1458:                                va += PAGE_SIZE;
        !          1459:                        }
        !          1460:                }
        !          1461:        }
        !          1462:        PMAP_UNLOCK(pmap);
        !          1463:        splx(spl);
        !          1464: }
        !          1465:
        !          1466: /*
        !          1467:  * Routine:    PMAP_EXPAND
        !          1468:  *
        !          1469:  * Function:
        !          1470:  *     Expands a pmap to be able to map the specified virtual address.
        !          1471:  *     New kernel virtual memory is allocated for a page table.
        !          1472:  *
        !          1473:  *     Must be called with the pmap system and the pmap unlocked, since
        !          1474:  *     these must be unlocked to use vm_allocate or vm_deallocate (via
        !          1475:  *     uvm_km_zalloc). Thus it must be called in a unlock/lock loop
        !          1476:  *     that checks whether the map has been expanded enough. (We won't loop
        !          1477:  *     forever, since page table aren't shrunk.)
        !          1478:  *
        !          1479:  * Parameters:
        !          1480:  *     pmap    point to pmap structure
        !          1481:  *     v       VA indicating which tables are needed
        !          1482:  *
        !          1483:  * Extern/Global:
        !          1484:  *     user_pt_map
        !          1485:  *     kernel_pmap
        !          1486:  *
        !          1487:  * Calls:
        !          1488:  *     pmap_pte
        !          1489:  *     uvm_km_free
        !          1490:  *     uvm_km_zalloc
        !          1491:  *     pmap_extract
        !          1492:  *
        !          1493:  * Special Assumptions
        !          1494:  *     no pmap locks held
        !          1495:  *     pmap != kernel_pmap
        !          1496:  *
        !          1497:  * 1:  This routine immediately allocates space for a page table.
        !          1498:  *
        !          1499:  * 2:  The page table entries (PTEs) are initialized (set invalid), and
        !          1500:  *     the corresponding segment table entry is set to point to the new
        !          1501:  *     page table.
        !          1502:  */
        !          1503: void
        !          1504: pmap_expand(pmap_t pmap, vaddr_t v)
        !          1505: {
        !          1506:        int spl;
        !          1507:        vaddr_t pdt_vaddr;
        !          1508:        paddr_t pdt_paddr;
        !          1509:        sdt_entry_t *sdt;
        !          1510:        pt_entry_t *pte;
        !          1511:
        !          1512: #ifdef DEBUG
        !          1513:        if (pmap_con_dbg & CD_EXP)
        !          1514:                printf ("(pmap_expand: %x) map %x v %x\n", curproc, pmap, v);
        !          1515: #endif
        !          1516:
        !          1517:        /* XXX */
        !          1518:        pdt_vaddr = uvm_km_zalloc(kernel_map, PAGE_SIZE);
        !          1519:        if (pmap_extract(kernel_pmap, pdt_vaddr, &pdt_paddr) == FALSE)
        !          1520:                panic("pmap_expand: pmap_extract failed");
        !          1521:
        !          1522:        /* memory for page tables should not be writeback or local */
        !          1523:        pmap_cache_ctrl(kernel_pmap,
        !          1524:            pdt_vaddr, pdt_vaddr + PAGE_SIZE, CACHE_WT);
        !          1525:
        !          1526:        spl = splvm();
        !          1527:        PMAP_LOCK(pmap);
        !          1528:
        !          1529:        if ((pte = pmap_pte(pmap, v)) != NULL) {
        !          1530:                /*
        !          1531:                 * Someone else caused us to expand
        !          1532:                 * during our vm_allocate.
        !          1533:                 */
        !          1534:                PMAP_UNLOCK(pmap);
        !          1535:                uvm_km_free(kernel_map, pdt_vaddr, PAGE_SIZE);
        !          1536:
        !          1537: #ifdef DEBUG
        !          1538:                if (pmap_con_dbg & CD_EXP)
        !          1539:                        printf("(pmap_expand: %x) table has already been allocated\n", curproc);
        !          1540: #endif
        !          1541:                splx(spl);
        !          1542:                return;
        !          1543:        }
        !          1544:        /*
        !          1545:         * Apply a mask to V to obtain the vaddr of the beginning of
        !          1546:         * its containing page 'table group', i.e. the group of
        !          1547:         * page tables that fit eithin a single VM page.
        !          1548:         * Using that, obtain the segment table pointer that references the
        !          1549:         * first page table in the group, and initialize all the
        !          1550:         * segment table descriptions for the page 'table group'.
        !          1551:         */
        !          1552:        v &= ~((1 << (PDT_BITS + PG_BITS)) - 1);
        !          1553:
        !          1554:        sdt = SDTENT(pmap, v);
        !          1555:
        !          1556:        /*
        !          1557:         * Init each of the segment entries to point the freshly allocated
        !          1558:         * page tables.
        !          1559:         */
        !          1560:        *((sdt_entry_t *)sdt) = pdt_paddr | SG_RW | SG_V;
        !          1561:        *((sdt_entry_t *)(sdt + SDT_ENTRIES)) = pdt_vaddr | SG_RW | SG_V;
        !          1562:
        !          1563:        PMAP_UNLOCK(pmap);
        !          1564:        splx(spl);
        !          1565: }
        !          1566:
        !          1567: /*
        !          1568:  * Routine:    PMAP_ENTER
        !          1569:  *
        !          1570:  * Function:
        !          1571:  *     Insert the given physical page (p) at the specified virtual
        !          1572:  *     address (v) in the target phisical map with the protecton requested.
        !          1573:  *     If specified, the page will be wired down, meaning that the
        !          1574:  *     related pte can not be reclaimed.
        !          1575:  *
        !          1576:  * N.B.: This is the only routine which MAY NOT lazy-evaluation or lose
        !          1577:  *     information. That is, this routine must actually insert this page
        !          1578:  *     into the given map NOW.
        !          1579:  *
        !          1580:  * Parameters:
        !          1581:  *     pmap    pointer to pmap structure
        !          1582:  *     va      VA of page to be mapped
        !          1583:  *     pa      PA of page to be mapped
        !          1584:  *     prot    protection attributes for page
        !          1585:  *     wired   wired attribute for page
        !          1586:  *
        !          1587:  * Extern/Global:
        !          1588:  *     pv lists
        !          1589:  *
        !          1590:  * Calls:
        !          1591:  *     pmap_pte
        !          1592:  *     pmap_expand
        !          1593:  *     pmap_remove_pte
        !          1594:  *
        !          1595:  *     This routine starts off by calling pmap_pte to obtain a (virtual)
        !          1596:  * pointer to the page table entry corresponding to given virtual
        !          1597:  * address. If the page table itself does not exist, pmap_expand is
        !          1598:  * called to allocate it.
        !          1599:  *
        !          1600:  *     If the page table entry (PTE) already maps the given physical page,
        !          1601:  * all that is needed is to set the protection and wired attributes as
        !          1602:  * given. TLB entries are flushed and pmap_enter returns.
        !          1603:  *
        !          1604:  *     If the page table entry (PTE) maps a different physical page than
        !          1605:  * that given, the old mapping is removed by a call to map_remove_range.
        !          1606:  * And execution of pmap_enter continues.
        !          1607:  *
        !          1608:  *     To map the new physical page, the routine first inserts a new
        !          1609:  * entry in the PV list exhibiting the given pmap and virtual address.
        !          1610:  * It then inserts the physical page address, protection attributes, and
        !          1611:  * wired attributes into the page table entry (PTE).
        !          1612:  *
        !          1613:  *
        !          1614:  *     get machine-dependent prot code
        !          1615:  *     get the pte for this page
        !          1616:  *     if necessary pmap_expand(pmap, v)
        !          1617:  *     if (changing wired attribute or protection) {
        !          1618:  *             flush entry from TLB
        !          1619:  *             update template
        !          1620:  *             for (ptes per vm page)
        !          1621:  *                     stuff pte
        !          1622:  *     } else if (mapped at wrong addr)
        !          1623:  *             flush entry from TLB
        !          1624:  *             pmap_remove_pte
        !          1625:  *     } else {
        !          1626:  *             enter mapping in pv_list
        !          1627:  *             setup template and stuff ptes
        !          1628:  *     }
        !          1629:  *
        !          1630:  */
        !          1631: int
        !          1632: pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
        !          1633: {
        !          1634:        int spl;
        !          1635:        pt_entry_t *pte, template;
        !          1636:        paddr_t old_pa;
        !          1637:        pv_entry_t pv_e, pvl;
        !          1638:        boolean_t wired = (flags & PMAP_WIRED) != 0;
        !          1639:        struct vm_page *pg;
        !          1640:
        !          1641: #ifdef DEBUG
        !          1642:        if (pmap_con_dbg & CD_ENT) {
        !          1643:                if (pmap == kernel_pmap)
        !          1644:                        printf("(pmap_enter: %x) pmap kernel va %x pa %x\n", curproc, va, pa);
        !          1645:                else
        !          1646:                        printf("(pmap_enter: %x) pmap %x va %x pa %x\n", curproc, pmap, va, pa);
        !          1647:        }
        !          1648: #endif
        !          1649:
        !          1650:        template = m88k_protection(prot);
        !          1651:
        !          1652:        spl = splvm();
        !          1653:        PMAP_LOCK(pmap);
        !          1654:
        !          1655:        /*
        !          1656:         * Expand pmap to include this pte.
        !          1657:         */
        !          1658:        while ((pte = pmap_pte(pmap, va)) == NULL) {
        !          1659:                if (pmap == kernel_pmap) {
        !          1660:                        /* will only return NULL if PMAP_CANFAIL is set */
        !          1661:                        if (pmap_expand_kmap(va, VM_PROT_READ | VM_PROT_WRITE,
        !          1662:                            flags & PMAP_CANFAIL) == NULL)
        !          1663:                                return (ENOMEM);
        !          1664:                } else {
        !          1665:                        /*
        !          1666:                         * Must unlock to expand the pmap.
        !          1667:                         */
        !          1668:                        PMAP_UNLOCK(pmap);
        !          1669:                        pmap_expand(pmap, va);
        !          1670:                        PMAP_LOCK(pmap);
        !          1671:                }
        !          1672:        }
        !          1673:        /*
        !          1674:         * Special case if the physical page is already mapped at this address.
        !          1675:         */
        !          1676:        old_pa = ptoa(PG_PFNUM(*pte));
        !          1677: #ifdef DEBUG
        !          1678:        if (pmap_con_dbg & CD_ENT)
        !          1679:                printf("(pmap_enter) old_pa %x pte %x\n", old_pa, *pte);
        !          1680: #endif
        !          1681:
        !          1682:        pg = PHYS_TO_VM_PAGE(pa);
        !          1683:        if (pg != NULL)
        !          1684:                pvl = pg_to_pvh(pg);
        !          1685:        else
        !          1686:                pvl = NULL;
        !          1687:
        !          1688:        if (old_pa == pa) {
        !          1689:                /* May be changing its wired attributes or protection */
        !          1690:                if (wired && !(pmap_pte_w(pte)))
        !          1691:                        pmap->pm_stats.wired_count++;
        !          1692:                else if (!wired && pmap_pte_w(pte))
        !          1693:                        pmap->pm_stats.wired_count--;
        !          1694:        } else {
        !          1695:                /* Remove old mapping from the PV list if necessary. */
        !          1696:                pmap_remove_pte(pmap, va, pte);
        !          1697:
        !          1698:                if (pvl != NULL) {
        !          1699:                        /*
        !          1700:                         * Enter the mapping in the PV list for this
        !          1701:                         * managed page.
        !          1702:                         */
        !          1703:                        if (pvl->pv_pmap == NULL) {
        !          1704:                                /*
        !          1705:                                 *      No mappings yet
        !          1706:                                 */
        !          1707:                                pvl->pv_va = va;
        !          1708:                                pvl->pv_pmap = pmap;
        !          1709:                                pvl->pv_next = NULL;
        !          1710:                                pvl->pv_flags = 0;
        !          1711:
        !          1712:                        } else {
        !          1713:                                /*
        !          1714:                                 * Add new pv_entry after header.
        !          1715:                                 */
        !          1716:                                pv_e = pool_get(&pvpool, PR_NOWAIT);
        !          1717:                                if (pv_e == NULL) {
        !          1718:                                        if (flags & PMAP_CANFAIL) {
        !          1719:                                                PMAP_UNLOCK(pmap);
        !          1720:                                                splx(spl);
        !          1721:                                                return (ENOMEM);
        !          1722:                                        } else
        !          1723:                                                panic("pmap_enter: "
        !          1724:                                                    "pvpool exhausted");
        !          1725:                                }
        !          1726:                                pv_e->pv_va = va;
        !          1727:                                pv_e->pv_pmap = pmap;
        !          1728:                                pv_e->pv_next = pvl->pv_next;
        !          1729:                                pv_e->pv_flags = 0;
        !          1730:                                pvl->pv_next = pv_e;
        !          1731:                        }
        !          1732:                }
        !          1733:
        !          1734:                /*
        !          1735:                 * And count the mapping.
        !          1736:                 */
        !          1737:                pmap->pm_stats.resident_count++;
        !          1738:                if (wired)
        !          1739:                        pmap->pm_stats.wired_count++;
        !          1740:        } /* if (pa == old_pa) ... else */
        !          1741:
        !          1742:        template |= PG_V;
        !          1743:        if (wired)
        !          1744:                template |= PG_W;
        !          1745:
        !          1746:        /*
        !          1747:         * If outside physical memory, disable cache on this (I/O) page.
        !          1748:         */
        !          1749:        if ((unsigned long)pa >= last_addr)
        !          1750:                template |= CACHE_INH;
        !          1751:
        !          1752:        if (flags & VM_PROT_WRITE)
        !          1753:                template |= PG_M_U;
        !          1754:        else if (flags & VM_PROT_ALL)
        !          1755:                template |= PG_U;
        !          1756:
        !          1757:        /*
        !          1758:         * Invalidate pte temporarily to avoid being written
        !          1759:         * back the modified bit and/or the reference bit by
        !          1760:         * any other cpu.
        !          1761:         */
        !          1762:        template |= invalidate_pte(pte) & PG_M_U;
        !          1763:        *pte = template | pa;
        !          1764:        flush_atc_entry(pmap, va);
        !          1765: #ifdef DEBUG
        !          1766:        if (pmap_con_dbg & CD_ENT)
        !          1767:                printf("(pmap_enter) set pte to %x\n", *pte);
        !          1768: #endif
        !          1769:
        !          1770:        /*
        !          1771:         * Cache attribute flags
        !          1772:         */
        !          1773:        if (pvl != NULL)
        !          1774:                pvl->pv_flags |= template & PG_M_U;
        !          1775:
        !          1776:        PMAP_UNLOCK(pmap);
        !          1777:        splx(spl);
        !          1778:
        !          1779:        return 0;
        !          1780: }
        !          1781:
        !          1782: /*
        !          1783:  * Routine:    pmap_unwire
        !          1784:  *
        !          1785:  * Function:   Change the wiring attributes for a map/virtual-address pair.
        !          1786:  *
        !          1787:  * Parameters:
        !          1788:  *     pmap    pointer to pmap structure
        !          1789:  *     v       virtual address of page to be unwired
        !          1790:  *
        !          1791:  * Calls:
        !          1792:  *     pmap_pte
        !          1793:  *
        !          1794:  * Special Assumptions:
        !          1795:  *     The mapping must already exist in the pmap.
        !          1796:  */
        !          1797: void
        !          1798: pmap_unwire(pmap_t pmap, vaddr_t v)
        !          1799: {
        !          1800:        pt_entry_t *pte;
        !          1801:        int spl;
        !          1802:
        !          1803:        spl = splvm();
        !          1804:        PMAP_LOCK(pmap);
        !          1805:
        !          1806:        if ((pte = pmap_pte(pmap, v)) == NULL)
        !          1807:                panic("pmap_unwire: pte missing");
        !          1808:
        !          1809:        if (pmap_pte_w(pte)) {
        !          1810:                /* unwired mapping */
        !          1811:                pmap->pm_stats.wired_count--;
        !          1812:                *pte &= ~PG_W;
        !          1813:        }
        !          1814:
        !          1815:        PMAP_UNLOCK(pmap);
        !          1816:        splx(spl);
        !          1817: }
        !          1818:
        !          1819: /*
        !          1820:  * Routine:    PMAP_EXTRACT
        !          1821:  *
        !          1822:  * Function:
        !          1823:  *     Extract the physical page address associoated
        !          1824:  *     with the given map/virtual_address pair.
        !          1825:  *
        !          1826:  * Parameters:
        !          1827:  *     pmap            pointer to pmap structure
        !          1828:  *     va              virtual address
        !          1829:  *     pap             storage for result.
        !          1830:  *
        !          1831:  * Calls:
        !          1832:  *     PMAP_LOCK, PMAP_UNLOCK
        !          1833:  *     pmap_pte
        !          1834:  *
        !          1835:  * The routine calls pmap_pte to get a (virtual) pointer to
        !          1836:  * the page table entry (PTE) associated with the given virtual
        !          1837:  * address. If the page table does not exist, or if the PTE is not valid,
        !          1838:  * then 0 address is returned. Otherwise, the physical page address from
        !          1839:  * the PTE is returned.
        !          1840:  */
        !          1841: boolean_t
        !          1842: pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap)
        !          1843: {
        !          1844:        pt_entry_t *pte;
        !          1845:        paddr_t pa;
        !          1846:        int spl;
        !          1847:        boolean_t rv = FALSE;
        !          1848:
        !          1849: #ifdef DIAGNOSTIC
        !          1850:        if (pmap == NULL)
        !          1851:                panic("pmap_extract: pmap is NULL");
        !          1852: #endif
        !          1853:
        !          1854: #ifdef M88100
        !          1855:        /*
        !          1856:         * 88100-based designs have two hardwired BATC entries which map
        !          1857:         * the upper 1MB 1:1 in supervisor space.
        !          1858:         */
        !          1859:        if (CPU_IS88100) {
        !          1860:                if (va >= BATC8_VA && pmap == kernel_pmap) {
        !          1861:                        *pap = va;
        !          1862:                        return (TRUE);
        !          1863:                }
        !          1864:        }
        !          1865: #endif
        !          1866:
        !          1867:        spl = splvm();
        !          1868:        PMAP_LOCK(pmap);
        !          1869:
        !          1870:        pte = pmap_pte(pmap, va);
        !          1871:        if (pte != NULL && PDT_VALID(pte)) {
        !          1872:                rv = TRUE;
        !          1873:                if (pap != NULL) {
        !          1874:                        pa = ptoa(PG_PFNUM(*pte));
        !          1875:                        pa |= (va & PAGE_MASK); /* offset within page */
        !          1876:                        *pap = pa;
        !          1877:                }
        !          1878:        }
        !          1879:
        !          1880:        PMAP_UNLOCK(pmap);
        !          1881:        splx(spl);
        !          1882:        return rv;
        !          1883: }
        !          1884:
        !          1885: /*
        !          1886:  * Routine:    PMAP_COLLECT
        !          1887:  *
        !          1888:  * Runction:
        !          1889:  *     Garbage collects the physical map system for pages which are
        !          1890:  *     no longer used. there may well be pages which are not
        !          1891:  *     referenced, but others may be collected as well.
        !          1892:  *     Called by the pageout daemon when pages are scarce.
        !          1893:  *
        !          1894:  * Parameters:
        !          1895:  *     pmap            pointer to pmap structure
        !          1896:  *
        !          1897:  * Calls:
        !          1898:  *     pmap_pte
        !          1899:  *     pmap_remove_range
        !          1900:  *     uvm_km_free
        !          1901:  *
        !          1902:  *     The intent of this routine is to release memory pages being used
        !          1903:  * by translation tables. They can be release only if they contain no
        !          1904:  * valid mappings, and their parent table entry has been invalidated.
        !          1905:  *
        !          1906:  *     The routine sequences through the entries user address space,
        !          1907:  * inspecting page-sized groups of page tables for wired entries. If
        !          1908:  * a full page of tables has no wired enties, any otherwise valid
        !          1909:  * entries are invalidated (via pmap_remove_range). Then, the segment
        !          1910:  * table entries corresponding to this group of page tables are
        !          1911:  * invalidated. Finally, uvm_km_free is called to return the page to the
        !          1912:  * system.
        !          1913:  *
        !          1914:  *     If all entries in a segment table are invalidated, it too can
        !          1915:  * be returned to the system.
        !          1916:  */
        !          1917: void
        !          1918: pmap_collect(pmap_t pmap)
        !          1919: {
        !          1920:        u_int sdt;              /* outer loop index */
        !          1921:        vaddr_t sdt_va;
        !          1922:        sdt_entry_t *sdtp;      /* ptr to index into segment table */
        !          1923:        pt_entry_t *gdttbl;     /* ptr to first entry in a page table */
        !          1924:        pt_entry_t *gdttblend;  /* ptr to byte after last entry in
        !          1925:                                   table group */
        !          1926:        pt_entry_t *gdtp;       /* ptr to index into a page table */
        !          1927:        boolean_t found_gdt_wired; /* flag indicating a wired page exists
        !          1928:                                   in a page table's address range */
        !          1929:        int spl;
        !          1930:
        !          1931: #ifdef DEBUG
        !          1932:        if (pmap_con_dbg & CD_COL)
        !          1933:                printf ("(pmap_collect: %x) pmap %x\n", curproc, pmap);
        !          1934: #endif
        !          1935:
        !          1936:        spl = splvm();
        !          1937:        PMAP_LOCK(pmap);
        !          1938:
        !          1939:        sdtp = pmap->pm_stab; /* addr of segment table */
        !          1940:
        !          1941:        /* segment table loop */
        !          1942:        for (sdt = VM_MIN_ADDRESS >> SDT_SHIFT;
        !          1943:            sdt <= VM_MAX_ADDRESS >> SDT_SHIFT; sdt++, sdtp++) {
        !          1944:                sdt_va = sdt << SDT_SHIFT;
        !          1945:                gdttbl = pmap_pte(pmap, sdt_va);
        !          1946:                if (gdttbl == NULL)
        !          1947:                        continue; /* no maps in this range */
        !          1948:
        !          1949:                gdttblend = gdttbl + PDT_ENTRIES;
        !          1950:
        !          1951:                /* scan page maps for wired pages */
        !          1952:                found_gdt_wired = FALSE;
        !          1953:                for (gdtp = gdttbl; gdtp < gdttblend; gdtp++) {
        !          1954:                        if (pmap_pte_w(gdtp)) {
        !          1955:                                found_gdt_wired = TRUE;
        !          1956:                                break;
        !          1957:                        }
        !          1958:                }
        !          1959:
        !          1960:                if (found_gdt_wired)
        !          1961:                        continue; /* can't free this range */
        !          1962:
        !          1963:                /* invalidate all maps in this range */
        !          1964:                pmap_remove_range(pmap, sdt_va, sdt_va + (1 << SDT_SHIFT));
        !          1965:
        !          1966:                /*
        !          1967:                 * we can safely deallocate the page map(s)
        !          1968:                 */
        !          1969:                *((sdt_entry_t *) sdtp) = 0;
        !          1970:                *((sdt_entry_t *)(sdtp + SDT_ENTRIES)) = 0;
        !          1971:
        !          1972:                /*
        !          1973:                 * we have to unlock before freeing the table, since
        !          1974:                 * uvm_km_free will invoke another pmap routine
        !          1975:                 */
        !          1976:                PMAP_UNLOCK(pmap);
        !          1977:                uvm_km_free(kernel_map, (vaddr_t)gdttbl, PAGE_SIZE);
        !          1978:                PMAP_LOCK(pmap);
        !          1979:        }
        !          1980:
        !          1981:        PMAP_UNLOCK(pmap);
        !          1982:        splx(spl);
        !          1983:
        !          1984: #ifdef DEBUG
        !          1985:        if (pmap_con_dbg & CD_COL)
        !          1986:                printf("(pmap_collect: %x) done\n", curproc);
        !          1987: #endif
        !          1988: }
        !          1989:
        !          1990: /*
        !          1991:  * Routine:    PMAP_ACTIVATE
        !          1992:  *
        !          1993:  * Function:
        !          1994:  *     Binds the pmap associated to the process to the current processor.
        !          1995:  *
        !          1996:  * Parameters:
        !          1997:  *     p       pointer to proc structure
        !          1998:  *
        !          1999:  * Notes:
        !          2000:  *     If the specified pmap is not kernel_pmap, this routine stores its
        !          2001:  *     apr template into UAPR (user area pointer register) in the
        !          2002:  *     CMMUs connected to the specified CPU.
        !          2003:  *
        !          2004:  *     Then it flushes the TLBs mapping user virtual space, in the CMMUs
        !          2005:  *     connected to the specified CPU.
        !          2006:  */
        !          2007: void
        !          2008: pmap_activate(struct proc *p)
        !          2009: {
        !          2010:        pmap_t pmap = vm_map_pmap(&p->p_vmspace->vm_map);
        !          2011:        int cpu = cpu_number();
        !          2012:
        !          2013: #ifdef DEBUG
        !          2014:        if (pmap_con_dbg & CD_ACTIVATE)
        !          2015:                printf("(pmap_activate: %x) pmap %p\n", p, pmap);
        !          2016: #endif
        !          2017:
        !          2018:        if (pmap != kernel_pmap) {
        !          2019:                /*
        !          2020:                 * Lock the pmap to put this cpu in its active set.
        !          2021:                 */
        !          2022:                PMAP_LOCK(pmap);
        !          2023:
        !          2024:                cmmu_set_uapr(pmap->pm_apr);
        !          2025:                cmmu_flush_tlb(cpu, FALSE, 0, -1);
        !          2026:
        !          2027:                /*
        !          2028:                 * Mark that this cpu is using the pmap.
        !          2029:                 */
        !          2030:                SETBIT_CPUSET(cpu, &(pmap->pm_cpus));
        !          2031:
        !          2032:                PMAP_UNLOCK(pmap);
        !          2033:        }
        !          2034: }
        !          2035:
        !          2036: /*
        !          2037:  * Routine:    PMAP_DEACTIVATE
        !          2038:  *
        !          2039:  * Function:
        !          2040:  *     Unbinds the pmap associated to the process from the current processor.
        !          2041:  *
        !          2042:  * Parameters:
        !          2043:  *     p               pointer to proc structure
        !          2044:  */
        !          2045: void
        !          2046: pmap_deactivate(struct proc *p)
        !          2047: {
        !          2048:        pmap_t pmap = vm_map_pmap(&p->p_vmspace->vm_map);
        !          2049:        int cpu = cpu_number();
        !          2050:
        !          2051:        if (pmap != kernel_pmap) {
        !          2052:                /*
        !          2053:                 * We expect the spl to already have been raised to sched level.
        !          2054:                 */
        !          2055:                PMAP_LOCK(pmap);
        !          2056:                CLRBIT_CPUSET(cpu, &(pmap->pm_cpus));
        !          2057:                PMAP_UNLOCK(pmap);
        !          2058:        }
        !          2059: }
        !          2060:
        !          2061: /*
        !          2062:  * Routine:    PMAP_COPY_PAGE
        !          2063:  *
        !          2064:  * Function:
        !          2065:  *     Copies the specified pages.
        !          2066:  *
        !          2067:  * Parameters:
        !          2068:  *     src     PA of source page
        !          2069:  *     dst     PA of destination page
        !          2070:  *
        !          2071:  * Extern/Global:
        !          2072:  *     phys_map_vaddr
        !          2073:  *
        !          2074:  * Special Assumptions:
        !          2075:  *     no locking required
        !          2076:  *
        !          2077:  * This routine maps the physical pages at the 'phys_map' virtual
        !          2078:  * addresses set up in pmap_bootstrap. It flushes the TLB to make the
        !          2079:  * new mappings effective, and performs the copy.
        !          2080:  */
        !          2081: void
        !          2082: pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
        !          2083: {
        !          2084:        paddr_t src = VM_PAGE_TO_PHYS(srcpg);
        !          2085:        paddr_t dst = VM_PAGE_TO_PHYS(dstpg);
        !          2086:        vaddr_t dstva, srcva;
        !          2087:        int spl;
        !          2088:        pt_entry_t *dstpte, *srcpte;
        !          2089:        int cpu = cpu_number();
        !          2090:
        !          2091:        dstva = (vaddr_t)(phys_map_vaddr + 2 * (cpu << PAGE_SHIFT));
        !          2092:        srcva = dstva + PAGE_SIZE;
        !          2093:        dstpte = pmap_pte(kernel_pmap, dstva);
        !          2094:        srcpte = pmap_pte(kernel_pmap, srcva);
        !          2095:
        !          2096:        spl = splvm();
        !          2097:
        !          2098:        *dstpte = m88k_protection(VM_PROT_READ | VM_PROT_WRITE) |
        !          2099:            PG_M /* 88110 */ | PG_V | dst;
        !          2100:        *srcpte = m88k_protection(VM_PROT_READ) |
        !          2101:            PG_V | src;
        !          2102:
        !          2103:        /*
        !          2104:         * We don't need the flush_atc_entry() dance, as these pages are
        !          2105:         * bound to only one cpu.
        !          2106:         */
        !          2107:        cmmu_flush_tlb(cpu, TRUE, dstva, 2);
        !          2108:
        !          2109:        /*
        !          2110:         * The source page is likely to be a non-kernel mapping, and as
        !          2111:         * such write back. Also, we might have split U/S caches!
        !          2112:         * So be sure to have the source pa flushed before the copy is
        !          2113:         * attempted, and the destination pa flushed afterwards.
        !          2114:         */
        !          2115:        cmmu_flush_data_page(cpu, src);
        !          2116:        bcopy((const void *)srcva, (void *)dstva, PAGE_SIZE);
        !          2117:        cmmu_flush_data_page(cpu, dst);
        !          2118:
        !          2119:        splx(spl);
        !          2120: }
        !          2121:
        !          2122: /*
        !          2123:  * Routine:    PMAP_CHANGEBIT
        !          2124:  *
        !          2125:  * Function:
        !          2126:  *     Update the pte bits on the specified physical page.
        !          2127:  *
        !          2128:  * Parameters:
        !          2129:  *     pg      physical page
        !          2130:  *     set     bits to set
        !          2131:  *     mask    bits to mask
        !          2132:  *
        !          2133:  * Extern/Global:
        !          2134:  *     pv_lists
        !          2135:  *
        !          2136:  * Calls:
        !          2137:  *     pmap_pte
        !          2138:  *
        !          2139:  * The pte bits corresponding to the page's frame index will be changed as
        !          2140:  * requested. The PV list will be traversed.
        !          2141:  * For each pmap/va the hardware the necessary bits in the page descriptor
        !          2142:  * table entry will be altered as well if necessary. If any bits were changed,
        !          2143:  * a TLB flush will be performed.
        !          2144:  */
        !          2145: void
        !          2146: pmap_changebit(struct vm_page *pg, int set, int mask)
        !          2147: {
        !          2148:        pv_entry_t pvl, pvep;
        !          2149:        pt_entry_t *pte, npte, opte;
        !          2150:        pmap_t pmap;
        !          2151:        int spl;
        !          2152:        vaddr_t va;
        !          2153:
        !          2154:        spl = splvm();
        !          2155:
        !          2156: #ifdef MULTIPROCESSOR
        !          2157: changebit_Retry:
        !          2158: #endif
        !          2159:        pvl = pg_to_pvh(pg);
        !          2160:
        !          2161:        /*
        !          2162:         * Clear saved attributes (modify, reference)
        !          2163:         */
        !          2164:        pvl->pv_flags &= mask;
        !          2165:
        !          2166:        if (pvl->pv_pmap == NULL) {
        !          2167: #ifdef DEBUG
        !          2168:                if (pmap_con_dbg & CD_CBIT)
        !          2169:                        printf("(pmap_changebit: %x) vm page 0x%x not mapped\n",
        !          2170:                            curproc, pg);
        !          2171: #endif
        !          2172:                splx(spl);
        !          2173:                return;
        !          2174:        }
        !          2175:
        !          2176:        /* for each listed pmap, update the affected bits */
        !          2177:        for (pvep = pvl; pvep != NULL; pvep = pvep->pv_next) {
        !          2178:                pmap = pvep->pv_pmap;
        !          2179: #ifdef MULTIPROCESSOR
        !          2180:                if (!__cpu_simple_lock_try(&pmap->pm_lock)) {
        !          2181:                        goto changebit_Retry;
        !          2182:                }
        !          2183: #endif
        !          2184:                va = pvep->pv_va;
        !          2185:                pte = pmap_pte(pmap, va);
        !          2186:
        !          2187:                /*
        !          2188:                 * Check for existing and valid pte
        !          2189:                 */
        !          2190:                if (pte == NULL || !PDT_VALID(pte)) {
        !          2191:                        goto next;       /* no page mapping */
        !          2192:                }
        !          2193: #ifdef DIAGNOSTIC
        !          2194:                if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
        !          2195:                        panic("pmap_changebit: pte %x in pmap %p doesn't point to page %p %lx",
        !          2196:                            *pte, pmap, pg, VM_PAGE_TO_PHYS(pg));
        !          2197: #endif
        !          2198:
        !          2199:                /*
        !          2200:                 * Update bits
        !          2201:                 */
        !          2202:                opte = *pte;
        !          2203:                npte = (opte | set) & mask;
        !          2204:
        !          2205:                /*
        !          2206:                 * Flush TLB of which cpus using pmap.
        !          2207:                 *
        !          2208:                 * Invalidate pte temporarily to avoid the modified bit
        !          2209:                 * and/or the reference being written back by any other cpu.
        !          2210:                 */
        !          2211:                if (npte != opte) {
        !          2212:                        invalidate_pte(pte);
        !          2213:                        *pte = npte;
        !          2214:                        flush_atc_entry(pmap, va);
        !          2215:                }
        !          2216: next:
        !          2217:                PMAP_UNLOCK(pmap);
        !          2218:        }
        !          2219:        splx(spl);
        !          2220: }
        !          2221:
        !          2222: /*
        !          2223:  * Routine:    PMAP_TESTBIT
        !          2224:  *
        !          2225:  * Function:
        !          2226:  *     Test the modified/referenced bits of a physical page.
        !          2227:  *
        !          2228:  * Parameters:
        !          2229:  *     pg      physical page
        !          2230:  *     bit     bit to test
        !          2231:  *
        !          2232:  * Extern/Global:
        !          2233:  *     pv lists
        !          2234:  *
        !          2235:  * Calls:
        !          2236:  *     pmap_pte
        !          2237:  *
        !          2238:  * If the attribute list for the given page has the bit, this routine
        !          2239:  * returns TRUE.
        !          2240:  *
        !          2241:  * Otherwise, this routine walks the PV list corresponding to the
        !          2242:  * given page. For each pmap/va pair, the page descriptor table entry is
        !          2243:  * examined. If the selected bit is found on, the function returns TRUE
        !          2244:  * immediately (doesn't need to walk remainder of list), and updates the
        !          2245:  * attribute list.
        !          2246:  */
        !          2247: boolean_t
        !          2248: pmap_testbit(struct vm_page *pg, int bit)
        !          2249: {
        !          2250:        pv_entry_t pvl, pvep;
        !          2251:        pt_entry_t *pte;
        !          2252:        pmap_t pmap;
        !          2253:        int spl;
        !          2254:
        !          2255:        spl = splvm();
        !          2256:
        !          2257: #ifdef MULTIPROCESSOR
        !          2258: testbit_Retry:
        !          2259: #endif
        !          2260:        pvl = pg_to_pvh(pg);
        !          2261:
        !          2262:        if (pvl->pv_flags & bit) {
        !          2263:                /* we've already cached this flag for this page,
        !          2264:                   no use looking further... */
        !          2265: #ifdef DEBUG
        !          2266:                if (pmap_con_dbg & CD_TBIT)
        !          2267:                        printf("(pmap_testbit: %x) already cached a %x flag for this page\n",
        !          2268:                            curproc, bit);
        !          2269: #endif
        !          2270:                splx(spl);
        !          2271:                return (TRUE);
        !          2272:        }
        !          2273:
        !          2274:        if (pvl->pv_pmap == NULL) {
        !          2275: #ifdef DEBUG
        !          2276:                if (pmap_con_dbg & CD_TBIT)
        !          2277:                        printf("(pmap_testbit: %x) vm page 0x%x not mapped\n",
        !          2278:                            curproc, pg);
        !          2279: #endif
        !          2280:                splx(spl);
        !          2281:                return (FALSE);
        !          2282:        }
        !          2283:
        !          2284:        /* for each listed pmap, check modified bit for given page */
        !          2285:        for (pvep = pvl; pvep != NULL; pvep = pvep->pv_next) {
        !          2286:                pmap = pvep->pv_pmap;
        !          2287: #ifdef MULTIPROCESSOR
        !          2288:                if (!__cpu_simple_lock_try(&pmap->pm_lock)) {
        !          2289:                        goto testbit_Retry;
        !          2290:                }
        !          2291: #endif
        !          2292:
        !          2293:                pte = pmap_pte(pmap, pvep->pv_va);
        !          2294:                if (pte == NULL || !PDT_VALID(pte)) {
        !          2295:                        goto next;
        !          2296:                }
        !          2297:
        !          2298: #ifdef DIAGNOSTIC
        !          2299:                if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
        !          2300:                        panic("pmap_testbit: pte %x in pmap %p %d doesn't point to page %p %lx",
        !          2301:                            *pte, pmap, pmap == kernel_pmap ? 1 : 0, pg, VM_PAGE_TO_PHYS(pg));
        !          2302: #endif
        !          2303:
        !          2304:                if ((*pte & bit) != 0) {
        !          2305:                        PMAP_UNLOCK(pmap);
        !          2306:                        pvl->pv_flags |= bit;
        !          2307: #ifdef DEBUG
        !          2308:                        if ((pmap_con_dbg & (CD_TBIT | CD_FULL)) == (CD_TBIT | CD_FULL))
        !          2309:                                printf("(pmap_testbit: %x) true on page pte@%p\n", curproc, pte);
        !          2310: #endif
        !          2311:                        splx(spl);
        !          2312:                        return (TRUE);
        !          2313:                }
        !          2314: next:
        !          2315:                PMAP_UNLOCK(pmap);
        !          2316:        }
        !          2317:
        !          2318:        splx(spl);
        !          2319:        return (FALSE);
        !          2320: }
        !          2321:
        !          2322: /*
        !          2323:  * Routine:    PMAP_UNSETBIT
        !          2324:  *
        !          2325:  * Function:
        !          2326:  *     Clears a pte bit and returns its previous state, for the
        !          2327:  *     specified physical page.
        !          2328:  *     This is an optimized version of:
        !          2329:  *             rv = pmap_testbit(pg, bit);
        !          2330:  *             pmap_changebit(pg, 0, ~bit);
        !          2331:  *             return rv;
        !          2332:  */
        !          2333: boolean_t
        !          2334: pmap_unsetbit(struct vm_page *pg, int bit)
        !          2335: {
        !          2336:        boolean_t rv = FALSE;
        !          2337:        pv_entry_t pvl, pvep;
        !          2338:        pt_entry_t *pte, opte;
        !          2339:        pmap_t pmap;
        !          2340:        int spl;
        !          2341:        vaddr_t va;
        !          2342:
        !          2343:        spl = splvm();
        !          2344:
        !          2345: #ifdef MULTIPROCESSOR
        !          2346: unsetbit_Retry:
        !          2347: #endif
        !          2348:        pvl = pg_to_pvh(pg);
        !          2349:
        !          2350:        /*
        !          2351:         * Clear saved attributes
        !          2352:         */
        !          2353:        pvl->pv_flags &= ~bit;
        !          2354:
        !          2355:        if (pvl->pv_pmap == NULL) {
        !          2356: #ifdef DEBUG
        !          2357:                if (pmap_con_dbg & CD_USBIT)
        !          2358:                        printf("(pmap_unsetbit: %x) vm page 0x%x not mapped\n",
        !          2359:                            curproc, pg);
        !          2360: #endif
        !          2361:                splx(spl);
        !          2362:                return (FALSE);
        !          2363:        }
        !          2364:
        !          2365:        /* for each listed pmap, update the specified bit */
        !          2366:        for (pvep = pvl; pvep != NULL; pvep = pvep->pv_next) {
        !          2367:                pmap = pvep->pv_pmap;
        !          2368: #ifdef MULTIPROCESSOR
        !          2369:                if (!__cpu_simple_lock_try(&pmap->pm_lock)) {
        !          2370:                        goto unsetbit_Retry;
        !          2371:                }
        !          2372: #endif
        !          2373:                va = pvep->pv_va;
        !          2374:                pte = pmap_pte(pmap, va);
        !          2375:
        !          2376:                /*
        !          2377:                 * Check for existing and valid pte
        !          2378:                 */
        !          2379:                if (pte == NULL || !PDT_VALID(pte)) {
        !          2380:                        goto next;       /* no page mapping */
        !          2381:                }
        !          2382: #ifdef DIAGNOSTIC
        !          2383:                if (ptoa(PG_PFNUM(*pte)) != VM_PAGE_TO_PHYS(pg))
        !          2384:                        panic("pmap_unsetbit: pte %x in pmap %p doesn't point to page %p %lx",
        !          2385:                            *pte, pmap, pg, VM_PAGE_TO_PHYS(pg));
        !          2386: #endif
        !          2387:
        !          2388:                /*
        !          2389:                 * Update bits
        !          2390:                 */
        !          2391:                opte = *pte;
        !          2392:                if (opte & bit) {
        !          2393:                        /*
        !          2394:                         * Flush TLB of which cpus using pmap.
        !          2395:                         *
        !          2396:                         * Invalidate pte temporarily to avoid the specified
        !          2397:                         * bit being written back by any other cpu.
        !          2398:                         */
        !          2399:                        invalidate_pte(pte);
        !          2400:                        *pte = opte ^ bit;
        !          2401:                        flush_atc_entry(pmap, va);
        !          2402:                } else
        !          2403:                        rv = TRUE;
        !          2404: next:
        !          2405:                PMAP_UNLOCK(pmap);
        !          2406:        }
        !          2407:        splx(spl);
        !          2408:
        !          2409:        return (rv);
        !          2410: }
        !          2411:
        !          2412: /*
        !          2413:  * Routine:    PMAP_IS_MODIFIED
        !          2414:  *
        !          2415:  * Function:
        !          2416:  *     Return whether or not the specified physical page is modified
        !          2417:  *     by any physical maps.
        !          2418:  */
        !          2419: boolean_t
        !          2420: pmap_is_modified(struct vm_page *pg)
        !          2421: {
        !          2422:        return pmap_testbit(pg, PG_M);
        !          2423: }
        !          2424:
        !          2425: /*
        !          2426:  * Routine:    PMAP_IS_REFERENCED
        !          2427:  *
        !          2428:  * Function:
        !          2429:  *     Return whether or not the specified physical page is referenced by
        !          2430:  *     any physical maps.
        !          2431:  */
        !          2432: boolean_t
        !          2433: pmap_is_referenced(struct vm_page *pg)
        !          2434: {
        !          2435:        return pmap_testbit(pg, PG_U);
        !          2436: }
        !          2437:
        !          2438: /*
        !          2439:  * Routine:    PMAP_PAGE_PROTECT
        !          2440:  *
        !          2441:  * Calls:
        !          2442:  *     pmap_changebit
        !          2443:  *     pmap_remove_all
        !          2444:  *
        !          2445:  *     Lower the permission for all mappings to a given page.
        !          2446:  */
        !          2447: void
        !          2448: pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
        !          2449: {
        !          2450:        if ((prot & VM_PROT_READ) == VM_PROT_NONE)
        !          2451:                pmap_remove_all(pg);
        !          2452:        else if ((prot & VM_PROT_WRITE) == VM_PROT_NONE)
        !          2453:                pmap_changebit(pg, PG_RO, ~0);
        !          2454: }
        !          2455:
        !          2456: void
        !          2457: pmap_virtual_space(vaddr_t *startp, vaddr_t *endp)
        !          2458: {
        !          2459:        *startp = virtual_avail;
        !          2460:        *endp = virtual_end;
        !          2461: }
        !          2462:
        !          2463: void
        !          2464: pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
        !          2465: {
        !          2466:        int spl;
        !          2467:        pt_entry_t template, *pte;
        !          2468:
        !          2469: #ifdef DEBUG
        !          2470:        if (pmap_con_dbg & CD_ENT) {
        !          2471:                printf ("(pmap_kenter_pa: %x) va %x pa %x\n", curproc, va, pa);
        !          2472:        }
        !          2473: #endif
        !          2474:
        !          2475:        spl = splvm();
        !          2476:        PMAP_LOCK(kernel_pmap);
        !          2477:
        !          2478:        template = m88k_protection(prot);
        !          2479: #ifdef M88110
        !          2480:        if (CPU_IS88110 && m88k_protection(prot) != PG_RO)
        !          2481:                template |= PG_M;
        !          2482: #endif
        !          2483:
        !          2484:        /*
        !          2485:         * Expand pmap to include this pte.
        !          2486:         */
        !          2487:        while ((pte = pmap_pte(kernel_pmap, va)) == NULL)
        !          2488:                pmap_expand_kmap(va, VM_PROT_READ | VM_PROT_WRITE, 0);
        !          2489:
        !          2490:        /*
        !          2491:         * And count the mapping.
        !          2492:         */
        !          2493:        kernel_pmap->pm_stats.resident_count++;
        !          2494:        kernel_pmap->pm_stats.wired_count++;
        !          2495:
        !          2496:        invalidate_pte(pte);
        !          2497:
        !          2498:        /*
        !          2499:         * If outside physical memory, disable cache on this (I/O) page.
        !          2500:         */
        !          2501:        if ((unsigned long)pa >= last_addr)
        !          2502:                template |= CACHE_INH | PG_V | PG_W;
        !          2503:        else
        !          2504:                template |= PG_V | PG_W;
        !          2505:        *pte = template | pa;
        !          2506:        flush_atc_entry(kernel_pmap, va);
        !          2507:
        !          2508:        PMAP_UNLOCK(kernel_pmap);
        !          2509:        splx(spl);
        !          2510: }
        !          2511:
        !          2512: void
        !          2513: pmap_kremove(vaddr_t va, vsize_t len)
        !          2514: {
        !          2515:        int spl;
        !          2516:        vaddr_t e, eseg;
        !          2517:
        !          2518: #ifdef DEBUG
        !          2519:        if (pmap_con_dbg & CD_RM)
        !          2520:                printf("(pmap_kremove: %x) va %x len %x\n", curproc, va, len);
        !          2521: #endif
        !          2522:
        !          2523:        spl = splvm();
        !          2524:        PMAP_LOCK(kernel_pmap);
        !          2525:
        !          2526:        e = va + len;
        !          2527:        while (va != e) {
        !          2528:                sdt_entry_t *sdt;
        !          2529:                pt_entry_t *pte;
        !          2530:
        !          2531:                eseg = (va & SDT_MASK) + (1 << SDT_SHIFT);
        !          2532:                if (eseg > e || eseg == 0)
        !          2533:                        eseg = e;
        !          2534:
        !          2535:                sdt = SDTENT(kernel_pmap, va);
        !          2536:
        !          2537:                /* If no segment table, skip a whole segment */
        !          2538:                if (!SDT_VALID(sdt))
        !          2539:                        va = eseg;
        !          2540:                else {
        !          2541:                        while (va != eseg) {
        !          2542:                                pte = sdt_pte(sdt, va);
        !          2543:                                if (pte != NULL && PDT_VALID(pte)) {
        !          2544:                                        /* Update the counts */
        !          2545:                                        kernel_pmap->pm_stats.resident_count--;
        !          2546:                                        kernel_pmap->pm_stats.wired_count--;
        !          2547:
        !          2548:                                        invalidate_pte(pte);
        !          2549:                                        flush_atc_entry(kernel_pmap, va);
        !          2550:                                }
        !          2551:                                va += PAGE_SIZE;
        !          2552:                        }
        !          2553:                }
        !          2554:        }
        !          2555:        PMAP_UNLOCK(kernel_pmap);
        !          2556:        splx(spl);
        !          2557: }
        !          2558:
        !          2559: void
        !          2560: pmap_proc_iflush(struct proc *p, vaddr_t va, vsize_t len)
        !          2561: {
        !          2562:        pmap_t pmap = vm_map_pmap(&p->p_vmspace->vm_map);
        !          2563:        paddr_t pa;
        !          2564:        vsize_t count;
        !          2565:        u_int32_t users;
        !          2566:        int cpu;
        !          2567:
        !          2568:        while (len != 0) {
        !          2569:                count = min(len, PAGE_SIZE - (va & PAGE_MASK));
        !          2570:                if (pmap_extract(pmap, va, &pa)) {
        !          2571:                        users = pmap->pm_cpus;
        !          2572:                        while ((cpu = ff1(users)) != 32) {
        !          2573:                                cmmu_flush_inst_cache(cpu, pa, count);
        !          2574:                                users &= ~(1 << cpu);
        !          2575:                        }
        !          2576:                }
        !          2577:                va += count;
        !          2578:                len -= count;
        !          2579:        }
        !          2580: }

CVSweb