Annotation of sys/arch/hppa64/hppa64/pmap.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pmap.c,v 1.5 2007/04/13 18:57:49 art Exp $ */
! 2:
! 3: /*
! 4: * Copyright (c) 2005 Michael Shalayeff
! 5: * All rights reserved.
! 6: *
! 7: * Permission to use, copy, modify, and distribute this software for any
! 8: * purpose with or without fee is hereby granted, provided that the above
! 9: * copyright notice and this permission notice appear in all copies.
! 10: *
! 11: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 12: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 13: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 14: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 15: * WHATSOEVER RESULTING FROM LOSS OF MIND, USE, DATA OR PROFITS, WHETHER IN
! 16: * AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT
! 17: * OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 18: */
! 19:
! 20: #define PMAPDEBUG
! 21:
! 22: #include <sys/param.h>
! 23: #include <sys/systm.h>
! 24: #include <sys/lock.h>
! 25: #include <sys/user.h>
! 26: #include <sys/proc.h>
! 27: #include <sys/pool.h>
! 28: #include <sys/extent.h>
! 29:
! 30: #include <uvm/uvm.h>
! 31:
! 32: #include <machine/iomod.h>
! 33:
! 34: #include <dev/rndvar.h>
! 35:
! 36: #ifdef PMAPDEBUG
! 37: #define DPRINTF(l,s) do { \
! 38: if ((pmapdebug & (l)) == (l)) \
! 39: printf s; \
! 40: } while(0)
! 41: #define PDB_FOLLOW 0x00000001
! 42: #define PDB_INIT 0x00000002
! 43: #define PDB_ENTER 0x00000004
! 44: #define PDB_REMOVE 0x00000008
! 45: #define PDB_CREATE 0x00000010
! 46: #define PDB_PTPAGE 0x00000020
! 47: #define PDB_CACHE 0x00000040
! 48: #define PDB_BITS 0x00000080
! 49: #define PDB_COLLECT 0x00000100
! 50: #define PDB_PROTECT 0x00000200
! 51: #define PDB_EXTRACT 0x00000400
! 52: #define PDB_VP 0x00000800
! 53: #define PDB_PV 0x00001000
! 54: #define PDB_PARANOIA 0x00002000
! 55: #define PDB_WIRING 0x00004000
! 56: #define PDB_PMAP 0x00008000
! 57: #define PDB_STEAL 0x00010000
! 58: #define PDB_PHYS 0x00020000
! 59: #define PDB_POOL 0x00040000
! 60: int pmapdebug = 0
! 61: | PDB_INIT
! 62: /* | PDB_FOLLOW */
! 63: /* | PDB_VP */
! 64: /* | PDB_PV */
! 65: /* | PDB_ENTER */
! 66: /* | PDB_REMOVE */
! 67: /* | PDB_STEAL */
! 68: /* | PDB_PROTECT */
! 69: /* | PDB_PHYS */
! 70: ;
! 71: #else
! 72: #define DPRINTF(l,s) /* */
! 73: #endif
! 74:
! 75: paddr_t physical_steal, physical_end;
! 76:
! 77: struct pmap kernel_pmap_store;
! 78: struct pool pmap_pmap_pool;
! 79: struct pool pmap_pv_pool;
! 80: int pmap_pvlowat = 252;
! 81: int pmap_initialized;
! 82: int pmap_nkpdes = 32;
! 83:
! 84: pt_entry_t hppa_prot[8];
! 85: #define pmap_prot(m,vp) (hppa_prot[(vp)] | ((m) == pmap_kernel()? 0 : PTE_USER))
! 86:
! 87: pt_entry_t kernel_ptes[] = {
! 88: PTE_EXEC | PTE_ORDER | PTE_PREDICT | PTE_WIRED |
! 89: TLB_PAGE(0x000000) | PTE_PG4M,
! 90: PTE_WRITE | PTE_ORDER | PTE_DIRTY | PTE_WIRED |
! 91: TLB_PAGE(0x400000) | PTE_PG4M,
! 92: PTE_WRITE | PTE_ORDER | PTE_DIRTY | PTE_WIRED |
! 93: TLB_PAGE(0x800000) | PTE_PG4M,
! 94: PTE_WRITE | PTE_ORDER | PTE_DIRTY | PTE_WIRED |
! 95: TLB_PAGE(0xc00000) | PTE_PG4M
! 96: };
! 97:
! 98: #define pmap_pvh_attrs(a) \
! 99: (((a) & PTE_DIRTY) | ((a) ^ PTE_REFTRAP))
! 100:
! 101: struct vm_page *
! 102: pmap_pagealloc(int wait)
! 103: {
! 104: struct vm_page *pg;
! 105:
! 106: if ((pg = uvm_pagealloc(NULL, 0, NULL,
! 107: UVM_PGA_USERESERVE | UVM_PGA_ZERO)) == NULL)
! 108: printf("pmap_pagealloc fail\n");
! 109:
! 110: return (pg);
! 111: }
! 112:
! 113: volatile pt_entry_t *
! 114: pmap_pde_get(volatile u_int32_t *pd, vaddr_t va)
! 115: {
! 116: int i;
! 117:
! 118: DPRINTF(PDB_FOLLOW|PDB_VP,
! 119: ("pmap_pde_get(%p, 0x%lx)\n", pd, va));
! 120:
! 121: i = (va & PIE_MASK) >> PIE_SHIFT;
! 122: if (i) {
! 123: pd = (volatile u_int32_t *)((u_int64_t)pd[i] << PAGE_SHIFT);
! 124:
! 125: if (!pd)
! 126: return (NULL);
! 127: } else
! 128: pd += PAGE_SIZE / sizeof(*pd);
! 129:
! 130: i = (va & PDE_MASK) >> PDE_SHIFT;
! 131: return (pt_entry_t *)((u_int64_t)pd[i] << PAGE_SHIFT);
! 132: }
! 133:
! 134: void
! 135: pmap_pde_set(struct pmap *pm, vaddr_t va, paddr_t ptp)
! 136: {
! 137: volatile u_int32_t *pd = pm->pm_pdir;
! 138: int i;
! 139:
! 140: DPRINTF(PDB_FOLLOW|PDB_VP,
! 141: ("pmap_pde_set(%p, 0x%lx, 0x%lx)\n", pm, va, ptp));
! 142:
! 143: i = (va & PIE_MASK) >> PIE_SHIFT;
! 144: if (i)
! 145: pd = (volatile u_int32_t *)((u_int64_t)pd[i] << PAGE_SHIFT);
! 146: else
! 147: pd += PAGE_SIZE / sizeof(*pd);
! 148:
! 149: i = (va & PDE_MASK) >> PDE_SHIFT;
! 150: pd[i] = ptp >> PAGE_SHIFT;
! 151: }
! 152:
! 153: pt_entry_t *
! 154: pmap_pde_alloc(struct pmap *pm, vaddr_t va, struct vm_page **pdep)
! 155: {
! 156: struct vm_page *pg;
! 157: paddr_t pa;
! 158:
! 159: DPRINTF(PDB_FOLLOW|PDB_VP,
! 160: ("pmap_pde_alloc(%p, 0x%lx, %p)\n", pm, va, pdep));
! 161:
! 162: if ((pg = pmap_pagealloc(0)) == NULL)
! 163: return (NULL);
! 164:
! 165: pa = VM_PAGE_TO_PHYS(pg);
! 166:
! 167: DPRINTF(PDB_FOLLOW|PDB_VP, ("pmap_pde_alloc: pde %lx\n", pa));
! 168:
! 169: atomic_clearbits_int(&pg->pg_flags, PG_BUSY);
! 170: pg->wire_count = 1; /* no mappings yet */
! 171: pmap_pde_set(pm, va, pa);
! 172: pm->pm_stats.resident_count++; /* count PTP as resident */
! 173: pm->pm_ptphint = pg;
! 174: if (pdep)
! 175: *pdep = pg;
! 176: return ((pt_entry_t *)pa);
! 177: }
! 178:
! 179: static __inline struct vm_page *
! 180: pmap_pde_ptp(struct pmap *pm, volatile pt_entry_t *pde)
! 181: {
! 182: paddr_t pa = (paddr_t)pde;
! 183:
! 184: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pde_ptp(%p, %p)\n", pm, pde));
! 185:
! 186: if (pm->pm_ptphint && VM_PAGE_TO_PHYS(pm->pm_ptphint) == pa)
! 187: return (pm->pm_ptphint);
! 188:
! 189: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pde_ptp: lookup 0x%lx\n", pa));
! 190:
! 191: return (PHYS_TO_VM_PAGE(pa));
! 192: }
! 193:
! 194: static __inline void
! 195: pmap_pde_release(struct pmap *pmap, vaddr_t va, struct vm_page *ptp)
! 196: {
! 197: DPRINTF(PDB_FOLLOW|PDB_PV,
! 198: ("pmap_pde_release(%p, 0x%lx, %p)\n", pmap, va, ptp));
! 199:
! 200: if (pmap != pmap_kernel() && --ptp->wire_count <= 1) {
! 201: DPRINTF(PDB_FOLLOW|PDB_PV,
! 202: ("pmap_pde_release: disposing ptp %p\n", ptp));
! 203: pmap_pde_set(pmap, va, 0);
! 204: pmap->pm_stats.resident_count--;
! 205: if (pmap->pm_ptphint == ptp)
! 206: pmap->pm_ptphint = NULL;
! 207: ptp->wire_count = 0;
! 208: #ifdef DIAGNOSTIC
! 209: if (ptp->pg_flags & PG_BUSY)
! 210: panic("pmap_pde_release: busy page table page");
! 211: #endif
! 212: pdcache(HPPA_SID_KERNEL, (vaddr_t)ptp, PAGE_SIZE);
! 213: uvm_pagefree(ptp);
! 214: }
! 215: }
! 216:
! 217: static __inline pt_entry_t
! 218: pmap_pte_get(volatile pt_entry_t *pde, vaddr_t va)
! 219: {
! 220: DPRINTF(PDB_FOLLOW|PDB_VP,
! 221: ("pmap_pte_get(%p, 0x%lx)\n", pde, va));
! 222:
! 223: return (pde[(va & PTE_MASK) >> PTE_SHIFT]);
! 224: }
! 225:
! 226: static __inline void
! 227: pmap_pte_set(volatile pt_entry_t *pde, vaddr_t va, pt_entry_t pte)
! 228: {
! 229: DPRINTF(PDB_FOLLOW|PDB_VP,
! 230: ("pmap_pte_set(%p, 0x%lx, 0x%lx)\n", pde, va, pte));
! 231:
! 232: pde[(va & PTE_MASK) >> PTE_SHIFT] = pte;
! 233: }
! 234:
! 235: void
! 236: pmap_pte_flush(struct pmap *pmap, vaddr_t va, pt_entry_t pte)
! 237: {
! 238: if (pte & PTE_EXEC) {
! 239: ficache(pmap->pm_space, va, PAGE_SIZE);
! 240: pitlb(pmap->pm_space, va);
! 241: }
! 242: fdcache(pmap->pm_space, va, PAGE_SIZE);
! 243: pdtlb(pmap->pm_space, va);
! 244: }
! 245:
! 246: static __inline pt_entry_t
! 247: pmap_vp_find(struct pmap *pm, vaddr_t va)
! 248: {
! 249: volatile pt_entry_t *pde;
! 250:
! 251: if (!(pde = pmap_pde_get(pm->pm_pdir, va)))
! 252: return (0);
! 253:
! 254: return (pmap_pte_get(pde, va));
! 255: }
! 256:
! 257: #ifdef DDB
! 258: void
! 259: pmap_dump_table(pa_space_t space, vaddr_t sva)
! 260: {
! 261: pa_space_t sp;
! 262: volatile pt_entry_t *pde;
! 263: volatile u_int32_t *pd;
! 264: pt_entry_t pte;
! 265: vaddr_t va, pdemask;
! 266:
! 267: if (space)
! 268: pd = (u_int32_t *)mfctl(CR_VTOP);
! 269: else
! 270: pd = pmap_kernel()->pm_pdir;
! 271:
! 272: for (pdemask = 1, va = sva ? sva : 0;
! 273: va < VM_MAX_ADDRESS; va += PAGE_SIZE) {
! 274: if (pdemask != (va & (PDE_MASK|PIE_MASK))) {
! 275: pdemask = va & (PDE_MASK|PIE_MASK);
! 276: if (!(pde = pmap_pde_get(pd, va))) {
! 277: va += ~PDE_MASK + 1 - PAGE_SIZE;
! 278: continue;
! 279: }
! 280: printf("%x:%8p:\n", sp, pde);
! 281: }
! 282:
! 283: if (!(pte = pmap_pte_get(pde, va)))
! 284: continue;
! 285:
! 286: printf("0x%08lx-0x%08lx:%b\n",
! 287: va, PTE_PAGE(pte), PTE_GETBITS(pte), PTE_BITS);
! 288: }
! 289: }
! 290:
! 291: void
! 292: pmap_dump_pv(paddr_t pa)
! 293: {
! 294: struct vm_page *pg;
! 295: struct pv_entry *pve;
! 296:
! 297: pg = PHYS_TO_VM_PAGE(pa);
! 298: simple_lock(&pg->mdpage.pvh_lock);
! 299: for(pve = pg->mdpage.pvh_list; pve; pve = pve->pv_next)
! 300: printf("%x:%lx\n", pve->pv_pmap->pm_space, pve->pv_va);
! 301: simple_unlock(&pg->mdpage.pvh_lock);
! 302: }
! 303: #endif
! 304:
! 305: #ifdef PMAPDEBUG
! 306: int
! 307: pmap_check_alias(struct pv_entry *pve, vaddr_t va, pt_entry_t pte)
! 308: {
! 309: int ret;
! 310:
! 311: /* check for non-equ aliased mappings */
! 312: for (ret = 0; pve; pve = pve->pv_next) {
! 313: pte |= pmap_vp_find(pve->pv_pmap, pve->pv_va);
! 314: if ((va & HPPA_PGAOFF) != (pve->pv_va & HPPA_PGAOFF) &&
! 315: (pte & PTE_WRITE)) {
! 316: printf("pmap_check_alias: "
! 317: "aliased writable mapping 0x%x:0x%lx\n",
! 318: pve->pv_pmap->pm_space, pve->pv_va);
! 319: ret++;
! 320: }
! 321: }
! 322:
! 323: return (ret);
! 324: }
! 325: #endif
! 326:
! 327: static __inline struct pv_entry *
! 328: pmap_pv_alloc(void)
! 329: {
! 330: struct pv_entry *pv;
! 331:
! 332: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_alloc()\n"));
! 333:
! 334: pv = pool_get(&pmap_pv_pool, PR_NOWAIT);
! 335:
! 336: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_alloc: %p\n", pv));
! 337:
! 338: return (pv);
! 339: }
! 340:
! 341: void
! 342: pmap_pv_free(struct pv_entry *pv)
! 343: {
! 344: if (pv->pv_ptp)
! 345: pmap_pde_release(pv->pv_pmap, pv->pv_va, pv->pv_ptp);
! 346:
! 347: pool_put(&pmap_pv_pool, pv);
! 348: }
! 349:
! 350: void
! 351: pmap_pv_enter(struct vm_page *pg, struct pv_entry *pve, struct pmap *pm,
! 352: vaddr_t va, struct vm_page *pdep)
! 353: {
! 354: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_enter(%p, %p, %p, 0x%lx, %p)\n",
! 355: pg, pve, pm, va, pdep));
! 356: pve->pv_pmap = pm;
! 357: pve->pv_va = va;
! 358: pve->pv_ptp = pdep;
! 359: pve->pv_next = pg->mdpage.pvh_list;
! 360: pg->mdpage.pvh_list = pve;
! 361: #ifdef PMAPDEBUG
! 362: if (pmap_check_alias(pve, va, 0))
! 363: Debugger();
! 364: #endif
! 365: }
! 366:
! 367: struct pv_entry *
! 368: pmap_pv_remove(struct vm_page *pg, struct pmap *pmap, vaddr_t va)
! 369: {
! 370: struct pv_entry **pve, *pv;
! 371:
! 372: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_pv_remove(%p, %p, 0x%lx)\n",
! 373: pg, pmap, va));
! 374:
! 375: simple_lock(&pg->mdpage.pvh_lock); /* lock pv_head */
! 376: for(pv = *(pve = &pg->mdpage.pvh_list);
! 377: pv; pv = *(pve = &(*pve)->pv_next))
! 378: if (pv->pv_pmap == pmap && pv->pv_va == va) {
! 379: *pve = pv->pv_next;
! 380: break;
! 381: }
! 382: simple_unlock(&pg->mdpage.pvh_lock); /* unlock, done! */
! 383: return (pv);
! 384: }
! 385:
! 386: const pt_entry_t hppa_pgs[] = {
! 387: PTE_PG4K,
! 388: PTE_PG16K,
! 389: PTE_PG64K,
! 390: PTE_PG256K,
! 391: PTE_PG1M,
! 392: PTE_PG4M,
! 393: PTE_PG16M,
! 394: PTE_PG64M
! 395: };
! 396: #define nhppa_pgs sizeof(hppa_pgs)/sizeof(hppa_pgs[0])
! 397:
! 398: void
! 399: pmap_maphys(paddr_t spa, paddr_t epa)
! 400: {
! 401: volatile pt_entry_t *pde, *epde, pte;
! 402: paddr_t pa, tpa;
! 403: int s, e, i;
! 404:
! 405: DPRINTF(PDB_INIT, ("pmap_maphys: mapping 0x%lx - 0x%lx\n", spa, epa));
! 406:
! 407: s = ffs(spa) - 12;
! 408: e = ffs(epa) - 12;
! 409:
! 410: if (s < e || (s == e && s / 2 < nhppa_pgs)) {
! 411: i = s / 2;
! 412: if (i > nhppa_pgs)
! 413: i = nhppa_pgs;
! 414: pa = spa;
! 415: spa = tpa = 0x1000 << ((i + 1) * 2);
! 416: } else if (s > e) {
! 417: i = e / 2;
! 418: if (i > nhppa_pgs)
! 419: i = nhppa_pgs;
! 420: epa = pa = epa & (0xfffff000 << ((i + 1) * 2));
! 421: tpa = epa;
! 422: } else {
! 423: i = s / 2;
! 424: if (i > nhppa_pgs)
! 425: i = nhppa_pgs;
! 426: pa = spa;
! 427: spa = tpa = epa;
! 428: }
! 429:
! 430: printf("pa 0x%lx tpa 0x%lx\n", pa, tpa);
! 431: while (pa < tpa) {
! 432: pte = TLB_PAGE(pa) | hppa_pgs[i - 1] |
! 433: PTE_WRITE | PTE_ORDER | PTE_DIRTY | PTE_WIRED;
! 434: pde = pmap_pde_get(pmap_kernel()->pm_pdir, pa);
! 435: epde = pde + (PTE_MASK >> PTE_SHIFT) + 1;
! 436: if (pa + (PTE_MASK + (1 << PTE_SHIFT)) > tpa)
! 437: epde = pde + ((tpa & PTE_MASK) >> PTE_SHIFT);
! 438: printf("pde %p epde %p pte 0x%lx\n", pde, epde, pte);
! 439: for (pde += (pa & PTE_MASK) >> PTE_SHIFT; pde < epde;)
! 440: *pde++ = pte;
! 441: pa += PTE_MASK + (1 << PTE_SHIFT);
! 442: pa &= ~(PTE_MASK | PAGE_MASK);
! 443: }
! 444:
! 445: if (spa < epa)
! 446: pmap_maphys(spa, epa);
! 447: }
! 448:
! 449: void
! 450: pmap_bootstrap(vstart)
! 451: vaddr_t vstart;
! 452: {
! 453: extern int resvphysmem, __rodata_end, __data_start;
! 454: vaddr_t va, eaddr, addr = round_page(vstart);
! 455: struct pmap *kpm;
! 456:
! 457: DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_bootstrap(0x%lx)\n", vstart));
! 458:
! 459: uvm_setpagesize();
! 460:
! 461: hppa_prot[UVM_PROT_NONE] = PTE_ORDER|PTE_ACC_NONE;
! 462: hppa_prot[UVM_PROT_READ] = PTE_ORDER|PTE_READ;
! 463: hppa_prot[UVM_PROT_WRITE] = PTE_ORDER|PTE_WRITE;
! 464: hppa_prot[UVM_PROT_RW] = PTE_ORDER|PTE_READ|PTE_WRITE;
! 465: hppa_prot[UVM_PROT_EXEC] = PTE_ORDER|PTE_EXEC;
! 466: hppa_prot[UVM_PROT_RX] = PTE_ORDER|PTE_READ|PTE_EXEC;
! 467: hppa_prot[UVM_PROT_WX] = PTE_ORDER|PTE_WRITE|PTE_EXEC;
! 468: hppa_prot[UVM_PROT_RWX] = PTE_ORDER|PTE_READ|PTE_WRITE|PTE_EXEC;
! 469:
! 470: /*
! 471: * Initialize kernel pmap
! 472: */
! 473: kpm = &kernel_pmap_store;
! 474: bzero(kpm, sizeof(*kpm));
! 475: simple_lock_init(&kpm->pm_lock);
! 476: kpm->pm_refcount = 1;
! 477: kpm->pm_space = HPPA_SID_KERNEL;
! 478: TAILQ_INIT(&kpm->pm_pglist);
! 479: kpm->pm_pdir = (u_int32_t *)mfctl(CR_VTOP);
! 480:
! 481: /*
! 482: * Allocate various tables and structures.
! 483: */
! 484:
! 485: if (&__rodata_end < &__data_start) {
! 486: physical_steal = (vaddr_t)&__rodata_end;
! 487: physical_end = (vaddr_t)&__data_start;
! 488: DPRINTF(PDB_INIT, ("physpool: 0x%lx @ 0x%lx\n",
! 489: physical_end - physical_steal, physical_steal));
! 490: }
! 491:
! 492: /* map enough PDEs to map initial physmem */
! 493: for (va = 0x1000000, eaddr = ptoa(physmem);
! 494: va < eaddr; addr += PAGE_SIZE, va += 1 << PDE_SHIFT) {
! 495: bzero((void *)addr, PAGE_SIZE);
! 496: pmap_pde_set(kpm, va, addr);
! 497: kpm->pm_stats.resident_count++; /* count PTP as resident */
! 498: }
! 499:
! 500: /* map a little of initial kmem */
! 501: for (va = VM_MIN_KERNEL_ADDRESS + ((pmap_nkpdes - 1) << PDE_SHIFT);
! 502: va >= VM_MIN_KERNEL_ADDRESS;
! 503: addr += PAGE_SIZE, va -= 1 << PDE_SHIFT) {
! 504: bzero((void *)addr, PAGE_SIZE);
! 505: pmap_pde_set(kpm, va, addr);
! 506: kpm->pm_stats.resident_count++; /* count PTP as resident */
! 507: }
! 508:
! 509: pmap_maphys(0x1000000, ctob(physmem));
! 510:
! 511: eaddr = physmem - atop(round_page(MSGBUFSIZE));
! 512: resvphysmem = atop(addr);
! 513: DPRINTF(PDB_INIT, ("physmem: 0x%lx - 0x%lx\n", resvphysmem, eaddr));
! 514: uvm_page_physload(0, physmem,
! 515: resvphysmem, eaddr, VM_FREELIST_DEFAULT);
! 516: }
! 517:
! 518: void
! 519: pmap_init()
! 520: {
! 521: DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_init()\n"));
! 522:
! 523: pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl",
! 524: &pool_allocator_nointr);
! 525: pool_init(&pmap_pv_pool, sizeof(struct pv_entry),0,0,0, "pmappv", NULL);
! 526: pool_setlowat(&pmap_pv_pool, pmap_pvlowat);
! 527: pool_sethiwat(&pmap_pv_pool, pmap_pvlowat * 32);
! 528:
! 529: pmap_initialized = 1;
! 530:
! 531: DPRINTF(PDB_FOLLOW|PDB_INIT, ("pmap_init(): done\n"));
! 532: }
! 533:
! 534: #ifdef PMAP_STEAL_MEMORY
! 535: vaddr_t
! 536: pmap_steal_memory(vsize_t size, vaddr_t *vstartp, vaddr_t *vendp)
! 537: {
! 538: vaddr_t va;
! 539: int npg;
! 540:
! 541: DPRINTF(PDB_FOLLOW|PDB_PHYS,
! 542: ("pmap_steal_memory(0x%lx, %p, %p)\n", size, vstartp, vendp));
! 543:
! 544: size = round_page(size);
! 545: npg = atop(size);
! 546:
! 547: if (vm_physmem[0].avail_end - vm_physmem[0].avail_start < npg)
! 548: panic("pmap_steal_memory: no more");
! 549:
! 550: if (vstartp)
! 551: *vstartp = VM_MIN_KERNEL_ADDRESS;
! 552: if (vendp)
! 553: *vendp = VM_MAX_KERNEL_ADDRESS;
! 554:
! 555: vm_physmem[0].end -= npg;
! 556: vm_physmem[0].avail_end -= npg;
! 557: va = ptoa(vm_physmem[0].avail_end) - size;
! 558: bzero((void *)va, size);
! 559:
! 560: DPRINTF(PDB_FOLLOW|PDB_PHYS, ("pmap_steal_memory: 0x%lx\n", va));
! 561:
! 562: return (va);
! 563: }
! 564: #else
! 565: void
! 566: pmap_virtual_space(vaddr_t *startp, vaddr_t *endp)
! 567: {
! 568: *startp = VM_MIN_KERNEL_ADDRESS;
! 569: *endp = VM_MAX_KERNEL_ADDRESS;
! 570: }
! 571: #endif /* PMAP_STEAL_MEMORY */
! 572:
! 573: #ifdef PMAP_GROWKERNEL
! 574: vaddr_t
! 575: pmap_growkernel(vaddr_t kva)
! 576: {
! 577: vaddr_t va;
! 578:
! 579: DPRINTF(PDB_FOLLOW|PDB_PHYS, ("pmap_growkernel(0x%lx)\n", kva));
! 580:
! 581: va = VM_MIN_KERNEL_ADDRESS + (pmap_nkpdes << PDE_SHIFT);
! 582: DPRINTF(PDB_PHYS, ("pmap_growkernel: was va 0x%lx\n", va));
! 583: if (va < kva) {
! 584: simple_lock(&pmap_kernel()->pm_obj.vmobjlock);
! 585:
! 586: for ( ; va < kva ; pmap_nkpdes++, va += 1 << PDE_SHIFT)
! 587: if (uvm.page_init_done) {
! 588: if (!pmap_pde_alloc(pmap_kernel(), va, NULL))
! 589: break;
! 590: } else {
! 591: paddr_t pa;
! 592:
! 593: pa = pmap_steal_memory(PAGE_SIZE, NULL, NULL);
! 594: if (pa)
! 595: panic("pmap_growkernel: out of memory");
! 596: pmap_pde_set(pmap_kernel(), va, pa);
! 597: pmap_kernel()->pm_stats.resident_count++;
! 598: }
! 599:
! 600: simple_unlock(&pmap_kernel()->pm_obj.vmobjlock);
! 601: }
! 602: DPRINTF(PDB_PHYS|PDB_VP, ("pmap_growkernel: now va 0x%lx\n", va));
! 603: return (va);
! 604: }
! 605: #endif /* PMAP_GROWKERNEL */
! 606:
! 607: struct pmap *
! 608: pmap_create()
! 609: {
! 610: struct pmap *pmap;
! 611: struct vm_page *pg;
! 612: pa_space_t space;
! 613: paddr_t pa;
! 614:
! 615: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_create()\n"));
! 616:
! 617: pmap = pool_get(&pmap_pmap_pool, PR_WAITOK);
! 618:
! 619: simple_lock_init(&pmap->pm_lock);
! 620: pmap->pm_refcount = 1;
! 621: pmap->pm_ptphint = NULL;
! 622:
! 623: TAILQ_INIT(&pmap->pm_pglist);
! 624: if (uvm_pglistalloc(2 * PAGE_SIZE, 0, VM_MIN_KERNEL_ADDRESS,
! 625: PAGE_SIZE, 2 * PAGE_SIZE, &pmap->pm_pglist, 1, 1))
! 626: panic("pmap_create: no pages");
! 627:
! 628: pg = TAILQ_FIRST(&pmap->pm_pglist);
! 629: atomic_clearbits_int(&pg->pg_flags, PG_BUSY|PG_CLEAN);
! 630: pmap->pm_pdir = (u_int32_t *)(pa = VM_PAGE_TO_PHYS(pg));
! 631: bzero((void *)pa, PAGE_SIZE);
! 632:
! 633: /* set the first PIE that's covering low 2g of the address space */
! 634: pg = TAILQ_LAST(&pmap->pm_pglist, pglist);
! 635: atomic_clearbits_int(&pg->pg_flags, PG_BUSY|PG_CLEAN);
! 636: *pmap->pm_pdir = (pa = VM_PAGE_TO_PHYS(pg)) >> PAGE_SHIFT;
! 637: bzero((void *)pa, PAGE_SIZE);
! 638:
! 639: /* TODO for (space = 1 + (arc4random() & HPPA_SID_MAX);
! 640: pmap_sdir_get(space); space = (space + 1) % HPPA_SID_MAX); */
! 641: pmap->pm_space = space;
! 642:
! 643: pmap->pm_stats.resident_count = 2;
! 644: pmap->pm_stats.wired_count = 0;
! 645:
! 646: return (pmap);
! 647: }
! 648:
! 649: void
! 650: pmap_destroy(pmap)
! 651: struct pmap *pmap;
! 652: {
! 653: int refs;
! 654:
! 655: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_destroy(%p)\n", pmap));
! 656:
! 657: simple_lock(&pmap->pm_lock);
! 658: refs = --pmap->pm_refcount;
! 659: simple_unlock(&pmap->pm_lock);
! 660:
! 661: if (refs > 0)
! 662: return;
! 663:
! 664: uvm_pglistfree(&pmap->pm_pglist);
! 665: TAILQ_INIT(&pmap->pm_pglist);
! 666: pool_put(&pmap_pmap_pool, pmap);
! 667: }
! 668:
! 669: /*
! 670: * Add a reference to the specified pmap.
! 671: */
! 672: void
! 673: pmap_reference(struct pmap *pmap)
! 674: {
! 675: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_reference(%p)\n", pmap));
! 676:
! 677: simple_lock(&pmap->pm_lock);
! 678: pmap->pm_refcount++;
! 679: simple_unlock(&pmap->pm_lock);
! 680: }
! 681:
! 682: void
! 683: pmap_collect(struct pmap *pmap)
! 684: {
! 685: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_collect(%p)\n", pmap));
! 686: /* nothing yet */
! 687: }
! 688:
! 689: int
! 690: pmap_enter(pmap, va, pa, prot, flags)
! 691: struct pmap *pmap;
! 692: vaddr_t va;
! 693: paddr_t pa;
! 694: vm_prot_t prot;
! 695: int flags;
! 696: {
! 697: volatile pt_entry_t *pde;
! 698: pt_entry_t pte;
! 699: struct vm_page *pg, *ptp = NULL;
! 700: struct pv_entry *pve;
! 701: boolean_t wired = (flags & PMAP_WIRED) != 0;
! 702:
! 703: DPRINTF(PDB_FOLLOW|PDB_ENTER,
! 704: ("pmap_enter(%p, 0x%lx, 0x%lx, 0x%x, 0x%x)\n",
! 705: pmap, va, pa, prot, flags));
! 706:
! 707: simple_lock(&pmap->pm_lock);
! 708:
! 709: if (!(pde = pmap_pde_get(pmap->pm_pdir, va)) &&
! 710: !(pde = pmap_pde_alloc(pmap, va, &ptp))) {
! 711: if (flags & PMAP_CANFAIL) {
! 712: simple_unlock(&pmap->pm_lock);
! 713: return (ENOMEM);
! 714: }
! 715:
! 716: panic("pmap_enter: cannot allocate pde");
! 717: }
! 718:
! 719: if (!ptp)
! 720: ptp = pmap_pde_ptp(pmap, pde);
! 721:
! 722: if ((pte = pmap_pte_get(pde, va))) {
! 723:
! 724: DPRINTF(PDB_ENTER,
! 725: ("pmap_enter: remapping 0x%lx -> 0x%lx\n", pte, pa));
! 726:
! 727: pmap_pte_flush(pmap, va, pte);
! 728: if (wired && !(pte & PTE_WIRED))
! 729: pmap->pm_stats.wired_count++;
! 730: else if (!wired && (pte & PTE_WIRED))
! 731: pmap->pm_stats.wired_count--;
! 732: pte &= PTE_UNCACHABLE|PTE_DIRTY|PTE_REFTRAP;
! 733:
! 734: if (PTE_PAGE(pte) == pa) {
! 735: DPRINTF(PDB_FOLLOW|PDB_ENTER,
! 736: ("pmap_enter: same page\n"));
! 737: goto enter;
! 738: }
! 739:
! 740: pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte));
! 741: simple_lock(&pg->mdpage.pvh_lock);
! 742: pve = pmap_pv_remove(pg, pmap, va);
! 743: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 744: } else {
! 745: DPRINTF(PDB_ENTER,
! 746: ("pmap_enter: new mapping 0x%lx -> 0x%lx\n", va, pa));
! 747: pte = PTE_REFTRAP;
! 748: pve = NULL;
! 749: pmap->pm_stats.resident_count++;
! 750: if (wired)
! 751: pmap->pm_stats.wired_count++;
! 752: if (ptp)
! 753: ptp->wire_count++;
! 754: simple_lock(&pg->mdpage.pvh_lock);
! 755: }
! 756:
! 757: if (pmap_initialized && (pg = PHYS_TO_VM_PAGE(pa))) {
! 758: if (!pve && !(pve = pmap_pv_alloc())) {
! 759: if (flags & PMAP_CANFAIL) {
! 760: simple_unlock(&pg->mdpage.pvh_lock);
! 761: simple_unlock(&pmap->pm_lock);
! 762: return (ENOMEM);
! 763: }
! 764: panic("pmap_enter: no pv entries available");
! 765: }
! 766: pmap_pv_enter(pg, pve, pmap, va, ptp);
! 767: } else if (pve)
! 768: pmap_pv_free(pve);
! 769: simple_unlock(&pg->mdpage.pvh_lock);
! 770:
! 771: enter:
! 772: /* preserve old ref & mod */
! 773: pte = TLB_PAGE(pa) | pmap_prot(pmap, prot);
! 774: if (wired)
! 775: pte |= PTE_WIRED;
! 776: pmap_pte_set(pde, va, pte);
! 777:
! 778: simple_unlock(&pmap->pm_lock);
! 779:
! 780: DPRINTF(PDB_FOLLOW|PDB_ENTER, ("pmap_enter: leaving\n"));
! 781:
! 782: return (0);
! 783: }
! 784:
! 785: void
! 786: pmap_remove(pmap, sva, eva)
! 787: struct pmap *pmap;
! 788: vaddr_t sva;
! 789: vaddr_t eva;
! 790: {
! 791: struct pv_entry *pve;
! 792: volatile pt_entry_t *pde;
! 793: pt_entry_t pte;
! 794: struct vm_page *pg;
! 795: vaddr_t pdemask;
! 796: int batch;
! 797:
! 798: DPRINTF(PDB_FOLLOW|PDB_REMOVE,
! 799: ("pmap_remove(%p, 0x%lx, 0x%lx)\n", pmap, sva, eva));
! 800:
! 801: simple_lock(&pmap->pm_lock);
! 802:
! 803: for (batch = 0, pdemask = 1; sva < eva; sva += PAGE_SIZE) {
! 804: if (pdemask != (sva & PDE_MASK)) {
! 805: pdemask = sva & PDE_MASK;
! 806: if (!(pde = pmap_pde_get(pmap->pm_pdir, sva))) {
! 807: sva += ~PDE_MASK + 1 - PAGE_SIZE;
! 808: continue;
! 809: }
! 810: batch = pdemask == sva && sva + ~PDE_MASK + 1 <= eva;
! 811: }
! 812:
! 813: if ((pte = pmap_pte_get(pde, sva))) {
! 814:
! 815: /* TODO measure here the speed tradeoff
! 816: * for flushing whole PT vs per-page
! 817: * in case of non-complete pde fill
! 818: */
! 819: pmap_pte_flush(pmap, sva, pte);
! 820: if (pte & PTE_WIRED)
! 821: pmap->pm_stats.wired_count--;
! 822: pmap->pm_stats.resident_count--;
! 823:
! 824: /* iff properly accounted pde will be dropped anyway */
! 825: if (!batch)
! 826: pmap_pte_set(pde, sva, 0);
! 827:
! 828: if (pmap_initialized &&
! 829: (pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte)))) {
! 830:
! 831: simple_lock(&pg->mdpage.pvh_lock);
! 832: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 833: if ((pve = pmap_pv_remove(pg, pmap, sva)))
! 834: pmap_pv_free(pve);
! 835: simple_unlock(&pg->mdpage.pvh_lock);
! 836: }
! 837: }
! 838: }
! 839:
! 840: simple_unlock(&pmap->pm_lock);
! 841:
! 842: DPRINTF(PDB_FOLLOW|PDB_REMOVE, ("pmap_remove: leaving\n"));
! 843: }
! 844:
! 845: void
! 846: pmap_write_protect(pmap, sva, eva, prot)
! 847: struct pmap *pmap;
! 848: vaddr_t sva;
! 849: vaddr_t eva;
! 850: vm_prot_t prot;
! 851: {
! 852: struct vm_page *pg;
! 853: volatile pt_entry_t *pde;
! 854: pt_entry_t pte;
! 855: u_int tlbprot, pdemask;
! 856:
! 857: DPRINTF(PDB_FOLLOW|PDB_PMAP,
! 858: ("pmap_write_protect(%p, %lx, %lx, %x)\n", pmap, sva, eva, prot));
! 859:
! 860: sva = trunc_page(sva);
! 861: tlbprot = pmap_prot(pmap, prot);
! 862:
! 863: simple_lock(&pmap->pm_lock);
! 864:
! 865: for (pdemask = 1; sva < eva; sva += PAGE_SIZE) {
! 866: if (pdemask != (sva & PDE_MASK)) {
! 867: pdemask = sva & PDE_MASK;
! 868: if (!(pde = pmap_pde_get(pmap->pm_pdir, sva))) {
! 869: sva += ~PDE_MASK + 1 - PAGE_SIZE;
! 870: continue;
! 871: }
! 872: }
! 873: if ((pte = pmap_pte_get(pde, sva))) {
! 874:
! 875: DPRINTF(PDB_PMAP,
! 876: ("pmap_write_protect: va=0x%lx pte=0x%lx\n",
! 877: sva, pte));
! 878: /*
! 879: * Determine if mapping is changing.
! 880: * If not, nothing to do.
! 881: */
! 882: if ((pte & PTE_ACC_MASK) == tlbprot)
! 883: continue;
! 884:
! 885: pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte));
! 886: simple_lock(&pg->mdpage.pvh_lock);
! 887: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 888: simple_unlock(&pg->mdpage.pvh_lock);
! 889:
! 890: pmap_pte_flush(pmap, sva, pte);
! 891: pte &= ~PTE_ACC_MASK;
! 892: pte |= tlbprot;
! 893: pmap_pte_set(pde, sva, pte);
! 894: }
! 895: }
! 896:
! 897: simple_unlock(&pmap->pm_lock);
! 898: }
! 899:
! 900: void
! 901: pmap_page_remove(pg)
! 902: struct vm_page *pg;
! 903: {
! 904: struct pv_entry *pve, *ppve;
! 905:
! 906: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_page_remove(%p)\n", pg));
! 907:
! 908: if (pg->mdpage.pvh_list == NULL)
! 909: return;
! 910:
! 911: simple_lock(&pg->mdpage.pvh_lock);
! 912: for (pve = pg->mdpage.pvh_list; pve;
! 913: pve = (ppve = pve)->pv_next, pmap_pv_free(ppve)) {
! 914: struct pmap *pmap = pve->pv_pmap;
! 915: vaddr_t va = pve->pv_va;
! 916: volatile pt_entry_t *pde;
! 917: pt_entry_t pte;
! 918:
! 919: simple_lock(&pmap->pm_lock);
! 920:
! 921: pde = pmap_pde_get(pmap->pm_pdir, va);
! 922: pte = pmap_pte_get(pde, va);
! 923: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 924:
! 925: pmap_pte_flush(pmap, va, pte);
! 926: if (pte & PTE_WIRED)
! 927: pmap->pm_stats.wired_count--;
! 928: pmap->pm_stats.resident_count--;
! 929:
! 930: pmap_pte_set(pde, va, 0);
! 931: simple_unlock(&pmap->pm_lock);
! 932: }
! 933: pg->mdpage.pvh_list = NULL;
! 934: simple_unlock(&pg->mdpage.pvh_lock);
! 935:
! 936: DPRINTF(PDB_FOLLOW|PDB_PV, ("pmap_page_remove: leaving\n"));
! 937:
! 938: }
! 939:
! 940: void
! 941: pmap_unwire(pmap, va)
! 942: struct pmap *pmap;
! 943: vaddr_t va;
! 944: {
! 945: volatile pt_entry_t *pde;
! 946: pt_entry_t pte = 0;
! 947:
! 948: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_unwire(%p, 0x%lx)\n", pmap, va));
! 949:
! 950: simple_lock(&pmap->pm_lock);
! 951: if ((pde = pmap_pde_get(pmap->pm_pdir, va))) {
! 952: pte = pmap_pte_get(pde, va);
! 953:
! 954: if (pte & PTE_WIRED) {
! 955: pte &= ~PTE_WIRED;
! 956: pmap->pm_stats.wired_count--;
! 957: pmap_pte_set(pde, va, pte);
! 958: }
! 959: }
! 960: simple_unlock(&pmap->pm_lock);
! 961:
! 962: DPRINTF(PDB_FOLLOW|PDB_PMAP, ("pmap_unwire: leaving\n"));
! 963:
! 964: #ifdef DIAGNOSTIC
! 965: if (!pte)
! 966: panic("pmap_unwire: invalid va 0x%lx", va);
! 967: #endif
! 968: }
! 969:
! 970: boolean_t
! 971: pmap_changebit(struct vm_page *pg, pt_entry_t set, pt_entry_t clear)
! 972: {
! 973: struct pv_entry *pve;
! 974: pt_entry_t res;
! 975:
! 976: DPRINTF(PDB_FOLLOW|PDB_BITS,
! 977: ("pmap_changebit(%p, %lx, %lx)\n", pg, set, clear));
! 978:
! 979: simple_lock(&pg->mdpage.pvh_lock);
! 980: res = pg->mdpage.pvh_attrs = 0;
! 981: for(pve = pg->mdpage.pvh_list; pve; pve = pve->pv_next) {
! 982: struct pmap *pmap = pve->pv_pmap;
! 983: vaddr_t va = pve->pv_va;
! 984: volatile pt_entry_t *pde;
! 985: pt_entry_t opte, pte;
! 986:
! 987: simple_lock(&pmap->pm_lock);
! 988: if ((pde = pmap_pde_get(pmap->pm_pdir, va))) {
! 989: opte = pte = pmap_pte_get(pde, va);
! 990: #ifdef PMAPDEBUG
! 991: if (!pte) {
! 992: printf("pmap_changebit: zero pte for 0x%lx\n",
! 993: va);
! 994: continue;
! 995: }
! 996: #endif
! 997: pte &= ~clear;
! 998: pte |= set;
! 999: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 1000: res |= pmap_pvh_attrs(opte);
! 1001:
! 1002: if (opte != pte) {
! 1003: pmap_pte_flush(pmap, va, opte);
! 1004: pmap_pte_set(pde, va, pte);
! 1005: }
! 1006: }
! 1007: simple_unlock(&pmap->pm_lock);
! 1008: }
! 1009: simple_unlock(&pg->mdpage.pvh_lock);
! 1010:
! 1011: return ((res & (clear | set)) != 0);
! 1012: }
! 1013:
! 1014: boolean_t
! 1015: pmap_testbit(struct vm_page *pg, pt_entry_t bit)
! 1016: {
! 1017: struct pv_entry *pve;
! 1018: pt_entry_t pte;
! 1019:
! 1020: DPRINTF(PDB_FOLLOW|PDB_BITS, ("pmap_testbit(%p, %lx)\n", pg, bit));
! 1021:
! 1022: simple_lock(&pg->mdpage.pvh_lock);
! 1023: for(pve = pg->mdpage.pvh_list; !(pg->mdpage.pvh_attrs & bit) && pve;
! 1024: pve = pve->pv_next) {
! 1025: simple_lock(&pve->pv_pmap->pm_lock);
! 1026: pte = pmap_vp_find(pve->pv_pmap, pve->pv_va);
! 1027: simple_unlock(&pve->pv_pmap->pm_lock);
! 1028: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 1029: }
! 1030: simple_unlock(&pg->mdpage.pvh_lock);
! 1031:
! 1032: return ((pg->mdpage.pvh_attrs & bit) != 0);
! 1033: }
! 1034:
! 1035: boolean_t
! 1036: pmap_extract(pmap, va, pap)
! 1037: struct pmap *pmap;
! 1038: vaddr_t va;
! 1039: paddr_t *pap;
! 1040: {
! 1041: pt_entry_t pte;
! 1042:
! 1043: DPRINTF(PDB_FOLLOW|PDB_EXTRACT, ("pmap_extract(%p, %lx)\n", pmap, va));
! 1044:
! 1045: simple_lock(&pmap->pm_lock);
! 1046: pte = pmap_vp_find(pmap, va);
! 1047: simple_unlock(&pmap->pm_lock);
! 1048:
! 1049: if (pte) {
! 1050: if (pap)
! 1051: *pap = PTE_PAGE(pte) | (va & PAGE_MASK);
! 1052: return (TRUE);
! 1053: }
! 1054:
! 1055: return (FALSE);
! 1056: }
! 1057:
! 1058: void
! 1059: pmap_activate(struct proc *p)
! 1060: {
! 1061: struct pmap *pmap = p->p_vmspace->vm_map.pmap;
! 1062: struct pcb *pcb = &p->p_addr->u_pcb;
! 1063:
! 1064: pcb->pcb_space = pmap->pm_space;
! 1065: pcb->pcb_uva = (vaddr_t)p->p_addr;
! 1066: }
! 1067:
! 1068: void
! 1069: pmap_deactivate(struct proc *p)
! 1070: {
! 1071:
! 1072: }
! 1073:
! 1074: static __inline void
! 1075: pmap_flush_page(struct vm_page *pg, int purge)
! 1076: {
! 1077: struct pv_entry *pve;
! 1078:
! 1079: /* purge cache for all possible mappings for the pa */
! 1080: simple_lock(&pg->mdpage.pvh_lock);
! 1081: for(pve = pg->mdpage.pvh_list; pve; pve = pve->pv_next)
! 1082: if (purge)
! 1083: pdcache(pve->pv_pmap->pm_space, pve->pv_va, PAGE_SIZE);
! 1084: else
! 1085: fdcache(pve->pv_pmap->pm_space, pve->pv_va, PAGE_SIZE);
! 1086: simple_unlock(&pg->mdpage.pvh_lock);
! 1087: }
! 1088:
! 1089: void
! 1090: pmap_zero_page(struct vm_page *pg)
! 1091: {
! 1092: paddr_t pa = VM_PAGE_TO_PHYS(pg);
! 1093:
! 1094: DPRINTF(PDB_FOLLOW|PDB_PHYS, ("pmap_zero_page(%lx)\n", pa));
! 1095:
! 1096: pmap_flush_page(pg, 1);
! 1097: bzero((void *)pa, PAGE_SIZE);
! 1098: fdcache(HPPA_SID_KERNEL, pa, PAGE_SIZE);
! 1099: }
! 1100:
! 1101: void
! 1102: pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
! 1103: {
! 1104: paddr_t spa = VM_PAGE_TO_PHYS(srcpg);
! 1105: paddr_t dpa = VM_PAGE_TO_PHYS(dstpg);
! 1106: DPRINTF(PDB_FOLLOW|PDB_PHYS, ("pmap_copy_page(%lx, %lx)\n", spa, dpa));
! 1107:
! 1108: pmap_flush_page(srcpg, 0);
! 1109: pmap_flush_page(dstpg, 1);
! 1110: bcopy((void *)spa, (void *)dpa, PAGE_SIZE);
! 1111: pdcache(HPPA_SID_KERNEL, spa, PAGE_SIZE);
! 1112: fdcache(HPPA_SID_KERNEL, dpa, PAGE_SIZE);
! 1113: }
! 1114:
! 1115: void
! 1116: pmap_kenter_pa(va, pa, prot)
! 1117: vaddr_t va;
! 1118: paddr_t pa;
! 1119: vm_prot_t prot;
! 1120: {
! 1121: volatile pt_entry_t *pde;
! 1122: pt_entry_t pte, opte;
! 1123:
! 1124: DPRINTF(PDB_FOLLOW|PDB_ENTER,
! 1125: ("pmap_kenter_pa(%lx, %lx, %x)\n", va, pa, prot));
! 1126:
! 1127: simple_lock(&pmap->pm_lock);
! 1128:
! 1129: if (!(pde = pmap_pde_get(pmap_kernel()->pm_pdir, va)) &&
! 1130: !(pde = pmap_pde_alloc(pmap_kernel(), va, NULL)))
! 1131: panic("pmap_kenter_pa: cannot allocate pde for va=0x%lx", va);
! 1132: opte = pmap_pte_get(pde, va);
! 1133: pte = TLB_PAGE(pa) | PTE_WIRED | PTE_REFTRAP |
! 1134: pmap_prot(pmap_kernel(), prot);
! 1135: if (pa >= 0xf0000000ULL /* TODO (HPPA_IOBEGIN & HPPA_PHYSMAP) */)
! 1136: pte |= PTE_UNCACHABLE | PTE_ORDER;
! 1137: DPRINTF(PDB_ENTER, ("pmap_kenter_pa: pde %p va %lx pte %lx\n",
! 1138: pde, va, pte));
! 1139: pmap_pte_set(pde, va, pte);
! 1140: pmap_kernel()->pm_stats.wired_count++;
! 1141: pmap_kernel()->pm_stats.resident_count++;
! 1142: if (opte)
! 1143: pmap_pte_flush(pmap_kernel(), va, opte);
! 1144:
! 1145: #ifdef PMAPDEBUG
! 1146: {
! 1147: struct vm_page *pg;
! 1148:
! 1149: if (pmap_initialized && (pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte)))) {
! 1150:
! 1151: simple_lock(&pg->mdpage.pvh_lock);
! 1152: if (pmap_check_alias(pg->mdpage.pvh_list, va, pte))
! 1153: Debugger();
! 1154: simple_unlock(&pg->mdpage.pvh_lock);
! 1155: }
! 1156: }
! 1157: #endif
! 1158: simple_unlock(&pmap->pm_lock);
! 1159:
! 1160: DPRINTF(PDB_FOLLOW|PDB_ENTER, ("pmap_kenter_pa: leaving\n"));
! 1161: }
! 1162:
! 1163: void
! 1164: pmap_kremove(va, size)
! 1165: vaddr_t va;
! 1166: vsize_t size;
! 1167: {
! 1168: struct pv_entry *pve;
! 1169: vaddr_t eva, pdemask;
! 1170: volatile pt_entry_t *pde;
! 1171: pt_entry_t pte;
! 1172: struct vm_page *pg;
! 1173:
! 1174: DPRINTF(PDB_FOLLOW|PDB_REMOVE,
! 1175: ("pmap_kremove(%lx, %lx)\n", va, size));
! 1176: #ifdef PMAPDEBUG
! 1177: if (va < ptoa(physmem)) {
! 1178: printf("pmap_kremove(%lx, %lx): unmapping physmem\n", va, size);
! 1179: return;
! 1180: }
! 1181: #endif
! 1182:
! 1183: simple_lock(&pmap->pm_lock);
! 1184:
! 1185: for (pdemask = 1, eva = va + size; va < eva; va += PAGE_SIZE) {
! 1186: if (pdemask != (va & PDE_MASK)) {
! 1187: pdemask = va & PDE_MASK;
! 1188: if (!(pde = pmap_pde_get(pmap_kernel()->pm_pdir, va))) {
! 1189: va += ~PDE_MASK + 1 - PAGE_SIZE;
! 1190: continue;
! 1191: }
! 1192: }
! 1193: if (!(pte = pmap_pte_get(pde, va))) {
! 1194: #ifdef DEBUG
! 1195: printf("pmap_kremove: unmapping unmapped 0x%lx\n", va);
! 1196: #endif
! 1197: continue;
! 1198: }
! 1199:
! 1200: pmap_pte_flush(pmap_kernel(), va, pte);
! 1201: pmap_pte_set(pde, va, 0);
! 1202: if (pmap_initialized && (pg = PHYS_TO_VM_PAGE(PTE_PAGE(pte)))) {
! 1203:
! 1204: simple_lock(&pg->mdpage.pvh_lock);
! 1205: pg->mdpage.pvh_attrs |= pmap_pvh_attrs(pte);
! 1206: /* just in case we have enter/kenter mismatch */
! 1207: if ((pve = pmap_pv_remove(pg, pmap_kernel(), va)))
! 1208: pmap_pv_free(pve);
! 1209: simple_unlock(&pg->mdpage.pvh_lock);
! 1210: }
! 1211: }
! 1212:
! 1213: simple_unlock(&pmap->pm_lock);
! 1214:
! 1215: DPRINTF(PDB_FOLLOW|PDB_REMOVE, ("pmap_kremove: leaving\n"));
! 1216: }
CVSweb