Annotation of sys/arch/i386/i386/pmap.c, Revision 1.1
1.1 ! nbrk 1: /* $OpenBSD: pmap.c,v 1.119 2007/06/27 16:16:53 art Exp $ */
! 2: /* $NetBSD: pmap.c,v 1.91 2000/06/02 17:46:37 thorpej Exp $ */
! 3:
! 4: /*
! 5: *
! 6: * Copyright (c) 1997 Charles D. Cranor and Washington University.
! 7: * All rights reserved.
! 8: *
! 9: * Redistribution and use in source and binary forms, with or without
! 10: * modification, are permitted provided that the following conditions
! 11: * are met:
! 12: * 1. Redistributions of source code must retain the above copyright
! 13: * notice, this list of conditions and the following disclaimer.
! 14: * 2. Redistributions in binary form must reproduce the above copyright
! 15: * notice, this list of conditions and the following disclaimer in the
! 16: * documentation and/or other materials provided with the distribution.
! 17: * 3. All advertising materials mentioning features or use of this software
! 18: * must display the following acknowledgement:
! 19: * This product includes software developed by Charles D. Cranor and
! 20: * Washington University.
! 21: * 4. The name of the author may not be used to endorse or promote products
! 22: * derived from this software without specific prior written permission.
! 23: *
! 24: * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
! 25: * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
! 26: * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
! 27: * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
! 28: * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
! 29: * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
! 30: * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
! 31: * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
! 32: * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
! 33: * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
! 34: */
! 35:
! 36: /*
! 37: * pmap.c: i386 pmap module rewrite
! 38: * Chuck Cranor <chuck@ccrc.wustl.edu>
! 39: * 11-Aug-97
! 40: *
! 41: * history of this pmap module: in addition to my own input, i used
! 42: * the following references for this rewrite of the i386 pmap:
! 43: *
! 44: * [1] the NetBSD i386 pmap. this pmap appears to be based on the
! 45: * BSD hp300 pmap done by Mike Hibler at University of Utah.
! 46: * it was then ported to the i386 by William Jolitz of UUNET
! 47: * Technologies, Inc. Then Charles M. Hannum of the NetBSD
! 48: * project fixed some bugs and provided some speed ups.
! 49: *
! 50: * [2] the FreeBSD i386 pmap. this pmap seems to be the
! 51: * Hibler/Jolitz pmap, as modified for FreeBSD by John S. Dyson
! 52: * and David Greenman.
! 53: *
! 54: * [3] the Mach pmap. this pmap, from CMU, seems to have migrated
! 55: * between several processors. the VAX version was done by
! 56: * Avadis Tevanian, Jr., and Michael Wayne Young. the i386
! 57: * version was done by Lance Berc, Mike Kupfer, Bob Baron,
! 58: * David Golub, and Richard Draves. the alpha version was
! 59: * done by Alessandro Forin (CMU/Mach) and Chris Demetriou
! 60: * (NetBSD/alpha).
! 61: */
! 62:
! 63: #include <sys/param.h>
! 64: #include <sys/systm.h>
! 65: #include <sys/proc.h>
! 66: #include <sys/malloc.h>
! 67: #include <sys/pool.h>
! 68: #include <sys/user.h>
! 69: #include <sys/kernel.h>
! 70: #include <sys/mutex.h>
! 71:
! 72: #include <uvm/uvm.h>
! 73:
! 74: #include <machine/atomic.h>
! 75: #include <machine/cpu.h>
! 76: #include <machine/specialreg.h>
! 77: #include <machine/gdt.h>
! 78:
! 79: #include <dev/isa/isareg.h>
! 80: #include <sys/msgbuf.h>
! 81: #include <stand/boot/bootarg.h>
! 82:
! 83: /*
! 84: * general info:
! 85: *
! 86: * - for an explanation of how the i386 MMU hardware works see
! 87: * the comments in <machine/pte.h>.
! 88: *
! 89: * - for an explanation of the general memory structure used by
! 90: * this pmap (including the recursive mapping), see the comments
! 91: * in <machine/pmap.h>.
! 92: *
! 93: * this file contains the code for the "pmap module." the module's
! 94: * job is to manage the hardware's virtual to physical address mappings.
! 95: * note that there are two levels of mapping in the VM system:
! 96: *
! 97: * [1] the upper layer of the VM system uses vm_map's and vm_map_entry's
! 98: * to map ranges of virtual address space to objects/files. for
! 99: * example, the vm_map may say: "map VA 0x1000 to 0x22000 read-only
! 100: * to the file /bin/ls starting at offset zero." note that
! 101: * the upper layer mapping is not concerned with how individual
! 102: * vm_pages are mapped.
! 103: *
! 104: * [2] the lower layer of the VM system (the pmap) maintains the mappings
! 105: * from virtual addresses. it is concerned with which vm_page is
! 106: * mapped where. for example, when you run /bin/ls and start
! 107: * at page 0x1000 the fault routine may lookup the correct page
! 108: * of the /bin/ls file and then ask the pmap layer to establish
! 109: * a mapping for it.
! 110: *
! 111: * note that information in the lower layer of the VM system can be
! 112: * thrown away since it can easily be reconstructed from the info
! 113: * in the upper layer.
! 114: *
! 115: * data structures we use include:
! 116: *
! 117: * - struct pmap: describes the address space of one thread
! 118: * - struct pv_entry: describes one <PMAP,VA> mapping of a PA
! 119: * - struct pv_head: there is one pv_head per managed page of
! 120: * physical memory. the pv_head points to a list of pv_entry
! 121: * structures which describe all the <PMAP,VA> pairs that this
! 122: * page is mapped in. this is critical for page based operations
! 123: * such as pmap_page_protect() [change protection on _all_ mappings
! 124: * of a page]
! 125: * - pv_page/pv_page_info: pv_entry's are allocated out of pv_page's.
! 126: * if we run out of pv_entry's we allocate a new pv_page and free
! 127: * its pv_entrys.
! 128: */
! 129: /*
! 130: * memory allocation
! 131: *
! 132: * - there are three data structures that we must dynamically allocate:
! 133: *
! 134: * [A] new process' page directory page (PDP)
! 135: * - plan 1: done at pmap_create() we use
! 136: * uvm_km_alloc(kernel_map, PAGE_SIZE) [fka kmem_alloc] to do this
! 137: * allocation.
! 138: *
! 139: * if we are low in free physical memory then we sleep in
! 140: * uvm_km_alloc -- in this case this is ok since we are creating
! 141: * a new pmap and should not be holding any locks.
! 142: *
! 143: * if the kernel is totally out of virtual space
! 144: * (i.e. uvm_km_alloc returns NULL), then we panic.
! 145: *
! 146: * XXX: the fork code currently has no way to return an "out of
! 147: * memory, try again" error code since uvm_fork [fka vm_fork]
! 148: * is a void function.
! 149: *
! 150: * [B] new page tables pages (PTP)
! 151: * call uvm_pagealloc()
! 152: * => success: zero page, add to pm_pdir
! 153: * => failure: we are out of free vm_pages, let pmap_enter()
! 154: * tell UVM about it.
! 155: *
! 156: * note: for kernel PTPs, we start with NKPTP of them. as we map
! 157: * kernel memory (at uvm_map time) we check to see if we've grown
! 158: * the kernel pmap. if so, we call the optional function
! 159: * pmap_growkernel() to grow the kernel PTPs in advance.
! 160: *
! 161: * [C] pv_entry structures
! 162: * - plan 1: try to allocate one off the free list
! 163: * => success: done!
! 164: * => failure: no more free pv_entrys on the list
! 165: * - plan 2: try to allocate a new pv_page to add a chunk of
! 166: * pv_entrys to the free list
! 167: * [a] obtain a free, unmapped, VA in kmem_map. either
! 168: * we have one saved from a previous call, or we allocate
! 169: * one now using a "vm_map_lock_try" in uvm_map
! 170: * => success: we have an unmapped VA, continue to [b]
! 171: * => failure: unable to lock kmem_map or out of VA in it.
! 172: * move on to plan 3.
! 173: * [b] allocate a page for the VA
! 174: * => success: map it in, free the pv_entry's, DONE!
! 175: * => failure: no free vm_pages, etc.
! 176: * save VA for later call to [a], go to plan 3.
! 177: * If we fail, we simply let pmap_enter() tell UVM about it.
! 178: */
! 179: /*
! 180: * locking
! 181: *
! 182: * we have the following locks that we must contend with:
! 183: *
! 184: * "simple" locks:
! 185: *
! 186: * - pmap lock (per pmap, part of uvm_object)
! 187: * this lock protects the fields in the pmap structure including
! 188: * the non-kernel PDEs in the PDP, and the PTEs. it also locks
! 189: * in the alternate PTE space (since that is determined by the
! 190: * entry in the PDP).
! 191: *
! 192: * - pvalloc_lock
! 193: * this lock protects the data structures which are used to manage
! 194: * the free list of pv_entry structures.
! 195: *
! 196: * - pmaps_lock
! 197: * this lock protects the list of active pmaps (headed by "pmaps").
! 198: * we lock it when adding or removing pmaps from this list.
! 199: *
! 200: */
! 201:
! 202: /*
! 203: * locking data structures
! 204: */
! 205:
! 206: struct simplelock pvalloc_lock;
! 207: struct simplelock pmaps_lock;
! 208:
! 209: #define PMAP_MAP_TO_HEAD_LOCK() /* null */
! 210: #define PMAP_MAP_TO_HEAD_UNLOCK() /* null */
! 211:
! 212: #define PMAP_HEAD_TO_MAP_LOCK() /* null */
! 213: #define PMAP_HEAD_TO_MAP_UNLOCK() /* null */
! 214:
! 215: /*
! 216: * global data structures
! 217: */
! 218:
! 219: struct pmap kernel_pmap_store; /* the kernel's pmap (proc0) */
! 220:
! 221: /*
! 222: * nkpde is the number of kernel PTPs allocated for the kernel at
! 223: * boot time (NKPTP is a compile time override). this number can
! 224: * grow dynamically as needed (but once allocated, we never free
! 225: * kernel PTPs).
! 226: */
! 227:
! 228: int nkpde = NKPTP;
! 229: #ifdef NKPDE
! 230: #error "obsolete NKPDE: use NKPTP"
! 231: #endif
! 232:
! 233: /*
! 234: * pmap_pg_g: if our processor supports PG_G in the PTE then we
! 235: * set pmap_pg_g to PG_G (otherwise it is zero).
! 236: */
! 237:
! 238: int pmap_pg_g = 0;
! 239:
! 240: /*
! 241: * i386 physical memory comes in a big contig chunk with a small
! 242: * hole toward the front of it... the following 4 paddr_t's
! 243: * (shared with machdep.c) describe the physical address space
! 244: * of this machine.
! 245: */
! 246: paddr_t avail_start; /* PA of first available physical page */
! 247: paddr_t hole_start; /* PA of start of "hole" */
! 248: paddr_t hole_end; /* PA of end of "hole" */
! 249:
! 250: /*
! 251: * other data structures
! 252: */
! 253:
! 254: static pt_entry_t protection_codes[8]; /* maps MI prot to i386 prot code */
! 255: static boolean_t pmap_initialized = FALSE; /* pmap_init done yet? */
! 256:
! 257: /*
! 258: * the following two vaddr_t's are used during system startup
! 259: * to keep track of how much of the kernel's VM space we have used.
! 260: * once the system is started, the management of the remaining kernel
! 261: * VM space is turned over to the kernel_map vm_map.
! 262: */
! 263:
! 264: static vaddr_t virtual_avail; /* VA of first free KVA */
! 265: static vaddr_t virtual_end; /* VA of last free KVA */
! 266:
! 267: /*
! 268: * pv_page management structures: locked by pvalloc_lock
! 269: */
! 270:
! 271: TAILQ_HEAD(pv_pagelist, pv_page);
! 272: static struct pv_pagelist pv_freepages; /* list of pv_pages with free entries */
! 273: static struct pv_pagelist pv_unusedpgs; /* list of unused pv_pages */
! 274: static int pv_nfpvents; /* # of free pv entries */
! 275: static struct pv_page *pv_initpage; /* bootstrap page from kernel_map */
! 276: static vaddr_t pv_cachedva; /* cached VA for later use */
! 277:
! 278: #define PVE_LOWAT (PVE_PER_PVPAGE / 2) /* free pv_entry low water mark */
! 279: #define PVE_HIWAT (PVE_LOWAT + (PVE_PER_PVPAGE * 2))
! 280: /* high water mark */
! 281:
! 282: /*
! 283: * linked list of all non-kernel pmaps
! 284: */
! 285:
! 286: struct pmap_head pmaps;
! 287:
! 288: /*
! 289: * pool that pmap structures are allocated from
! 290: */
! 291:
! 292: struct pool pmap_pmap_pool;
! 293:
! 294: /*
! 295: * MULTIPROCESSOR: special VA's/ PTE's are actually allocated inside a
! 296: * I386_MAXPROCS*NPTECL array of PTE's, to avoid cache line thrashing
! 297: * due to false sharing.
! 298: */
! 299:
! 300: #ifdef MULTIPROCESSOR
! 301: #define PTESLEW(pte, id) ((pte)+(id)*NPTECL)
! 302: #define VASLEW(va,id) ((va)+(id)*NPTECL*NBPG)
! 303: #else
! 304: #define PTESLEW(pte, id) (pte)
! 305: #define VASLEW(va,id) (va)
! 306: #endif
! 307:
! 308: /*
! 309: * special VAs and the PTEs that map them
! 310: */
! 311:
! 312: static pt_entry_t *csrc_pte, *cdst_pte, *zero_pte, *ptp_pte;
! 313: static caddr_t csrcp, cdstp, zerop, ptpp;
! 314: caddr_t vmmap; /* XXX: used by mem.c... it should really uvm_map_reserve it */
! 315:
! 316: #if defined(I586_CPU)
! 317: /* stuff to fix the pentium f00f bug */
! 318: extern vaddr_t pentium_idt_vaddr;
! 319: #endif
! 320:
! 321:
! 322: /*
! 323: * local prototypes
! 324: */
! 325:
! 326: struct pv_entry *pmap_add_pvpage(struct pv_page *, boolean_t);
! 327: struct vm_page *pmap_alloc_ptp(struct pmap *, int, boolean_t, pt_entry_t);
! 328: struct pv_entry *pmap_alloc_pv(struct pmap *, int); /* see codes below */
! 329: #define ALLOCPV_NEED 0 /* need PV now */
! 330: #define ALLOCPV_TRY 1 /* just try to allocate */
! 331: #define ALLOCPV_NONEED 2 /* don't need PV, just growing cache */
! 332: struct pv_entry *pmap_alloc_pvpage(struct pmap *, int);
! 333: void pmap_enter_pv(struct vm_page *, struct pv_entry *,
! 334: struct pmap *, vaddr_t, struct vm_page *);
! 335: void pmap_free_pv(struct pmap *, struct pv_entry *);
! 336: void pmap_free_pvs(struct pmap *, struct pv_entry *);
! 337: void pmap_free_pv_doit(struct pv_entry *);
! 338: void pmap_free_pvpage(void);
! 339: struct vm_page *pmap_get_ptp(struct pmap *, int, boolean_t);
! 340: boolean_t pmap_is_curpmap(struct pmap *);
! 341: boolean_t pmap_is_active(struct pmap *, int);
! 342: void pmap_sync_flags_pte(struct vm_page *, u_long);
! 343: pt_entry_t *pmap_map_ptes(struct pmap *);
! 344: struct pv_entry *pmap_remove_pv(struct vm_page *, struct pmap *, vaddr_t);
! 345: void pmap_do_remove(struct pmap *, vaddr_t, vaddr_t, int);
! 346: boolean_t pmap_remove_pte(struct pmap *, struct vm_page *, pt_entry_t *,
! 347: vaddr_t, int);
! 348: void pmap_remove_ptes(struct pmap *, struct vm_page *, vaddr_t,
! 349: vaddr_t, vaddr_t, int);
! 350:
! 351: #define PMAP_REMOVE_ALL 0
! 352: #define PMAP_REMOVE_SKIPWIRED 1
! 353:
! 354: vaddr_t pmap_tmpmap_pa(paddr_t);
! 355: pt_entry_t *pmap_tmpmap_pvepte(struct pv_entry *);
! 356: void pmap_tmpunmap_pa(void);
! 357: void pmap_tmpunmap_pvepte(struct pv_entry *);
! 358: void pmap_apte_flush(struct pmap *);
! 359: void pmap_unmap_ptes(struct pmap *);
! 360: void pmap_exec_account(struct pmap *, vaddr_t, pt_entry_t,
! 361: pt_entry_t);
! 362:
! 363: void pmap_pinit(pmap_t);
! 364: void pmap_release(pmap_t);
! 365:
! 366: void pmap_zero_phys(paddr_t);
! 367:
! 368: void setcslimit(struct pmap *, struct trapframe *, struct pcb *, vaddr_t);
! 369:
! 370: /*
! 371: * p m a p i n l i n e h e l p e r f u n c t i o n s
! 372: */
! 373:
! 374: /*
! 375: * pmap_is_curpmap: is this pmap the one currently loaded [in %cr3]?
! 376: * of course the kernel is always loaded
! 377: */
! 378:
! 379: boolean_t
! 380: pmap_is_curpmap(pmap)
! 381: struct pmap *pmap;
! 382: {
! 383: return((pmap == pmap_kernel()) ||
! 384: (pmap->pm_pdirpa == (paddr_t) rcr3()));
! 385: }
! 386:
! 387: /*
! 388: * pmap_is_active: is this pmap loaded into the specified processor's %cr3?
! 389: */
! 390:
! 391: boolean_t
! 392: pmap_is_active(pmap, cpu_id)
! 393: struct pmap *pmap;
! 394: int cpu_id;
! 395: {
! 396:
! 397: return (pmap == pmap_kernel() ||
! 398: (pmap->pm_cpus & (1U << cpu_id)) != 0);
! 399: }
! 400:
! 401: static __inline u_int
! 402: pmap_pte2flags(u_long pte)
! 403: {
! 404: return (((pte & PG_U) ? PG_PMAP_REF : 0) |
! 405: ((pte & PG_M) ? PG_PMAP_MOD : 0));
! 406: }
! 407:
! 408: static __inline u_int
! 409: pmap_flags2pte(u_long pte)
! 410: {
! 411: return (((pte & PG_PMAP_REF) ? PG_U : 0) |
! 412: ((pte & PG_PMAP_MOD) ? PG_M : 0));
! 413: }
! 414:
! 415: void
! 416: pmap_sync_flags_pte(struct vm_page *pg, u_long pte)
! 417: {
! 418: if (pte & (PG_U|PG_M)) {
! 419: atomic_setbits_int(&pg->pg_flags, pmap_pte2flags(pte));
! 420: }
! 421: }
! 422:
! 423: /*
! 424: * pmap_tmpmap_pa: map a page in for tmp usage
! 425: */
! 426:
! 427: vaddr_t
! 428: pmap_tmpmap_pa(paddr_t pa)
! 429: {
! 430: #ifdef MULTIPROCESSOR
! 431: int id = cpu_number();
! 432: #endif
! 433: pt_entry_t *ptpte = PTESLEW(ptp_pte, id);
! 434: caddr_t ptpva = VASLEW(ptpp, id);
! 435: #if defined(DIAGNOSTIC)
! 436: if (*ptpte)
! 437: panic("pmap_tmpmap_pa: ptp_pte in use?");
! 438: #endif
! 439: *ptpte = PG_V | PG_RW | pa; /* always a new mapping */
! 440: return((vaddr_t)ptpva);
! 441: }
! 442:
! 443: /*
! 444: * pmap_tmpunmap_pa: unmap a tmp use page (undoes pmap_tmpmap_pa)
! 445: */
! 446:
! 447: void
! 448: pmap_tmpunmap_pa()
! 449: {
! 450: #ifdef MULTIPROCESSOR
! 451: int id = cpu_number();
! 452: #endif
! 453: pt_entry_t *ptpte = PTESLEW(ptp_pte, id);
! 454: caddr_t ptpva = VASLEW(ptpp, id);
! 455: #if defined(DIAGNOSTIC)
! 456: if (!pmap_valid_entry(*ptpte))
! 457: panic("pmap_tmpunmap_pa: our pte invalid?");
! 458: #endif
! 459: *ptpte = 0; /* zap! */
! 460: pmap_update_pg((vaddr_t)ptpva);
! 461: #ifdef MULTIPROCESSOR
! 462: /*
! 463: * No need for tlb shootdown here, since ptp_pte is per-CPU.
! 464: */
! 465: #endif
! 466: }
! 467:
! 468: /*
! 469: * pmap_tmpmap_pvepte: get a quick mapping of a PTE for a pv_entry
! 470: *
! 471: * => do NOT use this on kernel mappings [why? because pv_ptp may be NULL]
! 472: */
! 473:
! 474: pt_entry_t *
! 475: pmap_tmpmap_pvepte(struct pv_entry *pve)
! 476: {
! 477: #ifdef DIAGNOSTIC
! 478: if (pve->pv_pmap == pmap_kernel())
! 479: panic("pmap_tmpmap_pvepte: attempt to map kernel");
! 480: #endif
! 481:
! 482: /* is it current pmap? use direct mapping... */
! 483: if (pmap_is_curpmap(pve->pv_pmap))
! 484: return(vtopte(pve->pv_va));
! 485:
! 486: return(((pt_entry_t *)pmap_tmpmap_pa(VM_PAGE_TO_PHYS(pve->pv_ptp)))
! 487: + ptei((unsigned)pve->pv_va));
! 488: }
! 489:
! 490: /*
! 491: * pmap_tmpunmap_pvepte: release a mapping obtained with pmap_tmpmap_pvepte
! 492: */
! 493:
! 494: void
! 495: pmap_tmpunmap_pvepte(struct pv_entry *pve)
! 496: {
! 497: /* was it current pmap? if so, return */
! 498: if (pmap_is_curpmap(pve->pv_pmap))
! 499: return;
! 500:
! 501: pmap_tmpunmap_pa();
! 502: }
! 503:
! 504: void
! 505: pmap_apte_flush(struct pmap *pmap)
! 506: {
! 507: pmap_tlb_shoottlb();
! 508: pmap_tlb_shootwait();
! 509: }
! 510:
! 511: /*
! 512: * pmap_map_ptes: map a pmap's PTEs into KVM and lock them in
! 513: *
! 514: * => we lock enough pmaps to keep things locked in
! 515: * => must be undone with pmap_unmap_ptes before returning
! 516: */
! 517:
! 518: pt_entry_t *
! 519: pmap_map_ptes(struct pmap *pmap)
! 520: {
! 521: pd_entry_t opde;
! 522:
! 523: /* the kernel's pmap is always accessible */
! 524: if (pmap == pmap_kernel()) {
! 525: return(PTE_BASE);
! 526: }
! 527:
! 528: /* if curpmap then we are always mapped */
! 529: if (pmap_is_curpmap(pmap)) {
! 530: simple_lock(&pmap->pm_obj.vmobjlock);
! 531: return(PTE_BASE);
! 532: }
! 533:
! 534: /* need to lock both curpmap and pmap: use ordered locking */
! 535: if ((unsigned) pmap < (unsigned) curpcb->pcb_pmap) {
! 536: simple_lock(&pmap->pm_obj.vmobjlock);
! 537: simple_lock(&curpcb->pcb_pmap->pm_obj.vmobjlock);
! 538: } else {
! 539: simple_lock(&curpcb->pcb_pmap->pm_obj.vmobjlock);
! 540: simple_lock(&pmap->pm_obj.vmobjlock);
! 541: }
! 542:
! 543: /* need to load a new alternate pt space into curpmap? */
! 544: opde = *APDP_PDE;
! 545: if (!pmap_valid_entry(opde) || (opde & PG_FRAME) != pmap->pm_pdirpa) {
! 546: *APDP_PDE = (pd_entry_t) (pmap->pm_pdirpa | PG_RW | PG_V |
! 547: PG_U | PG_M);
! 548: if (pmap_valid_entry(opde))
! 549: pmap_apte_flush(curpcb->pcb_pmap);
! 550: }
! 551: return(APTE_BASE);
! 552: }
! 553:
! 554: /*
! 555: * pmap_unmap_ptes: unlock the PTE mapping of "pmap"
! 556: */
! 557:
! 558: void
! 559: pmap_unmap_ptes(struct pmap *pmap)
! 560: {
! 561: if (pmap == pmap_kernel())
! 562: return;
! 563:
! 564: if (pmap_is_curpmap(pmap)) {
! 565: simple_unlock(&pmap->pm_obj.vmobjlock);
! 566: } else {
! 567: #if defined(MULTIPROCESSOR)
! 568: *APDP_PDE = 0;
! 569: pmap_apte_flush(curpcb->pcb_pmap);
! 570: #endif
! 571: simple_unlock(&pmap->pm_obj.vmobjlock);
! 572: simple_unlock(&curpcb->pcb_pmap->pm_obj.vmobjlock);
! 573: }
! 574: }
! 575:
! 576: void
! 577: pmap_exec_account(struct pmap *pm, vaddr_t va,
! 578: pt_entry_t opte, pt_entry_t npte)
! 579: {
! 580: if (pm == pmap_kernel())
! 581: return;
! 582:
! 583: if (curproc == NULL || curproc->p_vmspace == NULL ||
! 584: pm != vm_map_pmap(&curproc->p_vmspace->vm_map))
! 585: return;
! 586:
! 587: if ((opte ^ npte) & PG_X)
! 588: pmap_tlb_shootpage(pm, va);
! 589:
! 590: /*
! 591: * Executability was removed on the last executable change.
! 592: * Reset the code segment to something conservative and
! 593: * let the trap handler deal with setting the right limit.
! 594: * We can't do that because of locking constraints on the vm map.
! 595: *
! 596: * XXX - floating cs - set this _really_ low.
! 597: */
! 598: if ((opte & PG_X) && (npte & PG_X) == 0 && va == pm->pm_hiexec) {
! 599: struct trapframe *tf = curproc->p_md.md_regs;
! 600: struct pcb *pcb = &curproc->p_addr->u_pcb;
! 601:
! 602: pm->pm_hiexec = I386_MAX_EXE_ADDR;
! 603: setcslimit(pm, tf, pcb, I386_MAX_EXE_ADDR);
! 604: }
! 605: }
! 606:
! 607: /*
! 608: * Fixup the code segment to cover all potential executable mappings.
! 609: * Called by kernel SEGV trap handler.
! 610: * returns 0 if no changes to the code segment were made.
! 611: */
! 612: int
! 613: pmap_exec_fixup(struct vm_map *map, struct trapframe *tf, struct pcb *pcb)
! 614: {
! 615: struct vm_map_entry *ent;
! 616: struct pmap *pm = vm_map_pmap(map);
! 617: vaddr_t va = 0;
! 618:
! 619: vm_map_lock(map);
! 620: for (ent = (&map->header)->next; ent != &map->header; ent = ent->next) {
! 621: /*
! 622: * This entry has greater va than the entries before.
! 623: * We need to make it point to the last page, not past it.
! 624: */
! 625: if (ent->protection & VM_PROT_EXECUTE)
! 626: va = trunc_page(ent->end - 1);
! 627: }
! 628: vm_map_unlock(map);
! 629:
! 630: if (va <= pm->pm_hiexec) {
! 631: return (0);
! 632: }
! 633:
! 634: pm->pm_hiexec = va;
! 635:
! 636: /*
! 637: * We have a new 'highest executable' va, so we need to update
! 638: * the value for the code segment limit, which is stored in the
! 639: * PCB.
! 640: */
! 641: setcslimit(pm, tf, pcb, va);
! 642:
! 643: return (1);
! 644: }
! 645:
! 646: void
! 647: setcslimit(struct pmap *pm, struct trapframe *tf, struct pcb *pcb,
! 648: vaddr_t limit)
! 649: {
! 650: /*
! 651: * Called when we have a new 'highest executable' va, so we need
! 652: * to update the value for the code segment limit, which is stored
! 653: * in the PCB.
! 654: *
! 655: * There are no caching issues to be concerned with: the
! 656: * processor reads the whole descriptor from the GDT when the
! 657: * appropriate selector is loaded into a segment register, and
! 658: * this only happens on the return to userland.
! 659: *
! 660: * This also works in the MP case, since whichever CPU gets to
! 661: * run the process will pick up the right descriptor value from
! 662: * the PCB.
! 663: */
! 664: limit = min(limit, VM_MAXUSER_ADDRESS - 1);
! 665:
! 666: setsegment(&pm->pm_codeseg, 0, atop(limit),
! 667: SDT_MEMERA, SEL_UPL, 1, 1);
! 668:
! 669: /* And update the GDT and LDT since we may be called by the
! 670: * trap handler (cpu_switch won't get a chance).
! 671: */
! 672: curcpu()->ci_gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd =
! 673: pm->pm_codeseg;
! 674:
! 675: pcb->pcb_cs = tf->tf_cs = GSEL(GUCODE_SEL, SEL_UPL);
! 676: }
! 677:
! 678: /*
! 679: * p m a p k e n t e r f u n c t i o n s
! 680: *
! 681: * functions to quickly enter/remove pages from the kernel address
! 682: * space. pmap_kremove is exported to MI kernel. we make use of
! 683: * the recursive PTE mappings.
! 684: */
! 685:
! 686: /*
! 687: * pmap_kenter_pa: enter a kernel mapping without R/M (pv_entry) tracking
! 688: *
! 689: * => no need to lock anything, assume va is already allocated
! 690: * => should be faster than normal pmap enter function
! 691: */
! 692:
! 693: void
! 694: pmap_kenter_pa(vaddr_t va, paddr_t pa, vm_prot_t prot)
! 695: {
! 696: pt_entry_t *pte, opte, npte;
! 697:
! 698: pte = vtopte(va);
! 699: npte = pa | ((prot & VM_PROT_WRITE)? PG_RW : PG_RO) | PG_V |
! 700: pmap_pg_g | PG_U | PG_M;
! 701: opte = i386_atomic_testset_ul(pte, npte); /* zap! */
! 702: if (pmap_valid_entry(opte)) {
! 703: /* NB. - this should not happen. */
! 704: pmap_tlb_shootpage(pmap_kernel(), va);
! 705: pmap_tlb_shootwait();
! 706: }
! 707: }
! 708:
! 709: /*
! 710: * pmap_kremove: remove a kernel mapping(s) without R/M (pv_entry) tracking
! 711: *
! 712: * => no need to lock anything
! 713: * => caller must dispose of any vm_page mapped in the va range
! 714: * => note: not an inline function
! 715: * => we assume the va is page aligned and the len is a multiple of PAGE_SIZE
! 716: */
! 717:
! 718: void
! 719: pmap_kremove(vaddr_t sva, vsize_t len)
! 720: {
! 721: pt_entry_t *pte, opte;
! 722: vaddr_t va, eva;
! 723:
! 724: eva = sva + len;
! 725:
! 726: for (va = sva; va != eva; va += PAGE_SIZE) {
! 727: pte = kvtopte(va);
! 728: opte = i386_atomic_testset_ul(pte, 0);
! 729: #ifdef DIAGNOSTIC
! 730: if (opte & PG_PVLIST)
! 731: panic("pmap_kremove: PG_PVLIST mapping for 0x%lx", va);
! 732: #endif
! 733: }
! 734: pmap_tlb_shootrange(pmap_kernel(), sva, eva);
! 735: pmap_tlb_shootwait();
! 736: }
! 737:
! 738: /*
! 739: * p m a p i n i t f u n c t i o n s
! 740: *
! 741: * pmap_bootstrap and pmap_init are called during system startup
! 742: * to init the pmap module. pmap_bootstrap() does a low level
! 743: * init just to get things rolling. pmap_init() finishes the job.
! 744: */
! 745:
! 746: /*
! 747: * pmap_bootstrap: get the system in a state where it can run with VM
! 748: * properly enabled (called before main()). the VM system is
! 749: * fully init'd later...
! 750: *
! 751: * => on i386, locore.s has already enabled the MMU by allocating
! 752: * a PDP for the kernel, and nkpde PTP's for the kernel.
! 753: * => kva_start is the first free virtual address in kernel space
! 754: */
! 755:
! 756: void
! 757: pmap_bootstrap(vaddr_t kva_start)
! 758: {
! 759: extern paddr_t avail_end;
! 760: struct pmap *kpm;
! 761: vaddr_t kva;
! 762: pt_entry_t *pte;
! 763:
! 764: /*
! 765: * set the page size (default value is 4K which is ok)
! 766: */
! 767:
! 768: uvm_setpagesize();
! 769:
! 770: /*
! 771: * a quick sanity check
! 772: */
! 773:
! 774: if (PAGE_SIZE != NBPG)
! 775: panic("pmap_bootstrap: PAGE_SIZE != NBPG");
! 776:
! 777: /*
! 778: * use the very last page of physical memory for the message buffer
! 779: */
! 780:
! 781: avail_end -= round_page(MSGBUFSIZE);
! 782: /*
! 783: * The arguments passed in from /boot needs space too.
! 784: */
! 785: avail_end -= round_page(bootargc);
! 786:
! 787: /*
! 788: * set up our local static global vars that keep track of the
! 789: * usage of KVM before kernel_map is set up
! 790: */
! 791:
! 792: virtual_avail = kva_start; /* first free KVA */
! 793: virtual_end = VM_MAX_KERNEL_ADDRESS; /* last KVA */
! 794:
! 795: /*
! 796: * set up protection_codes: we need to be able to convert from
! 797: * a MI protection code (some combo of VM_PROT...) to something
! 798: * we can jam into a i386 PTE.
! 799: */
! 800:
! 801: protection_codes[UVM_PROT_NONE] = 0; /* --- */
! 802: protection_codes[UVM_PROT_EXEC] = PG_X; /* --x */
! 803: protection_codes[UVM_PROT_READ] = PG_RO; /* -r- */
! 804: protection_codes[UVM_PROT_RX] = PG_X; /* -rx */
! 805: protection_codes[UVM_PROT_WRITE] = PG_RW; /* w-- */
! 806: protection_codes[UVM_PROT_WX] = PG_RW|PG_X; /* w-x */
! 807: protection_codes[UVM_PROT_RW] = PG_RW; /* wr- */
! 808: protection_codes[UVM_PROT_RWX] = PG_RW|PG_X; /* wrx */
! 809:
! 810: /*
! 811: * now we init the kernel's pmap
! 812: *
! 813: * the kernel pmap's pm_obj is not used for much. however, in
! 814: * user pmaps the pm_obj contains the list of active PTPs.
! 815: * the pm_obj currently does not have a pager. it might be possible
! 816: * to add a pager that would allow a process to read-only mmap its
! 817: * own page tables (fast user level vtophys?). this may or may not
! 818: * be useful.
! 819: */
! 820:
! 821: kpm = pmap_kernel();
! 822: simple_lock_init(&kpm->pm_obj.vmobjlock);
! 823: kpm->pm_obj.pgops = NULL;
! 824: TAILQ_INIT(&kpm->pm_obj.memq);
! 825: kpm->pm_obj.uo_npages = 0;
! 826: kpm->pm_obj.uo_refs = 1;
! 827: bzero(&kpm->pm_list, sizeof(kpm->pm_list)); /* pm_list not used */
! 828: kpm->pm_pdir = (pd_entry_t *)(proc0.p_addr->u_pcb.pcb_cr3 + KERNBASE);
! 829: kpm->pm_pdirpa = (u_int32_t) proc0.p_addr->u_pcb.pcb_cr3;
! 830: kpm->pm_stats.wired_count = kpm->pm_stats.resident_count =
! 831: atop(kva_start - VM_MIN_KERNEL_ADDRESS);
! 832:
! 833: /*
! 834: * the above is just a rough estimate and not critical to the proper
! 835: * operation of the system.
! 836: */
! 837:
! 838: /*
! 839: * enable global TLB entries if they are supported
! 840: */
! 841:
! 842: if (cpu_feature & CPUID_PGE) {
! 843: lcr4(rcr4() | CR4_PGE); /* enable hardware (via %cr4) */
! 844: pmap_pg_g = PG_G; /* enable software */
! 845:
! 846: /* add PG_G attribute to already mapped kernel pages */
! 847: for (kva = VM_MIN_KERNEL_ADDRESS ; kva < virtual_avail ;
! 848: kva += PAGE_SIZE)
! 849: if (pmap_valid_entry(PTE_BASE[atop(kva)]))
! 850: PTE_BASE[atop(kva)] |= PG_G;
! 851: }
! 852:
! 853: /*
! 854: * now we allocate the "special" VAs which are used for tmp mappings
! 855: * by the pmap (and other modules). we allocate the VAs by advancing
! 856: * virtual_avail (note that there are no pages mapped at these VAs).
! 857: * we find the PTE that maps the allocated VA via the linear PTE
! 858: * mapping.
! 859: */
! 860:
! 861: pte = PTE_BASE + atop(virtual_avail);
! 862:
! 863: #ifdef MULTIPROCESSOR
! 864: /*
! 865: * Waste some VA space to avoid false sharing of cache lines
! 866: * for page table pages: Give each possible CPU a cache line
! 867: * of PTE's (8) to play with, though we only need 4. We could
! 868: * recycle some of this waste by putting the idle stacks here
! 869: * as well; we could waste less space if we knew the largest
! 870: * CPU ID beforehand.
! 871: */
! 872: csrcp = (caddr_t) virtual_avail; csrc_pte = pte;
! 873:
! 874: cdstp = (caddr_t) virtual_avail+PAGE_SIZE; cdst_pte = pte+1;
! 875:
! 876: zerop = (caddr_t) virtual_avail+PAGE_SIZE*2; zero_pte = pte+2;
! 877:
! 878: ptpp = (caddr_t) virtual_avail+PAGE_SIZE*3; ptp_pte = pte+3;
! 879:
! 880: virtual_avail += PAGE_SIZE * I386_MAXPROCS * NPTECL;
! 881: pte += I386_MAXPROCS * NPTECL;
! 882: #else
! 883: csrcp = (caddr_t) virtual_avail; csrc_pte = pte; /* allocate */
! 884: virtual_avail += PAGE_SIZE; pte++; /* advance */
! 885:
! 886: cdstp = (caddr_t) virtual_avail; cdst_pte = pte;
! 887: virtual_avail += PAGE_SIZE; pte++;
! 888:
! 889: zerop = (caddr_t) virtual_avail; zero_pte = pte;
! 890: virtual_avail += PAGE_SIZE; pte++;
! 891:
! 892: ptpp = (caddr_t) virtual_avail; ptp_pte = pte;
! 893: virtual_avail += PAGE_SIZE; pte++;
! 894: #endif
! 895:
! 896: /* XXX: vmmap used by mem.c... should be uvm_map_reserve */
! 897: vmmap = (char *)virtual_avail; /* don't need pte */
! 898: virtual_avail += PAGE_SIZE;
! 899:
! 900: msgbufp = (struct msgbuf *)virtual_avail; /* don't need pte */
! 901: virtual_avail += round_page(MSGBUFSIZE); pte++;
! 902:
! 903: bootargp = (bootarg_t *)virtual_avail;
! 904: virtual_avail += round_page(bootargc); pte++;
! 905:
! 906: /*
! 907: * now we reserve some VM for mapping pages when doing a crash dump
! 908: */
! 909:
! 910: virtual_avail = reserve_dumppages(virtual_avail);
! 911:
! 912: /*
! 913: * init the static-global locks and global lists.
! 914: */
! 915:
! 916: simple_lock_init(&pvalloc_lock);
! 917: simple_lock_init(&pmaps_lock);
! 918: LIST_INIT(&pmaps);
! 919: TAILQ_INIT(&pv_freepages);
! 920: TAILQ_INIT(&pv_unusedpgs);
! 921:
! 922: /*
! 923: * initialize the pmap pool.
! 924: */
! 925:
! 926: pool_init(&pmap_pmap_pool, sizeof(struct pmap), 0, 0, 0, "pmappl",
! 927: &pool_allocator_nointr);
! 928:
! 929: /*
! 930: * ensure the TLB is sync'd with reality by flushing it...
! 931: */
! 932:
! 933: tlbflush();
! 934: }
! 935:
! 936: /*
! 937: * pmap_init: called from uvm_init, our job is to get the pmap
! 938: * system ready to manage mappings... this mainly means initing
! 939: * the pv_entry stuff.
! 940: */
! 941:
! 942: void
! 943: pmap_init(void)
! 944: {
! 945: /*
! 946: * now we need to free enough pv_entry structures to allow us to get
! 947: * the kmem_map allocated and inited (done after this function is
! 948: * finished). to do this we allocate one bootstrap page out of
! 949: * kernel_map and use it to provide an initial pool of pv_entry
! 950: * structures. we never free this page.
! 951: */
! 952:
! 953: pv_initpage = (struct pv_page *) uvm_km_alloc(kernel_map, PAGE_SIZE);
! 954: if (pv_initpage == NULL)
! 955: panic("pmap_init: pv_initpage");
! 956: pv_cachedva = 0; /* a VA we have allocated but not used yet */
! 957: pv_nfpvents = 0;
! 958: (void) pmap_add_pvpage(pv_initpage, FALSE);
! 959:
! 960: /*
! 961: * done: pmap module is up (and ready for business)
! 962: */
! 963:
! 964: pmap_initialized = TRUE;
! 965: }
! 966:
! 967: /*
! 968: * p v _ e n t r y f u n c t i o n s
! 969: */
! 970:
! 971: /*
! 972: * pv_entry allocation functions:
! 973: * the main pv_entry allocation functions are:
! 974: * pmap_alloc_pv: allocate a pv_entry structure
! 975: * pmap_free_pv: free one pv_entry
! 976: * pmap_free_pvs: free a list of pv_entrys
! 977: *
! 978: * the rest are helper functions
! 979: */
! 980:
! 981: /*
! 982: * pmap_alloc_pv: inline function to allocate a pv_entry structure
! 983: * => we lock pvalloc_lock
! 984: * => if we fail, we call out to pmap_alloc_pvpage
! 985: * => 3 modes:
! 986: * ALLOCPV_NEED = we really need a pv_entry
! 987: * ALLOCPV_TRY = we want a pv_entry
! 988: * ALLOCPV_NONEED = we are trying to grow our free list, don't really need
! 989: * one now
! 990: *
! 991: * "try" is for optional functions like pmap_copy().
! 992: */
! 993:
! 994: struct pv_entry *
! 995: pmap_alloc_pv(struct pmap *pmap, int mode)
! 996: {
! 997: struct pv_page *pvpage;
! 998: struct pv_entry *pv;
! 999:
! 1000: simple_lock(&pvalloc_lock);
! 1001:
! 1002: if (!TAILQ_EMPTY(&pv_freepages)) {
! 1003: pvpage = TAILQ_FIRST(&pv_freepages);
! 1004: pvpage->pvinfo.pvpi_nfree--;
! 1005: if (pvpage->pvinfo.pvpi_nfree == 0) {
! 1006: /* nothing left in this one? */
! 1007: TAILQ_REMOVE(&pv_freepages, pvpage, pvinfo.pvpi_list);
! 1008: }
! 1009: pv = pvpage->pvinfo.pvpi_pvfree;
! 1010: #ifdef DIAGNOSTIC
! 1011: if (pv == NULL)
! 1012: panic("pmap_alloc_pv: pvpi_nfree off");
! 1013: #endif
! 1014: pvpage->pvinfo.pvpi_pvfree = pv->pv_next;
! 1015: pv_nfpvents--; /* took one from pool */
! 1016: } else {
! 1017: pv = NULL; /* need more of them */
! 1018: }
! 1019:
! 1020: /*
! 1021: * if below low water mark or we didn't get a pv_entry we try and
! 1022: * create more pv_entrys ...
! 1023: */
! 1024:
! 1025: if (pv_nfpvents < PVE_LOWAT || pv == NULL) {
! 1026: if (pv == NULL)
! 1027: pv = pmap_alloc_pvpage(pmap, (mode == ALLOCPV_TRY) ?
! 1028: mode : ALLOCPV_NEED);
! 1029: else
! 1030: (void) pmap_alloc_pvpage(pmap, ALLOCPV_NONEED);
! 1031: }
! 1032:
! 1033: simple_unlock(&pvalloc_lock);
! 1034: return(pv);
! 1035: }
! 1036:
! 1037: /*
! 1038: * pmap_alloc_pvpage: maybe allocate a new pvpage
! 1039: *
! 1040: * if need_entry is false: try and allocate a new pv_page
! 1041: * if need_entry is true: try and allocate a new pv_page and return a
! 1042: * new pv_entry from it.
! 1043: *
! 1044: * => we assume that the caller holds pvalloc_lock
! 1045: */
! 1046:
! 1047: struct pv_entry *
! 1048: pmap_alloc_pvpage(struct pmap *pmap, int mode)
! 1049: {
! 1050: struct vm_page *pg;
! 1051: struct pv_page *pvpage;
! 1052: struct pv_entry *pv;
! 1053: int s;
! 1054:
! 1055: /*
! 1056: * if we need_entry and we've got unused pv_pages, allocate from there
! 1057: */
! 1058:
! 1059: if (mode != ALLOCPV_NONEED && !TAILQ_EMPTY(&pv_unusedpgs)) {
! 1060:
! 1061: /* move it to pv_freepages list */
! 1062: pvpage = TAILQ_FIRST(&pv_unusedpgs);
! 1063: TAILQ_REMOVE(&pv_unusedpgs, pvpage, pvinfo.pvpi_list);
! 1064: TAILQ_INSERT_HEAD(&pv_freepages, pvpage, pvinfo.pvpi_list);
! 1065:
! 1066: /* allocate a pv_entry */
! 1067: pvpage->pvinfo.pvpi_nfree--; /* can't go to zero */
! 1068: pv = pvpage->pvinfo.pvpi_pvfree;
! 1069: #ifdef DIAGNOSTIC
! 1070: if (pv == NULL)
! 1071: panic("pmap_alloc_pvpage: pvpi_nfree off");
! 1072: #endif
! 1073: pvpage->pvinfo.pvpi_pvfree = pv->pv_next;
! 1074:
! 1075: pv_nfpvents--; /* took one from pool */
! 1076: return(pv);
! 1077: }
! 1078:
! 1079: /*
! 1080: * see if we've got a cached unmapped VA that we can map a page in.
! 1081: * if not, try to allocate one.
! 1082: */
! 1083:
! 1084: s = splvm(); /* must protect kmem_map with splvm! */
! 1085: if (pv_cachedva == 0) {
! 1086: pv_cachedva = uvm_km_kmemalloc(kmem_map, NULL,
! 1087: NBPG, UVM_KMF_TRYLOCK|UVM_KMF_VALLOC);
! 1088: }
! 1089: splx(s);
! 1090: if (pv_cachedva == 0)
! 1091: return (NULL);
! 1092:
! 1093: pg = uvm_pagealloc(NULL, 0, NULL, UVM_PGA_USERESERVE);
! 1094: if (pg == NULL)
! 1095: return (NULL);
! 1096:
! 1097: atomic_clearbits_int(&pg->pg_flags, PG_BUSY);
! 1098:
! 1099: /*
! 1100: * add a mapping for our new pv_page and free its entries (save one!)
! 1101: *
! 1102: * NOTE: If we are allocating a PV page for the kernel pmap, the
! 1103: * pmap is already locked! (...but entering the mapping is safe...)
! 1104: */
! 1105:
! 1106: pmap_kenter_pa(pv_cachedva, VM_PAGE_TO_PHYS(pg),
! 1107: VM_PROT_READ|VM_PROT_WRITE);
! 1108: pvpage = (struct pv_page *) pv_cachedva;
! 1109: pv_cachedva = 0;
! 1110: return (pmap_add_pvpage(pvpage, mode != ALLOCPV_NONEED));
! 1111: }
! 1112:
! 1113: /*
! 1114: * pmap_add_pvpage: add a pv_page's pv_entrys to the free list
! 1115: *
! 1116: * => caller must hold pvalloc_lock
! 1117: * => if need_entry is true, we allocate and return one pv_entry
! 1118: */
! 1119:
! 1120: struct pv_entry *
! 1121: pmap_add_pvpage(struct pv_page *pvp, boolean_t need_entry)
! 1122: {
! 1123: int tofree, lcv;
! 1124:
! 1125: /* do we need to return one? */
! 1126: tofree = (need_entry) ? PVE_PER_PVPAGE - 1 : PVE_PER_PVPAGE;
! 1127:
! 1128: pvp->pvinfo.pvpi_pvfree = NULL;
! 1129: pvp->pvinfo.pvpi_nfree = tofree;
! 1130: for (lcv = 0 ; lcv < tofree ; lcv++) {
! 1131: pvp->pvents[lcv].pv_next = pvp->pvinfo.pvpi_pvfree;
! 1132: pvp->pvinfo.pvpi_pvfree = &pvp->pvents[lcv];
! 1133: }
! 1134: if (need_entry)
! 1135: TAILQ_INSERT_TAIL(&pv_freepages, pvp, pvinfo.pvpi_list);
! 1136: else
! 1137: TAILQ_INSERT_TAIL(&pv_unusedpgs, pvp, pvinfo.pvpi_list);
! 1138: pv_nfpvents += tofree;
! 1139: return((need_entry) ? &pvp->pvents[lcv] : NULL);
! 1140: }
! 1141:
! 1142: /*
! 1143: * pmap_free_pv_doit: actually free a pv_entry
! 1144: *
! 1145: * => do not call this directly! instead use either
! 1146: * 1. pmap_free_pv ==> free a single pv_entry
! 1147: * 2. pmap_free_pvs => free a list of pv_entrys
! 1148: * => we must be holding pvalloc_lock
! 1149: */
! 1150:
! 1151: void
! 1152: pmap_free_pv_doit(struct pv_entry *pv)
! 1153: {
! 1154: struct pv_page *pvp;
! 1155:
! 1156: pvp = (struct pv_page*)trunc_page((vaddr_t)pv);
! 1157: pv_nfpvents++;
! 1158: pvp->pvinfo.pvpi_nfree++;
! 1159:
! 1160: /* nfree == 1 => fully allocated page just became partly allocated */
! 1161: if (pvp->pvinfo.pvpi_nfree == 1) {
! 1162: TAILQ_INSERT_HEAD(&pv_freepages, pvp, pvinfo.pvpi_list);
! 1163: }
! 1164:
! 1165: /* free it */
! 1166: pv->pv_next = pvp->pvinfo.pvpi_pvfree;
! 1167: pvp->pvinfo.pvpi_pvfree = pv;
! 1168:
! 1169: /*
! 1170: * are all pv_page's pv_entry's free? move it to unused queue.
! 1171: */
! 1172:
! 1173: if (pvp->pvinfo.pvpi_nfree == PVE_PER_PVPAGE) {
! 1174: TAILQ_REMOVE(&pv_freepages, pvp, pvinfo.pvpi_list);
! 1175: TAILQ_INSERT_HEAD(&pv_unusedpgs, pvp, pvinfo.pvpi_list);
! 1176: }
! 1177: }
! 1178:
! 1179: /*
! 1180: * pmap_free_pv: free a single pv_entry
! 1181: *
! 1182: * => we gain the pvalloc_lock
! 1183: */
! 1184:
! 1185: void
! 1186: pmap_free_pv(struct pmap *pmap, struct pv_entry *pv)
! 1187: {
! 1188: simple_lock(&pvalloc_lock);
! 1189: pmap_free_pv_doit(pv);
! 1190:
! 1191: /*
! 1192: * Can't free the PV page if the PV entries were associated with
! 1193: * the kernel pmap; the pmap is already locked.
! 1194: */
! 1195: if (pv_nfpvents > PVE_HIWAT && TAILQ_FIRST(&pv_unusedpgs) != NULL &&
! 1196: pmap != pmap_kernel())
! 1197: pmap_free_pvpage();
! 1198:
! 1199: simple_unlock(&pvalloc_lock);
! 1200: }
! 1201:
! 1202: /*
! 1203: * pmap_free_pvs: free a list of pv_entrys
! 1204: *
! 1205: * => we gain the pvalloc_lock
! 1206: */
! 1207:
! 1208: void
! 1209: pmap_free_pvs(struct pmap *pmap, struct pv_entry *pvs)
! 1210: {
! 1211: struct pv_entry *nextpv;
! 1212:
! 1213: simple_lock(&pvalloc_lock);
! 1214:
! 1215: for ( /* null */ ; pvs != NULL ; pvs = nextpv) {
! 1216: nextpv = pvs->pv_next;
! 1217: pmap_free_pv_doit(pvs);
! 1218: }
! 1219:
! 1220: /*
! 1221: * Can't free the PV page if the PV entries were associated with
! 1222: * the kernel pmap; the pmap is already locked.
! 1223: */
! 1224: if (pv_nfpvents > PVE_HIWAT && TAILQ_FIRST(&pv_unusedpgs) != NULL &&
! 1225: pmap != pmap_kernel())
! 1226: pmap_free_pvpage();
! 1227:
! 1228: simple_unlock(&pvalloc_lock);
! 1229: }
! 1230:
! 1231:
! 1232: /*
! 1233: * pmap_free_pvpage: try and free an unused pv_page structure
! 1234: *
! 1235: * => assume caller is holding the pvalloc_lock and that
! 1236: * there is a page on the pv_unusedpgs list
! 1237: * => if we can't get a lock on the kmem_map we try again later
! 1238: */
! 1239:
! 1240: void
! 1241: pmap_free_pvpage(void)
! 1242: {
! 1243: int s;
! 1244: struct vm_map *map;
! 1245: struct vm_map_entry *dead_entries;
! 1246: struct pv_page *pvp;
! 1247:
! 1248: s = splvm(); /* protect kmem_map */
! 1249: pvp = TAILQ_FIRST(&pv_unusedpgs);
! 1250:
! 1251: /*
! 1252: * note: watch out for pv_initpage which is allocated out of
! 1253: * kernel_map rather than kmem_map.
! 1254: */
! 1255:
! 1256: if (pvp == pv_initpage)
! 1257: map = kernel_map;
! 1258: else
! 1259: map = kmem_map;
! 1260: if (vm_map_lock_try(map)) {
! 1261:
! 1262: /* remove pvp from pv_unusedpgs */
! 1263: TAILQ_REMOVE(&pv_unusedpgs, pvp, pvinfo.pvpi_list);
! 1264:
! 1265: /* unmap the page */
! 1266: dead_entries = NULL;
! 1267: uvm_unmap_remove(map, (vaddr_t)pvp, ((vaddr_t)pvp) + PAGE_SIZE,
! 1268: &dead_entries, NULL);
! 1269: vm_map_unlock(map);
! 1270:
! 1271: if (dead_entries != NULL)
! 1272: uvm_unmap_detach(dead_entries, 0);
! 1273:
! 1274: pv_nfpvents -= PVE_PER_PVPAGE; /* update free count */
! 1275: }
! 1276:
! 1277: if (pvp == pv_initpage)
! 1278: /* no more initpage, we've freed it */
! 1279: pv_initpage = NULL;
! 1280:
! 1281: splx(s);
! 1282: }
! 1283:
! 1284: /*
! 1285: * main pv_entry manipulation functions:
! 1286: * pmap_enter_pv: enter a mapping onto a pv list
! 1287: * pmap_remove_pv: remove a mappiing from a pv list
! 1288: */
! 1289:
! 1290: /*
! 1291: * pmap_enter_pv: enter a mapping onto a pv list
! 1292: *
! 1293: * => caller should have pmap locked
! 1294: * => we will gain the lock on the pv and allocate the new pv_entry
! 1295: * => caller should adjust ptp's wire_count before calling
! 1296: *
! 1297: * pve: preallocated pve for us to use
! 1298: * ptp: PTP in pmap that maps this VA
! 1299: */
! 1300:
! 1301: void
! 1302: pmap_enter_pv(struct vm_page *pg, struct pv_entry *pve, struct pmap *pmap,
! 1303: vaddr_t va, struct vm_page *ptp)
! 1304: {
! 1305: pve->pv_pmap = pmap;
! 1306: pve->pv_va = va;
! 1307: pve->pv_ptp = ptp; /* NULL for kernel pmap */
! 1308: pve->pv_next = pg->mdpage.pv_list; /* add to ... */
! 1309: pg->mdpage.pv_list = pve; /* ... locked list */
! 1310: }
! 1311:
! 1312: /*
! 1313: * pmap_remove_pv: try to remove a mapping from a pv_list
! 1314: *
! 1315: * => pmap should be locked
! 1316: * => caller should hold lock on pv [so that attrs can be adjusted]
! 1317: * => caller should adjust ptp's wire_count and free PTP if needed
! 1318: * => we return the removed pve
! 1319: */
! 1320:
! 1321: struct pv_entry *
! 1322: pmap_remove_pv(struct vm_page *pg, struct pmap *pmap, vaddr_t va)
! 1323: {
! 1324: struct pv_entry *pve, **prevptr;
! 1325:
! 1326: prevptr = &pg->mdpage.pv_list; /* previous pv_entry pointer */
! 1327: while ((pve = *prevptr) != NULL) {
! 1328: if (pve->pv_pmap == pmap && pve->pv_va == va) { /* match? */
! 1329: *prevptr = pve->pv_next; /* remove it! */
! 1330: break;
! 1331: }
! 1332: prevptr = &pve->pv_next; /* previous pointer */
! 1333: }
! 1334: return(pve); /* return removed pve */
! 1335: }
! 1336:
! 1337: /*
! 1338: * p t p f u n c t i o n s
! 1339: */
! 1340:
! 1341: /*
! 1342: * pmap_alloc_ptp: allocate a PTP for a PMAP
! 1343: *
! 1344: * => pmap should already be locked by caller
! 1345: * => we use the ptp's wire_count to count the number of active mappings
! 1346: * in the PTP (we start it at one to prevent any chance this PTP
! 1347: * will ever leak onto the active/inactive queues)
! 1348: * => we may need to lock pv lists if we have to steal a PTP
! 1349: * => just_try: true if we want a PTP, but not enough to steal one
! 1350: * from another pmap (e.g. during optional functions like pmap_copy)
! 1351: */
! 1352:
! 1353: struct vm_page *
! 1354: pmap_alloc_ptp(struct pmap *pmap, int pde_index, boolean_t just_try,
! 1355: pt_entry_t pde_flags)
! 1356: {
! 1357: struct vm_page *ptp;
! 1358:
! 1359: ptp = uvm_pagealloc(&pmap->pm_obj, ptp_i2o(pde_index), NULL,
! 1360: UVM_PGA_USERESERVE|UVM_PGA_ZERO);
! 1361: if (ptp == NULL)
! 1362: return (NULL);
! 1363:
! 1364: /* got one! */
! 1365: atomic_clearbits_int(&ptp->pg_flags, PG_BUSY);
! 1366: ptp->wire_count = 1; /* no mappings yet */
! 1367: pmap->pm_pdir[pde_index] = (pd_entry_t)(VM_PAGE_TO_PHYS(ptp) |
! 1368: PG_RW | PG_V | PG_M | PG_U | pde_flags);
! 1369: pmap->pm_stats.resident_count++; /* count PTP as resident */
! 1370: pmap->pm_ptphint = ptp;
! 1371: return(ptp);
! 1372: }
! 1373:
! 1374: /*
! 1375: * pmap_get_ptp: get a PTP (if there isn't one, allocate a new one)
! 1376: *
! 1377: * => pmap should NOT be pmap_kernel()
! 1378: * => pmap should be locked
! 1379: */
! 1380:
! 1381: struct vm_page *
! 1382: pmap_get_ptp(struct pmap *pmap, int pde_index, boolean_t just_try)
! 1383: {
! 1384: struct vm_page *ptp;
! 1385:
! 1386: if (pmap_valid_entry(pmap->pm_pdir[pde_index])) {
! 1387:
! 1388: /* valid... check hint (saves us a PA->PG lookup) */
! 1389: if (pmap->pm_ptphint &&
! 1390: (pmap->pm_pdir[pde_index] & PG_FRAME) ==
! 1391: VM_PAGE_TO_PHYS(pmap->pm_ptphint))
! 1392: return(pmap->pm_ptphint);
! 1393:
! 1394: ptp = uvm_pagelookup(&pmap->pm_obj, ptp_i2o(pde_index));
! 1395: #ifdef DIAGNOSTIC
! 1396: if (ptp == NULL)
! 1397: panic("pmap_get_ptp: unmanaged user PTP");
! 1398: #endif
! 1399: pmap->pm_ptphint = ptp;
! 1400: return(ptp);
! 1401: }
! 1402:
! 1403: /* allocate a new PTP (updates ptphint) */
! 1404: return (pmap_alloc_ptp(pmap, pde_index, just_try, PG_u));
! 1405: }
! 1406:
! 1407: /*
! 1408: * p m a p l i f e c y c l e f u n c t i o n s
! 1409: */
! 1410:
! 1411: /*
! 1412: * pmap_create: create a pmap
! 1413: *
! 1414: * => note: old pmap interface took a "size" args which allowed for
! 1415: * the creation of "software only" pmaps (not in bsd).
! 1416: */
! 1417:
! 1418: struct pmap *
! 1419: pmap_create(void)
! 1420: {
! 1421: struct pmap *pmap;
! 1422:
! 1423: pmap = pool_get(&pmap_pmap_pool, PR_WAITOK);
! 1424: pmap_pinit(pmap);
! 1425: return(pmap);
! 1426: }
! 1427:
! 1428: /*
! 1429: * pmap_pinit: given a zero'd pmap structure, init it.
! 1430: */
! 1431:
! 1432: void
! 1433: pmap_pinit(struct pmap *pmap)
! 1434: {
! 1435: /* init uvm_object */
! 1436: simple_lock_init(&pmap->pm_obj.vmobjlock);
! 1437: pmap->pm_obj.pgops = NULL; /* currently not a mappable object */
! 1438: TAILQ_INIT(&pmap->pm_obj.memq);
! 1439: pmap->pm_obj.uo_npages = 0;
! 1440: pmap->pm_obj.uo_refs = 1;
! 1441: pmap->pm_stats.wired_count = 0;
! 1442: pmap->pm_stats.resident_count = 1; /* count the PDP allocd below */
! 1443: pmap->pm_ptphint = NULL;
! 1444: pmap->pm_hiexec = 0;
! 1445: pmap->pm_flags = 0;
! 1446: pmap->pm_cpus = 0;
! 1447:
! 1448: setsegment(&pmap->pm_codeseg, 0, atop(I386_MAX_EXE_ADDR) - 1,
! 1449: SDT_MEMERA, SEL_UPL, 1, 1);
! 1450:
! 1451: /* allocate PDP */
! 1452: pmap->pm_pdir = (pd_entry_t *) uvm_km_alloc(kernel_map, NBPG);
! 1453: if (pmap->pm_pdir == NULL)
! 1454: panic("pmap_pinit: kernel_map out of virtual space!");
! 1455: (void) pmap_extract(pmap_kernel(), (vaddr_t)pmap->pm_pdir,
! 1456: (paddr_t *)&pmap->pm_pdirpa);
! 1457:
! 1458: /* init PDP */
! 1459: /* zero init area */
! 1460: bzero(pmap->pm_pdir, PDSLOT_PTE * sizeof(pd_entry_t));
! 1461: /* put in recursive PDE to map the PTEs */
! 1462: pmap->pm_pdir[PDSLOT_PTE] = pmap->pm_pdirpa | PG_V | PG_KW | PG_U |
! 1463: PG_M;
! 1464:
! 1465: /* init the LDT */
! 1466: pmap->pm_ldt = NULL;
! 1467: pmap->pm_ldt_len = 0;
! 1468: pmap->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
! 1469:
! 1470: /*
! 1471: * we need to lock pmaps_lock to prevent nkpde from changing on
! 1472: * us. note that there is no need to splvm to protect us from
! 1473: * malloc since malloc allocates out of a submap and we should have
! 1474: * already allocated kernel PTPs to cover the range...
! 1475: */
! 1476: simple_lock(&pmaps_lock);
! 1477: /* put in kernel VM PDEs */
! 1478: bcopy(&PDP_BASE[PDSLOT_KERN], &pmap->pm_pdir[PDSLOT_KERN],
! 1479: nkpde * sizeof(pd_entry_t));
! 1480: /* zero the rest */
! 1481: bzero(&pmap->pm_pdir[PDSLOT_KERN + nkpde],
! 1482: NBPG - ((PDSLOT_KERN + nkpde) * sizeof(pd_entry_t)));
! 1483: LIST_INSERT_HEAD(&pmaps, pmap, pm_list);
! 1484: simple_unlock(&pmaps_lock);
! 1485: }
! 1486:
! 1487: /*
! 1488: * pmap_destroy: drop reference count on pmap. free pmap if
! 1489: * reference count goes to zero.
! 1490: */
! 1491:
! 1492: void
! 1493: pmap_destroy(struct pmap *pmap)
! 1494: {
! 1495: int refs;
! 1496:
! 1497: /*
! 1498: * drop reference count
! 1499: */
! 1500:
! 1501: simple_lock(&pmap->pm_obj.vmobjlock);
! 1502: refs = --pmap->pm_obj.uo_refs;
! 1503: simple_unlock(&pmap->pm_obj.vmobjlock);
! 1504: if (refs > 0)
! 1505: return;
! 1506:
! 1507: /*
! 1508: * reference count is zero, free pmap resources and then free pmap.
! 1509: */
! 1510:
! 1511: pmap_release(pmap);
! 1512: pool_put(&pmap_pmap_pool, pmap);
! 1513: }
! 1514:
! 1515: /*
! 1516: * pmap_release: release all resources held by a pmap
! 1517: *
! 1518: * => if pmap is still referenced it should be locked
! 1519: * => XXX: we currently don't expect any busy PTPs because we don't
! 1520: * allow anything to map them (except for the kernel's private
! 1521: * recursive mapping) or make them busy.
! 1522: */
! 1523:
! 1524: void
! 1525: pmap_release(struct pmap *pmap)
! 1526: {
! 1527: struct vm_page *pg;
! 1528:
! 1529: /*
! 1530: * remove it from global list of pmaps
! 1531: */
! 1532:
! 1533: simple_lock(&pmaps_lock);
! 1534: LIST_REMOVE(pmap, pm_list);
! 1535: simple_unlock(&pmaps_lock);
! 1536:
! 1537: /*
! 1538: * Before we free the pmap just make sure it's not cached anywhere.
! 1539: */
! 1540: tlbflushg();
! 1541:
! 1542: /*
! 1543: * free any remaining PTPs
! 1544: */
! 1545:
! 1546: while (!TAILQ_EMPTY(&pmap->pm_obj.memq)) {
! 1547: pg = TAILQ_FIRST(&pmap->pm_obj.memq);
! 1548: #ifdef DIAGNOSTIC
! 1549: if (pg->pg_flags & PG_BUSY)
! 1550: panic("pmap_release: busy page table page");
! 1551: #endif
! 1552: /* pmap_page_protect? currently no need for it. */
! 1553:
! 1554: pg->wire_count = 0;
! 1555: uvm_pagefree(pg);
! 1556: }
! 1557:
! 1558: /*
! 1559: * MULTIPROCESSOR -- no need to flush out of other processors'
! 1560: * APTE space because we do that in pmap_unmap_ptes().
! 1561: */
! 1562: uvm_km_free(kernel_map, (vaddr_t)pmap->pm_pdir, NBPG);
! 1563:
! 1564: #ifdef USER_LDT
! 1565: if (pmap->pm_flags & PMF_USER_LDT) {
! 1566: /*
! 1567: * no need to switch the LDT; this address space is gone,
! 1568: * nothing is using it.
! 1569: *
! 1570: * No need to lock the pmap for ldt_free (or anything else),
! 1571: * we're the last one to use it.
! 1572: */
! 1573: ldt_free(pmap);
! 1574: uvm_km_free(kernel_map, (vaddr_t)pmap->pm_ldt,
! 1575: pmap->pm_ldt_len * sizeof(union descriptor));
! 1576: }
! 1577: #endif
! 1578: }
! 1579:
! 1580: /*
! 1581: * Add a reference to the specified pmap.
! 1582: */
! 1583:
! 1584: void
! 1585: pmap_reference(struct pmap *pmap)
! 1586: {
! 1587: simple_lock(&pmap->pm_obj.vmobjlock);
! 1588: pmap->pm_obj.uo_refs++;
! 1589: simple_unlock(&pmap->pm_obj.vmobjlock);
! 1590: }
! 1591:
! 1592: #if defined(PMAP_FORK)
! 1593: /*
! 1594: * pmap_fork: perform any necessary data structure manipulation when
! 1595: * a VM space is forked.
! 1596: */
! 1597:
! 1598: void
! 1599: pmap_fork(struct pmap *pmap1, struct pmap *pmap2)
! 1600: {
! 1601: simple_lock(&pmap1->pm_obj.vmobjlock);
! 1602: simple_lock(&pmap2->pm_obj.vmobjlock);
! 1603:
! 1604: #ifdef USER_LDT
! 1605: /* Copy the LDT, if necessary. */
! 1606: if (pmap1->pm_flags & PMF_USER_LDT) {
! 1607: union descriptor *new_ldt;
! 1608: size_t len;
! 1609:
! 1610: len = pmap1->pm_ldt_len * sizeof(union descriptor);
! 1611: new_ldt = (union descriptor *)uvm_km_alloc(kernel_map, len);
! 1612: bcopy(pmap1->pm_ldt, new_ldt, len);
! 1613: pmap2->pm_ldt = new_ldt;
! 1614: pmap2->pm_ldt_len = pmap1->pm_ldt_len;
! 1615: pmap2->pm_flags |= PMF_USER_LDT;
! 1616: ldt_alloc(pmap2, new_ldt, len);
! 1617: }
! 1618: #endif /* USER_LDT */
! 1619:
! 1620: simple_unlock(&pmap2->pm_obj.vmobjlock);
! 1621: simple_unlock(&pmap1->pm_obj.vmobjlock);
! 1622: }
! 1623: #endif /* PMAP_FORK */
! 1624:
! 1625: #ifdef USER_LDT
! 1626: /*
! 1627: * pmap_ldt_cleanup: if the pmap has a local LDT, deallocate it, and
! 1628: * restore the default.
! 1629: */
! 1630:
! 1631: void
! 1632: pmap_ldt_cleanup(struct proc *p)
! 1633: {
! 1634: struct pcb *pcb = &p->p_addr->u_pcb;
! 1635: pmap_t pmap = p->p_vmspace->vm_map.pmap;
! 1636: union descriptor *old_ldt = NULL;
! 1637: size_t len = 0;
! 1638:
! 1639: simple_lock(&pmap->pm_obj.vmobjlock);
! 1640:
! 1641: if (pmap->pm_flags & PMF_USER_LDT) {
! 1642: ldt_free(pmap);
! 1643: pmap->pm_ldt_sel = GSEL(GLDT_SEL, SEL_KPL);
! 1644: pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
! 1645: /* Reset the cached address of the LDT that this process uses */
! 1646: #ifdef MULTIPROCESSOR
! 1647: pcb->pcb_ldt = curcpu()->ci_ldt;
! 1648: #else
! 1649: pcb->pcb_ldt = ldt;
! 1650: #endif
! 1651: if (pcb == curpcb)
! 1652: lldt(pcb->pcb_ldt_sel);
! 1653: old_ldt = pmap->pm_ldt;
! 1654: len = pmap->pm_ldt_len * sizeof(union descriptor);
! 1655: pmap->pm_ldt = NULL;
! 1656: pmap->pm_ldt_len = 0;
! 1657: pmap->pm_flags &= ~PMF_USER_LDT;
! 1658: }
! 1659:
! 1660: simple_unlock(&pmap->pm_obj.vmobjlock);
! 1661:
! 1662: if (old_ldt != NULL)
! 1663: uvm_km_free(kernel_map, (vaddr_t)old_ldt, len);
! 1664: }
! 1665: #endif /* USER_LDT */
! 1666:
! 1667: /*
! 1668: * pmap_activate: activate a process' pmap (fill in %cr3 and LDT info)
! 1669: *
! 1670: * => called from cpu_switch()
! 1671: * => if proc is the curproc, then load it into the MMU
! 1672: */
! 1673:
! 1674: void
! 1675: pmap_activate(struct proc *p)
! 1676: {
! 1677: struct pcb *pcb = &p->p_addr->u_pcb;
! 1678: struct pmap *pmap = p->p_vmspace->vm_map.pmap;
! 1679: struct cpu_info *self = curcpu();
! 1680:
! 1681: pcb->pcb_pmap = pmap;
! 1682: /* Get the LDT that this process will actually use */
! 1683: #ifdef MULTIPROCESSOR
! 1684: pcb->pcb_ldt = pmap->pm_ldt == NULL ? self->ci_ldt : pmap->pm_ldt;
! 1685: #else
! 1686: pcb->pcb_ldt = pmap->pm_ldt == NULL ? ldt : pmap->pm_ldt;
! 1687: #endif
! 1688: pcb->pcb_ldt_sel = pmap->pm_ldt_sel;
! 1689: pcb->pcb_cr3 = pmap->pm_pdirpa;
! 1690: if (p == curproc) {
! 1691: /*
! 1692: * Set the correct descriptor value (i.e. with the
! 1693: * correct code segment X limit) in the GDT and the LDT.
! 1694: */
! 1695: self->ci_gdt[GUCODE_SEL].sd = pcb->pcb_ldt[LUCODE_SEL].sd =
! 1696: pmap->pm_codeseg;
! 1697:
! 1698: lcr3(pcb->pcb_cr3);
! 1699: lldt(pcb->pcb_ldt_sel);
! 1700:
! 1701: /*
! 1702: * mark the pmap in use by this processor.
! 1703: */
! 1704: i386_atomic_setbits_l(&pmap->pm_cpus, (1U << cpu_number()));
! 1705: }
! 1706: }
! 1707:
! 1708: /*
! 1709: * pmap_deactivate: deactivate a process' pmap
! 1710: */
! 1711:
! 1712: void
! 1713: pmap_deactivate(struct proc *p)
! 1714: {
! 1715: struct pmap *pmap = p->p_vmspace->vm_map.pmap;
! 1716:
! 1717: /*
! 1718: * mark the pmap no longer in use by this processor.
! 1719: */
! 1720: i386_atomic_clearbits_l(&pmap->pm_cpus, (1U << cpu_number()));
! 1721: }
! 1722:
! 1723: /*
! 1724: * end of lifecycle functions
! 1725: */
! 1726:
! 1727: /*
! 1728: * some misc. functions
! 1729: */
! 1730:
! 1731: /*
! 1732: * pmap_extract: extract a PA for the given VA
! 1733: */
! 1734:
! 1735: boolean_t
! 1736: pmap_extract(struct pmap *pmap, vaddr_t va, paddr_t *pap)
! 1737: {
! 1738: pt_entry_t *ptes, pte;
! 1739:
! 1740: if (pmap_valid_entry(pmap->pm_pdir[pdei(va)])) {
! 1741: ptes = pmap_map_ptes(pmap);
! 1742: pte = ptes[atop(va)];
! 1743: pmap_unmap_ptes(pmap);
! 1744: if (!pmap_valid_entry(pte))
! 1745: return (FALSE);
! 1746: if (pap != NULL)
! 1747: *pap = (pte & PG_FRAME) | (va & ~PG_FRAME);
! 1748: return (TRUE);
! 1749: }
! 1750: return (FALSE);
! 1751: }
! 1752:
! 1753: /*
! 1754: * pmap_virtual_space: used during bootup [pmap_steal_memory] to
! 1755: * determine the bounds of the kernel virtual address space.
! 1756: */
! 1757:
! 1758: void
! 1759: pmap_virtual_space(vaddr_t *startp, vaddr_t *endp)
! 1760: {
! 1761: *startp = virtual_avail;
! 1762: *endp = virtual_end;
! 1763: }
! 1764:
! 1765: /*
! 1766: * pmap_zero_page: zero a page
! 1767: */
! 1768: void (*pagezero)(void *, size_t) = bzero;
! 1769:
! 1770: void
! 1771: pmap_zero_page(struct vm_page *pg)
! 1772: {
! 1773: pmap_zero_phys(VM_PAGE_TO_PHYS(pg));
! 1774: }
! 1775:
! 1776: /*
! 1777: * pmap_zero_phys: same as pmap_zero_page, but for use before vm_pages are
! 1778: * initialized.
! 1779: */
! 1780: void
! 1781: pmap_zero_phys(paddr_t pa)
! 1782: {
! 1783: #ifdef MULTIPROCESSOR
! 1784: int id = cpu_number();
! 1785: #endif
! 1786: pt_entry_t *zpte = PTESLEW(zero_pte, id);
! 1787: caddr_t zerova = VASLEW(zerop, id);
! 1788:
! 1789: #ifdef DIAGNOSTIC
! 1790: if (*zpte)
! 1791: panic("pmap_zero_phys: lock botch");
! 1792: #endif
! 1793:
! 1794: *zpte = (pa & PG_FRAME) | PG_V | PG_RW; /* map in */
! 1795: pmap_update_pg((vaddr_t)zerova); /* flush TLB */
! 1796: pagezero(zerova, PAGE_SIZE); /* zero */
! 1797: *zpte = 0; /* zap! */
! 1798: }
! 1799:
! 1800: /*
! 1801: * pmap_zero_page_uncached: the same, except uncached.
! 1802: */
! 1803:
! 1804: boolean_t
! 1805: pmap_zero_page_uncached(paddr_t pa)
! 1806: {
! 1807: #ifdef MULTIPROCESSOR
! 1808: int id = cpu_number();
! 1809: #endif
! 1810: pt_entry_t *zpte = PTESLEW(zero_pte, id);
! 1811: caddr_t zerova = VASLEW(zerop, id);
! 1812:
! 1813: #ifdef DIAGNOSTIC
! 1814: if (*zpte)
! 1815: panic("pmap_zero_page_uncached: lock botch");
! 1816: #endif
! 1817:
! 1818: *zpte = (pa & PG_FRAME) | PG_V | PG_RW | PG_N; /* map in */
! 1819: pmap_update_pg((vaddr_t)zerova); /* flush TLB */
! 1820: pagezero(zerova, PAGE_SIZE); /* zero */
! 1821: *zpte = 0; /* zap! */
! 1822:
! 1823: return (TRUE);
! 1824: }
! 1825:
! 1826: /*
! 1827: * pmap_copy_page: copy a page
! 1828: */
! 1829:
! 1830: void
! 1831: pmap_copy_page(struct vm_page *srcpg, struct vm_page *dstpg)
! 1832: {
! 1833: paddr_t srcpa = VM_PAGE_TO_PHYS(srcpg);
! 1834: paddr_t dstpa = VM_PAGE_TO_PHYS(dstpg);
! 1835: #ifdef MULTIPROCESSOR
! 1836: int id = cpu_number();
! 1837: #endif
! 1838: pt_entry_t *spte = PTESLEW(csrc_pte, id);
! 1839: pt_entry_t *dpte = PTESLEW(cdst_pte, id);
! 1840: caddr_t csrcva = VASLEW(csrcp, id);
! 1841: caddr_t cdstva = VASLEW(cdstp, id);
! 1842:
! 1843: #ifdef DIAGNOSTIC
! 1844: if (*spte || *dpte)
! 1845: panic("pmap_copy_page: lock botch");
! 1846: #endif
! 1847:
! 1848: *spte = (srcpa & PG_FRAME) | PG_V | PG_RW;
! 1849: *dpte = (dstpa & PG_FRAME) | PG_V | PG_RW;
! 1850: pmap_update_2pg((vaddr_t)csrcva, (vaddr_t)cdstva);
! 1851: bcopy(csrcva, cdstva, PAGE_SIZE);
! 1852: *spte = *dpte = 0; /* zap! */
! 1853: pmap_update_2pg((vaddr_t)csrcva, (vaddr_t)cdstva);
! 1854: }
! 1855:
! 1856: /*
! 1857: * p m a p r e m o v e f u n c t i o n s
! 1858: *
! 1859: * functions that remove mappings
! 1860: */
! 1861:
! 1862: /*
! 1863: * pmap_remove_ptes: remove PTEs from a PTP
! 1864: *
! 1865: * => must have proper locking on pmap_master_lock
! 1866: * => caller must hold pmap's lock
! 1867: * => PTP must be mapped into KVA
! 1868: * => PTP should be null if pmap == pmap_kernel()
! 1869: */
! 1870:
! 1871: void
! 1872: pmap_remove_ptes(struct pmap *pmap, struct vm_page *ptp, vaddr_t ptpva,
! 1873: vaddr_t startva, vaddr_t endva, int flags)
! 1874: {
! 1875: struct pv_entry *pv_tofree = NULL; /* list of pv_entrys to free */
! 1876: struct pv_entry *pve;
! 1877: pt_entry_t *pte = (pt_entry_t *) ptpva;
! 1878: struct vm_page *pg;
! 1879: pt_entry_t opte;
! 1880:
! 1881: /*
! 1882: * note that ptpva points to the PTE that maps startva. this may
! 1883: * or may not be the first PTE in the PTP.
! 1884: *
! 1885: * we loop through the PTP while there are still PTEs to look at
! 1886: * and the wire_count is greater than 1 (because we use the wire_count
! 1887: * to keep track of the number of real PTEs in the PTP).
! 1888: */
! 1889:
! 1890: for (/*null*/; startva < endva && (ptp == NULL || ptp->wire_count > 1)
! 1891: ; pte++, startva += NBPG) {
! 1892: if (!pmap_valid_entry(*pte))
! 1893: continue; /* VA not mapped */
! 1894:
! 1895: if ((flags & PMAP_REMOVE_SKIPWIRED) && (*pte & PG_W))
! 1896: continue;
! 1897:
! 1898: /* atomically save the old PTE and zap! it */
! 1899: opte = i386_atomic_testset_ul(pte, 0);
! 1900:
! 1901: if (opte & PG_W)
! 1902: pmap->pm_stats.wired_count--;
! 1903: pmap->pm_stats.resident_count--;
! 1904:
! 1905: if (ptp)
! 1906: ptp->wire_count--; /* dropping a PTE */
! 1907:
! 1908: /*
! 1909: * Unnecessary work if not PG_VLIST.
! 1910: */
! 1911: pg = PHYS_TO_VM_PAGE(opte & PG_FRAME);
! 1912:
! 1913: /*
! 1914: * if we are not on a pv list we are done.
! 1915: */
! 1916: if ((opte & PG_PVLIST) == 0) {
! 1917: #ifdef DIAGNOSTIC
! 1918: if (pg != NULL)
! 1919: panic("pmap_remove_ptes: managed page without "
! 1920: "PG_PVLIST for 0x%lx", startva);
! 1921: #endif
! 1922: continue;
! 1923: }
! 1924:
! 1925: #ifdef DIAGNOSTIC
! 1926: if (pg == NULL)
! 1927: panic("pmap_remove_ptes: unmanaged page marked "
! 1928: "PG_PVLIST, va = 0x%lx, pa = 0x%lx",
! 1929: startva, (u_long)(opte & PG_FRAME));
! 1930: #endif
! 1931:
! 1932: /* sync R/M bits */
! 1933: pmap_sync_flags_pte(pg, opte);
! 1934: pve = pmap_remove_pv(pg, pmap, startva);
! 1935: if (pve) {
! 1936: pve->pv_next = pv_tofree;
! 1937: pv_tofree = pve;
! 1938: }
! 1939:
! 1940: /* end of "for" loop: time for next pte */
! 1941: }
! 1942: if (pv_tofree)
! 1943: pmap_free_pvs(pmap, pv_tofree);
! 1944: }
! 1945:
! 1946:
! 1947: /*
! 1948: * pmap_remove_pte: remove a single PTE from a PTP
! 1949: *
! 1950: * => must have proper locking on pmap_master_lock
! 1951: * => caller must hold pmap's lock
! 1952: * => PTP must be mapped into KVA
! 1953: * => PTP should be null if pmap == pmap_kernel()
! 1954: * => returns true if we removed a mapping
! 1955: */
! 1956:
! 1957: boolean_t
! 1958: pmap_remove_pte(struct pmap *pmap, struct vm_page *ptp, pt_entry_t *pte,
! 1959: vaddr_t va, int flags)
! 1960: {
! 1961: struct pv_entry *pve;
! 1962: struct vm_page *pg;
! 1963: pt_entry_t opte;
! 1964:
! 1965: if (!pmap_valid_entry(*pte))
! 1966: return (FALSE); /* VA not mapped */
! 1967:
! 1968: if ((flags & PMAP_REMOVE_SKIPWIRED) && (*pte & PG_W))
! 1969: return (FALSE);
! 1970:
! 1971: opte = *pte; /* save the old PTE */
! 1972: *pte = 0; /* zap! */
! 1973:
! 1974: pmap_exec_account(pmap, va, opte, 0);
! 1975:
! 1976: if (opte & PG_W)
! 1977: pmap->pm_stats.wired_count--;
! 1978: pmap->pm_stats.resident_count--;
! 1979:
! 1980: if (ptp)
! 1981: ptp->wire_count--; /* dropping a PTE */
! 1982:
! 1983: pg = PHYS_TO_VM_PAGE(opte & PG_FRAME);
! 1984:
! 1985: /*
! 1986: * if we are not on a pv list we are done.
! 1987: */
! 1988: if ((opte & PG_PVLIST) == 0) {
! 1989: #ifdef DIAGNOSTIC
! 1990: if (pg != NULL)
! 1991: panic("pmap_remove_pte: managed page without "
! 1992: "PG_PVLIST for 0x%lx", va);
! 1993: #endif
! 1994: return(TRUE);
! 1995: }
! 1996:
! 1997: #ifdef DIAGNOSTIC
! 1998: if (pg == NULL)
! 1999: panic("pmap_remove_pte: unmanaged page marked "
! 2000: "PG_PVLIST, va = 0x%lx, pa = 0x%lx", va,
! 2001: (u_long)(opte & PG_FRAME));
! 2002: #endif
! 2003:
! 2004: pmap_sync_flags_pte(pg, opte);
! 2005: pve = pmap_remove_pv(pg, pmap, va);
! 2006: if (pve)
! 2007: pmap_free_pv(pmap, pve);
! 2008: return(TRUE);
! 2009: }
! 2010:
! 2011: /*
! 2012: * pmap_remove: top level mapping removal function
! 2013: *
! 2014: * => caller should not be holding any pmap locks
! 2015: */
! 2016:
! 2017: void
! 2018: pmap_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva)
! 2019: {
! 2020: pmap_do_remove(pmap, sva, eva, PMAP_REMOVE_ALL);
! 2021: }
! 2022:
! 2023: void
! 2024: pmap_do_remove(struct pmap *pmap, vaddr_t sva, vaddr_t eva, int flags)
! 2025: {
! 2026: pt_entry_t *ptes, opte;
! 2027: boolean_t result;
! 2028: paddr_t ptppa;
! 2029: vaddr_t blkendva;
! 2030: struct vm_page *ptp;
! 2031: TAILQ_HEAD(, vm_page) empty_ptps;
! 2032: int shootall;
! 2033: vaddr_t va;
! 2034:
! 2035: TAILQ_INIT(&empty_ptps);
! 2036:
! 2037: PMAP_MAP_TO_HEAD_LOCK();
! 2038: ptes = pmap_map_ptes(pmap); /* locks pmap */
! 2039:
! 2040: /*
! 2041: * removing one page? take shortcut function.
! 2042: */
! 2043:
! 2044: if (sva + PAGE_SIZE == eva) {
! 2045:
! 2046: if (pmap_valid_entry(pmap->pm_pdir[pdei(sva)])) {
! 2047:
! 2048: /* PA of the PTP */
! 2049: ptppa = pmap->pm_pdir[pdei(sva)] & PG_FRAME;
! 2050:
! 2051: /* get PTP if non-kernel mapping */
! 2052:
! 2053: if (pmap == pmap_kernel()) {
! 2054: /* we never free kernel PTPs */
! 2055: ptp = NULL;
! 2056: } else {
! 2057: if (pmap->pm_ptphint &&
! 2058: VM_PAGE_TO_PHYS(pmap->pm_ptphint) ==
! 2059: ptppa) {
! 2060: ptp = pmap->pm_ptphint;
! 2061: } else {
! 2062: ptp = PHYS_TO_VM_PAGE(ptppa);
! 2063: #ifdef DIAGNOSTIC
! 2064: if (ptp == NULL)
! 2065: panic("pmap_remove: unmanaged "
! 2066: "PTP detected");
! 2067: #endif
! 2068: }
! 2069: }
! 2070:
! 2071: /* do it! */
! 2072: result = pmap_remove_pte(pmap, ptp, &ptes[atop(sva)],
! 2073: sva, flags);
! 2074:
! 2075: /*
! 2076: * if mapping removed and the PTP is no longer
! 2077: * being used, free it!
! 2078: */
! 2079:
! 2080: if (result && ptp && ptp->wire_count <= 1) {
! 2081: opte = i386_atomic_testset_ul(
! 2082: &pmap->pm_pdir[pdei(sva)], 0);
! 2083: #ifdef MULTIPROCESSOR
! 2084: /*
! 2085: * XXXthorpej Redundant shootdown can happen
! 2086: * here if we're using APTE space.
! 2087: */
! 2088: #endif
! 2089: pmap_tlb_shootpage(curpcb->pcb_pmap,
! 2090: ((vaddr_t)ptes) + ptp->offset);
! 2091: #ifdef MULTIPROCESSOR
! 2092: /*
! 2093: * Always shoot down the pmap's self-mapping
! 2094: * of the PTP.
! 2095: * XXXthorpej Redundant shootdown can happen
! 2096: * here if pmap == curpcb->pcb_pmap (not APTE
! 2097: * space).
! 2098: */
! 2099: pmap_tlb_shootpage(pmap,
! 2100: ((vaddr_t)PTE_BASE) + ptp->offset);
! 2101: #endif
! 2102: pmap->pm_stats.resident_count--;
! 2103: if (pmap->pm_ptphint == ptp)
! 2104: pmap->pm_ptphint =
! 2105: TAILQ_FIRST(&pmap->pm_obj.memq);
! 2106: ptp->wire_count = 0;
! 2107: /* Postpone free to after shootdown. */
! 2108: uvm_pagerealloc(ptp, NULL, 0);
! 2109: TAILQ_INSERT_TAIL(&empty_ptps, ptp, listq);
! 2110: }
! 2111: /*
! 2112: * Shoot the tlb after any updates to the PDE.
! 2113: */
! 2114: pmap_tlb_shootpage(pmap, sva);
! 2115: }
! 2116: pmap_tlb_shootwait();
! 2117: pmap_unmap_ptes(pmap); /* unlock pmap */
! 2118: PMAP_MAP_TO_HEAD_UNLOCK();
! 2119: while ((ptp = TAILQ_FIRST(&empty_ptps)) != NULL) {
! 2120: TAILQ_REMOVE(&empty_ptps, ptp, listq);
! 2121: uvm_pagefree(ptp);
! 2122: }
! 2123: return;
! 2124: }
! 2125:
! 2126: /*
! 2127: * Decide if we want to shoot the whole tlb or just the range.
! 2128: * Right now, we simply shoot everything when we remove more
! 2129: * than 32 pages, but never in the kernel pmap. XXX - tune.
! 2130: */
! 2131: if ((eva - sva > 32 * PAGE_SIZE) && pmap != pmap_kernel())
! 2132: shootall = 1;
! 2133: else
! 2134: shootall = 0;
! 2135:
! 2136: for (va = sva ; va < eva ; va = blkendva) {
! 2137: /* determine range of block */
! 2138: blkendva = i386_round_pdr(va + 1);
! 2139: if (blkendva > eva)
! 2140: blkendva = eva;
! 2141:
! 2142: /*
! 2143: * XXXCDC: our PTE mappings should never be removed
! 2144: * with pmap_remove! if we allow this (and why would
! 2145: * we?) then we end up freeing the pmap's page
! 2146: * directory page (PDP) before we are finished using
! 2147: * it when we hit in in the recursive mapping. this
! 2148: * is BAD.
! 2149: *
! 2150: * long term solution is to move the PTEs out of user
! 2151: * address space. and into kernel address space (up
! 2152: * with APTE). then we can set VM_MAXUSER_ADDRESS to
! 2153: * be VM_MAX_ADDRESS.
! 2154: */
! 2155:
! 2156: if (pdei(va) == PDSLOT_PTE)
! 2157: /* XXXCDC: ugly hack to avoid freeing PDP here */
! 2158: continue;
! 2159:
! 2160: if (!pmap_valid_entry(pmap->pm_pdir[pdei(va)]))
! 2161: /* valid block? */
! 2162: continue;
! 2163:
! 2164: /* PA of the PTP */
! 2165: ptppa = (pmap->pm_pdir[pdei(va)] & PG_FRAME);
! 2166:
! 2167: /* get PTP if non-kernel mapping */
! 2168: if (pmap == pmap_kernel()) {
! 2169: /* we never free kernel PTPs */
! 2170: ptp = NULL;
! 2171: } else {
! 2172: if (pmap->pm_ptphint &&
! 2173: VM_PAGE_TO_PHYS(pmap->pm_ptphint) == ptppa) {
! 2174: ptp = pmap->pm_ptphint;
! 2175: } else {
! 2176: ptp = PHYS_TO_VM_PAGE(ptppa);
! 2177: #ifdef DIAGNOSTIC
! 2178: if (ptp == NULL)
! 2179: panic("pmap_remove: unmanaged PTP "
! 2180: "detected");
! 2181: #endif
! 2182: }
! 2183: }
! 2184: pmap_remove_ptes(pmap, ptp, (vaddr_t)&ptes[atop(va)],
! 2185: va, blkendva, flags);
! 2186:
! 2187: /* if PTP is no longer being used, free it! */
! 2188: if (ptp && ptp->wire_count <= 1) {
! 2189: opte = i386_atomic_testset_ul(
! 2190: &pmap->pm_pdir[pdei(va)], 0);
! 2191: #if defined(MULTIPROCESSOR)
! 2192: /*
! 2193: * XXXthorpej Redundant shootdown can happen here
! 2194: * if we're using APTE space.
! 2195: */
! 2196: #endif
! 2197: pmap_tlb_shootpage(curpcb->pcb_pmap,
! 2198: ((vaddr_t)ptes) + ptp->offset);
! 2199: #if defined(MULTIPROCESSOR)
! 2200: /*
! 2201: * Always shoot down the pmap's self-mapping
! 2202: * of the PTP.
! 2203: * XXXthorpej Redundant shootdown can happen here
! 2204: * if pmap == curpcb->pcb_pmap (not APTE space).
! 2205: */
! 2206: pmap_tlb_shootpage(pmap,
! 2207: ((vaddr_t)PTE_BASE) + ptp->offset);
! 2208: #endif
! 2209: pmap->pm_stats.resident_count--;
! 2210: if (pmap->pm_ptphint == ptp) /* update hint? */
! 2211: pmap->pm_ptphint =
! 2212: TAILQ_FIRST(&pmap->pm_obj.memq);
! 2213: ptp->wire_count = 0;
! 2214: /* Postpone free to after shootdown. */
! 2215: uvm_pagerealloc(ptp, NULL, 0);
! 2216: TAILQ_INSERT_TAIL(&empty_ptps, ptp, listq);
! 2217: }
! 2218: }
! 2219: if (!shootall)
! 2220: pmap_tlb_shootrange(pmap, sva, eva);
! 2221: else
! 2222: pmap_tlb_shoottlb();
! 2223:
! 2224: pmap_tlb_shootwait();
! 2225: pmap_unmap_ptes(pmap);
! 2226: PMAP_MAP_TO_HEAD_UNLOCK();
! 2227: while ((ptp = TAILQ_FIRST(&empty_ptps)) != NULL) {
! 2228: TAILQ_REMOVE(&empty_ptps, ptp, listq);
! 2229: uvm_pagefree(ptp);
! 2230: }
! 2231: }
! 2232:
! 2233: /*
! 2234: * pmap_page_remove: remove a managed vm_page from all pmaps that map it
! 2235: *
! 2236: * => R/M bits are sync'd back to attrs
! 2237: */
! 2238:
! 2239: void
! 2240: pmap_page_remove(struct vm_page *pg)
! 2241: {
! 2242: struct pv_entry *pve;
! 2243: pt_entry_t *ptes, opte;
! 2244: TAILQ_HEAD(, vm_page) empty_ptps;
! 2245: struct vm_page *ptp;
! 2246:
! 2247: if (pg->mdpage.pv_list == NULL)
! 2248: return;
! 2249:
! 2250: TAILQ_INIT(&empty_ptps);
! 2251:
! 2252: PMAP_HEAD_TO_MAP_LOCK();
! 2253:
! 2254: for (pve = pg->mdpage.pv_list ; pve != NULL ; pve = pve->pv_next) {
! 2255: ptes = pmap_map_ptes(pve->pv_pmap); /* locks pmap */
! 2256:
! 2257: #ifdef DIAGNOSTIC
! 2258: if (pve->pv_va >= uvm.pager_sva && pve->pv_va < uvm.pager_eva)
! 2259: printf("pmap_page_remove: found pager VA on pv_list\n");
! 2260: if (pve->pv_ptp && (pve->pv_pmap->pm_pdir[pdei(pve->pv_va)] &
! 2261: PG_FRAME)
! 2262: != VM_PAGE_TO_PHYS(pve->pv_ptp)) {
! 2263: printf("pmap_page_remove: pg=%p: va=%lx, pv_ptp=%p\n",
! 2264: pg, pve->pv_va, pve->pv_ptp);
! 2265: printf("pmap_page_remove: PTP's phys addr: "
! 2266: "actual=%x, recorded=%lx\n",
! 2267: (pve->pv_pmap->pm_pdir[pdei(pve->pv_va)] &
! 2268: PG_FRAME), VM_PAGE_TO_PHYS(pve->pv_ptp));
! 2269: panic("pmap_page_remove: mapped managed page has "
! 2270: "invalid pv_ptp field");
! 2271: }
! 2272: #endif
! 2273:
! 2274: opte = i386_atomic_testset_ul(&ptes[atop(pve->pv_va)], 0);
! 2275:
! 2276: if (opte & PG_W)
! 2277: pve->pv_pmap->pm_stats.wired_count--;
! 2278: pve->pv_pmap->pm_stats.resident_count--;
! 2279:
! 2280: /* sync R/M bits */
! 2281: pmap_sync_flags_pte(pg, opte);
! 2282:
! 2283: /* update the PTP reference count. free if last reference. */
! 2284: if (pve->pv_ptp) {
! 2285: pve->pv_ptp->wire_count--;
! 2286: if (pve->pv_ptp->wire_count <= 1) {
! 2287: opte = i386_atomic_testset_ul(
! 2288: &pve->pv_pmap->pm_pdir[pdei(pve->pv_va)],
! 2289: 0);
! 2290: pmap_tlb_shootpage(curpcb->pcb_pmap,
! 2291: ((vaddr_t)ptes) + pve->pv_ptp->offset);
! 2292: #if defined(MULTIPROCESSOR)
! 2293: /*
! 2294: * Always shoot down the other pmap's
! 2295: * self-mapping of the PTP.
! 2296: */
! 2297: pmap_tlb_shootpage(pve->pv_pmap,
! 2298: ((vaddr_t)PTE_BASE) + pve->pv_ptp->offset);
! 2299: #endif
! 2300: pve->pv_pmap->pm_stats.resident_count--;
! 2301: /* update hint? */
! 2302: if (pve->pv_pmap->pm_ptphint == pve->pv_ptp)
! 2303: pve->pv_pmap->pm_ptphint =
! 2304: TAILQ_FIRST(&pve->pv_pmap->pm_obj.memq);
! 2305: pve->pv_ptp->wire_count = 0;
! 2306: /* Postpone free to after shootdown. */
! 2307: uvm_pagerealloc(pve->pv_ptp, NULL, 0);
! 2308: TAILQ_INSERT_TAIL(&empty_ptps, pve->pv_ptp,
! 2309: listq);
! 2310: }
! 2311: }
! 2312:
! 2313: pmap_tlb_shootpage(pve->pv_pmap, pve->pv_va);
! 2314:
! 2315: pmap_unmap_ptes(pve->pv_pmap); /* unlocks pmap */
! 2316: }
! 2317: pmap_free_pvs(NULL, pg->mdpage.pv_list);
! 2318: pg->mdpage.pv_list = NULL;
! 2319: PMAP_HEAD_TO_MAP_UNLOCK();
! 2320: pmap_tlb_shootwait();
! 2321:
! 2322: while ((ptp = TAILQ_FIRST(&empty_ptps)) != NULL) {
! 2323: TAILQ_REMOVE(&empty_ptps, ptp, listq);
! 2324: uvm_pagefree(ptp);
! 2325: }
! 2326: }
! 2327:
! 2328: /*
! 2329: * p m a p a t t r i b u t e f u n c t i o n s
! 2330: * functions that test/change managed page's attributes
! 2331: * since a page can be mapped multiple times we must check each PTE that
! 2332: * maps it by going down the pv lists.
! 2333: */
! 2334:
! 2335: /*
! 2336: * pmap_test_attrs: test a page's attributes
! 2337: */
! 2338:
! 2339: boolean_t
! 2340: pmap_test_attrs(struct vm_page *pg, int testbits)
! 2341: {
! 2342: struct pv_entry *pve;
! 2343: pt_entry_t *ptes, pte;
! 2344: u_long mybits, testflags;
! 2345:
! 2346: testflags = pmap_pte2flags(testbits);
! 2347:
! 2348: if (pg->pg_flags & testflags)
! 2349: return (TRUE);
! 2350:
! 2351: PMAP_HEAD_TO_MAP_LOCK();
! 2352: mybits = 0;
! 2353: for (pve = pg->mdpage.pv_list; pve != NULL && mybits == 0;
! 2354: pve = pve->pv_next) {
! 2355: ptes = pmap_map_ptes(pve->pv_pmap);
! 2356: pte = ptes[atop(pve->pv_va)];
! 2357: pmap_unmap_ptes(pve->pv_pmap);
! 2358: mybits |= (pte & testbits);
! 2359: }
! 2360: PMAP_HEAD_TO_MAP_UNLOCK();
! 2361:
! 2362: if (mybits == 0)
! 2363: return (FALSE);
! 2364:
! 2365: atomic_setbits_int(&pg->pg_flags, pmap_pte2flags(mybits));
! 2366:
! 2367: return (TRUE);
! 2368: }
! 2369:
! 2370: /*
! 2371: * pmap_clear_attrs: change a page's attributes
! 2372: *
! 2373: * => we return TRUE if we cleared one of the bits we were asked to
! 2374: */
! 2375:
! 2376: boolean_t
! 2377: pmap_clear_attrs(struct vm_page *pg, int clearbits)
! 2378: {
! 2379: struct pv_entry *pve;
! 2380: pt_entry_t *ptes, npte, opte;
! 2381: u_long clearflags;
! 2382: int result;
! 2383:
! 2384: clearflags = pmap_pte2flags(clearbits);
! 2385:
! 2386: PMAP_HEAD_TO_MAP_LOCK();
! 2387:
! 2388: result = pg->pg_flags & clearflags;
! 2389: if (result)
! 2390: atomic_clearbits_int(&pg->pg_flags, clearflags);
! 2391:
! 2392: for (pve = pg->mdpage.pv_list; pve != NULL; pve = pve->pv_next) {
! 2393: #ifdef DIAGNOSTIC
! 2394: if (!pmap_valid_entry(pve->pv_pmap->pm_pdir[pdei(pve->pv_va)]))
! 2395: panic("pmap_change_attrs: mapping without PTP "
! 2396: "detected");
! 2397: #endif
! 2398:
! 2399: ptes = pmap_map_ptes(pve->pv_pmap); /* locks pmap */
! 2400: npte = ptes[atop(pve->pv_va)];
! 2401: if (npte & clearbits) {
! 2402: result = TRUE;
! 2403: npte &= ~clearbits;
! 2404: opte = i386_atomic_testset_ul(
! 2405: &ptes[atop(pve->pv_va)], npte);
! 2406: pmap_tlb_shootpage(pve->pv_pmap, pve->pv_va);
! 2407: }
! 2408: pmap_unmap_ptes(pve->pv_pmap); /* unlocks pmap */
! 2409: }
! 2410:
! 2411: PMAP_HEAD_TO_MAP_UNLOCK();
! 2412: pmap_tlb_shootwait();
! 2413:
! 2414: return (result != 0);
! 2415: }
! 2416:
! 2417: /*
! 2418: * p m a p p r o t e c t i o n f u n c t i o n s
! 2419: */
! 2420:
! 2421: /*
! 2422: * pmap_page_protect: change the protection of all recorded mappings
! 2423: * of a managed page
! 2424: *
! 2425: * => NOTE: this is an inline function in pmap.h
! 2426: */
! 2427:
! 2428: /* see pmap.h */
! 2429:
! 2430: /*
! 2431: * pmap_protect: set the protection in of the pages in a pmap
! 2432: *
! 2433: * => NOTE: this is an inline function in pmap.h
! 2434: */
! 2435:
! 2436: /* see pmap.h */
! 2437:
! 2438: /*
! 2439: * pmap_write_protect: write-protect pages in a pmap
! 2440: */
! 2441:
! 2442: void
! 2443: pmap_write_protect(struct pmap *pmap, vaddr_t sva, vaddr_t eva,
! 2444: vm_prot_t prot)
! 2445: {
! 2446: pt_entry_t *ptes, *spte, *epte, npte;
! 2447: vaddr_t blockend;
! 2448: u_int32_t md_prot;
! 2449: vaddr_t va;
! 2450: int shootall = 0;
! 2451:
! 2452: ptes = pmap_map_ptes(pmap); /* locks pmap */
! 2453:
! 2454: /* should be ok, but just in case ... */
! 2455: sva &= PG_FRAME;
! 2456: eva &= PG_FRAME;
! 2457:
! 2458: if ((eva - sva > 32 * PAGE_SIZE) && pmap != pmap_kernel())
! 2459: shootall = 1;
! 2460:
! 2461: for (va = sva; va < eva; va = blockend) {
! 2462: blockend = (va & PD_MASK) + NBPD;
! 2463: if (blockend > eva)
! 2464: blockend = eva;
! 2465:
! 2466: /*
! 2467: * XXXCDC: our PTE mappings should never be write-protected!
! 2468: *
! 2469: * long term solution is to move the PTEs out of user
! 2470: * address space. and into kernel address space (up
! 2471: * with APTE). then we can set VM_MAXUSER_ADDRESS to
! 2472: * be VM_MAX_ADDRESS.
! 2473: */
! 2474:
! 2475: /* XXXCDC: ugly hack to avoid freeing PDP here */
! 2476: if (pdei(va) == PDSLOT_PTE)
! 2477: continue;
! 2478:
! 2479: /* empty block? */
! 2480: if (!pmap_valid_entry(pmap->pm_pdir[pdei(va)]))
! 2481: continue;
! 2482:
! 2483: md_prot = protection_codes[prot];
! 2484: if (va < VM_MAXUSER_ADDRESS)
! 2485: md_prot |= PG_u;
! 2486: else if (va < VM_MAX_ADDRESS)
! 2487: /* XXX: write-prot our PTES? never! */
! 2488: md_prot |= (PG_u | PG_RW);
! 2489:
! 2490: spte = &ptes[atop(va)];
! 2491: epte = &ptes[atop(blockend)];
! 2492:
! 2493: for (/*null */; spte < epte ; spte++, va += PAGE_SIZE) {
! 2494:
! 2495: if (!pmap_valid_entry(*spte)) /* no mapping? */
! 2496: continue;
! 2497:
! 2498: npte = (*spte & ~PG_PROT) | md_prot;
! 2499:
! 2500: if (npte != *spte) {
! 2501: pmap_exec_account(pmap, va, *spte, npte);
! 2502: i386_atomic_testset_ul(spte, npte);
! 2503: }
! 2504: }
! 2505: }
! 2506: if (shootall)
! 2507: pmap_tlb_shoottlb();
! 2508: else
! 2509: pmap_tlb_shootrange(pmap, sva, eva);
! 2510:
! 2511: pmap_tlb_shootwait();
! 2512: pmap_unmap_ptes(pmap); /* unlocks pmap */
! 2513: }
! 2514:
! 2515: /*
! 2516: * end of protection functions
! 2517: */
! 2518:
! 2519: /*
! 2520: * pmap_unwire: clear the wired bit in the PTE
! 2521: *
! 2522: * => mapping should already be in map
! 2523: */
! 2524:
! 2525: void
! 2526: pmap_unwire(struct pmap *pmap, vaddr_t va)
! 2527: {
! 2528: pt_entry_t *ptes;
! 2529:
! 2530: if (pmap_valid_entry(pmap->pm_pdir[pdei(va)])) {
! 2531: ptes = pmap_map_ptes(pmap); /* locks pmap */
! 2532:
! 2533: #ifdef DIAGNOSTIC
! 2534: if (!pmap_valid_entry(ptes[atop(va)]))
! 2535: panic("pmap_unwire: invalid (unmapped) va 0x%lx", va);
! 2536: #endif
! 2537: if ((ptes[atop(va)] & PG_W) != 0) {
! 2538: ptes[atop(va)] &= ~PG_W;
! 2539: pmap->pm_stats.wired_count--;
! 2540: }
! 2541: #ifdef DIAGNOSTIC
! 2542: else {
! 2543: printf("pmap_unwire: wiring for pmap %p va 0x%lx "
! 2544: "didn't change!\n", pmap, va);
! 2545: }
! 2546: #endif
! 2547: pmap_unmap_ptes(pmap); /* unlocks map */
! 2548: }
! 2549: #ifdef DIAGNOSTIC
! 2550: else {
! 2551: panic("pmap_unwire: invalid PDE");
! 2552: }
! 2553: #endif
! 2554: }
! 2555:
! 2556: /*
! 2557: * pmap_collect: free resources held by a pmap
! 2558: *
! 2559: * => optional function.
! 2560: * => called when a process is swapped out to free memory.
! 2561: */
! 2562:
! 2563: void
! 2564: pmap_collect(struct pmap *pmap)
! 2565: {
! 2566: /*
! 2567: * free all of the pt pages by removing the physical mappings
! 2568: * for its entire address space.
! 2569: */
! 2570:
! 2571: pmap_do_remove(pmap, VM_MIN_ADDRESS, VM_MAX_ADDRESS,
! 2572: PMAP_REMOVE_SKIPWIRED);
! 2573: }
! 2574:
! 2575: /*
! 2576: * pmap_copy: copy mappings from one pmap to another
! 2577: *
! 2578: * => optional function
! 2579: * void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr)
! 2580: */
! 2581:
! 2582: /*
! 2583: * defined as macro in pmap.h
! 2584: */
! 2585:
! 2586: /*
! 2587: * pmap_enter: enter a mapping into a pmap
! 2588: *
! 2589: * => must be done "now" ... no lazy-evaluation
! 2590: */
! 2591:
! 2592: int
! 2593: pmap_enter(struct pmap *pmap, vaddr_t va, paddr_t pa,
! 2594: vm_prot_t prot, int flags)
! 2595: {
! 2596: pt_entry_t *ptes, opte, npte;
! 2597: struct vm_page *ptp;
! 2598: struct pv_entry *pve = NULL;
! 2599: boolean_t wired = (flags & PMAP_WIRED) != 0;
! 2600: struct vm_page *pg = NULL;
! 2601: int error;
! 2602:
! 2603: #ifdef DIAGNOSTIC
! 2604: /* sanity check: totally out of range? */
! 2605: if (va >= VM_MAX_KERNEL_ADDRESS)
! 2606: panic("pmap_enter: too big");
! 2607:
! 2608: if (va == (vaddr_t) PDP_BASE || va == (vaddr_t) APDP_BASE)
! 2609: panic("pmap_enter: trying to map over PDP/APDP!");
! 2610:
! 2611: /* sanity check: kernel PTPs should already have been pre-allocated */
! 2612: if (va >= VM_MIN_KERNEL_ADDRESS &&
! 2613: !pmap_valid_entry(pmap->pm_pdir[pdei(va)]))
! 2614: panic("pmap_enter: missing kernel PTP!");
! 2615: #endif
! 2616:
! 2617: /* get lock */
! 2618: PMAP_MAP_TO_HEAD_LOCK();
! 2619:
! 2620: /*
! 2621: * map in ptes and get a pointer to our PTP (unless we are the kernel)
! 2622: */
! 2623:
! 2624: ptes = pmap_map_ptes(pmap); /* locks pmap */
! 2625: if (pmap == pmap_kernel()) {
! 2626: ptp = NULL;
! 2627: } else {
! 2628: ptp = pmap_get_ptp(pmap, pdei(va), FALSE);
! 2629: if (ptp == NULL) {
! 2630: if (flags & PMAP_CANFAIL) {
! 2631: error = ENOMEM;
! 2632: goto out;
! 2633: }
! 2634: panic("pmap_enter: get ptp failed");
! 2635: }
! 2636: }
! 2637: opte = ptes[atop(va)]; /* old PTE */
! 2638:
! 2639: /*
! 2640: * is there currently a valid mapping at our VA?
! 2641: */
! 2642:
! 2643: if (pmap_valid_entry(opte)) {
! 2644:
! 2645: /*
! 2646: * first, update pm_stats. resident count will not
! 2647: * change since we are replacing/changing a valid
! 2648: * mapping. wired count might change...
! 2649: */
! 2650:
! 2651: if (wired && (opte & PG_W) == 0)
! 2652: pmap->pm_stats.wired_count++;
! 2653: else if (!wired && (opte & PG_W) != 0)
! 2654: pmap->pm_stats.wired_count--;
! 2655:
! 2656: /*
! 2657: * is the currently mapped PA the same as the one we
! 2658: * want to map?
! 2659: */
! 2660:
! 2661: if ((opte & PG_FRAME) == pa) {
! 2662:
! 2663: /* if this is on the PVLIST, sync R/M bit */
! 2664: if (opte & PG_PVLIST) {
! 2665: pg = PHYS_TO_VM_PAGE(pa);
! 2666: #ifdef DIAGNOSTIC
! 2667: if (pg == NULL)
! 2668: panic("pmap_enter: same pa PG_PVLIST "
! 2669: "mapping with unmanaged page "
! 2670: "pa = 0x%lx (0x%lx)", pa,
! 2671: atop(pa));
! 2672: #endif
! 2673: pmap_sync_flags_pte(pg, opte);
! 2674: }
! 2675: goto enter_now;
! 2676: }
! 2677:
! 2678: /*
! 2679: * changing PAs: we must remove the old one first
! 2680: */
! 2681:
! 2682: /*
! 2683: * if current mapping is on a pvlist,
! 2684: * remove it (sync R/M bits)
! 2685: */
! 2686:
! 2687: if (opte & PG_PVLIST) {
! 2688: pg = PHYS_TO_VM_PAGE(opte & PG_FRAME);
! 2689: #ifdef DIAGNOSTIC
! 2690: if (pg == NULL)
! 2691: panic("pmap_enter: PG_PVLIST mapping with "
! 2692: "unmanaged page "
! 2693: "pa = 0x%lx (0x%lx)", pa, atop(pa));
! 2694: #endif
! 2695: pmap_sync_flags_pte(pg, opte);
! 2696: pve = pmap_remove_pv(pg, pmap, va);
! 2697: pg = NULL; /* This is not page we are looking for */
! 2698: }
! 2699: } else { /* opte not valid */
! 2700: pmap->pm_stats.resident_count++;
! 2701: if (wired)
! 2702: pmap->pm_stats.wired_count++;
! 2703: if (ptp)
! 2704: ptp->wire_count++; /* count # of valid entries */
! 2705: }
! 2706:
! 2707: /*
! 2708: * at this point pm_stats has been updated. pve is either NULL
! 2709: * or points to a now-free pv_entry structure (the latter case is
! 2710: * if we called pmap_remove_pv above).
! 2711: *
! 2712: * if this entry is to be on a pvlist, enter it now.
! 2713: */
! 2714:
! 2715: if (pmap_initialized && pg == NULL)
! 2716: pg = PHYS_TO_VM_PAGE(pa);
! 2717:
! 2718: if (pg != NULL) {
! 2719: if (pve == NULL) {
! 2720: pve = pmap_alloc_pv(pmap, ALLOCPV_NEED);
! 2721: if (pve == NULL) {
! 2722: if (flags & PMAP_CANFAIL) {
! 2723: /*
! 2724: * XXX - Back out stats changes!
! 2725: */
! 2726: error = ENOMEM;
! 2727: goto out;
! 2728: }
! 2729: panic("pmap_enter: no pv entries available");
! 2730: }
! 2731: }
! 2732: /* lock pvh when adding */
! 2733: pmap_enter_pv(pg, pve, pmap, va, ptp);
! 2734: } else {
! 2735:
! 2736: /* new mapping is not PG_PVLIST. free pve if we've got one */
! 2737: if (pve)
! 2738: pmap_free_pv(pmap, pve);
! 2739: }
! 2740:
! 2741: enter_now:
! 2742: /*
! 2743: * at this point pvh is !NULL if we want the PG_PVLIST bit set
! 2744: */
! 2745:
! 2746: npte = pa | protection_codes[prot] | PG_V;
! 2747: pmap_exec_account(pmap, va, opte, npte);
! 2748: if (wired)
! 2749: npte |= PG_W;
! 2750: if (va < VM_MAXUSER_ADDRESS)
! 2751: npte |= PG_u;
! 2752: else if (va < VM_MAX_ADDRESS)
! 2753: npte |= (PG_u | PG_RW); /* XXXCDC: no longer needed? */
! 2754: if (pmap == pmap_kernel())
! 2755: npte |= pmap_pg_g;
! 2756: if (flags & VM_PROT_READ)
! 2757: npte |= PG_U;
! 2758: if (flags & VM_PROT_WRITE)
! 2759: npte |= PG_M;
! 2760: if (pg) {
! 2761: npte |= PG_PVLIST;
! 2762: pmap_sync_flags_pte(pg, npte);
! 2763: }
! 2764:
! 2765: opte = i386_atomic_testset_ul(&ptes[atop(va)], npte);
! 2766:
! 2767: if (opte & PG_V) {
! 2768: pmap_tlb_shootpage(pmap, va);
! 2769: pmap_tlb_shootwait();
! 2770: }
! 2771:
! 2772: error = 0;
! 2773:
! 2774: out:
! 2775: pmap_unmap_ptes(pmap);
! 2776: PMAP_MAP_TO_HEAD_UNLOCK();
! 2777:
! 2778: return error;
! 2779: }
! 2780:
! 2781: /*
! 2782: * pmap_growkernel: increase usage of KVM space
! 2783: *
! 2784: * => we allocate new PTPs for the kernel and install them in all
! 2785: * the pmaps on the system.
! 2786: */
! 2787:
! 2788: vaddr_t
! 2789: pmap_growkernel(vaddr_t maxkvaddr)
! 2790: {
! 2791: struct pmap *kpm = pmap_kernel(), *pm;
! 2792: int needed_kpde; /* needed number of kernel PTPs */
! 2793: int s;
! 2794: paddr_t ptaddr;
! 2795:
! 2796: needed_kpde = (int)(maxkvaddr - VM_MIN_KERNEL_ADDRESS + (NBPD-1))
! 2797: / NBPD;
! 2798: if (needed_kpde <= nkpde)
! 2799: goto out; /* we are OK */
! 2800:
! 2801: /*
! 2802: * whoops! we need to add kernel PTPs
! 2803: */
! 2804:
! 2805: s = splhigh(); /* to be safe */
! 2806: simple_lock(&kpm->pm_obj.vmobjlock);
! 2807:
! 2808: for (/*null*/ ; nkpde < needed_kpde ; nkpde++) {
! 2809:
! 2810: if (uvm.page_init_done == FALSE) {
! 2811:
! 2812: /*
! 2813: * we're growing the kernel pmap early (from
! 2814: * uvm_pageboot_alloc()). this case must be
! 2815: * handled a little differently.
! 2816: */
! 2817:
! 2818: if (uvm_page_physget(&ptaddr) == FALSE)
! 2819: panic("pmap_growkernel: out of memory");
! 2820: pmap_zero_phys(ptaddr);
! 2821:
! 2822: kpm->pm_pdir[PDSLOT_KERN + nkpde] =
! 2823: ptaddr | PG_RW | PG_V | PG_U | PG_M;
! 2824:
! 2825: /* count PTP as resident */
! 2826: kpm->pm_stats.resident_count++;
! 2827: continue;
! 2828: }
! 2829:
! 2830: /*
! 2831: * THIS *MUST* BE CODED SO AS TO WORK IN THE
! 2832: * pmap_initialized == FALSE CASE! WE MAY BE
! 2833: * INVOKED WHILE pmap_init() IS RUNNING!
! 2834: */
! 2835:
! 2836: while (!pmap_alloc_ptp(kpm, PDSLOT_KERN + nkpde, FALSE, 0))
! 2837: uvm_wait("pmap_growkernel");
! 2838:
! 2839: /* distribute new kernel PTP to all active pmaps */
! 2840: simple_lock(&pmaps_lock);
! 2841: LIST_FOREACH(pm, &pmaps, pm_list) {
! 2842: pm->pm_pdir[PDSLOT_KERN + nkpde] =
! 2843: kpm->pm_pdir[PDSLOT_KERN + nkpde];
! 2844: }
! 2845: simple_unlock(&pmaps_lock);
! 2846: }
! 2847:
! 2848: simple_unlock(&kpm->pm_obj.vmobjlock);
! 2849: splx(s);
! 2850:
! 2851: out:
! 2852: return (VM_MIN_KERNEL_ADDRESS + (nkpde * NBPD));
! 2853: }
! 2854:
! 2855: #ifdef DEBUG
! 2856: void pmap_dump(struct pmap *, vaddr_t, vaddr_t);
! 2857:
! 2858: /*
! 2859: * pmap_dump: dump all the mappings from a pmap
! 2860: *
! 2861: * => caller should not be holding any pmap locks
! 2862: */
! 2863:
! 2864: void
! 2865: pmap_dump(struct pmap *pmap, vaddr_t sva, vaddr_t eva)
! 2866: {
! 2867: pt_entry_t *ptes, *pte;
! 2868: vaddr_t blkendva;
! 2869:
! 2870: /*
! 2871: * if end is out of range truncate.
! 2872: * if (end == start) update to max.
! 2873: */
! 2874:
! 2875: if (eva > VM_MAXUSER_ADDRESS || eva <= sva)
! 2876: eva = VM_MAXUSER_ADDRESS;
! 2877:
! 2878: PMAP_MAP_TO_HEAD_LOCK();
! 2879: ptes = pmap_map_ptes(pmap); /* locks pmap */
! 2880:
! 2881: /*
! 2882: * dumping a range of pages: we dump in PTP sized blocks (4MB)
! 2883: */
! 2884:
! 2885: for (/* null */ ; sva < eva ; sva = blkendva) {
! 2886:
! 2887: /* determine range of block */
! 2888: blkendva = i386_round_pdr(sva+1);
! 2889: if (blkendva > eva)
! 2890: blkendva = eva;
! 2891:
! 2892: /* valid block? */
! 2893: if (!pmap_valid_entry(pmap->pm_pdir[pdei(sva)]))
! 2894: continue;
! 2895:
! 2896: pte = &ptes[atop(sva)];
! 2897: for (/* null */; sva < blkendva ; sva += NBPG, pte++) {
! 2898: if (!pmap_valid_entry(*pte))
! 2899: continue;
! 2900: printf("va %#lx -> pa %#x (pte=%#x)\n",
! 2901: sva, *pte, *pte & PG_FRAME);
! 2902: }
! 2903: }
! 2904: pmap_unmap_ptes(pmap);
! 2905: PMAP_MAP_TO_HEAD_UNLOCK();
! 2906: }
! 2907: #endif
! 2908:
! 2909: #ifdef MULTIPROCESSOR
! 2910: /*
! 2911: * Locking for tlb shootdown.
! 2912: *
! 2913: * We lock by setting tlb_shoot_wait to the number of cpus that will
! 2914: * receive our tlb shootdown. After sending the IPIs, we don't need to
! 2915: * worry about locking order or interrupts spinning for the lock because
! 2916: * the call that grabs the "lock" isn't the one that releases it. And
! 2917: * there is nothing that can block the IPI that releases the lock.
! 2918: *
! 2919: * The functions are organized so that we first count the number of
! 2920: * cpus we need to send the IPI to, then we grab the counter, then
! 2921: * we send the IPIs, then we finally do our own shootdown.
! 2922: *
! 2923: * Our shootdown is last to make it parallell with the other cpus
! 2924: * to shorten the spin time.
! 2925: *
! 2926: * Notice that we depend on failures to send IPIs only being able to
! 2927: * happen during boot. If they happen later, the above assumption
! 2928: * doesn't hold since we can end up in situations where noone will
! 2929: * release the lock if we get an interrupt in a bad moment.
! 2930: */
! 2931:
! 2932: volatile int tlb_shoot_wait;
! 2933:
! 2934: volatile vaddr_t tlb_shoot_addr1;
! 2935: volatile vaddr_t tlb_shoot_addr2;
! 2936:
! 2937: void
! 2938: pmap_tlb_shootpage(struct pmap *pm, vaddr_t va)
! 2939: {
! 2940: struct cpu_info *ci, *self = curcpu();
! 2941: CPU_INFO_ITERATOR cii;
! 2942: int wait = 0;
! 2943: int mask = 0;
! 2944:
! 2945: CPU_INFO_FOREACH(cii, ci) {
! 2946: if (ci == self || !pmap_is_active(pm, ci->ci_cpuid) ||
! 2947: !(ci->ci_flags & CPUF_RUNNING))
! 2948: continue;
! 2949: mask |= 1 << ci->ci_cpuid;
! 2950: wait++;
! 2951: }
! 2952:
! 2953: if (wait > 0) {
! 2954: int s = splvm();
! 2955:
! 2956: while (i486_atomic_cas_int(&tlb_shoot_wait, 0, wait) != 0) {
! 2957: while (tlb_shoot_wait != 0)
! 2958: SPINLOCK_SPIN_HOOK;
! 2959: }
! 2960: tlb_shoot_addr1 = va;
! 2961: CPU_INFO_FOREACH(cii, ci) {
! 2962: if ((mask & 1 << ci->ci_cpuid) == 0)
! 2963: continue;
! 2964: if (i386_fast_ipi(ci, LAPIC_IPI_INVLPG) != 0)
! 2965: panic("pmap_tlb_shootpage: ipi failed");
! 2966: }
! 2967: splx(s);
! 2968: }
! 2969:
! 2970: if (pmap_is_curpmap(pm))
! 2971: pmap_update_pg(va);
! 2972: }
! 2973:
! 2974: void
! 2975: pmap_tlb_shootrange(struct pmap *pm, vaddr_t sva, vaddr_t eva)
! 2976: {
! 2977: struct cpu_info *ci, *self = curcpu();
! 2978: CPU_INFO_ITERATOR cii;
! 2979: int wait = 0;
! 2980: int mask = 0;
! 2981: vaddr_t va;
! 2982:
! 2983: CPU_INFO_FOREACH(cii, ci) {
! 2984: if (ci == self || !pmap_is_active(pm, ci->ci_cpuid) ||
! 2985: !(ci->ci_flags & CPUF_RUNNING))
! 2986: continue;
! 2987: mask |= 1 << ci->ci_cpuid;
! 2988: wait++;
! 2989: }
! 2990:
! 2991: if (wait > 0) {
! 2992: int s = splvm();
! 2993:
! 2994: while (i486_atomic_cas_int(&tlb_shoot_wait, 0, wait) != 0) {
! 2995: while (tlb_shoot_wait != 0)
! 2996: SPINLOCK_SPIN_HOOK;
! 2997: }
! 2998: tlb_shoot_addr1 = sva;
! 2999: tlb_shoot_addr2 = eva;
! 3000: CPU_INFO_FOREACH(cii, ci) {
! 3001: if ((mask & 1 << ci->ci_cpuid) == 0)
! 3002: continue;
! 3003: if (i386_fast_ipi(ci, LAPIC_IPI_INVLRANGE) != 0)
! 3004: panic("pmap_tlb_shootrange: ipi failed");
! 3005: }
! 3006: splx(s);
! 3007: }
! 3008:
! 3009: if (pmap_is_curpmap(pm))
! 3010: for (va = sva; va < eva; va += PAGE_SIZE)
! 3011: pmap_update_pg(va);
! 3012: }
! 3013:
! 3014: void
! 3015: pmap_tlb_shoottlb(void)
! 3016: {
! 3017: struct cpu_info *ci, *self = curcpu();
! 3018: CPU_INFO_ITERATOR cii;
! 3019: int wait = 0;
! 3020: int mask = 0;
! 3021:
! 3022: CPU_INFO_FOREACH(cii, ci) {
! 3023: if (ci == self || !(ci->ci_flags & CPUF_RUNNING))
! 3024: continue;
! 3025: mask |= 1 << ci->ci_cpuid;
! 3026: wait++;
! 3027: }
! 3028:
! 3029: if (wait) {
! 3030: int s = splvm();
! 3031:
! 3032: while (i486_atomic_cas_int(&tlb_shoot_wait, 0, wait) != 0) {
! 3033: while (tlb_shoot_wait != 0)
! 3034: SPINLOCK_SPIN_HOOK;
! 3035: }
! 3036:
! 3037: CPU_INFO_FOREACH(cii, ci) {
! 3038: if ((mask & 1 << ci->ci_cpuid) == 0)
! 3039: continue;
! 3040: if (i386_fast_ipi(ci, LAPIC_IPI_INVLTLB) != 0)
! 3041: panic("pmap_tlb_shoottlb: ipi failed");
! 3042: }
! 3043: splx(s);
! 3044: }
! 3045:
! 3046: tlbflush();
! 3047: }
! 3048:
! 3049: void
! 3050: pmap_tlb_shootwait(void)
! 3051: {
! 3052: while (tlb_shoot_wait != 0)
! 3053: SPINLOCK_SPIN_HOOK;
! 3054: }
! 3055:
! 3056: #else
! 3057:
! 3058: void
! 3059: pmap_tlb_shootpage(struct pmap *pm, vaddr_t va)
! 3060: {
! 3061: if (pmap_is_curpmap(pm))
! 3062: pmap_update_pg(va);
! 3063:
! 3064: }
! 3065:
! 3066: void
! 3067: pmap_tlb_shootrange(struct pmap *pm, vaddr_t sva, vaddr_t eva)
! 3068: {
! 3069: vaddr_t va;
! 3070:
! 3071: for (va = sva; va < eva; va += PAGE_SIZE)
! 3072: pmap_update_pg(va);
! 3073: }
! 3074:
! 3075: void
! 3076: pmap_tlb_shoottlb(void)
! 3077: {
! 3078: tlbflush();
! 3079: }
! 3080: #endif /* MULTIPROCESSOR */
CVSweb