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

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

1.1     ! nbrk        1: /*     $OpenBSD: pmap.c,v 1.101 2007/05/27 15:46:02 drahn Exp $ */
        !             2:
        !             3: /*
        !             4:  * Copyright (c) 2001, 2002, 2007 Dale Rahn.
        !             5:  * All rights reserved.
        !             6:  *
        !             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:  *
        !            17:  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
        !            18:  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
        !            19:  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
        !            20:  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
        !            21:  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
        !            22:  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
        !            23:  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
        !            24:  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
        !            25:  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
        !            26:  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
        !            27:  *
        !            28:  * Effort sponsored in part by the Defense Advanced Research Projects
        !            29:  * Agency (DARPA) and Air Force Research Laboratory, Air Force
        !            30:  * Materiel Command, USAF, under agreement number F30602-01-2-0537.
        !            31:  */
        !            32:
        !            33: #include <sys/param.h>
        !            34: #include <sys/malloc.h>
        !            35: #include <sys/proc.h>
        !            36: #include <sys/queue.h>
        !            37: #include <sys/user.h>
        !            38: #include <sys/systm.h>
        !            39: #include <sys/pool.h>
        !            40:
        !            41: #include <uvm/uvm.h>
        !            42:
        !            43: #include <machine/pcb.h>
        !            44: #include <machine/powerpc.h>
        !            45: #include <machine/pmap.h>
        !            46:
        !            47: #include <machine/db_machdep.h>
        !            48: #include <ddb/db_extern.h>
        !            49: #include <ddb/db_output.h>
        !            50:
        !            51: struct pmap kernel_pmap_;
        !            52: static struct mem_region *pmap_mem, *pmap_avail;
        !            53: struct mem_region pmap_allocated[10];
        !            54: int pmap_cnt_avail;
        !            55: int pmap_cnt_allocated;
        !            56:
        !            57: struct pte_64  *pmap_ptable64;
        !            58: struct pte_32  *pmap_ptable32;
        !            59: int    pmap_ptab_cnt;
        !            60: u_int  pmap_ptab_mask;
        !            61:
        !            62: #define HTABSIZE_32    (pmap_ptab_cnt * 64)
        !            63: #define HTABMEMSZ_64   (pmap_ptab_cnt * 8 * sizeof(struct pte_64))
        !            64: #define HTABSIZE_64    (ffs(pmap_ptab_cnt) - 12)
        !            65:
        !            66: static u_int usedsr[NPMAPS / sizeof(u_int) / 8];
        !            67: paddr_t zero_page;
        !            68: paddr_t copy_src_page;
        !            69: paddr_t copy_dst_page;
        !            70:
        !            71: struct pte_desc {
        !            72:        /* Linked list of phys -> virt entries */
        !            73:        LIST_ENTRY(pte_desc) pted_pv_list;
        !            74:        union {
        !            75:        struct pte_32 pted_pte32;
        !            76:        struct pte_64 pted_pte64;
        !            77:        }p;
        !            78:        pmap_t pted_pmap;
        !            79:        vaddr_t pted_va;
        !            80: };
        !            81:
        !            82: void print_pteg(pmap_t pm, vaddr_t va);
        !            83:
        !            84: static inline void tlbsync(void);
        !            85: static inline void tlbie(vaddr_t ea);
        !            86: void tlbia(void);
        !            87:
        !            88: void pmap_attr_save(paddr_t pa, u_int32_t bits);
        !            89: void pmap_page_ro64(pmap_t pm, vaddr_t va, vm_prot_t prot);
        !            90: void pmap_page_ro32(pmap_t pm, vaddr_t va);
        !            91:
        !            92: /*
        !            93:  * LOCKING structures.
        !            94:  * This may not be correct, and doesn't do anything yet.
        !            95:  */
        !            96: #define pmap_simplelock_pm(pm)
        !            97: #define pmap_simpleunlock_pm(pm)
        !            98: #define pmap_simplelock_pv(pm)
        !            99: #define pmap_simpleunlock_pv(pm)
        !           100:
        !           101:
        !           102: /* VP routines */
        !           103: void pmap_vp_enter(pmap_t pm, vaddr_t va, struct pte_desc *pted);
        !           104: struct pte_desc *pmap_vp_remove(pmap_t pm, vaddr_t va);
        !           105: void pmap_vp_destroy(pmap_t pm);
        !           106: struct pte_desc *pmap_vp_lookup(pmap_t pm, vaddr_t va);
        !           107:
        !           108: /* PV routines */
        !           109: void pmap_enter_pv(struct pte_desc *pted, struct vm_page *);
        !           110: void pmap_remove_pv(struct pte_desc *pted);
        !           111:
        !           112:
        !           113: /* pte hash table routines */
        !           114: void pte_insert32(struct pte_desc *pted);
        !           115: void pte_insert64(struct pte_desc *pted);
        !           116: void pmap_hash_remove(struct pte_desc *pted);
        !           117: void pmap_fill_pte64(pmap_t pm, vaddr_t va, paddr_t pa,
        !           118:     struct pte_desc *pted, vm_prot_t prot, int flags, int cache);
        !           119: void pmap_fill_pte32(pmap_t pm, vaddr_t va, paddr_t pa,
        !           120:     struct pte_desc *pted, vm_prot_t prot, int flags, int cache);
        !           121:
        !           122: void pmap_syncicache_user_virt(pmap_t pm, vaddr_t va);
        !           123:
        !           124: void _pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags,
        !           125:     int cache);
        !           126: void pmap_remove_pg(pmap_t pm, vaddr_t va);
        !           127: void pmap_kremove_pg(vaddr_t va);
        !           128:
        !           129: /* setup/initialization functions */
        !           130: void pmap_avail_setup(void);
        !           131: void pmap_avail_fixup(void);
        !           132: void pmap_remove_avail(paddr_t base, paddr_t end);
        !           133: void *pmap_steal_avail(size_t size, int align);
        !           134:
        !           135: /* asm interface */
        !           136: int pte_spill_r(u_int32_t va, u_int32_t msr, u_int32_t access_type,
        !           137:     int exec_fault);
        !           138:
        !           139: u_int32_t pmap_setusr(pmap_t pm, vaddr_t va);
        !           140: void pmap_popusr(u_int32_t oldsr);
        !           141:
        !           142: /* pte invalidation */
        !           143: void pte_zap(void *ptp, struct pte_desc *pted);
        !           144:
        !           145: /* debugging */
        !           146: void pmap_print_pted(struct pte_desc *pted, int(*print)(const char *, ...));
        !           147:
        !           148: /* XXX - panic on pool get failures? */
        !           149: struct pool pmap_pmap_pool;
        !           150: struct pool pmap_vp_pool;
        !           151: struct pool pmap_pted_pool;
        !           152:
        !           153: int pmap_initialized = 0;
        !           154: int physmem;
        !           155: int physmaxaddr;
        !           156:
        !           157: /* virtual to physical helpers */
        !           158: static inline int
        !           159: VP_SR(vaddr_t va)
        !           160: {
        !           161:        return (va >>VP_SR_POS) & VP_SR_MASK;
        !           162: }
        !           163:
        !           164: static inline int
        !           165: VP_IDX1(vaddr_t va)
        !           166: {
        !           167:        return (va >> VP_IDX1_POS) & VP_IDX1_MASK;
        !           168: }
        !           169:
        !           170: static inline int
        !           171: VP_IDX2(vaddr_t va)
        !           172: {
        !           173:        return (va >> VP_IDX2_POS) & VP_IDX2_MASK;
        !           174: }
        !           175:
        !           176: #if VP_IDX1_SIZE != VP_IDX2_SIZE
        !           177: #error pmap allocation code expects IDX1 and IDX2 size to be same
        !           178: #endif
        !           179: struct pmapvp {
        !           180:        void *vp[VP_IDX1_SIZE];
        !           181: };
        !           182:
        !           183:
        !           184: /*
        !           185:  * VP routines, virtual to physical translation information.
        !           186:  * These data structures are based off of the pmap, per process.
        !           187:  */
        !           188:
        !           189: /*
        !           190:  * This is used for pmap_kernel() mappings, they are not to be removed
        !           191:  * from the vp table because they were statically initialized at the
        !           192:  * initial pmap initialization. This is so that memory allocation
        !           193:  * is not necessary in the pmap_kernel() mappings.
        !           194:  * Otherwise bad race conditions can appear.
        !           195:  */
        !           196: struct pte_desc *
        !           197: pmap_vp_lookup(pmap_t pm, vaddr_t va)
        !           198: {
        !           199:        struct pmapvp *vp1;
        !           200:        struct pmapvp *vp2;
        !           201:        struct pte_desc *pted;
        !           202:
        !           203:        vp1 = pm->pm_vp[VP_SR(va)];
        !           204:        if (vp1 == NULL) {
        !           205:                return NULL;
        !           206:        }
        !           207:
        !           208:        vp2 = vp1->vp[VP_IDX1(va)];
        !           209:        if (vp2 == NULL) {
        !           210:                return NULL;
        !           211:        }
        !           212:
        !           213:        pted = vp2->vp[VP_IDX2(va)];
        !           214:
        !           215:        return pted;
        !           216: }
        !           217:
        !           218: /*
        !           219:  * Remove, and return, pted at specified address, NULL if not present
        !           220:  */
        !           221: struct pte_desc *
        !           222: pmap_vp_remove(pmap_t pm, vaddr_t va)
        !           223: {
        !           224:        struct pmapvp *vp1;
        !           225:        struct pmapvp *vp2;
        !           226:        struct pte_desc *pted;
        !           227:
        !           228:        vp1 = pm->pm_vp[VP_SR(va)];
        !           229:        if (vp1 == NULL) {
        !           230:                return NULL;
        !           231:        }
        !           232:
        !           233:        vp2 = vp1->vp[VP_IDX1(va)];
        !           234:        if (vp2 == NULL) {
        !           235:                return NULL;
        !           236:        }
        !           237:
        !           238:        pted = vp2->vp[VP_IDX2(va)];
        !           239:        vp2->vp[VP_IDX2(va)] = NULL;
        !           240:
        !           241:        return pted;
        !           242: }
        !           243:
        !           244: /*
        !           245:  * Create a V -> P mapping for the given pmap and virtual address
        !           246:  * with reference to the pte descriptor that is used to map the page.
        !           247:  * This code should track allocations of vp table allocations
        !           248:  * so they can be freed efficiently.
        !           249:  *
        !           250:  * Should this be called under splvm?
        !           251:  */
        !           252: void
        !           253: pmap_vp_enter(pmap_t pm, vaddr_t va, struct pte_desc *pted)
        !           254: {
        !           255:        struct pmapvp *vp1;
        !           256:        struct pmapvp *vp2;
        !           257:        int s;
        !           258:
        !           259:        pmap_simplelock_pm(pm);
        !           260:
        !           261:        vp1 = pm->pm_vp[VP_SR(va)];
        !           262:        if (vp1 == NULL) {
        !           263:                s = splvm();
        !           264:                vp1 = pool_get(&pmap_vp_pool, PR_NOWAIT);
        !           265:                splx(s);
        !           266:                bzero(vp1, sizeof (struct pmapvp));
        !           267:                pm->pm_vp[VP_SR(va)] = vp1;
        !           268:        }
        !           269:
        !           270:        vp2 = vp1->vp[VP_IDX1(va)];
        !           271:        if (vp2 == NULL) {
        !           272:                s = splvm();
        !           273:                vp2 = pool_get(&pmap_vp_pool, PR_NOWAIT);
        !           274:                splx(s);
        !           275:                bzero(vp2, sizeof (struct pmapvp));
        !           276:                vp1->vp[VP_IDX1(va)] = vp2;
        !           277:        }
        !           278:
        !           279:        vp2->vp[VP_IDX2(va)] = pted;
        !           280:
        !           281:        pmap_simpleunlock_pm(pm);
        !           282: }
        !           283:
        !           284: /* PTE manipulation/calculations */
        !           285: static inline void
        !           286: tlbie(vaddr_t va)
        !           287: {
        !           288:        __asm volatile ("tlbie %0" :: "r"(va));
        !           289: }
        !           290:
        !           291: static inline void
        !           292: tlbsync(void)
        !           293: {
        !           294:        __asm volatile ("sync; tlbsync; sync");
        !           295: }
        !           296:
        !           297: void
        !           298: tlbia()
        !           299: {
        !           300:        vaddr_t va;
        !           301:
        !           302:        __asm volatile ("sync");
        !           303:        for (va = 0; va < 0x00040000; va += 0x00001000)
        !           304:                tlbie(va);
        !           305:        tlbsync();
        !           306: }
        !           307:
        !           308: static inline int
        !           309: ptesr(sr_t *sr, vaddr_t va)
        !           310: {
        !           311:        return sr[(u_int)va >> ADDR_SR_SHIFT];
        !           312: }
        !           313:
        !           314: static inline int
        !           315: pteidx(sr_t sr, vaddr_t va)
        !           316: {
        !           317:        int hash;
        !           318:        hash = (sr & SR_VSID) ^ (((u_int)va & ADDR_PIDX) >> ADDR_PIDX_SHIFT);
        !           319:        return hash & pmap_ptab_mask;
        !           320: }
        !           321:
        !           322: #define PTED_VA_PTEGIDX_M      0x07
        !           323: #define PTED_VA_HID_M          0x08
        !           324: #define PTED_VA_MANAGED_M      0x10
        !           325: #define PTED_VA_WIRED_M                0x20
        !           326: #define PTED_VA_EXEC_M         0x40
        !           327:
        !           328: static inline u_int32_t
        !           329: PTED_HID(struct pte_desc *pted)
        !           330: {
        !           331:        return (pted->pted_va & PTED_VA_HID_M);
        !           332: }
        !           333:
        !           334: static inline u_int32_t
        !           335: PTED_PTEGIDX(struct pte_desc *pted)
        !           336: {
        !           337:        return (pted->pted_va & PTED_VA_PTEGIDX_M);
        !           338: }
        !           339:
        !           340: static inline u_int32_t
        !           341: PTED_MANAGED(struct pte_desc *pted)
        !           342: {
        !           343:        return (pted->pted_va & PTED_VA_MANAGED_M);
        !           344: }
        !           345:
        !           346: static inline u_int32_t
        !           347: PTED_WIRED(struct pte_desc *pted)
        !           348: {
        !           349:        return (pted->pted_va & PTED_VA_WIRED_M);
        !           350: }
        !           351:
        !           352: static inline u_int32_t
        !           353: PTED_VALID(struct pte_desc *pted)
        !           354: {
        !           355:        if (ppc_proc_is_64b)
        !           356:                return (pted->p.pted_pte64.pte_hi & PTE_VALID_64);
        !           357:        else
        !           358:                return (pted->p.pted_pte32.pte_hi & PTE_VALID_32);
        !           359: }
        !           360:
        !           361: /*
        !           362:  * PV entries -
        !           363:  * manipulate the physical to virtual translations for the entire system.
        !           364:  *
        !           365:  * QUESTION: should all mapped memory be stored in PV tables? Or
        !           366:  * is it alright to only store "ram" memory. Currently device mappings
        !           367:  * are not stored.
        !           368:  * It makes sense to pre-allocate mappings for all of "ram" memory, since
        !           369:  * it is likely that it will be mapped at some point, but would it also
        !           370:  * make sense to use a tree/table like is use for pmap to store device
        !           371:  * mappings?
        !           372:  * Futher notes: It seems that the PV table is only used for pmap_protect
        !           373:  * and other paging related operations. Given this, it is not necessary
        !           374:  * to store any pmap_kernel() entries in PV tables and does not make
        !           375:  * sense to store device mappings in PV either.
        !           376:  *
        !           377:  * Note: unlike other powerpc pmap designs, the array is only an array
        !           378:  * of pointers. Since the same structure is used for holding information
        !           379:  * in the VP table, the PV table, and for kernel mappings, the wired entries.
        !           380:  * Allocate one data structure to hold all of the info, instead of replicating
        !           381:  * it multiple times.
        !           382:  *
        !           383:  * One issue of making this a single data structure is that two pointers are
        !           384:  * wasted for every page which does not map ram (device mappings), this
        !           385:  * should be a low percentage of mapped pages in the system, so should not
        !           386:  * have too noticable unnecessary ram consumption.
        !           387:  */
        !           388:
        !           389: void
        !           390: pmap_enter_pv(struct pte_desc *pted, struct vm_page *pg)
        !           391: {
        !           392:        if (__predict_false(!pmap_initialized)) {
        !           393:                return;
        !           394:        }
        !           395:
        !           396:        LIST_INSERT_HEAD(&(pg->mdpage.pv_list), pted, pted_pv_list);
        !           397:        pted->pted_va |= PTED_VA_MANAGED_M;
        !           398: }
        !           399:
        !           400: void
        !           401: pmap_remove_pv(struct pte_desc *pted)
        !           402: {
        !           403:        LIST_REMOVE(pted, pted_pv_list);
        !           404: }
        !           405:
        !           406:
        !           407: /* PTE_CHG_32 == PTE_CHG_64 */
        !           408: /* PTE_REF_32 == PTE_REF_64 */
        !           409: static __inline u_int
        !           410: pmap_pte2flags(u_int32_t pte)
        !           411: {
        !           412:        return (((pte & PTE_REF_32) ? PG_PMAP_REF : 0) |
        !           413:            ((pte & PTE_CHG_32) ? PG_PMAP_MOD : 0));
        !           414: }
        !           415:
        !           416: static __inline u_int
        !           417: pmap_flags2pte(u_int32_t flags)
        !           418: {
        !           419:        return (((flags & PG_PMAP_REF) ? PTE_REF_32 : 0) |
        !           420:            ((flags & PG_PMAP_MOD) ? PTE_CHG_32 : 0));
        !           421: }
        !           422:
        !           423: void
        !           424: pmap_attr_save(paddr_t pa, u_int32_t bits)
        !           425: {
        !           426:        struct vm_page *pg;
        !           427:
        !           428:        pg = PHYS_TO_VM_PAGE(pa);
        !           429:        if (pg == NULL)
        !           430:                return;
        !           431:
        !           432:        atomic_setbits_int(&pg->pg_flags,  pmap_pte2flags(bits));
        !           433: }
        !           434:
        !           435: int
        !           436: pmap_enter(pmap_t pm, vaddr_t va, paddr_t pa, vm_prot_t prot, int flags)
        !           437: {
        !           438:        struct pte_desc *pted;
        !           439:        struct vm_page *pg;
        !           440:        int s;
        !           441:        int need_sync = 0;
        !           442:        int cache;
        !           443:
        !           444:        /* MP - Acquire lock for this pmap */
        !           445:
        !           446:        s = splvm();
        !           447:        pted = pmap_vp_lookup(pm, va);
        !           448:        if (pted && PTED_VALID(pted)) {
        !           449:                pmap_remove_pg(pm, va);
        !           450:                /* we lost our pted if it was user */
        !           451:                if (pm != pmap_kernel())
        !           452:                        pted = pmap_vp_lookup(pm, va);
        !           453:        }
        !           454:
        !           455:        pm->pm_stats.resident_count++;
        !           456:
        !           457:        /* Do not have pted for this, get one and put it in VP */
        !           458:        if (pted == NULL) {
        !           459:                pted = pool_get(&pmap_pted_pool, PR_NOWAIT);
        !           460:                bzero(pted, sizeof (*pted));
        !           461:                pmap_vp_enter(pm, va, pted);
        !           462:        }
        !           463:
        !           464:        /* Calculate PTE */
        !           465:        pg = PHYS_TO_VM_PAGE(pa);
        !           466:        if (pg != NULL)
        !           467:                cache = PMAP_CACHE_WB; /* managed memory is cacheable */
        !           468:        else
        !           469:                cache = PMAP_CACHE_CI;
        !           470:
        !           471:        if (ppc_proc_is_64b)
        !           472:                pmap_fill_pte64(pm, va, pa, pted, prot, flags, cache);
        !           473:        else
        !           474:                pmap_fill_pte32(pm, va, pa, pted, prot, flags, cache);
        !           475:
        !           476:        if (pg != NULL) {
        !           477:                pmap_enter_pv(pted, pg); /* only managed mem */
        !           478:        }
        !           479:
        !           480:        /*
        !           481:         * Insert into HTAB
        !           482:         * We were told to map the page, probably called from vm_fault,
        !           483:         * so map the page!
        !           484:         */
        !           485:        if (ppc_proc_is_64b)
        !           486:                pte_insert64(pted);
        !           487:        else
        !           488:                pte_insert32(pted);
        !           489:
        !           490:         if (prot & VM_PROT_EXECUTE) {
        !           491:                u_int sn = VP_SR(va);
        !           492:
        !           493:                pm->pm_exec[sn]++;
        !           494:                if (pm->pm_sr[sn] & SR_NOEXEC)
        !           495:                        pm->pm_sr[sn] &= ~SR_NOEXEC;
        !           496:
        !           497:                if (pg != NULL) {
        !           498:                        need_sync = ((pg->pg_flags & PG_PMAP_EXE) == 0);
        !           499:                        atomic_setbits_int(&pg->pg_flags, PG_PMAP_EXE);
        !           500:                } else
        !           501:                        need_sync = 1;
        !           502:        } else {
        !           503:                /*
        !           504:                 * Should we be paranoid about writeable non-exec
        !           505:                 * mappings ? if so, clear the exec tag
        !           506:                 */
        !           507:                if ((prot & VM_PROT_WRITE) && (pg != NULL))
        !           508:                        atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE);
        !           509:        }
        !           510:
        !           511:        splx(s);
        !           512:
        !           513:        /* only instruction sync executable pages */
        !           514:        if (need_sync)
        !           515:                pmap_syncicache_user_virt(pm, va);
        !           516:
        !           517:        /* MP - free pmap lock */
        !           518:        return 0;
        !           519: }
        !           520:
        !           521: /*
        !           522:  * Remove the given range of mapping entries.
        !           523:  */
        !           524: void
        !           525: pmap_remove(pmap_t pm, vaddr_t va, vaddr_t endva)
        !           526: {
        !           527:        int i_sr, s_sr, e_sr;
        !           528:        int i_vp1, s_vp1, e_vp1;
        !           529:        int i_vp2, s_vp2, e_vp2;
        !           530:        struct pmapvp *vp1;
        !           531:        struct pmapvp *vp2;
        !           532:
        !           533:        /* I suspect that if this loop were unrolled better
        !           534:         * it would have better performance, testing i_sr and i_vp1
        !           535:         * in the middle loop seems excessive
        !           536:         */
        !           537:
        !           538:        s_sr = VP_SR(va);
        !           539:        e_sr = VP_SR(endva);
        !           540:        for (i_sr = s_sr; i_sr <= e_sr; i_sr++) {
        !           541:                vp1 = pm->pm_vp[i_sr];
        !           542:                if (vp1 == NULL)
        !           543:                        continue;
        !           544:
        !           545:                if (i_sr == s_sr)
        !           546:                        s_vp1 = VP_IDX1(va);
        !           547:                else
        !           548:                        s_vp1 = 0;
        !           549:
        !           550:                if (i_sr == e_sr)
        !           551:                        e_vp1 = VP_IDX1(endva);
        !           552:                else
        !           553:                        e_vp1 = VP_IDX1_SIZE-1;
        !           554:
        !           555:                for (i_vp1 = s_vp1; i_vp1 <= e_vp1; i_vp1++) {
        !           556:                        vp2 = vp1->vp[i_vp1];
        !           557:                        if (vp2 == NULL)
        !           558:                                continue;
        !           559:
        !           560:                        if ((i_sr == s_sr) && (i_vp1 == s_vp1))
        !           561:                                s_vp2 = VP_IDX2(va);
        !           562:                        else
        !           563:                                s_vp2 = 0;
        !           564:
        !           565:                        if ((i_sr == e_sr) && (i_vp1 == e_vp1))
        !           566:                                e_vp2 = VP_IDX2(endva);
        !           567:                        else
        !           568:                                e_vp2 = VP_IDX2_SIZE;
        !           569:
        !           570:                        for (i_vp2 = s_vp2; i_vp2 < e_vp2; i_vp2++) {
        !           571:                                if (vp2->vp[i_vp2] != NULL) {
        !           572:                                        pmap_remove_pg(pm,
        !           573:                                            (i_sr << VP_SR_POS) |
        !           574:                                            (i_vp1 << VP_IDX1_POS) |
        !           575:                                            (i_vp2 << VP_IDX2_POS));
        !           576:                                }
        !           577:                        }
        !           578:                }
        !           579:        }
        !           580: }
        !           581: /*
        !           582:  * remove a single mapping, notice that this code is O(1)
        !           583:  */
        !           584: void
        !           585: pmap_remove_pg(pmap_t pm, vaddr_t va)
        !           586: {
        !           587:        struct pte_desc *pted;
        !           588:        int s;
        !           589:
        !           590:        /*
        !           591:         * HASH needs to be locked here as well as pmap, and pv list.
        !           592:         * so that we know the mapping information is either valid,
        !           593:         * or that the mapping is not present in the hash table.
        !           594:         */
        !           595:        s = splvm();
        !           596:        if (pm == pmap_kernel()) {
        !           597:                pted = pmap_vp_lookup(pm, va);
        !           598:                if (pted == NULL || !PTED_VALID(pted)) {
        !           599:                        splx(s);
        !           600:                        return;
        !           601:                }
        !           602:        } else {
        !           603:                pted = pmap_vp_remove(pm, va);
        !           604:                if (pted == NULL || !PTED_VALID(pted)) {
        !           605:                        splx(s);
        !           606:                        return;
        !           607:                }
        !           608:        }
        !           609:        pm->pm_stats.resident_count--;
        !           610:
        !           611:        pmap_hash_remove(pted);
        !           612:
        !           613:        if (pted->pted_va & PTED_VA_EXEC_M) {
        !           614:                u_int sn = VP_SR(va);
        !           615:
        !           616:                pted->pted_va &= ~PTED_VA_EXEC_M;
        !           617:                pm->pm_exec[sn]--;
        !           618:                if (pm->pm_exec[sn] == 0)
        !           619:                        pm->pm_sr[sn] |= SR_NOEXEC;
        !           620:        }
        !           621:
        !           622:        if (ppc_proc_is_64b)
        !           623:                pted->p.pted_pte64.pte_hi &= ~PTE_VALID_64;
        !           624:        else
        !           625:                pted->p.pted_pte32.pte_hi &= ~PTE_VALID_32;
        !           626:
        !           627:        if (PTED_MANAGED(pted))
        !           628:                pmap_remove_pv(pted);
        !           629:
        !           630:        if (pm != pmap_kernel())
        !           631:                pool_put(&pmap_pted_pool, pted);
        !           632:
        !           633:        splx(s);
        !           634: }
        !           635:
        !           636: /*
        !           637:  * Enter a kernel mapping for the given page.
        !           638:  * kernel mappings have a larger set of prerequisites than normal mappings.
        !           639:  *
        !           640:  * 1. no memory should be allocated to create a kernel mapping.
        !           641:  * 2. a vp mapping should already exist, even if invalid. (see 1)
        !           642:  * 3. all vp tree mappings should already exist (see 1)
        !           643:  *
        !           644:  */
        !           645: void
        !           646: _pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot, int flags, int cache)
        !           647: {
        !           648:        struct pte_desc *pted;
        !           649:        int s;
        !           650:        pmap_t pm;
        !           651:
        !           652:        pm = pmap_kernel();
        !           653:
        !           654:        /* MP - lock pmap. */
        !           655:        s = splvm();
        !           656:
        !           657:        pted = pmap_vp_lookup(pm, va);
        !           658:        if (pted && PTED_VALID(pted))
        !           659:                pmap_kremove_pg(va); /* pted is reused */
        !           660:
        !           661:        pm->pm_stats.resident_count++;
        !           662:
        !           663:        /* Do not have pted for this, get one and put it in VP */
        !           664:        if (pted == NULL) {
        !           665:                /* XXX - future panic? */
        !           666:                printf("pted not preallocated in pmap_kernel() va %lx pa %lx\n",
        !           667:                    va, pa);
        !           668:                pted = pool_get(&pmap_pted_pool, PR_NOWAIT);
        !           669:                bzero(pted, sizeof (*pted));
        !           670:                pmap_vp_enter(pm, va, pted);
        !           671:        }
        !           672:
        !           673:        if (cache == PMAP_CACHE_DEFAULT) {
        !           674:                if (PHYS_TO_VM_PAGE(pa) != NULL)
        !           675:                        cache = PMAP_CACHE_WB; /* managed memory is cacheable */
        !           676:                else
        !           677:                        cache = PMAP_CACHE_CI;
        !           678:        }
        !           679:
        !           680:        /* Calculate PTE */
        !           681:        if (ppc_proc_is_64b)
        !           682:                pmap_fill_pte64(pm, va, pa, pted, prot, flags, cache);
        !           683:        else
        !           684:                pmap_fill_pte32(pm, va, pa, pted, prot, flags, cache);
        !           685:
        !           686:        /*
        !           687:         * Insert into HTAB
        !           688:         * We were told to map the page, probably called from vm_fault,
        !           689:         * so map the page!
        !           690:         */
        !           691:        if (ppc_proc_is_64b)
        !           692:                pte_insert64(pted);
        !           693:        else
        !           694:                pte_insert32(pted);
        !           695:
        !           696:        pted->pted_va |= PTED_VA_WIRED_M;
        !           697:
        !           698:         if (prot & VM_PROT_EXECUTE) {
        !           699:                u_int sn = VP_SR(va);
        !           700:
        !           701:                pm->pm_exec[sn]++;
        !           702:                if (pm->pm_sr[sn] & SR_NOEXEC)
        !           703:                        pm->pm_sr[sn] &= ~SR_NOEXEC;
        !           704:        }
        !           705:
        !           706:        splx(s);
        !           707: }
        !           708:
        !           709: void
        !           710: pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
        !           711: {
        !           712:        _pmap_kenter_pa(va, pa, prot, 0, PMAP_CACHE_DEFAULT);
        !           713: }
        !           714:
        !           715: void
        !           716: pmap_kenter_cache(vaddr_t va, paddr_t pa, vm_prot_t prot, int cacheable)
        !           717: {
        !           718:        _pmap_kenter_pa(va, pa, prot, 0, cacheable);
        !           719: }
        !           720:
        !           721:
        !           722: /*
        !           723:  * remove kernel (pmap_kernel()) mapping, one page
        !           724:  */
        !           725: void
        !           726: pmap_kremove_pg(vaddr_t va)
        !           727: {
        !           728:        struct pte_desc *pted;
        !           729:        pmap_t pm;
        !           730:        int s;
        !           731:
        !           732:        pm = pmap_kernel();
        !           733:        pted = pmap_vp_lookup(pm, va);
        !           734:        if (pted == NULL)
        !           735:                return;
        !           736:
        !           737:        if (!PTED_VALID(pted))
        !           738:                return; /* not mapped */
        !           739:
        !           740:        s = splvm();
        !           741:
        !           742:        pm->pm_stats.resident_count--;
        !           743:
        !           744:        /*
        !           745:         * HASH needs to be locked here as well as pmap, and pv list.
        !           746:         * so that we know the mapping information is either valid,
        !           747:         * or that the mapping is not present in the hash table.
        !           748:         */
        !           749:        pmap_hash_remove(pted);
        !           750:
        !           751:        if (pted->pted_va & PTED_VA_EXEC_M) {
        !           752:                u_int sn = VP_SR(va);
        !           753:
        !           754:                pted->pted_va &= ~PTED_VA_EXEC_M;
        !           755:                pm->pm_exec[sn]--;
        !           756:                if (pm->pm_exec[sn] == 0)
        !           757:                        pm->pm_sr[sn] |= SR_NOEXEC;
        !           758:        }
        !           759:
        !           760:        if (PTED_MANAGED(pted))
        !           761:                pmap_remove_pv(pted);
        !           762:
        !           763:        /* invalidate pted; */
        !           764:        if (ppc_proc_is_64b)
        !           765:                pted->p.pted_pte64.pte_hi &= ~PTE_VALID_64;
        !           766:        else
        !           767:                pted->p.pted_pte32.pte_hi &= ~PTE_VALID_32;
        !           768:
        !           769:        splx(s);
        !           770:
        !           771: }
        !           772: /*
        !           773:  * remove kernel (pmap_kernel()) mappings
        !           774:  */
        !           775: void
        !           776: pmap_kremove(vaddr_t va, vsize_t len)
        !           777: {
        !           778:        for (len >>= PAGE_SHIFT; len >0; len--, va += PAGE_SIZE)
        !           779:                pmap_kremove_pg(va);
        !           780: }
        !           781:
        !           782: void
        !           783: pte_zap(void *ptp, struct pte_desc *pted)
        !           784: {
        !           785:
        !           786:        struct pte_64 *ptp64 = (void*) ptp;
        !           787:        struct pte_32 *ptp32 = (void*) ptp;
        !           788:
        !           789:        if (ppc_proc_is_64b)
        !           790:                ptp64->pte_hi &= ~PTE_VALID_64;
        !           791:        else
        !           792:                ptp32->pte_hi &= ~PTE_VALID_32;
        !           793:
        !           794:        __asm volatile ("sync");
        !           795:        tlbie(pted->pted_va);
        !           796:        __asm volatile ("sync");
        !           797:        tlbsync();
        !           798:        __asm volatile ("sync");
        !           799:        if (ppc_proc_is_64b) {
        !           800:                if (PTED_MANAGED(pted))
        !           801:                        pmap_attr_save(pted->p.pted_pte64.pte_lo & PTE_RPGN_64,
        !           802:                            ptp64->pte_lo & (PTE_REF_64|PTE_CHG_64));
        !           803:        } else {
        !           804:                if (PTED_MANAGED(pted))
        !           805:                        pmap_attr_save(pted->p.pted_pte32.pte_lo & PTE_RPGN_32,
        !           806:                            ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32));
        !           807:        }
        !           808: }
        !           809:
        !           810: /*
        !           811:  * remove specified entry from hash table.
        !           812:  * all information is present in pted to look up entry
        !           813:  * LOCKS... should the caller lock?
        !           814:  */
        !           815: void
        !           816: pmap_hash_remove(struct pte_desc *pted)
        !           817: {
        !           818:        vaddr_t va = pted->pted_va;
        !           819:        pmap_t pm = pted->pted_pmap;
        !           820:        struct pte_64 *ptp64;
        !           821:        struct pte_32 *ptp32;
        !           822:        int sr, idx;
        !           823:
        !           824:        sr = ptesr(pm->pm_sr, va);
        !           825:        idx = pteidx(sr, va);
        !           826:
        !           827:        idx =  (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0));
        !           828:        /* determine which pteg mapping is present in */
        !           829:
        !           830:        if (ppc_proc_is_64b) {
        !           831:                ptp64 = pmap_ptable64 + (idx * 8);
        !           832:                ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !           833:                /*
        !           834:                 * We now have the pointer to where it will be, if it is
        !           835:                 * currently mapped. If the mapping was thrown away in
        !           836:                 * exchange for another page mapping, then this page is not
        !           837:                 * currently in the HASH.
        !           838:                 */
        !           839:                if ((pted->p.pted_pte64.pte_hi |
        !           840:                    (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi) {
        !           841:                        pte_zap((void*)ptp64, pted);
        !           842:                }
        !           843:        } else {
        !           844:                ptp32 = pmap_ptable32 + (idx * 8);
        !           845:                ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !           846:                /*
        !           847:                 * We now have the pointer to where it will be, if it is
        !           848:                 * currently mapped. If the mapping was thrown away in
        !           849:                 * exchange for another page mapping, then this page is not
        !           850:                 * currently in the HASH.
        !           851:                 */
        !           852:                if ((pted->p.pted_pte32.pte_hi |
        !           853:                    (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi) {
        !           854:                        pte_zap((void*)ptp32, pted);
        !           855:                }
        !           856:        }
        !           857: }
        !           858:
        !           859: /*
        !           860:  * What about execution control? Even at only a segment granularity.
        !           861:  */
        !           862: void
        !           863: pmap_fill_pte64(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted,
        !           864:        vm_prot_t prot, int flags, int cache)
        !           865: {
        !           866:        sr_t sr;
        !           867:        struct pte_64 *pte64;
        !           868:
        !           869:        sr = ptesr(pm->pm_sr, va);
        !           870:        pte64 = &pted->p.pted_pte64;
        !           871:
        !           872:        pte64->pte_hi = (((u_int64_t)sr & SR_VSID) <<
        !           873:           PTE_VSID_SHIFT_64) |
        !           874:            ((va >> ADDR_API_SHIFT_64) & PTE_API_64) | PTE_VALID_64;
        !           875:        pte64->pte_lo = (pa & PTE_RPGN_64);
        !           876:
        !           877:
        !           878:        if ((cache == PMAP_CACHE_WB))
        !           879:                pte64->pte_lo |= PTE_M_64;
        !           880:        else if ((cache == PMAP_CACHE_WT))
        !           881:                pte64->pte_lo |= (PTE_W_64 | PTE_M_64);
        !           882:        else
        !           883:                pte64->pte_lo |= (PTE_M_64 | PTE_I_64 | PTE_G_64);
        !           884:
        !           885:        if (prot & VM_PROT_WRITE)
        !           886:                pte64->pte_lo |= PTE_RW_64;
        !           887:        else
        !           888:                pte64->pte_lo |= PTE_RO_64;
        !           889:
        !           890:        pted->pted_va = va & ~PAGE_MASK;
        !           891:
        !           892:        if (prot & VM_PROT_EXECUTE)
        !           893:                pted->pted_va  |= PTED_VA_EXEC_M;
        !           894:        else
        !           895:                pte64->pte_lo |= PTE_N_64;
        !           896:
        !           897:        pted->pted_pmap = pm;
        !           898: }
        !           899: /*
        !           900:  * What about execution control? Even at only a segment granularity.
        !           901:  */
        !           902: void
        !           903: pmap_fill_pte32(pmap_t pm, vaddr_t va, paddr_t pa, struct pte_desc *pted,
        !           904:        vm_prot_t prot, int flags, int cache)
        !           905: {
        !           906:        sr_t sr;
        !           907:        struct pte_32 *pte32;
        !           908:
        !           909:        sr = ptesr(pm->pm_sr, va);
        !           910:        pte32 = &pted->p.pted_pte32;
        !           911:
        !           912:        pte32->pte_hi = ((sr & SR_VSID) << PTE_VSID_SHIFT_32) |
        !           913:            ((va >> ADDR_API_SHIFT_32) & PTE_API_32) | PTE_VALID_32;
        !           914:        pte32->pte_lo = (pa & PTE_RPGN_32);
        !           915:
        !           916:        if ((cache == PMAP_CACHE_WB))
        !           917:                pte32->pte_lo |= PTE_M_32;
        !           918:        else if ((cache == PMAP_CACHE_WT))
        !           919:                pte32->pte_lo |= (PTE_W_32 | PTE_M_32);
        !           920:        else
        !           921:                pte32->pte_lo |= (PTE_M_32 | PTE_I_32 | PTE_G_32);
        !           922:
        !           923:        if (prot & VM_PROT_WRITE)
        !           924:                pte32->pte_lo |= PTE_RW_32;
        !           925:        else
        !           926:                pte32->pte_lo |= PTE_RO_32;
        !           927:
        !           928:        pted->pted_va = va & ~PAGE_MASK;
        !           929:
        !           930:        /* XXX Per-page execution control. */
        !           931:        if (prot & VM_PROT_EXECUTE)
        !           932:                pted->pted_va  |= PTED_VA_EXEC_M;
        !           933:
        !           934:        pted->pted_pmap = pm;
        !           935: }
        !           936:
        !           937: /*
        !           938:  * read/clear bits from pte/attr cache, for reference/change
        !           939:  * ack, copied code in the pte flush code....
        !           940:  */
        !           941: int
        !           942: pteclrbits(struct vm_page *pg, u_int flagbit, u_int clear)
        !           943: {
        !           944:        u_int bits;
        !           945:        int s;
        !           946:        struct pte_desc *pted;
        !           947:        u_int ptebit = pmap_flags2pte(flagbit);
        !           948:
        !           949:        /* PTE_CHG_32 == PTE_CHG_64 */
        !           950:        /* PTE_REF_32 == PTE_REF_64 */
        !           951:
        !           952:        /*
        !           953:         *  First try the attribute cache
        !           954:         */
        !           955:        bits = pg->pg_flags & flagbit;
        !           956:        if ((bits == flagbit) && (clear == 0))
        !           957:                return bits;
        !           958:
        !           959:        /* cache did not contain all necessary bits,
        !           960:         * need to walk thru pv table to collect all mappings for this
        !           961:         * page, copying bits to the attribute cache
        !           962:         * then reread the attribute cache.
        !           963:         */
        !           964:        /* need lock for this pv */
        !           965:        s = splvm();
        !           966:
        !           967:        LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
        !           968:                vaddr_t va = pted->pted_va & PAGE_MASK;
        !           969:                pmap_t pm = pted->pted_pmap;
        !           970:                struct pte_64 *ptp64;
        !           971:                struct pte_32 *ptp32;
        !           972:                int sr, idx;
        !           973:
        !           974:                sr = ptesr(pm->pm_sr, va);
        !           975:                idx = pteidx(sr, va);
        !           976:
        !           977:                /* determine which pteg mapping is present in */
        !           978:                if (ppc_proc_is_64b) {
        !           979:                        ptp64 = pmap_ptable64 +
        !           980:                                (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !           981:                        ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !           982:
        !           983:                        /*
        !           984:                         * We now have the pointer to where it will be, if it is
        !           985:                         * currently mapped. If the mapping was thrown away in
        !           986:                         * exchange for another page mapping, then this page is
        !           987:                         * not currently in the HASH.
        !           988:                         *
        !           989:                         * if we are not clearing bits, and have found all of the
        !           990:                         * bits we want, we can stop
        !           991:                         */
        !           992:                        if ((pted->p.pted_pte64.pte_hi |
        !           993:                            (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi) {
        !           994:                                bits |= pmap_pte2flags(ptp64->pte_lo & ptebit);
        !           995:                                if (clear) {
        !           996:                                        ptp64->pte_hi &= ~PTE_VALID_64;
        !           997:                                        __asm__ volatile ("sync");
        !           998:                                        tlbie(va);
        !           999:                                        tlbsync();
        !          1000:                                        ptp64->pte_lo &= ~ptebit;
        !          1001:                                        __asm__ volatile ("sync");
        !          1002:                                        ptp64->pte_hi |= PTE_VALID_64;
        !          1003:                                } else if (bits == flagbit)
        !          1004:                                        break;
        !          1005:                        }
        !          1006:                } else {
        !          1007:                        ptp32 = pmap_ptable32 +
        !          1008:                                (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !          1009:                        ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          1010:
        !          1011:                        /*
        !          1012:                         * We now have the pointer to where it will be, if it is
        !          1013:                         * currently mapped. If the mapping was thrown away in
        !          1014:                         * exchange for another page mapping, then this page is
        !          1015:                         * not currently in the HASH.
        !          1016:                         *
        !          1017:                         * if we are not clearing bits, and have found all of the
        !          1018:                         * bits we want, we can stop
        !          1019:                         */
        !          1020:                        if ((pted->p.pted_pte32.pte_hi |
        !          1021:                            (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi) {
        !          1022:                                bits |= pmap_pte2flags(ptp32->pte_lo & ptebit);
        !          1023:                                if (clear) {
        !          1024:                                        ptp32->pte_hi &= ~PTE_VALID_32;
        !          1025:                                        __asm__ volatile ("sync");
        !          1026:                                        tlbie(va);
        !          1027:                                        tlbsync();
        !          1028:                                        ptp32->pte_lo &= ~ptebit;
        !          1029:                                        __asm__ volatile ("sync");
        !          1030:                                        ptp32->pte_hi |= PTE_VALID_32;
        !          1031:                                } else if (bits == flagbit)
        !          1032:                                        break;
        !          1033:                        }
        !          1034:                }
        !          1035:        }
        !          1036:
        !          1037:        if (clear) {
        !          1038:                /*
        !          1039:                 * this is done a second time, because while walking the list
        !          1040:                 * a bit could have been promoted via pmap_attr_save()
        !          1041:                 */
        !          1042:                bits |= pg->pg_flags & flagbit;
        !          1043:                atomic_clearbits_int(&pg->pg_flags,  flagbit);
        !          1044:        } else
        !          1045:                atomic_setbits_int(&pg->pg_flags,  bits);
        !          1046:
        !          1047:        splx(s);
        !          1048:        return bits;
        !          1049: }
        !          1050:
        !          1051: /*
        !          1052:  * Garbage collects the physical map system for pages which are
        !          1053:  * no longer used. Success need not be guaranteed -- that is, there
        !          1054:  * may well be pages which are not referenced, but others may be collected
        !          1055:  * Called by the pageout daemon when pages are scarce.
        !          1056:  */
        !          1057: void
        !          1058: pmap_collect(pmap_t pm)
        !          1059: {
        !          1060:        /* This could return unused v->p table layers which
        !          1061:         * are empty.
        !          1062:         * could malicious programs allocate memory and eat
        !          1063:         * these wired pages? These are allocated via pool.
        !          1064:         * Are there pool functions which could be called
        !          1065:         * to lower the pool usage here?
        !          1066:         */
        !          1067: }
        !          1068:
        !          1069: /*
        !          1070:  * Fill the given physical page with zeros.
        !          1071:  */
        !          1072: void
        !          1073: pmap_zero_page(struct vm_page *pg)
        !          1074: {
        !          1075:        paddr_t pa = VM_PAGE_TO_PHYS(pg);
        !          1076: #ifdef USE_DCBZ
        !          1077:        int i;
        !          1078:        paddr_t addr = zero_page;
        !          1079: #endif
        !          1080:
        !          1081:        /* simple_lock(&pmap_zero_page_lock); */
        !          1082:        pmap_kenter_pa(zero_page, pa, VM_PROT_READ|VM_PROT_WRITE);
        !          1083: #ifdef USE_DCBZ
        !          1084:        for (i = PAGE_SIZE/CACHELINESIZE; i>0; i--) {
        !          1085:                __asm volatile ("dcbz 0,%0" :: "r"(addr));
        !          1086:                addr += CACHELINESIZE;
        !          1087:        }
        !          1088: #else
        !          1089:        bzero((void *)zero_page, PAGE_SIZE);
        !          1090: #endif
        !          1091:        pmap_kremove_pg(zero_page);
        !          1092:
        !          1093:        /* simple_unlock(&pmap_zero_page_lock); */
        !          1094: }
        !          1095:
        !          1096: /*
        !          1097:  * copy the given physical page with zeros.
        !          1098:  */
        !          1099: void
        !          1100: pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
        !          1101: {
        !          1102:        paddr_t srcpa = VM_PAGE_TO_PHYS(srcpg);
        !          1103:        paddr_t dstpa = VM_PAGE_TO_PHYS(dstpg);
        !          1104:        /* simple_lock(&pmap_copy_page_lock); */
        !          1105:
        !          1106:        pmap_kenter_pa(copy_src_page, srcpa, VM_PROT_READ);
        !          1107:        pmap_kenter_pa(copy_dst_page, dstpa, VM_PROT_READ|VM_PROT_WRITE);
        !          1108:
        !          1109:        bcopy((void *)copy_src_page, (void *)copy_dst_page, PAGE_SIZE);
        !          1110:
        !          1111:        pmap_kremove_pg(copy_src_page);
        !          1112:        pmap_kremove_pg(copy_dst_page);
        !          1113:        /* simple_unlock(&pmap_copy_page_lock); */
        !          1114: }
        !          1115:
        !          1116: int pmap_id_avail = 0;
        !          1117:
        !          1118: void
        !          1119: pmap_pinit(pmap_t pm)
        !          1120: {
        !          1121:        int i, k, try, tblidx, tbloff;
        !          1122:        int s, seg;
        !          1123:
        !          1124:        bzero(pm, sizeof (struct pmap));
        !          1125:
        !          1126:        pmap_reference(pm);
        !          1127:
        !          1128:        /*
        !          1129:         * Allocate segment registers for this pmap.
        !          1130:         * Try not to reuse pmap ids, to spread the hash table usage.
        !          1131:         */
        !          1132: again:
        !          1133:        for (i = 0; i < NPMAPS; i++) {
        !          1134:                try = pmap_id_avail + i;
        !          1135:                try = try % NPMAPS; /* truncate back into bounds */
        !          1136:                tblidx = try / (8 * sizeof usedsr[0]);
        !          1137:                tbloff = try % (8 * sizeof usedsr[0]);
        !          1138:                if ((usedsr[tblidx] & (1 << tbloff)) == 0) {
        !          1139:                        /* pmap create lock? */
        !          1140:                        s = splvm();
        !          1141:                        if ((usedsr[tblidx] & (1 << tbloff)) == 1) {
        !          1142:                                /* entry was stolen out from under us, retry */
        !          1143:                                splx(s); /* pmap create unlock */
        !          1144:                                goto again;
        !          1145:                        }
        !          1146:                        usedsr[tblidx] |= (1 << tbloff);
        !          1147:                        pmap_id_avail = try + 1;
        !          1148:                        splx(s); /* pmap create unlock */
        !          1149:
        !          1150:                        seg = try << 4;
        !          1151:                        for (k = 0; k < 16; k++)
        !          1152:                                pm->pm_sr[k] = (seg + k) | SR_NOEXEC;
        !          1153:                        return;
        !          1154:                }
        !          1155:        }
        !          1156:        panic("out of pmap slots");
        !          1157: }
        !          1158:
        !          1159: /*
        !          1160:  * Create and return a physical map.
        !          1161:  */
        !          1162: pmap_t
        !          1163: pmap_create()
        !          1164: {
        !          1165:        pmap_t pmap;
        !          1166:        int s;
        !          1167:
        !          1168:        s = splvm();
        !          1169:        pmap = pool_get(&pmap_pmap_pool, PR_WAITOK);
        !          1170:        splx(s);
        !          1171:        pmap_pinit(pmap);
        !          1172:        return (pmap);
        !          1173: }
        !          1174:
        !          1175: /*
        !          1176:  * Add a reference to a given pmap.
        !          1177:  */
        !          1178: void
        !          1179: pmap_reference(pmap_t pm)
        !          1180: {
        !          1181:        /* simple_lock(&pmap->pm_obj.vmobjlock); */
        !          1182:        pm->pm_refs++;
        !          1183:        /* simple_unlock(&pmap->pm_obj.vmobjlock); */
        !          1184: }
        !          1185:
        !          1186: /*
        !          1187:  * Retire the given pmap from service.
        !          1188:  * Should only be called if the map contains no valid mappings.
        !          1189:  */
        !          1190: void
        !          1191: pmap_destroy(pmap_t pm)
        !          1192: {
        !          1193:        int refs;
        !          1194:        int s;
        !          1195:
        !          1196:        /* simple_lock(&pmap->pm_obj.vmobjlock); */
        !          1197:        refs = --pm->pm_refs;
        !          1198:        /* simple_unlock(&pmap->pm_obj.vmobjlock); */
        !          1199:        if (refs > 0)
        !          1200:                return;
        !          1201:
        !          1202:        /*
        !          1203:         * reference count is zero, free pmap resources and free pmap.
        !          1204:         */
        !          1205:        pmap_release(pm);
        !          1206:        s = splvm();
        !          1207:        pool_put(&pmap_pmap_pool, pm);
        !          1208:        splx(s);
        !          1209: }
        !          1210:
        !          1211: /*
        !          1212:  * Release any resources held by the given physical map.
        !          1213:  * Called when a pmap initialized by pmap_pinit is being released.
        !          1214:  */
        !          1215: void
        !          1216: pmap_release(pmap_t pm)
        !          1217: {
        !          1218:        int i, tblidx, tbloff;
        !          1219:        int s;
        !          1220:
        !          1221:        pmap_vp_destroy(pm);
        !          1222:        i = (pm->pm_sr[0] & SR_VSID) >> 4;
        !          1223:        tblidx = i / (8  * sizeof usedsr[0]);
        !          1224:        tbloff = i % (8  * sizeof usedsr[0]);
        !          1225:
        !          1226:        /* LOCK? */
        !          1227:        s = splvm();
        !          1228:        usedsr[tblidx] &= ~(1 << tbloff);
        !          1229:        splx(s);
        !          1230: }
        !          1231:
        !          1232: void
        !          1233: pmap_vp_destroy(pmap_t pm)
        !          1234: {
        !          1235:        int i, j;
        !          1236:        int s;
        !          1237:        struct pmapvp *vp1;
        !          1238:        struct pmapvp *vp2;
        !          1239:
        !          1240:        for (i = 0; i < VP_SR_SIZE; i++) {
        !          1241:                vp1 = pm->pm_vp[i];
        !          1242:                if (vp1 == NULL)
        !          1243:                        continue;
        !          1244:
        !          1245:                for (j = 0; j < VP_IDX1_SIZE; j++) {
        !          1246:                        vp2 = vp1->vp[j];
        !          1247:                        if (vp2 == NULL)
        !          1248:                                continue;
        !          1249:
        !          1250:                        s = splvm();
        !          1251:                        pool_put(&pmap_vp_pool, vp2);
        !          1252:                        splx(s);
        !          1253:                }
        !          1254:                pm->pm_vp[i] = NULL;
        !          1255:                s = splvm();
        !          1256:                pool_put(&pmap_vp_pool, vp1);
        !          1257:                splx(s);
        !          1258:        }
        !          1259: }
        !          1260:
        !          1261: void
        !          1262: pmap_avail_setup(void)
        !          1263: {
        !          1264:        struct mem_region *mp;
        !          1265:
        !          1266:        (fw->mem_regions) (&pmap_mem, &pmap_avail);
        !          1267:        pmap_cnt_avail = 0;
        !          1268:        physmem = 0;
        !          1269:
        !          1270:        ndumpmem = 0;
        !          1271:        for (mp = pmap_mem; mp->size !=0; mp++, ndumpmem++) {
        !          1272:                physmem += btoc(mp->size);
        !          1273:                dumpmem[ndumpmem].start = atop(mp->start);
        !          1274:                dumpmem[ndumpmem].end = atop(mp->start + mp->size);
        !          1275:        }
        !          1276:
        !          1277:        for (mp = pmap_avail; mp->size !=0 ; mp++) {
        !          1278:                if (physmaxaddr <  mp->start + mp->size)
        !          1279:                        physmaxaddr = mp->start + mp->size;
        !          1280:        }
        !          1281:
        !          1282:        for (mp = pmap_avail; mp->size !=0; mp++)
        !          1283:                pmap_cnt_avail += 1;
        !          1284: }
        !          1285:
        !          1286: void
        !          1287: pmap_avail_fixup(void)
        !          1288: {
        !          1289:        struct mem_region *mp;
        !          1290:        u_int32_t align;
        !          1291:        u_int32_t end;
        !          1292:
        !          1293:        mp = pmap_avail;
        !          1294:        while(mp->size !=0) {
        !          1295:                align = round_page(mp->start);
        !          1296:                if (mp->start != align) {
        !          1297:                        pmap_remove_avail(mp->start, align);
        !          1298:                        mp = pmap_avail;
        !          1299:                        continue;
        !          1300:                }
        !          1301:                end = mp->start+mp->size;
        !          1302:                align = trunc_page(end);
        !          1303:                if (end != align) {
        !          1304:                        pmap_remove_avail(align, end);
        !          1305:                        mp = pmap_avail;
        !          1306:                        continue;
        !          1307:                }
        !          1308:                mp++;
        !          1309:        }
        !          1310: }
        !          1311:
        !          1312: /* remove a given region from avail memory */
        !          1313: void
        !          1314: pmap_remove_avail(paddr_t base, paddr_t end)
        !          1315: {
        !          1316:        struct mem_region *mp;
        !          1317:        int i;
        !          1318:        int mpend;
        !          1319:
        !          1320:        /* remove given region from available */
        !          1321:        for (mp = pmap_avail; mp->size; mp++) {
        !          1322:                /*
        !          1323:                 * Check if this region holds all of the region
        !          1324:                 */
        !          1325:                mpend = mp->start + mp->size;
        !          1326:                if (base > mpend) {
        !          1327:                        continue;
        !          1328:                }
        !          1329:                if (base <= mp->start) {
        !          1330:                        if (end <= mp->start)
        !          1331:                                break; /* region not present -??? */
        !          1332:
        !          1333:                        if (end >= mpend) {
        !          1334:                                /* covers whole region */
        !          1335:                                /* shorten */
        !          1336:                                for (i = mp - pmap_avail;
        !          1337:                                    i < pmap_cnt_avail;
        !          1338:                                    i++) {
        !          1339:                                        pmap_avail[i] = pmap_avail[i+1];
        !          1340:                                }
        !          1341:                                pmap_cnt_avail--;
        !          1342:                                pmap_avail[pmap_cnt_avail].size = 0;
        !          1343:                        } else {
        !          1344:                                mp->start = end;
        !          1345:                                mp->size = mpend - end;
        !          1346:                        }
        !          1347:                } else {
        !          1348:                        /* start after the beginning */
        !          1349:                        if (end >= mpend) {
        !          1350:                                /* just truncate */
        !          1351:                                mp->size = base - mp->start;
        !          1352:                        } else {
        !          1353:                                /* split */
        !          1354:                                for (i = pmap_cnt_avail;
        !          1355:                                    i > (mp - pmap_avail);
        !          1356:                                    i--) {
        !          1357:                                        pmap_avail[i] = pmap_avail[i - 1];
        !          1358:                                }
        !          1359:                                pmap_cnt_avail++;
        !          1360:                                mp->size = base - mp->start;
        !          1361:                                mp++;
        !          1362:                                mp->start = end;
        !          1363:                                mp->size = mpend - end;
        !          1364:                        }
        !          1365:                }
        !          1366:        }
        !          1367:        for (mp = pmap_allocated; mp->size != 0; mp++) {
        !          1368:                if (base < mp->start) {
        !          1369:                        if (end == mp->start) {
        !          1370:                                mp->start = base;
        !          1371:                                mp->size += end - base;
        !          1372:                                break;
        !          1373:                        }
        !          1374:                        /* lengthen */
        !          1375:                        for (i = pmap_cnt_allocated; i > (mp - pmap_allocated);
        !          1376:                            i--) {
        !          1377:                                pmap_allocated[i] = pmap_allocated[i - 1];
        !          1378:                        }
        !          1379:                        pmap_cnt_allocated++;
        !          1380:                        mp->start = base;
        !          1381:                        mp->size = end - base;
        !          1382:                        return;
        !          1383:                }
        !          1384:                if (base == (mp->start + mp->size)) {
        !          1385:                        mp->size += end - base;
        !          1386:                        return;
        !          1387:                }
        !          1388:        }
        !          1389:        if (mp->size == 0) {
        !          1390:                mp->start = base;
        !          1391:                mp->size  = end - base;
        !          1392:                pmap_cnt_allocated++;
        !          1393:        }
        !          1394: }
        !          1395:
        !          1396: void *
        !          1397: pmap_steal_avail(size_t size, int align)
        !          1398: {
        !          1399:        struct mem_region *mp;
        !          1400:        int start;
        !          1401:        int remsize;
        !          1402:
        !          1403:        for (mp = pmap_avail; mp->size; mp++) {
        !          1404:                if (mp->size > size) {
        !          1405:                        start = (mp->start + (align -1)) & ~(align -1);
        !          1406:                        remsize = mp->size - (start - mp->start);
        !          1407:                        if (remsize >= 0) {
        !          1408:                                pmap_remove_avail(start, start+size);
        !          1409:                                return (void *)start;
        !          1410:                        }
        !          1411:                }
        !          1412:        }
        !          1413:        panic ("unable to allocate region with size %x align %x",
        !          1414:            size, align);
        !          1415: }
        !          1416:
        !          1417: /*
        !          1418:  * Similar to pmap_steal_avail, but operating on vm_physmem since
        !          1419:  * uvm_page_physload() has been called.
        !          1420:  */
        !          1421: vaddr_t
        !          1422: pmap_steal_memory(vsize_t size, vaddr_t *start, vaddr_t *end)
        !          1423: {
        !          1424:        int segno;
        !          1425:        u_int npg;
        !          1426:        vaddr_t va;
        !          1427:        paddr_t pa;
        !          1428:        struct vm_physseg *seg;
        !          1429:
        !          1430:        size = round_page(size);
        !          1431:        npg = atop(size);
        !          1432:
        !          1433:        for (segno = 0, seg = vm_physmem; segno < vm_nphysseg; segno++, seg++) {
        !          1434:                if (seg->avail_end - seg->avail_start < npg)
        !          1435:                        continue;
        !          1436:                /*
        !          1437:                 * We can only steal at an ``unused'' segment boundary,
        !          1438:                 * i.e. either at the start or at the end.
        !          1439:                 */
        !          1440:                if (seg->avail_start == seg->start ||
        !          1441:                    seg->avail_end == seg->end)
        !          1442:                        break;
        !          1443:        }
        !          1444:        if (segno == vm_nphysseg)
        !          1445:                va = 0;
        !          1446:        else {
        !          1447:                if (seg->avail_start == seg->start) {
        !          1448:                        pa = ptoa(seg->avail_start);
        !          1449:                        seg->avail_start += npg;
        !          1450:                        seg->start += npg;
        !          1451:                } else {
        !          1452:                        pa = ptoa(seg->avail_end) - size;
        !          1453:                        seg->avail_end -= npg;
        !          1454:                        seg->end -= npg;
        !          1455:                }
        !          1456:                /*
        !          1457:                 * If all the segment has been consumed now, remove it.
        !          1458:                 * Note that the crash dump code still knows about it
        !          1459:                 * and will dump it correctly.
        !          1460:                 */
        !          1461:                if (seg->start == seg->end) {
        !          1462:                        if (vm_nphysseg-- == 1)
        !          1463:                                panic("pmap_steal_memory: out of memory");
        !          1464:                        while (segno < vm_nphysseg) {
        !          1465:                                seg[0] = seg[1]; /* struct copy */
        !          1466:                                seg++;
        !          1467:                                segno++;
        !          1468:                        }
        !          1469:                }
        !          1470:
        !          1471:                va = (vaddr_t)pa;       /* 1:1 mapping */
        !          1472:                bzero((void *)va, size);
        !          1473:        }
        !          1474:
        !          1475:        if (start != NULL)
        !          1476:                *start = VM_MIN_KERNEL_ADDRESS;
        !          1477:        if (end != NULL)
        !          1478:                *end = VM_MAX_KERNEL_ADDRESS;
        !          1479:
        !          1480:        return (va);
        !          1481: }
        !          1482:
        !          1483: void *msgbuf_addr;
        !          1484:
        !          1485: /*
        !          1486:  * Initialize pmap setup.
        !          1487:  * ALL of the code which deals with avail needs rewritten as an actual
        !          1488:  * memory allocation.
        !          1489:  */
        !          1490: void
        !          1491: pmap_bootstrap(u_int kernelstart, u_int kernelend)
        !          1492: {
        !          1493:        struct mem_region *mp;
        !          1494:        int i, k;
        !          1495:        struct pmapvp *vp1;
        !          1496:        struct pmapvp *vp2;
        !          1497:
        !          1498:        ppc_check_procid();
        !          1499:
        !          1500:        /*
        !          1501:         * Get memory.
        !          1502:         */
        !          1503:        pmap_avail_setup();
        !          1504:
        !          1505:        /*
        !          1506:         * Page align all regions.
        !          1507:         * Non-page memory isn't very interesting to us.
        !          1508:         * Also, sort the entries for ascending addresses.
        !          1509:         */
        !          1510:        kernelstart = trunc_page(kernelstart);
        !          1511:        kernelend = round_page(kernelend);
        !          1512:        pmap_remove_avail(kernelstart, kernelend);
        !          1513:
        !          1514:        msgbuf_addr = pmap_steal_avail(MSGBUFSIZE,4);
        !          1515:
        !          1516:        for (mp = pmap_avail; mp->size; mp++) {
        !          1517:                bzero((void *)mp->start, mp->size);
        !          1518:        }
        !          1519:
        !          1520: #define HTABENTS_32 1024
        !          1521: #define HTABENTS_64 2048
        !          1522:
        !          1523:        if (ppc_proc_is_64b) {
        !          1524:                pmap_ptab_cnt = HTABENTS_64;
        !          1525:                while (pmap_ptab_cnt * 2 < physmem)
        !          1526:                        pmap_ptab_cnt <<= 1;
        !          1527:        } else {
        !          1528:                pmap_ptab_cnt = HTABENTS_32;
        !          1529:                while (HTABSIZE_32 < (ctob(physmem) >> 7))
        !          1530:                        pmap_ptab_cnt <<= 1;
        !          1531:        }
        !          1532:        /*
        !          1533:         * allocate suitably aligned memory for HTAB
        !          1534:         */
        !          1535:        if (ppc_proc_is_64b) {
        !          1536:                pmap_ptable64 = pmap_steal_avail(HTABMEMSZ_64, HTABMEMSZ_64);
        !          1537:                bzero((void *)pmap_ptable64, HTABMEMSZ_64);
        !          1538:                pmap_ptab_mask = pmap_ptab_cnt - 1;
        !          1539:        } else {
        !          1540:                pmap_ptable32 = pmap_steal_avail(HTABSIZE_32, HTABSIZE_32);
        !          1541:                bzero((void *)pmap_ptable32, HTABSIZE_32);
        !          1542:                pmap_ptab_mask = pmap_ptab_cnt - 1;
        !          1543:        }
        !          1544:
        !          1545:        /* allocate v->p mappings for pmap_kernel() */
        !          1546:        for (i = 0; i < VP_SR_SIZE; i++) {
        !          1547:                pmap_kernel()->pm_vp[i] = NULL;
        !          1548:        }
        !          1549:        vp1 = pmap_steal_avail(sizeof (struct pmapvp), 4);
        !          1550:        bzero (vp1, sizeof(struct pmapvp));
        !          1551:        pmap_kernel()->pm_vp[PPC_KERNEL_SR] = vp1;
        !          1552:        for (i = 0; i < VP_IDX1_SIZE; i++) {
        !          1553:                vp2 = vp1->vp[i] = pmap_steal_avail(sizeof (struct pmapvp), 4);
        !          1554:                bzero (vp2, sizeof(struct pmapvp));
        !          1555:                for (k = 0; k < VP_IDX2_SIZE; k++) {
        !          1556:                        struct pte_desc *pted;
        !          1557:                        pted = pmap_steal_avail(sizeof (struct pte_desc), 4);
        !          1558:                        bzero (pted, sizeof (struct pte_desc));
        !          1559:                        vp2->vp[k] = pted;
        !          1560:                }
        !          1561:        }
        !          1562:
        !          1563:        if (ppc_proc_is_64b) {
        !          1564:                vp1 = pmap_steal_avail(sizeof (struct pmapvp), 4);
        !          1565:                bzero (vp1, sizeof(struct pmapvp));
        !          1566:                pmap_kernel()->pm_vp[0] = vp1;
        !          1567:                for (i = 0; i < VP_IDX1_SIZE; i++) {
        !          1568:                        vp2 = vp1->vp[i] =
        !          1569:                            pmap_steal_avail(sizeof (struct pmapvp), 4);
        !          1570:                        bzero (vp2, sizeof(struct pmapvp));
        !          1571:                        for (k = 0; k < VP_IDX2_SIZE; k++) {
        !          1572:                                struct pte_desc *pted;
        !          1573:                                pted = pmap_steal_avail(sizeof (struct pte_desc), 4);
        !          1574:                                bzero (pted, sizeof (struct pte_desc));
        !          1575:                                vp2->vp[k] = pted;
        !          1576:                        }
        !          1577:                }
        !          1578:        }
        !          1579:
        !          1580:        zero_page = VM_MIN_KERNEL_ADDRESS + ppc_kvm_stolen;
        !          1581:        ppc_kvm_stolen += PAGE_SIZE;
        !          1582:        copy_src_page = VM_MIN_KERNEL_ADDRESS + ppc_kvm_stolen;
        !          1583:        ppc_kvm_stolen += PAGE_SIZE;
        !          1584:        copy_dst_page = VM_MIN_KERNEL_ADDRESS + ppc_kvm_stolen;
        !          1585:        ppc_kvm_stolen += PAGE_SIZE;
        !          1586:        ppc_kvm_stolen += reserve_dumppages( (caddr_t)(VM_MIN_KERNEL_ADDRESS +
        !          1587:            ppc_kvm_stolen));
        !          1588:
        !          1589:
        !          1590:        /*
        !          1591:         * Initialize kernel pmap and hardware.
        !          1592:         */
        !          1593: #if NPMAPS >= PPC_KERNEL_SEGMENT / 16
        !          1594:        usedsr[PPC_KERNEL_SEGMENT / 16 / (sizeof usedsr[0] * 8)]
        !          1595:                |= 1 << ((PPC_KERNEL_SEGMENT / 16) % (sizeof usedsr[0] * 8));
        !          1596: #endif
        !          1597:        for (i = 0; i < 16; i++) {
        !          1598:                pmap_kernel()->pm_sr[i] = (PPC_KERNEL_SEG0 + i) | SR_NOEXEC;
        !          1599:                ppc_mtsrin(PPC_KERNEL_SEG0 + i, i << ADDR_SR_SHIFT);
        !          1600:        }
        !          1601:
        !          1602:        if (ppc_proc_is_64b) {
        !          1603:                for(i = 0; i < 0x10000; i++)
        !          1604:                        pmap_kenter_cache(ctob(i), ctob(i), VM_PROT_ALL,
        !          1605:                            PMAP_CACHE_WB);
        !          1606:                asm volatile ("sync; mtsdr1 %0; isync"
        !          1607:                    :: "r"((u_int)pmap_ptable64 | HTABSIZE_64));
        !          1608:        } else
        !          1609:                asm volatile ("sync; mtsdr1 %0; isync"
        !          1610:                    :: "r"((u_int)pmap_ptable32 | (pmap_ptab_mask >> 10)));
        !          1611:
        !          1612:        pmap_avail_fixup();
        !          1613:
        !          1614:
        !          1615:        tlbia();
        !          1616:
        !          1617:        pmap_avail_fixup();
        !          1618:        for (mp = pmap_avail; mp->size; mp++) {
        !          1619:                if (mp->start > 0x80000000)
        !          1620:                        continue;
        !          1621:                if (mp->start + mp->size > 0x80000000)
        !          1622:                        mp->size = 0x80000000 - mp->start;
        !          1623:                uvm_page_physload(atop(mp->start), atop(mp->start+mp->size),
        !          1624:                    atop(mp->start), atop(mp->start+mp->size),
        !          1625:                    VM_FREELIST_DEFAULT);
        !          1626:        }
        !          1627: }
        !          1628:
        !          1629: /*
        !          1630:  * activate a pmap entry
        !          1631:  * NOOP on powerpc, all PTE entries exist in the same hash table.
        !          1632:  * Segment registers are filled on exit to user mode.
        !          1633:  */
        !          1634: void
        !          1635: pmap_activate(struct proc *p)
        !          1636: {
        !          1637: }
        !          1638:
        !          1639: /*
        !          1640:  * deactivate a pmap entry
        !          1641:  * NOOP on powerpc
        !          1642:  */
        !          1643: void
        !          1644: pmap_deactivate(struct proc *p)
        !          1645: {
        !          1646: }
        !          1647:
        !          1648: /*
        !          1649:  * Get the physical page address for the given pmap/virtual address.
        !          1650:  */
        !          1651: boolean_t
        !          1652: pmap_extract(pmap_t pm, vaddr_t va, paddr_t *pa)
        !          1653: {
        !          1654:        struct pte_desc *pted;
        !          1655:
        !          1656:        pted = pmap_vp_lookup(pm, va);
        !          1657:        if (pted == NULL || !PTED_VALID(pted)) {
        !          1658:                if (pm == pmap_kernel() && va < 0x80000000) {
        !          1659:                        /* XXX - this is not true without BATs */
        !          1660:                        /* if in kernel, va==pa for 0-0x80000000 */
        !          1661:                        *pa = va;
        !          1662:                        return TRUE;
        !          1663:                }
        !          1664:                return FALSE;
        !          1665:        }
        !          1666:        if (ppc_proc_is_64b)
        !          1667:                *pa = (pted->p.pted_pte64.pte_lo & PTE_RPGN_64) |
        !          1668:                    (va & ~PTE_RPGN_64);
        !          1669:        else
        !          1670:                *pa = (pted->p.pted_pte32.pte_lo & PTE_RPGN_32) |
        !          1671:                    (va & ~PTE_RPGN_32);
        !          1672:        return TRUE;
        !          1673: }
        !          1674:
        !          1675: u_int32_t
        !          1676: pmap_setusr(pmap_t pm, vaddr_t va)
        !          1677: {
        !          1678:        u_int32_t sr;
        !          1679:        u_int32_t oldsr;
        !          1680:
        !          1681:        sr = pm->pm_sr[(u_int)va >> ADDR_SR_SHIFT];
        !          1682:
        !          1683:        /* user address range lock?? */
        !          1684:        asm volatile ("mfsr %0,%1"
        !          1685:            : "=r" (oldsr): "n"(PPC_USER_SR));
        !          1686:        asm volatile ("isync; mtsr %0,%1; isync"
        !          1687:            :: "n"(PPC_USER_SR), "r"(sr));
        !          1688:        return oldsr;
        !          1689: }
        !          1690:
        !          1691: void
        !          1692: pmap_popusr(u_int32_t sr)
        !          1693: {
        !          1694:        asm volatile ("isync; mtsr %0,%1; isync"
        !          1695:            :: "n"(PPC_USER_SR), "r"(sr));
        !          1696: }
        !          1697:
        !          1698: int
        !          1699: copyin(const void *udaddr, void *kaddr, size_t len)
        !          1700: {
        !          1701:        void *p;
        !          1702:        size_t l;
        !          1703:        u_int32_t oldsr;
        !          1704:        faultbuf env;
        !          1705:        void *oldh = curpcb->pcb_onfault;
        !          1706:
        !          1707:        while (len > 0) {
        !          1708:                p = PPC_USER_ADDR + ((u_int)udaddr & ~PPC_SEGMENT_MASK);
        !          1709:                l = (PPC_USER_ADDR + PPC_SEGMENT_LENGTH) - p;
        !          1710:                if (l > len)
        !          1711:                        l = len;
        !          1712:                oldsr = pmap_setusr(curpcb->pcb_pm, (vaddr_t)udaddr);
        !          1713:                if (setfault(&env)) {
        !          1714:                        pmap_popusr(oldsr);
        !          1715:                        curpcb->pcb_onfault = oldh;
        !          1716:                        return EFAULT;
        !          1717:                }
        !          1718:                bcopy(p, kaddr, l);
        !          1719:                pmap_popusr(oldsr);
        !          1720:                udaddr += l;
        !          1721:                kaddr += l;
        !          1722:                len -= l;
        !          1723:        }
        !          1724:        curpcb->pcb_onfault = oldh;
        !          1725:        return 0;
        !          1726: }
        !          1727:
        !          1728: int
        !          1729: copyout(const void *kaddr, void *udaddr, size_t len)
        !          1730: {
        !          1731:        void *p;
        !          1732:        size_t l;
        !          1733:        u_int32_t oldsr;
        !          1734:        faultbuf env;
        !          1735:        void *oldh = curpcb->pcb_onfault;
        !          1736:
        !          1737:        while (len > 0) {
        !          1738:                p = PPC_USER_ADDR + ((u_int)udaddr & ~PPC_SEGMENT_MASK);
        !          1739:                l = (PPC_USER_ADDR + PPC_SEGMENT_LENGTH) - p;
        !          1740:                if (l > len)
        !          1741:                        l = len;
        !          1742:                oldsr = pmap_setusr(curpcb->pcb_pm, (vaddr_t)udaddr);
        !          1743:                if (setfault(&env)) {
        !          1744:                        pmap_popusr(oldsr);
        !          1745:                        curpcb->pcb_onfault = oldh;
        !          1746:                        return EFAULT;
        !          1747:                }
        !          1748:
        !          1749:                bcopy(kaddr, p, l);
        !          1750:                pmap_popusr(oldsr);
        !          1751:                udaddr += l;
        !          1752:                kaddr += l;
        !          1753:                len -= l;
        !          1754:        }
        !          1755:        curpcb->pcb_onfault = oldh;
        !          1756:        return 0;
        !          1757: }
        !          1758:
        !          1759: int
        !          1760: copyinstr(const void *udaddr, void *kaddr, size_t len, size_t *done)
        !          1761: {
        !          1762:        const u_char *uaddr = udaddr;
        !          1763:        u_char *kp    = kaddr;
        !          1764:        u_char *up;
        !          1765:        u_char c;
        !          1766:        void   *p;
        !          1767:        size_t   l;
        !          1768:        u_int32_t oldsr;
        !          1769:        int cnt = 0;
        !          1770:        faultbuf env;
        !          1771:        void *oldh = curpcb->pcb_onfault;
        !          1772:
        !          1773:        while (len > 0) {
        !          1774:                p = PPC_USER_ADDR + ((u_int)uaddr & ~PPC_SEGMENT_MASK);
        !          1775:                l = (PPC_USER_ADDR + PPC_SEGMENT_LENGTH) - p;
        !          1776:                up = p;
        !          1777:                if (l > len)
        !          1778:                        l = len;
        !          1779:                len -= l;
        !          1780:                oldsr = pmap_setusr(curpcb->pcb_pm, (vaddr_t)uaddr);
        !          1781:                if (setfault(&env)) {
        !          1782:                        if (done != NULL)
        !          1783:                                *done =  cnt;
        !          1784:
        !          1785:                        curpcb->pcb_onfault = oldh;
        !          1786:                        pmap_popusr(oldsr);
        !          1787:                        return EFAULT;
        !          1788:                }
        !          1789:                while (l > 0) {
        !          1790:                        c = *up;
        !          1791:                        *kp = c;
        !          1792:                        if (c == 0) {
        !          1793:                                if (done != NULL)
        !          1794:                                        *done = cnt + 1;
        !          1795:
        !          1796:                                curpcb->pcb_onfault = oldh;
        !          1797:                                pmap_popusr(oldsr);
        !          1798:                                return 0;
        !          1799:                        }
        !          1800:                        up++;
        !          1801:                        kp++;
        !          1802:                        l--;
        !          1803:                        cnt++;
        !          1804:                        uaddr++;
        !          1805:                }
        !          1806:                pmap_popusr(oldsr);
        !          1807:        }
        !          1808:        curpcb->pcb_onfault = oldh;
        !          1809:        if (done != NULL)
        !          1810:                *done = cnt;
        !          1811:
        !          1812:        return ENAMETOOLONG;
        !          1813: }
        !          1814:
        !          1815: int
        !          1816: copyoutstr(const void *kaddr, void *udaddr, size_t len, size_t *done)
        !          1817: {
        !          1818:        u_char *uaddr = (void *)udaddr;
        !          1819:        const u_char *kp    = kaddr;
        !          1820:        u_char *up;
        !          1821:        u_char c;
        !          1822:        void   *p;
        !          1823:        size_t   l;
        !          1824:        u_int32_t oldsr;
        !          1825:        int cnt = 0;
        !          1826:        faultbuf env;
        !          1827:        void *oldh = curpcb->pcb_onfault;
        !          1828:
        !          1829:        while (len > 0) {
        !          1830:                p = PPC_USER_ADDR + ((u_int)uaddr & ~PPC_SEGMENT_MASK);
        !          1831:                l = (PPC_USER_ADDR + PPC_SEGMENT_LENGTH) - p;
        !          1832:                up = p;
        !          1833:                if (l > len)
        !          1834:                        l = len;
        !          1835:                len -= l;
        !          1836:                oldsr = pmap_setusr(curpcb->pcb_pm, (vaddr_t)uaddr);
        !          1837:                if (setfault(&env)) {
        !          1838:                        if (done != NULL)
        !          1839:                                *done =  cnt;
        !          1840:
        !          1841:                        curpcb->pcb_onfault = oldh;
        !          1842:                        pmap_popusr(oldsr);
        !          1843:                        return EFAULT;
        !          1844:                }
        !          1845:                while (l > 0) {
        !          1846:                        c = *kp;
        !          1847:                        *up = c;
        !          1848:                        if (c == 0) {
        !          1849:                                if (done != NULL)
        !          1850:                                        *done = cnt + 1;
        !          1851:
        !          1852:                                curpcb->pcb_onfault = oldh;
        !          1853:                                pmap_popusr(oldsr);
        !          1854:                                return 0;
        !          1855:                        }
        !          1856:                        up++;
        !          1857:                        kp++;
        !          1858:                        l--;
        !          1859:                        cnt++;
        !          1860:                        uaddr++;
        !          1861:                }
        !          1862:                pmap_popusr(oldsr);
        !          1863:        }
        !          1864:        curpcb->pcb_onfault = oldh;
        !          1865:        if (done != NULL)
        !          1866:                *done = cnt;
        !          1867:
        !          1868:        return ENAMETOOLONG;
        !          1869: }
        !          1870:
        !          1871: /*
        !          1872:  * sync instruction cache for user virtual address.
        !          1873:  * The address WAS JUST MAPPED, so we have a VALID USERSPACE mapping
        !          1874:  */
        !          1875: #define CACHELINESIZE   32             /* For now XXX*/
        !          1876: void
        !          1877: pmap_syncicache_user_virt(pmap_t pm, vaddr_t va)
        !          1878: {
        !          1879:        vaddr_t p, start;
        !          1880:        int oldsr;
        !          1881:        int l;
        !          1882:
        !          1883:        if (pm != pmap_kernel()) {
        !          1884:                start = ((u_int)PPC_USER_ADDR + ((u_int)va &
        !          1885:                    ~PPC_SEGMENT_MASK));
        !          1886:                /* will only ever be page size, will not cross segments */
        !          1887:
        !          1888:                /* USER SEGMENT LOCK - MPXXX */
        !          1889:                oldsr = pmap_setusr(pm, va);
        !          1890:        } else {
        !          1891:                start = va; /* flush mapped page */
        !          1892:        }
        !          1893:        p = start;
        !          1894:        l = PAGE_SIZE;
        !          1895:        do {
        !          1896:                __asm__ __volatile__ ("dcbst 0,%0" :: "r"(p));
        !          1897:                p += CACHELINESIZE;
        !          1898:        } while ((l -= CACHELINESIZE) > 0);
        !          1899:        p = start;
        !          1900:        l = PAGE_SIZE;
        !          1901:        do {
        !          1902:                __asm__ __volatile__ ("icbi 0,%0" :: "r"(p));
        !          1903:                p += CACHELINESIZE;
        !          1904:        } while ((l -= CACHELINESIZE) > 0);
        !          1905:
        !          1906:
        !          1907:        if (pm != pmap_kernel()) {
        !          1908:                pmap_popusr(oldsr);
        !          1909:                /* USER SEGMENT UNLOCK -MPXXX */
        !          1910:        }
        !          1911: }
        !          1912:
        !          1913: void
        !          1914: pmap_page_ro64(pmap_t pm, vaddr_t va, vm_prot_t prot)
        !          1915: {
        !          1916:        struct pte_64 *ptp64;
        !          1917:        struct pte_desc *pted;
        !          1918:        int sr, idx;
        !          1919:
        !          1920:        pted = pmap_vp_lookup(pm, va);
        !          1921:        if (pted == NULL || !PTED_VALID(pted))
        !          1922:                return;
        !          1923:
        !          1924:        pted->p.pted_pte64.pte_lo &= ~PTE_PP_64;
        !          1925:        pted->p.pted_pte64.pte_lo |= PTE_RO_64;
        !          1926:
        !          1927:        if ((prot & VM_PROT_EXECUTE) == 0)
        !          1928:                pted->p.pted_pte64.pte_lo |= PTE_N_64;
        !          1929:
        !          1930:        sr = ptesr(pm->pm_sr, va);
        !          1931:        idx = pteidx(sr, va);
        !          1932:
        !          1933:        /* determine which pteg mapping is present in */
        !          1934:        ptp64 = pmap_ptable64 +
        !          1935:            (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !          1936:        ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          1937:
        !          1938:        /*
        !          1939:         * We now have the pointer to where it will be, if it is
        !          1940:         * currently mapped. If the mapping was thrown away in
        !          1941:         * exchange for another page mapping, then this page is
        !          1942:         * not currently in the HASH.
        !          1943:         */
        !          1944:        if ((pted->p.pted_pte64.pte_hi | (PTED_HID(pted) ? PTE_HID_64 : 0))
        !          1945:            == ptp64->pte_hi) {
        !          1946:                ptp64->pte_hi &= ~PTE_VALID_64;
        !          1947:                __asm__ volatile ("sync");
        !          1948:                tlbie(va);
        !          1949:                tlbsync();
        !          1950:                if (PTED_MANAGED(pted)) { /* XXX */
        !          1951:                        pmap_attr_save(ptp64->pte_lo & PTE_RPGN_64,
        !          1952:                            ptp64->pte_lo & (PTE_REF_64|PTE_CHG_64));
        !          1953:                }
        !          1954:                ptp64->pte_lo &= ~PTE_CHG_64;
        !          1955:                ptp64->pte_lo &= ~PTE_PP_64;
        !          1956:                ptp64->pte_lo |= PTE_RO_64;
        !          1957:                __asm__ volatile ("sync");
        !          1958:                ptp64->pte_hi |= PTE_VALID_64;
        !          1959:        }
        !          1960: }
        !          1961: void
        !          1962: pmap_page_ro32(pmap_t pm, vaddr_t va)
        !          1963: {
        !          1964:        struct pte_32 *ptp32;
        !          1965:        struct pte_desc *pted;
        !          1966:        int sr, idx;
        !          1967:
        !          1968:        pted = pmap_vp_lookup(pm, va);
        !          1969:        if (pted == NULL || !PTED_VALID(pted))
        !          1970:                return;
        !          1971:
        !          1972:        pted->p.pted_pte32.pte_lo &= ~PTE_PP_32;
        !          1973:        pted->p.pted_pte32.pte_lo |= PTE_RO_32;
        !          1974:
        !          1975:        sr = ptesr(pm->pm_sr, va);
        !          1976:        idx = pteidx(sr, va);
        !          1977:
        !          1978:        /* determine which pteg mapping is present in */
        !          1979:        ptp32 = pmap_ptable32 +
        !          1980:            (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !          1981:        ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          1982:
        !          1983:        /*
        !          1984:         * We now have the pointer to where it will be, if it is
        !          1985:         * currently mapped. If the mapping was thrown away in
        !          1986:         * exchange for another page mapping, then this page is
        !          1987:         * not currently in the HASH.
        !          1988:         */
        !          1989:        if ((pted->p.pted_pte32.pte_hi | (PTED_HID(pted) ? PTE_HID_32 : 0))
        !          1990:            == ptp32->pte_hi) {
        !          1991:                ptp32->pte_hi &= ~PTE_VALID_32;
        !          1992:                __asm__ volatile ("sync");
        !          1993:                tlbie(va);
        !          1994:                tlbsync();
        !          1995:                if (PTED_MANAGED(pted)) { /* XXX */
        !          1996:                        pmap_attr_save(ptp32->pte_lo & PTE_RPGN_32,
        !          1997:                            ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32));
        !          1998:                }
        !          1999:                ptp32->pte_lo &= ~PTE_CHG_32;
        !          2000:                ptp32->pte_lo &= ~PTE_PP_32;
        !          2001:                ptp32->pte_lo |= PTE_RO_32;
        !          2002:                __asm__ volatile ("sync");
        !          2003:                ptp32->pte_hi |= PTE_VALID_32;
        !          2004:        }
        !          2005: }
        !          2006:
        !          2007: /*
        !          2008:  * Lower the protection on the specified physical page.
        !          2009:  *
        !          2010:  * There are only two cases, either the protection is going to 0,
        !          2011:  * or it is going to read-only.
        !          2012:  */
        !          2013: void
        !          2014: pmap_page_protect(struct vm_page *pg, vm_prot_t prot)
        !          2015: {
        !          2016:        int s;
        !          2017:        struct pte_desc *pted;
        !          2018:
        !          2019:        /* need to lock for this pv */
        !          2020:        s = splvm();
        !          2021:
        !          2022:        if (prot == VM_PROT_NONE) {
        !          2023:                while (!LIST_EMPTY(&(pg->mdpage.pv_list))) {
        !          2024:                        pted = LIST_FIRST(&(pg->mdpage.pv_list));
        !          2025:                        pmap_remove_pg(pted->pted_pmap, pted->pted_va);
        !          2026:                }
        !          2027:                /* page is being reclaimed, sync icache next use */
        !          2028:                atomic_clearbits_int(&pg->pg_flags, PG_PMAP_EXE);
        !          2029:                splx(s);
        !          2030:                return;
        !          2031:        }
        !          2032:
        !          2033:        LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
        !          2034:                if (ppc_proc_is_64b)
        !          2035:                        pmap_page_ro64(pted->pted_pmap, pted->pted_va, prot);
        !          2036:                else
        !          2037:                        pmap_page_ro32(pted->pted_pmap, pted->pted_va);
        !          2038:        }
        !          2039:        splx(s);
        !          2040: }
        !          2041:
        !          2042: void
        !          2043: pmap_protect(pmap_t pm, vaddr_t sva, vaddr_t eva, vm_prot_t prot)
        !          2044: {
        !          2045:        int s;
        !          2046:        if (prot & (VM_PROT_READ | VM_PROT_EXECUTE)) {
        !          2047:                s = splvm();
        !          2048:                if (ppc_proc_is_64b) {
        !          2049:                        while (sva < eva) {
        !          2050:                                pmap_page_ro64(pm, sva, prot);
        !          2051:                                sva += PAGE_SIZE;
        !          2052:                        }
        !          2053:                } else {
        !          2054:                        while (sva < eva) {
        !          2055:                                pmap_page_ro32(pm, sva);
        !          2056:                                sva += PAGE_SIZE;
        !          2057:                        }
        !          2058:                }
        !          2059:                splx(s);
        !          2060:                return;
        !          2061:        }
        !          2062:        pmap_remove(pm, sva, eva);
        !          2063: }
        !          2064:
        !          2065: /*
        !          2066:  * Restrict given range to physical memory
        !          2067:  */
        !          2068: void
        !          2069: pmap_real_memory(paddr_t *start, vsize_t *size)
        !          2070: {
        !          2071:        struct mem_region *mp;
        !          2072:
        !          2073:        for (mp = pmap_mem; mp->size; mp++) {
        !          2074:                if (((*start + *size) > mp->start)
        !          2075:                        && (*start < (mp->start + mp->size)))
        !          2076:                {
        !          2077:                        if (*start < mp->start) {
        !          2078:                                *size -= mp->start - *start;
        !          2079:                                *start = mp->start;
        !          2080:                        }
        !          2081:                        if ((*start + *size) > (mp->start + mp->size))
        !          2082:                                *size = mp->start + mp->size - *start;
        !          2083:                        return;
        !          2084:                }
        !          2085:        }
        !          2086:        *size = 0;
        !          2087: }
        !          2088:
        !          2089: void
        !          2090: pmap_init()
        !          2091: {
        !          2092:        pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmap", NULL);
        !          2093:        pool_setlowat(&pmap_pmap_pool, 2);
        !          2094:        pool_init(&pmap_vp_pool, sizeof(struct pmapvp), 0, 0, 0, "vp", NULL);
        !          2095:        pool_setlowat(&pmap_vp_pool, 10);
        !          2096:        pool_init(&pmap_pted_pool, sizeof(struct pte_desc), 0, 0, 0, "pted",
        !          2097:            NULL);
        !          2098:        pool_setlowat(&pmap_pted_pool, 20);
        !          2099:
        !          2100:        pmap_initialized = 1;
        !          2101: }
        !          2102:
        !          2103: void
        !          2104: pmap_proc_iflush(struct proc *p, vaddr_t addr, vsize_t len)
        !          2105: {
        !          2106:        paddr_t pa;
        !          2107:        vsize_t clen;
        !          2108:
        !          2109:        while (len > 0) {
        !          2110:                /* add one to always round up to the next page */
        !          2111:                clen = round_page(addr + 1) - addr;
        !          2112:                if (clen > len)
        !          2113:                        clen = len;
        !          2114:
        !          2115:                if (pmap_extract(p->p_vmspace->vm_map.pmap, addr, &pa)) {
        !          2116:                        syncicache((void *)pa, clen);
        !          2117:                }
        !          2118:
        !          2119:                len -= clen;
        !          2120:                addr += clen;
        !          2121:        }
        !          2122: }
        !          2123:
        !          2124: /*
        !          2125:  * There are two routines, pte_spill_r and pte_spill_v
        !          2126:  * the _r version only handles kernel faults which are not user
        !          2127:  * accesses. The _v version handles all user faults and kernel copyin/copyout
        !          2128:  * "user" accesses.
        !          2129:  */
        !          2130: int
        !          2131: pte_spill_r(u_int32_t va, u_int32_t msr, u_int32_t dsisr, int exec_fault)
        !          2132: {
        !          2133:        pmap_t pm;
        !          2134:        struct pte_desc *pted;
        !          2135:        struct pte_desc pted_store;
        !          2136:
        !          2137:        /* lookup is done physical to prevent faults */
        !          2138:
        !          2139:        /*
        !          2140:         * This function only handles kernel faults, not supervisor copyins.
        !          2141:         */
        !          2142:        if (msr & PSL_PR)
        !          2143:                return 0;
        !          2144:
        !          2145:        /* if copyin, throw to full excption handler */
        !          2146:        if (VP_SR(va) == PPC_USER_SR)
        !          2147:                return 0;
        !          2148:
        !          2149:        pm = pmap_kernel();
        !          2150:
        !          2151:
        !          2152:        if (va < physmaxaddr) {
        !          2153:                u_int32_t aligned_va;
        !          2154:                pted =  &pted_store;
        !          2155:                /* 0 - physmaxaddr mapped 1-1 */
        !          2156:                /* XXX - no WRX control */
        !          2157:
        !          2158:                aligned_va = trunc_page(va);
        !          2159:                if (ppc_proc_is_64b) {
        !          2160:                        pmap_fill_pte64(pm, aligned_va, aligned_va,
        !          2161:                            pted, VM_PROT_READ | VM_PROT_WRITE |
        !          2162:                            VM_PROT_EXECUTE, 0, PMAP_CACHE_WB);
        !          2163:                        pte_insert64(pted);
        !          2164:                        return 1;
        !          2165:                } else {
        !          2166:                        pmap_fill_pte32(pm, aligned_va, aligned_va,
        !          2167:                            &pted_store, VM_PROT_READ | VM_PROT_WRITE |
        !          2168:                            VM_PROT_EXECUTE, 0, PMAP_CACHE_WB);
        !          2169:                        pte_insert32(pted);
        !          2170:                        return 1;
        !          2171:                }
        !          2172:                /* NOTREACHED */
        !          2173:        }
        !          2174:
        !          2175:        pted = pmap_vp_lookup(pm, va);
        !          2176:        if (pted == NULL) {
        !          2177:                return 0;
        !          2178:        }
        !          2179:
        !          2180:        /* if the current mapping is RO and the access was a write
        !          2181:         * we return 0
        !          2182:         */
        !          2183:        if (!PTED_VALID(pted)) {
        !          2184:                return 0;
        !          2185:        }
        !          2186:
        !          2187:        if (ppc_proc_is_64b) {
        !          2188:                /* check write fault and we have a readonly mapping */
        !          2189:                if ((dsisr & (1 << (31-6))) &&
        !          2190:                    (pted->p.pted_pte64.pte_lo & 0x1))
        !          2191:                        return 0;
        !          2192:                if ((exec_fault != 0)
        !          2193:                    && ((pted->pted_va & PTED_VA_EXEC_M) == 0)) {
        !          2194:                        /* attempted to execute non-executable page */
        !          2195:                        return 0;
        !          2196:                }
        !          2197:                pte_insert64(pted);
        !          2198:        } else {
        !          2199:                /* check write fault and we have a readonly mapping */
        !          2200:                if ((dsisr & (1 << (31-6))) &&
        !          2201:                    (pted->p.pted_pte32.pte_lo & 0x1))
        !          2202:                        return 0;
        !          2203:                if ((exec_fault != 0)
        !          2204:                    && ((pted->pted_va & PTED_VA_EXEC_M) == 0)) {
        !          2205:                        /* attempted to execute non-executable page */
        !          2206:                        return 0;
        !          2207:                }
        !          2208:                pte_insert32(pted);
        !          2209:        }
        !          2210:
        !          2211:        return 1;
        !          2212: }
        !          2213:
        !          2214: int
        !          2215: pte_spill_v(pmap_t pm, u_int32_t va, u_int32_t dsisr, int exec_fault)
        !          2216: {
        !          2217:        struct pte_desc *pted;
        !          2218:
        !          2219:        pted = pmap_vp_lookup(pm, va);
        !          2220:        if (pted == NULL) {
        !          2221:                return 0;
        !          2222:        }
        !          2223:
        !          2224:        /*
        !          2225:         * if the current mapping is RO and the access was a write
        !          2226:         * we return 0
        !          2227:         */
        !          2228:        if (!PTED_VALID(pted)) {
        !          2229:                return 0;
        !          2230:        }
        !          2231:        if (ppc_proc_is_64b) {
        !          2232:                /* check write fault and we have a readonly mapping */
        !          2233:                if ((dsisr & (1 << (31-6))) &&
        !          2234:                    (pted->p.pted_pte64.pte_lo & 0x1))
        !          2235:                        return 0;
        !          2236:        } else {
        !          2237:                /* check write fault and we have a readonly mapping */
        !          2238:                if ((dsisr & (1 << (31-6))) &&
        !          2239:                    (pted->p.pted_pte32.pte_lo & 0x1))
        !          2240:                        return 0;
        !          2241:        }
        !          2242:        if ((exec_fault != 0)
        !          2243:            && ((pted->pted_va & PTED_VA_EXEC_M) == 0)) {
        !          2244:                /* attempted to execute non-executable page */
        !          2245:                return 0;
        !          2246:        }
        !          2247:        if (ppc_proc_is_64b)
        !          2248:                pte_insert64(pted);
        !          2249:        else
        !          2250:                pte_insert32(pted);
        !          2251:        return 1;
        !          2252: }
        !          2253:
        !          2254:
        !          2255: /*
        !          2256:  * should pte_insert code avoid wired mappings?
        !          2257:  * is the stack safe?
        !          2258:  * is the pted safe? (physical)
        !          2259:  * -ugh
        !          2260:  */
        !          2261: void
        !          2262: pte_insert64(struct pte_desc *pted)
        !          2263: {
        !          2264:        int off;
        !          2265:        int secondary;
        !          2266:        struct pte_64 *ptp64;
        !          2267:        int sr, idx;
        !          2268:        int i;
        !          2269:
        !          2270:        /* HASH lock? */
        !          2271:
        !          2272:        sr = ptesr(pted->pted_pmap->pm_sr, pted->pted_va);
        !          2273:        idx = pteidx(sr, pted->pted_va);
        !          2274:
        !          2275:        ptp64 = pmap_ptable64 +
        !          2276:            (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !          2277:        ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          2278:        if ((pted->p.pted_pte64.pte_hi |
        !          2279:            (PTED_HID(pted) ? PTE_HID_64 : 0)) == ptp64->pte_hi)
        !          2280:                pte_zap(ptp64,pted);
        !          2281:
        !          2282:        pted->pted_va &= ~(PTED_VA_HID_M|PTED_VA_PTEGIDX_M);
        !          2283:
        !          2284:        /*
        !          2285:         * instead of starting at the beginning of each pteg,
        !          2286:         * the code should pick a random location with in the primary
        !          2287:         * then search all of the entries, then if not yet found,
        !          2288:         * do the same for the secondary.
        !          2289:         * this would reduce the frontloading of the pteg.
        !          2290:         */
        !          2291:        /* first just try fill of primary hash */
        !          2292:        ptp64 = pmap_ptable64 + (idx) * 8;
        !          2293:        for (i = 0; i < 8; i++) {
        !          2294:                if (ptp64[i].pte_hi & PTE_VALID_64)
        !          2295:                        continue;
        !          2296:
        !          2297:                /* not valid, just load */
        !          2298:                pted->pted_va |= i;
        !          2299:                ptp64[i].pte_hi =
        !          2300:                    pted->p.pted_pte64.pte_hi & ~PTE_VALID_64;
        !          2301:                ptp64[i].pte_lo = pted->p.pted_pte64.pte_lo;
        !          2302:                __asm__ volatile ("sync");
        !          2303:                ptp64[i].pte_hi |= PTE_VALID_64;
        !          2304:                __asm volatile ("sync");
        !          2305:                return;
        !          2306:        }
        !          2307:        /* try fill of secondary hash */
        !          2308:        ptp64 = pmap_ptable64 + (idx ^ pmap_ptab_mask) * 8;
        !          2309:        for (i = 0; i < 8; i++) {
        !          2310:                if (ptp64[i].pte_hi & PTE_VALID_64)
        !          2311:                        continue;
        !          2312:
        !          2313:                pted->pted_va |= (i | PTED_VA_HID_M);
        !          2314:                ptp64[i].pte_hi =
        !          2315:                    (pted->p.pted_pte64.pte_hi | PTE_HID_64) & ~PTE_VALID_64;
        !          2316:                ptp64[i].pte_lo = pted->p.pted_pte64.pte_lo;
        !          2317:                __asm__ volatile ("sync");
        !          2318:                ptp64[i].pte_hi |= PTE_VALID_64;
        !          2319:                __asm volatile ("sync");
        !          2320:                return;
        !          2321:        }
        !          2322:
        !          2323:        /* need decent replacement algorithm */
        !          2324:        __asm__ volatile ("mftb %0" : "=r"(off));
        !          2325:        secondary = off & 8;
        !          2326:        pted->pted_va |= off & (PTED_VA_PTEGIDX_M|PTED_VA_HID_M);
        !          2327:
        !          2328:        idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0));
        !          2329:
        !          2330:        ptp64 = pmap_ptable64 + (idx * 8);
        !          2331:        ptp64 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          2332:        if (ptp64->pte_hi & PTE_VALID_64) {
        !          2333:                vaddr_t va;
        !          2334:                ptp64->pte_hi &= ~PTE_VALID_64;
        !          2335:                __asm volatile ("sync");
        !          2336:
        !          2337:                /* Bits 9-19 */
        !          2338:                idx = (idx ^ ((ptp64->pte_hi & PTE_HID_64) ?
        !          2339:                    pmap_ptab_mask : 0));
        !          2340:                va = (ptp64->pte_hi >> PTE_VSID_SHIFT_64) ^ idx;
        !          2341:                va <<= ADDR_PIDX_SHIFT;
        !          2342:                /* Bits 4-8 */
        !          2343:                va |= (ptp64->pte_hi & PTE_API_64) << ADDR_API_SHIFT_32;
        !          2344:                /* Bits 0-3 */
        !          2345:                va |= (ptp64->pte_hi >> PTE_VSID_SHIFT_64)
        !          2346:                    << ADDR_SR_SHIFT;
        !          2347:                tlbie(va);
        !          2348:
        !          2349:                tlbsync();
        !          2350:                pmap_attr_save(ptp64->pte_lo & PTE_RPGN_64,
        !          2351:                    ptp64->pte_lo & (PTE_REF_64|PTE_CHG_64));
        !          2352:        }
        !          2353:
        !          2354:        if (secondary)
        !          2355:                ptp64->pte_hi =
        !          2356:                    (pted->p.pted_pte64.pte_hi | PTE_HID_64) &
        !          2357:                    ~PTE_VALID_64;
        !          2358:         else
        !          2359:                ptp64->pte_hi = pted->p.pted_pte64.pte_hi &
        !          2360:                    ~PTE_VALID_64;
        !          2361:
        !          2362:        ptp64->pte_lo = pted->p.pted_pte64.pte_lo;
        !          2363:        __asm__ volatile ("sync");
        !          2364:        ptp64->pte_hi |= PTE_VALID_64;
        !          2365: }
        !          2366:
        !          2367: void
        !          2368: pte_insert32(struct pte_desc *pted)
        !          2369: {
        !          2370:        int off;
        !          2371:        int secondary;
        !          2372:        struct pte_32 *ptp32;
        !          2373:        int sr, idx;
        !          2374:        int i;
        !          2375:
        !          2376:        /* HASH lock? */
        !          2377:
        !          2378:        sr = ptesr(pted->pted_pmap->pm_sr, pted->pted_va);
        !          2379:        idx = pteidx(sr, pted->pted_va);
        !          2380:
        !          2381:        /* determine if ptp is already mapped */
        !          2382:        ptp32 = pmap_ptable32 +
        !          2383:            (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0)) * 8;
        !          2384:        ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          2385:        if ((pted->p.pted_pte32.pte_hi |
        !          2386:            (PTED_HID(pted) ? PTE_HID_32 : 0)) == ptp32->pte_hi)
        !          2387:                pte_zap(ptp32,pted);
        !          2388:
        !          2389:        pted->pted_va &= ~(PTED_VA_HID_M|PTED_VA_PTEGIDX_M);
        !          2390:
        !          2391:        /*
        !          2392:         * instead of starting at the beginning of each pteg,
        !          2393:         * the code should pick a random location with in the primary
        !          2394:         * then search all of the entries, then if not yet found,
        !          2395:         * do the same for the secondary.
        !          2396:         * this would reduce the frontloading of the pteg.
        !          2397:         */
        !          2398:
        !          2399:        /* first just try fill of primary hash */
        !          2400:        ptp32 = pmap_ptable32 + (idx) * 8;
        !          2401:        for (i = 0; i < 8; i++) {
        !          2402:                if (ptp32[i].pte_hi & PTE_VALID_32)
        !          2403:                        continue;
        !          2404:
        !          2405:                /* not valid, just load */
        !          2406:                pted->pted_va |= i;
        !          2407:                ptp32[i].pte_hi = pted->p.pted_pte32.pte_hi & ~PTE_VALID_32;
        !          2408:                ptp32[i].pte_lo = pted->p.pted_pte32.pte_lo;
        !          2409:                __asm__ volatile ("sync");
        !          2410:                ptp32[i].pte_hi |= PTE_VALID_32;
        !          2411:                __asm volatile ("sync");
        !          2412:                return;
        !          2413:        }
        !          2414:        /* try fill of secondary hash */
        !          2415:        ptp32 = pmap_ptable32 + (idx ^ pmap_ptab_mask) * 8;
        !          2416:        for (i = 0; i < 8; i++) {
        !          2417:                if (ptp32[i].pte_hi & PTE_VALID_32)
        !          2418:                        continue;
        !          2419:
        !          2420:                pted->pted_va |= (i | PTED_VA_HID_M);
        !          2421:                ptp32[i].pte_hi =
        !          2422:                    (pted->p.pted_pte32.pte_hi | PTE_HID_32) & ~PTE_VALID_32;
        !          2423:                ptp32[i].pte_lo = pted->p.pted_pte32.pte_lo;
        !          2424:                __asm__ volatile ("sync");
        !          2425:                ptp32[i].pte_hi |= PTE_VALID_32;
        !          2426:                __asm volatile ("sync");
        !          2427:                return;
        !          2428:        }
        !          2429:
        !          2430:        /* need decent replacement algorithm */
        !          2431:        __asm__ volatile ("mftb %0" : "=r"(off));
        !          2432:        secondary = off & 8;
        !          2433:        pted->pted_va |= off & (PTED_VA_PTEGIDX_M|PTED_VA_HID_M);
        !          2434:
        !          2435:        idx = (idx ^ (PTED_HID(pted) ? pmap_ptab_mask : 0));
        !          2436:
        !          2437:        ptp32 = pmap_ptable32 + (idx * 8);
        !          2438:        ptp32 += PTED_PTEGIDX(pted); /* increment by index into pteg */
        !          2439:        if (ptp32->pte_hi & PTE_VALID_32) {
        !          2440:                vaddr_t va;
        !          2441:                ptp32->pte_hi &= ~PTE_VALID_32;
        !          2442:                __asm volatile ("sync");
        !          2443:
        !          2444:                va = ((ptp32->pte_hi & PTE_API_32) << ADDR_API_SHIFT_32) |
        !          2445:                     ((((ptp32->pte_hi >> PTE_VSID_SHIFT_32) & SR_VSID)
        !          2446:                        ^(idx ^ ((ptp32->pte_hi & PTE_HID_32) ? 0x3ff : 0)))
        !          2447:                            & 0x3ff) << PAGE_SHIFT;
        !          2448:                tlbie(va);
        !          2449:
        !          2450:                tlbsync();
        !          2451:                pmap_attr_save(ptp32->pte_lo & PTE_RPGN_32,
        !          2452:                    ptp32->pte_lo & (PTE_REF_32|PTE_CHG_32));
        !          2453:        }
        !          2454:        if (secondary)
        !          2455:                ptp32->pte_hi =
        !          2456:                    (pted->p.pted_pte32.pte_hi | PTE_HID_32) & ~PTE_VALID_32;
        !          2457:        else
        !          2458:                ptp32->pte_hi = pted->p.pted_pte32.pte_hi & ~PTE_VALID_32;
        !          2459:        ptp32->pte_lo = pted->p.pted_pte32.pte_lo;
        !          2460:        __asm__ volatile ("sync");
        !          2461:        ptp32->pte_hi |= PTE_VALID_32;
        !          2462:
        !          2463: }
        !          2464:
        !          2465: #ifdef DEBUG_PMAP
        !          2466: void
        !          2467: print_pteg(pmap_t pm, vaddr_t va)
        !          2468: {
        !          2469:        int sr, idx;
        !          2470:        struct pte *ptp;
        !          2471:
        !          2472:        sr = ptesr(pm->pm_sr, va);
        !          2473:        idx = pteidx(sr,  va);
        !          2474:
        !          2475:        ptp = pmap_ptable + idx  * 8;
        !          2476:        db_printf("va %x, sr %x, idx %x\n", va, sr, idx);
        !          2477:
        !          2478:        db_printf("%08x %08x %08x %08x  %08x %08x %08x %08x\n",
        !          2479:            ptp[0].pte_hi, ptp[1].pte_hi, ptp[2].pte_hi, ptp[3].pte_hi,
        !          2480:            ptp[4].pte_hi, ptp[5].pte_hi, ptp[6].pte_hi, ptp[7].pte_hi);
        !          2481:        db_printf("%08x %08x %08x %08x  %08x %08x %08x %08x\n",
        !          2482:            ptp[0].pte_lo, ptp[1].pte_lo, ptp[2].pte_lo, ptp[3].pte_lo,
        !          2483:            ptp[4].pte_lo, ptp[5].pte_lo, ptp[6].pte_lo, ptp[7].pte_lo);
        !          2484:        ptp = pmap_ptable + (idx ^ pmap_ptab_mask) * 8;
        !          2485:        db_printf("%08x %08x %08x %08x  %08x %08x %08x %08x\n",
        !          2486:            ptp[0].pte_hi, ptp[1].pte_hi, ptp[2].pte_hi, ptp[3].pte_hi,
        !          2487:            ptp[4].pte_hi, ptp[5].pte_hi, ptp[6].pte_hi, ptp[7].pte_hi);
        !          2488:        db_printf("%08x %08x %08x %08x  %08x %08x %08x %08x\n",
        !          2489:            ptp[0].pte_lo, ptp[1].pte_lo, ptp[2].pte_lo, ptp[3].pte_lo,
        !          2490:            ptp[4].pte_lo, ptp[5].pte_lo, ptp[6].pte_lo, ptp[7].pte_lo);
        !          2491: }
        !          2492:
        !          2493:
        !          2494: /* debugger assist function */
        !          2495: int pmap_prtrans(u_int pid, vaddr_t va);
        !          2496:
        !          2497: void
        !          2498: pmap_print_pted(struct pte_desc *pted, int(*print)(const char *, ...))
        !          2499: {
        !          2500:        vaddr_t va;
        !          2501:        va = pted->pted_va & ~PAGE_MASK;
        !          2502:        print("\n pted %x", pted);
        !          2503:        if (PTED_VALID(pted)) {
        !          2504:                print(" va %x:", pted->pted_va & ~PAGE_MASK);
        !          2505:                print(" HID %d", PTED_HID(pted) ? 1: 0);
        !          2506:                print(" PTEGIDX %x", PTED_PTEGIDX(pted));
        !          2507:                print(" MANAGED %d", PTED_MANAGED(pted) ? 1: 0);
        !          2508:                print(" WIRED %d\n", PTED_WIRED(pted) ? 1: 0);
        !          2509:                if (ppc_proc_is_64b) {
        !          2510:                        print("ptehi %x ptelo %x ptp %x Aptp %x\n",
        !          2511:                            pted->p.pted_pte64.pte_hi,
        !          2512:                            pted->p.pted_pte64.pte_lo,
        !          2513:                            pmap_ptable +
        !          2514:                                8*pteidx(ptesr(pted->pted_pmap->pm_sr, va), va),
        !          2515:                            pmap_ptable +
        !          2516:                                8*(pteidx(ptesr(pted->pted_pmap->pm_sr, va), va)
        !          2517:                                    ^ pmap_ptab_mask)
        !          2518:                            );
        !          2519:                } else {
        !          2520:                        print("ptehi %x ptelo %x ptp %x Aptp %x\n",
        !          2521:                            pted->p.pted_pte32.pte_hi,
        !          2522:                            pted->p.pted_pte32.pte_lo,
        !          2523:                            pmap_ptable +
        !          2524:                                8*pteidx(ptesr(pted->pted_pmap->pm_sr, va), va),
        !          2525:                            pmap_ptable +
        !          2526:                                8*(pteidx(ptesr(pted->pted_pmap->pm_sr, va), va)
        !          2527:                                    ^ pmap_ptab_mask)
        !          2528:                            );
        !          2529:                }
        !          2530:        }
        !          2531: }
        !          2532:
        !          2533: int pmap_user_read(int size, vaddr_t va);
        !          2534: int
        !          2535: pmap_user_read(int size, vaddr_t va)
        !          2536: {
        !          2537:        unsigned char  read1;
        !          2538:        unsigned short read2;
        !          2539:        unsigned int   read4;
        !          2540:        int err;
        !          2541:
        !          2542:        if (size == 1) {
        !          2543:                err = copyin((void *)va, &read1, 1);
        !          2544:                if (err == 0) {
        !          2545:                        db_printf("byte read %x\n", read1);
        !          2546:                }
        !          2547:        } else if (size == 2) {
        !          2548:                err = copyin((void *)va, &read2, 2);
        !          2549:                if (err == 0) {
        !          2550:                        db_printf("short read %x\n", read2);
        !          2551:                }
        !          2552:        } else if (size == 4) {
        !          2553:                err = copyin((void *)va, &read4, 4);
        !          2554:                if (err == 0) {
        !          2555:                        db_printf("int read %x\n", read4);
        !          2556:                }
        !          2557:        } else {
        !          2558:                return 1;
        !          2559:        }
        !          2560:
        !          2561:
        !          2562:        return 0;
        !          2563: }
        !          2564:
        !          2565: int pmap_dump_pmap(u_int pid);
        !          2566: int
        !          2567: pmap_dump_pmap(u_int pid)
        !          2568: {
        !          2569:        pmap_t pm;
        !          2570:        struct proc *p;
        !          2571:        if (pid == 0) {
        !          2572:                pm = pmap_kernel();
        !          2573:        } else {
        !          2574:                p = pfind(pid);
        !          2575:
        !          2576:                if (p == NULL) {
        !          2577:                        db_printf("invalid pid %d", pid);
        !          2578:                        return 1;
        !          2579:                }
        !          2580:                pm = p->p_vmspace->vm_map.pmap;
        !          2581:        }
        !          2582:        printf("pmap %x:\n", pm);
        !          2583:        printf("segid %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x %x",
        !          2584:            pm->pm_sr[0], pm->pm_sr[1], pm->pm_sr[2], pm->pm_sr[3],
        !          2585:            pm->pm_sr[4], pm->pm_sr[5], pm->pm_sr[6], pm->pm_sr[7],
        !          2586:            pm->pm_sr[8], pm->pm_sr[9], pm->pm_sr[10], pm->pm_sr[11],
        !          2587:            pm->pm_sr[12], pm->pm_sr[13], pm->pm_sr[14], pm->pm_sr[15]);
        !          2588:
        !          2589:        return 0;
        !          2590: }
        !          2591:
        !          2592: int
        !          2593: pmap_prtrans(u_int pid, vaddr_t va)
        !          2594: {
        !          2595:        struct proc *p;
        !          2596:        pmap_t pm;
        !          2597:        struct pmapvp *vp1;
        !          2598:        struct pmapvp *vp2;
        !          2599:        struct pte_desc *pted;
        !          2600:
        !          2601:        if (pid == 0) {
        !          2602:                pm = pmap_kernel();
        !          2603:        } else {
        !          2604:                p = pfind(pid);
        !          2605:
        !          2606:                if (p == NULL) {
        !          2607:                        db_printf("invalid pid %d", pid);
        !          2608:                        return 1;
        !          2609:                }
        !          2610:                pm = p->p_vmspace->vm_map.pmap;
        !          2611:        }
        !          2612:
        !          2613:        db_printf(" pid %d, va 0x%x pmap %x\n", pid, va, pm);
        !          2614:        vp1 = pm->pm_vp[VP_SR(va)];
        !          2615:        db_printf("sr %x id %x vp1 %x", VP_SR(va), pm->pm_sr[VP_SR(va)],
        !          2616:            vp1);
        !          2617:
        !          2618:        if (vp1) {
        !          2619:                vp2 = vp1->vp[VP_IDX1(va)];
        !          2620:                db_printf(" vp2 %x", vp2);
        !          2621:
        !          2622:                if (vp2) {
        !          2623:                        pted = vp2->vp[VP_IDX2(va)];
        !          2624:                        pmap_print_pted(pted, db_printf);
        !          2625:
        !          2626:                }
        !          2627:        }
        !          2628:        print_pteg(pm, va);
        !          2629:
        !          2630:        return 0;
        !          2631: }
        !          2632: int pmap_show_mappings(paddr_t pa);
        !          2633:
        !          2634: int
        !          2635: pmap_show_mappings(paddr_t pa)
        !          2636: {
        !          2637:        struct pte_desc *pted;
        !          2638:        struct vm_page *pg;
        !          2639:
        !          2640:        pg = PHYS_TO_VM_PAGE(pa);
        !          2641:        if (pg == NULL) {
        !          2642:                db_printf("pa %x: unmanaged\n");
        !          2643:        } else {
        !          2644:                LIST_FOREACH(pted, &(pg->mdpage.pv_list), pted_pv_list) {
        !          2645:                        pmap_print_pted(pted, db_printf);
        !          2646:                }
        !          2647:        }
        !          2648:        return 0;
        !          2649: }
        !          2650: #endif

CVSweb