pmap.c revision 424
1/* 2 * Copyright (c) 1991 Regents of the University of California. 3 * All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * the Systems Programming Group of the University of Utah Computer 7 * Science Department and William Jolitz of UUNET Technologies Inc. 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 the University of 20 * California, Berkeley and its contributors. 21 * 4. Neither the name of the University nor the names of its contributors 22 * may be used to endorse or promote products derived from this software 23 * without specific prior written permission. 24 * 25 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 26 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 27 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 28 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 29 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 30 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 31 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 32 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 33 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 34 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 35 * SUCH DAMAGE. 36 * 37 * @(#)pmap.c 7.7 (Berkeley) 5/12/91 38 * 39 * PATCHES MAGIC LEVEL PATCH THAT GOT US HERE 40 * -------------------- ----- ---------------------- 41 * CURRENT PATCH LEVEL: 1 00063 42 * -------------------- ----- ---------------------- 43 * 44 * 28 Nov 1991 Poul-Henning Kamp Speedup processing. 45 */ 46static char rcsid[] = "$Header: /a/cvs/386BSD/src/sys/i386/i386/pmap.c,v 1.2 1993/07/27 10:52:19 davidg Exp $"; 47 48/* 49 * Derived from hp300 version by Mike Hibler, this version by William 50 * Jolitz uses a recursive map [a pde points to the page directory] to 51 * map the page tables using the pagetables themselves. This is done to 52 * reduce the impact on kernel virtual memory for lots of sparse address 53 * space, and to reduce the cost of memory to each process. 54 * 55 * Derived from: hp300/@(#)pmap.c 7.1 (Berkeley) 12/5/90 56 */ 57 58/* 59 * Reno i386 version, from Mike Hibler's hp300 version. 60 */ 61 62/* 63 * Manages physical address maps. 64 * 65 * In addition to hardware address maps, this 66 * module is called upon to provide software-use-only 67 * maps which may or may not be stored in the same 68 * form as hardware maps. These pseudo-maps are 69 * used to store intermediate results from copy 70 * operations to and from address spaces. 71 * 72 * Since the information managed by this module is 73 * also stored by the logical address mapping module, 74 * this module may throw away valid virtual-to-physical 75 * mappings at almost any time. However, invalidations 76 * of virtual-to-physical mappings must be done as 77 * requested. 78 * 79 * In order to cope with hardware architectures which 80 * make virtual-to-physical map invalidates expensive, 81 * this module may delay invalidate or reduced protection 82 * operations until such time as they are actually 83 * necessary. This module is given full information as 84 * to which processors are currently using which maps, 85 * and to when physical maps must be made correct. 86 */ 87 88#include "param.h" 89#include "proc.h" 90#include "malloc.h" 91#include "user.h" 92 93#include "vm/vm.h" 94#include "vm/vm_kern.h" 95#include "vm/vm_page.h" 96/*#include "vm/vm_pageout.h"*/ 97 98#include "i386/isa/isa.h" 99 100/* 101 * Allocate various and sundry SYSMAPs used in the days of old VM 102 * and not yet converted. XXX. 103 */ 104#define BSDVM_COMPAT 1 105 106#ifdef DEBUG 107struct { 108 int kernel; /* entering kernel mapping */ 109 int user; /* entering user mapping */ 110 int ptpneeded; /* needed to allocate a PT page */ 111 int pwchange; /* no mapping change, just wiring or protection */ 112 int wchange; /* no mapping change, just wiring */ 113 int mchange; /* was mapped but mapping to different page */ 114 int managed; /* a managed page */ 115 int firstpv; /* first mapping for this PA */ 116 int secondpv; /* second mapping for this PA */ 117 int ci; /* cache inhibited */ 118 int unmanaged; /* not a managed page */ 119 int flushes; /* cache flushes */ 120} enter_stats; 121struct { 122 int calls; 123 int removes; 124 int pvfirst; 125 int pvsearch; 126 int ptinvalid; 127 int uflushes; 128 int sflushes; 129} remove_stats; 130 131int debugmap = 0; 132int pmapdebug = 0 /* 0xffff */; 133#define PDB_FOLLOW 0x0001 134#define PDB_INIT 0x0002 135#define PDB_ENTER 0x0004 136#define PDB_REMOVE 0x0008 137#define PDB_CREATE 0x0010 138#define PDB_PTPAGE 0x0020 139#define PDB_CACHE 0x0040 140#define PDB_BITS 0x0080 141#define PDB_COLLECT 0x0100 142#define PDB_PROTECT 0x0200 143#define PDB_PDRTAB 0x0400 144#define PDB_PARANOIA 0x2000 145#define PDB_WIRING 0x4000 146#define PDB_PVDUMP 0x8000 147 148int pmapvacflush = 0; 149#define PVF_ENTER 0x01 150#define PVF_REMOVE 0x02 151#define PVF_PROTECT 0x04 152#define PVF_TOTAL 0x80 153#endif 154 155/* 156 * Get PDEs and PTEs for user/kernel address space 157 */ 158#define pmap_pde(m, v) (&((m)->pm_pdir[((vm_offset_t)(v) >> PD_SHIFT)&1023])) 159 160#define pmap_pte_pa(pte) (*(int *)(pte) & PG_FRAME) 161 162#define pmap_pde_v(pte) ((pte)->pd_v) 163#define pmap_pte_w(pte) ((pte)->pg_w) 164/* #define pmap_pte_ci(pte) ((pte)->pg_ci) */ 165#define pmap_pte_m(pte) ((pte)->pg_m) 166#define pmap_pte_u(pte) ((pte)->pg_u) 167#define pmap_pte_v(pte) ((pte)->pg_v) 168#define pmap_pte_set_w(pte, v) ((pte)->pg_w = (v)) 169#define pmap_pte_set_prot(pte, v) ((pte)->pg_prot = (v)) 170 171/* 172 * Given a map and a machine independent protection code, 173 * convert to a vax protection code. 174 */ 175#define pte_prot(m, p) (protection_codes[p]) 176int protection_codes[8]; 177 178struct pmap kernel_pmap_store; 179pmap_t kernel_pmap; 180 181vm_offset_t avail_start; /* PA of first available physical page */ 182vm_offset_t avail_end; /* PA of last available physical page */ 183vm_size_t mem_size; /* memory size in bytes */ 184vm_offset_t virtual_avail; /* VA of first avail page (after kernel bss)*/ 185vm_offset_t virtual_end; /* VA of last avail page (end of kernel AS) */ 186vm_offset_t vm_first_phys; /* PA of first managed page */ 187vm_offset_t vm_last_phys; /* PA just past last managed page */ 188int i386pagesperpage; /* PAGE_SIZE / I386_PAGE_SIZE */ 189boolean_t pmap_initialized = FALSE; /* Has pmap_init completed? */ 190char *pmap_attributes; /* reference and modify bits */ 191 192boolean_t pmap_testbit(); 193void pmap_clear_modify(); 194 195#if BSDVM_COMPAT 196#include "msgbuf.h" 197 198/* 199 * All those kernel PT submaps that BSD is so fond of 200 */ 201struct pte *CMAP1, *CMAP2, *mmap; 202caddr_t CADDR1, CADDR2, vmmap; 203struct pte *msgbufmap; 204struct msgbuf *msgbufp; 205#endif 206 207/* 208 * Bootstrap the system enough to run with virtual memory. 209 * Map the kernel's code and data, and allocate the system page table. 210 * 211 * On the I386 this is called after mapping has already been enabled 212 * and just syncs the pmap module with what has already been done. 213 * [We can't call it easily with mapping off since the kernel is not 214 * mapped with PA == VA, hence we would have to relocate every address 215 * from the linked base (virtual) address 0xFE000000 to the actual 216 * (physical) address starting relative to 0] 217 */ 218struct pte *pmap_pte(); 219 220void 221pmap_bootstrap(firstaddr, loadaddr) 222 vm_offset_t firstaddr; 223 vm_offset_t loadaddr; 224{ 225#if BSDVM_COMPAT 226 vm_offset_t va; 227 struct pte *pte; 228#endif 229 extern vm_offset_t maxmem, physmem; 230extern int IdlePTD; 231 232 avail_start = firstaddr; 233 avail_end = maxmem << PG_SHIFT; 234 235 /* XXX: allow for msgbuf */ 236 avail_end -= i386_round_page(sizeof(struct msgbuf)); 237 238 mem_size = physmem << PG_SHIFT; 239 virtual_avail = (vm_offset_t)atdevbase + 0x100000 - 0xa0000 + 10*NBPG; 240 virtual_end = VM_MAX_KERNEL_ADDRESS; 241 i386pagesperpage = PAGE_SIZE / I386_PAGE_SIZE; 242 243 /* 244 * Initialize protection array. 245 */ 246 i386_protection_init(); 247 248 /* 249 * The kernel's pmap is statically allocated so we don't 250 * have to use pmap_create, which is unlikely to work 251 * correctly at this part of the boot sequence. 252 */ 253 kernel_pmap = &kernel_pmap_store; 254 255#ifdef notdef 256 /* 257 * Create Kernel page directory table and page maps. 258 * [ currently done in locore. i have wild and crazy ideas -wfj ] 259 */ 260 bzero(firstaddr, 4*NBPG); 261 kernel_pmap->pm_pdir = firstaddr + VM_MIN_KERNEL_ADDRESS; 262 kernel_pmap->pm_ptab = firstaddr + VM_MIN_KERNEL_ADDRESS + NBPG; 263 264 firstaddr += NBPG; 265 for (x = i386_btod(VM_MIN_KERNEL_ADDRESS); 266 x < i386_btod(VM_MIN_KERNEL_ADDRESS)+3; x++) { 267 struct pde *pde; 268 pde = kernel_pmap->pm_pdir + x; 269 *(int *)pde = firstaddr + x*NBPG | PG_V | PG_KW; 270 } 271#else 272 kernel_pmap->pm_pdir = (pd_entry_t *)(0xfe000000 + IdlePTD); 273#endif 274 275 276 simple_lock_init(&kernel_pmap->pm_lock); 277 kernel_pmap->pm_count = 1; 278 279#if BSDVM_COMPAT 280 /* 281 * Allocate all the submaps we need 282 */ 283#define SYSMAP(c, p, v, n) \ 284 v = (c)va; va += ((n)*I386_PAGE_SIZE); p = pte; pte += (n); 285 286 va = virtual_avail; 287 pte = pmap_pte(kernel_pmap, va); 288 289 SYSMAP(caddr_t ,CMAP1 ,CADDR1 ,1 ) 290 SYSMAP(caddr_t ,CMAP2 ,CADDR2 ,1 ) 291 SYSMAP(caddr_t ,mmap ,vmmap ,1 ) 292 SYSMAP(struct msgbuf * ,msgbufmap ,msgbufp ,1 ) 293 virtual_avail = va; 294#endif 295 /* 296 * reserve special hunk of memory for use by bus dma as a bounce 297 * buffer (contiguous virtual *and* physical memory). for now, 298 * assume vm does not use memory beneath hole, and we know that 299 * the bootstrap uses top 32k of base memory. -wfj 300 */ 301 { 302 extern vm_offset_t isaphysmem; 303 isaphysmem = va; 304 305 virtual_avail = pmap_map(va, 0xa0000 - 32*1024, 0xa0000, VM_PROT_ALL); 306 } 307 308 *(int *)PTD = 0; 309 load_cr3(rcr3()); 310 311} 312 313/* 314 * Initialize the pmap module. 315 * Called by vm_init, to initialize any structures that the pmap 316 * system needs to map virtual memory. 317 */ 318void 319pmap_init(phys_start, phys_end) 320 vm_offset_t phys_start, phys_end; 321{ 322 vm_offset_t addr, addr2; 323 vm_size_t npg, s; 324 int rv; 325 extern int KPTphys; 326 327#ifdef DEBUG 328 if (pmapdebug & PDB_FOLLOW) 329 printf("pmap_init(%x, %x)\n", phys_start, phys_end); 330#endif 331 /* 332 * Now that kernel map has been allocated, we can mark as 333 * unavailable regions which we have mapped in locore. 334 */ 335 addr = atdevbase; 336 (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0, 337 &addr, (0x100000-0xa0000), FALSE); 338 339 addr = (vm_offset_t) 0xfe000000+KPTphys/* *NBPG */; 340 vm_object_reference(kernel_object); 341 (void) vm_map_find(kernel_map, kernel_object, addr, 342 &addr, 2*NBPG, FALSE); 343 344 /* 345 * Allocate memory for random pmap data structures. Includes the 346 * pv_head_table and pmap_attributes. 347 */ 348 npg = atop(phys_end - phys_start); 349 s = (vm_size_t) (sizeof(struct pv_entry) * npg + npg); 350 s = round_page(s); 351 addr = (vm_offset_t) kmem_alloc(kernel_map, s); 352 pv_table = (pv_entry_t) addr; 353 addr += sizeof(struct pv_entry) * npg; 354 pmap_attributes = (char *) addr; 355#ifdef DEBUG 356 if (pmapdebug & PDB_INIT) 357 printf("pmap_init: %x bytes (%x pgs): tbl %x attr %x\n", 358 s, npg, pv_table, pmap_attributes); 359#endif 360 361 /* 362 * Now it is safe to enable pv_table recording. 363 */ 364 vm_first_phys = phys_start; 365 vm_last_phys = phys_end; 366 pmap_initialized = TRUE; 367} 368 369/* 370 * Used to map a range of physical addresses into kernel 371 * virtual address space. 372 * 373 * For now, VM is already on, we only need to map the 374 * specified memory. 375 */ 376vm_offset_t 377pmap_map(virt, start, end, prot) 378 vm_offset_t virt; 379 vm_offset_t start; 380 vm_offset_t end; 381 int prot; 382{ 383#ifdef DEBUG 384 if (pmapdebug & PDB_FOLLOW) 385 printf("pmap_map(%x, %x, %x, %x)\n", virt, start, end, prot); 386#endif 387 while (start < end) { 388 pmap_enter(kernel_pmap, virt, start, prot, FALSE); 389 virt += PAGE_SIZE; 390 start += PAGE_SIZE; 391 } 392 return(virt); 393} 394 395/* 396 * Create and return a physical map. 397 * 398 * If the size specified for the map 399 * is zero, the map is an actual physical 400 * map, and may be referenced by the 401 * hardware. 402 * 403 * If the size specified is non-zero, 404 * the map will be used in software only, and 405 * is bounded by that size. 406 * 407 * [ just allocate a ptd and mark it uninitialize -- should we track 408 * with a table which process has which ptd? -wfj ] 409 */ 410 411pmap_t 412pmap_create(size) 413 vm_size_t size; 414{ 415 register pmap_t pmap; 416 417#ifdef DEBUG 418 if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) 419 printf("pmap_create(%x)\n", size); 420#endif 421 /* 422 * Software use map does not need a pmap 423 */ 424 if (size) 425 return(NULL); 426 427 /* XXX: is it ok to wait here? */ 428 pmap = (pmap_t) malloc(sizeof *pmap, M_VMPMAP, M_WAITOK); 429#ifdef notifwewait 430 if (pmap == NULL) 431 panic("pmap_create: cannot allocate a pmap"); 432#endif 433 bzero(pmap, sizeof(*pmap)); 434 pmap_pinit(pmap); 435 return (pmap); 436} 437 438/* 439 * Initialize a preallocated and zeroed pmap structure, 440 * such as one in a vmspace structure. 441 */ 442void 443pmap_pinit(pmap) 444 register struct pmap *pmap; 445{ 446 447#ifdef DEBUG 448 if (pmapdebug & (PDB_FOLLOW|PDB_CREATE)) 449 pg("pmap_pinit(%x)\n", pmap); 450#endif 451 452 /* 453 * No need to allocate page table space yet but we do need a 454 * valid page directory table. 455 */ 456 pmap->pm_pdir = (pd_entry_t *) kmem_alloc(kernel_map, NBPG); 457 458 /* wire in kernel global address entries */ 459 bcopy(PTD+KPTDI_FIRST, pmap->pm_pdir+KPTDI_FIRST, 460 (KPTDI_LAST-KPTDI_FIRST+1)*4); 461 462 /* install self-referential address mapping entry */ 463 *(int *)(pmap->pm_pdir+PTDPTDI) = 464 (int)pmap_extract(kernel_pmap, pmap->pm_pdir) | PG_V | PG_KW; 465 466 pmap->pm_count = 1; 467 simple_lock_init(&pmap->pm_lock); 468} 469 470/* 471 * Retire the given physical map from service. 472 * Should only be called if the map contains 473 * no valid mappings. 474 */ 475void 476pmap_destroy(pmap) 477 register pmap_t pmap; 478{ 479 int count; 480 481#ifdef DEBUG 482 if (pmapdebug & PDB_FOLLOW) 483 printf("pmap_destroy(%x)\n", pmap); 484#endif 485 if (pmap == NULL) 486 return; 487 488 simple_lock(&pmap->pm_lock); 489 count = --pmap->pm_count; 490 simple_unlock(&pmap->pm_lock); 491 if (count == 0) { 492 pmap_release(pmap); 493 free((caddr_t)pmap, M_VMPMAP); 494 } 495} 496 497/* 498 * Release any resources held by the given physical map. 499 * Called when a pmap initialized by pmap_pinit is being released. 500 * Should only be called if the map contains no valid mappings. 501 */ 502void 503pmap_release(pmap) 504 register struct pmap *pmap; 505{ 506 507#ifdef DEBUG 508 if (pmapdebug & PDB_FOLLOW) 509 pg("pmap_release(%x)\n", pmap); 510#endif 511#ifdef notdef /* DIAGNOSTIC */ 512 /* count would be 0 from pmap_destroy... */ 513 simple_lock(&pmap->pm_lock); 514 if (pmap->pm_count != 1) 515 panic("pmap_release count"); 516#endif 517 kmem_free(kernel_map, (vm_offset_t)pmap->pm_pdir, NBPG); 518} 519 520/* 521 * Add a reference to the specified pmap. 522 */ 523void 524pmap_reference(pmap) 525 pmap_t pmap; 526{ 527#ifdef DEBUG 528 if (pmapdebug & PDB_FOLLOW) 529 printf("pmap_reference(%x)", pmap); 530#endif 531 if (pmap != NULL) { 532 simple_lock(&pmap->pm_lock); 533 pmap->pm_count++; 534 simple_unlock(&pmap->pm_lock); 535 } 536} 537 538/* 539 * Remove the given range of addresses from the specified map. 540 * 541 * It is assumed that the start and end are properly 542 * rounded to the page size. 543 */ 544void 545pmap_remove(pmap, sva, eva) 546 struct pmap *pmap; 547 register vm_offset_t sva; 548 register vm_offset_t eva; 549{ 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 printf("ptdi %x\n", pmap->pm_pdir[PTDPTDI]); 905 panic("Page Table Directory Invalid (ptdi)"); 906 } 907 908 pte = pmap_pte(pmap, va); 909 opa = pmap_pte_pa(pte); 910#ifdef DEBUG 911 if (pmapdebug & PDB_ENTER) 912 printf("enter: pte %x, *pte %x ", pte, *(int *)pte); 913#endif 914 915 /* 916 * Mapping has not changed, must be protection or wiring change. 917 */ 918 if (opa == pa) { 919#ifdef DEBUG 920 enter_stats.pwchange++; 921#endif 922 /* 923 * Wiring change, just update stats. 924 * We don't worry about wiring PT pages as they remain 925 * resident as long as there are valid mappings in them. 926 * Hence, if a user page is wired, the PT page will be also. 927 */ 928 if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { 929#ifdef DEBUG 930 if (pmapdebug & PDB_ENTER) 931 pg("enter: wiring change -> %x ", wired); 932#endif 933 if (wired) 934 pmap->pm_stats.wired_count++; 935 else 936 pmap->pm_stats.wired_count--; 937#ifdef DEBUG 938 enter_stats.wchange++; 939#endif 940 } 941 goto validate; 942 } 943 944 /* 945 * Mapping has changed, invalidate old range and fall through to 946 * handle validating new mapping. 947 */ 948 if (opa) { 949#ifdef DEBUG 950 if (pmapdebug & PDB_ENTER) 951 printf("enter: removing old mapping %x pa %x ", va, opa); 952#endif 953 pmap_remove(pmap, va, va + PAGE_SIZE); 954#ifdef DEBUG 955 enter_stats.mchange++; 956#endif 957 } 958 959 /* 960 * Enter on the PV list if part of our managed memory 961 * Note that we raise IPL while manipulating pv_table 962 * since pmap_enter can be called at interrupt time. 963 */ 964 if (pa >= vm_first_phys && pa < vm_last_phys) { 965 register pv_entry_t pv, npv; 966 int s; 967 968#ifdef DEBUG 969 enter_stats.managed++; 970#endif 971 pv = pa_to_pvh(pa); 972 s = splimp(); 973#ifdef DEBUG 974 if (pmapdebug & PDB_ENTER) 975 printf("enter: pv at %x: %x/%x/%x ", 976 pv, pv->pv_va, pv->pv_pmap, pv->pv_next); 977#endif 978 /* 979 * No entries yet, use header as the first entry 980 */ 981 if (pv->pv_pmap == NULL) { 982#ifdef DEBUG 983 enter_stats.firstpv++; 984#endif 985 pv->pv_va = va; 986 pv->pv_pmap = pmap; 987 pv->pv_next = NULL; 988 pv->pv_flags = 0; 989 } 990 /* 991 * There is at least one other VA mapping this page. 992 * Place this entry after the header. 993 */ 994 else { 995 /*printf("second time: ");*/ 996#ifdef DEBUG 997 for (npv = pv; npv; npv = npv->pv_next) 998 if (pmap == npv->pv_pmap && va == npv->pv_va) 999 panic("pmap_enter: already in pv_tab"); 1000#endif 1001 npv = (pv_entry_t) 1002 malloc(sizeof *npv, M_VMPVENT, M_NOWAIT); 1003 npv->pv_va = va; 1004 npv->pv_pmap = pmap; 1005 npv->pv_next = pv->pv_next; 1006 pv->pv_next = npv; 1007#ifdef DEBUG 1008 if (!npv->pv_next) 1009 enter_stats.secondpv++; 1010#endif 1011 } 1012 splx(s); 1013 } 1014 /* 1015 * Assumption: if it is not part of our managed memory 1016 * then it must be device memory which may be volitile. 1017 */ 1018 if (pmap_initialized) { 1019 checkpv = cacheable = FALSE; 1020#ifdef DEBUG 1021 enter_stats.unmanaged++; 1022#endif 1023 } 1024 1025 /* 1026 * Increment counters 1027 */ 1028 pmap->pm_stats.resident_count++; 1029 if (wired) 1030 pmap->pm_stats.wired_count++; 1031 1032validate: 1033 /* 1034 * Now validate mapping with desired protection/wiring. 1035 * Assume uniform modified and referenced status for all 1036 * I386 pages in a MACH page. 1037 */ 1038 npte = (pa & PG_FRAME) | pte_prot(pmap, prot) | PG_V; 1039 npte |= (*(int *)pte & (PG_M|PG_U)); 1040 if (wired) 1041 npte |= PG_W; 1042 if(va < UPT_MIN_ADDRESS) 1043 npte |= PG_u; 1044 else if(va < UPT_MAX_ADDRESS) 1045 npte |= PG_u | PG_RW; 1046#ifdef DEBUG 1047 if (pmapdebug & PDB_ENTER) 1048 printf("enter: new pte value %x ", npte); 1049#endif 1050 ix = 0; 1051 do { 1052 *(int *)pte++ = npte; 1053 /*TBIS(va);*/ 1054 npte += I386_PAGE_SIZE; 1055 va += I386_PAGE_SIZE; 1056 } while (++ix != i386pagesperpage); 1057 pte--; 1058#ifdef DEBUGx 1059cache, tlb flushes 1060#endif 1061/*pads(pmap);*/ 1062 /*load_cr3(((struct pcb *)curproc->p_addr)->pcb_ptd);*/ 1063 tlbflush(); 1064} 1065 1066/* 1067 * pmap_page_protect: 1068 * 1069 * Lower the permission for all mappings to a given page. 1070 */ 1071void 1072pmap_page_protect(phys, prot) 1073 vm_offset_t phys; 1074 vm_prot_t prot; 1075{ 1076 switch (prot) { 1077 case VM_PROT_READ: 1078 case VM_PROT_READ|VM_PROT_EXECUTE: 1079 pmap_copy_on_write(phys); 1080 break; 1081 case VM_PROT_ALL: 1082 break; 1083 default: 1084 pmap_remove_all(phys); 1085 break; 1086 } 1087} 1088 1089/* 1090 * Routine: pmap_change_wiring 1091 * Function: Change the wiring attribute for a map/virtual-address 1092 * pair. 1093 * In/out conditions: 1094 * The mapping must already exist in the pmap. 1095 */ 1096void 1097pmap_change_wiring(pmap, va, wired) 1098 register pmap_t pmap; 1099 vm_offset_t va; 1100 boolean_t wired; 1101{ 1102 register pt_entry_t *pte; 1103 register int ix; 1104 1105#ifdef DEBUG 1106 if (pmapdebug & PDB_FOLLOW) 1107 printf("pmap_change_wiring(%x, %x, %x)", pmap, va, wired); 1108#endif 1109 if (pmap == NULL) 1110 return; 1111 1112 pte = pmap_pte(pmap, va); 1113#ifdef DEBUG 1114 /* 1115 * Page table page is not allocated. 1116 * Should this ever happen? Ignore it for now, 1117 * we don't want to force allocation of unnecessary PTE pages. 1118 */ 1119 if (!pmap_pde_v(pmap_pde(pmap, va))) { 1120 if (pmapdebug & PDB_PARANOIA) 1121 pg("pmap_change_wiring: invalid PDE for %x ", va); 1122 return; 1123 } 1124 /* 1125 * Page not valid. Should this ever happen? 1126 * Just continue and change wiring anyway. 1127 */ 1128 if (!pmap_pte_v(pte)) { 1129 if (pmapdebug & PDB_PARANOIA) 1130 pg("pmap_change_wiring: invalid PTE for %x ", va); 1131 } 1132#endif 1133 if (wired && !pmap_pte_w(pte) || !wired && pmap_pte_w(pte)) { 1134 if (wired) 1135 pmap->pm_stats.wired_count++; 1136 else 1137 pmap->pm_stats.wired_count--; 1138 } 1139 /* 1140 * Wiring is not a hardware characteristic so there is no need 1141 * to invalidate TLB. 1142 */ 1143 ix = 0; 1144 do { 1145 pmap_pte_set_w(pte++, wired); 1146 } while (++ix != i386pagesperpage); 1147} 1148 1149/* 1150 * Routine: pmap_pte 1151 * Function: 1152 * Extract the page table entry associated 1153 * with the given map/virtual_address pair. 1154 * [ what about induced faults -wfj] 1155 */ 1156 1157struct pte *pmap_pte(pmap, va) 1158 register pmap_t pmap; 1159 vm_offset_t va; 1160{ 1161 1162#ifdef DEBUGx 1163 if (pmapdebug & PDB_FOLLOW) 1164 printf("pmap_pte(%x, %x) ->\n", pmap, va); 1165#endif 1166 if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { 1167 1168 /* are we current address space or kernel? */ 1169 if (pmap->pm_pdir[PTDPTDI].pd_pfnum == PTDpde.pd_pfnum 1170 || pmap == kernel_pmap) 1171 return ((struct pte *) vtopte(va)); 1172 1173 /* otherwise, we are alternate address space */ 1174 else { 1175 if (pmap->pm_pdir[PTDPTDI].pd_pfnum 1176 != APTDpde.pd_pfnum) { 1177 APTDpde = pmap->pm_pdir[PTDPTDI]; 1178 tlbflush(); 1179 } 1180 return((struct pte *) avtopte(va)); 1181 } 1182 } 1183 return(0); 1184} 1185 1186/* 1187 * Routine: pmap_extract 1188 * Function: 1189 * Extract the physical page address associated 1190 * with the given map/virtual_address pair. 1191 */ 1192 1193vm_offset_t 1194pmap_extract(pmap, va) 1195 register pmap_t pmap; 1196 vm_offset_t va; 1197{ 1198 register vm_offset_t pa; 1199 1200#ifdef DEBUGx 1201 if (pmapdebug & PDB_FOLLOW) 1202 pg("pmap_extract(%x, %x) -> ", pmap, va); 1203#endif 1204 pa = 0; 1205 if (pmap && pmap_pde_v(pmap_pde(pmap, va))) { 1206 pa = *(int *) pmap_pte(pmap, va); 1207 } 1208 if (pa) 1209 pa = (pa & PG_FRAME) | (va & ~PG_FRAME); 1210#ifdef DEBUGx 1211 if (pmapdebug & PDB_FOLLOW) 1212 printf("%x\n", pa); 1213#endif 1214 return(pa); 1215} 1216 1217/* 1218 * Copy the range specified by src_addr/len 1219 * from the source map to the range dst_addr/len 1220 * in the destination map. 1221 * 1222 * This routine is only advisory and need not do anything. 1223 */ 1224void pmap_copy(dst_pmap, src_pmap, dst_addr, len, src_addr) 1225 pmap_t dst_pmap; 1226 pmap_t src_pmap; 1227 vm_offset_t dst_addr; 1228 vm_size_t len; 1229 vm_offset_t src_addr; 1230{ 1231#ifdef DEBUG 1232 if (pmapdebug & PDB_FOLLOW) 1233 printf("pmap_copy(%x, %x, %x, %x, %x)", 1234 dst_pmap, src_pmap, dst_addr, len, src_addr); 1235#endif 1236} 1237 1238/* 1239 * Require that all active physical maps contain no 1240 * incorrect entries NOW. [This update includes 1241 * forcing updates of any address map caching.] 1242 * 1243 * Generally used to insure that a thread about 1244 * to run will see a semantically correct world. 1245 */ 1246void pmap_update() 1247{ 1248#ifdef DEBUG 1249 if (pmapdebug & PDB_FOLLOW) 1250 printf("pmap_update()"); 1251#endif 1252 tlbflush(); 1253} 1254 1255/* 1256 * Routine: pmap_collect 1257 * Function: 1258 * Garbage collects the physical map system for 1259 * pages which are no longer used. 1260 * Success need not be guaranteed -- that is, there 1261 * may well be pages which are not referenced, but 1262 * others may be collected. 1263 * Usage: 1264 * Called by the pageout daemon when pages are scarce. 1265 * [ needs to be written -wfj ] 1266 */ 1267void 1268pmap_collect(pmap) 1269 pmap_t pmap; 1270{ 1271 register vm_offset_t pa; 1272 register pv_entry_t pv; 1273 register int *pte; 1274 vm_offset_t kpa; 1275 int s; 1276 1277#ifdef DEBUG 1278 int *pde; 1279 int opmapdebug; 1280 printf("pmap_collect(%x) ", pmap); 1281#endif 1282 if (pmap != kernel_pmap) 1283 return; 1284 1285} 1286 1287/* [ macro again?, should I force kstack into user map here? -wfj ] */ 1288void 1289pmap_activate(pmap, pcbp) 1290 register pmap_t pmap; 1291 struct pcb *pcbp; 1292{ 1293int x; 1294#ifdef DEBUG 1295 if (pmapdebug & (PDB_FOLLOW|PDB_PDRTAB)) 1296 pg("pmap_activate(%x, %x) ", pmap, pcbp); 1297#endif 1298 PMAP_ACTIVATE(pmap, pcbp); 1299/*printf("pde "); 1300for(x=0x3f6; x < 0x3fA; x++) 1301 printf("%x ", pmap->pm_pdir[x]);*/ 1302/*pads(pmap);*/ 1303/*pg(" pcb_cr3 %x", pcbp->pcb_cr3);*/ 1304} 1305 1306/* 1307 * Routine: pmap_kernel 1308 * Function: 1309 * Returns the physical map handle for the kernel. 1310 */ 1311pmap_t 1312pmap_kernel() 1313{ 1314 return (kernel_pmap); 1315} 1316 1317/* 1318 * pmap_zero_page zeros the specified (machine independent) 1319 * page by mapping the page into virtual memory and using 1320 * bzero to clear its contents, one machine dependent page 1321 * at a time. 1322 */ 1323pmap_zero_page(phys) 1324 register vm_offset_t phys; 1325{ 1326 register int ix; 1327 1328#ifdef DEBUG 1329 if (pmapdebug & PDB_FOLLOW) 1330 printf("pmap_zero_page(%x)", phys); 1331#endif 1332 phys >>= PG_SHIFT; 1333 ix = 0; 1334 do { 1335 clearseg(phys++); 1336 } while (++ix != i386pagesperpage); 1337} 1338 1339/* 1340 * pmap_copy_page copies the specified (machine independent) 1341 * page by mapping the page into virtual memory and using 1342 * bcopy to copy the page, one machine dependent page at a 1343 * time. 1344 */ 1345pmap_copy_page(src, dst) 1346 register vm_offset_t src, dst; 1347{ 1348 register int ix; 1349 1350#ifdef DEBUG 1351 if (pmapdebug & PDB_FOLLOW) 1352 printf("pmap_copy_page(%x, %x)", src, dst); 1353#endif 1354 src >>= PG_SHIFT; 1355 dst >>= PG_SHIFT; 1356 ix = 0; 1357 do { 1358 physcopyseg(src++, dst++); 1359 } while (++ix != i386pagesperpage); 1360} 1361 1362 1363/* 1364 * Routine: pmap_pageable 1365 * Function: 1366 * Make the specified pages (by pmap, offset) 1367 * pageable (or not) as requested. 1368 * 1369 * A page which is not pageable may not take 1370 * a fault; therefore, its page table entry 1371 * must remain valid for the duration. 1372 * 1373 * This routine is merely advisory; pmap_enter 1374 * will specify that these pages are to be wired 1375 * down (or not) as appropriate. 1376 */ 1377pmap_pageable(pmap, sva, eva, pageable) 1378 pmap_t pmap; 1379 vm_offset_t sva, eva; 1380 boolean_t pageable; 1381{ 1382#ifdef DEBUG 1383 if (pmapdebug & PDB_FOLLOW) 1384 printf("pmap_pageable(%x, %x, %x, %x)", 1385 pmap, sva, eva, pageable); 1386#endif 1387 /* 1388 * If we are making a PT page pageable then all valid 1389 * mappings must be gone from that page. Hence it should 1390 * be all zeros and there is no need to clean it. 1391 * Assumptions: 1392 * - we are called with only one page at a time 1393 * - PT pages have only one pv_table entry 1394 */ 1395 if (pmap == kernel_pmap && pageable && sva + PAGE_SIZE == eva) { 1396 register pv_entry_t pv; 1397 register vm_offset_t pa; 1398 1399#ifdef DEBUG 1400 if ((pmapdebug & (PDB_FOLLOW|PDB_PTPAGE)) == PDB_PTPAGE) 1401 printf("pmap_pageable(%x, %x, %x, %x)", 1402 pmap, sva, eva, pageable); 1403#endif 1404 /*if (!pmap_pde_v(pmap_pde(pmap, sva))) 1405 return;*/ 1406 if(pmap_pte(pmap, sva) == 0) 1407 return; 1408 pa = pmap_pte_pa(pmap_pte(pmap, sva)); 1409 if (pa < vm_first_phys || pa >= vm_last_phys) 1410 return; 1411 pv = pa_to_pvh(pa); 1412 /*if (!ispt(pv->pv_va)) 1413 return;*/ 1414#ifdef DEBUG 1415 if (pv->pv_va != sva || pv->pv_next) { 1416 pg("pmap_pageable: bad PT page va %x next %x\n", 1417 pv->pv_va, pv->pv_next); 1418 return; 1419 } 1420#endif 1421 /* 1422 * Mark it unmodified to avoid pageout 1423 */ 1424 pmap_clear_modify(pa); 1425#ifdef needsomethinglikethis 1426 if (pmapdebug & PDB_PTPAGE) 1427 pg("pmap_pageable: PT page %x(%x) unmodified\n", 1428 sva, *(int *)pmap_pte(pmap, sva)); 1429 if (pmapdebug & PDB_WIRING) 1430 pmap_check_wiring("pageable", sva); 1431#endif 1432 } 1433} 1434 1435/* 1436 * Clear the modify bits on the specified physical page. 1437 */ 1438 1439void 1440pmap_clear_modify(pa) 1441 vm_offset_t pa; 1442{ 1443#ifdef DEBUG 1444 if (pmapdebug & PDB_FOLLOW) 1445 printf("pmap_clear_modify(%x)", pa); 1446#endif 1447 pmap_changebit(pa, PG_M, FALSE); 1448} 1449 1450/* 1451 * pmap_clear_reference: 1452 * 1453 * Clear the reference bit on the specified physical page. 1454 */ 1455 1456void pmap_clear_reference(pa) 1457 vm_offset_t pa; 1458{ 1459#ifdef DEBUG 1460 if (pmapdebug & PDB_FOLLOW) 1461 printf("pmap_clear_reference(%x)", pa); 1462#endif 1463 pmap_changebit(pa, PG_U, FALSE); 1464} 1465 1466/* 1467 * pmap_is_referenced: 1468 * 1469 * Return whether or not the specified physical page is referenced 1470 * by any physical maps. 1471 */ 1472 1473boolean_t 1474pmap_is_referenced(pa) 1475 vm_offset_t pa; 1476{ 1477#ifdef DEBUG 1478 if (pmapdebug & PDB_FOLLOW) { 1479 boolean_t rv = pmap_testbit(pa, PG_U); 1480 printf("pmap_is_referenced(%x) -> %c", pa, "FT"[rv]); 1481 return(rv); 1482 } 1483#endif 1484 return(pmap_testbit(pa, PG_U)); 1485} 1486 1487/* 1488 * pmap_is_modified: 1489 * 1490 * Return whether or not the specified physical page is modified 1491 * by any physical maps. 1492 */ 1493 1494boolean_t 1495pmap_is_modified(pa) 1496 vm_offset_t pa; 1497{ 1498#ifdef DEBUG 1499 if (pmapdebug & PDB_FOLLOW) { 1500 boolean_t rv = pmap_testbit(pa, PG_M); 1501 printf("pmap_is_modified(%x) -> %c", pa, "FT"[rv]); 1502 return(rv); 1503 } 1504#endif 1505 return(pmap_testbit(pa, PG_M)); 1506} 1507 1508vm_offset_t 1509pmap_phys_address(ppn) 1510 int ppn; 1511{ 1512 return(i386_ptob(ppn)); 1513} 1514 1515/* 1516 * Miscellaneous support routines follow 1517 */ 1518 1519i386_protection_init() 1520{ 1521 register int *kp, prot; 1522 1523 kp = protection_codes; 1524 for (prot = 0; prot < 8; prot++) { 1525 switch (prot) { 1526 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: 1527 *kp++ = 0; 1528 break; 1529 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: 1530 case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: 1531 case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: 1532 *kp++ = PG_RO; 1533 break; 1534 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: 1535 case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: 1536 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: 1537 case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: 1538 *kp++ = PG_RW; 1539 break; 1540 } 1541 } 1542} 1543 1544boolean_t 1545pmap_testbit(pa, bit) 1546 register vm_offset_t pa; 1547 int bit; 1548{ 1549 register pv_entry_t pv; 1550 register int *pte, ix; 1551 int s; 1552 1553 if (pa < vm_first_phys || pa >= vm_last_phys) 1554 return(FALSE); 1555 1556 pv = pa_to_pvh(pa); 1557 s = splimp(); 1558 /* 1559 * Check saved info first 1560 */ 1561 if (pmap_attributes[pa_index(pa)] & bit) { 1562 splx(s); 1563 return(TRUE); 1564 } 1565 /* 1566 * Not found, check current mappings returning 1567 * immediately if found. 1568 */ 1569 if (pv->pv_pmap != NULL) { 1570 for (; pv; pv = pv->pv_next) { 1571 pte = (int *) pmap_pte(pv->pv_pmap, pv->pv_va); 1572 ix = 0; 1573 do { 1574 if (*pte++ & bit) { 1575 splx(s); 1576 return(TRUE); 1577 } 1578 } while (++ix != i386pagesperpage); 1579 } 1580 } 1581 splx(s); 1582 return(FALSE); 1583} 1584 1585pmap_changebit(pa, bit, setem) 1586 register vm_offset_t pa; 1587 int bit; 1588 boolean_t setem; 1589{ 1590 register pv_entry_t pv; 1591 register int *pte, npte, ix; 1592 vm_offset_t va; 1593 int s; 1594 boolean_t firstpage = TRUE; 1595 1596#ifdef DEBUG 1597 if (pmapdebug & PDB_BITS) 1598 printf("pmap_changebit(%x, %x, %s)", 1599 pa, bit, setem ? "set" : "clear"); 1600#endif 1601 if (pa < vm_first_phys || pa >= vm_last_phys) 1602 return; 1603 1604 pv = pa_to_pvh(pa); 1605 s = splimp(); 1606 /* 1607 * Clear saved attributes (modify, reference) 1608 */ 1609 if (!setem) 1610 pmap_attributes[pa_index(pa)] &= ~bit; 1611 /* 1612 * Loop over all current mappings setting/clearing as appropos 1613 * If setting RO do we need to clear the VAC? 1614 */ 1615 if (pv->pv_pmap != NULL) { 1616#ifdef DEBUG 1617 int toflush = 0; 1618#endif 1619 for (; pv; pv = pv->pv_next) { 1620#ifdef DEBUG 1621 toflush |= (pv->pv_pmap == kernel_pmap) ? 2 : 1; 1622#endif 1623 va = pv->pv_va; 1624 1625 /* 1626 * XXX don't write protect pager mappings 1627 */ 1628 if (bit == PG_RO) { 1629 extern vm_offset_t pager_sva, pager_eva; 1630 1631 if (va >= pager_sva && va < pager_eva) 1632 continue; 1633 } 1634 1635 pte = (int *) pmap_pte(pv->pv_pmap, va); 1636 ix = 0; 1637 do { 1638 if (setem) 1639 npte = *pte | bit; 1640 else 1641 npte = *pte & ~bit; 1642 if (*pte != npte) { 1643 *pte = npte; 1644 /*TBIS(va);*/ 1645 } 1646 va += I386_PAGE_SIZE; 1647 pte++; 1648 } while (++ix != i386pagesperpage); 1649 1650 if (curproc && pv->pv_pmap == &curproc->p_vmspace->vm_pmap) 1651 pmap_activate(pv->pv_pmap, (struct pcb *)curproc->p_addr); 1652 } 1653#ifdef somethinglikethis 1654 if (setem && bit == PG_RO && (pmapvacflush & PVF_PROTECT)) { 1655 if ((pmapvacflush & PVF_TOTAL) || toflush == 3) 1656 DCIA(); 1657 else if (toflush == 2) 1658 DCIS(); 1659 else 1660 DCIU(); 1661 } 1662#endif 1663 } 1664 splx(s); 1665} 1666 1667#ifdef DEBUG 1668pmap_pvdump(pa) 1669 vm_offset_t pa; 1670{ 1671 register pv_entry_t pv; 1672 1673 printf("pa %x", pa); 1674 for (pv = pa_to_pvh(pa); pv; pv = pv->pv_next) { 1675 printf(" -> pmap %x, va %x, flags %x", 1676 pv->pv_pmap, pv->pv_va, pv->pv_flags); 1677 pads(pv->pv_pmap); 1678 } 1679 printf(" "); 1680} 1681 1682#ifdef notyet 1683pmap_check_wiring(str, va) 1684 char *str; 1685 vm_offset_t va; 1686{ 1687 vm_map_entry_t entry; 1688 register int count, *pte; 1689 1690 va = trunc_page(va); 1691 if (!pmap_pde_v(pmap_pde(kernel_pmap, va)) || 1692 !pmap_pte_v(pmap_pte(kernel_pmap, va))) 1693 return; 1694 1695 if (!vm_map_lookup_entry(pt_map, va, &entry)) { 1696 pg("wired_check: entry for %x not found\n", va); 1697 return; 1698 } 1699 count = 0; 1700 for (pte = (int *)va; pte < (int *)(va+PAGE_SIZE); pte++) 1701 if (*pte) 1702 count++; 1703 if (entry->wired_count != count) 1704 pg("*%s*: %x: w%d/a%d\n", 1705 str, va, entry->wired_count, count); 1706} 1707#endif 1708 1709/* print address space of pmap*/ 1710pads(pm) pmap_t pm; { 1711 unsigned va, i, j; 1712 struct pte *ptep; 1713 1714 if(pm == kernel_pmap) return; 1715 for (i = 0; i < 1024; i++) 1716 if(pm->pm_pdir[i].pd_v) 1717 for (j = 0; j < 1024 ; j++) { 1718 va = (i<<22)+(j<<12); 1719 if (pm == kernel_pmap && va < 0xfe000000) 1720 continue; 1721 if (pm != kernel_pmap && va > UPT_MAX_ADDRESS) 1722 continue; 1723 ptep = pmap_pte(pm, va); 1724 if(pmap_pte_v(ptep)) 1725 printf("%x:%x ", va, *(int *)ptep); 1726 } ; 1727 1728} 1729#endif 1730