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

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

1.1     ! nbrk        1: /*     $OpenBSD: pmap.c,v 1.29 2007/07/18 20:06:07 miod Exp $  */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2001-2004 Opsycon AB  (www.opsycon.se / www.opsycon.com)
        !             5:  *
        !             6:  * Redistribution and use in source and binary forms, with or without
        !             7:  * modification, are permitted provided that the following conditions
        !             8:  * are met:
        !             9:  * 1. Redistributions of source code must retain the above copyright
        !            10:  *    notice, this list of conditions and the following disclaimer.
        !            11:  * 2. Redistributions in binary form must reproduce the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer in the
        !            13:  *    documentation and/or other materials provided with the distribution.
        !            14:  *
        !            15:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
        !            16:  * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
        !            17:  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            18:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
        !            19:  * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            20:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            21:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            22:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            23:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            24:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            25:  * SUCH DAMAGE.
        !            26:  *
        !            27:  *     XXX This code needs some major rewriting.
        !            28:  */
        !            29:
        !            30: #include <sys/param.h>
        !            31: #include <sys/systm.h>
        !            32: #include <sys/proc.h>
        !            33: #include <sys/malloc.h>
        !            34: #include <sys/user.h>
        !            35: #include <sys/buf.h>
        !            36: #include <sys/pool.h>
        !            37: #ifdef SYSVSHM
        !            38: #include <sys/shm.h>
        !            39: #endif
        !            40:
        !            41: #include <machine/pte.h>
        !            42: #include <machine/cpu.h>
        !            43: #include <machine/autoconf.h>
        !            44: #include <machine/memconf.h>
        !            45: #include <machine/vmparam.h>
        !            46: #include <mips64/archtype.h>
        !            47:
        !            48: #include <uvm/uvm.h>
        !            49:
        !            50: extern void mem_zero_page(vaddr_t);
        !            51:
        !            52: struct pool pmap_pmap_pool;
        !            53: struct pool pmap_pv_pool;
        !            54:
        !            55: #define pmap_pv_alloc()                (pv_entry_t)pool_get(&pmap_pv_pool, PR_NOWAIT)
        !            56: #define pmap_pv_free(pv)       pool_put(&pmap_pv_pool, (pv))
        !            57:
        !            58: #ifndef PMAP_PV_LOWAT
        !            59: #define PMAP_PV_LOWAT   16
        !            60: #endif
        !            61: int    pmap_pv_lowat = PMAP_PV_LOWAT;
        !            62:
        !            63: int    pmap_alloc_tlbpid(struct proc *);
        !            64: int    pmap_enter_pv(pmap_t, vaddr_t, vm_page_t, u_int *);
        !            65: int    pmap_page_alloc(vaddr_t *);
        !            66: void   pmap_page_free(vaddr_t);
        !            67: void   pmap_page_cache(vm_page_t, int);
        !            68: void   pmap_remove_pv(pmap_t, vaddr_t, paddr_t);
        !            69:
        !            70: #ifdef PMAPDEBUG
        !            71: struct {
        !            72:        int kernel;     /* entering kernel mapping */
        !            73:        int user;       /* entering user mapping */
        !            74:        int ptpneeded;  /* needed to allocate a PT page */
        !            75:        int pwchange;   /* no mapping change, just wiring or protection */
        !            76:        int wchange;    /* no mapping change, just wiring */
        !            77:        int mchange;    /* was mapped but mapping to different page */
        !            78:        int managed;    /* a managed page */
        !            79:        int firstpv;    /* first mapping for this PA */
        !            80:        int secondpv;   /* second mapping for this PA */
        !            81:        int ci;         /* cache inhibited */
        !            82:        int unmanaged;  /* not a managed page */
        !            83:        int flushes;    /* cache flushes */
        !            84:        int cachehit;   /* new entry forced valid entry out */
        !            85: } enter_stats;
        !            86: struct {
        !            87:        int calls;
        !            88:        int removes;
        !            89:        int flushes;
        !            90:        int pidflushes; /* HW pid stolen */
        !            91:        int pvfirst;
        !            92:        int pvsearch;
        !            93: } remove_stats;
        !            94:
        !            95: #define PDB_FOLLOW     0x0001
        !            96: #define PDB_INIT       0x0002
        !            97: #define PDB_ENTER      0x0004
        !            98: #define PDB_REMOVE     0x0008
        !            99: #define PDB_CREATE     0x0010
        !           100: #define PDB_PTPAGE     0x0020
        !           101: #define PDB_PVENTRY    0x0040
        !           102: #define PDB_BITS       0x0080
        !           103: #define PDB_COLLECT    0x0100
        !           104: #define PDB_PROTECT    0x0200
        !           105: #define PDB_TLBPID     0x0400
        !           106: #define PDB_PARANOIA   0x2000
        !           107: #define PDB_WIRING     0x4000
        !           108: #define PDB_PVDUMP     0x8000
        !           109:
        !           110: #define DPRINTF(flag, printdata)       \
        !           111:        if (pmapdebug & (flag))         \
        !           112:                printf printdata;
        !           113:
        !           114: #define stat_count(what)       (what)++
        !           115: int pmapdebug = PDB_ENTER|PDB_FOLLOW;
        !           116:
        !           117: #else
        !           118:
        !           119: #define DPRINTF(flag, printdata)
        !           120: #define stat_count(what)
        !           121:
        !           122: #endif /* PMAPDEBUG */
        !           123:
        !           124:
        !           125: struct pmap    kernel_pmap_store;
        !           126:
        !           127: psize_t        mem_size;       /* memory size in bytes */
        !           128: vaddr_t        virtual_start;  /* VA of first avail page (after kernel bss)*/
        !           129: vaddr_t        virtual_end;    /* VA of last avail page (end of kernel AS) */
        !           130:
        !           131: u_int          tlbpid_gen = 1;         /* TLB PID generation count */
        !           132: int            tlbpid_cnt = 2;         /* next available TLB PID */
        !           133:
        !           134: pt_entry_t     *Sysmap;                /* kernel pte table */
        !           135: u_int          Sysmapsize;             /* number of pte's in Sysmap */
        !           136:
        !           137:
        !           138: /*
        !           139:  *     Bootstrap the system enough to run with virtual memory.
        !           140:  */
        !           141: void
        !           142: pmap_bootstrap()
        !           143: {
        !           144:        u_int i;
        !           145:        pt_entry_t *spte;
        !           146:
        !           147:        /*
        !           148:         * Create a mapping table for kernel virtual memory. This
        !           149:         * table is a linear table in contrast to the user process
        !           150:         * mapping tables which are built with segment/page tables.
        !           151:         * Create 1GB of map (this will only use 1MB of memory).
        !           152:         */
        !           153:        virtual_start = VM_MIN_KERNEL_ADDRESS;
        !           154:        virtual_end = VM_MAX_KERNEL_ADDRESS;
        !           155:
        !           156:        Sysmapsize = (VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS) /
        !           157:            PAGE_SIZE;
        !           158:        if (Sysmapsize & 1)
        !           159:                Sysmapsize++;   /* force even number of pages */
        !           160:
        !           161:        Sysmap = (pt_entry_t *)
        !           162:            uvm_pageboot_alloc(sizeof(pt_entry_t) * Sysmapsize);
        !           163:
        !           164:        pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0,"pmappl", NULL);
        !           165:        pool_init(&pmap_pv_pool, sizeof(struct pv_entry), 0, 0, 0,"pvpl", NULL);
        !           166:
        !           167:        simple_lock_init(&pmap_kernel()->pm_lock);
        !           168:        pmap_kernel()->pm_count = 1;
        !           169:
        !           170:        /*
        !           171:         * The 64 bit Mips architecture stores the AND result
        !           172:         * of the Global bits in the pte pair in the on chip
        !           173:         * translation lookaside buffer. Thus invalid entries
        !           174:         * must have the Global bit set so when Entry LO and
        !           175:         * Entry HI G bits are ANDed together they will produce
        !           176:         * a global bit to store in the tlb.
        !           177:         */
        !           178:        for (i = 0, spte = Sysmap; i < Sysmapsize; i++, spte++)
        !           179:                spte->pt_entry = PG_G;
        !           180: }
        !           181:
        !           182: /*
        !           183:  *  Page steal allocator used during bootup.
        !           184:  */
        !           185: vaddr_t
        !           186: pmap_steal_memory(vsize_t size, vaddr_t *vstartp, vaddr_t *vendp)
        !           187: {
        !           188:        int i, j, x;
        !           189:        int npg;
        !           190:        vaddr_t va;
        !           191:        paddr_t pa;
        !           192:
        !           193: #ifdef DIAGNOSTIC
        !           194:        if (uvm.page_init_done) {
        !           195:                panic("pmap_steal_memory: too late, vm is running!");
        !           196:        }
        !           197: #endif
        !           198:
        !           199:        size = round_page(size);
        !           200:        npg = atop(size);
        !           201:        va = 0;
        !           202:
        !           203:        for(i = 0; i < vm_nphysseg && va == 0; i++) {
        !           204:                if (vm_physmem[i].avail_start != vm_physmem[i].start ||
        !           205:                    vm_physmem[i].avail_start >= vm_physmem[i].avail_end) {
        !           206:                        continue;
        !           207:                }
        !           208:
        !           209:                if ((vm_physmem[i].avail_end - vm_physmem[i].avail_start) < npg)
        !           210:                        continue;
        !           211:
        !           212:                pa = ptoa(vm_physmem[i].avail_start);
        !           213:                vm_physmem[i].avail_start += npg;
        !           214:                vm_physmem[i].start += npg;
        !           215:
        !           216:                if (vm_physmem[i].avail_start == vm_physmem[i].end) {
        !           217:                        if (vm_nphysseg == 1)
        !           218:                                panic("pmap_steal_memory: out of memory!");
        !           219:
        !           220:                        vm_nphysseg--;
        !           221:                        for (j = i; j < vm_nphysseg; x++)
        !           222:                                vm_physmem[x] = vm_physmem[x + 1];
        !           223:                }
        !           224:                if (vstartp)
        !           225:                        *vstartp = round_page(virtual_start);
        !           226:                if (vendp)
        !           227:                        *vendp = virtual_end;
        !           228:
        !           229:                /*
        !           230:                 * Prefer KSEG0 addresses for now, whenever possible.
        !           231:                 */
        !           232:                if (pa + size < KSEG_SIZE)
        !           233:                        va = PHYS_TO_KSEG0(pa);
        !           234:                else
        !           235:                        va = PHYS_TO_XKPHYS(pa, CCA_NONCOHERENT);
        !           236:
        !           237:                bzero((void *)va, size);
        !           238:                return (va);
        !           239:        }
        !           240:
        !           241:        panic("pmap_steal_memory: no memory to steal");
        !           242: }
        !           243:
        !           244: /*
        !           245:  *     Initialize the pmap module.
        !           246:  *     Called by vm_init, to initialize any structures that the pmap
        !           247:  *     system needs to map virtual memory.
        !           248:  */
        !           249: void
        !           250: pmap_init()
        !           251: {
        !           252:
        !           253:        DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_init()\n"));
        !           254:
        !           255: #if 0 /* too early */
        !           256:        pool_setlowat(&pmap_pv_pool, pmap_pv_lowat);
        !           257: #endif
        !           258: }
        !           259:
        !           260: static pv_entry_t pg_to_pvh(struct vm_page *);
        !           261: static __inline pv_entry_t
        !           262: pg_to_pvh(struct vm_page *pg)
        !           263: {
        !           264:        return &pg->mdpage.pv_ent;
        !           265: }
        !           266:
        !           267: /*
        !           268:  *     Create and return a physical map.
        !           269:  */
        !           270: pmap_t
        !           271: pmap_create()
        !           272: {
        !           273:        pmap_t pmap;
        !           274:        vaddr_t va;
        !           275:        int s;
        !           276:
        !           277: extern struct vmspace vmspace0;
        !           278: extern struct user *proc0paddr;
        !           279:
        !           280:        DPRINTF(PDB_FOLLOW|PDB_CREATE, ("pmap_create()\n"));
        !           281:
        !           282:        s = splvm();
        !           283:        pmap = pool_get(&pmap_pmap_pool, PR_WAITOK);
        !           284:        splx(s);
        !           285:        bzero(pmap, sizeof(*pmap));
        !           286:
        !           287:        simple_lock_init(&pmap->pm_lock);
        !           288:        pmap->pm_count = 1;
        !           289:
        !           290:        while (pmap_page_alloc(&va) != 0) {
        !           291:                /* XXX What else can we do?  Deadlocks?  */
        !           292:                uvm_wait("pmap_create");
        !           293:        }
        !           294:
        !           295:        pmap->pm_segtab = (struct segtab *)va;
        !           296:
        !           297:        if (pmap == vmspace0.vm_map.pmap) {
        !           298:                /*
        !           299:                 * The initial process has already been allocated a TLBPID
        !           300:                 * in mach_init().
        !           301:                 */
        !           302:                pmap->pm_tlbpid = 1;
        !           303:                pmap->pm_tlbgen = tlbpid_gen;
        !           304:                proc0paddr->u_pcb.pcb_segtab = pmap->pm_segtab;
        !           305:        } else {
        !           306:                pmap->pm_tlbpid = 0;
        !           307:                pmap->pm_tlbgen = 0;
        !           308:        }
        !           309:
        !           310:        return (pmap);
        !           311: }
        !           312:
        !           313: /*
        !           314:  *     Retire the given physical map from service.
        !           315:  *     Should only be called if the map contains
        !           316:  *     no valid mappings.
        !           317:  */
        !           318: void
        !           319: pmap_destroy(pmap_t pmap)
        !           320: {
        !           321:        int s, count;
        !           322:
        !           323:        DPRINTF(PDB_FOLLOW|PDB_CREATE, ("pmap_destroy(%x)\n", pmap));
        !           324:
        !           325:        simple_lock(&pmap->pm_lock);
        !           326:        count = --pmap->pm_count;
        !           327:        simple_unlock(&pmap->pm_lock);
        !           328:        if (count > 0)
        !           329:                return;
        !           330:
        !           331:        if (pmap->pm_segtab) {
        !           332:                pt_entry_t *pte;
        !           333:                int i;
        !           334: #ifdef PARANOIA
        !           335:                int j;
        !           336: #endif
        !           337:
        !           338:                for (i = 0; i < PMAP_SEGTABSIZE; i++) {
        !           339:                        /* get pointer to segment map */
        !           340:                        pte = pmap->pm_segtab->seg_tab[i];
        !           341:                        if (!pte)
        !           342:                                continue;
        !           343: #ifdef PARANOIA
        !           344:                        for (j = 0; j < NPTEPG; j++) {
        !           345:                                if ((pte+j)->pt_entry)
        !           346:                                        panic("pmap_destroy: segmap not empty");
        !           347:                        }
        !           348: #endif
        !           349:                        Mips_HitInvalidateDCache((vaddr_t)pte, PAGE_SIZE);
        !           350:                        pmap_page_free((vaddr_t)pte);
        !           351: #ifdef PARANOIA
        !           352:                        pmap->pm_segtab->seg_tab[i] = NULL;
        !           353: #endif
        !           354:                }
        !           355:                pmap_page_free((vaddr_t)pmap->pm_segtab);
        !           356: #ifdef PARANOIA
        !           357:                pmap->pm_segtab = NULL;
        !           358: #endif
        !           359:        }
        !           360:
        !           361:        s = splvm();
        !           362:        pool_put(&pmap_pmap_pool, pmap);
        !           363:        splx(s);
        !           364: }
        !           365:
        !           366: /*
        !           367:  *     Add a reference to the specified pmap.
        !           368:  */
        !           369: void
        !           370: pmap_reference(pmap_t pmap)
        !           371: {
        !           372:
        !           373:        DPRINTF(PDB_FOLLOW, ("pmap_reference(%x)\n", pmap));
        !           374:
        !           375:        if (pmap) {
        !           376:                simple_lock(&pmap->pm_lock);
        !           377:                pmap->pm_count++;
        !           378:                simple_unlock(&pmap->pm_lock);
        !           379:        }
        !           380: }
        !           381:
        !           382: /*
        !           383:  *      Make a new pmap (vmspace) active for the given process.
        !           384:  */
        !           385: void
        !           386: pmap_activate(struct proc *p)
        !           387: {
        !           388:        pmap_t pmap = p->p_vmspace->vm_map.pmap;
        !           389:        p->p_addr->u_pcb.pcb_segtab = pmap->pm_segtab;
        !           390:        pmap_alloc_tlbpid(p);
        !           391: }
        !           392:
        !           393: /*
        !           394:  *      Make a previously active pmap (vmspace) inactive.
        !           395:  */
        !           396: void
        !           397: pmap_deactivate(struct proc *p)
        !           398: {
        !           399:        /* Empty */
        !           400: }
        !           401:
        !           402: /*
        !           403:  *     Remove the given range of addresses from the specified map.
        !           404:  *
        !           405:  *     It is assumed that the start and end are properly
        !           406:  *     rounded to the page size.
        !           407:  */
        !           408: void
        !           409: pmap_remove(pmap_t pmap, vaddr_t sva, vaddr_t eva)
        !           410: {
        !           411:        vaddr_t nssva;
        !           412:        pt_entry_t *pte;
        !           413:        unsigned entry;
        !           414:
        !           415:        DPRINTF(PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT,
        !           416:                ("pmap_remove(%x, %x, %x)\n", pmap, sva, eva));
        !           417:
        !           418:        stat_count(remove_stats.calls);
        !           419:
        !           420:        if (pmap == NULL)
        !           421:                return;
        !           422:
        !           423:        if (pmap == pmap_kernel()) {
        !           424:                pt_entry_t *pte;
        !           425:
        !           426:                /* remove entries from kernel pmap */
        !           427: #ifdef DIAGNOSTIC
        !           428:                if (sva < VM_MIN_KERNEL_ADDRESS || eva < sva)
        !           429:                        panic("pmap_remove: kva not in range");
        !           430: #endif
        !           431:                pte = kvtopte(sva);
        !           432:                for(; sva < eva; sva += NBPG, pte++) {
        !           433:                        entry = pte->pt_entry;
        !           434:                        if (!(entry & PG_V))
        !           435:                                continue;
        !           436:                        pmap->pm_stats.resident_count--;
        !           437:                        pmap_remove_pv(pmap, sva, pfn_to_pad(entry));
        !           438:                        pte->pt_entry = PG_NV | PG_G;
        !           439:                        /*
        !           440:                         * Flush the TLB for the given address.
        !           441:                         */
        !           442:                        tlb_flush_addr(sva);
        !           443:                        stat_count(remove_stats.flushes);
        !           444:                }
        !           445:                return;
        !           446:        }
        !           447:
        !           448: #ifdef DIAGNOSTIC
        !           449:        if (eva > VM_MAXUSER_ADDRESS)
        !           450:                panic("pmap_remove: uva not in range");
        !           451: #endif
        !           452:        while (sva < eva) {
        !           453:                nssva = mips_trunc_seg(sva) + NBSEG;
        !           454:                if (nssva == 0 || nssva > eva)
        !           455:                        nssva = eva;
        !           456:                /*
        !           457:                 * If VA belongs to an unallocated segment,
        !           458:                 * skip to the next segment boundary.
        !           459:                 */
        !           460:                if (!(pte = pmap_segmap(pmap, sva))) {
        !           461:                        sva = nssva;
        !           462:                        continue;
        !           463:                }
        !           464:                /*
        !           465:                 * Invalidate every valid mapping within this segment.
        !           466:                 */
        !           467:                pte += uvtopte(sva);
        !           468:                for (; sva < nssva; sva += NBPG, pte++) {
        !           469:                        entry = pte->pt_entry;
        !           470:                        if (!(entry & PG_V))
        !           471:                                continue;
        !           472:                        pmap->pm_stats.resident_count--;
        !           473:                        pmap_remove_pv(pmap, sva, pfn_to_pad(entry));
        !           474:                        pte->pt_entry = PG_NV;
        !           475:                        /*
        !           476:                         * Flush the TLB for the given address.
        !           477:                         */
        !           478:                        if (pmap->pm_tlbgen == tlbpid_gen) {
        !           479:                                tlb_flush_addr(sva | (pmap->pm_tlbpid <<
        !           480:                                        VMTLB_PID_SHIFT));
        !           481:                                stat_count(remove_stats.flushes);
        !           482:                        }
        !           483:                }
        !           484:        }
        !           485: }
        !           486:
        !           487: /*
        !           488:  *     pmap_page_protect:
        !           489:  *
        !           490:  *     Lower the permission for all mappings to a given page.
        !           491:  */
        !           492: void
        !           493: pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
        !           494: {
        !           495:        pv_entry_t pv;
        !           496:        vaddr_t va;
        !           497:        int s;
        !           498:
        !           499:        if (prot == VM_PROT_NONE) {
        !           500:                DPRINTF(PDB_REMOVE, ("pmap_page_protect(%p, %p)\n", pg, prot));
        !           501:        } else {
        !           502:                DPRINTF(PDB_FOLLOW|PDB_PROTECT,
        !           503:                        ("pmap_page_protect(%p, %p)\n", pg, prot));
        !           504:        }
        !           505:
        !           506:        switch (prot) {
        !           507:        case VM_PROT_READ|VM_PROT_WRITE:
        !           508:        case VM_PROT_ALL:
        !           509:                break;
        !           510:
        !           511:        /* copy_on_write */
        !           512:        case VM_PROT_READ:
        !           513:        case VM_PROT_READ|VM_PROT_EXECUTE:
        !           514:                pv = pg_to_pvh(pg);
        !           515:                s = splvm();
        !           516:                /*
        !           517:                 * Loop over all current mappings setting/clearing as apropos.
        !           518:                 */
        !           519:                if (pv->pv_pmap != NULL) {
        !           520:                        for (; pv; pv = pv->pv_next) {
        !           521:                                va = pv->pv_va;
        !           522:                                pmap_protect(pv->pv_pmap, va, va + PAGE_SIZE,
        !           523:                                    prot);
        !           524:                        }
        !           525:                }
        !           526:                splx(s);
        !           527:                break;
        !           528:
        !           529:        /* remove_all */
        !           530:        default:
        !           531:                pv = pg_to_pvh(pg);
        !           532:                s = splvm();
        !           533:                while (pv->pv_pmap != NULL) {
        !           534:                        va = pv->pv_va;
        !           535:                        pmap_remove(pv->pv_pmap, va, va + PAGE_SIZE);
        !           536:                }
        !           537:                splx(s);
        !           538:        }
        !           539: }
        !           540:
        !           541: /*
        !           542:  *     Set the physical protection on the
        !           543:  *     specified range of this map as requested.
        !           544:  */
        !           545: void
        !           546: pmap_protect(pmap_t pmap, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
        !           547: {
        !           548:        vaddr_t nssva;
        !           549:        pt_entry_t *pte;
        !           550:        u_int entry;
        !           551:        u_int p;
        !           552:
        !           553:        DPRINTF(PDB_FOLLOW|PDB_PROTECT,
        !           554:                ("pmap_protect(%p, %p, %p, %p)\n", pmap, sva, eva, prot));
        !           555:
        !           556:        if ((prot & VM_PROT_READ) == VM_PROT_NONE) {
        !           557:                pmap_remove(pmap, sva, eva);
        !           558:                return;
        !           559:        }
        !           560:
        !           561:        p = (prot & VM_PROT_WRITE) ? PG_M : PG_RO;
        !           562:
        !           563:        if (pmap == pmap_kernel()) {
        !           564:                /*
        !           565:                 * Change entries in kernel pmap.
        !           566:                 * This will trap if the page is writeable (in order to set
        !           567:                 * the dirty bit) even if the dirty bit is already set. The
        !           568:                 * optimization isn't worth the effort since this code isn't
        !           569:                 * executed much. The common case is to make a user page
        !           570:                 * read-only.
        !           571:                 */
        !           572: #ifdef DIAGNOSTIC
        !           573:                if (sva < VM_MIN_KERNEL_ADDRESS || eva < sva)
        !           574:                        panic("pmap_protect: kva not in range");
        !           575: #endif
        !           576:                pte = kvtopte(sva);
        !           577:                for (; sva < eva; sva += NBPG, pte++) {
        !           578:                        entry = pte->pt_entry;
        !           579:                        if (!(entry & PG_V))
        !           580:                                continue;
        !           581:                        entry = (entry & ~(PG_M | PG_RO)) | p;
        !           582:                        pte->pt_entry = entry;
        !           583:                        /*
        !           584:                         * Update the TLB if the given address is in the cache.
        !           585:                         */
        !           586:                        tlb_update(sva, entry);
        !           587:                }
        !           588:                return;
        !           589:        }
        !           590:
        !           591: #ifdef DIAGNOSTIC
        !           592:        if (eva > VM_MAXUSER_ADDRESS)
        !           593:                panic("pmap_protect: uva not in range");
        !           594: #endif
        !           595:        while (sva < eva) {
        !           596:                nssva = mips_trunc_seg(sva) + NBSEG;
        !           597:                if (nssva == 0 || nssva > eva)
        !           598:                        nssva = eva;
        !           599:                /*
        !           600:                 * If VA belongs to an unallocated segment,
        !           601:                 * skip to the next segment boundary.
        !           602:                 */
        !           603:                if (!(pte = pmap_segmap(pmap, sva))) {
        !           604:                        sva = nssva;
        !           605:                        continue;
        !           606:                }
        !           607:                /*
        !           608:                 * Change protection on every valid mapping within this segment.
        !           609:                 */
        !           610:                pte += uvtopte(sva);
        !           611:                for (; sva < nssva; sva += NBPG, pte++) {
        !           612:                        entry = pte->pt_entry;
        !           613:                        if (!(entry & PG_V))
        !           614:                                continue;
        !           615:                        entry = (entry & ~(PG_M | PG_RO)) | p;
        !           616:                        pte->pt_entry = entry;
        !           617:                        if (pmap->pm_tlbgen == tlbpid_gen)
        !           618:                                tlb_update(sva | (pmap->pm_tlbpid <<
        !           619:                                        VMTLB_PID_SHIFT), entry);
        !           620:                }
        !           621:        }
        !           622: }
        !           623:
        !           624: /*
        !           625:  *     Insert the given physical page (p) at
        !           626:  *     the specified virtual address (v) in the
        !           627:  *     target physical map with the protection requested.
        !           628:  *
        !           629:  *     NB:  This is the only routine which MAY NOT lazy-evaluate
        !           630:  *     or lose information.  That is, this routine must actually
        !           631:  *     insert this page into the given map NOW.
        !           632:  */
        !           633: int
        !           634: pmap_enter(pmap_t pmap, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
        !           635: {
        !           636:        pt_entry_t *pte;
        !           637:        u_int npte;
        !           638:        vm_page_t pg;
        !           639:
        !           640:        DPRINTF(PDB_FOLLOW|PDB_ENTER,
        !           641:                ("pmap_enter(%p, %p, %p, %p, %p)\n", pmap, va, pa, prot, flags));
        !           642:
        !           643: #ifdef DIAGNOSTIC
        !           644:        if (pmap == pmap_kernel()) {
        !           645:                stat_count(enter_stats.kernel);
        !           646:                if (va < VM_MIN_KERNEL_ADDRESS)
        !           647:                        panic("pmap_enter: kva %p", va);
        !           648:        } else {
        !           649:                stat_count(enter_stats.user);
        !           650:                if (va >= VM_MAXUSER_ADDRESS)
        !           651:                        panic("pmap_enter: uva %p", va);
        !           652:        }
        !           653: #endif
        !           654:
        !           655:        pg = PHYS_TO_VM_PAGE(pa);
        !           656:
        !           657:        if (pg != NULL) {
        !           658:                if (!(prot & VM_PROT_WRITE)) {
        !           659:                        npte = PG_ROPAGE;
        !           660:                } else {
        !           661:                        if (pmap == pmap_kernel()) {
        !           662:                                /*
        !           663:                                 * Don't bother to trap on kernel writes,
        !           664:                                 * just record page as dirty.
        !           665:                                 */
        !           666:                                npte = PG_RWPAGE;
        !           667:                        } else {
        !           668:                                if (pg->pg_flags & PV_ATTR_MOD) {
        !           669:                                        npte = PG_RWPAGE;
        !           670:                                } else {
        !           671:                                        npte = PG_CWPAGE;
        !           672:                                }
        !           673:                        }
        !           674:                }
        !           675:
        !           676:                /* Set page referenced/modified status based on flags */
        !           677:                if (flags & VM_PROT_WRITE)
        !           678:                        atomic_setbits_int(&pg->pg_flags,
        !           679:                            PV_ATTR_MOD | PV_ATTR_REF);
        !           680:                else if (flags & VM_PROT_ALL)
        !           681:                        atomic_setbits_int(&pg->pg_flags, PV_ATTR_REF);
        !           682:
        !           683:                stat_count(enter_stats.managed);
        !           684:        } else {
        !           685:                /*
        !           686:                 * Assumption: if it is not part of our managed memory
        !           687:                 * then it must be device memory which may be volatile.
        !           688:                 */
        !           689:                stat_count(enter_stats.unmanaged);
        !           690:                if (prot & VM_PROT_WRITE) {
        !           691:                        npte = PG_IOPAGE & ~PG_G;
        !           692:                } else {
        !           693:                        npte = (PG_IOPAGE | PG_RO) & ~(PG_G | PG_M);
        !           694:                }
        !           695:        }
        !           696:
        !           697:        if (pmap == pmap_kernel()) {
        !           698:                if (pg != NULL) {
        !           699:                        if (pmap_enter_pv(pmap, va, pg, &npte) != 0) {
        !           700:                                if (flags & PMAP_CANFAIL)
        !           701:                                        return ENOMEM;
        !           702:                                panic("pmap_enter: pmap_enter_pv() failed");
        !           703:                        }
        !           704:                }
        !           705:
        !           706:                pte = kvtopte(va);
        !           707:                npte |= vad_to_pfn(pa) | PG_G;
        !           708:                if (!(pte->pt_entry & PG_V)) {
        !           709:                        pmap->pm_stats.resident_count++;
        !           710:                }
        !           711:                if ((pte->pt_entry & PG_V) && pa != pfn_to_pad(pte->pt_entry)) {
        !           712:                        pmap_remove(pmap, va, va + NBPG);
        !           713:                        stat_count(enter_stats.mchange);
        !           714:                }
        !           715:
        !           716:                /*
        !           717:                 * Update the same virtual address entry.
        !           718:                 */
        !           719:                pte->pt_entry = npte;
        !           720:                tlb_update(va, npte);
        !           721:                return 0;
        !           722:        }
        !           723:
        !           724:        /*
        !           725:         *  User space mapping. Do table build.
        !           726:         */
        !           727:        if (!(pte = pmap_segmap(pmap, va))) {
        !           728:                vaddr_t nva;
        !           729:
        !           730:                while (pmap_page_alloc(&nva) != 0) {
        !           731:                        if (flags & PMAP_CANFAIL)
        !           732:                                return ENOMEM;
        !           733:                        uvm_wait("pmap_enter");
        !           734:                }
        !           735:
        !           736:                pmap_segmap(pmap, va) = pte = (pt_entry_t *)nva;
        !           737:        }
        !           738:
        !           739:        if (pg != NULL) {
        !           740:                if (pmap_enter_pv(pmap, va, pg, &npte) != 0) {
        !           741:                        if (flags & PMAP_CANFAIL)
        !           742:                                return ENOMEM;
        !           743:                        panic("pmap_enter: pmap_enter_pv() failed");
        !           744:                }
        !           745:        }
        !           746:
        !           747:        pte += uvtopte(va);
        !           748:
        !           749:        /*
        !           750:         * Now validate mapping with desired protection/wiring.
        !           751:         * Assume uniform modified and referenced status for all
        !           752:         * MIPS pages in a OpenBSD page.
        !           753:         */
        !           754:        npte |= vad_to_pfn(pa);
        !           755:        if (pmap->pm_tlbgen == tlbpid_gen) {
        !           756:                DPRINTF(PDB_ENTER, ("pmap_enter: new pte %x tlbpid %d\n",
        !           757:                        npte, pmap->pm_tlbpid));
        !           758:        } else {
        !           759:                DPRINTF(PDB_ENTER, ("pmap_enter: new pte 0x%08x\n", npte));
        !           760:        }
        !           761:
        !           762:        if ((pte->pt_entry & PG_V) && pa != pfn_to_pad(pte->pt_entry)) {
        !           763:                pmap_remove(pmap, va, va + NBPG);
        !           764:                stat_count(enter_stats.mchange);
        !           765:        }
        !           766:
        !           767:        if (!(pte->pt_entry & PG_V)) {
        !           768:                pmap->pm_stats.resident_count++;
        !           769:        }
        !           770:        pte->pt_entry = npte;
        !           771:        if (pmap->pm_tlbgen == tlbpid_gen) {
        !           772:                tlb_update(va | (pmap->pm_tlbpid << VMTLB_PID_SHIFT), npte);
        !           773:        }
        !           774:
        !           775:        /*
        !           776:         *  If mapping a memory space address invalidate ICache.
        !           777:         */
        !           778:        if (pg != NULL && (prot & VM_PROT_EXECUTE))
        !           779:                Mips_InvalidateICache(va, PAGE_SIZE);
        !           780:
        !           781:        return 0;
        !           782: }
        !           783:
        !           784: void
        !           785: pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
        !           786: {
        !           787:        pt_entry_t *pte;
        !           788:        u_int npte;
        !           789:
        !           790:        DPRINTF(PDB_FOLLOW|PDB_ENTER,
        !           791:                ("pmap_kenter_pa(%p, %p, 0x%x)\n", va, pa, prot));
        !           792:
        !           793:        npte = vad_to_pfn(pa) | PG_G;
        !           794:        if (prot & VM_PROT_WRITE)
        !           795:                npte |= PG_RWPAGE;
        !           796:        else
        !           797:                npte |= PG_ROPAGE;
        !           798:        pte = kvtopte(va);
        !           799:        pte->pt_entry = npte;
        !           800:        tlb_update(va, npte);
        !           801: }
        !           802:
        !           803: /*
        !           804:  *  Remove a mapping from the kernel map table. When doing this
        !           805:  *  the cache must be synced for the VA mapped since we mapped
        !           806:  *  pages behind the back of the VP tracking system.
        !           807:  */
        !           808: void
        !           809: pmap_kremove(vaddr_t va, vsize_t len)
        !           810: {
        !           811:        pt_entry_t *pte;
        !           812:        vaddr_t eva;
        !           813:        u_int entry;
        !           814:
        !           815:        DPRINTF(PDB_FOLLOW|PDB_REMOVE, ("pmap_kremove(%p, %p)\n", va, len));
        !           816:
        !           817:        pte = kvtopte(va);
        !           818:        eva = va + len;
        !           819:        for (; va < eva; va += PAGE_SIZE, pte++) {
        !           820:                entry = pte->pt_entry;
        !           821:                if (!(entry & PG_V))
        !           822:                        continue;
        !           823:                Mips_HitSyncDCache(va, PAGE_SIZE);
        !           824:                pte->pt_entry = PG_NV | PG_G;
        !           825:                tlb_flush_addr(va);
        !           826:        }
        !           827: }
        !           828:
        !           829: void
        !           830: pmap_unwire(pmap_t pmap, vaddr_t va)
        !           831: {
        !           832:        /* XXX this pmap does not handle wired mappings yet... */
        !           833: }
        !           834:
        !           835: /*
        !           836:  *     Routine:        pmap_extract
        !           837:  *     Function:
        !           838:  *             Extract the physical page address associated
        !           839:  *             with the given map/virtual_address pair.
        !           840:  */
        !           841: boolean_t
        !           842: pmap_extract(pmap_t pmap, vaddr_t va, paddr_t *pap)
        !           843: {
        !           844:        boolean_t rv = TRUE;
        !           845:        paddr_t pa;
        !           846:        pt_entry_t *pte;
        !           847:
        !           848:        if (pmap == pmap_kernel()) {
        !           849:                if (IS_XKPHYS(va))
        !           850:                        pa = XKPHYS_TO_PHYS(va);
        !           851:                else if (va >= (vaddr_t)KSEG0_BASE &&
        !           852:                    va < (vaddr_t)KSEG0_BASE + KSEG_SIZE)
        !           853:                        pa = KSEG0_TO_PHYS(va);
        !           854:                else if (va >= (vaddr_t)KSEG1_BASE &&
        !           855:                    va < (vaddr_t)KSEG1_BASE + KSEG_SIZE)
        !           856:                        pa = KSEG1_TO_PHYS(va);
        !           857:                else {
        !           858: #ifdef DIAGNOSTIC
        !           859:                        if (va < VM_MIN_KERNEL_ADDRESS ||
        !           860:                            va >= VM_MAX_KERNEL_ADDRESS)
        !           861:                                panic("pmap_extract(%p, %p)", pmap, va);
        !           862: #endif
        !           863:                        pte = kvtopte(va);
        !           864:                        if (pte->pt_entry & PG_V)
        !           865:                                pa = pfn_to_pad(pte->pt_entry) |
        !           866:                                    (va & PAGE_MASK);
        !           867:                        else
        !           868:                                rv = FALSE;
        !           869:                }
        !           870:        } else {
        !           871:                if (!(pte = pmap_segmap(pmap, va)))
        !           872:                        rv = FALSE;
        !           873:                else {
        !           874:                        pte += uvtopte(va);
        !           875:                        pa = pfn_to_pad(pte->pt_entry) | (va & PAGE_MASK);
        !           876:                }
        !           877:        }
        !           878:        if (rv != FALSE)
        !           879:                *pap = pa;
        !           880:
        !           881:        DPRINTF(PDB_FOLLOW, ("pmap_extract(%p, %p)=%p(%d)", pmap, va, pa, rv));
        !           882:
        !           883:        return (rv);
        !           884: }
        !           885:
        !           886: /*
        !           887:  * Find first virtual address >= *vap that
        !           888:  * will not cause cache aliases.
        !           889:  */
        !           890: void
        !           891: pmap_prefer(paddr_t foff, vaddr_t *vap)
        !           892: {
        !           893: #if 1
        !           894:        *vap += (foff - *vap) & (CpuCacheAliasMask | PAGE_MASK);
        !           895: #else
        !           896:        *vap += (*vap ^ foff) & CpuCacheAliasMask;
        !           897: #endif
        !           898: }
        !           899:
        !           900: /*
        !           901:  *     Copy the range specified by src_addr/len
        !           902:  *     from the source map to the range dst_addr/len
        !           903:  *     in the destination map.
        !           904:  *
        !           905:  *     This routine is only advisory and need not do anything.
        !           906:  */
        !           907: void
        !           908: pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
        !           909:        pmap_t dst_pmap;
        !           910:        pmap_t src_pmap;
        !           911:        vaddr_t dst_addr;
        !           912:        vsize_t len;
        !           913:        vaddr_t src_addr;
        !           914: {
        !           915:
        !           916:        DPRINTF(PDB_FOLLOW, ("pmap_copy(%p, %p, %p, %p, %p)\n",
        !           917:               dst_pmap, src_pmap, dst_addr, len, src_addr));
        !           918: }
        !           919:
        !           920: /*
        !           921:  *     pmap_zero_page zeros the specified (machine independent) page.
        !           922:  */
        !           923: void
        !           924: pmap_zero_page(struct vm_page *pg)
        !           925: {
        !           926:        paddr_t phys = VM_PAGE_TO_PHYS(pg);
        !           927:        vaddr_t va;
        !           928:        pv_entry_t pv;
        !           929:
        !           930:        DPRINTF(PDB_FOLLOW, ("pmap_zero_page(%p)\n", phys));
        !           931:
        !           932:        va = (vaddr_t)PHYS_TO_XKPHYS(phys, CCA_NONCOHERENT);
        !           933:        pv = pg_to_pvh(pg);
        !           934:        if ((pg->pg_flags & PV_CACHED) &&
        !           935:            ((pv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
        !           936:                Mips_SyncDCachePage(pv->pv_va);
        !           937:        }
        !           938:        mem_zero_page(va);
        !           939:        Mips_HitSyncDCache(va, PAGE_SIZE);
        !           940: }
        !           941:
        !           942: /*
        !           943:  *     pmap_copy_page copies the specified (machine independent) page.
        !           944:  *
        !           945:  *     We do the copy phys to phys and need to check if there may be
        !           946:  *     a virtual coherence problem. If so flush the cache for the
        !           947:  *     areas before copying, and flush afterwards.
        !           948:  */
        !           949: void
        !           950: pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
        !           951: {
        !           952:        paddr_t src, dst;
        !           953:        vaddr_t s, d;
        !           954:        int df = 1;
        !           955:        int sf = 1;
        !           956:        pv_entry_t pv;
        !           957:
        !           958:        src = VM_PAGE_TO_PHYS(srcpg);
        !           959:        dst = VM_PAGE_TO_PHYS(dstpg);
        !           960:        s = (vaddr_t)PHYS_TO_XKPHYS(src, CCA_NONCOHERENT);
        !           961:        d = (vaddr_t)PHYS_TO_XKPHYS(dst, CCA_NONCOHERENT);
        !           962:
        !           963:        DPRINTF(PDB_FOLLOW, ("pmap_copy_page(%p, %p)\n", src, dst));
        !           964:
        !           965:        pv = pg_to_pvh(srcpg);
        !           966:        if ((srcpg->pg_flags & PV_CACHED) &&
        !           967:            (sf = ((pv->pv_va ^ (long)s) & CpuCacheAliasMask) != 0)) {
        !           968:                Mips_SyncDCachePage(pv->pv_va);
        !           969:        }
        !           970:        pv = pg_to_pvh(dstpg);
        !           971:        if ((dstpg->pg_flags & PV_CACHED) &&
        !           972:            (df = ((pv->pv_va ^ (long)d) & CpuCacheAliasMask) != 0)) {
        !           973:                Mips_SyncDCachePage(pv->pv_va);
        !           974:        }
        !           975:
        !           976:        memcpy((void *)d, (void *)s, PAGE_SIZE);
        !           977:
        !           978:        if (sf) {
        !           979:                Mips_HitSyncDCache(s, PAGE_SIZE);
        !           980:        }
        !           981:        Mips_HitSyncDCache(d, PAGE_SIZE);
        !           982: }
        !           983:
        !           984: /*
        !           985:  *  Clear the modify bits on the specified physical page.
        !           986:  *  Also sync the cache so it reflects the new clean state of the page.
        !           987:  */
        !           988: boolean_t
        !           989: pmap_clear_modify(struct vm_page *pg)
        !           990: {
        !           991:        pv_entry_t pv;
        !           992:        pt_entry_t *pte;
        !           993:        unsigned entry;
        !           994:        boolean_t rv = FALSE;
        !           995:        int s;
        !           996:
        !           997:        DPRINTF(PDB_FOLLOW, ("pmap_clear_modify(%p)\n", VM_PAGE_TO_PHYS(pg)));
        !           998:
        !           999:        pv = pg_to_pvh(pg);
        !          1000:        s = splvm();
        !          1001:        if (pg->pg_flags & PV_ATTR_MOD) {
        !          1002:                atomic_clearbits_int(&pg->pg_flags, PV_ATTR_MOD);
        !          1003:                rv = TRUE;
        !          1004:        }
        !          1005:        if (pg->pg_flags & PV_CACHED)
        !          1006:                Mips_SyncDCachePage(pv->pv_va);
        !          1007:
        !          1008:        for (; pv != NULL; pv = pv->pv_next) {
        !          1009:                if (pv->pv_pmap == pmap_kernel()) {
        !          1010:                        pte = kvtopte(pv->pv_va);
        !          1011:                        entry = pte->pt_entry;
        !          1012:                        if ((entry & PG_V) != 0 && (entry & PG_M) != 0) {
        !          1013:                                rv = TRUE;
        !          1014:                                entry &= ~PG_M;
        !          1015:                                pte->pt_entry = entry;
        !          1016:                                tlb_update(pv->pv_va, entry);
        !          1017:                        }
        !          1018:                } else if (pv->pv_pmap != NULL) {
        !          1019:                        if ((pte = pmap_segmap(pv->pv_pmap, pv->pv_va)) == NULL)
        !          1020:                                continue;
        !          1021:                        pte += uvtopte(pv->pv_va);
        !          1022:                        entry = pte->pt_entry;
        !          1023:                        if ((entry & PG_V) != 0 && (entry & PG_M) != 0) {
        !          1024:                                rv = TRUE;
        !          1025:                                entry &= ~PG_M;
        !          1026:                                pte->pt_entry = entry;
        !          1027:                                if (pv->pv_pmap->pm_tlbgen == tlbpid_gen)
        !          1028:                                        tlb_update(pv->pv_va | (pv->pv_pmap->pm_tlbpid <<
        !          1029:                                                VMTLB_PID_SHIFT), entry);
        !          1030:                        }
        !          1031:                }
        !          1032:        }
        !          1033:        splx(s);
        !          1034:
        !          1035:        return rv;
        !          1036: }
        !          1037:
        !          1038: void
        !          1039: pmap_set_modify(struct vm_page *pg)
        !          1040: {
        !          1041:        atomic_setbits_int(&pg->pg_flags, PV_ATTR_MOD | PV_ATTR_REF);
        !          1042: }
        !          1043:
        !          1044: /*
        !          1045:  *     pmap_clear_reference:
        !          1046:  *
        !          1047:  *     Clear the reference bit on the specified physical page.
        !          1048:  */
        !          1049: boolean_t
        !          1050: pmap_clear_reference(struct vm_page *pg)
        !          1051: {
        !          1052:        boolean_t rv;
        !          1053:
        !          1054:        DPRINTF(PDB_FOLLOW, ("pmap_clear_reference(%p)\n", VM_PAGE_TO_PHYS(pg)));
        !          1055:
        !          1056:        rv = (pg->pg_flags & PV_ATTR_REF) != 0;
        !          1057:        atomic_clearbits_int(&pg->pg_flags, PV_ATTR_REF);
        !          1058:        return rv;
        !          1059: }
        !          1060:
        !          1061: /*
        !          1062:  *     pmap_is_referenced:
        !          1063:  *
        !          1064:  *     Return whether or not the specified physical page is referenced
        !          1065:  *     by any physical maps.
        !          1066:  */
        !          1067: boolean_t
        !          1068: pmap_is_referenced(struct vm_page *pg)
        !          1069: {
        !          1070:        return (pg->pg_flags & PV_ATTR_REF) != 0;
        !          1071: }
        !          1072:
        !          1073: /*
        !          1074:  *     pmap_is_modified:
        !          1075:  *
        !          1076:  *     Return whether or not the specified physical page is modified
        !          1077:  *     by any physical maps.
        !          1078:  */
        !          1079: boolean_t
        !          1080: pmap_is_modified(struct vm_page *pg)
        !          1081: {
        !          1082:        return (pg->pg_flags & PV_ATTR_MOD) != 0;
        !          1083: }
        !          1084:
        !          1085: /*
        !          1086:  * Miscellaneous support routines not part of the pmap API
        !          1087:  */
        !          1088:
        !          1089: /*
        !          1090:  *     Return RO protection of page.
        !          1091:  */
        !          1092: int
        !          1093: pmap_is_page_ro(pmap_t pmap, vaddr_t va, int entry)
        !          1094: {
        !          1095:        return (entry & PG_RO);
        !          1096: }
        !          1097:
        !          1098:
        !          1099: /*
        !          1100:  *  Walk the PV tree for a physical page and change all its
        !          1101:  *  mappings to cached or uncached.
        !          1102:  */
        !          1103: void
        !          1104: pmap_page_cache(vm_page_t pg, int mode)
        !          1105: {
        !          1106:        pv_entry_t pv;
        !          1107:        pt_entry_t *pte;
        !          1108:        u_int entry;
        !          1109:        u_int newmode;
        !          1110:        int s;
        !          1111:
        !          1112:        DPRINTF(PDB_FOLLOW|PDB_ENTER, ("pmap_page_uncache(%p)\n", pg));
        !          1113:
        !          1114:        newmode = mode & PV_UNCACHED ? PG_UNCACHED : PG_CACHED;
        !          1115:        pv = pg_to_pvh(pg);
        !          1116:
        !          1117:        s = splvm();
        !          1118:        for (; pv != NULL; pv = pv->pv_next) {
        !          1119:                if (pv->pv_pmap == pmap_kernel()) {
        !          1120:                        pte = kvtopte(pv->pv_va);
        !          1121:                        entry = pte->pt_entry;
        !          1122:                        if (entry & PG_V) {
        !          1123:                                entry = (entry & ~PG_CACHEMODE) | newmode;
        !          1124:                                pte->pt_entry = entry;
        !          1125:                                tlb_update(pv->pv_va, entry);
        !          1126:                        }
        !          1127:                } else {
        !          1128:                        if ((pte = pmap_segmap(pv->pv_pmap, pv->pv_va))) {
        !          1129:                                pte += uvtopte(pv->pv_va);
        !          1130:                                entry = pte->pt_entry;
        !          1131:                                if (entry & PG_V) {
        !          1132:                                        entry = (entry & ~PG_CACHEMODE) | newmode;
        !          1133:                                        pte->pt_entry = entry;
        !          1134:                                        if (pv->pv_pmap->pm_tlbgen == tlbpid_gen)
        !          1135:                                                tlb_update(pv->pv_va | (pv->pv_pmap->pm_tlbpid <<
        !          1136:                                                        VMTLB_PID_SHIFT), entry);
        !          1137:                                }
        !          1138:                        }
        !          1139:                }
        !          1140:        }
        !          1141:        atomic_clearbits_int(&pg->pg_flags, PV_CACHED | PV_UNCACHED);
        !          1142:        atomic_setbits_int(&pg->pg_flags, mode);
        !          1143:        splx(s);
        !          1144: }
        !          1145:
        !          1146: /*
        !          1147:  *  Use this function to allocate pages for the mapping tables.
        !          1148:  *  Mapping tables are walked by the TLB miss code and are mapped in
        !          1149:  *  XKPHYS to avoid additional page faults when servicing a TLB miss.
        !          1150:  */
        !          1151: int
        !          1152: pmap_page_alloc(vaddr_t *ret)
        !          1153: {
        !          1154:        vm_page_t pg;
        !          1155:
        !          1156:        pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE | UVM_PGA_ZERO);
        !          1157:        if (pg == NULL)
        !          1158:                return ENOMEM;
        !          1159:
        !          1160:        *ret = PHYS_TO_XKPHYS(VM_PAGE_TO_PHYS(pg), CCA_NONCOHERENT);
        !          1161:        return 0;
        !          1162: }
        !          1163:
        !          1164: void
        !          1165: pmap_page_free(vaddr_t va)
        !          1166: {
        !          1167:        vm_page_t pg;
        !          1168:
        !          1169:        pg = PHYS_TO_VM_PAGE(XKPHYS_TO_PHYS(va));
        !          1170:        uvm_pagefree(pg);
        !          1171: }
        !          1172:
        !          1173: /*
        !          1174:  * Allocate a hardware PID and return it.
        !          1175:  * It takes almost as much or more time to search the TLB for a
        !          1176:  * specific PID and flush those entries as it does to flush the entire TLB.
        !          1177:  * Therefore, when we allocate a new PID, we just take the next number. When
        !          1178:  * we run out of numbers, we flush the TLB, increment the generation count
        !          1179:  * and start over. PID zero is reserved for kernel use.
        !          1180:  * This is called only by switch().
        !          1181:  */
        !          1182: int
        !          1183: pmap_alloc_tlbpid(struct proc *p)
        !          1184: {
        !          1185:        pmap_t pmap;
        !          1186:        int id;
        !          1187:
        !          1188:        pmap = p->p_vmspace->vm_map.pmap;
        !          1189:        if (pmap->pm_tlbgen != tlbpid_gen) {
        !          1190:                id = tlbpid_cnt;
        !          1191:                if (id >= VMNUM_PIDS) {
        !          1192:                        tlb_flush(sys_config.cpu[0].tlbsize);
        !          1193:                        /* reserve tlbpid_gen == 0 to alway mean invalid */
        !          1194:                        if (++tlbpid_gen == 0)
        !          1195:                                tlbpid_gen = 1;
        !          1196:                        id = 1;
        !          1197:                }
        !          1198:                tlbpid_cnt = id + 1;
        !          1199:                pmap->pm_tlbpid = id;
        !          1200:                pmap->pm_tlbgen = tlbpid_gen;
        !          1201:        } else {
        !          1202:                id = pmap->pm_tlbpid;
        !          1203:        }
        !          1204:
        !          1205:        if (curproc) {
        !          1206:                DPRINTF(PDB_FOLLOW|PDB_TLBPID,
        !          1207:                        ("pmap_alloc_tlbpid: curproc %d '%s' ",
        !          1208:                                curproc->p_pid, curproc->p_comm));
        !          1209:        } else {
        !          1210:                DPRINTF(PDB_FOLLOW|PDB_TLBPID,
        !          1211:                        ("pmap_alloc_tlbpid: curproc <none> "));
        !          1212:        }
        !          1213:        DPRINTF(PDB_FOLLOW|PDB_TLBPID, ("segtab %p tlbpid %d pid %d '%s'\n",
        !          1214:                        pmap->pm_segtab, id, p->p_pid, p->p_comm));
        !          1215:
        !          1216:        return (id);
        !          1217: }
        !          1218:
        !          1219: /*
        !          1220:  * Enter the pmap and virtual address into the physical to virtual map table.
        !          1221:  */
        !          1222: int
        !          1223: pmap_enter_pv(pmap_t pmap, vaddr_t va, vm_page_t pg, u_int *npte)
        !          1224: {
        !          1225:        pv_entry_t pv, npv;
        !          1226:        int s;
        !          1227:
        !          1228:        pv = pg_to_pvh(pg);
        !          1229:
        !          1230:        s = splvm();
        !          1231:        if (pv->pv_pmap == NULL) {
        !          1232:                /*
        !          1233:                 * No entries yet, use header as the first entry
        !          1234:                 */
        !          1235:
        !          1236:                DPRINTF(PDB_PVENTRY,
        !          1237:                        ("pmap_enter: first pv: pmap %p va %p pa %p\n",
        !          1238:                                pmap, va, VM_PAGE_TO_PHYS(pg)));
        !          1239:
        !          1240:                stat_count(enter_stats.firstpv);
        !          1241:
        !          1242:                pv->pv_va = va;
        !          1243:                atomic_setbits_int(&pg->pg_flags, PV_CACHED);
        !          1244:                pv->pv_pmap = pmap;
        !          1245:                pv->pv_next = NULL;
        !          1246:        } else {
        !          1247:                if (pg->pg_flags & PV_UNCACHED) {
        !          1248:                        /*
        !          1249:                         * If page is mapped uncached it's either because
        !          1250:                         * an uncached mapping was requested or we have a
        !          1251:                         * VAC situation. Map this page uncached as well.
        !          1252:                         */
        !          1253:                        *npte = (*npte & ~PG_CACHEMODE) | PG_UNCACHED;
        !          1254:                } else if (CpuCacheAliasMask != 0) {
        !          1255:                        /*
        !          1256:                         * We have a VAC possibility.  Check if virtual
        !          1257:                         * address of current mappings are compatible
        !          1258:                         * with this new mapping. Only need to check first
        !          1259:                         * since all others have been checked compatible
        !          1260:                         * when added. If they are incompatible, remove
        !          1261:                         * all mappings, flush the cache and set page
        !          1262:                         * to be mapped uncached.
        !          1263:                         */
        !          1264:                        if (((pv->pv_va ^ va) & CpuCacheAliasMask) != 0) {
        !          1265: #ifdef PMAP_DEBUG
        !          1266:                                printf("pmap_enter: VAC for pa %p, %p !=  %p\n",
        !          1267:                                    VM_PAGE_TO_PHYS(pg), npv->pv_va, va);
        !          1268: #endif
        !          1269:                                pmap_page_cache(pg, PV_UNCACHED);
        !          1270:                                Mips_SyncDCachePage(pv->pv_va);
        !          1271:                                *npte = (*npte & ~PG_CACHEMODE) | PG_UNCACHED;
        !          1272:                        }
        !          1273:                }
        !          1274:
        !          1275:                /*
        !          1276:                 * There is at least one other VA mapping this page.
        !          1277:                 * Place this entry after the header.
        !          1278:                 *
        !          1279:                 * Note: the entry may already be in the table if
        !          1280:                 * we are only changing the protection bits.
        !          1281:                 */
        !          1282:                for (npv = pv; npv; npv = npv->pv_next) {
        !          1283:                        if (pmap == npv->pv_pmap && va == npv->pv_va) {
        !          1284:                                return 0;
        !          1285:                        }
        !          1286:                }
        !          1287:
        !          1288:                DPRINTF(PDB_PVENTRY,
        !          1289:                        ("pmap_enter: new pv: pmap %x va %x pg %p\n",
        !          1290:                            pmap, va, VM_PAGE_TO_PHYS(pg)));
        !          1291:
        !          1292:                npv = pmap_pv_alloc();
        !          1293:                if (npv == NULL) {
        !          1294:                        splx(s);
        !          1295:                        return ENOMEM;
        !          1296:                }
        !          1297:                npv->pv_va = va;
        !          1298:                npv->pv_pmap = pmap;
        !          1299:                npv->pv_next = pv->pv_next;
        !          1300:                pv->pv_next = npv;
        !          1301:
        !          1302:                if (!npv->pv_next)
        !          1303:                        stat_count(enter_stats.secondpv);
        !          1304:        }
        !          1305:
        !          1306:        splx(s);
        !          1307:        return 0;
        !          1308: }
        !          1309:
        !          1310: /*
        !          1311:  * Remove a physical to virtual address translation from the PV table.
        !          1312:  */
        !          1313: void
        !          1314: pmap_remove_pv(pmap_t pmap, vaddr_t va, paddr_t pa)
        !          1315: {
        !          1316:        pv_entry_t pv, npv;
        !          1317:        vm_page_t pg;
        !          1318:        int s;
        !          1319:
        !          1320:        DPRINTF(PDB_FOLLOW|PDB_PVENTRY,
        !          1321:                ("pmap_remove_pv(%p, %p, %p)\n", pmap, va, pa));
        !          1322:
        !          1323:        /*
        !          1324:         * Remove page from the PV table
        !          1325:         */
        !          1326:        pg = PHYS_TO_VM_PAGE(pa);
        !          1327:        if (pg == NULL)
        !          1328:                return;
        !          1329:
        !          1330:        pv = pg_to_pvh(pg);
        !          1331:        s = splvm();
        !          1332:        /*
        !          1333:         * If we are removing the first entry on the list, copy up
        !          1334:         * the next entry, if any, and free that pv item since the
        !          1335:         * first root item can't be freed. Else walk the list.
        !          1336:         */
        !          1337:        if (pmap == pv->pv_pmap && va == pv->pv_va) {
        !          1338:                npv = pv->pv_next;
        !          1339:                if (npv) {
        !          1340:                        *pv = *npv;
        !          1341:                        pmap_pv_free(npv);
        !          1342:                } else {
        !          1343:                        pv->pv_pmap = NULL;
        !          1344:                        atomic_clearbits_int(&pg->pg_flags,
        !          1345:                            (PG_PMAP0 | PG_PMAP1 | PG_PMAP2 | PG_PMAP3) &
        !          1346:                            ~PV_PRESERVE);
        !          1347:                        Mips_SyncDCachePage(va);
        !          1348:                }
        !          1349:                stat_count(remove_stats.pvfirst);
        !          1350:        } else {
        !          1351:                for (npv = pv->pv_next; npv; pv = npv, npv = npv->pv_next) {
        !          1352:                        stat_count(remove_stats.pvsearch);
        !          1353:                        if (pmap == npv->pv_pmap && va == npv->pv_va)
        !          1354:                                break;
        !          1355:                }
        !          1356:                if (npv != NULL) {
        !          1357:                        pv->pv_next = npv->pv_next;
        !          1358:                        pmap_pv_free(npv);
        !          1359:                } else {
        !          1360: #ifdef DIAGNOSTIC
        !          1361:                        panic("pmap_remove_pv(%x, %x, %x) not found",
        !          1362:                            pmap, va, pa);
        !          1363: #endif
        !          1364:                }
        !          1365:        }
        !          1366:        splx(s);
        !          1367: }
        !          1368:
        !          1369: /*==================================================================*/
        !          1370: /* Bus space map utility functions */
        !          1371:
        !          1372: int
        !          1373: bus_mem_add_mapping(bus_addr_t bpa, bus_size_t size, int cacheable,
        !          1374:                        bus_space_handle_t *bshp)
        !          1375: {
        !          1376:        bus_addr_t vaddr;
        !          1377:        bus_addr_t spa, epa;
        !          1378:        bus_size_t off;
        !          1379:        int len;
        !          1380:
        !          1381:        spa = trunc_page(bpa);
        !          1382:        epa = bpa + size;
        !          1383:        off = bpa - spa;
        !          1384:        len = size+off;
        !          1385:
        !          1386:        vaddr = uvm_km_valloc_wait(kernel_map, len);
        !          1387:        *bshp = vaddr + off;
        !          1388: #ifdef DEBUG_BUS_MEM_ADD_MAPPING
        !          1389:        printf("map bus %x size %x to %x vbase %x\n", bpa, size, *bshp, spa);
        !          1390: #endif
        !          1391:        for (; len > 0; len -= NBPG) {
        !          1392:                pt_entry_t *pte;
        !          1393:                u_int npte;
        !          1394:
        !          1395:                npte = vad_to_pfn(spa) | PG_G;
        !          1396:                npte |= PG_V | PG_M | PG_IOPAGE;
        !          1397:                pte = kvtopte(vaddr);
        !          1398:                pte->pt_entry = npte;
        !          1399:                tlb_update(vaddr, npte);
        !          1400:
        !          1401:                spa += NBPG;
        !          1402:                vaddr += NBPG;
        !          1403:        }
        !          1404:        return 0;
        !          1405: }

CVSweb