|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: vm/vm_page.c ! 31: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 32: * ! 33: * Resident memory management module. ! 34: */ ! 35: #include <cpus.h> ! 36: ! 37: #include <mach/vm_prot.h> ! 38: #include <kern/counters.h> ! 39: #include <kern/sched_prim.h> ! 40: #include <kern/task.h> ! 41: #include <kern/thread.h> ! 42: #include <mach/vm_statistics.h> ! 43: #include "vm_param.h" ! 44: #include <kern/zalloc.h> ! 45: #include <vm/pmap.h> ! 46: #include <vm/vm_map.h> ! 47: #include <vm/vm_page.h> ! 48: #include <vm/vm_pageout.h> ! 49: #include <vm/vm_kern.h> ! 50: ! 51: #include <mach_vm_debug.h> ! 52: #if MACH_VM_DEBUG ! 53: #include <mach/kern_return.h> ! 54: #include <mach_debug/hash_info.h> ! 55: #include <vm/vm_user.h> ! 56: #endif ! 57: ! 58: /* ! 59: * Associated with eacn page of user-allocatable memory is a ! 60: * page structure. ! 61: */ ! 62: ! 63: /* ! 64: * These variables record the values returned by vm_page_bootstrap, ! 65: * for debugging purposes. The implementation of pmap_steal_memory ! 66: * and pmap_startup here also uses them internally. ! 67: */ ! 68: ! 69: vm_offset_t virtual_space_start; ! 70: vm_offset_t virtual_space_end; ! 71: ! 72: /* ! 73: * The vm_page_lookup() routine, which provides for fast ! 74: * (virtual memory object, offset) to page lookup, employs ! 75: * the following hash table. The vm_page_{insert,remove} ! 76: * routines install and remove associations in the table. ! 77: * [This table is often called the virtual-to-physical, ! 78: * or VP, table.] ! 79: */ ! 80: typedef struct { ! 81: decl_simple_lock_data(,lock) ! 82: vm_page_t pages; ! 83: } vm_page_bucket_t; ! 84: ! 85: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */ ! 86: unsigned int vm_page_bucket_count = 0; /* How big is array? */ ! 87: unsigned int vm_page_hash_mask; /* Mask for hash function */ ! 88: ! 89: /* ! 90: * Resident page structures are initialized from ! 91: * a template (see vm_page_alloc). ! 92: * ! 93: * When adding a new field to the virtual memory ! 94: * object structure, be sure to add initialization ! 95: * (see vm_page_bootstrap). ! 96: */ ! 97: struct vm_page vm_page_template; ! 98: ! 99: /* ! 100: * Resident pages that represent real memory ! 101: * are allocated from a free list. ! 102: */ ! 103: vm_page_t vm_page_queue_free; ! 104: vm_page_t vm_page_queue_fictitious; ! 105: decl_simple_lock_data(,vm_page_queue_free_lock) ! 106: unsigned int vm_page_free_wanted; ! 107: int vm_page_queue_free_count; ! 108: int vm_page_unqueued_count; ! 109: int vm_page_fictitious_count; ! 110: int vm_page_external_count; ! 111: ! 112: unsigned int vm_page_free_count_minimum; /* debugging */ ! 113: ! 114: /* ! 115: * Occasionally, the virtual memory system uses ! 116: * resident page structures that do not refer to ! 117: * real pages, for example to leave a page with ! 118: * important state information in the VP table. ! 119: * ! 120: * These page structures are allocated the way ! 121: * most other kernel structures are. ! 122: */ ! 123: zone_t vm_page_zone; ! 124: ! 125: /* ! 126: * Fictitious pages don't have a physical address, ! 127: * but we must initialize phys_addr to something. ! 128: * For debugging, this should be a strange value ! 129: * that the pmap module can recognize in assertions. ! 130: */ ! 131: vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1; ! 132: ! 133: /* ! 134: * Resident page structures are also chained on ! 135: * queues that are used by the page replacement ! 136: * system (pageout daemon). These queues are ! 137: * defined here, but are shared by the pageout ! 138: * module. ! 139: */ ! 140: queue_head_t vm_page_queue_active; ! 141: queue_head_t vm_page_queue_inactive; ! 142: decl_simple_lock_data(,vm_page_queue_lock) ! 143: int vm_page_active_count; ! 144: int vm_page_inactive_count; ! 145: int vm_page_wire_count; ! 146: ! 147: /* ! 148: * Several page replacement parameters are also ! 149: * shared with this module, so that page allocation ! 150: * (done here in vm_page_alloc) can trigger the ! 151: * pageout daemon. ! 152: */ ! 153: int vm_page_free_target = 0; ! 154: int vm_page_free_min = 0; ! 155: int vm_page_inactive_target = 0; ! 156: int vm_page_free_reserved = 0; ! 157: int vm_page_laundry_count = 0; ! 158: int vm_page_external_limit = 0; ! 159: ! 160: ! 161: /* ! 162: * The VM system has a couple of heuristics for deciding ! 163: * that pages are "uninteresting" and should be placed ! 164: * on the inactive queue as likely candidates for replacement. ! 165: * These variables let the heuristics be controlled at run-time ! 166: * to make experimentation easier. ! 167: */ ! 168: ! 169: boolean_t vm_page_deactivate_behind = TRUE; ! 170: boolean_t vm_page_deactivate_hint = TRUE; ! 171: ! 172: /* ! 173: * vm_page_bootstrap: ! 174: * ! 175: * Initializes the resident memory module. ! 176: * ! 177: * Allocates memory for the page cells, and ! 178: * for the object/offset-to-page hash table headers. ! 179: * Each page cell is initialized and placed on the free list. ! 180: * Returns the range of available kernel virtual memory. ! 181: */ ! 182: ! 183: void vm_page_bootstrap( ! 184: vm_offset_t *startp, ! 185: vm_offset_t *endp) ! 186: { ! 187: register vm_page_t m; ! 188: int i; ! 189: ! 190: /* ! 191: * Initialize the vm_page template. ! 192: */ ! 193: ! 194: m = &vm_page_template; ! 195: m->object = VM_OBJECT_NULL; /* reset later */ ! 196: m->offset = 0; /* reset later */ ! 197: m->wire_count = 0; ! 198: ! 199: m->inactive = FALSE; ! 200: m->active = FALSE; ! 201: m->laundry = FALSE; ! 202: m->free = FALSE; ! 203: m->external = FALSE; ! 204: ! 205: m->busy = TRUE; ! 206: m->wanted = FALSE; ! 207: m->tabled = FALSE; ! 208: m->fictitious = FALSE; ! 209: m->private = FALSE; ! 210: m->absent = FALSE; ! 211: m->error = FALSE; ! 212: m->dirty = FALSE; ! 213: m->precious = FALSE; ! 214: m->reference = FALSE; ! 215: ! 216: m->phys_addr = 0; /* reset later */ ! 217: ! 218: m->page_lock = VM_PROT_NONE; ! 219: m->unlock_request = VM_PROT_NONE; ! 220: ! 221: /* ! 222: * Initialize the page queues. ! 223: */ ! 224: ! 225: simple_lock_init(&vm_page_queue_free_lock); ! 226: simple_lock_init(&vm_page_queue_lock); ! 227: ! 228: vm_page_queue_free = VM_PAGE_NULL; ! 229: vm_page_queue_fictitious = VM_PAGE_NULL; ! 230: queue_init(&vm_page_queue_active); ! 231: queue_init(&vm_page_queue_inactive); ! 232: ! 233: vm_page_free_wanted = 0; ! 234: ! 235: /* ! 236: * Allocate (and initialize) the virtual-to-physical ! 237: * table hash buckets. ! 238: * ! 239: * The number of buckets should be a power of two to ! 240: * get a good hash function. The following computation ! 241: * chooses the first power of two that is greater ! 242: * than the number of physical pages in the system. ! 243: */ ! 244: ! 245: if (vm_page_bucket_count == 0) { ! 246: unsigned int npages = pmap_free_pages(); ! 247: ! 248: vm_page_bucket_count = 1; ! 249: while (vm_page_bucket_count < npages) ! 250: vm_page_bucket_count <<= 1; ! 251: } ! 252: ! 253: vm_page_hash_mask = vm_page_bucket_count - 1; ! 254: ! 255: if (vm_page_hash_mask & vm_page_bucket_count) ! 256: printf("vm_page_bootstrap: WARNING -- strange page hash\n"); ! 257: ! 258: vm_page_buckets = (vm_page_bucket_t *) ! 259: pmap_steal_memory(vm_page_bucket_count * ! 260: sizeof(vm_page_bucket_t)); ! 261: ! 262: for (i = 0; i < vm_page_bucket_count; i++) { ! 263: register vm_page_bucket_t *bucket = &vm_page_buckets[i]; ! 264: ! 265: bucket->pages = VM_PAGE_NULL; ! 266: simple_lock_init(&bucket->lock); ! 267: } ! 268: ! 269: /* ! 270: * Steal memory for the kentry zone. ! 271: */ ! 272: ! 273: kentry_data_size = kentry_count * sizeof(struct vm_map_entry); ! 274: kentry_data = pmap_steal_memory(kentry_data_size); ! 275: ! 276: /* ! 277: * Machine-dependent code allocates the resident page table. ! 278: * It uses vm_page_init to initialize the page frames. ! 279: * The code also returns to us the virtual space available ! 280: * to the kernel. We don't trust the pmap module ! 281: * to get the alignment right. ! 282: */ ! 283: ! 284: /* pmap_startup is responsible for stealing memory for ! 285: the zone system and putting it in zdata. */ ! 286: pmap_startup(&virtual_space_start, &virtual_space_end); ! 287: virtual_space_start = round_page(virtual_space_start); ! 288: virtual_space_end = trunc_page(virtual_space_end); ! 289: ! 290: *startp = virtual_space_start; ! 291: *endp = virtual_space_end; ! 292: ! 293: /* printf("vm_page_bootstrap: %d free pages\n", vm_page_free_count);*/ ! 294: vm_page_free_count_minimum = vm_page_free_count; ! 295: } ! 296: ! 297: #ifndef MACHINE_PAGES ! 298: /* ! 299: * We implement pmap_steal_memory and pmap_startup with the help ! 300: * of two simpler functions, pmap_virtual_space and pmap_next_page. ! 301: */ ! 302: ! 303: vm_offset_t pmap_steal_memory( ! 304: vm_size_t size) ! 305: { ! 306: vm_offset_t addr, vaddr, paddr; ! 307: ! 308: /* ! 309: * We round the size to an integer multiple. ! 310: */ ! 311: ! 312: size = (size + 3) &~ 3; ! 313: ! 314: /* ! 315: * If this is the first call to pmap_steal_memory, ! 316: * we have to initialize ourself. ! 317: */ ! 318: ! 319: if (virtual_space_start == virtual_space_end) { ! 320: pmap_virtual_space(&virtual_space_start, &virtual_space_end); ! 321: ! 322: /* ! 323: * The initial values must be aligned properly, and ! 324: * we don't trust the pmap module to do it right. ! 325: */ ! 326: ! 327: virtual_space_start = round_page(virtual_space_start); ! 328: virtual_space_end = trunc_page(virtual_space_end); ! 329: } ! 330: ! 331: /* ! 332: * Allocate virtual memory for this request. ! 333: */ ! 334: ! 335: addr = virtual_space_start; ! 336: virtual_space_start += size; ! 337: ! 338: /* ! 339: * Allocate and map physical pages to back new virtual pages. ! 340: */ ! 341: ! 342: for (vaddr = round_page(addr); ! 343: vaddr < addr + size; ! 344: vaddr += PAGE_SIZE) { ! 345: paddr = pmap_grab_page(); ! 346: ! 347: /* ! 348: * XXX Logically, these mappings should be wired, ! 349: * but some pmap modules barf if they are. ! 350: */ ! 351: ! 352: pmap_enter(kernel_pmap, vaddr, paddr, ! 353: VM_PROT_READ|VM_PROT_WRITE, FALSE); ! 354: } ! 355: ! 356: return addr; ! 357: } ! 358: ! 359: #if 0 ! 360: void pmap_startup( ! 361: vm_offset_t *startp, ! 362: vm_offset_t *endp) ! 363: { ! 364: unsigned int i, npages, pages_initialized; ! 365: vm_page_t pages; ! 366: vm_offset_t paddr; ! 367: ! 368: /* ! 369: * We calculate how many page frames we will have ! 370: * and then allocate the page structures in one chunk. ! 371: */ ! 372: ! 373: npages = ((PAGE_SIZE * pmap_free_pages() + ! 374: (round_page(virtual_space_start) - virtual_space_start)) / ! 375: (PAGE_SIZE + sizeof *pages)); ! 376: ! 377: pages = (vm_page_t) pmap_steal_memory(npages * sizeof *pages); ! 378: ! 379: /* ! 380: * Initialize the page frames. ! 381: */ ! 382: ! 383: for (i = 0, pages_initialized = 0; i < npages; i++) { ! 384: if (!pmap_next_page(&paddr)) ! 385: break; ! 386: ! 387: vm_page_init(&pages[i], paddr); ! 388: pages_initialized++; ! 389: } ! 390: ! 391: /* ! 392: * Release pages in reverse order so that physical pages ! 393: * initially get allocated in ascending addresses. This keeps ! 394: * the devices (which must address physical memory) happy if ! 395: * they require several consecutive pages. ! 396: */ ! 397: ! 398: for (i = pages_initialized; i > 0; i--) { ! 399: vm_page_release(&pages[i - 1], FALSE); ! 400: } ! 401: ! 402: /* ! 403: * We have to re-align virtual_space_start, ! 404: * because pmap_steal_memory has been using it. ! 405: */ ! 406: ! 407: virtual_space_start = round_page(virtual_space_start); ! 408: ! 409: *startp = virtual_space_start; ! 410: *endp = virtual_space_end; ! 411: } ! 412: #endif ! 413: #endif /* MACHINE_PAGES */ ! 414: ! 415: /* ! 416: * Routine: vm_page_module_init ! 417: * Purpose: ! 418: * Second initialization pass, to be done after ! 419: * the basic VM system is ready. ! 420: */ ! 421: void vm_page_module_init(void) ! 422: { ! 423: vm_page_zone = zinit((vm_size_t) sizeof(struct vm_page), ! 424: VM_MAX_KERNEL_ADDRESS - VM_MIN_KERNEL_ADDRESS, ! 425: PAGE_SIZE, ! 426: /* ! 427: * This zone can be collectable, since we ! 428: * dynamically add and remove pages from the ! 429: * pool as the needs of drivers for contiguous ! 430: * memory changes. ! 431: */ ! 432: ZONE_COLLECTABLE, "vm pages"); ! 433: } ! 434: ! 435: /* ! 436: * Routine: vm_page_create ! 437: * Purpose: ! 438: * After the VM system is up, machine-dependent code ! 439: * may stumble across more physical memory. For example, ! 440: * memory that it was reserving for a frame buffer. ! 441: * vm_page_create turns this memory into available pages. ! 442: */ ! 443: ! 444: void vm_page_create( ! 445: vm_offset_t start, ! 446: vm_offset_t end) ! 447: { ! 448: vm_offset_t paddr; ! 449: vm_page_t m; ! 450: ! 451: for (paddr = round_page(start); ! 452: paddr < trunc_page(end); ! 453: paddr += PAGE_SIZE) { ! 454: m = (vm_page_t) zalloc(vm_page_zone); ! 455: if (m == VM_PAGE_NULL) ! 456: panic("vm_page_create"); ! 457: ! 458: vm_page_init(m, paddr); ! 459: vm_page_release(m, FALSE); ! 460: } ! 461: } ! 462: ! 463: /* ! 464: * vm_page_hash: ! 465: * ! 466: * Distributes the object/offset key pair among hash buckets. ! 467: * ! 468: * NOTE: To get a good hash function, the bucket count should ! 469: * be a power of two. ! 470: */ ! 471: #define vm_page_hash(object, offset) \ ! 472: (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \ ! 473: & vm_page_hash_mask) ! 474: ! 475: /* ! 476: * vm_page_insert: [ internal use only ] ! 477: * ! 478: * Inserts the given mem entry into the object/object-page ! 479: * table and object list. ! 480: * ! 481: * The object and page must be locked. ! 482: */ ! 483: ! 484: void vm_page_insert( ! 485: register vm_page_t mem, ! 486: register vm_object_t object, ! 487: register vm_offset_t offset) ! 488: { ! 489: register vm_page_bucket_t *bucket; ! 490: ! 491: VM_PAGE_CHECK(mem); ! 492: ! 493: if (mem->tabled) ! 494: panic("vm_page_insert"); ! 495: ! 496: /* ! 497: * Record the object/offset pair in this page ! 498: */ ! 499: ! 500: mem->object = object; ! 501: mem->offset = offset; ! 502: ! 503: /* ! 504: * Insert it into the object_object/offset hash table ! 505: */ ! 506: ! 507: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 508: simple_lock(&bucket->lock); ! 509: mem->next = bucket->pages; ! 510: bucket->pages = mem; ! 511: simple_unlock(&bucket->lock); ! 512: ! 513: /* ! 514: * Now link into the object's list of backed pages. ! 515: */ ! 516: ! 517: queue_enter(&object->memq, mem, vm_page_t, listq); ! 518: mem->tabled = TRUE; ! 519: ! 520: /* ! 521: * Show that the object has one more resident page. ! 522: */ ! 523: ! 524: object->resident_page_count++; ! 525: ! 526: /* ! 527: * Detect sequential access and inactivate previous page. ! 528: * We ignore busy pages. ! 529: */ ! 530: ! 531: if (vm_page_deactivate_behind && ! 532: (offset == object->last_alloc + PAGE_SIZE)) { ! 533: vm_page_t last_mem; ! 534: ! 535: last_mem = vm_page_lookup(object, object->last_alloc); ! 536: if ((last_mem != VM_PAGE_NULL) && !last_mem->busy) ! 537: vm_page_deactivate(last_mem); ! 538: } ! 539: object->last_alloc = offset; ! 540: } ! 541: ! 542: /* ! 543: * vm_page_replace: ! 544: * ! 545: * Exactly like vm_page_insert, except that we first ! 546: * remove any existing page at the given offset in object ! 547: * and we don't do deactivate-behind. ! 548: * ! 549: * The object and page must be locked. ! 550: */ ! 551: ! 552: void vm_page_replace( ! 553: register vm_page_t mem, ! 554: register vm_object_t object, ! 555: register vm_offset_t offset) ! 556: { ! 557: register vm_page_bucket_t *bucket; ! 558: ! 559: VM_PAGE_CHECK(mem); ! 560: ! 561: if (mem->tabled) ! 562: panic("vm_page_replace"); ! 563: ! 564: /* ! 565: * Record the object/offset pair in this page ! 566: */ ! 567: ! 568: mem->object = object; ! 569: mem->offset = offset; ! 570: ! 571: /* ! 572: * Insert it into the object_object/offset hash table, ! 573: * replacing any page that might have been there. ! 574: */ ! 575: ! 576: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 577: simple_lock(&bucket->lock); ! 578: if (bucket->pages) { ! 579: vm_page_t *mp = &bucket->pages; ! 580: register vm_page_t m = *mp; ! 581: do { ! 582: if (m->object == object && m->offset == offset) { ! 583: /* ! 584: * Remove page from bucket and from object, ! 585: * and return it to the free list. ! 586: */ ! 587: *mp = m->next; ! 588: queue_remove(&object->memq, m, vm_page_t, ! 589: listq); ! 590: m->tabled = FALSE; ! 591: object->resident_page_count--; ! 592: ! 593: /* ! 594: * Return page to the free list. ! 595: * Note the page is not tabled now, so this ! 596: * won't self-deadlock on the bucket lock. ! 597: */ ! 598: ! 599: vm_page_free(m); ! 600: break; ! 601: } ! 602: mp = &m->next; ! 603: } while ((m = *mp) != 0); ! 604: mem->next = bucket->pages; ! 605: } else { ! 606: mem->next = VM_PAGE_NULL; ! 607: } ! 608: bucket->pages = mem; ! 609: simple_unlock(&bucket->lock); ! 610: ! 611: /* ! 612: * Now link into the object's list of backed pages. ! 613: */ ! 614: ! 615: queue_enter(&object->memq, mem, vm_page_t, listq); ! 616: mem->tabled = TRUE; ! 617: ! 618: /* ! 619: * And show that the object has one more resident ! 620: * page. ! 621: */ ! 622: ! 623: object->resident_page_count++; ! 624: } ! 625: ! 626: /* ! 627: * vm_page_remove: [ internal use only ] ! 628: * ! 629: * Removes the given mem entry from the object/offset-page ! 630: * table and the object page list. ! 631: * ! 632: * The object and page must be locked. ! 633: */ ! 634: ! 635: void vm_page_remove( ! 636: register vm_page_t mem) ! 637: { ! 638: register vm_page_bucket_t *bucket; ! 639: register vm_page_t this; ! 640: ! 641: assert(mem->tabled); ! 642: VM_PAGE_CHECK(mem); ! 643: ! 644: /* ! 645: * Remove from the object_object/offset hash table ! 646: */ ! 647: ! 648: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)]; ! 649: simple_lock(&bucket->lock); ! 650: if ((this = bucket->pages) == mem) { ! 651: /* optimize for common case */ ! 652: ! 653: bucket->pages = mem->next; ! 654: } else { ! 655: register vm_page_t *prev; ! 656: ! 657: for (prev = &this->next; ! 658: (this = *prev) != mem; ! 659: prev = &this->next) ! 660: continue; ! 661: *prev = this->next; ! 662: } ! 663: simple_unlock(&bucket->lock); ! 664: ! 665: /* ! 666: * Now remove from the object's list of backed pages. ! 667: */ ! 668: ! 669: queue_remove(&mem->object->memq, mem, vm_page_t, listq); ! 670: ! 671: /* ! 672: * And show that the object has one fewer resident ! 673: * page. ! 674: */ ! 675: ! 676: mem->object->resident_page_count--; ! 677: ! 678: mem->tabled = FALSE; ! 679: } ! 680: ! 681: /* ! 682: * vm_page_lookup: ! 683: * ! 684: * Returns the page associated with the object/offset ! 685: * pair specified; if none is found, VM_PAGE_NULL is returned. ! 686: * ! 687: * The object must be locked. No side effects. ! 688: */ ! 689: ! 690: vm_page_t vm_page_lookup( ! 691: register vm_object_t object, ! 692: register vm_offset_t offset) ! 693: { ! 694: register vm_page_t mem; ! 695: register vm_page_bucket_t *bucket; ! 696: ! 697: /* ! 698: * Search the hash table for this object/offset pair ! 699: */ ! 700: ! 701: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 702: ! 703: simple_lock(&bucket->lock); ! 704: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) { ! 705: VM_PAGE_CHECK(mem); ! 706: if ((mem->object == object) && (mem->offset == offset)) ! 707: break; ! 708: } ! 709: simple_unlock(&bucket->lock); ! 710: return mem; ! 711: } ! 712: ! 713: /* ! 714: * vm_page_rename: ! 715: * ! 716: * Move the given memory entry from its ! 717: * current object to the specified target object/offset. ! 718: * ! 719: * The object must be locked. ! 720: */ ! 721: void vm_page_rename( ! 722: register vm_page_t mem, ! 723: register vm_object_t new_object, ! 724: vm_offset_t new_offset) ! 725: { ! 726: /* ! 727: * Changes to mem->object require the page lock because ! 728: * the pageout daemon uses that lock to get the object. ! 729: */ ! 730: ! 731: vm_page_lock_queues(); ! 732: vm_page_remove(mem); ! 733: vm_page_insert(mem, new_object, new_offset); ! 734: vm_page_unlock_queues(); ! 735: } ! 736: ! 737: /* ! 738: * vm_page_init: ! 739: * ! 740: * Initialize the fields in a new page. ! 741: * This takes a structure with random values and initializes it ! 742: * so that it can be given to vm_page_release or vm_page_insert. ! 743: */ ! 744: void vm_page_init( ! 745: vm_page_t mem, ! 746: vm_offset_t phys_addr) ! 747: { ! 748: *mem = vm_page_template; ! 749: mem->phys_addr = phys_addr; ! 750: } ! 751: ! 752: /* ! 753: * vm_page_grab_fictitious: ! 754: * ! 755: * Remove a fictitious page from the free list. ! 756: * Returns VM_PAGE_NULL if there are no free pages. ! 757: */ ! 758: ! 759: vm_page_t vm_page_grab_fictitious(void) ! 760: { ! 761: register vm_page_t m; ! 762: ! 763: simple_lock(&vm_page_queue_free_lock); ! 764: m = vm_page_queue_fictitious; ! 765: if (m != VM_PAGE_NULL) { ! 766: vm_page_fictitious_count--; ! 767: vm_page_queue_fictitious = (vm_page_t) m->pageq.next; ! 768: m->free = FALSE; ! 769: } ! 770: simple_unlock(&vm_page_queue_free_lock); ! 771: ! 772: return m; ! 773: } ! 774: ! 775: /* ! 776: * vm_page_release_fictitious: ! 777: * ! 778: * Release a fictitious page to the free list. ! 779: */ ! 780: ! 781: void vm_page_release_fictitious( ! 782: register vm_page_t m) ! 783: { ! 784: simple_lock(&vm_page_queue_free_lock); ! 785: if (m->free) ! 786: panic("vm_page_release_fictitious"); ! 787: m->free = TRUE; ! 788: m->pageq.next = (queue_entry_t) vm_page_queue_fictitious; ! 789: vm_page_queue_fictitious = m; ! 790: vm_page_fictitious_count++; ! 791: simple_unlock(&vm_page_queue_free_lock); ! 792: } ! 793: ! 794: /* ! 795: * vm_page_more_fictitious: ! 796: * ! 797: * Add more fictitious pages to the free list. ! 798: * Allowed to block. ! 799: */ ! 800: ! 801: int vm_page_fictitious_quantum = 5; ! 802: ! 803: void vm_page_more_fictitious(void) ! 804: { ! 805: register vm_page_t m; ! 806: int i; ! 807: ! 808: for (i = 0; i < vm_page_fictitious_quantum; i++) { ! 809: m = (vm_page_t) zalloc(vm_page_zone); ! 810: if (m == VM_PAGE_NULL) ! 811: panic("vm_page_more_fictitious"); ! 812: ! 813: vm_page_init(m, vm_page_fictitious_addr); ! 814: m->fictitious = TRUE; ! 815: vm_page_release_fictitious(m); ! 816: } ! 817: } ! 818: ! 819: /* ! 820: * vm_page_convert: ! 821: * ! 822: * Attempt to convert a fictitious page into a real page. ! 823: */ ! 824: ! 825: boolean_t vm_page_convert( ! 826: register vm_page_t m, ! 827: boolean_t external) ! 828: { ! 829: register vm_page_t real_m; ! 830: ! 831: real_m = vm_page_grab(external); ! 832: if (real_m == VM_PAGE_NULL) ! 833: return FALSE; ! 834: ! 835: m->phys_addr = real_m->phys_addr; ! 836: m->fictitious = FALSE; ! 837: ! 838: real_m->phys_addr = vm_page_fictitious_addr; ! 839: real_m->fictitious = TRUE; ! 840: ! 841: vm_page_release_fictitious(real_m); ! 842: return TRUE; ! 843: } ! 844: ! 845: /* ! 846: * vm_page_grab: ! 847: * ! 848: * Remove a page from the free list. ! 849: * Returns VM_PAGE_NULL if the free list is too small. ! 850: */ ! 851: ! 852: vm_page_t vm_page_grab( ! 853: boolean_t external) ! 854: { ! 855: register vm_page_t mem; ! 856: ! 857: simple_lock(&vm_page_queue_free_lock); ! 858: ! 859: /* ! 860: * Only let privileged threads (involved in pageout) ! 861: * dip into the reserved pool or exceed the limit ! 862: * for externally-managed pages. ! 863: */ ! 864: ! 865: if (((vm_page_free_count < vm_page_free_reserved) ! 866: || (external ! 867: && (vm_page_external_count > vm_page_external_limit))) ! 868: && !current_thread()->vm_privilege) { ! 869: simple_unlock(&vm_page_queue_free_lock); ! 870: return VM_PAGE_NULL; ! 871: } ! 872: ! 873: if (vm_page_queue_free == VM_PAGE_NULL) { ! 874: vm_page_grab_oskit_page(); ! 875: assert (vm_page_queue_free != VM_PAGE_NULL); ! 876: } ! 877: ! 878: --vm_page_queue_free_count; ! 879: if (vm_page_free_count < vm_page_free_count_minimum) ! 880: vm_page_free_count_minimum = vm_page_free_count; ! 881: if (external) ! 882: vm_page_external_count++; ! 883: mem = vm_page_queue_free; ! 884: vm_page_queue_free = (vm_page_t) mem->pageq.next; ! 885: mem->free = FALSE; ! 886: mem->extcounted = mem->external = external; ! 887: simple_unlock(&vm_page_queue_free_lock); ! 888: ! 889: /* ! 890: * Decide if we should poke the pageout daemon. ! 891: * We do this if the free count is less than the low ! 892: * water mark, or if the free count is less than the high ! 893: * water mark (but above the low water mark) and the inactive ! 894: * count is less than its target. ! 895: * ! 896: * We don't have the counts locked ... if they change a little, ! 897: * it doesn't really matter. ! 898: */ ! 899: ! 900: if ((vm_page_free_count < vm_page_free_min) || ! 901: ((vm_page_free_count < vm_page_free_target) && ! 902: (vm_page_inactive_count < vm_page_inactive_target)) || ! 903: vm_page_queue_free_count < vm_page_unqueued_count) ! 904: thread_wakeup((event_t) &vm_page_free_wanted); ! 905: ! 906: return mem; ! 907: } ! 908: ! 909: #if 0 ! 910: vm_offset_t vm_page_grab_phys_addr() ! 911: { ! 912: vm_page_t p = vm_page_grab(FALSE); ! 913: if (p == VM_PAGE_NULL) ! 914: return -1; ! 915: else ! 916: return p->phys_addr; ! 917: } ! 918: ! 919: /* ! 920: * vm_page_grab_contiguous_pages: ! 921: * ! 922: * Take N pages off the free list, the pages should ! 923: * cover a contiguous range of physical addresses. ! 924: * [Used by device drivers to cope with DMA limitations] ! 925: * ! 926: * Returns the page descriptors in ascending order, or ! 927: * Returns KERN_RESOURCE_SHORTAGE if it could not. ! 928: */ ! 929: ! 930: /* Biggest phys page number for the pages we handle in VM */ ! 931: ! 932: vm_size_t vm_page_big_pagenum = 0; /* Set this before call! */ ! 933: ! 934: kern_return_t ! 935: vm_page_grab_contiguous_pages( ! 936: int npages, ! 937: vm_page_t pages[], ! 938: natural_t *bits, ! 939: boolean_t external) ! 940: { ! 941: register int first_set; ! 942: int size, alloc_size; ! 943: kern_return_t ret; ! 944: vm_page_t mem, prevmem; ! 945: ! 946: #ifndef NBBY ! 947: #define NBBY 8 /* size in bits of sizeof()`s unity */ ! 948: #endif ! 949: ! 950: #define NBPEL (sizeof(natural_t)*NBBY) ! 951: ! 952: size = (vm_page_big_pagenum + NBPEL - 1) ! 953: & ~(NBPEL - 1); /* in bits */ ! 954: ! 955: size = size / NBBY; /* in bytes */ ! 956: ! 957: /* ! 958: * If we are called before the VM system is fully functional ! 959: * the invoker must provide us with the work space. [one bit ! 960: * per page starting at phys 0 and up to vm_page_big_pagenum] ! 961: */ ! 962: if (bits == 0) { ! 963: alloc_size = round_page(size); ! 964: if (kmem_alloc_wired(kernel_map, ! 965: (vm_offset_t *)&bits, ! 966: alloc_size) ! 967: != KERN_SUCCESS) ! 968: return KERN_RESOURCE_SHORTAGE; ! 969: } else ! 970: alloc_size = 0; ! 971: ! 972: bzero(bits, size); ! 973: ! 974: /* ! 975: * A very large granularity call, its rare so that is ok ! 976: */ ! 977: simple_lock(&vm_page_queue_free_lock); ! 978: ! 979: /* ! 980: * Do not dip into the reserved pool. ! 981: */ ! 982: ! 983: if ((vm_page_free_count < vm_page_free_reserved) ! 984: || (vm_page_external_count >= vm_page_external_limit)) { ! 985: simple_unlock(&vm_page_queue_free_lock); ! 986: return KERN_RESOURCE_SHORTAGE; ! 987: } ! 988: ! 989: /* ! 990: * First pass through, build a big bit-array of ! 991: * the pages that are free. It is not going to ! 992: * be too large anyways, in 4k we can fit info ! 993: * for 32k pages. ! 994: */ ! 995: mem = vm_page_queue_free; ! 996: while (mem) { ! 997: register int word_index, bit_index; ! 998: ! 999: bit_index = (mem->phys_addr >> PAGE_SHIFT); ! 1000: word_index = bit_index / NBPEL; ! 1001: bit_index = bit_index - (word_index * NBPEL); ! 1002: bits[word_index] |= 1 << bit_index; ! 1003: ! 1004: mem = (vm_page_t) mem->pageq.next; ! 1005: } ! 1006: ! 1007: /* ! 1008: * Second loop. Scan the bit array for NPAGES ! 1009: * contiguous bits. That gives us, if any, ! 1010: * the range of pages we will be grabbing off ! 1011: * the free list. ! 1012: */ ! 1013: { ! 1014: register int bits_so_far = 0, i; ! 1015: ! 1016: first_set = 0; ! 1017: ! 1018: for (i = 0; i < size; i += sizeof(natural_t)) { ! 1019: ! 1020: register natural_t v = bits[i / sizeof(natural_t)]; ! 1021: register int bitpos; ! 1022: ! 1023: /* ! 1024: * Bitscan this one word ! 1025: */ ! 1026: if (v) { ! 1027: /* ! 1028: * keep counting them beans ? ! 1029: */ ! 1030: bitpos = 0; ! 1031: ! 1032: if (bits_so_far) { ! 1033: count_ones: ! 1034: while (v & 1) { ! 1035: bitpos++; ! 1036: /* ! 1037: * got enough beans ? ! 1038: */ ! 1039: if (++bits_so_far == npages) ! 1040: goto found_em; ! 1041: v >>= 1; ! 1042: } ! 1043: /* if we are being lucky, roll again */ ! 1044: if (bitpos == NBPEL) ! 1045: continue; ! 1046: } ! 1047: ! 1048: /* ! 1049: * search for beans here ! 1050: */ ! 1051: bits_so_far = 0; ! 1052: count_zeroes: ! 1053: while ((bitpos < NBPEL) && ((v & 1) == 0)) { ! 1054: bitpos++; ! 1055: v >>= 1; ! 1056: } ! 1057: if (v & 1) { ! 1058: first_set = (i * NBBY) + bitpos; ! 1059: goto count_ones; ! 1060: } ! 1061: } ! 1062: /* ! 1063: * No luck ! 1064: */ ! 1065: bits_so_far = 0; ! 1066: } ! 1067: } ! 1068: ! 1069: /* ! 1070: * We could not find enough contiguous pages. ! 1071: */ ! 1072: not_found_em: ! 1073: simple_unlock(&vm_page_queue_free_lock); ! 1074: ! 1075: ret = KERN_RESOURCE_SHORTAGE; ! 1076: goto out; ! 1077: ! 1078: /* ! 1079: * Final pass. Now we know which pages we want. ! 1080: * Scan the list until we find them all, grab ! 1081: * pages as we go. FIRST_SET tells us where ! 1082: * in the bit-array our pages start. ! 1083: */ ! 1084: found_em: ! 1085: vm_page_free_count -= npages; ! 1086: if (vm_page_free_count < vm_page_free_count_minimum) ! 1087: vm_page_free_count_minimum = vm_page_free_count; ! 1088: if (external) ! 1089: vm_page_external_count += npages; ! 1090: { ! 1091: register vm_offset_t first_phys, last_phys; ! 1092: ! 1093: /* cache values for compare */ ! 1094: first_phys = first_set << PAGE_SHIFT; ! 1095: last_phys = first_phys + (npages << PAGE_SHIFT);/* not included */ ! 1096: ! 1097: /* running pointers */ ! 1098: mem = vm_page_queue_free; ! 1099: prevmem = VM_PAGE_NULL; ! 1100: ! 1101: while (mem) { ! 1102: ! 1103: register vm_offset_t addr; ! 1104: ! 1105: addr = mem->phys_addr; ! 1106: ! 1107: if ((addr >= first_phys) && ! 1108: (addr < last_phys)) { ! 1109: if (prevmem) ! 1110: prevmem->pageq.next = mem->pageq.next; ! 1111: pages[(addr - first_phys) >> PAGE_SHIFT] = mem; ! 1112: mem->free = FALSE; ! 1113: mem->extcounted = mem->external = external; ! 1114: /* ! 1115: * Got them all ? ! 1116: */ ! 1117: if (--npages == 0) break; ! 1118: } else ! 1119: prevmem = mem; ! 1120: ! 1121: mem = (vm_page_t) mem->pageq.next; ! 1122: } ! 1123: } ! 1124: ! 1125: simple_unlock(&vm_page_queue_free_lock); ! 1126: ! 1127: /* ! 1128: * Decide if we should poke the pageout daemon. ! 1129: * We do this if the free count is less than the low ! 1130: * water mark, or if the free count is less than the high ! 1131: * water mark (but above the low water mark) and the inactive ! 1132: * count is less than its target. ! 1133: * ! 1134: * We don't have the counts locked ... if they change a little, ! 1135: * it doesn't really matter. ! 1136: */ ! 1137: ! 1138: if ((vm_page_free_count < vm_page_free_min) || ! 1139: ((vm_page_free_count < vm_page_free_target) && ! 1140: (vm_page_inactive_count < vm_page_inactive_target))) ! 1141: thread_wakeup(&vm_page_free_wanted); ! 1142: ! 1143: ret = KERN_SUCCESS; ! 1144: out: ! 1145: if (alloc_size) ! 1146: kmem_free(kernel_map, (vm_offset_t) bits, alloc_size); ! 1147: ! 1148: return ret; ! 1149: } ! 1150: #endif ! 1151: ! 1152: /* ! 1153: * vm_page_release: ! 1154: * ! 1155: * Return a page to the free list. ! 1156: */ ! 1157: ! 1158: void vm_page_release( ! 1159: register vm_page_t mem, ! 1160: boolean_t external) ! 1161: { ! 1162: simple_lock(&vm_page_queue_free_lock); ! 1163: if (mem->free) ! 1164: panic("vm_page_release"); ! 1165: mem->free = TRUE; ! 1166: mem->pageq.next = (queue_entry_t) vm_page_queue_free; ! 1167: vm_page_queue_free = mem; ! 1168: vm_page_queue_free_count++; ! 1169: if (external) ! 1170: vm_page_external_count--; ! 1171: ! 1172: /* ! 1173: * Check if we should wake up someone waiting for page. ! 1174: * But don't bother waking them unless they can allocate. ! 1175: * ! 1176: * We wakeup only one thread, to prevent starvation. ! 1177: * Because the scheduling system handles wait queues FIFO, ! 1178: * if we wakeup all waiting threads, one greedy thread ! 1179: * can starve multiple niceguy threads. When the threads ! 1180: * all wakeup, the greedy threads runs first, grabs the page, ! 1181: * and waits for another page. It will be the first to run ! 1182: * when the next page is freed. ! 1183: * ! 1184: * However, there is a slight danger here. ! 1185: * The thread we wake might not use the free page. ! 1186: * Then the other threads could wait indefinitely ! 1187: * while the page goes unused. To forestall this, ! 1188: * the pageout daemon will keep making free pages ! 1189: * as long as vm_page_free_wanted is non-zero. ! 1190: */ ! 1191: ! 1192: if ((vm_page_free_wanted > 0) && ! 1193: (vm_page_free_count >= vm_page_free_reserved)) { ! 1194: vm_page_free_wanted--; ! 1195: thread_wakeup_one((event_t) &vm_page_queue_free_count); ! 1196: } ! 1197: ! 1198: simple_unlock(&vm_page_queue_free_lock); ! 1199: } ! 1200: ! 1201: /* ! 1202: * vm_page_wait: ! 1203: * ! 1204: * Wait for a page to become available. ! 1205: * If there are plenty of free pages, then we don't sleep. ! 1206: */ ! 1207: ! 1208: void vm_page_wait( ! 1209: void (*continuation)(void)) ! 1210: { ! 1211: ! 1212: #ifndef CONTINUATIONS ! 1213: assert (continuation == 0); ! 1214: #endif ! 1215: ! 1216: /* ! 1217: * We can't use vm_page_free_reserved to make this ! 1218: * determination. Consider: some thread might ! 1219: * need to allocate two pages. The first allocation ! 1220: * succeeds, the second fails. After the first page is freed, ! 1221: * a call to vm_page_wait must really block. ! 1222: */ ! 1223: ! 1224: simple_lock(&vm_page_queue_free_lock); ! 1225: if ((vm_page_free_count < vm_page_free_target) ! 1226: || (vm_page_external_count > vm_page_external_limit)) { ! 1227: if (vm_page_free_wanted++ == 0) ! 1228: thread_wakeup((event_t)&vm_page_free_wanted); ! 1229: assert_wait((event_t)&vm_page_queue_free_count, FALSE); ! 1230: simple_unlock(&vm_page_queue_free_lock); ! 1231: if (continuation != 0) { ! 1232: counter(c_vm_page_wait_block_user++); ! 1233: thread_block(continuation); ! 1234: } else { ! 1235: counter(c_vm_page_wait_block_kernel++); ! 1236: thread_block((void (*)(void)) 0); ! 1237: } ! 1238: } else ! 1239: simple_unlock(&vm_page_queue_free_lock); ! 1240: } ! 1241: ! 1242: /* ! 1243: * vm_page_alloc: ! 1244: * ! 1245: * Allocate and return a memory cell associated ! 1246: * with this VM object/offset pair. ! 1247: * ! 1248: * Object must be locked. ! 1249: */ ! 1250: ! 1251: vm_page_t vm_page_alloc( ! 1252: vm_object_t object, ! 1253: vm_offset_t offset) ! 1254: { ! 1255: register vm_page_t mem; ! 1256: ! 1257: mem = vm_page_grab(!object->internal); ! 1258: if (mem == VM_PAGE_NULL) ! 1259: return VM_PAGE_NULL; ! 1260: ! 1261: vm_page_lock_queues(); ! 1262: vm_page_insert(mem, object, offset); ! 1263: vm_page_unlock_queues(); ! 1264: ! 1265: return mem; ! 1266: } ! 1267: ! 1268: /* ! 1269: * vm_page_free: ! 1270: * ! 1271: * Returns the given page to the free list, ! 1272: * disassociating it with any VM object. ! 1273: * ! 1274: * Object and page queues must be locked prior to entry. ! 1275: */ ! 1276: void vm_page_free( ! 1277: register vm_page_t mem) ! 1278: { ! 1279: if (mem->free) ! 1280: panic("vm_page_free"); ! 1281: ! 1282: if (mem->tabled) ! 1283: vm_page_remove(mem); ! 1284: VM_PAGE_QUEUES_REMOVE(mem); ! 1285: ! 1286: if (mem->wire_count != 0) { ! 1287: if (!mem->private && !mem->fictitious) ! 1288: vm_page_wire_count--; ! 1289: mem->wire_count = 0; ! 1290: } ! 1291: ! 1292: if (mem->laundry) { ! 1293: vm_page_laundry_count--; ! 1294: mem->laundry = FALSE; ! 1295: } ! 1296: ! 1297: PAGE_WAKEUP_DONE(mem); ! 1298: ! 1299: if (mem->absent) ! 1300: vm_object_absent_release(mem->object); ! 1301: ! 1302: /* ! 1303: * XXX The calls to vm_page_init here are ! 1304: * really overkill. ! 1305: */ ! 1306: ! 1307: if (mem->private || mem->fictitious) { ! 1308: vm_page_init(mem, vm_page_fictitious_addr); ! 1309: mem->fictitious = TRUE; ! 1310: vm_page_release_fictitious(mem); ! 1311: } else { ! 1312: int external = mem->external && mem->extcounted; ! 1313: vm_page_init(mem, mem->phys_addr); ! 1314: vm_page_release(mem, external); ! 1315: } ! 1316: } ! 1317: ! 1318: /* ! 1319: * vm_page_wire: ! 1320: * ! 1321: * Mark this page as wired down by yet ! 1322: * another map, removing it from paging queues ! 1323: * as necessary. ! 1324: * ! 1325: * The page's object and the page queues must be locked. ! 1326: */ ! 1327: void vm_page_wire( ! 1328: register vm_page_t mem) ! 1329: { ! 1330: VM_PAGE_CHECK(mem); ! 1331: ! 1332: if (mem->wire_count == 0) { ! 1333: VM_PAGE_QUEUES_REMOVE(mem); ! 1334: if (!mem->private && !mem->fictitious) ! 1335: vm_page_wire_count++; ! 1336: } ! 1337: mem->wire_count++; ! 1338: } ! 1339: ! 1340: /* ! 1341: * vm_page_unwire: ! 1342: * ! 1343: * Release one wiring of this page, potentially ! 1344: * enabling it to be paged again. ! 1345: * ! 1346: * The page's object and the page queues must be locked. ! 1347: */ ! 1348: void vm_page_unwire( ! 1349: register vm_page_t mem) ! 1350: { ! 1351: VM_PAGE_CHECK(mem); ! 1352: ! 1353: if (--mem->wire_count == 0) { ! 1354: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq); ! 1355: vm_page_active_count++; ! 1356: mem->active = TRUE; ! 1357: if (!mem->private && !mem->fictitious) ! 1358: vm_page_wire_count--; ! 1359: } ! 1360: } ! 1361: ! 1362: /* ! 1363: * vm_page_deactivate: ! 1364: * ! 1365: * Returns the given page to the inactive list, ! 1366: * indicating that no physical maps have access ! 1367: * to this page. [Used by the physical mapping system.] ! 1368: * ! 1369: * The page queues must be locked. ! 1370: */ ! 1371: void vm_page_deactivate( ! 1372: register vm_page_t m) ! 1373: { ! 1374: VM_PAGE_CHECK(m); ! 1375: ! 1376: /* ! 1377: * This page is no longer very interesting. If it was ! 1378: * interesting (active or inactive/referenced), then we ! 1379: * clear the reference bit and (re)enter it in the ! 1380: * inactive queue. Note wired pages should not have ! 1381: * their reference bit cleared. ! 1382: */ ! 1383: ! 1384: if (m->active || (m->inactive && m->reference)) { ! 1385: if (!m->fictitious && !m->absent) ! 1386: pmap_clear_reference(m->phys_addr); ! 1387: m->reference = FALSE; ! 1388: VM_PAGE_QUEUES_REMOVE(m); ! 1389: } ! 1390: if (m->wire_count == 0 && !m->inactive) { ! 1391: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); ! 1392: m->inactive = TRUE; ! 1393: vm_page_inactive_count++; ! 1394: } ! 1395: } ! 1396: ! 1397: /* ! 1398: * vm_page_activate: ! 1399: * ! 1400: * Put the specified page on the active list (if appropriate). ! 1401: * ! 1402: * The page queues must be locked. ! 1403: */ ! 1404: ! 1405: void vm_page_activate( ! 1406: register vm_page_t m) ! 1407: { ! 1408: VM_PAGE_CHECK(m); ! 1409: ! 1410: if (m->inactive) { ! 1411: queue_remove(&vm_page_queue_inactive, m, vm_page_t, ! 1412: pageq); ! 1413: vm_page_inactive_count--; ! 1414: m->inactive = FALSE; ! 1415: } ! 1416: if (m->wire_count == 0) { ! 1417: if (m->active) ! 1418: panic("vm_page_activate: already active"); ! 1419: ! 1420: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq); ! 1421: m->active = TRUE; ! 1422: vm_page_active_count++; ! 1423: } ! 1424: } ! 1425: ! 1426: /* ! 1427: * vm_page_zero_fill: ! 1428: * ! 1429: * Zero-fill the specified page. ! 1430: */ ! 1431: void vm_page_zero_fill( ! 1432: vm_page_t m) ! 1433: { ! 1434: VM_PAGE_CHECK(m); ! 1435: ! 1436: pmap_zero_page(m->phys_addr); ! 1437: } ! 1438: ! 1439: /* ! 1440: * vm_page_copy: ! 1441: * ! 1442: * Copy one page to another ! 1443: */ ! 1444: ! 1445: void vm_page_copy( ! 1446: vm_page_t src_m, ! 1447: vm_page_t dest_m) ! 1448: { ! 1449: VM_PAGE_CHECK(src_m); ! 1450: VM_PAGE_CHECK(dest_m); ! 1451: ! 1452: pmap_copy_page(src_m->phys_addr, dest_m->phys_addr); ! 1453: } ! 1454: ! 1455: #if MACH_VM_DEBUG ! 1456: /* ! 1457: * Routine: vm_page_info ! 1458: * Purpose: ! 1459: * Return information about the global VP table. ! 1460: * Fills the buffer with as much information as possible ! 1461: * and returns the desired size of the buffer. ! 1462: * Conditions: ! 1463: * Nothing locked. The caller should provide ! 1464: * possibly-pageable memory. ! 1465: */ ! 1466: ! 1467: unsigned int ! 1468: vm_page_info( ! 1469: hash_info_bucket_t *info, ! 1470: unsigned int count) ! 1471: { ! 1472: int i; ! 1473: ! 1474: if (vm_page_bucket_count < count) ! 1475: count = vm_page_bucket_count; ! 1476: ! 1477: for (i = 0; i < count; i++) { ! 1478: vm_page_bucket_t *bucket = &vm_page_buckets[i]; ! 1479: unsigned int bucket_count = 0; ! 1480: vm_page_t m; ! 1481: ! 1482: simple_lock(&bucket->lock); ! 1483: for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next) ! 1484: bucket_count++; ! 1485: simple_unlock(&bucket->lock); ! 1486: ! 1487: /* don't touch pageable memory while holding locks */ ! 1488: info[i].hib_count = bucket_count; ! 1489: } ! 1490: ! 1491: return vm_page_bucket_count; ! 1492: } ! 1493: #endif /* MACH_VM_DEBUG */ ! 1494: ! 1495: #include <mach_kdb.h> ! 1496: #if MACH_KDB ! 1497: #define printf kdbprintf ! 1498: ! 1499: /* ! 1500: * Routine: vm_page_print [exported] ! 1501: */ ! 1502: void vm_page_print(p) ! 1503: vm_page_t p; ! 1504: { ! 1505: iprintf("Page 0x%X: object 0x%X,", (vm_offset_t) p, (vm_offset_t) p->object); ! 1506: printf(" offset 0x%X", (vm_offset_t) p->offset); ! 1507: printf("wire_count %d,", p->wire_count); ! 1508: printf(" %s", ! 1509: (p->active ? "active" : (p->inactive ? "inactive" : "loose"))); ! 1510: printf("%s", ! 1511: (p->free ? " free" : "")); ! 1512: printf("%s ", ! 1513: (p->laundry ? " laundry" : "")); ! 1514: printf("%s", ! 1515: (p->dirty ? "dirty" : "clean")); ! 1516: printf("%s", ! 1517: (p->busy ? " busy" : "")); ! 1518: printf("%s", ! 1519: (p->absent ? " absent" : "")); ! 1520: printf("%s", ! 1521: (p->error ? " error" : "")); ! 1522: printf("%s", ! 1523: (p->fictitious ? " fictitious" : "")); ! 1524: printf("%s", ! 1525: (p->private ? " private" : "")); ! 1526: printf("%s", ! 1527: (p->wanted ? " wanted" : "")); ! 1528: printf("%s,", ! 1529: (p->tabled ? "" : "not_tabled")); ! 1530: printf("phys_addr = 0x%X, lock = 0x%X, unlock_request = 0x%X\n", ! 1531: (vm_offset_t) p->phys_addr, ! 1532: (vm_offset_t) p->page_lock, ! 1533: (vm_offset_t) p->unlock_request); ! 1534: } ! 1535: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.