|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1993-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: * File: vm/vm_page.c ! 52: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 53: * ! 54: * Resident memory management module. ! 55: */ ! 56: ! 57: #import <mach/features.h> ! 58: ! 59: #include <mach/vm_prot.h> ! 60: #include <kern/counters.h> ! 61: #include <kern/sched_prim.h> ! 62: #include <kern/task.h> ! 63: #include <kern/thread.h> ! 64: #include <mach/vm_statistics.h> ! 65: #include <kern/xpr.h> ! 66: #include <kern/zalloc.h> ! 67: #include <vm/pmap.h> ! 68: #include <vm/vm_map.h> ! 69: #include <vm/vm_page.h> ! 70: #include <vm/vm_pageout.h> ! 71: ! 72: #include <mach/vm_policy.h> ! 73: ! 74: /* ! 75: * Associated with eacn page of user-allocatable memory is a ! 76: * page structure. ! 77: */ ! 78: ! 79: /* ! 80: * These variables record the values returned by vm_page_bootstrap, ! 81: * for debugging purposes. The implementation of pmap_steal_memory ! 82: * and pmap_startup here also uses them internally. ! 83: */ ! 84: ! 85: vm_offset_t virtual_space_start; ! 86: vm_offset_t virtual_space_end; ! 87: ! 88: /* ! 89: * The vm_page_lookup() routine, which provides for fast ! 90: * (virtual memory object, offset) to page lookup, employs ! 91: * the following hash table. The vm_page_{insert,remove} ! 92: * routines install and remove associations in the table. ! 93: * [This table is often called the virtual-to-physical, ! 94: * or VP, table.] ! 95: */ ! 96: typedef struct { ! 97: decl_simple_lock_data(,lock) ! 98: vm_page_t pages; ! 99: } vm_page_bucket_t; ! 100: ! 101: vm_page_bucket_t *vm_page_buckets; /* Array of buckets */ ! 102: unsigned int vm_page_bucket_count = 0; /* How big is array? */ ! 103: unsigned int vm_page_hash_mask; /* Mask for hash function */ ! 104: ! 105: /* ! 106: * The virtual page size is currently implemented as a runtime ! 107: * variable, but is constant once initialized using vm_set_page_size. ! 108: * This initialization must be done in the machine-dependent ! 109: * bootstrap sequence, before calling other machine-independent ! 110: * initializations. ! 111: * ! 112: * All references to the virtual page size outside this ! 113: * module must use the PAGE_SIZE constant. ! 114: */ ! 115: vm_size_t page_size = 0; ! 116: vm_size_t page_mask; ! 117: int page_shift; ! 118: ! 119: vm_offset_t map_data; ! 120: vm_size_t map_data_size; ! 121: ! 122: vm_offset_t kentry_data; ! 123: vm_size_t kentry_data_size; ! 124: ! 125: extern vm_offset_t zdata; ! 126: extern vm_size_t zdata_size; ! 127: ! 128: queue_head_t vm_page_queue_free; ! 129: queue_head_t vm_page_queue_active; ! 130: queue_head_t vm_page_queue_inactive; ! 131: simple_lock_data_t vm_page_queue_lock; ! 132: simple_lock_data_t vm_page_queue_free_lock; ! 133: ! 134: vm_page_t vm_page_array; ! 135: long first_page; ! 136: long last_page; ! 137: vm_offset_t first_phys_addr; ! 138: vm_offset_t last_phys_addr; ! 139: ! 140: int vm_page_free_count; ! 141: int vm_page_active_count; ! 142: int vm_page_inactive_count; ! 143: int vm_page_wire_count; ! 144: ! 145: /* ! 146: * Several page replacement parameters are also ! 147: * shared with this module, so that page allocation ! 148: * (done here in vm_page_alloc) can trigger the ! 149: * pageout daemon. ! 150: */ ! 151: int vm_page_free_target = 0; ! 152: int vm_page_free_min = 0; ! 153: int vm_page_inactive_target = 0; ! 154: int vm_page_free_reserved = 0; ! 155: int vm_page_laundry_count = 0; ! 156: ! 157: struct vm_page vm_page_template; ! 158: ! 159: #if SHOW_SPACE ! 160: extern int show_space; ! 161: #endif SHOW_SPACE ! 162: ! 163: /* ! 164: * vm_set_page_size: ! 165: * ! 166: * Sets the page size, perhaps based upon the memory ! 167: * size. Must be called before any use of page-size ! 168: * dependent functions. ! 169: * ! 170: * Sets page_shift and page_mask from page_size. ! 171: */ ! 172: void vm_set_page_size(void) ! 173: { ! 174: page_mask = page_size - 1; ! 175: ! 176: if ((page_mask & page_size) != 0) ! 177: panic("vm_set_page_size: page size not a power of two"); ! 178: ! 179: for (page_shift = 0; ; page_shift++) ! 180: if ((1 << page_shift) == page_size) ! 181: break; ! 182: } ! 183: ! 184: /* ! 185: * vm_page_startup: ! 186: * ! 187: * Initializes the resident memory module. ! 188: * ! 189: * Allocates memory for the page cells, and ! 190: * for the object/offset-to-page hash table headers. ! 191: * Each page cell is initialized and placed on the free list. ! 192: */ ! 193: ! 194: #if SHOW_SPACE ! 195: #define PALLOC(name, type, num) \ ! 196: MACRO_BEGIN \ ! 197: (type *)(name) = (type *) \ ! 198: vm_alloc_from_regions((num) * sizeof(type), \ ! 199: __alignof__(type)); \ ! 200: bzero((name), (num) * sizeof(type)); \ ! 201: if (show_space) { \ ! 202: printf(#name " = %d (0x%x) bytes @%x," \ ! 203: " %d cells of %d bytes\n", \ ! 204: (num)*sizeof(type), (num)*sizeof(type), name, \ ! 205: num, sizeof(type)); \ ! 206: } \ ! 207: MACRO_END ! 208: ! 209: #define PALLOC_SIZE(name, size, type, num) \ ! 210: MACRO_BEGIN \ ! 211: (size) = (num) * sizeof(type); \ ! 212: (type *)(name) = (type *) \ ! 213: vm_alloc_from_regions((size), \ ! 214: __alignof__(type)); \ ! 215: bzero((name), (size)); \ ! 216: if (show_space) { \ ! 217: printf(#name " = %d (0x%x) bytes @%x," \ ! 218: " %d cells of %d bytes\n", \ ! 219: (size), (size), name, \ ! 220: num, sizeof(type)); \ ! 221: } \ ! 222: MACRO_END ! 223: ! 224: #define PALLOC_PAGES(name, type, size) \ ! 225: MACRO_BEGIN \ ! 226: (size) = round_page(size); \ ! 227: (type *)(name) = (type *) \ ! 228: vm_alloc_from_regions((size), PAGE_SIZE); \ ! 229: bzero((name), (size)); \ ! 230: if (show_space) { \ ! 231: printf(#name " = %d (0x%x) bytes @%x," \ ! 232: " %d pages of %d bytes\n", \ ! 233: (size), (size), name, \ ! 234: (size) / PAGE_SIZE, PAGE_SIZE); \ ! 235: } \ ! 236: MACRO_END ! 237: #else SHOW_SPACE ! 238: #define PALLOC(name, type, num) \ ! 239: MACRO_BEGIN \ ! 240: (type *)(name) = (type *) \ ! 241: vm_alloc_from_regions((num) * sizeof(type), \ ! 242: __alignof__(type)); \ ! 243: bzero((name), (num) * sizeof(type)); \ ! 244: MACRO_END ! 245: ! 246: #define PALLOC_SIZE(name, size, type, num) \ ! 247: MACRO_BEGIN \ ! 248: (size) = (num) * sizeof(type); \ ! 249: (type *)(name) = (type *) \ ! 250: vm_alloc_from_regions((size), \ ! 251: __alignof__(type)); \ ! 252: bzero((name), (size)); \ ! 253: MACRO_END ! 254: ! 255: #define PALLOC_PAGES(name, type, size) \ ! 256: MACRO_BEGIN \ ! 257: (size) = round_page(size); \ ! 258: (type *)(name) = (type *) \ ! 259: vm_alloc_from_regions((size), PAGE_SIZE); \ ! 260: bzero((name), (size)); \ ! 261: MACRO_END ! 262: #endif SHOW_SPACE ! 263: ! 264: vm_offset_t vm_page_startup(mem_region, num_regions, vavail) ! 265: mem_region_t mem_region; ! 266: int num_regions; ! 267: vm_offset_t vavail; ! 268: { ! 269: int mem_size; ! 270: mem_region_t rp; ! 271: vm_page_t m; ! 272: queue_t bucket; ! 273: int i; ! 274: vm_offset_t pa; ! 275: extern vm_offset_t virtual_avail; ! 276: ! 277: /* ! 278: * Initialize the vm_page template. ! 279: */ ! 280: ! 281: m = &vm_page_template; ! 282: m->object = VM_OBJECT_NULL; /* reset later */ ! 283: m->offset = 0; /* reset later */ ! 284: m->wire_count = 0; ! 285: ! 286: #if OLD_VM_CODE ! 287: m->clean = TRUE; ! 288: m->nfspagereq = FALSE; ! 289: m->copy_on_write = FALSE; ! 290: m->asyncrw = FALSE; ! 291: #endif ! 292: m->inactive = FALSE; ! 293: m->active = FALSE; ! 294: m->laundry = FALSE; ! 295: m->free = FALSE; ! 296: ! 297: m->busy = TRUE; ! 298: m->wanted = FALSE; ! 299: m->tabled = FALSE; ! 300: m->fictitious = FALSE; ! 301: m->private = FALSE; ! 302: m->absent = FALSE; ! 303: m->error = FALSE; ! 304: m->dirty = FALSE; ! 305: m->precious = FALSE; ! 306: m->reference = FALSE; ! 307: ! 308: m->phys_addr = 0; /* reset later */ ! 309: ! 310: m->page_lock = VM_PROT_NONE; ! 311: m->unlock_request = VM_PROT_NONE; ! 312: ! 313: /* ! 314: * Initialize the locks ! 315: */ ! 316: ! 317: simple_lock_init(&vm_page_queue_free_lock); ! 318: simple_lock_init(&vm_page_queue_lock); ! 319: ! 320: /* ! 321: * Initialize the queue headers for the free queue, ! 322: * the active queue and the inactive queue. ! 323: */ ! 324: ! 325: queue_init(&vm_page_queue_free); ! 326: queue_init(&vm_page_queue_active); ! 327: queue_init(&vm_page_queue_inactive); ! 328: ! 329: /* ! 330: * Allocate (and initialize) the virtual-to-physical ! 331: * table hash buckets. ! 332: * ! 333: * The number of buckets should be a power of two to ! 334: * get a good hash function. The following computation ! 335: * chooses the first power of two that is greater ! 336: * than the number of physical pages in the system. ! 337: */ ! 338: mem_size = 0; ! 339: for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) { ! 340: mem_size += trunc_page(rp->last_phys_addr) ! 341: - round_page(rp->first_phys_addr); ! 342: } ! 343: ! 344: if (vm_page_bucket_count == 0) { ! 345: vm_page_bucket_count = 1; ! 346: while (vm_page_bucket_count < atop(mem_size)) ! 347: vm_page_bucket_count <<= 1; ! 348: } ! 349: ! 350: vm_page_hash_mask = vm_page_bucket_count - 1; ! 351: ! 352: if (vm_page_hash_mask & vm_page_bucket_count) ! 353: printf("vm_page_bootstrap: WARNING -- strange page hash\n"); ! 354: ! 355: PALLOC(vm_page_buckets, vm_page_bucket_t, vm_page_bucket_count); ! 356: ! 357: for (i = 0; i < vm_page_bucket_count; i++) { ! 358: register vm_page_bucket_t *bucket = &vm_page_buckets[i]; ! 359: ! 360: bucket->pages = VM_PAGE_NULL; ! 361: simple_lock_init(&bucket->lock); ! 362: } ! 363: ! 364: /* ! 365: * Steal pages for some zones that cannot be ! 366: * dynamically allocated. ! 367: */ ! 368: #if 1 ! 369: zdata_size = 8*PAGE_SIZE; ! 370: PALLOC_PAGES(zdata, void, zdata_size); ! 371: #else ! 372: PALLOC_SIZE(zdata, zdata_size, struct zone, 40); ! 373: #endif ! 374: PALLOC_SIZE(map_data, map_data_size, struct vm_map, 10); ! 375: ! 376: /* ! 377: * Allow 2048 kernel map entries... this should be plenty ! 378: * since people shouldn't be cluttering up the kernel ! 379: * map (they should use their own maps). ! 380: */ ! 381: PALLOC_SIZE(kentry_data, kentry_data_size, struct vm_map_entry, 2048); ! 382: ! 383: /* ! 384: * First make a pass over each region and allocate ! 385: * vm_page_arrays. Later go back and size the pages in the ! 386: * region (since some of the region may have been taken ! 387: * by the vm_page_array). ! 388: */ ! 389: for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) { ! 390: ASSERT(rp->first_phys_addr <= rp->last_phys_addr); ! 391: PALLOC(rp->vm_page_array, struct vm_page, ! 392: atop(trunc_page(rp->last_phys_addr) - ! 393: round_page(rp->first_phys_addr))); ! 394: } ! 395: vm_page_free_count = 0; ! 396: for (rp = mem_region; rp < &mem_region[num_regions]; rp += 1) { ! 397: rp->first_phys_addr = round_page(rp->first_phys_addr); ! 398: rp->last_phys_addr = trunc_page(rp->last_phys_addr); ! 399: rp->first_page = atop(rp->first_phys_addr); ! 400: rp->last_page = atop(rp->last_phys_addr); ! 401: rp->num_pages = rp->last_page - rp->first_page; ! 402: ASSERT((int)rp->num_pages >= 0); ! 403: vm_page_free_count += rp->num_pages; ! 404: ! 405: m = rp->vm_page_array; ! 406: pa = rp->first_phys_addr; ! 407: ! 408: for (i = 0; i < rp->num_pages; i += 1) { ! 409: m->phys_addr = pa; ! 410: queue_enter(&vm_page_queue_free, m, vm_page_t, pageq); ! 411: m->free = TRUE; ! 412: m++; ! 413: pa += page_size; ! 414: } ! 415: } ! 416: ! 417: /* ! 418: * Initialize vm_pages_needed lock here - don't wait for pageout ! 419: * daemon XXX ! 420: */ ! 421: simple_lock_init(&vm_pages_needed_lock); ! 422: ! 423: return(virtual_avail); ! 424: } ! 425: ! 426: /* ! 427: * vm_page_hash: ! 428: * ! 429: * Distributes the object/offset key pair among hash buckets. ! 430: * ! 431: * NOTE: To get a good hash function, the bucket count should ! 432: * be a power of two. ! 433: */ ! 434: #define vm_page_hash(object, offset) \ ! 435: (((unsigned int)(vm_offset_t)object + (unsigned int)atop(offset)) \ ! 436: & vm_page_hash_mask) ! 437: ! 438: /* ! 439: * vm_page_insert: [ internal use only ] ! 440: * ! 441: * Inserts the given mem entry into the object/object-page ! 442: * table and object list. ! 443: * ! 444: * The object and page must be locked. ! 445: */ ! 446: ! 447: void vm_page_insert( ! 448: register vm_page_t mem, ! 449: register vm_object_t object, ! 450: register vm_offset_t offset) ! 451: { ! 452: register vm_page_bucket_t *bucket; ! 453: ! 454: VM_PAGE_CHECK(mem); ! 455: ! 456: if (mem->tabled) ! 457: panic("vm_page_insert"); ! 458: ! 459: /* ! 460: * Record the object/offset pair in this page ! 461: */ ! 462: ! 463: mem->object = object; ! 464: mem->offset = offset; ! 465: ! 466: /* ! 467: * Insert it into the object_object/offset hash table ! 468: */ ! 469: ! 470: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 471: { ! 472: int spl = splimp(); ! 473: ! 474: simple_lock(&bucket->lock); ! 475: mem->next = bucket->pages; ! 476: bucket->pages = mem; ! 477: simple_unlock(&bucket->lock); ! 478: (void) splx(spl); ! 479: } ! 480: ! 481: /* ! 482: * Now link into the object's list of backed pages. ! 483: */ ! 484: ! 485: queue_enter(&object->memq, mem, vm_page_t, listq); ! 486: mem->tabled = TRUE; ! 487: ! 488: /* ! 489: * Show that the object has one more resident page. ! 490: */ ! 491: ! 492: object->resident_page_count++; ! 493: } ! 494: ! 495: /* ! 496: * vm_page_remove: [ internal use only ] ! 497: * ! 498: * Removes the given mem entry from the object/offset-page ! 499: * table and the object page list. ! 500: * ! 501: * The object and page must be locked. ! 502: */ ! 503: ! 504: void vm_page_remove( ! 505: register vm_page_t mem) ! 506: { ! 507: register vm_page_bucket_t *bucket; ! 508: register vm_page_t this; ! 509: ! 510: assert(mem->tabled); ! 511: VM_PAGE_CHECK(mem); ! 512: ! 513: if (!mem->tabled) ! 514: return; ! 515: ! 516: /* ! 517: * Remove from the object_object/offset hash table ! 518: */ ! 519: ! 520: bucket = &vm_page_buckets[vm_page_hash(mem->object, mem->offset)]; ! 521: { ! 522: int spl = splimp(); ! 523: ! 524: simple_lock(&bucket->lock); ! 525: if ((this = bucket->pages) == mem) { ! 526: /* optimize for common case */ ! 527: ! 528: bucket->pages = mem->next; ! 529: } else { ! 530: register vm_page_t *prev; ! 531: ! 532: for (prev = &this->next; ! 533: (this = *prev) != mem; ! 534: prev = &this->next) ! 535: continue; ! 536: *prev = this->next; ! 537: } ! 538: simple_unlock(&bucket->lock); ! 539: splx(spl); ! 540: } ! 541: ! 542: /* ! 543: * Now remove from the object's list of backed pages. ! 544: */ ! 545: ! 546: queue_remove(&mem->object->memq, mem, vm_page_t, listq); ! 547: ! 548: /* ! 549: * And show that the object has one fewer resident ! 550: * page. ! 551: */ ! 552: ! 553: mem->object->resident_page_count--; ! 554: ! 555: mem->tabled = FALSE; ! 556: } ! 557: ! 558: /* ! 559: * vm_page_lookup: ! 560: * ! 561: * Returns the page associated with the object/offset ! 562: * pair specified; if none is found, VM_PAGE_NULL is returned. ! 563: * ! 564: * The object must be locked. No side effects. ! 565: */ ! 566: ! 567: vm_page_t vm_page_lookup( ! 568: register vm_object_t object, ! 569: register vm_offset_t offset) ! 570: { ! 571: register vm_page_t mem; ! 572: register vm_page_bucket_t *bucket; ! 573: ! 574: /* ! 575: * Search the hash table for this object/offset pair ! 576: */ ! 577: ! 578: bucket = &vm_page_buckets[vm_page_hash(object, offset)]; ! 579: ! 580: { ! 581: int spl = splimp(); ! 582: ! 583: simple_lock(&bucket->lock); ! 584: for (mem = bucket->pages; mem != VM_PAGE_NULL; mem = mem->next) { ! 585: VM_PAGE_CHECK(mem); ! 586: if ((mem->object == object) && (mem->offset == offset)) ! 587: break; ! 588: } ! 589: simple_unlock(&bucket->lock); ! 590: splx(spl); ! 591: } ! 592: return mem; ! 593: } ! 594: ! 595: /* ! 596: * vm_page_rename: ! 597: * ! 598: * Move the given memory entry from its ! 599: * current object to the specified target object/offset. ! 600: * ! 601: * The object must be locked. ! 602: */ ! 603: void vm_page_rename( ! 604: register vm_page_t mem, ! 605: register vm_object_t new_object, ! 606: vm_offset_t new_offset) ! 607: { ! 608: /* ! 609: * Changes to mem->object require the page lock because ! 610: * the pageout daemon uses that lock to get the object. ! 611: */ ! 612: ! 613: vm_page_lock_queues(); ! 614: vm_page_remove(mem); ! 615: vm_page_insert(mem, new_object, new_offset); ! 616: vm_page_unlock_queues(); ! 617: } ! 618: ! 619: /* ! 620: * vm_page_init: ! 621: * ! 622: * Initialize the given vm_page, entering it into ! 623: * the VP table at the given (object, offset), ! 624: * and noting its physical address. ! 625: * ! 626: * Implemented using a template set up in vm_page_startup. ! 627: * All fields except those passed as arguments are static. ! 628: */ ! 629: void vm_page_init(mem, object, offset, phys_addr) ! 630: vm_page_t mem; ! 631: vm_object_t object; ! 632: vm_offset_t offset; ! 633: vm_offset_t phys_addr; ! 634: { ! 635: #define vm_page_init(page, object, offset, pa) { \ ! 636: register \ ! 637: vm_offset_t a = (pa); \ ! 638: *(page) = vm_page_template; \ ! 639: (page)->phys_addr = a; \ ! 640: vm_page_insert((page), (object), (offset)); \ ! 641: } ! 642: ! 643: vm_page_init(mem, object, offset, phys_addr); ! 644: } ! 645: ! 646: /* ! 647: * vm_page_alloc_sequential: ! 648: * ! 649: * vm_page_alloc: is a macro calling ! 650: * vm_page_alloc_sequential(object,offset,TRUE) ! 651: * ! 652: * Allocate and return a memory cell associated ! 653: * with this VM object/offset pair. Don't perform sequential ! 654: * access checks if called from ICS. ! 655: * ! 656: * Object must be locked. ! 657: */ ! 658: vm_page_t vm_page_alloc_sequential(object, offset, sequential_unmap) ! 659: vm_object_t object; ! 660: vm_offset_t offset; ! 661: boolean_t sequential_unmap; ! 662: { ! 663: register vm_page_t mem; ! 664: int spl; ! 665: ! 666: spl = splimp(); ! 667: simple_lock(&vm_page_queue_free_lock); ! 668: ! 669: if (queue_empty(&vm_page_queue_free)) { ! 670: simple_unlock(&vm_page_queue_free_lock); ! 671: splx(spl); ! 672: return(VM_PAGE_NULL); ! 673: } ! 674: ! 675: if ((vm_page_free_count < vm_page_free_reserved) && ! 676: !current_thread()->vm_privilege) { ! 677: simple_unlock(&vm_page_queue_free_lock); ! 678: splx(spl); ! 679: return(VM_PAGE_NULL); ! 680: } ! 681: ! 682: queue_remove_first(&vm_page_queue_free, mem, vm_page_t, pageq); ! 683: mem->free = FALSE; ! 684: ! 685: vm_page_free_count--; ! 686: simple_unlock(&vm_page_queue_free_lock); ! 687: splx(spl); ! 688: ! 689: vm_page_remove(mem); /* in case it is still in hash table */ ! 690: ! 691: vm_page_init(mem, object, offset, mem->phys_addr); ! 692: ! 693: /* ! 694: * Decide if we should poke the pageout daemon. ! 695: * We do this if the free count is less than the low ! 696: * water mark, or if the free count is less than the high ! 697: * water mark (but above the low water mark) and the inactive ! 698: * count is less than its target. ! 699: * ! 700: * We don't have the counts locked ... if they change a little, ! 701: * it doesn't really matter. ! 702: */ ! 703: ! 704: if ((vm_page_free_count < vm_page_free_min) || ! 705: ((vm_page_free_count < vm_page_free_target) && ! 706: (vm_page_inactive_count < vm_page_inactive_target))){ ! 707: thread_wakeup(&vm_pages_needed); ! 708: } ! 709: ! 710: /* ! 711: * Detect sequential access and inactivate previous page ! 712: */ ! 713: if (object->policy & VM_POLICY_SEQUENTIAL && sequential_unmap && ! 714: (abs(offset - object->last_alloc) == PAGE_SIZE)) { ! 715: vm_page_t last_mem; ! 716: ! 717: last_mem = vm_page_lookup(object, object->last_alloc); ! 718: if (last_mem != VM_PAGE_NULL) { ! 719: int when; ! 720: ! 721: switch (object->policy) { ! 722: case VM_POLICY_SEQ_DEACTIVATE: ! 723: when = VM_DEACTIVATE_SOON; ! 724: break; ! 725: case VM_POLICY_SEQ_FREE: ! 726: default: ! 727: when = VM_DEACTIVATE_NOW; ! 728: break; ! 729: } ! 730: vm_policy_apply(object, last_mem, when); ! 731: } ! 732: } ! 733: // else if (object->policy & VM_SEQUENTIAL && sequential_unmap) ! 734: // object->policy = VM_RANDOM; ! 735: ! 736: object->last_alloc = offset; ! 737: return(mem); ! 738: } ! 739: ! 740: /* ! 741: * vm_page_free: ! 742: * ! 743: * Returns the given page to the free list, ! 744: * disassociating it with any VM object. ! 745: * ! 746: * Object and page must be locked prior to entry. ! 747: */ ! 748: void vm_page_free(mem) ! 749: register vm_page_t mem; ! 750: { ! 751: vm_page_remove(mem); ! 752: if (!mem->free) { ! 753: vm_page_addfree(mem); ! 754: } ! 755: } ! 756: ! 757: void vm_page_addfree(mem) ! 758: register vm_page_t mem; ! 759: { ! 760: if (mem->active) { ! 761: queue_remove(&vm_page_queue_active, mem, vm_page_t, pageq); ! 762: mem->active = FALSE; ! 763: vm_page_active_count--; ! 764: } ! 765: ! 766: if (mem->inactive) { ! 767: queue_remove(&vm_page_queue_inactive, mem, vm_page_t, pageq); ! 768: mem->inactive = FALSE; ! 769: vm_page_inactive_count--; ! 770: } ! 771: ! 772: if (!mem->fictitious) { ! 773: int spl; ! 774: ! 775: spl = splimp(); ! 776: simple_lock(&vm_page_queue_free_lock); ! 777: queue_enter(&vm_page_queue_free, mem, vm_page_t, pageq); ! 778: mem->free = TRUE; ! 779: vm_page_free_count++; ! 780: simple_unlock(&vm_page_queue_free_lock); ! 781: splx(spl); ! 782: } ! 783: } ! 784: ! 785: /* ! 786: * vm_page_wire: ! 787: * ! 788: * Mark this page as wired down by yet ! 789: * another map, removing it from paging queues ! 790: * as necessary. ! 791: * ! 792: * The page queues must be locked. ! 793: */ ! 794: void vm_page_wire(mem) ! 795: register vm_page_t mem; ! 796: { ! 797: VM_PAGE_CHECK(mem); ! 798: ! 799: if (mem->wire_count == 0) { ! 800: if (mem->active) { ! 801: queue_remove(&vm_page_queue_active, mem, vm_page_t, ! 802: pageq); ! 803: vm_page_active_count--; ! 804: mem->active = FALSE; ! 805: } ! 806: if (mem->inactive) { ! 807: queue_remove(&vm_page_queue_inactive, mem, vm_page_t, ! 808: pageq); ! 809: vm_page_inactive_count--; ! 810: mem->inactive = FALSE; ! 811: } ! 812: if (mem->free) { ! 813: queue_remove(&vm_page_queue_free, mem, vm_page_t, ! 814: pageq); ! 815: vm_page_free_count--; ! 816: mem->free = FALSE; ! 817: } ! 818: vm_page_wire_count++; ! 819: } ! 820: mem->wire_count++; ! 821: } ! 822: ! 823: /* ! 824: * vm_page_unwire: ! 825: * ! 826: * Release one wiring of this page, potentially ! 827: * enabling it to be paged again. ! 828: * ! 829: * The page queues must be locked. ! 830: */ ! 831: void vm_page_unwire(mem) ! 832: register vm_page_t mem; ! 833: { ! 834: VM_PAGE_CHECK(mem); ! 835: ! 836: if (--mem->wire_count == 0) { ! 837: queue_enter(&vm_page_queue_active, mem, vm_page_t, pageq); ! 838: vm_page_active_count++; ! 839: mem->active = TRUE; ! 840: vm_page_wire_count--; ! 841: } ! 842: } ! 843: ! 844: /* ! 845: * _vm_page_deactivate: ! 846: * ! 847: * Internal routine to Returns the given page to the inactive list, ! 848: * Page is put at the head of the inactive list if age is TRUE. ! 849: * indicating that no physical maps have access ! 850: * to this page. [Used by the physical mapping system.] ! 851: * ! 852: * The page queues must be locked. ! 853: */ ! 854: static void _vm_page_deactivate(m, age) ! 855: register vm_page_t m; ! 856: register boolean_t age; ! 857: { ! 858: VM_PAGE_CHECK(m); ! 859: ! 860: /* ! 861: * Only move active pages -- ignore locked or already ! 862: * inactive ones. ! 863: */ ! 864: ! 865: if (m->active) { ! 866: pmap_clear_reference(VM_PAGE_TO_PHYS(m)); ! 867: queue_remove(&vm_page_queue_active, m, vm_page_t, pageq); ! 868: if (age) ! 869: queue_enter_first(&vm_page_queue_inactive, m, vm_page_t, pageq); ! 870: else ! 871: queue_enter(&vm_page_queue_inactive, m, vm_page_t, pageq); ! 872: m->active = FALSE; ! 873: m->inactive = TRUE; ! 874: vm_page_active_count--; ! 875: vm_page_inactive_count++; ! 876: if (m->clean && pmap_is_modified(VM_PAGE_TO_PHYS(m))) ! 877: m->clean = FALSE; ! 878: m->laundry = !m->clean; ! 879: } ! 880: } ! 881: ! 882: /* ! 883: * vm_page_deactivate: ! 884: * ! 885: * Returns the given page to the inactive list, ! 886: * indicating that no physical maps have access ! 887: * to this page. [Used by the physical mapping system.] ! 888: * ! 889: * The page queues must be locked. ! 890: */ ! 891: void vm_page_deactivate(m) ! 892: register vm_page_t m; ! 893: { ! 894: _vm_page_deactivate(m, FALSE); ! 895: } ! 896: ! 897: /* ! 898: * vm_page_deactivate_first: ! 899: * ! 900: * Returns the given page to the head of inactive list, ! 901: * indicating that no physical maps have access ! 902: * to this page. [Used by the physical mapping system.] ! 903: * ! 904: * The page queues must be locked. ! 905: */ ! 906: void vm_page_deactivate_first(m) ! 907: register vm_page_t m; ! 908: { ! 909: _vm_page_deactivate(m, FALSE); ! 910: } ! 911: ! 912: /* ! 913: * vm_page_activate: ! 914: * ! 915: * Put the specified page on the active list (if appropriate). ! 916: * ! 917: * The page queues must be locked. ! 918: */ ! 919: ! 920: void vm_page_activate(m) ! 921: register vm_page_t m; ! 922: { ! 923: VM_PAGE_CHECK(m); ! 924: ! 925: ! 926: if (m->inactive) { ! 927: queue_remove(&vm_page_queue_inactive, m, vm_page_t, ! 928: pageq); ! 929: vm_page_inactive_count--; ! 930: m->inactive = FALSE; ! 931: } ! 932: if (m->free) { ! 933: queue_remove(&vm_page_queue_free, m, vm_page_t, ! 934: pageq); ! 935: vm_page_free_count--; ! 936: m->free = FALSE; ! 937: } ! 938: if (m->wire_count == 0) { ! 939: if (m->active) ! 940: panic("vm_page_activate: already active"); ! 941: ! 942: queue_enter(&vm_page_queue_active, m, vm_page_t, pageq); ! 943: m->active = TRUE; ! 944: vm_page_active_count++; ! 945: } ! 946: } ! 947: ! 948: /* ! 949: * vm_page_zero_fill: ! 950: * ! 951: * Zero-fill the specified page. ! 952: * Written as a standard pagein routine, to ! 953: * be used by the zero-fill object. ! 954: */ ! 955: ! 956: boolean_t vm_page_zero_fill(m) ! 957: vm_page_t m; ! 958: { ! 959: VM_PAGE_CHECK(m); ! 960: ! 961: pmap_zero_page(VM_PAGE_TO_PHYS(m)); ! 962: return(TRUE); ! 963: } ! 964: ! 965: /* ! 966: * vm_page_copy: ! 967: * ! 968: * Copy one page to another ! 969: */ ! 970: ! 971: void vm_page_copy(src_m, dest_m) ! 972: vm_page_t src_m; ! 973: vm_page_t dest_m; ! 974: { ! 975: VM_PAGE_CHECK(src_m); ! 976: VM_PAGE_CHECK(dest_m); ! 977: ! 978: pmap_copy_page(VM_PAGE_TO_PHYS(src_m), VM_PAGE_TO_PHYS(dest_m)); ! 979: } ! 980: ! 981: ! 982: /* ! 983: * vm_page_to_phys: ! 984: * ! 985: * return the physical page, this routine is here so that ! 986: * loadable drivers like macfs do not have to deref vm_page_t ! 987: * directly. ! 988: */ ! 989: ! 990: vm_offset_t ! 991: vm_page_to_phys(m) ! 992: vm_page_t m; ! 993: { ! 994: return(VM_PAGE_TO_PHYS(m)); ! 995: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.