pmap.c revision 4
1311116Sdim/* 2311116Sdim * Copyright (c) 1991 Regents of the University of California. 3353358Sdim * All rights reserved. 4353358Sdim * 5353358Sdim * This code is derived from software contributed to Berkeley by 6311116Sdim * the Systems Programming Group of the University of Utah Computer 7311116Sdim * Science Department and William Jolitz of UUNET Technologies Inc. 8311116Sdim * 9321369Sdim * Redistribution and use in source and binary forms, with or without 10321369Sdim * modification, are permitted provided that the following conditions 11311116Sdim * are met: 12321369Sdim * 1. Redistributions of source code must retain the above copyright 13311116Sdim * notice, this list of conditions and the following disclaimer. 14311116Sdim * 2. Redistributions in binary form must reproduce the above copyright 15311116Sdim * notice, this list of conditions and the following disclaimer in the 16321369Sdim * documentation and/or other materials provided with the distribution. 17311116Sdim * 3. All advertising materials mentioning features or use of this software 18311116Sdim * must display the following acknowledgement: 19311116Sdim * This product includes software developed by the University of 20360784Sdim * California, Berkeley and its contributors. 21341825Sdim * 4. Neither the name of the University nor the names of its contributors 22311116Sdim * may be used to endorse or promote products derived from this software 23311116Sdim * without specific prior written permission. 24321369Sdim * 25321369Sdim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26321369Sdim * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27341825Sdim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28360784Sdim * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29311116Sdim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30321369Sdim * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31311116Sdim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32311116Sdim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33311116Sdim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34311116Sdim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35311116Sdim * SUCH DAMAGE. 36311116Sdim * 37321369Sdim * @(#)pmap.c 7.7 (Berkeley) 5/12/91 38321369Sdim * 39321369Sdim * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE 40321369Sdim * -------------------- ----- ---------------------- 41311116Sdim * CURRENT PATCH LEVEL: 1 00063 42321369Sdim * -------------------- ----- ---------------------- 43311116Sdim * 44321369Sdim * 28 Nov 1991 Poul-Henning Kamp Speedup processing. 45327952Sdim */ 46327952Sdimstatic char rcsid[] = "$Header: /usr/src/sys.386bsd/i386/i386/RCS/pmap.c,v 1.3 92/01/21 14:26:44 william Exp Locker: root $"; 47327952Sdim 48327952Sdim/* 49327952Sdim * Derived from hp300 version by Mike Hibler, this version by William 50327952Sdim * Jolitz uses a recursive map [a pde points to the page directory] to 51327952Sdim * map the page tables using the pagetables themselves. This is done to 52327952Sdim * reduce the impact on kernel virtual memory for lots of sparse address 53327952Sdim * space, and to reduce the cost of memory to each process. 54327952Sdim * 55327952Sdim * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 56311116Sdim */ 57321369Sdim 58311116Sdim/* 59321369Sdim * Reno i386 version, from Mike Hibler's hp300 version. 60321369Sdim */ 61321369Sdim 62321369Sdim/* 63311116Sdim * Manages physical address maps. 64311116Sdim * 65311116Sdim * In addition to hardware address maps, this 66311116Sdim * module is called upon to provide software-use-only 67321369Sdim * maps which may or may not be stored in the same 68321369Sdim * form as hardware maps. These pseudo-maps are 69321369Sdim * used to store intermediate results from copy 70321369Sdim * operations to and from address spaces. 71321369Sdim * 72311116Sdim * Since the information managed by this module is 73321369Sdim * also stored by the logical address mapping module, 74321369Sdim * this module may throw away valid virtual-to-physical 75321369Sdim * mappings at almost any time. However, invalidations 76321369Sdim * of virtual-to-physical mappings must be done as 77321369Sdim * requested. 78321369Sdim * 79321369Sdim * In order to cope with hardware architectures which 80311116Sdim * make virtual-to-physical map invalidates expensive, 81311116Sdim * this module may delay invalidate or reduced protection 82311116Sdim * operations until such time as they are actually 83311116Sdim * necessary. This module is given full information as 84311116Sdim * to which processors are currently using which maps, 85311116Sdim * and to when physical maps must be made correct. 86311116Sdim */ 87311116Sdim 88311116Sdim#include "param.h" 89311116Sdim#include "proc.h" 90311116Sdim#include "malloc.h" 91311116Sdim#include "user.h" 92311116Sdim 93311116Sdim#include "vm/vm.h" 94311116Sdim#include "vm/vm_kern.h" 95311116Sdim#include "vm/vm_page.h" 96327952Sdim/*#include "vm/vm_pageout.h"*/ 97311116Sdim 98311116Sdim#include "i386/isa/isa.h" 99311116Sdim 100311116Sdim/* 101311116Sdim * Allocate various and sundry SYSMAPs used in the days of old VM 102311116Sdim * and not yet converted. XXX. 103311116Sdim */ 104311116Sdim#define BSDVM_COMPAT 1 105311116Sdim 106311116Sdim#ifdef DEBUG 107311116Sdimstruct { 108311116Sdim int kernel; /* entering kernel mapping */ 109311116Sdim int user; /* entering user mapping */ 110311116Sdim int ptpneeded; /* needed to allocate a PT page */ 111311116Sdim int pwchange; /* no mapping change, just wiring or protection */ 112311116Sdim int wchange; /* no mapping change, just wiring */ 113311116Sdim int mchange; /* was mapped but mapping to different page */ 114311116Sdim int managed; /* a managed page */ 115311116Sdim int firstpv; /* first mapping for this PA */ 116311116Sdim int secondpv; /* second mapping for this PA */ 117311116Sdim int ci; /* cache inhibited */ 118311116Sdim int unmanaged; /* not a managed page */ 119311116Sdim int flushes; /* cache flushes */ 120311116Sdim} enter_stats; 121311116Sdimstruct { 122311116Sdim int calls; 123311116Sdim int removes; 124311116Sdim int pvfirst; 125311116Sdim int pvsearch; 126311116Sdim int ptinvalid; 127311116Sdim int uflushes; 128311116Sdim int sflushes; 129311116Sdim} remove_stats; 130311116Sdim 131311116Sdimint debugmap = 0; 132311116Sdimint pmapdebug = 0 /* 0xffff */; 133311116Sdim#define PDB_FOLLOW 0x0001 134341825Sdim#define PDB_INIT 0x0002 135311116Sdim#define PDB_ENTER 0x0004 136311116Sdim#define PDB_REMOVE 0x0008 137311116Sdim#define PDB_CREATE 0x0010 138311116Sdim#define PDB_PTPAGE 0x0020 139311116Sdim#define PDB_CACHE 0x0040 140311116Sdim#define PDB_BITS 0x0080 141311116Sdim#define PDB_COLLECT 0x0100 142311116Sdim#define PDB_PROTECT 0x0200 143311116Sdim#define PDB_PDRTAB 0x0400 144311116Sdim#define PDB_PARANOIA 0x2000 145311116Sdim#define PDB_WIRING 0x4000 146311116Sdim#define PDB_PVDUMP 0x8000 147311116Sdim 148311116Sdimint pmapvacflush = 0; 149311116Sdim#define PVF_ENTER 0x01 150311116Sdim#define PVF_REMOVE 0x02 151311116Sdim#define PVF_PROTECT 0x04 152327952Sdim#define PVF_TOTAL 0x80 153327952Sdim#endif 154327952Sdim 155311116Sdim/* 156311116Sdim * Get PDEs and PTEs for user/kernel address space 157311116Sdim */ 158344779Sdim#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023])) 159344779Sdim 160311116Sdim#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME) 161311116Sdim 162311116Sdim#define pmap_pde_v(pte) ((pte)->pd_v) 163311116Sdim#define pmap_pte_w(pte) ((pte)->pg_w) 164311116Sdim/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */ 165311116Sdim#define pmap_pte_m(pte) ((pte)->pg_m) 166311116Sdim#define pmap_pte_u(pte) ((pte)->pg_u) 167311116Sdim#define pmap_pte_v(pte) ((pte)->pg_v) 168311116Sdim#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v)) 169311116Sdim#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v)) 170311116Sdim 171311116Sdim/* 172311116Sdim * Given a map and a machine independent protection code, 173311116Sdim * convert to a vax protection code. 174311116Sdim */ 175341825Sdim#define pte_prot(m, p) (protection_codes[p]) 176341825Sdimint protection_codes[8]; 177341825Sdim 178341825Sdimstruct pmap kernel_pmap_store; 179341825Sdimpmap_t kernel_pmap; 180341825Sdim 181341825Sdimvm_offset_t avail_start; /* PA of first available physical page */ 182311116Sdimvm_offset_t avail_end; /* PA of last available physical page */ 183341825Sdimvm_size_t mem_size; /* memory size in bytes */ 184341825Sdimvm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ 185341825Sdimvm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ 186311116Sdimvm_offset_t vm_first_phys; /* PA of first managed page */ 187311116Sdimvm_offset_t vm_last_phys; /* PA just past last managed page */ 188321369Sdimint i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */ 189321369Sdimboolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ 190321369Sdimchar *pmap_attributes; /* reference and modify bits */ 191321369Sdim 192321369Sdimboolean_t pmap_testbit(); 193321369Sdimvoid pmap_clear_modify(); 194321369Sdim 195321369Sdim#if BSDVM_COMPAT 196321369Sdim#include "msgbuf.h" 197311116Sdim 198311116Sdim/* 199311116Sdim * All those kernel PT submaps that BSD is so fond of 200321369Sdim */ 201321369Sdimstruct pte *CMAP1, *CMAP2, *mmap; 202321369Sdimcaddr_t CADDR1, CADDR2, vmmap; 203321369Sdimstruct pte *msgbufmap; 204311116Sdimstruct msgbuf *msgbufp; 205341825Sdim#endif 206341825Sdim 207341825Sdim/* 208341825Sdim * Bootstrap the system enough to run with virtual memory. 209341825Sdim * Map the kernel's code and data, and allocate the system page table. 210341825Sdim * 211341825Sdim * On the I386 this is called after mapping has already been enabled 212321369Sdim * and just syncs the pmap module with what has already been done. 213321369Sdim * [We can't call it easily with mapping off since the kernel is not 214321369Sdim * mapped with PA == VA, hence we would have to relocate every address 215341825Sdim * from the linked base (virtual) address 0xFE000000 to the actual 216341825Sdim * (physical) address starting relative to 0] 217341825Sdim */ 218311116Sdimstruct pte *pmap_pte(); 219311116Sdim 220311116Sdimvoid 221311116Sdimpmap_bootstrap(firstaddr, loadaddr) 222311116Sdim vm_offset_t firstaddr; 223360784Sdim vm_offset_t loadaddr; 224360784Sdim{ 225360784Sdim#if BSDVM_COMPAT 226360784Sdim vm_offset_t va; 227360784Sdim struct pte *pte; 228360784Sdim#endif 229341825Sdim extern vm_offset_t maxmem, physmem; 230360784Sdimextern int IdlePTD; 231360784Sdim 232360784Sdim avail_start = firstaddr; 233360784Sdim avail_end = maxmem << PG_SHIFT; 234360784Sdim 235341825Sdim /* XXX: allow for msgbuf */ 236311116Sdim avail_end -= i386_round_page(sizeof(struct msgbuf)); 237311116Sdim 238321369Sdim mem_size = physmem << PG_SHIFT; 239321369Sdim virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG; 240321369Sdim virtual_end = VM_MAX_KERNEL_ADDRESS; 241321369Sdim i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE; 242321369Sdim 243321369Sdim /* 244321369Sdim * Initialize protection array. 245321369Sdim */ 246321369Sdim i386_protection_init(); 247321369Sdim 248321369Sdim /* 249321369Sdim * The kernel's pmap is statically allocated so we don't 250344779Sdim * have to use pmap_create, which is unlikely to work 251321369Sdim * correctly at this part of the boot sequence. 252321369Sdim */ 253321369Sdim kernel_pmap = &kernel_pmap_store; 254321369Sdim 255321369Sdim#ifdef notdef 256321369Sdim /* 257321369Sdim * Create Kernel page directory table and page maps. 258321369Sdim * [ currently done in locore. i have wild and crazy ideas -wfj ] 259321369Sdim */ 260321369Sdim bzero(firstaddr, 4*NBPG); 261321369Sdim kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS; 262321369Sdim kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG; 263321369Sdim 264321369Sdim firstaddr += NBPG; 265321369Sdim for (x = i386_btod(VM_MIN_KERNEL_ADDRESS); 266321369Sdim x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) { 267321369Sdim struct pde *pde; 268321369Sdim pde = kernel_pmap->pm_pdir + x; 269321369Sdim *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW; 270321369Sdim } 271321369Sdim#else 272321369Sdim kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD); 273321369Sdim#endif 274311116Sdim 275321369Sdim 276341825Sdim simple_lock_init(&kernel_pmap->pm_lock); 277321369Sdim kernel_pmap->pm_count = 1; 278321369Sdim 279321369Sdim#if BSDVM_COMPAT 280321369Sdim /* 281321369Sdim * Allocate all the submaps we need 282321369Sdim */ 283321369Sdim#define SYSMAP(c, p, v, n) \ 284321369Sdim v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n); 285321369Sdim 286321369Sdim va = virtual_avail; 287341825Sdim pte = pmap_pte(kernel_pmap, va); 288311116Sdim 289321369Sdim SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) 290321369Sdim SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) 291321369Sdim SYSMAP(caddr_t ,mmap ,vmmap ,1 ) 292321369Sdim SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 ) 293321369Sdim virtual_avail = va; 294321369Sdim#endif 295321369Sdim /* 296321369Sdim * reserve special hunk of memory for use by bus dma as a bounce 297311116Sdim * buffer (contiguous virtual *and* physical memory). for now, 298321369Sdim * assume vm does not use memory beneath hole, and we know that 299321369Sdim * the bootstrap uses top 32k of base memory. -wfj 300321369Sdim */ 301321369Sdim { 302311116Sdim extern vm_offset_t isaphysmem; 303321369Sdim isaphysmem = va; 304321369Sdim 305321369Sdim virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL); 306321369Sdim } 307321369Sdim 308321369Sdim *(int *)PTD = 0; 309321369Sdim load_cr3(rcr3()); 310321369Sdim 311321369Sdim} 312321369Sdim 313321369Sdim/* 314321369Sdim * Initialize the pmap module. 315321369Sdim * Called by vm_init, to initialize any structures that the pmap 316321369Sdim * system needs to map virtual memory. 317321369Sdim */ 318341825Sdimvoid 319321369Sdimpmap_init(phys_start, phys_end) 320321369Sdim vm_offset_t phys_start, phys_end; 321321369Sdim{ 322321369Sdim vm_offset_t addr, addr2; 323321369Sdim vm_size_t npg, s; 324321369Sdim int rv; 325321369Sdim extern int KPTphys; 326321369Sdim 327321369Sdim#ifdef DEBUG 328360784Sdim if (pmapdebug & PDB_FOLLOW) 329321369Sdim printf("pmap_init(%x, %x)\n", phys_start, phys_end); 330360784Sdim#endif 331321369Sdim /* 332321369Sdim * Now that kernel map has been allocated, we can mark as 333321369Sdim * unavailable regions which we have mapped in locore. 334321369Sdim */ 335321369Sdim addr = atdevbase; 336321369Sdim (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, 337321369Sdim &addr, (0x100000-0xa0000), FALSE); 338321369Sdim 339321369Sdim addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */; 340321369Sdim vm_object_reference(kernel_object); 341321369Sdim (void) vm_map_find(kernel_map, kernel_object, addr, 342321369Sdim &addr, 2*NBPG, FALSE); 343321369Sdim 344321369Sdim /* 345321369Sdim * Allocate memory for random pmap data structures. Includes the 346321369Sdim * pv_head_table and pmap_attributes. 347341825Sdim */ 348341825Sdim npg = atop(phys_end - phys_start); 349341825Sdim s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg); 350341825Sdim s = round_page(s); 351341825Sdim addr = (vm_offset_t) kmem_alloc(kernel_map, s); 352341825Sdim pv_table = (pv_entry_t) addr; 353341825Sdim addr += sizeof(struct pv_entry) * npg; 354341825Sdim pmap_attributes = (char *) addr; 355341825Sdim#ifdef DEBUG 356341825Sdim if (pmapdebug & PDB_INIT) 357341825Sdim printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n", 358341825Sdim s, npg, pv_table, pmap_attributes); 359341825Sdim#endif 360341825Sdim 361341825Sdim /* 362341825Sdim * Now it is safe to enable pv_table recording. 363341825Sdim */ 364341825Sdim vm_first_phys = phys_start; 365341825Sdim vm_last_phys = phys_end; 366341825Sdim pmap_initialized = TRUE; 367341825Sdim} 368341825Sdim 369341825Sdim/* 370341825Sdim * Used to map a range of physical addresses into kernel 371341825Sdim * virtual address space. 372341825Sdim * 373341825Sdim * For now, VM is already on, we only need to map the 374341825Sdim * specified memory. 375341825Sdim */ 376341825Sdimvm_offset_t 377341825Sdimpmap_map(virt, start, end, prot) 378341825Sdim vm_offset_t virt; 379341825Sdim vm_offset_t start; 380341825Sdim vm_offset_t end; 381341825Sdim int prot; 382341825Sdim{ 383341825Sdim#ifdef DEBUG 384341825Sdim if (pmapdebug & PDB_FOLLOW) 385341825Sdim printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot); 386341825Sdim#endif 387341825Sdim while (start < end) { 388311116Sdim pmap_enter(kernel_pmap, virt, start, prot, FALSE); 389311116Sdim virt += PAGE_SIZE; 390321369Sdim start += PAGE_SIZE; 391321369Sdim } 392321369Sdim return(virt); 393321369Sdim} 394321369Sdim 395321369Sdim/* 396321369Sdim * Create and return a physical map. 397321369Sdim * 398321369Sdim * If the size specified for the map 399321369Sdim * is zero, the map is an actual physical 400311116Sdim * map, and may be referenced by the 401321369Sdim * hardware. 402311116Sdim * 403321369Sdim * If the size specified is non-zero, 404321369Sdim * the map will be used in software only, and 405321369Sdim * is bounded by that size. 406321369Sdim * 407341825Sdim * [ just allocate a ptd and mark it uninitialize -- should we track 408321369Sdim * with a table which process has which ptd? -wfj ] 409341825Sdim */ 410321369Sdim 411321369Sdimpmap_t 412321369Sdimpmap_create(size) 413311116Sdim vm_size_t size; 414327952Sdim{ 415327952Sdim register pmap_t pmap; 416327952Sdim 417321369Sdim#ifdef DEBUG 418321369Sdim if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) 419321369Sdim printf("pmap_create(%x)\n", size); 420321369Sdim#endif 421341825Sdim /* 422341825Sdim * Software use map does not need a pmap 423321369Sdim */ 424321369Sdim if (size) 425321369Sdim return(NULL); 426321369Sdim 427321369Sdim /* XXX: is it ok to wait here? */ 428311116Sdim pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); 429311116Sdim#ifdef notifwewait 430353358Sdim if (pmap == NULL) 431353358Sdim panic("pmap_create: cannot allocate a pmap"); 432344779Sdim#endif 433344779Sdim bzero(pmap, sizeof(*pmap)); 434344779Sdim pmap_pinit(pmap); 435344779Sdim return (pmap); 436353358Sdim} 437353358Sdim 438344779Sdim/* 439353358Sdim * Initialize a preallocated and zeroed pmap structure, 440353358Sdim * such as one in a vmspace structure. 441311116Sdim */ 442341825Sdimvoid 443311116Sdimpmap_pinit(pmap) 444311116Sdim register struct pmap *pmap; 445311116Sdim{ 446311116Sdim 447311116Sdim#ifdef DEBUG 448321369Sdim if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) 449321369Sdim pg("pmap_pinit(%x)\n", pmap); 450321369Sdim#endif 451353358Sdim 452353358Sdim /* 453353358Sdim * No need to allocate page table space yet but we do need a 454353358Sdim * valid page directory table. 455353358Sdim */ 456353358Sdim pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG); 457353358Sdim 458353358Sdim /* wire in kernel global address entries */ 459353358Sdim bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST, 460353358Sdim (KPTDI_LAST-KPTDI_FIRST+1)*4); 461353358Sdim 462353358Sdim /* install self-referential address mapping entry */ 463353358Sdim *(int *)(pmap->pm_pdir+PTDPTDI) = 464353358Sdim (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_URKW; 465353358Sdim 466353358Sdim pmap->pm_count = 1; 467353358Sdim simple_lock_init(&pmap->pm_lock); 468353358Sdim} 469353358Sdim 470360784Sdim/* 471353358Sdim * Retire the given physical map from service. 472353358Sdim * Should only be called if the map contains 473353358Sdim * no valid mappings. 474353358Sdim */ 475311116Sdimvoid 476353358Sdimpmap_destroy(pmap) 477321369Sdim register pmap_t pmap; 478321369Sdim{ 479321369Sdim int count; 480321369Sdim 481321369Sdim#ifdef DEBUG 482341825Sdim if (pmapdebug & PDB_FOLLOW) 483321369Sdim printf("pmap_destroy(%x)\n", pmap); 484327952Sdim#endif 485327952Sdim if (pmap == NULL) 486327952Sdim return; 487327952Sdim 488341825Sdim simple_lock(&pmap->pm_lock); 489311116Sdim count = --pmap->pm_count; 490311116Sdim simple_unlock(&pmap->pm_lock); 491311116Sdim if (count == 0) { 492311116Sdim pmap_release(pmap); 493321369Sdim free((caddr_t)pmap, M_VMPMAP); 494321369Sdim } 495321369Sdim} 496311116Sdim 497311116Sdim/* 498311116Sdim * Release any resources held by the given physical map. 499321369Sdim * Called when a pmap initialized by pmap_pinit is being released. 500311116Sdim * Should only be called if the map contains no valid mappings. 501311116Sdim */ 502311116Sdimvoid 503321369Sdimpmap_release(pmap) 504321369Sdim register struct pmap *pmap; 505311116Sdim{ 506311116Sdim 507311116Sdim#ifdef DEBUG 508311116Sdim if (pmapdebug & PDB_FOLLOW) 509311116Sdim pg("pmap_release(%x)\n", pmap); 510311116Sdim#endif 511311116Sdim#ifdef notdef /* DIAGNOSTIC */ 512311116Sdim /* count would be 0 from pmap_destroy... */ 513321369Sdim simple_lock(&pmap->pm_lock); 514311116Sdim if (pmap->pm_count != 1) 515311116Sdim panic("pmap_release count"); 516311116Sdim#endif 517311116Sdim kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG); 518321369Sdim} 519311116Sdim 520321369Sdim/* 521311116Sdim * Add a reference to the specified pmap. 522311116Sdim */ 523311116Sdimvoid 524311116Sdimpmap_reference(pmap) 525311116Sdim pmap_t pmap; 526311116Sdim{ 527311116Sdim#ifdef DEBUG 528321369Sdim if (pmapdebug & PDB_FOLLOW) 529311116Sdim printf("pmap_reference(%x)", pmap); 530321369Sdim#endif 531311116Sdim if (pmap != NULL) { 532311116Sdim simple_lock(&pmap->pm_lock); 533311116Sdim pmap->pm_count++; 534321369Sdim simple_unlock(&pmap->pm_lock); 535321369Sdim } 536321369Sdim} 537311116Sdim 538321369Sdim/* 539321369Sdim * Remove the given range of addresses from the specified map. 540321369Sdim * 541321369Sdim * It is assumed that the start and end are properly 542321369Sdim * rounded to the page size. 543321369Sdim */ 544321369Sdimvoid 545321369Sdimpmap_remove(pmap, sva, eva) 546321369Sdim struct pmap *pmap; 547321369Sdim register vm_offset_t sva; 548321369Sdim register vm_offset_t eva; 549321369Sdim{ 550 register pt_entry_t *ptp,*ptq; 551 vm_offset_t va; 552 vm_offset_t pa; 553 pt_entry_t *pte; 554 pv_entry_t pv, npv; 555 int ix; 556 int s, bits; 557#ifdef DEBUG 558 pt_entry_t opte; 559 560 if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) 561 pg("pmap_remove(%x, %x, %x)", pmap, sva, eva); 562#endif 563 564 if (pmap == NULL) 565 return; 566 567 /* are we current address space or kernel? */ 568 if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum 569 || pmap == kernel_pmap) 570 ptp=PTmap; 571 572 /* otherwise, we are alternate address space */ 573 else { 574 if (pmap->pm_pdir[PTDPTDI].pd_pfnum 575 != APTDpde.pd_pfnum) { 576 APTDpde = pmap->pm_pdir[PTDPTDI]; 577 tlbflush(); 578 } 579 ptp=APTmap; 580 } 581#ifdef DEBUG 582 remove_stats.calls++; 583#endif 584 585 /* this is essential since we must check the PDE(sva) for precense */ 586 while (sva <= eva && !pmap_pde_v(pmap_pde(pmap, sva))) 587 sva = (sva & PD_MASK) + (1<<PD_SHIFT); 588 sva = i386_btop(sva); 589 eva = i386_btop(eva); 590 591 for (; sva < eva; sva++) { 592 /* 593 * Weed out invalid mappings. 594 * Note: we assume that the page directory table is 595 * always allocated, and in kernel virtual. 596 */ 597 ptq=ptp+sva; 598 while((sva & 0x3ff) && !pmap_pte_pa(ptq)) 599 { 600 if(++sva >= eva) 601 return; 602 ptq++; 603 } 604 605 606 if(!(sva & 0x3ff)) /* Only check once in a while */ 607 { 608 if (!pmap_pde_v(pmap_pde(pmap, i386_ptob(sva)))) 609 { 610 /* We can race ahead here, straight to next pde.. */ 611 sva = (sva & 0xffc00) + (1<<10) -1 ; 612 continue; 613 } 614 } 615 if(!pmap_pte_pa(ptp+sva)) 616 continue; 617 618 pte = ptp + sva; 619 pa = pmap_pte_pa(pte); 620 va = i386_ptob(sva); 621#ifdef DEBUG 622 opte = *pte; 623 remove_stats.removes++; 624#endif 625 /* 626 * Update statistics 627 */ 628 if (pmap_pte_w(pte)) 629 pmap->pm_stats.wired_count--; 630 pmap->pm_stats.resident_count--; 631 632 /* 633 * Invalidate the PTEs. 634 * XXX: should cluster them up and invalidate as many 635 * as possible at once. 636 */ 637#ifdef DEBUG 638 if (pmapdebug & PDB_REMOVE) 639 printf("remove: inv %x ptes at %x(%x) ", 640 i386pagesperpage, pte, *(int *)pte); 641#endif 642 bits = ix = 0; 643 do { 644 bits |= *(int *)pte & (PG_U|PG_M); 645 *(int *)pte++ = 0; 646 /*TBIS(va + ix * I386_PAGE_SIZE);*/ 647 } while (++ix != i386pagesperpage); 648 if (curproc && pmap == &curproc->p_vmspace->vm_pmap) 649 pmap_activate(pmap, (struct pcb *)curproc->p_addr); 650 /* are we current address space or kernel? */ 651 /*if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum 652 || pmap == kernel_pmap) 653 load_cr3(curpcb->pcb_ptd);*/ 654 tlbflush(); 655 656#ifdef needednotdone 657reduce wiring count on page table pages as references drop 658#endif 659 660 /* 661 * Remove from the PV table (raise IPL since we 662 * may be called at interrupt time). 663 */ 664 if (pa < vm_first_phys || pa >= vm_last_phys) 665 continue; 666 pv = pa_to_pvh(pa); 667 s = splimp(); 668 /* 669 * If it is the first entry on the list, it is actually 670 * in the header and we must copy the following entry up 671 * to the header. Otherwise we must search the list for 672 * the entry. In either case we free the now unused entry. 673 */ 674 if (pmap == pv->pv_pmap && va == pv->pv_va) { 675 npv = pv->pv_next; 676 if (npv) { 677 *pv = *npv; 678 free((caddr_t)npv, M_VMPVENT); 679 } else 680 pv->pv_pmap = NULL; 681#ifdef DEBUG 682 remove_stats.pvfirst++; 683#endif 684 } else { 685 for (npv = pv->pv_next; npv; npv = npv->pv_next) { 686#ifdef DEBUG 687 remove_stats.pvsearch++; 688#endif 689 if (pmap == npv->pv_pmap && va == npv->pv_va) 690 break; 691 pv = npv; 692 } 693#ifdef DEBUG 694 if (npv == NULL) 695 panic("pmap_remove: PA not in pv_tab"); 696#endif 697 pv->pv_next = npv->pv_next; 698 free((caddr_t)npv, M_VMPVENT); 699 pv = pa_to_pvh(pa); 700 } 701 702#ifdef notdef 703[tally number of pagetable pages, if sharing of ptpages adjust here] 704#endif 705 /* 706 * Update saved attributes for managed page 707 */ 708 pmap_attributes[pa_index(pa)] |= bits; 709 splx(s); 710 } 711#ifdef notdef 712[cache and tlb flushing, if needed] 713#endif 714} 715 716/* 717 * Routine: pmap_remove_all 718 * Function: 719 * Removes this physical page from 720 * all physical maps in which it resides. 721 * Reflects back modify bits to the pager. 722 */ 723void 724pmap_remove_all(pa) 725 vm_offset_t pa; 726{ 727 register pv_entry_t pv; 728 int s; 729 730#ifdef DEBUG 731 if (pmapdebug & (PDB_FOLLOW|PDB_REMOVE|PDB_PROTECT)) 732 printf("pmap_remove_all(%x)", pa); 733 /*pmap_pvdump(pa);*/ 734#endif 735 /* 736 * Not one of ours 737 */ 738 if (pa < vm_first_phys || pa >= vm_last_phys) 739 return; 740 741 pv = pa_to_pvh(pa); 742 s = splimp(); 743 /* 744 * Do it the easy way for now 745 */ 746 while (pv->pv_pmap != NULL) { 747#ifdef DEBUG 748 if (!pmap_pde_v(pmap_pde(pv->pv_pmap, pv->pv_va)) || 749 pmap_pte_pa(pmap_pte(pv->pv_pmap, pv->pv_va)) != pa) 750 panic("pmap_remove_all: bad mapping"); 751#endif 752 pmap_remove(pv->pv_pmap, pv->pv_va, pv->pv_va + PAGE_SIZE); 753 } 754 splx(s); 755} 756 757/* 758 * Routine: pmap_copy_on_write 759 * Function: 760 * Remove write privileges from all 761 * physical maps for this physical page. 762 */ 763void 764pmap_copy_on_write(pa) 765 vm_offset_t pa; 766{ 767#ifdef DEBUG 768 if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) 769 printf("pmap_copy_on_write(%x)", pa); 770#endif 771 pmap_changebit(pa, PG_RO, TRUE); 772} 773 774/* 775 * Set the physical protection on the 776 * specified range of this map as requested. 777 */ 778void 779pmap_protect(pmap, sva, eva, prot) 780 register pmap_t pmap; 781 vm_offset_t sva, eva; 782 vm_prot_t prot; 783{ 784 register pt_entry_t *pte; 785 register vm_offset_t va; 786 register int ix; 787 int i386prot; 788 boolean_t firstpage = TRUE; 789 register pt_entry_t *ptp; 790 791#ifdef DEBUG 792 if (pmapdebug & (PDB_FOLLOW|PDB_PROTECT)) 793 printf("pmap_protect(%x, %x, %x, %x)", pmap, sva, eva, prot); 794#endif 795 if (pmap == NULL) 796 return; 797 798 if ((prot & VM_PROT_READ) == VM_PROT_NONE) { 799 pmap_remove(pmap, sva, eva); 800 return; 801 } 802 if (prot & VM_PROT_WRITE) 803 return; 804 805 /* are we current address space or kernel? */ 806 if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum 807 || pmap == kernel_pmap) 808 ptp=PTmap; 809 810 /* otherwise, we are alternate address space */ 811 else { 812 if (pmap->pm_pdir[PTDPTDI].pd_pfnum 813 != APTDpde.pd_pfnum) { 814 APTDpde = pmap->pm_pdir[PTDPTDI]; 815 tlbflush(); 816 } 817 ptp=APTmap; 818 } 819 for (va = sva; va < eva; va += PAGE_SIZE) { 820 /* 821 * Page table page is not allocated. 822 * Skip it, we don't want to force allocation 823 * of unnecessary PTE pages just to set the protection. 824 */ 825 if (!pmap_pde_v(pmap_pde(pmap, va))) { 826 /* XXX: avoid address wrap around */ 827 if (va >= i386_trunc_pdr((vm_offset_t)-1)) 828 break; 829 va = i386_round_pdr(va + PAGE_SIZE) - PAGE_SIZE; 830 continue; 831 } 832 833 pte = ptp + i386_btop(va); 834 835 /* 836 * Page not valid. Again, skip it. 837 * Should we do this? Or set protection anyway? 838 */ 839 if (!pmap_pte_v(pte)) 840 continue; 841 842 ix = 0; 843 i386prot = pte_prot(pmap, prot); 844 if(va < UPT_MAX_ADDRESS) 845 i386prot |= 2 /*PG_u*/; 846 do { 847 /* clear VAC here if PG_RO? */ 848 pmap_pte_set_prot(pte++, i386prot); 849 /*TBIS(va + ix * I386_PAGE_SIZE);*/ 850 } while (++ix != i386pagesperpage); 851 } 852 if (curproc && pmap == &curproc->p_vmspace->vm_pmap) 853 pmap_activate(pmap, (struct pcb *)curproc->p_addr); 854} 855 856/* 857 * Insert the given physical page (p) at 858 * the specified virtual address (v) in the 859 * target physical map with the protection requested. 860 * 861 * If specified, the page will be wired down, meaning 862 * that the related pte can not be reclaimed. 863 * 864 * NB: This is the only routine which MAY NOT lazy-evaluate 865 * or lose information. That is, this routine must actually 866 * insert this page into the given map NOW. 867 */ 868void 869pmap_enter(pmap, va, pa, prot, wired) 870 register pmap_t pmap; 871 vm_offset_t va; 872 register vm_offset_t pa; 873 vm_prot_t prot; 874 boolean_t wired; 875{ 876 register pt_entry_t *pte; 877 register int npte, ix; 878 vm_offset_t opa; 879 boolean_t cacheable = TRUE; 880 boolean_t checkpv = TRUE; 881 882#ifdef DEBUG 883 if (pmapdebug & (PDB_FOLLOW|PDB_ENTER)) 884 printf("pmap_enter(%x, %x, %x, %x, %x)", 885 pmap, va, pa, prot, wired); 886#endif 887 if (pmap == NULL) 888 return; 889 890 if(va > VM_MAX_KERNEL_ADDRESS)panic("pmap_enter: toobig"); 891 /* also, should not muck with PTD va! */ 892 893#ifdef DEBUG 894 if (pmap == kernel_pmap) 895 enter_stats.kernel++; 896 else 897 enter_stats.user++; 898#endif 899 900 /* 901 * Page Directory table entry not valid, we need a new PT page 902 */ 903 if (!pmap_pde_v(pmap_pde(pmap, va))) { 904 pg("ptdi %x", pmap->pm_pdir[PTDPTDI]); 905 } 906 907 pte = pmap_pte(pmap, va); 908 opa = pmap_pte_pa(pte); 909#ifdef DEBUG 910 if (pmapdebug & PDB_ENTER) 911 printf("enter: pte %x, *pte %x ", pte, *(int *)pte); 912#endif 913 914 /* 915 * Mapping has not changed, must be protection or wiring change. 916 */ 917 if (opa == pa) { 918#ifdef DEBUG 919 enter_stats.pwchange++; 920#endif 921 /* 922 * Wiring change, just update stats. 923 * We don't worry about wiring PT pages as they remain 924 * resident as long as there are valid mappings in them. 925 * Hence, if a user page is wired, the PT page will be also. 926 */ 927 if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { 928#ifdef DEBUG 929 if (pmapdebug & PDB_ENTER) 930 pg("enter: wiring change -> %x ", wired); 931#endif 932 if (wired) 933 pmap->pm_stats.wired_count++; 934 else 935 pmap->pm_stats.wired_count--; 936#ifdef DEBUG 937 enter_stats.wchange++; 938#endif 939 } 940 goto validate; 941 } 942 943 /* 944 * Mapping has changed, invalidate old range and fall through to 945 * handle validating new mapping. 946 */ 947 if (opa) { 948#ifdef DEBUG 949 if (pmapdebug & PDB_ENTER) 950 printf("enter: removing old mapping %x pa %x ", va, opa); 951#endif 952 pmap_remove(pmap, va, va + PAGE_SIZE); 953#ifdef DEBUG 954 enter_stats.mchange++; 955#endif 956 } 957 958 /* 959 * Enter on the PV list if part of our managed memory 960 * Note that we raise IPL while manipulating pv_table 961 * since pmap_enter can be called at interrupt time. 962 */ 963 if (pa >= vm_first_phys && pa < vm_last_phys) { 964 register pv_entry_t pv, npv; 965 int s; 966 967#ifdef DEBUG 968 enter_stats.managed++; 969#endif 970 pv = pa_to_pvh(pa); 971 s = splimp(); 972#ifdef DEBUG 973 if (pmapdebug & PDB_ENTER) 974 printf("enter: pv at %x: %x/%x/%x ", 975 pv, pv->pv_va, pv->pv_pmap, pv->pv_next); 976#endif 977 /* 978 * No entries yet, use header as the first entry 979 */ 980 if (pv->pv_pmap == NULL) { 981#ifdef DEBUG 982 enter_stats.firstpv++; 983#endif 984 pv->pv_va = va; 985 pv->pv_pmap = pmap; 986 pv->pv_next = NULL; 987 pv->pv_flags = 0; 988 } 989 /* 990 * There is at least one other VA mapping this page. 991 * Place this entry after the header. 992 */ 993 else { 994 /*printf("second time: ");*/ 995#ifdef DEBUG 996 for (npv = pv; npv; npv = npv->pv_next) 997 if (pmap == npv->pv_pmap && va == npv->pv_va) 998 panic("pmap_enter: already in pv_tab"); 999#endif 1000 npv = (pv_entry_t) 1001 malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); 1002 npv->pv_va = va; 1003 npv->pv_pmap = pmap; 1004 npv->pv_next = pv->pv_next; 1005 pv->pv_next = npv; 1006#ifdef DEBUG 1007 if (!npv->pv_next) 1008 enter_stats.secondpv++; 1009#endif 1010 } 1011 splx(s); 1012 } 1013 /* 1014 * Assumption: if it is not part of our managed memory 1015 * then it must be device memory which may be volitile. 1016 */ 1017 if (pmap_initialized) { 1018 checkpv = cacheable = FALSE; 1019#ifdef DEBUG 1020 enter_stats.unmanaged++; 1021#endif 1022 } 1023 1024 /* 1025 * Increment counters 1026 */ 1027 pmap->pm_stats.resident_count++; 1028 if (wired) 1029 pmap->pm_stats.wired_count++; 1030 1031validate: 1032 /* 1033 * Now validate mapping with desired protection/wiring. 1034 * Assume uniform modified and referenced status for all 1035 * I386 pages in a MACH page. 1036 */ 1037 npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; 1038 npte |= (*(int *)pte & (PG_M|PG_U)); 1039 if (wired) 1040 npte |= PG_W; 1041 if(va < UPT_MIN_ADDRESS) 1042 npte |= PG_u; 1043 else if(va < UPT_MAX_ADDRESS) 1044 npte |= PG_u | PG_RW; 1045#ifdef DEBUG 1046 if (pmapdebug & PDB_ENTER) 1047 printf("enter: new pte value %x ", npte); 1048#endif 1049 ix = 0; 1050 do { 1051 *(int *)pte++ = npte; 1052 /*TBIS(va);*/ 1053 npte += I386_PAGE_SIZE; 1054 va += I386_PAGE_SIZE; 1055 } while (++ix != i386pagesperpage); 1056 pte--; 1057#ifdef DEBUGx 1058cache, tlb flushes 1059#endif 1060/*pads(pmap);*/ 1061 /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/ 1062 tlbflush(); 1063} 1064 1065/* 1066 * pmap_page_protect: 1067 * 1068 * Lower the permission for all mappings to a given page. 1069 */ 1070void 1071pmap_page_protect(phys, prot) 1072 vm_offset_t phys; 1073 vm_prot_t prot; 1074{ 1075 switch (prot) { 1076 case VM_PROT_READ: 1077 case VM_PROT_READ|VM_PROT_EXECUTE: 1078 pmap_copy_on_write(phys); 1079 break; 1080 case VM_PROT_ALL: 1081 break; 1082 default: 1083 pmap_remove_all(phys); 1084 break; 1085 } 1086} 1087 1088/* 1089 * Routine: pmap_change_wiring 1090 * Function: Change the wiring attribute for a map/virtual-address 1091 * pair. 1092 * In/out conditions: 1093 * The mapping must already exist in the pmap. 1094 */ 1095void 1096pmap_change_wiring(pmap, va, wired) 1097 register pmap_t pmap; 1098 vm_offset_t va; 1099 boolean_t wired; 1100{ 1101 register pt_entry_t *pte; 1102 register int ix; 1103 1104#ifdef DEBUG 1105 if (pmapdebug & PDB_FOLLOW) 1106 printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired); 1107#endif 1108 if (pmap == NULL) 1109 return; 1110 1111 pte = pmap_pte(pmap, va); 1112#ifdef DEBUG 1113 /* 1114 * Page table page is not allocated. 1115 * Should this ever happen? Ignore it for now, 1116 * we don't want to force allocation of unnecessary PTE pages. 1117 */ 1118 if (!pmap_pde_v(pmap_pde(pmap, va))) { 1119 if (pmapdebug & PDB_PARANOIA) 1120 pg("pmap_change_wiring: invalid PDE for %x ", va); 1121 return; 1122 } 1123 /* 1124 * Page not valid. Should this ever happen? 1125 * Just continue and change wiring anyway. 1126 */ 1127 if (!pmap_pte_v(pte)) { 1128 if (pmapdebug & PDB_PARANOIA) 1129 pg("pmap_change_wiring: invalid PTE for %x ", va); 1130 } 1131#endif 1132 if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { 1133 if (wired) 1134 pmap->pm_stats.wired_count++; 1135 else 1136 pmap->pm_stats.wired_count--; 1137 } 1138 /* 1139 * Wiring is not a hardware characteristic so there is no need 1140 * to invalidate TLB. 1141 */ 1142 ix = 0; 1143 do { 1144 pmap_pte_set_w(pte++, wired); 1145 } while (++ix != i386pagesperpage); 1146} 1147 1148/* 1149 * Routine: pmap_pte 1150 * Function: 1151 * Extract the page table entry associated 1152 * with the given map/virtual_address pair. 1153 * [ what about induced faults -wfj] 1154 */ 1155 1156struct pte *pmap_pte(pmap, va) 1157 register pmap_t pmap; 1158 vm_offset_t va; 1159{ 1160 1161#ifdef DEBUGx 1162 if (pmapdebug & PDB_FOLLOW) 1163 printf("pmap_pte(%x, %x) ->\n", pmap, va); 1164#endif 1165 if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { 1166 1167 /* are we current address space or kernel? */ 1168 if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum 1169 || pmap == kernel_pmap) 1170 return ((struct pte *) vtopte(va)); 1171 1172 /* otherwise, we are alternate address space */ 1173 else { 1174 if (pmap->pm_pdir[PTDPTDI].pd_pfnum 1175 != APTDpde.pd_pfnum) { 1176 APTDpde = pmap->pm_pdir[PTDPTDI]; 1177 tlbflush(); 1178 } 1179 return((struct pte *) avtopte(va)); 1180 } 1181 } 1182 return(0); 1183} 1184 1185/* 1186 * Routine: pmap_extract 1187 * Function: 1188 * Extract the physical page address associated 1189 * with the given map/virtual_address pair. 1190 */ 1191 1192vm_offset_t 1193pmap_extract(pmap, va) 1194 register pmap_t pmap; 1195 vm_offset_t va; 1196{ 1197 register vm_offset_t pa; 1198 1199#ifdef DEBUGx 1200 if (pmapdebug & PDB_FOLLOW) 1201 pg("pmap_extract(%x, %x) -> ", pmap, va); 1202#endif 1203 pa = 0; 1204 if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { 1205 pa = *(int *) pmap_pte(pmap, va); 1206 } 1207 if (pa) 1208 pa = (pa & PG_FRAME) | (va & ~PG_FRAME); 1209#ifdef DEBUGx 1210 if (pmapdebug & PDB_FOLLOW) 1211 printf("%x\n", pa); 1212#endif 1213 return(pa); 1214} 1215 1216/* 1217 * Copy the range specified by src_addr/len 1218 * from the source map to the range dst_addr/len 1219 * in the destination map. 1220 * 1221 * This routine is only advisory and need not do anything. 1222 */ 1223void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) 1224 pmap_t dst_pmap; 1225 pmap_t src_pmap; 1226 vm_offset_t dst_addr; 1227 vm_size_t len; 1228 vm_offset_t src_addr; 1229{ 1230#ifdef DEBUG 1231 if (pmapdebug & PDB_FOLLOW) 1232 printf("pmap_copy(%x, %x, %x, %x, %x)", 1233 dst_pmap, src_pmap, dst_addr, len, src_addr); 1234#endif 1235} 1236 1237/* 1238 * Require that all active physical maps contain no 1239 * incorrect entries NOW. [This update includes 1240 * forcing updates of any address map caching.] 1241 * 1242 * Generally used to insure that a thread about 1243 * to run will see a semantically correct world. 1244 */ 1245void pmap_update() 1246{ 1247#ifdef DEBUG 1248 if (pmapdebug & PDB_FOLLOW) 1249 printf("pmap_update()"); 1250#endif 1251 tlbflush(); 1252} 1253 1254/* 1255 * Routine: pmap_collect 1256 * Function: 1257 * Garbage collects the physical map system for 1258 * pages which are no longer used. 1259 * Success need not be guaranteed -- that is, there 1260 * may well be pages which are not referenced, but 1261 * others may be collected. 1262 * Usage: 1263 * Called by the pageout daemon when pages are scarce. 1264 * [ needs to be written -wfj ] 1265 */ 1266void 1267pmap_collect(pmap) 1268 pmap_t pmap; 1269{ 1270 register vm_offset_t pa; 1271 register pv_entry_t pv; 1272 register int *pte; 1273 vm_offset_t kpa; 1274 int s; 1275 1276#ifdef DEBUG 1277 int *pde; 1278 int opmapdebug; 1279 printf("pmap_collect(%x) ", pmap); 1280#endif 1281 if (pmap != kernel_pmap) 1282 return; 1283 1284} 1285 1286/* [ macro again?, should I force kstack into user map here? -wfj ] */ 1287void 1288pmap_activate(pmap, pcbp) 1289 register pmap_t pmap; 1290 struct pcb *pcbp; 1291{ 1292int x; 1293#ifdef DEBUG 1294 if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB)) 1295 pg("pmap_activate(%x, %x) ", pmap, pcbp); 1296#endif 1297 PMAP_ACTIVATE(pmap, pcbp); 1298/*printf("pde "); 1299for(x=0x3f6; x < 0x3fA; x++) 1300 printf("%x ", pmap->pm_pdir[x]);*/ 1301/*pads(pmap);*/ 1302/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/ 1303} 1304 1305/* 1306 * Routine: pmap_kernel 1307 * Function: 1308 * Returns the physical map handle for the kernel. 1309 */ 1310pmap_t 1311pmap_kernel() 1312{ 1313 return (kernel_pmap); 1314} 1315 1316/* 1317 * pmap_zero_page zeros the specified (machine independent) 1318 * page by mapping the page into virtual memory and using 1319 * bzero to clear its contents, one machine dependent page 1320 * at a time. 1321 */ 1322pmap_zero_page(phys) 1323 register vm_offset_t phys; 1324{ 1325 register int ix; 1326 1327#ifdef DEBUG 1328 if (pmapdebug & PDB_FOLLOW) 1329 printf("pmap_zero_page(%x)", phys); 1330#endif 1331 phys >>= PG_SHIFT; 1332 ix = 0; 1333 do { 1334 clearseg(phys++); 1335 } while (++ix != i386pagesperpage); 1336} 1337 1338/* 1339 * pmap_copy_page copies the specified (machine independent) 1340 * page by mapping the page into virtual memory and using 1341 * bcopy to copy the page, one machine dependent page at a 1342 * time. 1343 */ 1344pmap_copy_page(src, dst) 1345 register vm_offset_t src, dst; 1346{ 1347 register int ix; 1348 1349#ifdef DEBUG 1350 if (pmapdebug & PDB_FOLLOW) 1351 printf("pmap_copy_page(%x, %x)", src, dst); 1352#endif 1353 src >>= PG_SHIFT; 1354 dst >>= PG_SHIFT; 1355 ix = 0; 1356 do { 1357 physcopyseg(src++, dst++); 1358 } while (++ix != i386pagesperpage); 1359} 1360 1361 1362/* 1363 * Routine: pmap_pageable 1364 * Function: 1365 * Make the specified pages (by pmap, offset) 1366 * pageable (or not) as requested. 1367 * 1368 * A page which is not pageable may not take 1369 * a fault; therefore, its page table entry 1370 * must remain valid for the duration. 1371 * 1372 * This routine is merely advisory; pmap_enter 1373 * will specify that these pages are to be wired 1374 * down (or not) as appropriate. 1375 */ 1376pmap_pageable(pmap, sva, eva, pageable) 1377 pmap_t pmap; 1378 vm_offset_t sva, eva; 1379 boolean_t pageable; 1380{ 1381#ifdef DEBUG 1382 if (pmapdebug & PDB_FOLLOW) 1383 printf("pmap_pageable(%x, %x, %x, %x)", 1384 pmap, sva, eva, pageable); 1385#endif 1386 /* 1387 * If we are making a PT page pageable then all valid 1388 * mappings must be gone from that page. Hence it should 1389 * be all zeros and there is no need to clean it. 1390 * Assumptions: 1391 * - we are called with only one page at a time 1392 * - PT pages have only one pv_table entry 1393 */ 1394 if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) { 1395 register pv_entry_t pv; 1396 register vm_offset_t pa; 1397 1398#ifdef DEBUG 1399 if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) 1400 printf("pmap_pageable(%x, %x, %x, %x)", 1401 pmap, sva, eva, pageable); 1402#endif 1403 /*if (!pmap_pde_v(pmap_pde(pmap, sva))) 1404 return;*/ 1405 if(pmap_pte(pmap, sva) == 0) 1406 return; 1407 pa = pmap_pte_pa(pmap_pte(pmap, sva)); 1408 if (pa < vm_first_phys || pa >= vm_last_phys) 1409 return; 1410 pv = pa_to_pvh(pa); 1411 /*if (!ispt(pv->pv_va)) 1412 return;*/ 1413#ifdef DEBUG 1414 if (pv->pv_va != sva || pv->pv_next) { 1415 pg("pmap_pageable: bad PT page va %x next %x\n", 1416 pv->pv_va, pv->pv_next); 1417 return; 1418 } 1419#endif 1420 /* 1421 * Mark it unmodified to avoid pageout 1422 */ 1423 pmap_clear_modify(pa); 1424#ifdef needsomethinglikethis 1425 if (pmapdebug & PDB_PTPAGE) 1426 pg("pmap_pageable: PT page %x(%x) unmodified\n", 1427 sva, *(int *)pmap_pte(pmap, sva)); 1428 if (pmapdebug & PDB_WIRING) 1429 pmap_check_wiring("pageable", sva); 1430#endif 1431 } 1432} 1433 1434/* 1435 * Clear the modify bits on the specified physical page. 1436 */ 1437 1438void 1439pmap_clear_modify(pa) 1440 vm_offset_t pa; 1441{ 1442#ifdef DEBUG 1443 if (pmapdebug & PDB_FOLLOW) 1444 printf("pmap_clear_modify(%x)", pa); 1445#endif 1446 pmap_changebit(pa, PG_M, FALSE); 1447} 1448 1449/* 1450 * pmap_clear_reference: 1451 * 1452 * Clear the reference bit on the specified physical page. 1453 */ 1454 1455void pmap_clear_reference(pa) 1456 vm_offset_t pa; 1457{ 1458#ifdef DEBUG 1459 if (pmapdebug & PDB_FOLLOW) 1460 printf("pmap_clear_reference(%x)", pa); 1461#endif 1462 pmap_changebit(pa, PG_U, FALSE); 1463} 1464 1465/* 1466 * pmap_is_referenced: 1467 * 1468 * Return whether or not the specified physical page is referenced 1469 * by any physical maps. 1470 */ 1471 1472boolean_t 1473pmap_is_referenced(pa) 1474 vm_offset_t pa; 1475{ 1476#ifdef DEBUG 1477 if (pmapdebug & PDB_FOLLOW) { 1478 boolean_t rv = pmap_testbit(pa, PG_U); 1479 printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]); 1480 return(rv); 1481 } 1482#endif 1483 return(pmap_testbit(pa, PG_U)); 1484} 1485 1486/* 1487 * pmap_is_modified: 1488 * 1489 * Return whether or not the specified physical page is modified 1490 * by any physical maps. 1491 */ 1492 1493boolean_t 1494pmap_is_modified(pa) 1495 vm_offset_t pa; 1496{ 1497#ifdef DEBUG 1498 if (pmapdebug & PDB_FOLLOW) { 1499 boolean_t rv = pmap_testbit(pa, PG_M); 1500 printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]); 1501 return(rv); 1502 } 1503#endif 1504 return(pmap_testbit(pa, PG_M)); 1505} 1506 1507vm_offset_t 1508pmap_phys_address(ppn) 1509 int ppn; 1510{ 1511 return(i386_ptob(ppn)); 1512} 1513 1514/* 1515 * Miscellaneous support routines follow 1516 */ 1517 1518i386_protection_init() 1519{ 1520 register int *kp, prot; 1521 1522 kp = protection_codes; 1523 for (prot = 0; prot < 8; prot++) { 1524 switch (prot) { 1525 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: 1526 *kp++ = 0; 1527 break; 1528 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: 1529 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: 1530 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: 1531 *kp++ = PG_RO; 1532 break; 1533 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: 1534 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: 1535 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: 1536 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: 1537 *kp++ = PG_RW; 1538 break; 1539 } 1540 } 1541} 1542 1543boolean_t 1544pmap_testbit(pa, bit) 1545 register vm_offset_t pa; 1546 int bit; 1547{ 1548 register pv_entry_t pv; 1549 register int *pte, ix; 1550 int s; 1551 1552 if (pa < vm_first_phys || pa >= vm_last_phys) 1553 return(FALSE); 1554 1555 pv = pa_to_pvh(pa); 1556 s = splimp(); 1557 /* 1558 * Check saved info first 1559 */ 1560 if (pmap_attributes[pa_index(pa)] & bit) { 1561 splx(s); 1562 return(TRUE); 1563 } 1564 /* 1565 * Not found, check current mappings returning 1566 * immediately if found. 1567 */ 1568 if (pv->pv_pmap != NULL) { 1569 for (; pv; pv = pv->pv_next) { 1570 pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va); 1571 ix = 0; 1572 do { 1573 if (*pte++ & bit) { 1574 splx(s); 1575 return(TRUE); 1576 } 1577 } while (++ix != i386pagesperpage); 1578 } 1579 } 1580 splx(s); 1581 return(FALSE); 1582} 1583 1584pmap_changebit(pa, bit, setem) 1585 register vm_offset_t pa; 1586 int bit; 1587 boolean_t setem; 1588{ 1589 register pv_entry_t pv; 1590 register int *pte, npte, ix; 1591 vm_offset_t va; 1592 int s; 1593 boolean_t firstpage = TRUE; 1594 1595#ifdef DEBUG 1596 if (pmapdebug & PDB_BITS) 1597 printf("pmap_changebit(%x, %x, %s)", 1598 pa, bit, setem ? "set" : "clear"); 1599#endif 1600 if (pa < vm_first_phys || pa >= vm_last_phys) 1601 return; 1602 1603 pv = pa_to_pvh(pa); 1604 s = splimp(); 1605 /* 1606 * Clear saved attributes (modify, reference) 1607 */ 1608 if (!setem) 1609 pmap_attributes[pa_index(pa)] &= ~bit; 1610 /* 1611 * Loop over all current mappings setting/clearing as appropos 1612 * If setting RO do we need to clear the VAC? 1613 */ 1614 if (pv->pv_pmap != NULL) { 1615#ifdef DEBUG 1616 int toflush = 0; 1617#endif 1618 for (; pv; pv = pv->pv_next) { 1619#ifdef DEBUG 1620 toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1; 1621#endif 1622 va = pv->pv_va; 1623 1624 /* 1625 * XXX don't write protect pager mappings 1626 */ 1627 if (bit == PG_RO) { 1628 extern vm_offset_t pager_sva, pager_eva; 1629 1630 if (va >= pager_sva && va < pager_eva) 1631 continue; 1632 } 1633 1634 pte = (int *) pmap_pte(pv->pv_pmap, va); 1635 ix = 0; 1636 do { 1637 if (setem) 1638 npte = *pte | bit; 1639 else 1640 npte = *pte & ~bit; 1641 if (*pte != npte) { 1642 *pte = npte; 1643 /*TBIS(va);*/ 1644 } 1645 va += I386_PAGE_SIZE; 1646 pte++; 1647 } while (++ix != i386pagesperpage); 1648 1649 if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap) 1650 pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr); 1651 } 1652#ifdef somethinglikethis 1653 if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) { 1654 if ((pmapvacflush & PVF_TOTAL) || toflush == 3) 1655 DCIA(); 1656 else if (toflush == 2) 1657 DCIS(); 1658 else 1659 DCIU(); 1660 } 1661#endif 1662 } 1663 splx(s); 1664} 1665 1666#ifdef DEBUG 1667pmap_pvdump(pa) 1668 vm_offset_t pa; 1669{ 1670 register pv_entry_t pv; 1671 1672 printf("pa %x", pa); 1673 for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) { 1674 printf(" -> pmap %x, va %x, flags %x", 1675 pv->pv_pmap, pv->pv_va, pv->pv_flags); 1676 pads(pv->pv_pmap); 1677 } 1678 printf(" "); 1679} 1680 1681#ifdef notyet 1682pmap_check_wiring(str, va) 1683 char *str; 1684 vm_offset_t va; 1685{ 1686 vm_map_entry_t entry; 1687 register int count, *pte; 1688 1689 va = trunc_page(va); 1690 if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) || 1691 !pmap_pte_v(pmap_pte(kernel_pmap, va))) 1692 return; 1693 1694 if (!vm_map_lookup_entry(pt_map, va, &entry)) { 1695 pg("wired_check: entry for %x not found\n", va); 1696 return; 1697 } 1698 count = 0; 1699 for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++) 1700 if (*pte) 1701 count++; 1702 if (entry->wired_count != count) 1703 pg("*%s*: %x: w%d/a%d\n", 1704 str, va, entry->wired_count, count); 1705} 1706#endif 1707 1708/* print address space of pmap*/ 1709pads(pm) pmap_t pm; { 1710 unsigned va, i, j; 1711 struct pte *ptep; 1712 1713 if(pm == kernel_pmap) return; 1714 for (i = 0; i < 1024; i++) 1715 if(pm->pm_pdir[i].pd_v) 1716 for (j = 0; j < 1024 ; j++) { 1717 va = (i<<22)+(j<<12); 1718 if (pm == kernel_pmap && va < 0xfe000000) 1719 continue; 1720 if (pm != kernel_pmap && va > UPT_MAX_ADDRESS) 1721 continue; 1722 ptep = pmap_pte(pm, va); 1723 if(pmap_pte_v(ptep)) 1724 printf("%x:%x ", va, *(int *)ptep); 1725 } ; 1726 1727} 1728#endif 1729