|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: vm/vm_page.c ! 54: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 55: * ! 56: * Resident memory management module. ! 57: */ ! 58: ! 59: #include <mach/vm_prot.h> ! 60: #include <mach/vm_statistics.h> ! 61: #include <kern/counters.h> ! 62: #include <kern/sched_prim.h> ! 63: #include <kern/task.h> ! 64: #include <kern/thread.h> ! 65: #include <kern/zalloc.h> ! 66: #include <kern/xpr.h> ! 67: #include <vm/pmap.h> ! 68: #include <vm/vm_init.h> ! 69: #include <vm/vm_map.h> ! 70: #include <vm/vm_page.h> ! 71: #include <vm/vm_pageout.h> ! 72: #include <vm/vm_kern.h> /* kernel_memory_allocate() */ ! 73: #include <kern/misc_protos.h> ! 74: #include <zone_debug.h> ! 75: #include <vm/cpm.h> ! 76: ! 77: /* ! 78: * Associated with page of user-allocatable memory is a ! 79: * page structure. ! 80: */ ! 81: ! 82: /* ! 83: * These variables record the values returned by vm_page_bootstrap, ! 84: * for debugging purposes. The implementation of pmap_steal_memory ! 85: * and pmap_startup here also uses them internally. ! 86: */ ! 87: ! 88: vm_offset_t virtual_space_start; ! 89: vm_offset_t virtual_space_end; ! 90: int vm_page_pages; ! 91: ! 92: /* ! 93: * The vm_page_lookup() routine, which provides for fast ! 94: * (virtual memory object, offset) to page lookup, employs ! 95: * the following hash table. The vm_page_{insert,remove} ! 96: * routines install and remove associations in the table. ! 97: * [This table is often called the virtual-to-physical, ! 98: * or VP, table.] ! 99: */ ! 100: typedef struct { ! 101: vm_page_t pages; ! 102: #if MACH_PAGE_HASH_STATS ! 103: int cur_count; /* current count */ ! 104: int hi_count; /* high water mark */ ! 105: #endif /* MACH_PAGE_HASH_STATS */ ! 106: } vm_page_bucket_t; ! 107: ! 108: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */ ! 109: unsigned int vm_page_bucket_count = 0; /* How big is array? */ ! 110: unsigned int vm_page_hash_mask; /* Mask for hash function */ ! 111: unsigned int vm_page_hash_shift; /* Shift for hash function */ ! 112: decl_simple_lock_data(,vm_page_bucket_lock) ! 113: ! 114: #if MACH_PAGE_HASH_STATS ! 115: /* This routine is only for debug. It is intended to be called by ! 116: * hand by a developer using a kernel debugger. This routine prints ! 117: * out vm_page_hash table statistics to the kernel debug console. ! 118: */ ! 119: void ! 120: hash_debug(void) ! 121: { ! 122: int i; ! 123: int numbuckets = 0; ! 124: int highsum = 0; ! 125: int maxdepth = 0; ! 126: ! 127: for (i = 0; i < vm_page_bucket_count; i++) { ! 128: if (vm_page_buckets[i].hi_count) { ! 129: numbuckets++; ! 130: highsum += vm_page_buckets[i].hi_count; ! 131: if (vm_page_buckets[i].hi_count > maxdepth) ! 132: maxdepth = vm_page_buckets[i].hi_count; ! 133: } ! 134: } ! 135: printf("Total number of buckets: %d\n", vm_page_bucket_count); ! 136: printf("Number used buckets: %d = %d%%\n", ! 137: numbuckets, 100*numbuckets/vm_page_bucket_count); ! 138: printf("Number unused buckets: %d = %d%%\n", ! 139: vm_page_bucket_count - numbuckets, ! 140: 100*(vm_page_bucket_count-numbuckets)/vm_page_bucket_count); ! 141: printf("Sum of bucket max depth: %d\n", highsum); ! 142: printf("Average bucket depth: %d.%2d\n", ! 143: highsum/vm_page_bucket_count, ! 144: highsum%vm_page_bucket_count); ! 145: printf("Maximum bucket depth: %d\n", maxdepth); ! 146: } ! 147: #endif /* MACH_PAGE_HASH_STATS */ ! 148: ! 149: /* ! 150: * The virtual page size is currently implemented as a runtime ! 151: * variable, but is constant once initialized using vm_set_page_size. ! 152: * This initialization must be done in the machine-dependent ! 153: * bootstrap sequence, before calling other machine-independent ! 154: * initializations. ! 155: * ! 156: * All references to the virtual page size outside this ! 157: * module must use the PAGE_SIZE, PAGE_MASK and PAGE_SHIFT ! 158: * constants. ! 159: */ ! 160: #ifndef PAGE_SIZE_FIXED ! 161: vm_size_t page_size = 4096; ! 162: vm_size_t page_mask = 4095; ! 163: int page_shift = 12; ! 164: #endif /* PAGE_SIZE_FIXED */ ! 165: ! 166: /* ! 167: * Resident page structures are initialized from ! 168: * a template (see vm_page_alloc). ! 169: * ! 170: * When adding a new field to the virtual memory ! 171: * object structure, be sure to add initialization ! 172: * (see vm_page_bootstrap). ! 173: */ ! 174: struct vm_page vm_page_template; ! 175: ! 176: /* ! 177: * Resident pages that represent real memory ! 178: * are allocated from a free list. ! 179: */ ! 180: vm_page_t vm_page_queue_free; ! 181: vm_page_t vm_page_queue_fictitious; ! 182: decl_mutex_data(,vm_page_queue_free_lock) ! 183: unsigned int vm_page_free_wanted; ! 184: int vm_page_free_count; ! 185: int vm_page_fictitious_count; ! 186: ! 187: unsigned int vm_page_free_count_minimum; /* debugging */ ! 188: ! 189: /* ! 190: * Occasionally, the virtual memory system uses ! 191: * resident page structures that do not refer to ! 192: * real pages, for example to leave a page with ! 193: * important state information in the VP table. ! 194: * ! 195: * These page structures are allocated the way ! 196: * most other kernel structures are. ! 197: */ ! 198: zone_t vm_page_zone; ! 199: decl_mutex_data(,vm_page_alloc_lock) ! 200: ! 201: /* ! 202: * Fictitious pages don't have a physical address, ! 203: * but we must initialize phys_addr to something. ! 204: * For debugging, this should be a strange value ! 205: * that the pmap module can recognize in assertions. ! 206: */ ! 207: vm_offset_t vm_page_fictitious_addr = (vm_offset_t) -1; ! 208: ! 209: /* ! 210: * Resident page structures are also chained on ! 211: * queues that are used by the page replacement ! 212: * system (pageout daemon). These queues are ! 213: * defined here, but are shared by the pageout ! 214: * module. ! 215: */ ! 216: queue_head_t vm_page_queue_active; ! 217: queue_head_t vm_page_queue_inactive; ! 218: decl_mutex_data(,vm_page_queue_lock) ! 219: int vm_page_active_count; ! 220: int vm_page_inactive_count; ! 221: int vm_page_wire_count; ! 222: int vm_page_gobble_count = 0; ! 223: int vm_page_wire_count_warning = 0; ! 224: int vm_page_gobble_count_warning = 0; ! 225: ! 226: /* the following fields are protected by the vm_page_queue_lock */ ! 227: queue_head_t vm_page_queue_limbo; ! 228: int vm_page_limbo_count = 0; /* total pages in limbo */ ! 229: int vm_page_limbo_real_count = 0; /* real pages in limbo */ ! 230: int vm_page_pin_count = 0; /* number of pinned pages */ ! 231: ! 232: decl_simple_lock_data(,vm_page_preppin_lock) ! 233: ! 234: /* ! 235: * Several page replacement parameters are also ! 236: * shared with this module, so that page allocation ! 237: * (done here in vm_page_alloc) can trigger the ! 238: * pageout daemon. ! 239: */ ! 240: int vm_page_free_target = 0; ! 241: int vm_page_free_min = 0; ! 242: int vm_page_inactive_target = 0; ! 243: int vm_page_free_reserved = 0; ! 244: int vm_page_laundry_count = 0; ! 245: ! 246: /* ! 247: * The VM system has a couple of heuristics for deciding ! 248: * that pages are "uninteresting" and should be placed ! 249: * on the inactive queue as likely candidates for replacement. ! 250: * These variables let the heuristics be controlled at run-time ! 251: * to make experimentation easier. ! 252: */ ! 253: ! 254: boolean_t vm_page_deactivate_hint = TRUE; ! 255: ! 256: /* ! 257: * Definition for automatic physical memory reservation. Declared in ! 258: * vm_page.h, defined here. See vm_page.h for details. There's an ! 259: * extra zero entry to allow the code to compile if there are no requests ! 260: * for physical memory allocation; pmem_reserve_ctl_size is decremented ! 261: * by one to compensate. ! 262: */ ! 263: #include <flipc.h> ! 264: #if FLIPC ! 265: #include <flipc/flipc_usermsg.h> ! 266: #endif ! 267: ! 268: struct pmem_reserve pmem_reserve_ctl_array[] = { ! 269: #if FLIPC ! 270: { &flipc_cb_length, (vm_offset_t *) &flipc_cb_base }, ! 271: #endif ! 272: { 0, (vm_offset_t *) 0 } ! 273: }; ! 274: ! 275: struct pmem_reserve *pmem_reserve_ctl = &pmem_reserve_ctl_array[0]; ! 276: ! 277: int pmem_reserve_ctl_size = ! 278: (sizeof(pmem_reserve_ctl_array) / sizeof(struct pmem_reserve)) - 1; ! 279: ! 280: /* ! 281: * vm_set_page_size: ! 282: * ! 283: * Sets the page size, perhaps based upon the memory ! 284: * size. Must be called before any use of page-size ! 285: * dependent functions. ! 286: * ! 287: * Sets page_shift and page_mask from page_size. ! 288: */ ! 289: void ! 290: vm_set_page_size(void) ! 291: { ! 292: #ifndef PAGE_SIZE_FIXED ! 293: page_mask = page_size - 1; ! 294: ! 295: if ((page_mask & page_size) != 0) ! 296: panic("vm_set_page_size: page size not a power of two"); ! 297: ! 298: for (page_shift = 0; ; page_shift++) ! 299: if ((1 << page_shift) == page_size) ! 300: break; ! 301: #endif /* PAGE_SIZE_FIXED */ ! 302: } ! 303: ! 304: /* ! 305: * vm_page_bootstrap: ! 306: * ! 307: * Initializes the resident memory module. ! 308: * ! 309: * Allocates memory for the page cells, and ! 310: * for the object/offset-to-page hash table headers. ! 311: * Each page cell is initialized and placed on the free list. ! 312: * Returns the range of available kernel virtual memory. ! 313: */ ! 314: ! 315: void ! 316: vm_page_bootstrap( ! 317: vm_offset_t *startp, ! 318: vm_offset_t *endp) ! 319: { ! 320: register vm_page_t m; ! 321: int i; ! 322: unsigned int log1; ! 323: unsigned int log2; ! 324: unsigned int size; ! 325: ! 326: /* ! 327: * Initialize the vm_page template. ! 328: */ ! 329: ! 330: m = &vm_page_template; ! 331: m->object = VM_OBJECT_NULL; /* reset later */ ! 332: m->offset = 0; /* reset later */ ! 333: m->wire_count = 0; ! 334: ! 335: m->inactive = FALSE; ! 336: m->active = FALSE; ! 337: m->laundry = FALSE; ! 338: m->free = FALSE; ! 339: m->reference = FALSE; ! 340: m->pageout = FALSE; ! 341: m->list_req_pending = FALSE; ! 342: ! 343: m->busy = TRUE; ! 344: m->wanted = FALSE; ! 345: m->tabled = FALSE; ! 346: m->fictitious = FALSE; ! 347: m->private = FALSE; ! 348: m->absent = FALSE; ! 349: m->error = FALSE; ! 350: m->dirty = FALSE; ! 351: m->cleaning = FALSE; ! 352: m->precious = FALSE; ! 353: m->clustered = FALSE; ! 354: m->lock_supplied = FALSE; ! 355: m->unusual = FALSE; ! 356: m->restart = FALSE; ! 357: m->limbo = FALSE; ! 358: ! 359: m->phys_addr = 0; /* reset later */ ! 360: ! 361: m->page_lock = VM_PROT_NONE; ! 362: m->unlock_request = VM_PROT_NONE; ! 363: m->page_error = KERN_SUCCESS; ! 364: ! 365: /* ! 366: * Initialize the page queues. ! 367: */ ! 368: ! 369: mutex_init(&vm_page_queue_free_lock, ETAP_VM_PAGEQ_FREE); ! 370: mutex_init(&vm_page_queue_lock, ETAP_VM_PAGEQ); ! 371: simple_lock_init(&vm_page_preppin_lock, ETAP_VM_PREPPIN); ! 372: ! 373: vm_page_queue_free = VM_PAGE_NULL; ! 374: vm_page_queue_fictitious = VM_PAGE_NULL; ! 375: queue_init(&vm_page_queue_active); ! 376: queue_init(&vm_page_queue_inactive); ! 377: queue_init(&vm_page_queue_limbo); ! 378: ! 379: vm_page_free_wanted = 0; ! 380: ! 381: /* ! 382: * Steal memory for the map and zone subsystems. ! 383: */ ! 384: ! 385: vm_map_steal_memory(); ! 386: zone_steal_memory(); ! 387: ! 388: /* ! 389: * Allocate (and initialize) the virtual-to-physical ! 390: * table hash buckets. ! 391: * ! 392: * The number of buckets should be a power of two to ! 393: * get a good hash function. The following computation ! 394: * chooses the first power of two that is greater ! 395: * than the number of physical pages in the system. ! 396: */ ! 397: ! 398: simple_lock_init(&vm_page_bucket_lock, ETAP_VM_BUCKET); ! 399: ! 400: if (vm_page_bucket_count == 0) { ! 401: unsigned int npages = pmap_free_pages(); ! 402: ! 403: vm_page_bucket_count = 1; ! 404: while (vm_page_bucket_count < npages) ! 405: vm_page_bucket_count <<= 1; ! 406: } ! 407: ! 408: vm_page_hash_mask = vm_page_bucket_count - 1; ! 409: ! 410: /* ! 411: * Calculate object shift value for hashing algorithm: ! 412: * O = log2(sizeof(struct vm_object)) ! 413: * B = log2(vm_page_bucket_count) ! 414: * hash shifts the object left by ! 415: * B/2 - O ! 416: */ ! 417: size = vm_page_bucket_count; ! 418: for (log1 = 0; size > 1; log1++) ! 419: size /= 2; ! 420: size = sizeof(struct vm_object); ! 421: for (log2 = 0; size > 1; log2++) ! 422: size /= 2; ! 423: vm_page_hash_shift = log1/2 - log2 + 1; ! 424: ! 425: if (vm_page_hash_mask & vm_page_bucket_count) ! 426: printf("vm_page_bootstrap: WARNING -- strange page hash\n"); ! 427: ! 428: vm_page_buckets = (vm_page_bucket_t *) ! 429: pmap_steal_memory(vm_page_bucket_count * ! 430: sizeof(vm_page_bucket_t)); ! 431: ! 432: for (i = 0; i < vm_page_bucket_count; i++) { ! 433: register vm_page_bucket_t *bucket = &vm_page_buckets[i]; ! 434: ! 435: bucket->pages = VM_PAGE_NULL; ! 436: #if MACH_PAGE_HASH_STATS ! 437: bucket->cur_count = 0; ! 438: bucket->hi_count = 0; ! 439: #endif /* MACH_PAGE_HASH_STATS */ ! 440: } ! 441: ! 442: /* ! 443: * Machine-dependent code allocates the resident page table. ! 444: * It uses vm_page_init to initialize the page frames. ! 445: * The code also returns to us the virtual space available ! 446: * to the kernel. We don't trust the pmap module ! 447: * to get the alignment right. ! 448: */ ! 449: ! 450: pmap_startup(&virtual_space_start, &virtual_space_end); ! 451: virtual_space_start = round_page(virtual_space_start); ! 452: virtual_space_end = trunc_page(virtual_space_end); ! 453: ! 454: *startp = virtual_space_start; ! 455: *endp = virtual_space_end; ! 456: ! 457: /* ! 458: * Compute the initial "wire" count. ! 459: * Up until now, the pages which have been set aside are not under ! 460: * the VM system's control, so although they aren't explicitly ! 461: * wired, they nonetheless can't be moved. At this moment, ! 462: * all VM managed pages are "free", courtesy of pmap_startup. ! 463: */ ! 464: vm_page_wire_count = atop(mem_size) - vm_page_free_count; /* initial value */ ! 465: ! 466: printf("vm_page_bootstrap: %d free pages\n", vm_page_free_count); ! 467: vm_page_free_count_minimum = vm_page_free_count; ! 468: } ! 469: ! 470: #ifndef MACHINE_PAGES ! 471: /* ! 472: * We implement pmap_steal_memory and pmap_startup with the help ! 473: * of two simpler functions, pmap_virtual_space and pmap_next_page. ! 474: */ ! 475: ! 476: vm_offset_t ! 477: pmap_steal_memory( ! 478: vm_size_t size) ! 479: { ! 480: vm_offset_t addr, vaddr, paddr; ! 481: ! 482: /* ! 483: * We round the size to a round multiple. ! 484: */ ! 485: ! 486: size = (size + sizeof (void *) - 1) &~ (sizeof (void *) - 1); ! 487: ! 488: /* ! 489: * If this is the first call to pmap_steal_memory, ! 490: * we have to initialize ourself. ! 491: */ ! 492: ! 493: if (virtual_space_start == virtual_space_end) { ! 494: pmap_virtual_space(&virtual_space_start, &virtual_space_end); ! 495: ! 496: /* ! 497: * The initial values must be aligned properly, and ! 498: * we don't trust the pmap module to do it right. ! 499: */ ! 500: ! 501: virtual_space_start = round_page(virtual_space_start); ! 502: virtual_space_end = trunc_page(virtual_space_end); ! 503: } ! 504: ! 505: /* ! 506: * Allocate virtual memory for this request. ! 507: */ ! 508: ! 509: addr = virtual_space_start; ! 510: virtual_space_start += size; ! 511: ! 512: kprintf("pmap_steal_memory: %08X - %08X; size=%08X\n", addr, virtual_space_start, size); /* (TEST/DEBUG) */ ! 513: ! 514: /* ! 515: * Allocate and map physical pages to back new virtual pages. ! 516: */ ! 517: ! 518: for (vaddr = round_page(addr); ! 519: vaddr < addr + size; ! 520: vaddr += PAGE_SIZE) { ! 521: if (!pmap_next_page(&paddr)) ! 522: panic("pmap_steal_memory"); ! 523: ! 524: /* ! 525: * XXX Logically, these mappings should be wired, ! 526: * but some pmap modules barf if they are. ! 527: */ ! 528: ! 529: pmap_enter(kernel_pmap, vaddr, paddr, ! 530: VM_PROT_READ|VM_PROT_WRITE, FALSE); ! 531: /* ! 532: * Account for newly stolen memory ! 533: */ ! 534: vm_page_wire_count++; ! 535: ! 536: } ! 537: ! 538: return addr; ! 539: } ! 540: ! 541: void ! 542: pmap_startup( ! 543: vm_offset_t *startp, ! 544: vm_offset_t *endp) ! 545: { ! 546: unsigned int i, npages, pages_initialized; ! 547: vm_page_t pages; ! 548: vm_offset_t paddr; ! 549: ! 550: /* ! 551: * We calculate how many page frames we will have ! 552: * and then allocate the page structures in one chunk. ! 553: */ ! 554: ! 555: npages = ((PAGE_SIZE * pmap_free_pages() + ! 556: (round_page(virtual_space_start) - virtual_space_start)) / ! 557: (PAGE_SIZE + sizeof *pages)); ! 558: ! 559: pages = (vm_page_t) pmap_steal_memory(npages * sizeof *pages); ! 560: ! 561: /* ! 562: * Initialize the page frames. ! 563: */ ! 564: ! 565: for (i = 0, pages_initialized = 0; i < npages; i++) { ! 566: if (!pmap_next_page(&paddr)) ! 567: break; ! 568: ! 569: vm_page_init(&pages[i], paddr); ! 570: vm_page_pages++; ! 571: pages_initialized++; ! 572: } ! 573: ! 574: /* ! 575: * Release pages in reverse order so that physical pages ! 576: * initially get allocated in ascending addresses. This keeps ! 577: * the devices (which must address physical memory) happy if ! 578: * they require several consecutive pages. ! 579: */ ! 580: ! 581: for (i = pages_initialized; i > 0; i--) { ! 582: vm_page_release(&pages[i - 1]); ! 583: } ! 584: ! 585: /* ! 586: * We have to re-align virtual_space_start, ! 587: * because pmap_steal_memory has been using it. ! 588: */ ! 589: ! 590: virtual_space_start = round_page(virtual_space_start); ! 591: ! 592: *startp = virtual_space_start; ! 593: *endp = virtual_space_end; ! 594: } ! 595: #endif /* MACHINE_PAGES */ ! 596: ! 597: /* ! 598: * Routine: vm_page_module_init ! 599: * Purpose: ! 600: * Second initialization pass, to be done after ! 601: * the basic VM system is ready. ! 602: */ ! 603: void ! 604: vm_page_module_init(void) ! 605: { ! 606: vm_page_zone = zinit((vm_size_t) sizeof(struct vm_page), ! 607: 0, PAGE_SIZE, "vm pages"); ! 608: ! 609: #if ZONE_DEBUG ! 610: zone_debug_disable(vm_page_zone); ! 611: #endif /* ZONE_DEBUG */ ! 612: ! 613: zone_change(vm_page_zone, Z_EXPAND, FALSE); ! 614: zone_change(vm_page_zone, Z_EXHAUST, TRUE); ! 615: zone_change(vm_page_zone, Z_FOREIGN, TRUE); ! 616: ! 617: /* ! 618: * Adjust zone statistics to account for the real pages allocated ! 619: * in vm_page_create(). [Q: is this really what we want?] ! 620: */ ! 621: vm_page_zone->count += vm_page_pages; ! 622: vm_page_zone->cur_size += vm_page_pages * vm_page_zone->elem_size; ! 623: ! 624: mutex_init(&vm_page_alloc_lock, ETAP_VM_PAGE_ALLOC); ! 625: } ! 626: ! 627: /* ! 628: * Routine: vm_page_create ! 629: * Purpose: ! 630: * After the VM system is up, machine-dependent code ! 631: * may stumble across more physical memory. For example, ! 632: * memory that it was reserving for a frame buffer. ! 633: * vm_page_create turns this memory into available pages. ! 634: */ ! 635: ! 636: void ! 637: vm_page_create( ! 638: vm_offset_t start, ! 639: vm_offset_t end) ! 640: { ! 641: vm_offset_t paddr; ! 642: vm_page_t m; ! 643: ! 644: for (paddr = round_page(start); ! 645: paddr < trunc_page(end); ! 646: paddr += PAGE_SIZE) { ! 647: while ((m = (vm_page_t) vm_page_grab_fictitious()) ! 648: == VM_PAGE_NULL) ! 649: vm_page_more_fictitious(); ! 650: ! 651: vm_page_init(m, paddr); ! 652: vm_page_pages++; ! 653: vm_page_release(m); ! 654: } ! 655: } ! 656: ! 657: /* ! 658: * vm_page_hash: ! 659: * ! 660: * Distributes the object/offset key pair among hash buckets. ! 661: * ! 662: * NOTE: To get a good hash function, the bucket count should ! 663: * be a power of two. ! 664: */ ! 665: #define vm_page_hash(object, offset) (\ ! 666: ( ((natural_t)(vm_offset_t)object<<vm_page_hash_shift) + (natural_t)atop(offset))\ ! 667: & vm_page_hash_mask) ! 668: ! 669: /* ! 670: * vm_page_insert: [ internal use only ] ! 671: * ! 672: * Inserts the given mem entry into the object/object-page ! 673: * table and object list. ! 674: * ! 675: * The object must be locked. ! 676: */ ! 677: ! 678: void ! 679: vm_page_insert( ! 680: register vm_page_t mem, ! 681: register vm_object_t object, ! 682: register vm_offset_t offset) ! 683: { ! 684: register vm_page_bucket_t *bucket; ! 685: ! 686: XPR(XPR_VM_PAGE, ! 687: "vm_page_insert, object 0x%X offset 0x%X page 0x%X\n", ! 688: (integer_t)object, (integer_t)offset, (integer_t)mem, 0,0); ! 689: ! 690: VM_PAGE_CHECK(mem); ! 691: ! 692: if (mem->tabled) ! 693: panic("vm_page_insert"); ! 694: ! 695: assert(!object->internal || offset < object->size); ! 696: ! 697: /* only insert "pageout" pages into "pageout" objects, ! 698: * and normal pages into normal objects */ ! 699: assert(object->pageout == mem->pageout); ! 700: ! 701: /* ! 702: * Record the object/offset pair in this page ! 703: */ ! 704: ! 705: mem->object = object; ! 706: mem->offset = offset; ! 707: ! 708: /* ! 709: * Insert it into the object_object/offset hash table ! 710: */ ! 711: ! 712: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 713: simple_lock(&vm_page_bucket_lock); ! 714: mem->next = bucket->pages; ! 715: bucket->pages = mem; ! 716: #if MACH_PAGE_HASH_STATS ! 717: if (++bucket->cur_count > bucket->hi_count) ! 718: bucket->hi_count = bucket->cur_count; ! 719: #endif /* MACH_PAGE_HASH_STATS */ ! 720: simple_unlock(&vm_page_bucket_lock); ! 721: ! 722: /* ! 723: * Now link into the object's list of backed pages. ! 724: */ ! 725: ! 726: queue_enter(&object->memq, mem, vm_page_t, listq); ! 727: mem->tabled = TRUE; ! 728: ! 729: /* ! 730: * Show that the object has one more resident page. ! 731: */ ! 732: ! 733: object->resident_page_count++; ! 734: } ! 735: ! 736: /* ! 737: * vm_page_replace: ! 738: * ! 739: * Exactly like vm_page_insert, except that we first ! 740: * remove any existing page at the given offset in object. ! 741: * ! 742: * The object and page queues must be locked. ! 743: */ ! 744: ! 745: void ! 746: vm_page_replace( ! 747: register vm_page_t mem, ! 748: register vm_object_t object, ! 749: register vm_offset_t offset) ! 750: { ! 751: register vm_page_bucket_t *bucket; ! 752: ! 753: VM_PAGE_CHECK(mem); ! 754: ! 755: if (mem->tabled) ! 756: panic("vm_page_replace"); ! 757: ! 758: /* ! 759: * Record the object/offset pair in this page ! 760: */ ! 761: ! 762: mem->object = object; ! 763: mem->offset = offset; ! 764: ! 765: /* ! 766: * Insert it into the object_object/offset hash table, ! 767: * replacing any page that might have been there. ! 768: */ ! 769: ! 770: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 771: simple_lock(&vm_page_bucket_lock); ! 772: if (bucket->pages) { ! 773: vm_page_t *mp = &bucket->pages; ! 774: register vm_page_t m = *mp; ! 775: do { ! 776: if (m->object == object && m->offset == offset) { ! 777: /* ! 778: * Remove page from bucket and from object, ! 779: * and return it to the free list. ! 780: */ ! 781: *mp = m->next; ! 782: queue_remove(&object->memq, m, vm_page_t, ! 783: listq); ! 784: m->tabled = FALSE; ! 785: object->resident_page_count--; ! 786: ! 787: /* ! 788: * Return page to the free list. ! 789: * Note the page is not tabled now, so this ! 790: * won't self-deadlock on the bucket lock. ! 791: */ ! 792: ! 793: vm_page_free(m); ! 794: break; ! 795: } ! 796: mp = &m->next; ! 797: } while (m = *mp); ! 798: mem->next = bucket->pages; ! 799: } else { ! 800: mem->next = VM_PAGE_NULL; ! 801: } ! 802: bucket->pages = mem; ! 803: simple_unlock(&vm_page_bucket_lock); ! 804: ! 805: /* ! 806: * Now link into the object's list of backed pages. ! 807: */ ! 808: ! 809: queue_enter(&object->memq, mem, vm_page_t, listq); ! 810: mem->tabled = TRUE; ! 811: ! 812: /* ! 813: * And show that the object has one more resident ! 814: * page. ! 815: */ ! 816: ! 817: object->resident_page_count++; ! 818: } ! 819: ! 820: /* ! 821: * vm_page_remove: [ internal use only ] ! 822: * ! 823: * Removes the given mem entry from the object/offset-page ! 824: * table and the object page list. ! 825: * ! 826: * The object and page must be locked. ! 827: */ ! 828: ! 829: void ! 830: vm_page_remove( ! 831: register vm_page_t mem) ! 832: { ! 833: register vm_page_bucket_t *bucket; ! 834: register vm_page_t this; ! 835: ! 836: XPR(XPR_VM_PAGE, ! 837: "vm_page_remove, object 0x%X offset 0x%X page 0x%X\n", ! 838: (integer_t)mem->object, (integer_t)mem->offset, ! 839: (integer_t)mem, 0,0); ! 840: ! 841: assert(mem->tabled); ! 842: assert(!mem->cleaning); ! 843: VM_PAGE_CHECK(mem); ! 844: ! 845: /* ! 846: * Remove from the object_object/offset hash table ! 847: */ ! 848: ! 849: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)]; ! 850: simple_lock(&vm_page_bucket_lock); ! 851: if ((this = bucket->pages) == mem) { ! 852: /* optimize for common case */ ! 853: ! 854: bucket->pages = mem->next; ! 855: } else { ! 856: register vm_page_t *prev; ! 857: ! 858: for (prev = &this->next; ! 859: (this = *prev) != mem; ! 860: prev = &this->next) ! 861: continue; ! 862: *prev = this->next; ! 863: } ! 864: #if MACH_PAGE_HASH_STATS ! 865: bucket->cur_count--; ! 866: #endif /* MACH_PAGE_HASH_STATS */ ! 867: simple_unlock(&vm_page_bucket_lock); ! 868: ! 869: /* ! 870: * Now remove from the object's list of backed pages. ! 871: */ ! 872: ! 873: queue_remove(&mem->object->memq, mem, vm_page_t, listq); ! 874: ! 875: /* ! 876: * And show that the object has one fewer resident ! 877: * page. ! 878: */ ! 879: ! 880: mem->object->resident_page_count--; ! 881: ! 882: mem->tabled = FALSE; ! 883: mem->object = VM_OBJECT_NULL; ! 884: mem->offset = 0; ! 885: } ! 886: ! 887: /* ! 888: * vm_page_lookup: ! 889: * ! 890: * Returns the page associated with the object/offset ! 891: * pair specified; if none is found, VM_PAGE_NULL is returned. ! 892: * ! 893: * The object must be locked. No side effects. ! 894: */ ! 895: ! 896: vm_page_t ! 897: vm_page_lookup( ! 898: register vm_object_t object, ! 899: register vm_offset_t offset) ! 900: { ! 901: register vm_page_t mem; ! 902: register vm_page_bucket_t *bucket; ! 903: ! 904: /* ! 905: * Search the hash table for this object/offset pair ! 906: */ ! 907: ! 908: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 909: ! 910: simple_lock(&vm_page_bucket_lock); ! 911: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) { ! 912: VM_PAGE_CHECK(mem); ! 913: if ((mem->object == object) && (mem->offset == offset)) ! 914: break; ! 915: } ! 916: simple_unlock(&vm_page_bucket_lock); ! 917: return(mem); ! 918: } ! 919: ! 920: /* ! 921: * vm_page_rename: ! 922: * ! 923: * Move the given memory entry from its ! 924: * current object to the specified target object/offset. ! 925: * ! 926: * The object must be locked. ! 927: */ ! 928: void ! 929: vm_page_rename( ! 930: register vm_page_t mem, ! 931: register vm_object_t new_object, ! 932: vm_offset_t new_offset) ! 933: { ! 934: assert(mem->object != new_object); ! 935: /* ! 936: * Changes to mem->object require the page lock because ! 937: * the pageout daemon uses that lock to get the object. ! 938: */ ! 939: ! 940: XPR(XPR_VM_PAGE, ! 941: "vm_page_rename, new object 0x%X, offset 0x%X page 0x%X\n", ! 942: (integer_t)new_object, (integer_t)new_offset, ! 943: (integer_t)mem, 0,0); ! 944: ! 945: vm_page_lock_queues(); ! 946: vm_page_remove(mem); ! 947: vm_page_insert(mem, new_object, new_offset); ! 948: vm_page_unlock_queues(); ! 949: } ! 950: ! 951: /* ! 952: * vm_page_init: ! 953: * ! 954: * Initialize the fields in a new page. ! 955: * This takes a structure with random values and initializes it ! 956: * so that it can be given to vm_page_release or vm_page_insert. ! 957: */ ! 958: void ! 959: vm_page_init( ! 960: vm_page_t mem, ! 961: vm_offset_t phys_addr) ! 962: { ! 963: *mem = vm_page_template; ! 964: mem->phys_addr = phys_addr; ! 965: } ! 966: ! 967: /* ! 968: * vm_page_grab_fictitious: ! 969: * ! 970: * Remove a fictitious page from the free list. ! 971: * Returns VM_PAGE_NULL if there are no free pages. ! 972: */ ! 973: int c_vm_page_grab_fictitious = 0; ! 974: int c_vm_page_release_fictitious = 0; ! 975: int c_vm_page_more_fictitious = 0; ! 976: ! 977: vm_page_t ! 978: vm_page_grab_fictitious(void) ! 979: { ! 980: register vm_page_t m; ! 981: ! 982: m = (vm_page_t)zget(vm_page_zone); ! 983: if (m) { ! 984: m->free = FALSE; ! 985: #if MACH_ASSERT || ZONE_DEBUG ! 986: vm_page_init(m, vm_page_fictitious_addr); ! 987: m->fictitious = TRUE; ! 988: #endif /* MACH_ASSERT || ZONE_DEBUG */ ! 989: } ! 990: ! 991: c_vm_page_grab_fictitious++; ! 992: return m; ! 993: } ! 994: ! 995: /* ! 996: * vm_page_release_fictitious: ! 997: * ! 998: * Release a fictitious page to the free list. ! 999: */ ! 1000: ! 1001: void ! 1002: vm_page_release_fictitious( ! 1003: register vm_page_t m) ! 1004: { ! 1005: assert(!m->free); ! 1006: assert(m->busy); ! 1007: assert(m->fictitious); ! 1008: assert(m->phys_addr == vm_page_fictitious_addr); ! 1009: ! 1010: c_vm_page_release_fictitious++; ! 1011: ! 1012: if (m->free) ! 1013: panic("vm_page_release_fictitious"); ! 1014: m->free = TRUE; ! 1015: zfree(vm_page_zone, (vm_offset_t)m); ! 1016: } ! 1017: ! 1018: /* ! 1019: * vm_page_more_fictitious: ! 1020: * ! 1021: * Add more fictitious pages to the free list. ! 1022: * Allowed to block. This routine is way intimate ! 1023: * with the zones code, for several reasons: ! 1024: * 1. we need to carve some page structures out of physical ! 1025: * memory before zones work, so they _cannot_ come from ! 1026: * the zone_map. ! 1027: * 2. the zone needs to be collectable in order to prevent ! 1028: * growth without bound. These structures are used by ! 1029: * the device pager (by the hundreds and thousands), as ! 1030: * private pages for pageout, and as blocking pages for ! 1031: * pagein. Temporary bursts in demand should not result in ! 1032: * permanent allocation of a resource. ! 1033: * 3. To smooth allocation humps, we allocate single pages ! 1034: * with kernel_memory_allocate(), and cram them into the ! 1035: * zone. This also allows us to initialize the vm_page_t's ! 1036: * on the way into the zone, so that zget() always returns ! 1037: * an initialized structure. The zone free element pointer ! 1038: * and the free page pointer are both the first item in the ! 1039: * vm_page_t. ! 1040: * 4. By having the pages in the zone pre-initialized, we need ! 1041: * not keep 2 levels of lists. The garbage collector simply ! 1042: * scans our list, and reduces physical memory usage as it ! 1043: * sees fit. ! 1044: */ ! 1045: ! 1046: void vm_page_more_fictitious(void) ! 1047: { ! 1048: extern vm_map_t zone_map; ! 1049: register vm_page_t m; ! 1050: vm_offset_t addr; ! 1051: kern_return_t retval; ! 1052: int i; ! 1053: ! 1054: c_vm_page_more_fictitious++; ! 1055: ! 1056: /* this may free up some fictitious pages */ ! 1057: cleanup_limbo_queue(); ! 1058: ! 1059: /* ! 1060: * Allocate a single page from the zone_map. Do not wait if no physical ! 1061: * pages are immediately available, and do not zero the space. We need ! 1062: * our own blocking lock here to prevent having multiple, ! 1063: * simultaneous requests from piling up on the zone_map lock. Exactly ! 1064: * one (of our) threads should be potentially waiting on the map lock. ! 1065: * If winner is not vm-privileged, then the page allocation will fail, ! 1066: * and it will temporarily block here in the vm_page_wait(). ! 1067: */ ! 1068: mutex_lock(&vm_page_alloc_lock); ! 1069: /* ! 1070: * If another thread allocated space, just bail out now. ! 1071: */ ! 1072: if (zone_free_count(vm_page_zone) > 5) { ! 1073: /* ! 1074: * The number "5" is a small number that is larger than the ! 1075: * number of fictitious pages that any single caller will ! 1076: * attempt to allocate. Otherwise, a thread will attempt to ! 1077: * acquire a fictitious page (vm_page_grab_fictitious), fail, ! 1078: * release all of the resources and locks already acquired, ! 1079: * and then call this routine. This routine finds the pages ! 1080: * that the caller released, so fails to allocate new space. ! 1081: * The process repeats infinitely. The largest known number ! 1082: * of fictitious pages required in this manner is 2. 5 is ! 1083: * simply a somewhat larger number. ! 1084: */ ! 1085: mutex_unlock(&vm_page_alloc_lock); ! 1086: return; ! 1087: } ! 1088: ! 1089: if ((retval = kernel_memory_allocate(zone_map, ! 1090: &addr, PAGE_SIZE, VM_PROT_ALL, ! 1091: KMA_KOBJECT|KMA_NOPAGEWAIT)) != KERN_SUCCESS) { ! 1092: /* ! 1093: * No page was available. Tell the pageout daemon, drop the ! 1094: * lock to give another thread a chance at it, and ! 1095: * wait for the pageout daemon to make progress. ! 1096: */ ! 1097: mutex_unlock(&vm_page_alloc_lock); ! 1098: vm_page_wait(); ! 1099: return; ! 1100: } ! 1101: /* ! 1102: * Initialize as many vm_page_t's as will fit on this page. This ! 1103: * depends on the zone code disturbing ONLY the first item of ! 1104: * each zone element. ! 1105: */ ! 1106: m = (vm_page_t)addr; ! 1107: for (i = PAGE_SIZE/sizeof(struct vm_page); i > 0; i--) { ! 1108: vm_page_init(m, vm_page_fictitious_addr); ! 1109: m->fictitious = TRUE; ! 1110: m++; ! 1111: } ! 1112: zcram(vm_page_zone, addr, PAGE_SIZE); ! 1113: mutex_unlock(&vm_page_alloc_lock); ! 1114: } ! 1115: ! 1116: /* ! 1117: * vm_page_convert: ! 1118: * ! 1119: * Attempt to convert a fictitious page into a real page. ! 1120: */ ! 1121: ! 1122: boolean_t ! 1123: vm_page_convert( ! 1124: register vm_page_t m) ! 1125: { ! 1126: register vm_page_t real_m; ! 1127: ! 1128: assert(m->busy); ! 1129: assert(m->fictitious); ! 1130: assert(!m->dirty); ! 1131: ! 1132: real_m = vm_page_grab(); ! 1133: if (real_m == VM_PAGE_NULL) ! 1134: return FALSE; ! 1135: ! 1136: m->phys_addr = real_m->phys_addr; ! 1137: m->fictitious = FALSE; ! 1138: ! 1139: vm_page_lock_queues(); ! 1140: if (m->active) ! 1141: vm_page_active_count++; ! 1142: else if (m->inactive) ! 1143: vm_page_inactive_count++; ! 1144: vm_page_unlock_queues(); ! 1145: ! 1146: real_m->phys_addr = vm_page_fictitious_addr; ! 1147: real_m->fictitious = TRUE; ! 1148: ! 1149: vm_page_release_fictitious(real_m); ! 1150: return TRUE; ! 1151: } ! 1152: ! 1153: /* ! 1154: * vm_pool_low(): ! 1155: * ! 1156: * Return true if it is not likely that a non-vm_privileged thread ! 1157: * can get memory without blocking. Advisory only, since the ! 1158: * situation may change under us. ! 1159: */ ! 1160: int ! 1161: vm_pool_low(void) ! 1162: { ! 1163: /* No locking, at worst we will fib. */ ! 1164: return( vm_page_free_count < vm_page_free_reserved ); ! 1165: } ! 1166: ! 1167: /* ! 1168: * vm_page_grab: ! 1169: * ! 1170: * Remove a page from the free list. ! 1171: * Returns VM_PAGE_NULL if the free list is too small. ! 1172: */ ! 1173: ! 1174: unsigned long vm_page_grab_count = 0; /* measure demand */ ! 1175: ! 1176: vm_page_t ! 1177: vm_page_grab(void) ! 1178: { ! 1179: register vm_page_t mem; ! 1180: ! 1181: mutex_lock(&vm_page_queue_free_lock); ! 1182: vm_page_grab_count++; ! 1183: ! 1184: /* ! 1185: * Optionally produce warnings if the wire or gobble ! 1186: * counts exceed some threshold. ! 1187: */ ! 1188: if (vm_page_wire_count_warning > 0 ! 1189: && vm_page_wire_count >= vm_page_wire_count_warning) { ! 1190: printf("mk: vm_page_grab(): high wired page count of %d\n", ! 1191: vm_page_wire_count); ! 1192: assert(vm_page_wire_count < vm_page_wire_count_warning); ! 1193: } ! 1194: if (vm_page_gobble_count_warning > 0 ! 1195: && vm_page_gobble_count >= vm_page_gobble_count_warning) { ! 1196: printf("mk: vm_page_grab(): high gobbled page count of %d\n", ! 1197: vm_page_gobble_count); ! 1198: assert(vm_page_gobble_count < vm_page_gobble_count_warning); ! 1199: } ! 1200: ! 1201: /* ! 1202: * Only let privileged threads (involved in pageout) ! 1203: * dip into the reserved pool. ! 1204: */ ! 1205: ! 1206: if ((vm_page_free_count < vm_page_free_reserved) && ! 1207: !current_thread()->vm_privilege) { ! 1208: mutex_unlock(&vm_page_queue_free_lock); ! 1209: mem = VM_PAGE_NULL; ! 1210: goto wakeup_pageout; ! 1211: } ! 1212: ! 1213: while (vm_page_queue_free == VM_PAGE_NULL) { ! 1214: printf("vm_page_grab: no free pages, trouble expected...\n"); ! 1215: mutex_unlock(&vm_page_queue_free_lock); ! 1216: VM_PAGE_WAIT(); ! 1217: mutex_lock(&vm_page_queue_free_lock); ! 1218: } ! 1219: ! 1220: if (--vm_page_free_count < vm_page_free_count_minimum) ! 1221: vm_page_free_count_minimum = vm_page_free_count; ! 1222: mem = vm_page_queue_free; ! 1223: vm_page_queue_free = (vm_page_t) mem->pageq.next; ! 1224: mem->free = FALSE; ! 1225: mutex_unlock(&vm_page_queue_free_lock); ! 1226: ! 1227: /* ! 1228: * Decide if we should poke the pageout daemon. ! 1229: * We do this if the free count is less than the low ! 1230: * water mark, or if the free count is less than the high ! 1231: * water mark (but above the low water mark) and the inactive ! 1232: * count is less than its target. ! 1233: * ! 1234: * We don't have the counts locked ... if they change a little, ! 1235: * it doesn't really matter. ! 1236: */ ! 1237: ! 1238: wakeup_pageout: ! 1239: if ((vm_page_free_count < vm_page_free_min) || ! 1240: ((vm_page_free_count < vm_page_free_target) && ! 1241: (vm_page_inactive_count < vm_page_inactive_target))) ! 1242: thread_wakeup((event_t) &vm_page_free_wanted); ! 1243: ! 1244: // dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 4); /* (TEST/DEBUG) */ ! 1245: ! 1246: return mem; ! 1247: } ! 1248: ! 1249: /* ! 1250: * vm_page_release: ! 1251: * ! 1252: * Return a page to the free list. ! 1253: */ ! 1254: ! 1255: void ! 1256: vm_page_release( ! 1257: register vm_page_t mem) ! 1258: { ! 1259: assert(!mem->private && !mem->fictitious); ! 1260: ! 1261: // dbgLog(mem->phys_addr, vm_page_free_count, vm_page_wire_count, 5); /* (TEST/DEBUG) */ ! 1262: ! 1263: mutex_lock(&vm_page_queue_free_lock); ! 1264: if (mem->free) ! 1265: panic("vm_page_release"); ! 1266: mem->free = TRUE; ! 1267: mem->pageq.next = (queue_entry_t) vm_page_queue_free; ! 1268: vm_page_queue_free = mem; ! 1269: vm_page_free_count++; ! 1270: ! 1271: /* ! 1272: * Check if we should wake up someone waiting for page. ! 1273: * But don't bother waking them unless they can allocate. ! 1274: * ! 1275: * We wakeup only one thread, to prevent starvation. ! 1276: * Because the scheduling system handles wait queues FIFO, ! 1277: * if we wakeup all waiting threads, one greedy thread ! 1278: * can starve multiple niceguy threads. When the threads ! 1279: * all wakeup, the greedy threads runs first, grabs the page, ! 1280: * and waits for another page. It will be the first to run ! 1281: * when the next page is freed. ! 1282: * ! 1283: * However, there is a slight danger here. ! 1284: * The thread we wake might not use the free page. ! 1285: * Then the other threads could wait indefinitely ! 1286: * while the page goes unused. To forestall this, ! 1287: * the pageout daemon will keep making free pages ! 1288: * as long as vm_page_free_wanted is non-zero. ! 1289: */ ! 1290: ! 1291: if ((vm_page_free_wanted > 0) && ! 1292: (vm_page_free_count >= vm_page_free_reserved)) { ! 1293: vm_page_free_wanted--; ! 1294: thread_wakeup_one((event_t) &vm_page_free_count); ! 1295: } ! 1296: ! 1297: mutex_unlock(&vm_page_queue_free_lock); ! 1298: } ! 1299: ! 1300: /* ! 1301: * Release a page to the limbo list. ! 1302: * Put real pages at the head of the queue, fictitious at the tail. ! 1303: * Page queues must be locked. ! 1304: */ ! 1305: void ! 1306: vm_page_release_limbo( ! 1307: register vm_page_t m) ! 1308: { ! 1309: assert(m->limbo); ! 1310: vm_page_limbo_count++; ! 1311: if (m->fictitious) { ! 1312: queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq); ! 1313: } else { ! 1314: vm_page_limbo_real_count++; ! 1315: queue_enter_first(&vm_page_queue_limbo, m, vm_page_t, pageq); ! 1316: } ! 1317: } ! 1318: ! 1319: /* ! 1320: * Exchange a real page in limbo (limbo_m) with a fictitious page (new_m). ! 1321: * The end result is that limbo_m is fictitious and still in limbo, and new_m ! 1322: * is the real page. The prep and pin counts remain with the page in limbo ! 1323: * although they will be briefly cleared by vm_page_init. This is OK since ! 1324: * there will be no interrupt-level interactions (the page is in limbo) and ! 1325: * vm_page_unprep must lock the page queues before changing the prep count. ! 1326: * ! 1327: * Page queues must be locked, and limbo_m must have been removed from its ! 1328: * object. ! 1329: */ ! 1330: void ! 1331: vm_page_limbo_exchange( ! 1332: register vm_page_t limbo_m, ! 1333: register vm_page_t new_m) ! 1334: { ! 1335: assert(limbo_m->limbo && !limbo_m->fictitious); ! 1336: assert(!limbo_m->tabled); ! 1337: assert(new_m->fictitious); ! 1338: ! 1339: *new_m = *limbo_m; ! 1340: vm_page_init(limbo_m, vm_page_fictitious_addr); ! 1341: ! 1342: limbo_m->fictitious = TRUE; ! 1343: limbo_m->limbo = TRUE; ! 1344: new_m->limbo = FALSE; ! 1345: ! 1346: limbo_m->prep_pin_count = new_m->prep_pin_count; ! 1347: new_m->prep_pin_count = 0; ! 1348: } ! 1349: ! 1350: /* ! 1351: * vm_page_wait: ! 1352: * ! 1353: * Wait for a page to become available. ! 1354: * If there are plenty of free pages, then we don't sleep. ! 1355: */ ! 1356: ! 1357: void ! 1358: vm_page_wait( void ) ! 1359: { ! 1360: /* ! 1361: * We can't use vm_page_free_reserved to make this ! 1362: * determination. Consider: some thread might ! 1363: * need to allocate two pages. The first allocation ! 1364: * succeeds, the second fails. After the first page is freed, ! 1365: * a call to vm_page_wait must really block. ! 1366: */ ! 1367: ! 1368: mutex_lock(&vm_page_queue_free_lock); ! 1369: if (vm_page_free_count < vm_page_free_target) { ! 1370: if (vm_page_free_wanted++ == 0) ! 1371: thread_wakeup((event_t)&vm_page_free_wanted); ! 1372: assert_wait((event_t)&vm_page_free_count, THREAD_UNINT); ! 1373: mutex_unlock(&vm_page_queue_free_lock); ! 1374: counter(c_vm_page_wait_block++); ! 1375: thread_block((void (*)(void))0); ! 1376: } else ! 1377: mutex_unlock(&vm_page_queue_free_lock); ! 1378: } ! 1379: ! 1380: /* ! 1381: * vm_page_alloc: ! 1382: * ! 1383: * Allocate and return a memory cell associated ! 1384: * with this VM object/offset pair. ! 1385: * ! 1386: * Object must be locked. ! 1387: */ ! 1388: ! 1389: vm_page_t ! 1390: vm_page_alloc( ! 1391: vm_object_t object, ! 1392: vm_offset_t offset) ! 1393: { ! 1394: register vm_page_t mem; ! 1395: ! 1396: mem = vm_page_grab(); ! 1397: if (mem == VM_PAGE_NULL) ! 1398: return VM_PAGE_NULL; ! 1399: ! 1400: vm_page_insert(mem, object, offset); ! 1401: ! 1402: return(mem); ! 1403: } ! 1404: ! 1405: int c_limbo_page_free = 0; /* debugging */ ! 1406: int c_limbo_convert = 0; /* debugging */ ! 1407: counter(unsigned int c_laundry_pages_freed = 0;) ! 1408: ! 1409: int vm_pagein_cluster_unused = 0; ! 1410: boolean_t vm_page_free_verify = FALSE; ! 1411: /* ! 1412: * vm_page_free: ! 1413: * ! 1414: * Returns the given page to the free list, ! 1415: * disassociating it with any VM object. ! 1416: * ! 1417: * Object and page queues must be locked prior to entry. ! 1418: */ ! 1419: void ! 1420: vm_page_free( ! 1421: register vm_page_t mem) ! 1422: { ! 1423: vm_object_t object = mem->object; ! 1424: ! 1425: assert(!mem->free); ! 1426: assert(!mem->cleaning); ! 1427: assert(!mem->pageout); ! 1428: assert(!vm_page_free_verify || pmap_verify_free(mem->phys_addr)); ! 1429: ! 1430: if (mem->tabled) ! 1431: vm_page_remove(mem); /* clears tabled, object, offset */ ! 1432: VM_PAGE_QUEUES_REMOVE(mem); /* clears active or inactive */ ! 1433: ! 1434: if (mem->clustered) { ! 1435: mem->clustered = FALSE; ! 1436: vm_pagein_cluster_unused++; ! 1437: } ! 1438: ! 1439: if (mem->wire_count) { ! 1440: if (!mem->private && !mem->fictitious) ! 1441: vm_page_wire_count--; ! 1442: mem->wire_count = 0; ! 1443: assert(!mem->gobbled); ! 1444: } else if (mem->gobbled) { ! 1445: if (!mem->private && !mem->fictitious) ! 1446: vm_page_wire_count--; ! 1447: vm_page_gobble_count--; ! 1448: } ! 1449: mem->gobbled = FALSE; ! 1450: ! 1451: if (mem->laundry) { ! 1452: extern int vm_page_laundry_min; ! 1453: vm_page_laundry_count--; ! 1454: mem->laundry = FALSE; /* laundry is now clear */ ! 1455: counter(++c_laundry_pages_freed); ! 1456: if (vm_page_laundry_count < vm_page_laundry_min) { ! 1457: vm_page_laundry_min = 0; ! 1458: thread_wakeup((event_t) &vm_page_laundry_count); ! 1459: } ! 1460: } ! 1461: ! 1462: mem->discard_request = FALSE; ! 1463: ! 1464: PAGE_WAKEUP(mem); /* clears wanted */ ! 1465: ! 1466: if (mem->absent) ! 1467: vm_object_absent_release(object); ! 1468: ! 1469: if (mem->limbo) { ! 1470: /* ! 1471: * The pageout daemon put this page into limbo and then freed ! 1472: * it. The page has already been removed from the object and ! 1473: * queues, so any attempt to look it up will fail. Put it ! 1474: * on the limbo queue; the pageout daemon will convert it to a ! 1475: * fictitious page and/or free the real one later. ! 1476: */ ! 1477: /* assert that it came from pageout daemon (how?) */ ! 1478: assert(!mem->fictitious && !mem->absent); ! 1479: c_limbo_page_free++; ! 1480: vm_page_release_limbo(mem); ! 1481: return; ! 1482: } ! 1483: assert(mem->prep_pin_count == 0); ! 1484: ! 1485: /* Some of these may be unnecessary */ ! 1486: mem->page_lock = 0; ! 1487: mem->unlock_request = 0; ! 1488: mem->busy = TRUE; ! 1489: mem->absent = FALSE; ! 1490: mem->error = FALSE; ! 1491: mem->dirty = FALSE; ! 1492: mem->precious = FALSE; ! 1493: mem->reference = FALSE; ! 1494: ! 1495: mem->page_error = KERN_SUCCESS; ! 1496: ! 1497: if (mem->private) { ! 1498: mem->private = FALSE; ! 1499: mem->fictitious = TRUE; ! 1500: mem->phys_addr = vm_page_fictitious_addr; ! 1501: } ! 1502: if (mem->fictitious) { ! 1503: vm_page_release_fictitious(mem); ! 1504: } else { ! 1505: vm_page_init(mem, mem->phys_addr); ! 1506: vm_page_release(mem); ! 1507: } ! 1508: } ! 1509: ! 1510: /* ! 1511: * vm_page_wire: ! 1512: * ! 1513: * Mark this page as wired down by yet ! 1514: * another map, removing it from paging queues ! 1515: * as necessary. ! 1516: * ! 1517: * The page's object and the page queues must be locked. ! 1518: */ ! 1519: void ! 1520: vm_page_wire( ! 1521: register vm_page_t mem) ! 1522: { ! 1523: ! 1524: // dbgLog(current_act(), mem->offset, mem->object, 1); /* (TEST/DEBUG) */ ! 1525: ! 1526: VM_PAGE_CHECK(mem); ! 1527: ! 1528: if (mem->wire_count == 0) { ! 1529: VM_PAGE_QUEUES_REMOVE(mem); ! 1530: if (!mem->private && !mem->fictitious && !mem->gobbled) ! 1531: vm_page_wire_count++; ! 1532: if (mem->gobbled) ! 1533: vm_page_gobble_count--; ! 1534: mem->gobbled = FALSE; ! 1535: } ! 1536: assert(!mem->gobbled); ! 1537: mem->wire_count++; ! 1538: } ! 1539: ! 1540: /* ! 1541: * vm_page_gobble: ! 1542: * ! 1543: * Mark this page as consumed by the vm/ipc/xmm subsystems. ! 1544: * ! 1545: * Called only for freshly vm_page_grab()ed pages - w/ nothing locked. ! 1546: */ ! 1547: void ! 1548: vm_page_gobble( ! 1549: register vm_page_t mem) ! 1550: { ! 1551: vm_page_lock_queues(); ! 1552: VM_PAGE_CHECK(mem); ! 1553: ! 1554: assert(!mem->gobbled); ! 1555: assert(mem->wire_count == 0); ! 1556: ! 1557: if (!mem->gobbled && mem->wire_count == 0) { ! 1558: if (!mem->private && !mem->fictitious) ! 1559: vm_page_wire_count++; ! 1560: } ! 1561: vm_page_gobble_count++; ! 1562: mem->gobbled = TRUE; ! 1563: vm_page_unlock_queues(); ! 1564: } ! 1565: ! 1566: /* ! 1567: * vm_page_unwire: ! 1568: * ! 1569: * Release one wiring of this page, potentially ! 1570: * enabling it to be paged again. ! 1571: * ! 1572: * The page's object and the page queues must be locked. ! 1573: */ ! 1574: void ! 1575: vm_page_unwire( ! 1576: register vm_page_t mem) ! 1577: { ! 1578: ! 1579: // dbgLog(current_act(), mem->offset, mem->object, 0); /* (TEST/DEBUG) */ ! 1580: ! 1581: VM_PAGE_CHECK(mem); ! 1582: assert(mem->wire_count > 0); ! 1583: ! 1584: if (--mem->wire_count == 0) { ! 1585: assert(!mem->private && !mem->fictitious); ! 1586: vm_page_wire_count--; ! 1587: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq); ! 1588: vm_page_active_count++; ! 1589: mem->active = TRUE; ! 1590: mem->reference = TRUE; ! 1591: } ! 1592: } ! 1593: ! 1594: /* ! 1595: * vm_page_deactivate: ! 1596: * ! 1597: * Returns the given page to the inactive list, ! 1598: * indicating that no physical maps have access ! 1599: * to this page. [Used by the physical mapping system.] ! 1600: * ! 1601: * The page queues must be locked. ! 1602: */ ! 1603: void ! 1604: vm_page_deactivate( ! 1605: register vm_page_t m) ! 1606: { ! 1607: VM_PAGE_CHECK(m); ! 1608: ! 1609: // dbgLog(m->phys_addr, vm_page_free_count, vm_page_wire_count, 6); /* (TEST/DEBUG) */ ! 1610: ! 1611: /* ! 1612: * This page is no longer very interesting. If it was ! 1613: * interesting (active or inactive/referenced), then we ! 1614: * clear the reference bit and (re)enter it in the ! 1615: * inactive queue. Note wired pages should not have ! 1616: * their reference bit cleared. ! 1617: */ ! 1618: if (m->gobbled) { /* can this happen? */ ! 1619: assert(m->wire_count == 0); ! 1620: if (!m->private && !m->fictitious) ! 1621: vm_page_wire_count--; ! 1622: vm_page_gobble_count--; ! 1623: m->gobbled = FALSE; ! 1624: } ! 1625: if (m->private || (m->wire_count != 0)) ! 1626: return; ! 1627: if (m->active || (m->inactive && m->reference)) { ! 1628: if (!m->fictitious && !m->absent) ! 1629: pmap_clear_reference(m->phys_addr); ! 1630: m->reference = FALSE; ! 1631: VM_PAGE_QUEUES_REMOVE(m); ! 1632: } ! 1633: if (m->wire_count == 0 && !m->inactive) { ! 1634: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); ! 1635: m->inactive = TRUE; ! 1636: if (!m->fictitious) ! 1637: vm_page_inactive_count++; ! 1638: } ! 1639: } ! 1640: ! 1641: /* ! 1642: * vm_page_activate: ! 1643: * ! 1644: * Put the specified page on the active list (if appropriate). ! 1645: * ! 1646: * The page queues must be locked. ! 1647: */ ! 1648: ! 1649: void ! 1650: vm_page_activate( ! 1651: register vm_page_t m) ! 1652: { ! 1653: VM_PAGE_CHECK(m); ! 1654: ! 1655: if (m->gobbled) { ! 1656: assert(m->wire_count == 0); ! 1657: if (!m->private && !m->fictitious) ! 1658: vm_page_wire_count--; ! 1659: vm_page_gobble_count--; ! 1660: m->gobbled = FALSE; ! 1661: } ! 1662: if (m->private) ! 1663: return; ! 1664: ! 1665: if (m->inactive) { ! 1666: queue_remove(&vm_page_queue_inactive, m, vm_page_t, pageq); ! 1667: if (!m->fictitious) ! 1668: vm_page_inactive_count--; ! 1669: m->inactive = FALSE; ! 1670: } ! 1671: if (m->wire_count == 0) { ! 1672: if (m->active) ! 1673: panic("vm_page_activate: already active"); ! 1674: ! 1675: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq); ! 1676: m->active = TRUE; ! 1677: m->reference = TRUE; ! 1678: if (!m->fictitious) ! 1679: vm_page_active_count++; ! 1680: } ! 1681: } ! 1682: ! 1683: /* ! 1684: * vm_page_part_zero_fill: ! 1685: * ! 1686: * Zero-fill a part of the page. ! 1687: */ ! 1688: void ! 1689: vm_page_part_zero_fill( ! 1690: vm_page_t m, ! 1691: vm_offset_t m_pa, ! 1692: vm_size_t len) ! 1693: { ! 1694: VM_PAGE_CHECK(m); ! 1695: ! 1696: pmap_zero_part_page(m->phys_addr, m_pa, len); ! 1697: } ! 1698: ! 1699: /* ! 1700: * vm_page_zero_fill: ! 1701: * ! 1702: * Zero-fill the specified page. ! 1703: */ ! 1704: void ! 1705: vm_page_zero_fill( ! 1706: vm_page_t m) ! 1707: { ! 1708: XPR(XPR_VM_PAGE, ! 1709: "vm_page_zero_fill, object 0x%X offset 0x%X page 0x%X\n", ! 1710: (integer_t)m->object, (integer_t)m->offset, (integer_t)m, 0,0); ! 1711: ! 1712: VM_PAGE_CHECK(m); ! 1713: ! 1714: pmap_zero_page(m->phys_addr); ! 1715: } ! 1716: ! 1717: /* ! 1718: * vm_page_part_copy: ! 1719: * ! 1720: * copy part of one page to another ! 1721: */ ! 1722: ! 1723: void ! 1724: vm_page_part_copy( ! 1725: vm_page_t src_m, ! 1726: vm_offset_t src_pa, ! 1727: vm_page_t dst_m, ! 1728: vm_offset_t dst_pa, ! 1729: vm_size_t len) ! 1730: { ! 1731: VM_PAGE_CHECK(src_m); ! 1732: VM_PAGE_CHECK(dst_m); ! 1733: ! 1734: pmap_copy_part_page(src_m->phys_addr, src_pa, ! 1735: dst_m->phys_addr, dst_pa, len); ! 1736: } ! 1737: ! 1738: /* ! 1739: * vm_page_copy: ! 1740: * ! 1741: * Copy one page to another ! 1742: */ ! 1743: ! 1744: void ! 1745: vm_page_copy( ! 1746: vm_page_t src_m, ! 1747: vm_page_t dest_m) ! 1748: { ! 1749: XPR(XPR_VM_PAGE, ! 1750: "vm_page_copy, object 0x%X offset 0x%X to object 0x%X offset 0x%X\n", ! 1751: (integer_t)src_m->object, src_m->offset, ! 1752: (integer_t)dest_m->object, dest_m->offset, ! 1753: 0); ! 1754: ! 1755: VM_PAGE_CHECK(src_m); ! 1756: VM_PAGE_CHECK(dest_m); ! 1757: ! 1758: pmap_copy_page(src_m->phys_addr, dest_m->phys_addr); ! 1759: } ! 1760: ! 1761: /* ! 1762: * Limbo pages are placed on the limbo queue to await their prep count ! 1763: * going to zero. A page is put into limbo by the pageout daemon. If the ! 1764: * page is real, then the pageout daemon did not need to page out the page, ! 1765: * it just freed it. When the prep_pin_count is zero the page can be freed. ! 1766: * Real pages with a non-zero prep count are converted to fictitious pages ! 1767: * so that the memory can be reclaimed; the fictitious page will remain on ! 1768: * the limbo queue until its prep count reaches zero. ! 1769: * ! 1770: * cleanup_limbo_queue is called by vm_page_more_fictitious and the pageout ! 1771: * daemon since it can free both real and fictitious pages. ! 1772: * It returns the number of fictitious pages freed. ! 1773: */ ! 1774: void ! 1775: cleanup_limbo_queue(void) ! 1776: { ! 1777: register vm_page_t free_m, m; ! 1778: vm_offset_t phys_addr; ! 1779: ! 1780: vm_page_lock_queues(); ! 1781: assert(vm_page_limbo_count >= vm_page_limbo_real_count); ! 1782: ! 1783: /* ! 1784: * first free up all pages with prep/pin counts of zero. This ! 1785: * may free both real and fictitious pages, which may be needed ! 1786: * later to convert real ones. ! 1787: */ ! 1788: m = (vm_page_t)queue_first(&vm_page_queue_limbo); ! 1789: while (!queue_end(&vm_page_queue_limbo, (queue_entry_t)m)) { ! 1790: if (m->prep_pin_count == 0) { ! 1791: free_m = m; ! 1792: m = (vm_page_t)queue_next(&m->pageq); ! 1793: queue_remove(&vm_page_queue_limbo, free_m, vm_page_t, ! 1794: pageq); ! 1795: vm_page_limbo_count--; ! 1796: if (!free_m->fictitious) ! 1797: vm_page_limbo_real_count--; ! 1798: free_m->limbo = FALSE; ! 1799: vm_page_free(free_m); ! 1800: assert(vm_page_limbo_count >= 0); ! 1801: assert(vm_page_limbo_real_count >= 0); ! 1802: } else { ! 1803: m = (vm_page_t)queue_next(&m->pageq); ! 1804: } ! 1805: } ! 1806: ! 1807: /* ! 1808: * now convert any remaining real pages to fictitious and free the ! 1809: * real ones. ! 1810: */ ! 1811: while (vm_page_limbo_real_count > 0) { ! 1812: queue_remove_first(&vm_page_queue_limbo, m, vm_page_t, pageq); ! 1813: assert(!m->fictitious); ! 1814: assert(m->limbo); ! 1815: ! 1816: /* ! 1817: * Try to get a fictitious page. If impossible, ! 1818: * requeue the real one and give up. ! 1819: */ ! 1820: free_m = vm_page_grab_fictitious(); ! 1821: if (free_m == VM_PAGE_NULL) { ! 1822: queue_enter_first(&vm_page_queue_limbo, m, vm_page_t, ! 1823: pageq); ! 1824: break; ! 1825: } ! 1826: c_limbo_convert++; ! 1827: vm_page_limbo_exchange(m, free_m); ! 1828: assert(m->limbo && m->fictitious); ! 1829: assert(!free_m->limbo && !free_m->fictitious); ! 1830: queue_enter(&vm_page_queue_limbo, m, vm_page_t, pageq); ! 1831: vm_page_free(free_m); ! 1832: vm_page_limbo_real_count--; ! 1833: } ! 1834: ! 1835: vm_page_unlock_queues(); ! 1836: } ! 1837: ! 1838: /* ! 1839: * Increment prep_count on a page. ! 1840: * Must be called in thread context. Page must not disappear: object ! 1841: * must be locked. ! 1842: */ ! 1843: kern_return_t ! 1844: vm_page_prep( ! 1845: register vm_page_t m) ! 1846: { ! 1847: kern_return_t retval = KERN_SUCCESS; ! 1848: ! 1849: assert(m != VM_PAGE_NULL); ! 1850: vm_page_lock_queues(); ! 1851: if (!m->busy && !m->error && !m->fictitious && !m->absent) { ! 1852: if (m->prep_pin_count != 0) { ! 1853: vm_page_pin_lock(); ! 1854: m->prep_count++; ! 1855: vm_page_pin_unlock(); ! 1856: } else { ! 1857: m->prep_count++; ! 1858: } ! 1859: assert(m->prep_count != 0); /* check for wraparound */ ! 1860: } else { ! 1861: retval = KERN_FAILURE; ! 1862: } ! 1863: vm_page_unlock_queues(); ! 1864: return retval; ! 1865: } ! 1866: ! 1867: ! 1868: /* ! 1869: * Pin a page (increment pin count). ! 1870: * Must have been previously prepped. ! 1871: * ! 1872: * MUST BE CALLED AT SPLVM. ! 1873: * ! 1874: * May be called from thread or interrupt context. ! 1875: * If page is in "limbo" it cannot be pinned. ! 1876: */ ! 1877: kern_return_t ! 1878: vm_page_pin( ! 1879: register vm_page_t m) ! 1880: { ! 1881: kern_return_t retval = KERN_SUCCESS; ! 1882: ! 1883: assert(m != VM_PAGE_NULL); ! 1884: vm_page_pin_lock(); ! 1885: if (m->limbo || m->prep_count == 0) { ! 1886: retval = KERN_FAILURE; ! 1887: } else { ! 1888: assert(!m->fictitious); ! 1889: if (m->pin_count == 0) ! 1890: vm_page_pin_count++; ! 1891: m->pin_count++; ! 1892: } ! 1893: vm_page_pin_unlock(); ! 1894: return retval; ! 1895: } ! 1896: ! 1897: ! 1898: /* ! 1899: * Unprep a page (decrement prep count). ! 1900: * Must have been previously prepped. ! 1901: * Called to decrement prep count after an attempt to pin failed. ! 1902: * Must be called from thread context. ! 1903: */ ! 1904: kern_return_t ! 1905: vm_page_unprep( ! 1906: register vm_page_t m) ! 1907: { ! 1908: kern_return_t retval = KERN_SUCCESS; ! 1909: ! 1910: assert(m != VM_PAGE_NULL); ! 1911: vm_page_lock_queues(); ! 1912: vm_page_pin_lock(); ! 1913: assert(m->prep_count != 0); ! 1914: if (m->prep_count == 0) ! 1915: retval = KERN_FAILURE; /* shouldn't happen */ ! 1916: else ! 1917: m->prep_count--; ! 1918: vm_page_pin_unlock(); ! 1919: vm_page_unlock_queues(); ! 1920: return retval; ! 1921: } ! 1922: ! 1923: ! 1924: /* ! 1925: * Unpin a page: decrement pin AND prep counts. ! 1926: * Must have been previously prepped AND pinned. ! 1927: * ! 1928: * MUST BE CALLED AT SPLVM. ! 1929: * ! 1930: * May be called from thread or interrupt context. ! 1931: */ ! 1932: kern_return_t ! 1933: vm_page_unpin( ! 1934: register vm_page_t m) ! 1935: { ! 1936: kern_return_t retval = KERN_SUCCESS; ! 1937: ! 1938: assert(m != VM_PAGE_NULL); ! 1939: vm_page_pin_lock(); ! 1940: assert(m->prep_count != 0 && m->pin_count != 0); ! 1941: assert(m->prep_count >= m->pin_count); ! 1942: assert(!m->limbo && !m->fictitious); ! 1943: if (m->prep_count != 0 && m->pin_count != 0) { ! 1944: m->prep_count--; ! 1945: m->pin_count--; ! 1946: if (m->pin_count == 0) ! 1947: vm_page_pin_count--; ! 1948: } else { ! 1949: retval = KERN_FAILURE; /* shouldn't happen */ ! 1950: } ! 1951: vm_page_pin_unlock(); ! 1952: return retval; ! 1953: } ! 1954: ! 1955: /* ! 1956: * Currently, this is a primitive allocator that grabs ! 1957: * free pages from the system, sorts them by physical ! 1958: * address, then searches for a region large enough to ! 1959: * satisfy the user's request. ! 1960: * ! 1961: * Additional levels of effort: ! 1962: * + steal clean active/inactive pages ! 1963: * + force pageouts of dirty pages ! 1964: * + maintain a map of available physical ! 1965: * memory ! 1966: */ ! 1967: ! 1968: #define SET_NEXT_PAGE(m,n) ((m)->pageq.next = (struct queue_entry *) (n)) ! 1969: ! 1970: #if MACH_ASSERT ! 1971: int vm_page_verify_contiguous( ! 1972: vm_page_t pages, ! 1973: unsigned int npages); ! 1974: #endif /* MACH_ASSERT */ ! 1975: ! 1976: cpm_counter(unsigned int vpfls_pages_handled = 0;) ! 1977: cpm_counter(unsigned int vpfls_head_insertions = 0;) ! 1978: cpm_counter(unsigned int vpfls_tail_insertions = 0;) ! 1979: cpm_counter(unsigned int vpfls_general_insertions = 0;) ! 1980: cpm_counter(unsigned int vpfc_failed = 0;) ! 1981: cpm_counter(unsigned int vpfc_satisfied = 0;) ! 1982: ! 1983: /* ! 1984: * Sort free list by ascending physical address, ! 1985: * using a not-particularly-bright sort algorithm. ! 1986: * Caller holds vm_page_queue_free_lock. ! 1987: */ ! 1988: static void ! 1989: vm_page_free_list_sort(void) ! 1990: { ! 1991: vm_page_t sort_list; ! 1992: vm_page_t sort_list_end; ! 1993: vm_page_t m, m1, *prev, next_m; ! 1994: vm_offset_t addr; ! 1995: #if MACH_ASSERT ! 1996: unsigned int npages; ! 1997: int old_free_count; ! 1998: #endif /* MACH_ASSERT */ ! 1999: ! 2000: #if MACH_ASSERT ! 2001: /* ! 2002: * Verify pages in the free list.. ! 2003: */ ! 2004: npages = 0; ! 2005: for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) ! 2006: ++npages; ! 2007: if (npages != vm_page_free_count) ! 2008: panic("vm_sort_free_list: prelim: npages %d free_count %d", ! 2009: npages, vm_page_free_count); ! 2010: old_free_count = vm_page_free_count; ! 2011: #endif /* MACH_ASSERT */ ! 2012: ! 2013: sort_list = sort_list_end = vm_page_queue_free; ! 2014: m = NEXT_PAGE(vm_page_queue_free); ! 2015: SET_NEXT_PAGE(vm_page_queue_free, VM_PAGE_NULL); ! 2016: cpm_counter(vpfls_pages_handled = 0); ! 2017: while (m != VM_PAGE_NULL) { ! 2018: cpm_counter(++vpfls_pages_handled); ! 2019: next_m = NEXT_PAGE(m); ! 2020: if (m->phys_addr < sort_list->phys_addr) { ! 2021: cpm_counter(++vpfls_head_insertions); ! 2022: SET_NEXT_PAGE(m, sort_list); ! 2023: sort_list = m; ! 2024: } else if (m->phys_addr > sort_list_end->phys_addr) { ! 2025: cpm_counter(++vpfls_tail_insertions); ! 2026: SET_NEXT_PAGE(sort_list_end, m); ! 2027: SET_NEXT_PAGE(m, VM_PAGE_NULL); ! 2028: sort_list_end = m; ! 2029: } else { ! 2030: cpm_counter(++vpfls_general_insertions); ! 2031: /* general sorted list insertion */ ! 2032: prev = &sort_list; ! 2033: for (m1=sort_list; m1!=VM_PAGE_NULL; m1=NEXT_PAGE(m1)) { ! 2034: if (m1->phys_addr > m->phys_addr) { ! 2035: if (*prev != m1) ! 2036: panic("vm_sort_free_list: ugh"); ! 2037: SET_NEXT_PAGE(m, *prev); ! 2038: *prev = m; ! 2039: break; ! 2040: } ! 2041: prev = (vm_page_t *) &m1->pageq.next; ! 2042: } ! 2043: } ! 2044: m = next_m; ! 2045: } ! 2046: ! 2047: #if MACH_ASSERT ! 2048: /* ! 2049: * Verify that pages are sorted into ascending order. ! 2050: */ ! 2051: for (m = sort_list, npages = 0; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) { ! 2052: if (m != sort_list && ! 2053: m->phys_addr <= addr) { ! 2054: printf("m 0x%x addr 0x%x\n", m, addr); ! 2055: panic("vm_sort_free_list"); ! 2056: } ! 2057: addr = m->phys_addr; ! 2058: ++npages; ! 2059: } ! 2060: if (old_free_count != vm_page_free_count) ! 2061: panic("vm_sort_free_list: old_free %d free_count %d", ! 2062: old_free_count, vm_page_free_count); ! 2063: if (npages != vm_page_free_count) ! 2064: panic("vm_sort_free_list: npages %d free_count %d", ! 2065: npages, vm_page_free_count); ! 2066: #endif /* MACH_ASSERT */ ! 2067: ! 2068: vm_page_queue_free = sort_list; ! 2069: } ! 2070: ! 2071: ! 2072: #if MACH_ASSERT ! 2073: /* ! 2074: * Check that the list of pages is ordered by ! 2075: * ascending physical address and has no holes. ! 2076: */ ! 2077: int ! 2078: vm_page_verify_contiguous( ! 2079: vm_page_t pages, ! 2080: unsigned int npages) ! 2081: { ! 2082: register vm_page_t m; ! 2083: unsigned int page_count; ! 2084: vm_offset_t prev_addr; ! 2085: ! 2086: prev_addr = pages->phys_addr; ! 2087: page_count = 1; ! 2088: for (m = NEXT_PAGE(pages); m != VM_PAGE_NULL; m = NEXT_PAGE(m)) { ! 2089: if (m->phys_addr != prev_addr + page_size) { ! 2090: printf("m 0x%x prev_addr 0x%x, current addr 0x%x\n", ! 2091: m, prev_addr, m->phys_addr); ! 2092: printf("pages 0x%x page_count %d\n", pages, page_count); ! 2093: panic("vm_page_verify_contiguous: not contiguous!"); ! 2094: } ! 2095: prev_addr = m->phys_addr; ! 2096: ++page_count; ! 2097: } ! 2098: if (page_count != npages) { ! 2099: printf("pages 0x%x actual count 0x%x but requested 0x%x\n", ! 2100: pages, page_count, npages); ! 2101: panic("vm_page_verify_contiguous: count error"); ! 2102: } ! 2103: return 1; ! 2104: } ! 2105: #endif /* MACH_ASSERT */ ! 2106: ! 2107: ! 2108: /* ! 2109: * Find a region large enough to contain at least npages ! 2110: * of contiguous physical memory. ! 2111: * ! 2112: * Requirements: ! 2113: * - Called while holding vm_page_queue_free_lock. ! 2114: * - Doesn't respect vm_page_free_reserved; caller ! 2115: * must not ask for more pages than are legal to grab. ! 2116: * ! 2117: * Returns a pointer to a list of gobbled pages or VM_PAGE_NULL. ! 2118: * ! 2119: */ ! 2120: static vm_page_t ! 2121: vm_page_find_contiguous( ! 2122: int npages) ! 2123: { ! 2124: vm_page_t m, *contig_prev, *prev_ptr; ! 2125: vm_offset_t prev_addr; ! 2126: unsigned int contig_npages; ! 2127: vm_page_t list; ! 2128: ! 2129: if (npages < 1) ! 2130: return VM_PAGE_NULL; ! 2131: ! 2132: prev_addr = vm_page_queue_free->phys_addr - (page_size + 1); ! 2133: prev_ptr = &vm_page_queue_free; ! 2134: for (m = vm_page_queue_free; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) { ! 2135: ! 2136: if (m->phys_addr != prev_addr + page_size) { ! 2137: /* ! 2138: * Whoops! Pages aren't contiguous. Start over. ! 2139: */ ! 2140: contig_npages = 0; ! 2141: contig_prev = prev_ptr; ! 2142: } ! 2143: ! 2144: if (++contig_npages == npages) { ! 2145: /* ! 2146: * Chop these pages out of the free list. ! 2147: * Mark them all as gobbled. ! 2148: */ ! 2149: list = *contig_prev; ! 2150: *contig_prev = NEXT_PAGE(m); ! 2151: SET_NEXT_PAGE(m, VM_PAGE_NULL); ! 2152: for (m = list; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) { ! 2153: assert(m->free); ! 2154: assert(!m->wanted); ! 2155: m->free = FALSE; ! 2156: m->gobbled = TRUE; ! 2157: } ! 2158: vm_page_free_count -= npages; ! 2159: if (vm_page_free_count < vm_page_free_count_minimum) ! 2160: vm_page_free_count_minimum = vm_page_free_count; ! 2161: vm_page_gobble_count += npages; ! 2162: cpm_counter(++vpfc_satisfied); ! 2163: assert(vm_page_verify_contiguous(list, contig_npages)); ! 2164: return list; ! 2165: } ! 2166: ! 2167: assert(contig_npages < npages); ! 2168: prev_ptr = (vm_page_t *) &m->pageq.next; ! 2169: prev_addr = m->phys_addr; ! 2170: } ! 2171: cpm_counter(++vpfc_failed); ! 2172: return VM_PAGE_NULL; ! 2173: } ! 2174: ! 2175: /* ! 2176: * Allocate a list of contiguous, wired pages. ! 2177: */ ! 2178: kern_return_t ! 2179: cpm_allocate( ! 2180: vm_size_t size, ! 2181: vm_page_t *list, ! 2182: boolean_t wire) ! 2183: { ! 2184: register vm_page_t m; ! 2185: vm_page_t *first_contig; ! 2186: vm_page_t free_list, pages; ! 2187: unsigned int npages, n1pages; ! 2188: int vm_pages_available; ! 2189: ! 2190: if (size % page_size != 0) ! 2191: return KERN_INVALID_ARGUMENT; ! 2192: ! 2193: vm_page_lock_queues(); ! 2194: mutex_lock(&vm_page_queue_free_lock); ! 2195: ! 2196: /* ! 2197: * Should also take active and inactive pages ! 2198: * into account... One day... ! 2199: */ ! 2200: vm_pages_available = vm_page_free_count - vm_page_free_reserved; ! 2201: ! 2202: if (size > vm_pages_available * page_size) { ! 2203: mutex_unlock(&vm_page_queue_free_lock); ! 2204: return KERN_RESOURCE_SHORTAGE; ! 2205: } ! 2206: ! 2207: vm_page_free_list_sort(); ! 2208: ! 2209: npages = size / page_size; ! 2210: ! 2211: /* ! 2212: * Obtain a pointer to a subset of the free ! 2213: * list large enough to satisfy the request; ! 2214: * the region will be physically contiguous. ! 2215: */ ! 2216: pages = vm_page_find_contiguous(npages); ! 2217: if (pages == VM_PAGE_NULL) { ! 2218: mutex_unlock(&vm_page_queue_free_lock); ! 2219: return KERN_NO_SPACE; ! 2220: } ! 2221: ! 2222: mutex_unlock(&vm_page_queue_free_lock); ! 2223: ! 2224: /* ! 2225: * Walk the returned list, wiring the pages. ! 2226: */ ! 2227: if (wire == TRUE) ! 2228: for (m = pages; m != VM_PAGE_NULL; m = NEXT_PAGE(m)) { ! 2229: /* ! 2230: * Essentially inlined vm_page_wire. ! 2231: */ ! 2232: assert(!m->active); ! 2233: assert(!m->inactive); ! 2234: assert(!m->private); ! 2235: assert(!m->fictitious); ! 2236: assert(m->wire_count == 0); ! 2237: assert(m->gobbled); ! 2238: m->gobbled = FALSE; ! 2239: m->wire_count++; ! 2240: ++vm_page_wire_count; ! 2241: --vm_page_gobble_count; ! 2242: } ! 2243: vm_page_unlock_queues(); ! 2244: ! 2245: /* ! 2246: * The CPM pages should now be available and ! 2247: * ordered by ascending physical address. ! 2248: */ ! 2249: assert(vm_page_verify_contiguous(pages, npages)); ! 2250: ! 2251: *list = pages; ! 2252: return KERN_SUCCESS; ! 2253: } ! 2254: ! 2255: ! 2256: #include <mach_vm_debug.h> ! 2257: #if MACH_VM_DEBUG ! 2258: ! 2259: #include <mach_debug/hash_info.h> ! 2260: #include <vm/vm_debug.h> ! 2261: ! 2262: /* ! 2263: * Routine: vm_page_info ! 2264: * Purpose: ! 2265: * Return information about the global VP table. ! 2266: * Fills the buffer with as much information as possible ! 2267: * and returns the desired size of the buffer. ! 2268: * Conditions: ! 2269: * Nothing locked. The caller should provide ! 2270: * possibly-pageable memory. ! 2271: */ ! 2272: ! 2273: unsigned int ! 2274: vm_page_info( ! 2275: hash_info_bucket_t *info, ! 2276: unsigned int count) ! 2277: { ! 2278: int i; ! 2279: ! 2280: if (vm_page_bucket_count < count) ! 2281: count = vm_page_bucket_count; ! 2282: ! 2283: for (i = 0; i < count; i++) { ! 2284: vm_page_bucket_t *bucket = &vm_page_buckets[i]; ! 2285: unsigned int bucket_count = 0; ! 2286: vm_page_t m; ! 2287: ! 2288: simple_lock(&vm_page_bucket_lock); ! 2289: for (m = bucket->pages; m != VM_PAGE_NULL; m = m->next) ! 2290: bucket_count++; ! 2291: simple_unlock(&vm_page_bucket_lock); ! 2292: ! 2293: /* don't touch pageable memory while holding locks */ ! 2294: info[i].hib_count = bucket_count; ! 2295: } ! 2296: ! 2297: return vm_page_bucket_count; ! 2298: } ! 2299: #endif /* MACH_VM_DEBUG */ ! 2300: ! 2301: #include <mach_kdb.h> ! 2302: #if MACH_KDB ! 2303: ! 2304: #include <ddb/db_output.h> ! 2305: #include <vm/vm_print.h> ! 2306: #define printf kdbprintf ! 2307: ! 2308: /* ! 2309: * Routine: vm_page_print [exported] ! 2310: */ ! 2311: void ! 2312: vm_page_print( ! 2313: vm_page_t p) ! 2314: { ! 2315: extern db_indent; ! 2316: ! 2317: iprintf("page 0x%x\n", p); ! 2318: ! 2319: db_indent += 2; ! 2320: ! 2321: iprintf("object=0x%x", p->object); ! 2322: printf(", offset=0x%x", p->offset); ! 2323: printf(", wire_count=%d", p->wire_count); ! 2324: printf(", prep_count=%d", p->prep_count); ! 2325: printf(", pin_count=%d\n", p->pin_count); ! 2326: ! 2327: iprintf("%sinactive, %sactive, %sgobbled, %slaundry, %sfree, %sref, %sdiscard\n", ! 2328: (p->inactive ? "" : "!"), ! 2329: (p->active ? "" : "!"), ! 2330: (p->gobbled ? "" : "!"), ! 2331: (p->laundry ? "" : "!"), ! 2332: (p->free ? "" : "!"), ! 2333: (p->reference ? "" : "!"), ! 2334: (p->discard_request ? "" : "!")); ! 2335: iprintf("%sbusy, %swanted, %stabled, %sfictitious, %sprivate, %sprecious\n", ! 2336: (p->busy ? "" : "!"), ! 2337: (p->wanted ? "" : "!"), ! 2338: (p->tabled ? "" : "!"), ! 2339: (p->fictitious ? "" : "!"), ! 2340: (p->private ? "" : "!"), ! 2341: (p->precious ? "" : "!")); ! 2342: iprintf("%sabsent, %serror, %sdirty, %scleaning, %spageout, %sclustered\n", ! 2343: (p->absent ? "" : "!"), ! 2344: (p->error ? "" : "!"), ! 2345: (p->dirty ? "" : "!"), ! 2346: (p->cleaning ? "" : "!"), ! 2347: (p->pageout ? "" : "!"), ! 2348: (p->clustered ? "" : "!")); ! 2349: iprintf("%slock_supplied, %soverwriting, %srestart, %sunusual, %slimbo\n", ! 2350: (p->lock_supplied ? "" : "!"), ! 2351: (p->overwriting ? "" : "!"), ! 2352: (p->restart ? "" : "!"), ! 2353: (p->unusual ? "" : "!"), ! 2354: (p->limbo ? "" : "!")); ! 2355: ! 2356: iprintf("phys_addr=0x%x", p->phys_addr); ! 2357: printf(", page_error=0x%x", p->page_error); ! 2358: printf(", page_lock=0x%x", p->page_lock); ! 2359: printf(", unlock_request=%d\n", p->unlock_request); ! 2360: ! 2361: db_indent -= 2; ! 2362: } ! 2363: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.