|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1992 NeXT Computer, Inc. ! 27: * ! 28: * Intel386 Family: Hardware page mapping. ! 29: * ! 30: * HISTORY ! 31: * ! 32: * 9 April 1992 ? at NeXT ! 33: * Created. ! 34: */ ! 35: ! 36: #import <cpus.h> ! 37: ! 38: #import <mach/mach_types.h> ! 39: ! 40: #import <vm/vm_kern.h> ! 41: #import <vm/vm_page.h> ! 42: ! 43: #import <machdep/i386/pmap_private.h> ! 44: #import <machdep/i386/pmap_inline.h> ! 45: #import <machdep/i386/cpu_inline.h> ! 46: ! 47: /* ! 48: * Setup structures to map from mach vm_prot_t ! 49: * to machine protections. ! 50: */ ! 51: unsigned int user_prot_codes[8]; ! 52: unsigned int kernel_prot_codes[8]; ! 53: #define kernel_pmap_prot(x) (kernel_prot_codes[(x)]) ! 54: ! 55: static ! 56: void ! 57: pte_prot_init( ! 58: void ! 59: ) ! 60: { ! 61: unsigned int *kp, *up; ! 62: int prot; ! 63: ! 64: kp = kernel_prot_codes; ! 65: up = user_prot_codes; ! 66: for (prot = 0; prot < 8; prot++) { ! 67: switch ((vm_prot_t)prot) { ! 68: case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_NONE: ! 69: *kp++ = 0; ! 70: *up++ = 0; ! 71: break; ! 72: case VM_PROT_READ | VM_PROT_NONE | VM_PROT_NONE: ! 73: case VM_PROT_READ | VM_PROT_NONE | VM_PROT_EXECUTE: ! 74: case VM_PROT_NONE | VM_PROT_NONE | VM_PROT_EXECUTE: ! 75: *kp++ = PT_PROT_KR; ! 76: *up++ = PT_PROT_UR; ! 77: break; ! 78: case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_NONE: ! 79: case VM_PROT_NONE | VM_PROT_WRITE | VM_PROT_EXECUTE: ! 80: case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_NONE: ! 81: case VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE: ! 82: *kp++ = PT_PROT_KRW; ! 83: *up++ = PT_PROT_URW; ! 84: break; ! 85: } ! 86: } ! 87: } ! 88: ! 89: /* ! 90: * Given a map and a machine independent protection code, ! 91: * set the protection code in the given pte ! 92: */ ! 93: static inline ! 94: void ! 95: pte_prot( ! 96: pmap_t pmap, ! 97: vm_prot_t prot, ! 98: int valid, /* valid bit for pte */ ! 99: pt_entry_t * pte /* IN/OUT */ ! 100: ) ! 101: { ! 102: if (pmap == kernel_pmap) ! 103: pte->prot = kernel_prot_codes[prot]; ! 104: else ! 105: pte->prot = user_prot_codes[prot]; ! 106: ! 107: pte->valid = valid; ! 108: } ! 109: ! 110: /* ! 111: * Return a ptr to the page ! 112: * table entry at the indicated ! 113: * offset in the pmap. Return ! 114: * PT_ENTRY_NULL if the page table ! 115: * does not exist. ! 116: */ ! 117: inline ! 118: pt_entry_t * ! 119: pmap_pt_entry( ! 120: pmap_t pmap, ! 121: vm_offset_t va ! 122: ) ! 123: { ! 124: pd_entry_t * pde; ! 125: ! 126: pde = pd_to_pd_entry(pmap->root, va); ! 127: ! 128: if (!pde->valid) ! 129: return (PT_ENTRY_NULL); ! 130: ! 131: return (pd_entry_to_pt_entry(pde, va)); ! 132: } ! 133: ! 134: /* ! 135: * Return a ptr to the page ! 136: * directory entry at the indicated ! 137: * offset in the pmap. ! 138: */ ! 139: inline ! 140: pd_entry_t * ! 141: pmap_pd_entry( ! 142: pmap_t pmap, ! 143: vm_offset_t va ! 144: ) ! 145: { ! 146: return (pd_to_pd_entry(pmap->root, va)); ! 147: } ! 148: ! 149: /* ! 150: * Return the physical address ! 151: * corresponding to the indicated ! 152: * offset in the pmap. Only used ! 153: * internally since no locking is ! 154: * done. ! 155: */ ! 156: static inline ! 157: unsigned int ! 158: pmap_phys( ! 159: pmap_t pmap, ! 160: vm_offset_t va ! 161: ) ! 162: { ! 163: pt_entry_t *pte; ! 164: ! 165: pte = pmap_pt_entry(pmap, va); ! 166: if (pte == PT_ENTRY_NULL || !pte->valid) ! 167: return (0); ! 168: ! 169: return (pfn_to_phys(pte->pfn) + page_offset(va)); ! 170: } ! 171: ! 172: static inline ! 173: void ! 174: pmap_update_tlbs( ! 175: pmap_t pmap, ! 176: vm_offset_t start, ! 177: vm_offset_t end ! 178: ) ! 179: { ! 180: if (pmap == kernel_pmap || pmap->cpus_using) { ! 181: tlb_stat.total++; ! 182: if (end - start > PAGE_SIZE) ! 183: flush_tlb(); ! 184: else { ! 185: for (; start < end; start += I386_PGBYTES) ! 186: invlpg(start, pmap == kernel_pmap); ! 187: ! 188: tlb_stat.single++; ! 189: } ! 190: } ! 191: } ! 192: ! 193: /* ! 194: * Allocate a new page table ! 195: * in the kernel pmap at the ! 196: * given offset when one does ! 197: * not already exist. ! 198: */ ! 199: static ! 200: void ! 201: pmap_kernel_pt_alloc( ! 202: vm_offset_t addr ! 203: ) ! 204: { ! 205: pd_entry_t template, *pde; ! 206: vm_offset_t pt; ! 207: unsigned int phys; ! 208: int i; ! 209: ! 210: pde = pmap_pd_entry(kernel_pmap, trunc_section(addr)); ! 211: if (pde->valid) ! 212: panic("pmap_kernel_pt_alloc"); ! 213: ! 214: if (!pmap_initialized) { ! 215: pt = alloc_pages(PAGE_SIZE); ! 216: if (!pt) ! 217: panic("pmap_kernel_pt_alloc 2"); ! 218: ! 219: bzero(pt, PAGE_SIZE); ! 220: ! 221: phys = pt - VM_MIN_KERNEL_ADDRESS; ! 222: } ! 223: else { ! 224: if (kmem_alloc_wired(kernel_map, &pt, PAGE_SIZE) != KERN_SUCCESS) ! 225: panic("pmap_kernel_pt_alloc 3"); ! 226: ! 227: phys = pmap_phys(kernel_pmap, pt); ! 228: } ! 229: ! 230: template = (pd_entry_t) { 0 }; ! 231: template.valid = 1; ! 232: template.prot = PT_PROT_KRW; ! 233: template.pfn = phys_to_pfn(phys); ! 234: ! 235: for (i = ptes_per_vm_page; i-- > 0; pde++) { ! 236: *pde = template; ! 237: template.pfn++; ! 238: } ! 239: } ! 240: ! 241: /* ! 242: * Map memory at initialization. The physical addresses being ! 243: * mapped are not managed and are never unmapped. ! 244: */ ! 245: vm_offset_t ! 246: pmap_map( ! 247: vm_offset_t virt, ! 248: vm_offset_t start, ! 249: vm_offset_t end, ! 250: vm_prot_t prot ! 251: ) ! 252: { ! 253: pt_entry_t template, *pte; ! 254: ! 255: template = (pt_entry_t) { 0 }; ! 256: ! 257: if (prot != VM_PROT_NONE) { ! 258: template.valid = 1; ! 259: template.prot = kernel_pmap_prot(prot); ! 260: template.pfn = phys_to_pfn(start); ! 261: } ! 262: ! 263: while (start < end) { ! 264: pte = pmap_pt_entry(kernel_pmap, virt); ! 265: if (pte == PT_ENTRY_NULL) { ! 266: pmap_kernel_pt_alloc(virt); ! 267: pte = pmap_pt_entry(kernel_pmap, virt); ! 268: } ! 269: ! 270: /* ! 271: * Is this necessary ?? ! 272: */ ! 273: if ( start >= (640 * 1024) && ! 274: start < (1024 * 1024)) ! 275: template.cachewrt = 1; ! 276: else ! 277: template.cachewrt = 0; ! 278: ! 279: *pte = template; ! 280: if (prot != VM_PROT_NONE) ! 281: template.pfn++; ! 282: ! 283: virt += I386_PGBYTES; ! 284: start += I386_PGBYTES; ! 285: } ! 286: ! 287: flush_tlb(); ! 288: ! 289: return (virt); ! 290: } ! 291: ! 292: static ! 293: void ! 294: pmap_enable_pg( ! 295: vm_offset_t kernel_pd ! 296: ) ! 297: { ! 298: pd_entry_t *kpde, *end_kpde; ! 299: pd_entry_t *pde; ! 300: cr0_t _cr0 = cr0(); ! 301: ! 302: /* ! 303: * Double map the kernel memory ! 304: * into the low end of the kernel ! 305: * pmap linear space. This is ! 306: * necessary in order to enable ! 307: * paging. ! 308: */ ! 309: pde = (pd_entry_t *)kernel_pd; ! 310: ! 311: kpde = ! 312: pmap_pd_entry(kernel_pmap, ! 313: VM_MIN_KERNEL_ADDRESS); ! 314: end_kpde = ! 315: pmap_pd_entry(kernel_pmap, ! 316: VM_MAX_KERNEL_ADDRESS); ! 317: ! 318: while (kpde < end_kpde) ! 319: *pde++ = *kpde++; ! 320: ! 321: /* ! 322: * Use the kernel pmap ! 323: * as our initial translation ! 324: * tree. ! 325: */ ! 326: kernel_pmap->cr3 = ! 327: pmap_phys(kernel_pmap, kernel_pd); ! 328: ! 329: set_cr3(kernel_pmap->cr3); ! 330: ! 331: /* ! 332: * Now, enable paging by ! 333: * turning on the PG bit ! 334: * in CR0. Also turn on ! 335: * the WP bit to allow ! 336: * the write protecting of ! 337: * memory with repect to ! 338: * the kernel. ! 339: */ ! 340: _cr0.pg = _cr0.wp = TRUE; ! 341: set_cr0(_cr0); ! 342: } ! 343: ! 344: /* ! 345: */ ! 346: void ! 347: pmap_bootstrap( ! 348: mem_region_t mem_region, ! 349: int num_regions, ! 350: vm_offset_t * virt_avail, /* OUT */ ! 351: vm_offset_t * virt_end /* OUT */ ! 352: ) ! 353: { ! 354: vm_offset_t va; ! 355: unsigned int phys_end = mem_region[0].last_phys_addr; ! 356: vm_offset_t kernel_pd; ! 357: ! 358: /* ! 359: * Setup section_size variable. ! 360: */ ! 361: section_size = SECTION_SIZE; ! 362: ! 363: /* ! 364: * Set ptes_per_vm_page for general use. ! 365: */ ! 366: ptes_per_vm_page = PAGE_SIZE / I386_PGBYTES; ! 367: ! 368: /* ! 369: * Initialize pte protection arrays. ! 370: */ ! 371: pte_prot_init(); ! 372: ! 373: /* ! 374: * The kernel's pmap is statically allocated so we don't ! 375: * have to use pmap_create, which does not work ! 376: * correctly at this part of the boot sequence. ! 377: */ ! 378: kernel_pmap = &kernel_pmap_store; ! 379: ! 380: simple_lock_init(&kernel_pmap->lock); ! 381: ! 382: /* ! 383: * Allocate a page directory for the ! 384: * kernel pmap. ! 385: */ ! 386: (vm_offset_t)kernel_pmap->root = ! 387: kernel_pd = alloc_cnvmem(I386_PGBYTES, I386_PGBYTES); ! 388: ! 389: bzero((vm_offset_t)kernel_pmap->root, I386_PGBYTES); ! 390: ! 391: kernel_pmap->ref_count = 1; ! 392: ! 393: kernel_pmap->root += ! 394: (KERNEL_LINEAR_BASE - VM_MIN_KERNEL_ADDRESS) / I386_SECTBYTES; ! 395: ! 396: /* ! 397: * Map all physical memory V == P. ! 398: */ ! 399: va = pmap_map(VM_MIN_KERNEL_ADDRESS, ! 400: 0, ! 401: phys_end, ! 402: VM_PROT_READ | VM_PROT_WRITE); ! 403: ! 404: /* ! 405: * Allocate additional kernel page tables ! 406: * needed for allocating kernel virtual memory later. ! 407: */ ! 408: *virt_avail = va; ! 409: va = pmap_map(va, ! 410: 0, ! 411: 64*1024*1024 + /* base size */ ! 412: zone_map_sizer() + /* zone allocator */ ! 413: buffer_map_sizer(), /* buffer cache */ ! 414: VM_PROT_NONE); ! 415: ! 416: *virt_end = va; ! 417: ! 418: /* ! 419: * Finish initialization ! 420: * of the kernel pmap, and ! 421: * then enable paging. ! 422: */ ! 423: pmap_enable_pg(kernel_pd); ! 424: } ! 425: ! 426: /* ! 427: * Initialize the pmap module. ! 428: * Called by vm_init, to initialize any structures that the pmap ! 429: * system needs to map virtual memory. ! 430: */ ! 431: void ! 432: pmap_init( ! 433: mem_region_t mem_region, ! 434: int num_regions ! 435: ) ! 436: { ! 437: unsigned int phys_start, phys_end; ! 438: int npages; ! 439: vm_size_t s; ! 440: ! 441: phys_start = mem_region[0].first_phys_addr; ! 442: phys_end = mem_region[0].last_phys_addr; ! 443: ! 444: npages = mem_region[0].num_pages; ! 445: ! 446: /* ! 447: * Allocate memory for the page descriptor ! 448: * table. ! 449: */ ! 450: s = sizeof(struct pg_desc) * npages; ! 451: (void) kmem_alloc_wired(kernel_map, (vm_offset_t *)&pg_desc_tbl, s); ! 452: pg_first_phys = phys_start; ! 453: ! 454: /* ! 455: * Create the zone of physical maps, ! 456: * and of the physical-to-virtual entries. ! 457: */ ! 458: s = sizeof (struct pmap); ! 459: pmap_zone = zinit(s, 400*s, 0, FALSE, "pmap"); /* XXX */ ! 460: ! 461: s = sizeof (struct pv_entry); ! 462: pv_entry_zone = zinit(s, 10000*s, 0, FALSE, "pv_entry"); /* XXX */ ! 463: ! 464: /* ! 465: * Create the zone of page ! 466: * extensions. ! 467: */ ! 468: s = sizeof (struct pg_exten); ! 469: pg_exten_zone = zinit(s, npages*s, 0, FALSE, "pg_exten"); ! 470: ! 471: /* ! 472: * Initialize the queues of active and ! 473: * free page tables and free page directories. ! 474: */ ! 475: queue_init(&pt_active_queue); ! 476: queue_init(&pt_free_queue); ! 477: queue_init(&pd_free_queue); ! 478: ! 479: /* ! 480: * Only now, when all of the data structures are allocated, ! 481: * can we set vm_first_phys and vm_last_phys. If we set them ! 482: * too soon, the kmem_alloc above will try to use these ! 483: * data structures and blow up. ! 484: */ ! 485: ! 486: vm_first_phys = phys_start; ! 487: vm_last_phys = phys_end; ! 488: ! 489: pmap_initialized = TRUE; ! 490: } ! 491: ! 492: static ! 493: pg_exten_t * ! 494: pg_exten_alloc( ! 495: vm_offset_t page ! 496: ) ! 497: { ! 498: pg_exten_t *pe; ! 499: pg_desc_t *pd; ! 500: ! 501: (vm_offset_t)pe = zalloc(pg_exten_zone); ! 502: ! 503: pe->phys = pmap_phys(kernel_pmap, page); ! 504: ! 505: pd = pg_desc(pe->phys); ! 506: ! 507: pd->pg_exten = pe; pe->pg_desc = pd; ! 508: ! 509: pe->alloc_count = pe->wired_count = pe->unrefd_age = pe->alloc_bmap = 0; ! 510: ! 511: return (pe); ! 512: } ! 513: ! 514: static ! 515: void ! 516: pg_exten_free( ! 517: pg_exten_t *pe ! 518: ) ! 519: { ! 520: pe->pg_desc->pg_exten = PG_EXTEN_NULL; ! 521: ! 522: zfree(pg_exten_zone, (vm_offset_t)pe); ! 523: } ! 524: ! 525: static ! 526: void ! 527: pmap_alloc_pd( ! 528: pmap_t pmap ! 529: ) ! 530: { ! 531: pg_exten_t *pe; ! 532: int i; ! 533: ! 534: if (pe = pd_free_obtain()) { ! 535: if (++pe->alloc_count == ptes_per_vm_page) ! 536: pd_free_remove(pe); ! 537: ! 538: i = ffs(~pe->alloc_bmap) - 1; ! 539: pe->alloc_bmap |= (1 << i); ! 540: ! 541: (vm_offset_t)pmap->root = pe->pg_desc->pv_list.va + (I386_PGBYTES * i); ! 542: } ! 543: else { ! 544: if (kmem_alloc_wired(kernel_map, ! 545: (vm_offset_t *)&pmap->root, PAGE_SIZE) != KERN_SUCCESS) ! 546: panic("pmap_alloc_pd"); ! 547: ! 548: pd_alloc_count++; ! 549: ! 550: pe = pg_exten_alloc((vm_offset_t)pmap->root); ! 551: ! 552: if (++pe->alloc_count < ptes_per_vm_page) ! 553: pd_free_add(pe); ! 554: ! 555: pe->alloc_bmap |= 1; ! 556: } ! 557: } ! 558: ! 559: static ! 560: void ! 561: pmap_free_pd( ! 562: pmap_t pmap ! 563: ) ! 564: { ! 565: pg_exten_t *pe; ! 566: pg_desc_t *pd; ! 567: int i; ! 568: ! 569: pd = pg_desc(pmap_phys(kernel_pmap, (vm_offset_t)pmap->root)); ! 570: ! 571: pe = pd->pg_exten; ! 572: ! 573: if (pe->alloc_count-- == ptes_per_vm_page) ! 574: pd_free_add(pe); ! 575: ! 576: i = ((vm_offset_t)pmap->root - pd->pv_list.va) / I386_PGBYTES; ! 577: ! 578: pe->alloc_bmap &= ~(1 << i); ! 579: } ! 580: ! 581: /* ! 582: * Allocate and setup the page directory ! 583: * for a new pmap. The pd_entries that ! 584: * correspond to the kernel address space ! 585: * are initialized by copying them from ! 586: * the kernel pmap. This works correctly ! 587: * since we never expand the kernel pmap. ! 588: */ ! 589: static ! 590: void ! 591: pmap_create_pd( ! 592: pmap_t pmap ! 593: ) ! 594: { ! 595: pd_entry_t *pde; ! 596: pd_entry_t *kpde, *end_kpde; ! 597: ! 598: pmap_alloc_pd(pmap); ! 599: ! 600: if (pmap->root == PD_ENTRY_NULL) ! 601: panic("pmap_create_page_directory"); ! 602: ! 603: if (i386_trunc_page(pmap->root) != (vm_offset_t)pmap->root) ! 604: panic("pmap_create_page_directory 1"); ! 605: ! 606: pmap->cr3 = pmap_phys(kernel_pmap, (vm_offset_t)pmap->root); ! 607: ! 608: kpde = ! 609: pmap_pd_entry(kernel_pmap, ! 610: VM_MIN_KERNEL_ADDRESS); ! 611: end_kpde = ! 612: pmap_pd_entry(kernel_pmap, ! 613: VM_MAX_KERNEL_ADDRESS); ! 614: ! 615: pde = pmap_pd_entry(pmap, KERNEL_LINEAR_BASE); ! 616: ! 617: while (kpde < end_kpde) ! 618: *pde++ = *kpde++; ! 619: } ! 620: ! 621: /* ! 622: * Create and return a physical map. ! 623: * ! 624: * If the size specified for the map ! 625: * is zero, the map is an actual physical ! 626: * map, and may be referenced by the ! 627: * hardware. ! 628: * ! 629: * If the size specified is non-zero, ! 630: * the map will be used in software only, and ! 631: * is bounded by that size. ! 632: */ ! 633: pmap_t ! 634: pmap_create( ! 635: vm_size_t size ! 636: ) ! 637: { ! 638: pmap_t pmap; ! 639: ! 640: /* ! 641: * A software use-only map doesn't even need a pmap. ! 642: */ ! 643: if (size != 0) ! 644: return (PMAP_NULL); ! 645: ! 646: /* ! 647: * Allocate a pmap struct from the pmap_zone. ! 648: */ ! 649: pmap = (pmap_t) zalloc(pmap_zone); ! 650: if (pmap == PMAP_NULL) ! 651: panic("pmap_create pmap"); ! 652: ! 653: bzero((vm_offset_t)pmap, sizeof (struct pmap)); ! 654: ! 655: /* ! 656: * Create the page directory. ! 657: */ ! 658: pmap_create_pd(pmap); ! 659: ! 660: pmap->ref_count = 1; ! 661: ! 662: simple_lock_init(&pmap->lock); ! 663: ! 664: return (pmap); ! 665: } ! 666: ! 667: /* ! 668: * Retire the given physical map from service. ! 669: * Should only be called if the map contains ! 670: * no valid mappings. ! 671: */ ! 672: void ! 673: pmap_destroy( ! 674: pmap_t pmap ! 675: ) ! 676: { ! 677: int c, s; ! 678: ! 679: if (pmap == PMAP_NULL) ! 680: return; ! 681: ! 682: SPLVM(s); ! 683: simple_lock(&pmap->lock); ! 684: ! 685: c = --pmap->ref_count; ! 686: ! 687: simple_unlock(&pmap->lock); ! 688: SPLX(s); ! 689: ! 690: if (c != 0) ! 691: return; ! 692: ! 693: pmap_free_pd(pmap); ! 694: ! 695: zfree(pmap_zone, (vm_offset_t)pmap); ! 696: } ! 697: ! 698: /* ! 699: * Add a reference to the specified pmap. ! 700: */ ! 701: ! 702: void ! 703: pmap_reference( ! 704: pmap_t pmap ! 705: ) ! 706: { ! 707: int s; ! 708: ! 709: if (pmap != PMAP_NULL) { ! 710: SPLVM(s); ! 711: simple_lock(&pmap->lock); ! 712: ! 713: pmap->ref_count++; ! 714: ! 715: simple_unlock(&pmap->lock); ! 716: SPLX(s); ! 717: } ! 718: } ! 719: ! 720: /* ! 721: * Remove a range of mappings from ! 722: * a pmap. The indicated range must ! 723: * lie completely within one section, ! 724: * i.e. the ptes must be within one ! 725: * page table. ! 726: */ ! 727: static ! 728: void ! 729: pmap_remove_range( ! 730: pmap_t pmap, ! 731: vm_offset_t start, ! 732: vm_offset_t end, ! 733: boolean_t free_table ! 734: ) ! 735: { ! 736: pt_entry_t *pte, *epte; ! 737: pg_desc_t *pd; ! 738: pv_entry_t pv_h; ! 739: pv_entry_t cur, prev; ! 740: unsigned int pa; ! 741: vm_offset_t va = start; ! 742: int i, num_removed = 0, num_unwired = 0; ! 743: ! 744: if ((pte = pmap_pt_entry(pmap, start)) == PT_ENTRY_NULL) ! 745: return; ! 746: ! 747: epte = pmap_pt_entry(pmap, end); ! 748: if (trunc_page(pte) != trunc_page(epte)) ! 749: epte = (pt_entry_t *)round_page(pte + ptes_per_vm_page); ! 750: ! 751: for (; pte < epte; va += PAGE_SIZE) { ! 752: if (!pte->valid) { ! 753: pte += ptes_per_vm_page; ! 754: continue; ! 755: } ! 756: ! 757: num_removed++; ! 758: if (pte->wired) ! 759: num_unwired++; ! 760: ! 761: pa = pfn_to_phys(pte->pfn); ! 762: if (!managed_page(pa)) { ! 763: for (i = ptes_per_vm_page; i-- > 0; pte++) ! 764: *pte = (pt_entry_t) { 0 }; ! 765: continue; ! 766: } ! 767: ! 768: pd = pg_desc(pa); ! 769: LOCK_PVH(pd); ! 770: ! 771: /* ! 772: * Collect the referenced & dirty bits ! 773: * and clear the mapping. ! 774: */ ! 775: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 776: if (pte->dirty) { ! 777: vm_page_t m = PHYS_TO_VM_PAGE(pa); ! 778: ! 779: vm_page_set_modified(m); ! 780: pd->page_attrib |= PG_DIRTY; ! 781: } ! 782: ! 783: if (pte->refer) ! 784: pd->page_attrib |= PG_REFER; ! 785: ! 786: *pte = (pt_entry_t) { 0 }; ! 787: } ! 788: ! 789: /* ! 790: * Remove the mapping from the pvlist for ! 791: * this physical page. ! 792: */ ! 793: pv_h = pg_desc_pvh(pd); ! 794: if (pv_h->pmap == PMAP_NULL) ! 795: panic("pmap_remove_range"); ! 796: ! 797: if (pv_h->va == va && pv_h->pmap == pmap) { ! 798: /* ! 799: * Header is the pv_entry. Copy the next one ! 800: * to header and free the next one (we can't ! 801: * free the header) ! 802: */ ! 803: cur = pv_h->next; ! 804: if (cur != PV_ENTRY_NULL) { ! 805: *pv_h = *cur; ! 806: zfree(pv_entry_zone, (vm_offset_t) cur); ! 807: } ! 808: else ! 809: pv_h->pmap = PMAP_NULL; ! 810: } ! 811: else { ! 812: prev = pv_h; ! 813: while ((cur = prev->next) != PV_ENTRY_NULL) { ! 814: if (cur->va == va && cur->pmap == pmap) ! 815: break; ! 816: prev = cur; ! 817: } ! 818: if (cur == PV_ENTRY_NULL) ! 819: panic("pmap_remove_range 2"); ! 820: ! 821: prev->next = cur->next; ! 822: zfree(pv_entry_zone, (vm_offset_t) cur); ! 823: } ! 824: ! 825: UNLOCK_PVH(pd); ! 826: } ! 827: ! 828: /* ! 829: * Free the mappings from the page table. ! 830: */ ! 831: pmap_deallocate_mappings( ! 832: pmap, start, ! 833: num_removed, num_unwired, free_table); ! 834: } ! 835: ! 836: /* ! 837: * Remove the given range of addresses ! 838: * from the specified pmap. ! 839: * ! 840: * It is assumed that the start and end are properly ! 841: * rounded to the page size. ! 842: */ ! 843: void ! 844: pmap_remove( ! 845: pmap_t pmap, ! 846: vm_offset_t start, ! 847: vm_offset_t end ! 848: ) ! 849: { ! 850: vm_offset_t sect_end; ! 851: int s; ! 852: ! 853: if (pmap == PMAP_NULL) ! 854: return; ! 855: ! 856: PMAP_READ_LOCK(pmap, s); ! 857: ! 858: /* ! 859: * Invalidate the translation buffer first ! 860: */ ! 861: PMAP_UPDATE_TLBS(pmap, start, end); ! 862: ! 863: while (start < end) { ! 864: sect_end = round_section(start + PAGE_SIZE); ! 865: if (sect_end > end) ! 866: sect_end = end; ! 867: ! 868: pmap_remove_range(pmap, start, sect_end, TRUE); ! 869: start = sect_end; ! 870: } ! 871: ! 872: PMAP_READ_UNLOCK(pmap, s); ! 873: } ! 874: ! 875: /* ! 876: * Remove all references to ! 877: * the indicated page from ! 878: * all pmaps. ! 879: */ ! 880: void ! 881: pmap_remove_all( ! 882: unsigned int pa ! 883: ) ! 884: { ! 885: pt_entry_t *pte; ! 886: pv_entry_t pv_h, cur; ! 887: pg_desc_t *pd; ! 888: vm_offset_t va; ! 889: pmap_t pmap; ! 890: int s, i; ! 891: ! 892: if (!managed_page(pa)) ! 893: return; ! 894: ! 895: /* ! 896: * Lock the pmap system first, since we will be changing ! 897: * several pmaps. ! 898: */ ! 899: PMAP_WRITE_LOCK(s); ! 900: ! 901: /* ! 902: * Walk down PV list, removing all mappings. ! 903: * We have to do the same work as in pmap_remove_range ! 904: * since that routine locks the pv_head. We don't have ! 905: * to lock the pv_head, since we have the entire pmap system. ! 906: */ ! 907: pd = pg_desc(pa); ! 908: pv_h = pg_desc_pvh(pd); ! 909: ! 910: while ((pmap = pv_h->pmap) != PMAP_NULL) { ! 911: va = pv_h->va; ! 912: ! 913: simple_lock(&pmap->lock); ! 914: ! 915: pte = pmap_pt_entry(pmap, va); ! 916: if (pte == PT_ENTRY_NULL || !pte->valid) ! 917: panic("pmap_remove_all"); ! 918: ! 919: if (pfn_to_phys(pte->pfn) != pa) ! 920: panic("pmap_remove_all 2"); ! 921: ! 922: if (pte->wired) ! 923: panic("pmap_remove_all 3"); ! 924: ! 925: /* ! 926: * Tell CPU using pmap to invalidate its TLB ! 927: */ ! 928: PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE); ! 929: ! 930: if ((cur = pv_h->next) != PV_ENTRY_NULL) { ! 931: *pv_h = *cur; ! 932: zfree(pv_entry_zone, (vm_offset_t) cur); ! 933: } ! 934: else ! 935: pv_h->pmap = PMAP_NULL; ! 936: ! 937: /* ! 938: * Collect the referenced & dirty bits ! 939: * and clear the mapping. ! 940: */ ! 941: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 942: if (pte->dirty) { ! 943: vm_page_t m = PHYS_TO_VM_PAGE(pa); ! 944: ! 945: vm_page_set_modified(m); ! 946: pd->page_attrib |= PG_DIRTY; ! 947: } ! 948: ! 949: if (pte->refer) ! 950: pd->page_attrib |= PG_REFER; ! 951: ! 952: *pte = (pt_entry_t) { 0 }; ! 953: } ! 954: ! 955: pmap_deallocate_mappings(pmap, va, 1, 0, TRUE); ! 956: ! 957: simple_unlock(&pmap->lock); ! 958: } ! 959: ! 960: PMAP_WRITE_UNLOCK(s); ! 961: } ! 962: ! 963: /* ! 964: * Remove write access to the ! 965: * indicated page from all pmaps. ! 966: */ ! 967: void ! 968: pmap_copy_on_write( ! 969: unsigned int pa ! 970: ) ! 971: { ! 972: pt_entry_t *pte; ! 973: pv_entry_t pv_e; ! 974: int i, s; ! 975: ! 976: if (!managed_page(pa)) ! 977: return; ! 978: ! 979: /* ! 980: * Lock the entire pmap system, since we may be changing ! 981: * several maps. ! 982: */ ! 983: PMAP_WRITE_LOCK(s); ! 984: ! 985: pv_e = pg_desc_pvh(pg_desc(pa)); ! 986: if (pv_e->pmap == PMAP_NULL) { ! 987: PMAP_WRITE_UNLOCK(s); ! 988: return; ! 989: } ! 990: ! 991: /* ! 992: * Run down the list of mappings to this physical page, ! 993: * disabling write privileges on each one. ! 994: */ ! 995: while (pv_e != PV_ENTRY_NULL) { ! 996: pmap_t pmap; ! 997: vm_offset_t va; ! 998: ! 999: pmap = pv_e->pmap; ! 1000: va = pv_e->va; ! 1001: ! 1002: simple_lock(&pmap->lock); ! 1003: ! 1004: pte = pmap_pt_entry(pmap, va); ! 1005: ! 1006: if (pte == PT_ENTRY_NULL || !pte->valid) ! 1007: panic("pmap_copy_on_write"); ! 1008: ! 1009: /* ! 1010: * Ask cpus using pmap to invalidate their TLBs ! 1011: */ ! 1012: PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE); ! 1013: ! 1014: if (pte->prot == PT_PROT_URW || pte->prot == PT_PROT_KRW) ! 1015: for (i = ptes_per_vm_page; i-- > 0; pte++) ! 1016: pte_prot(pmap, VM_PROT_READ, pte->valid, pte); ! 1017: ! 1018: simple_unlock(&pmap->lock); ! 1019: ! 1020: pv_e = pv_e->next; ! 1021: } ! 1022: ! 1023: PMAP_WRITE_UNLOCK(s); ! 1024: } ! 1025: ! 1026: /* ! 1027: * Change the page protection ! 1028: * on a range of addresses in ! 1029: * the indicated pmap. If protect ! 1030: * is being changed to VM_PROT_NONE, ! 1031: * remove the mappings. ! 1032: */ ! 1033: void ! 1034: pmap_protect( ! 1035: pmap_t pmap, ! 1036: vm_offset_t start, ! 1037: vm_offset_t end, ! 1038: vm_prot_t prot ! 1039: ) ! 1040: { ! 1041: pt_entry_t *pte, *epte; ! 1042: vm_offset_t sect_end; ! 1043: int i, s; ! 1044: ! 1045: if (pmap == PMAP_NULL) ! 1046: return; ! 1047: ! 1048: if (prot == VM_PROT_NONE) { ! 1049: pmap_remove(pmap, start, end); ! 1050: return; ! 1051: } ! 1052: ! 1053: SPLVM(s); ! 1054: simple_lock(&pmap->lock); ! 1055: ! 1056: /* ! 1057: * Invalidate the translation buffer first ! 1058: */ ! 1059: PMAP_UPDATE_TLBS(pmap, start, end); ! 1060: ! 1061: while (start < end) { ! 1062: sect_end = round_section(start + PAGE_SIZE); ! 1063: if (sect_end > end) ! 1064: sect_end = end; ! 1065: ! 1066: pte = pmap_pt_entry(pmap, start); ! 1067: if (pte != PT_ENTRY_NULL) { ! 1068: epte = pmap_pt_entry(pmap, sect_end); ! 1069: if (trunc_page(pte) != trunc_page(epte)) ! 1070: epte = (pt_entry_t *)round_page(pte + ptes_per_vm_page); ! 1071: ! 1072: while (pte < epte) { ! 1073: if (!pte->valid) { ! 1074: pte += ptes_per_vm_page; ! 1075: continue; ! 1076: } ! 1077: ! 1078: for (i = ptes_per_vm_page; i-- > 0; pte++) ! 1079: pte_prot(pmap, prot, pte->valid, pte); ! 1080: } ! 1081: } ! 1082: ! 1083: start = sect_end; ! 1084: } ! 1085: ! 1086: simple_unlock(&pmap->lock); ! 1087: SPLX(s); ! 1088: } ! 1089: ! 1090: /* ! 1091: * Insert the given physical page (p) at ! 1092: * the specified virtual address (v) in the ! 1093: * target physical map with the protection requested. ! 1094: * ! 1095: * If specified, the page will be wired down, meaning ! 1096: * that the related pte can not be reclaimed. ! 1097: * ! 1098: * NB: This is the only routine which MAY NOT lazy-evaluate ! 1099: * or lose information. That is, this routine must actually ! 1100: * insert this page into the given map NOW. ! 1101: */ ! 1102: void inline ! 1103: pmap_enter_cache_spec( ! 1104: pmap_t pmap, ! 1105: vm_offset_t va, ! 1106: vm_offset_t pa, ! 1107: vm_prot_t prot, ! 1108: boolean_t wired, ! 1109: cache_spec_t caching ! 1110: ) ! 1111: { ! 1112: pt_entry_t *pte; ! 1113: pv_entry_t pv_h; ! 1114: pg_desc_t *pd; ! 1115: int i, s; ! 1116: pv_entry_t pv_e; ! 1117: pt_entry_t template; ! 1118: vm_offset_t old_pa; ! 1119: ! 1120: if (pmap == PMAP_NULL) ! 1121: return; ! 1122: ! 1123: if (prot == VM_PROT_NONE) { ! 1124: pmap_remove(pmap, va, va + PAGE_SIZE); ! 1125: return; ! 1126: } ! 1127: ! 1128: /* ! 1129: * Must allocate a new pvlist entry while we're unlocked; ! 1130: * zalloc may cause pageout (which will lock the pmap system). ! 1131: * If we determine we need a pvlist entry, we will unlock ! 1132: * and allocate one. Then we will retry, throwing away ! 1133: * the allocated entry later (if we no longer need it). ! 1134: */ ! 1135: pv_e = PV_ENTRY_NULL; ! 1136: template = (pt_entry_t) { 0 }; ! 1137: ! 1138: Retry: ! 1139: PMAP_READ_LOCK(pmap, s); ! 1140: ! 1141: /* ! 1142: * Expand pmap to include this pte. Assume that ! 1143: * pmap is always expanded to include enough ! 1144: * pages to map one VM page. ! 1145: */ ! 1146: while ((pte = pmap_pt_entry(pmap, va)) == PT_ENTRY_NULL) { ! 1147: /* ! 1148: * Must unlock to expand the pmap. ! 1149: */ ! 1150: PMAP_READ_UNLOCK(pmap, s); ! 1151: ! 1152: pmap_expand(pmap, va); ! 1153: ! 1154: PMAP_READ_LOCK(pmap, s); ! 1155: } ! 1156: ! 1157: /* ! 1158: * Special case if the physical page is already mapped ! 1159: * at this address. ! 1160: */ ! 1161: old_pa = pfn_to_phys(pte->pfn); ! 1162: if (pte->valid && old_pa == pa) { ! 1163: /* ! 1164: * May be changing its wired attribute or protection ! 1165: */ ! 1166: if (wired && !pte->wired) ! 1167: pmap_wire_mapping(pmap, va); ! 1168: else ! 1169: if (!wired && pte->wired) ! 1170: pmap_unwire_mapping(pmap, va); ! 1171: ! 1172: pte_prot(pmap, prot, 1, &template); ! 1173: template.pfn = phys_to_pfn(pa); ! 1174: if (wired) ! 1175: template.wired = 1; ! 1176: ! 1177: if (caching == cache_disable) ! 1178: template.cachedis = 1; ! 1179: else ! 1180: if (caching == cache_writethrough) ! 1181: template.cachewrt = 1; ! 1182: ! 1183: PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE); ! 1184: ! 1185: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 1186: if (pte->dirty) ! 1187: template.dirty = 1; ! 1188: *pte = template; ! 1189: template.pfn++; ! 1190: } ! 1191: } ! 1192: else { ! 1193: ! 1194: /* ! 1195: * Remove old mapping from the PV list if necessary. ! 1196: */ ! 1197: if (pte->valid) { ! 1198: /* ! 1199: * Invalidate the translation buffer, ! 1200: * then remove the mapping. ! 1201: */ ! 1202: PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE); ! 1203: ! 1204: pmap_remove_range(pmap, va, va + PAGE_SIZE, FALSE); ! 1205: } ! 1206: ! 1207: if (managed_page(pa)) { ! 1208: ! 1209: /* ! 1210: * Enter the mapping in the PV list for this ! 1211: * physical page. ! 1212: */ ! 1213: pd = pg_desc(pa); ! 1214: LOCK_PVH(pd); ! 1215: pv_h = pg_desc_pvh(pd); ! 1216: ! 1217: if (pv_h->pmap == PMAP_NULL) { ! 1218: ! 1219: /* ! 1220: * No mappings yet ! 1221: */ ! 1222: pv_h->va = va; ! 1223: pv_h->pmap = pmap; ! 1224: pv_h->next = PV_ENTRY_NULL; ! 1225: } ! 1226: else { ! 1227: ! 1228: /* ! 1229: * Add new pv_entry after header. ! 1230: */ ! 1231: if (pv_e == PV_ENTRY_NULL) { ! 1232: UNLOCK_PVH(pd); ! 1233: PMAP_READ_UNLOCK(pmap, s); ! 1234: pv_e = (pv_entry_t) zalloc(pv_entry_zone); ! 1235: goto Retry; ! 1236: } ! 1237: pv_e->va = va; ! 1238: pv_e->pmap = pmap; ! 1239: pv_e->next = pv_h->next; ! 1240: pv_h->next = pv_e; ! 1241: /* ! 1242: * Remember that we used the pvlist entry. ! 1243: */ ! 1244: pv_e = PV_ENTRY_NULL; ! 1245: } ! 1246: ! 1247: UNLOCK_PVH(pd); ! 1248: } ! 1249: ! 1250: pmap_allocate_mapping(pmap, va, wired); ! 1251: ! 1252: /* ! 1253: * Build a template to speed up entering - ! 1254: * only the pfn changes. ! 1255: */ ! 1256: pte_prot(pmap, prot, 1, &template); ! 1257: template.pfn = phys_to_pfn(pa); ! 1258: if (wired) ! 1259: template.wired = 1; ! 1260: ! 1261: if (caching == cache_disable) ! 1262: template.cachedis = 1; ! 1263: else ! 1264: if (caching == cache_writethrough) ! 1265: template.cachewrt = 1; ! 1266: ! 1267: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 1268: *pte = template; ! 1269: template.pfn++; ! 1270: } ! 1271: } ! 1272: ! 1273: PMAP_READ_UNLOCK(pmap, s); ! 1274: ! 1275: if (pv_e != PV_ENTRY_NULL) ! 1276: zfree(pv_entry_zone, (vm_offset_t) pv_e); ! 1277: } ! 1278: ! 1279: void ! 1280: pmap_enter( ! 1281: pmap_t pmap, ! 1282: vm_offset_t va, ! 1283: vm_offset_t pa, ! 1284: vm_prot_t prot, ! 1285: boolean_t wired ! 1286: ) ! 1287: { ! 1288: pmap_enter_cache_spec( ! 1289: pmap, ! 1290: va, ! 1291: pa, ! 1292: prot, ! 1293: wired, ! 1294: cache_default); ! 1295: } ! 1296: ! 1297: void ! 1298: pmap_enter_shared_range( ! 1299: pmap_t pmap, ! 1300: vm_offset_t va, ! 1301: vm_size_t size, ! 1302: vm_offset_t kern ! 1303: ) ! 1304: { ! 1305: vm_offset_t end = round_page(va + size); ! 1306: ! 1307: while (va < end) { ! 1308: pmap_enter( ! 1309: pmap, ! 1310: va, ! 1311: pmap_resident_extract(kernel_pmap, kern), ! 1312: VM_PROT_READ|VM_PROT_WRITE, ! 1313: TRUE); ! 1314: ! 1315: va += PAGE_SIZE; kern += PAGE_SIZE; ! 1316: } ! 1317: } ! 1318: ! 1319: /* ! 1320: * Change the wiring attribute for a ! 1321: * pmap/virtual-address pair. ! 1322: * ! 1323: * The mapping must already exist in the pmap. ! 1324: */ ! 1325: void ! 1326: pmap_change_wiring( ! 1327: pmap_t pmap, ! 1328: vm_offset_t va, ! 1329: boolean_t wired ! 1330: ) ! 1331: { ! 1332: pt_entry_t *pte; ! 1333: int i, s; ! 1334: ! 1335: /* ! 1336: * We must grab the pmap system lock because we may ! 1337: * change a pte_page queue. ! 1338: */ ! 1339: PMAP_READ_LOCK(pmap, s); ! 1340: ! 1341: if ((pte = pmap_pt_entry(pmap, va)) == PT_ENTRY_NULL) ! 1342: panic("pmap_change_wiring"); ! 1343: ! 1344: if (wired && !pte->wired) { ! 1345: /* ! 1346: * wiring down mapping ! 1347: */ ! 1348: pmap_wire_mapping(pmap, va); ! 1349: } ! 1350: else ! 1351: if (!wired && pte->wired) { ! 1352: /* ! 1353: * unwiring mapping ! 1354: */ ! 1355: pmap_unwire_mapping(pmap, va); ! 1356: } ! 1357: ! 1358: for (i = ptes_per_vm_page; i-- > 0; pte++) ! 1359: pte->wired = wired; ! 1360: ! 1361: PMAP_READ_UNLOCK(map, s); ! 1362: } ! 1363: ! 1364: vm_offset_t ! 1365: pmap_extract( ! 1366: pmap_t pmap, ! 1367: vm_offset_t va ! 1368: ) ! 1369: { ! 1370: vm_offset_t pa; ! 1371: int s; ! 1372: ! 1373: SPLVM(s); ! 1374: simple_lock(&pmap->lock); ! 1375: ! 1376: pa = pmap_phys(pmap, va); ! 1377: ! 1378: simple_unlock(&pmap->lock); ! 1379: SPLX(s); ! 1380: ! 1381: return (pa); ! 1382: } ! 1383: ! 1384: vm_offset_t ! 1385: pmap_resident_extract( ! 1386: pmap_t pmap, ! 1387: vm_offset_t va ! 1388: ) ! 1389: { ! 1390: return ((vm_offset_t) pmap_phys(pmap, va)); ! 1391: } ! 1392: ! 1393: /* ! 1394: * Expand a pmap to be able to map the ! 1395: * specified virtual address by allocating ! 1396: * a single page table either from the list ! 1397: * of free page tables or directly from kernel ! 1398: * memory. ! 1399: */ ! 1400: static ! 1401: void ! 1402: pmap_expand( ! 1403: pmap_t pmap, ! 1404: vm_offset_t va ! 1405: ) ! 1406: { ! 1407: pd_entry_t template, *pde; ! 1408: pg_exten_t *pe; ! 1409: vm_offset_t pt; ! 1410: int i, s; ! 1411: ! 1412: if (pmap == kernel_pmap) ! 1413: panic("pmap_expand"); ! 1414: ! 1415: if (pe = pt_free_obtain()) ! 1416: pt = pe->pg_desc->pv_list.va; ! 1417: else { ! 1418: if (kmem_alloc_wired(kernel_map, &pt, PAGE_SIZE) != KERN_SUCCESS) ! 1419: return; ! 1420: ! 1421: pt_alloc_count++; ! 1422: ! 1423: pe = pg_exten_alloc(pt); ! 1424: } ! 1425: ! 1426: PMAP_READ_LOCK(pmap, s); ! 1427: ! 1428: /* ! 1429: * See if someone else expanded us first. ! 1430: */ ! 1431: if (pmap_pt_entry(pmap, va) != PT_ENTRY_NULL) { ! 1432: PMAP_READ_UNLOCK(pmap, s); ! 1433: ! 1434: pg_exten_free(pe); ! 1435: ! 1436: kmem_free(kernel_map, pt, PAGE_SIZE); ! 1437: ! 1438: pt_alloc_count--; ! 1439: ! 1440: return; ! 1441: } ! 1442: ! 1443: /* ! 1444: * What virtual memory does this ! 1445: * page table map ? ! 1446: */ ! 1447: pe->offset = trunc_section(va); ! 1448: pe->pmap = pmap; ! 1449: ! 1450: /* ! 1451: * Clear the reference aging ! 1452: * tick count. ! 1453: */ ! 1454: pe->unrefd_age = 0; ! 1455: ! 1456: /* ! 1457: * Add this page table ! 1458: * to the active queue. ! 1459: */ ! 1460: pt_active_add(pe); ! 1461: ! 1462: /* ! 1463: * Setup entry template. ! 1464: */ ! 1465: template = (pd_entry_t) { 0 }; ! 1466: template.valid = 1; ! 1467: template.prot = PT_PROT_URW; ! 1468: template.pfn = phys_to_pfn(pe->phys); ! 1469: ! 1470: /* ! 1471: * Set the page directory entries for this page table ! 1472: */ ! 1473: pde = pmap_pd_entry(pmap, pe->offset); ! 1474: for (i = ptes_per_vm_page; i-- > 0; pde++) { ! 1475: *pde = template; ! 1476: template.pfn++; ! 1477: } ! 1478: ! 1479: PMAP_READ_UNLOCK(pmap, s); ! 1480: } ! 1481: ! 1482: /* ! 1483: * Allocate one additional mapping ! 1484: * in a page table. Note: pmap is ! 1485: * already locked. ! 1486: */ ! 1487: static ! 1488: void ! 1489: pmap_allocate_mapping( ! 1490: pmap_t pmap, ! 1491: vm_offset_t va, ! 1492: boolean_t wired ! 1493: ) ! 1494: { ! 1495: pd_entry_t *pde; ! 1496: pg_exten_t *pe; ! 1497: ! 1498: pmap->stats.resident_count++; ! 1499: if (wired) ! 1500: pmap->stats.wired_count++; ! 1501: ! 1502: if (pmap == kernel_pmap) ! 1503: return; ! 1504: ! 1505: pde = pmap_pd_entry(pmap, trunc_section(va)); ! 1506: if (pde->valid) { ! 1507: pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten; ! 1508: pe->alloc_count++; ! 1509: if (wired) ! 1510: pe->wired_count++; ! 1511: } ! 1512: } ! 1513: ! 1514: /* ! 1515: * Deallocate one or more mappings ! 1516: * in a page table. The page table ! 1517: * is freed if no mappings remain. ! 1518: * Note: pmap is already locked. ! 1519: */ ! 1520: static ! 1521: void ! 1522: pmap_deallocate_mappings( ! 1523: pmap_t pmap, ! 1524: vm_offset_t va, ! 1525: int count, ! 1526: int unwire_count, ! 1527: boolean_t free_table ! 1528: ) ! 1529: { ! 1530: pd_entry_t *pde; ! 1531: pg_exten_t *pe; ! 1532: int i; ! 1533: ! 1534: pmap->stats.wired_count -= unwire_count; ! 1535: pmap->stats.resident_count -= count; ! 1536: ! 1537: if (pmap == kernel_pmap) ! 1538: return; ! 1539: ! 1540: pde = pmap_pd_entry(pmap, trunc_section(va)); ! 1541: if (pde->valid) { ! 1542: pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten; ! 1543: if (pe->wired_count < unwire_count) ! 1544: panic("pmap_deallocate_mappings unwire"); ! 1545: pe->wired_count -= unwire_count; ! 1546: if (pe->alloc_count < count) ! 1547: panic("pmap_deallocate_mappings"); ! 1548: pe->alloc_count -= count; ! 1549: ! 1550: if (free_table && pe->alloc_count == 0) { ! 1551: for (i = ptes_per_vm_page; i-- > 0; pde++) ! 1552: pde->valid = 0; ! 1553: ! 1554: pt_active_remove(pe); ! 1555: ! 1556: pt_free_add(pe); ! 1557: } ! 1558: } ! 1559: } ! 1560: ! 1561: static ! 1562: void ! 1563: pmap_wire_mapping( ! 1564: pmap_t pmap, ! 1565: vm_offset_t va ! 1566: ) ! 1567: { ! 1568: pd_entry_t *pde; ! 1569: pg_exten_t *pe; ! 1570: ! 1571: pmap->stats.wired_count++; ! 1572: ! 1573: if (pmap == kernel_pmap) ! 1574: return; ! 1575: ! 1576: pde = pmap_pd_entry(pmap, trunc_section(va)); ! 1577: if (pde->valid) { ! 1578: pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten; ! 1579: pe->wired_count++; ! 1580: } ! 1581: } ! 1582: ! 1583: static ! 1584: void ! 1585: pmap_unwire_mapping( ! 1586: pmap_t pmap, ! 1587: vm_offset_t va ! 1588: ) ! 1589: { ! 1590: pd_entry_t *pde; ! 1591: pg_exten_t *pe; ! 1592: ! 1593: pmap->stats.wired_count--; ! 1594: ! 1595: if (pmap == kernel_pmap) ! 1596: return; ! 1597: ! 1598: pde = pmap_pd_entry(pmap, trunc_section(va)); ! 1599: if (pde->valid) { ! 1600: pe = pg_desc(pfn_to_phys(pde->pfn))->pg_exten; ! 1601: pe->wired_count--; ! 1602: } ! 1603: } ! 1604: ! 1605: /* ! 1606: * Copy the range specified by src_addr/len ! 1607: * from the source map to the range dst_addr/len ! 1608: * in the destination map. ! 1609: * ! 1610: * This routine is only advisory and need not do anything. ! 1611: */ ! 1612: void ! 1613: pmap_copy( ! 1614: pmap_t dst_pmap, ! 1615: pmap_t src_pmap, ! 1616: vm_offset_t dst_addr, ! 1617: vm_size_t len, ! 1618: vm_offset_t src_addr ! 1619: ) ! 1620: { ! 1621: /* OPTIONAL */ ! 1622: } ! 1623: ! 1624: /* ! 1625: * Require that all active physical maps contain no ! 1626: * incorrect entries NOW. [This update includes ! 1627: * forcing updates of any address map caching.] ! 1628: * ! 1629: * Generally used to insure that a thread about ! 1630: * to run will see a semantically correct world. ! 1631: */ ! 1632: void ! 1633: pmap_update( ! 1634: void ! 1635: ) ! 1636: { ! 1637: pg_exten_t *pe, *npe; ! 1638: vm_offset_t page; ! 1639: pd_entry_t *pde; ! 1640: int tick_delta; ! 1641: static unsigned int last_tick; ! 1642: ! 1643: if (!last_tick) ! 1644: last_tick = sched_tick; /* initialization */ ! 1645: ! 1646: tick_delta = sched_tick - last_tick; ! 1647: ! 1648: if (tick_delta > 1) { ! 1649: /* ! 1650: * Free all of the pages in ! 1651: * the free page table list. ! 1652: */ ! 1653: while (pe = pt_free_obtain()) { ! 1654: page = pe->pg_desc->pv_list.va; ! 1655: ! 1656: pg_exten_free(pe); ! 1657: ! 1658: kmem_free(kernel_map, page, PAGE_SIZE); ! 1659: pt_alloc_count--; ! 1660: } ! 1661: ! 1662: /* ! 1663: * Run through the page directory ! 1664: * free list, freeing any that are ! 1665: * not in use. ! 1666: */ ! 1667: (queue_entry_t)pe = queue_first(&pd_free_queue); ! 1668: while (!queue_end(&pd_free_queue, (queue_entry_t)pe)) { ! 1669: if (pe->alloc_count == 0) { ! 1670: remqueue(&pd_free_queue, (queue_entry_t)pe); ! 1671: ! 1672: pd_free_count--; ! 1673: ! 1674: page = pe->pg_desc->pv_list.va; ! 1675: ! 1676: pg_exten_free(pe); ! 1677: ! 1678: kmem_free(kernel_map, page, PAGE_SIZE); ! 1679: pd_alloc_count--; ! 1680: ! 1681: (queue_entry_t)pe = queue_first(&pd_free_queue); ! 1682: } ! 1683: else ! 1684: (queue_entry_t)pe = queue_next((queue_entry_t)pe); ! 1685: } ! 1686: } ! 1687: ! 1688: /* ! 1689: * Age the active page tables. Remove ! 1690: * all of the mappings from the tables ! 1691: * which have not been used for address ! 1692: * translation recently (excluding those ! 1693: * with wired mappings). Removing all of ! 1694: * a table's mappings causes the table to ! 1695: * be removed from the pmap and added to ! 1696: * the free page table list. ! 1697: */ ! 1698: { ! 1699: static int pt_aging_k[] = { 8, 12, 16, 24, 32 }, ! 1700: pt_aging_n = sizeof pt_aging_k / sizeof pt_aging_k[0]; ! 1701: int tick_age; ! 1702: ! 1703: tick_age = ((tick_age = tick_delta >> 3) > (pt_aging_n - 1)) ? ! 1704: pt_aging_k[pt_aging_n - 1] : ! 1705: pt_aging_k[tick_age]; ! 1706: ! 1707: (queue_entry_t)pe = queue_first(&pt_active_queue); ! 1708: while (!queue_end(&pt_active_queue, (queue_entry_t)pe)) { ! 1709: pde = pmap_pd_entry(pe->pmap, pe->offset); ! 1710: if (pe->wired_count == 0 && pde->valid) { ! 1711: (queue_entry_t)npe = queue_next((queue_entry_t)pe); ! 1712: ! 1713: if (tick_delta > 0 && !pde->refer) { ! 1714: int old_age = pe->unrefd_age; ! 1715: ! 1716: pe->unrefd_age += tick_delta; ! 1717: if (old_age > pe->unrefd_age || pe->unrefd_age > tick_age) ! 1718: pmap_remove( ! 1719: pe->pmap, ! 1720: pe->offset, ! 1721: pe->offset + section_size); ! 1722: } ! 1723: else if (pde->refer) { ! 1724: pde->refer = FALSE; ! 1725: pe->unrefd_age = 0; ! 1726: } ! 1727: ! 1728: pe = npe; ! 1729: } ! 1730: else { ! 1731: pe->unrefd_age = 0; ! 1732: (queue_entry_t)pe = queue_next((queue_entry_t)pe); ! 1733: } ! 1734: } ! 1735: } ! 1736: ! 1737: last_tick += tick_delta; ! 1738: } ! 1739: ! 1740: /* ! 1741: * Garbage collects the physical map system for ! 1742: * pages which are no longer used. ! 1743: * Success need not be guaranteed -- that is, there ! 1744: * may well be pages which are not referenced, but ! 1745: * others may be collected. ! 1746: * ! 1747: * Called by the pageout daemon when pages are scarce. ! 1748: */ ! 1749: void ! 1750: pmap_collect( ! 1751: pmap_t pmap ! 1752: ) ! 1753: { ! 1754: /* OPTIONAL */ ! 1755: } ! 1756: ! 1757: /* ! 1758: * Bind the given pmap to the given ! 1759: * processor. ! 1760: */ ! 1761: void ! 1762: pmap_activate( ! 1763: pmap_t pmap, ! 1764: thread_t thread, ! 1765: int cpu ! 1766: ) ! 1767: { ! 1768: PMAP_ACTIVATE(pmap, thread, cpu); ! 1769: } ! 1770: ! 1771: ! 1772: /* ! 1773: * Indicates that the given physical map is no longer ! 1774: * in use on the specified processor. ! 1775: */ ! 1776: void ! 1777: pmap_deactivate( ! 1778: pmap_t pmap, ! 1779: thread_t thread, ! 1780: int cpu ! 1781: ) ! 1782: { ! 1783: PMAP_DEACTIVATE(pmap, thread, cpu); ! 1784: } ! 1785: ! 1786: /* ! 1787: * Return the pmap handle for the kernel. ! 1788: */ ! 1789: pmap_t ! 1790: pmap_kernel( ! 1791: void ! 1792: ) ! 1793: { ! 1794: return (kernel_pmap); ! 1795: } ! 1796: ! 1797: /* ! 1798: * pmap_zero_page zeros the specified (machine independent) ! 1799: * page. ! 1800: */ ! 1801: void ! 1802: pmap_zero_page( ! 1803: vm_offset_t pa ! 1804: ) ! 1805: { ! 1806: page_set(pmap_phys_to_kern(pa), 0, PAGE_SIZE); ! 1807: } ! 1808: ! 1809: /* ! 1810: * pmap_copy_page copies the specified (machine independent) ! 1811: * pages. ! 1812: */ ! 1813: void ! 1814: pmap_copy_page( ! 1815: vm_offset_t src, ! 1816: vm_offset_t dst ! 1817: ) ! 1818: { ! 1819: page_copy(pmap_phys_to_kern(dst), pmap_phys_to_kern(src), PAGE_SIZE); ! 1820: } ! 1821: ! 1822: void ! 1823: copy_to_phys( ! 1824: vm_offset_t src, ! 1825: vm_offset_t dst, ! 1826: vm_size_t count ! 1827: ) ! 1828: { ! 1829: bcopy(src, pmap_phys_to_kern(dst), count); ! 1830: } ! 1831: ! 1832: void ! 1833: copy_from_phys( ! 1834: vm_offset_t src, ! 1835: vm_offset_t dst, ! 1836: vm_size_t count ! 1837: ) ! 1838: { ! 1839: bcopy(pmap_phys_to_kern(src), dst, count); ! 1840: } ! 1841: ! 1842: /* ! 1843: * Make the specified pages (by pmap, offset) ! 1844: * pageable (or not) as requested. ! 1845: * ! 1846: * A page which is not pageable may not take ! 1847: * a fault; therefore, its page table entry ! 1848: * must remain valid for the duration. ! 1849: * ! 1850: * This routine is merely advisory; pmap_enter ! 1851: * will specify that these pages are to be wired ! 1852: * down (or not) as appropriate. ! 1853: */ ! 1854: pmap_pageable( ! 1855: pmap_t pmap, ! 1856: vm_offset_t start, ! 1857: vm_offset_t end, ! 1858: boolean_t pageable ! 1859: ) ! 1860: { ! 1861: /* OPTIONAL */ ! 1862: } ! 1863: ! 1864: kern_return_t ! 1865: pmap_attribute( ! 1866: pmap_t pmap, ! 1867: vm_offset_t address, ! 1868: vm_size_t size, ! 1869: vm_machine_attribute_t attribute, ! 1870: vm_machine_attribute_val_t *value ! 1871: ) ! 1872: { ! 1873: kern_return_t ret; ! 1874: ! 1875: if (attribute != MATTR_CACHE) ! 1876: return KERN_INVALID_ARGUMENT; ! 1877: ! 1878: /* ! 1879: ** We can't get the caching attribute for more than one page ! 1880: ** at a time ! 1881: */ ! 1882: if ((*value == MATTR_VAL_GET) && ! 1883: (trunc_page(address) != trunc_page(address+size-1))) ! 1884: return KERN_INVALID_ARGUMENT; ! 1885: ! 1886: if (pmap == PMAP_NULL) ! 1887: return KERN_SUCCESS; ! 1888: ! 1889: ret = KERN_SUCCESS; ! 1890: ! 1891: simple_lock(&pmap->lock); ! 1892: ! 1893: switch (*value) { ! 1894: case MATTR_VAL_CACHE_FLUSH: /* flush from all caches */ ! 1895: case MATTR_VAL_DCACHE_FLUSH: /* flush from data cache(s) */ ! 1896: case MATTR_VAL_ICACHE_FLUSH: /* flush from instr cache(s) */ ! 1897: break; ! 1898: ! 1899: case MATTR_VAL_GET: /* return current value */ ! 1900: case MATTR_VAL_OFF: /* turn attribute off */ ! 1901: case MATTR_VAL_ON: /* turn attribute on */ ! 1902: default: ! 1903: ret = KERN_INVALID_ARGUMENT; ! 1904: break; ! 1905: } ! 1906: simple_unlock(&pmap->lock); ! 1907: ! 1908: return ret; ! 1909: ! 1910: } ! 1911: ! 1912: /* ! 1913: * Clear the modify bits on the specified physical page. ! 1914: */ ! 1915: void ! 1916: pmap_clear_modify( ! 1917: vm_offset_t pa ! 1918: ) ! 1919: { ! 1920: if (managed_page(pa)) ! 1921: pmap_clear_page_attrib(pa, PG_DIRTY); ! 1922: } ! 1923: ! 1924: /* ! 1925: * Return whether or not the specified physical page is modified ! 1926: * by any pmaps. ! 1927: */ ! 1928: boolean_t ! 1929: pmap_is_modified( ! 1930: vm_offset_t pa ! 1931: ) ! 1932: { ! 1933: if (managed_page(pa)) ! 1934: return (pmap_check_page_attrib(pa, PG_DIRTY)); ! 1935: else ! 1936: return (FALSE); ! 1937: } ! 1938: ! 1939: /* ! 1940: * Clear the reference bit on the specified physical page. ! 1941: */ ! 1942: void ! 1943: pmap_clear_reference( ! 1944: vm_offset_t pa ! 1945: ) ! 1946: { ! 1947: if (managed_page(pa)) ! 1948: pmap_clear_page_attrib(pa, PG_REFER); ! 1949: } ! 1950: ! 1951: /* ! 1952: * Return whether or not the specified physical page is referenced ! 1953: * by any physical maps. ! 1954: */ ! 1955: boolean_t ! 1956: pmap_is_referenced( ! 1957: vm_offset_t pa ! 1958: ) ! 1959: { ! 1960: if (managed_page(pa)) ! 1961: return (pmap_check_page_attrib(pa, PG_REFER)); ! 1962: else ! 1963: return (FALSE); ! 1964: } ! 1965: ! 1966: /* ! 1967: * Clear the specified page attributes both in the ! 1968: * pmap_page_attributes table and the address translation ! 1969: * tables. Note that we DO have to flush the entries from ! 1970: * the TLB since the processor uses the bits in the TLB to ! 1971: * determine whether it has to write the bits out to memory. ! 1972: */ ! 1973: static ! 1974: void ! 1975: pmap_clear_page_attrib( ! 1976: vm_offset_t pa, ! 1977: int attrib ! 1978: ) ! 1979: { ! 1980: pt_entry_t *pte; ! 1981: pv_entry_t pv_h; ! 1982: pmap_t pmap; ! 1983: vm_offset_t va; ! 1984: pg_desc_t *pd; ! 1985: int i, s; ! 1986: ! 1987: pd = pg_desc(pa); ! 1988: ! 1989: PMAP_WRITE_LOCK(s); ! 1990: ! 1991: pd->page_attrib &= ~attrib; ! 1992: ! 1993: pv_h = pg_desc_pvh(pd); ! 1994: ! 1995: while ((pmap = pv_h->pmap) != PMAP_NULL) { ! 1996: va = pv_h->va; ! 1997: ! 1998: simple_lock(&pmap->lock); ! 1999: ! 2000: PMAP_UPDATE_TLBS(pmap, va, va + PAGE_SIZE); ! 2001: ! 2002: pte = pmap_pt_entry(pmap, va); ! 2003: if (pte != PT_ENTRY_NULL) { ! 2004: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 2005: if (attrib & PG_DIRTY) ! 2006: pte->dirty = 0; ! 2007: if (attrib & PG_REFER) ! 2008: pte->refer = 0; ! 2009: } ! 2010: } ! 2011: ! 2012: simple_unlock(&pmap->lock); ! 2013: ! 2014: if ((pv_h = pv_h->next) == PV_ENTRY_NULL) ! 2015: break; ! 2016: } ! 2017: ! 2018: PMAP_WRITE_UNLOCK(s); ! 2019: } ! 2020: ! 2021: /* ! 2022: * Check for the specified attributes for the ! 2023: * physical page. if all bits are true in ! 2024: * the pmap_page_attributes table, we can trust ! 2025: * it. otherwise, we must check the address ! 2026: * translation tables ourselves. Note that we ! 2027: * DO NOT have to flush the entry from the TLB ! 2028: * before looking at the address translation ! 2029: * table since the TLB is write-through for the bits. ! 2030: */ ! 2031: static ! 2032: boolean_t ! 2033: pmap_check_page_attrib( ! 2034: vm_offset_t pa, ! 2035: int attrib ! 2036: ) ! 2037: { ! 2038: pt_entry_t *pte; ! 2039: pv_entry_t pv_h; ! 2040: pmap_t pmap; ! 2041: vm_offset_t va; ! 2042: pg_desc_t *pd; ! 2043: int i, s; ! 2044: ! 2045: pd = pg_desc(pa); ! 2046: ! 2047: if ((pd->page_attrib & attrib) == attrib) ! 2048: return (TRUE); ! 2049: ! 2050: pv_h = pg_desc_pvh(pd); ! 2051: ! 2052: PMAP_WRITE_LOCK(s); ! 2053: ! 2054: while ((pmap = pv_h->pmap) != PMAP_NULL) { ! 2055: va = pv_h->va; ! 2056: ! 2057: simple_lock(&pmap->lock); ! 2058: ! 2059: pte = pmap_pt_entry(pmap, va); ! 2060: if (pte != PT_ENTRY_NULL) { ! 2061: for (i = ptes_per_vm_page; i-- > 0; pte++) { ! 2062: if (pte->dirty) ! 2063: pd->page_attrib |= PG_DIRTY; ! 2064: if (pte->refer) ! 2065: pd->page_attrib |= PG_REFER; ! 2066: } ! 2067: ! 2068: if ((pd->page_attrib & attrib) == attrib) { ! 2069: simple_unlock(&pmap->lock); ! 2070: ! 2071: PMAP_WRITE_UNLOCK(s); ! 2072: ! 2073: return (TRUE); ! 2074: } ! 2075: } ! 2076: ! 2077: simple_unlock(&pmap->lock); ! 2078: ! 2079: if ((pv_h = pv_h->next) == PV_ENTRY_NULL) ! 2080: break; ! 2081: } ! 2082: ! 2083: PMAP_WRITE_UNLOCK(s); ! 2084: ! 2085: return (FALSE); ! 2086: } ! 2087: ! 2088: /* ! 2089: * Dummy routine to satisfy external reference. ! 2090: */ ! 2091: void ! 2092: pmap_update_interrupt( ! 2093: void ! 2094: ) ! 2095: { ! 2096: /* should never be called. */ ! 2097: panic("pmap_update_interrupt"); ! 2098: } ! 2099: ! 2100: /* ! 2101: * Lower the permission for all mappings to a given page. ! 2102: */ ! 2103: void ! 2104: pmap_page_protect( ! 2105: vm_offset_t pa, ! 2106: vm_prot_t prot ! 2107: ) ! 2108: { ! 2109: switch (prot) { ! 2110: case VM_PROT_READ: ! 2111: case VM_PROT_READ|VM_PROT_EXECUTE: ! 2112: pmap_copy_on_write(pa); ! 2113: break; ! 2114: ! 2115: case VM_PROT_ALL: ! 2116: break; ! 2117: ! 2118: default: ! 2119: pmap_remove_all(pa); ! 2120: break; ! 2121: } ! 2122: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.