|
|
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) 1992,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: * File: vm/memory_object.c ! 52: * Author: Michael Wayne Young ! 53: * ! 54: * External memory management interface control functions. ! 55: */ ! 56: ! 57: /* ! 58: * Interface dependencies: ! 59: */ ! 60: ! 61: #include <mach/std_types.h> /* For pointer_t */ ! 62: #include <mach/mach_types.h> ! 63: ! 64: #include <mach/kern_return.h> ! 65: #include <vm/vm_object.h> ! 66: #include <mach/memory_object.h> ! 67: #include <mach/memory_object_user.h> ! 68: #include <mach/memory_object_default.h> ! 69: #include <mach/boolean.h> ! 70: #include <mach/vm_prot.h> ! 71: #include <mach/message.h> ! 72: ! 73: /* ! 74: * Implementation dependencies: ! 75: */ ! 76: #include <vm/memory_object.h> ! 77: #include <vm/vm_page.h> ! 78: #include <vm/vm_pageout.h> ! 79: #include <vm/pmap.h> /* For copy_to_phys, pmap_clear_modify */ ! 80: #include <kern/thread.h> /* For current_thread() */ ! 81: #include <kern/host.h> ! 82: #include <vm/vm_kern.h> /* For kernel_map, vm_move */ ! 83: #include <vm/vm_map.h> /* For vm_map_pageable */ ! 84: #include <ipc/ipc_port.h> ! 85: ! 86: #include <norma_vm.h> ! 87: #include <norma_ipc.h> ! 88: #if NORMA_VM ! 89: #include <norma/xmm_server_rename.h> ! 90: #endif NORMA_VM ! 91: #include <mach_pagemap.h> ! 92: #if MACH_PAGEMAP ! 93: #include <vm/vm_external.h> ! 94: #endif MACH_PAGEMAP ! 95: ! 96: typedef int memory_object_lock_result_t; /* moved from below */ ! 97: ! 98: ! 99: ipc_port_t memory_manager_default = IP_NULL; ! 100: decl_simple_lock_data(,memory_manager_default_lock) ! 101: ! 102: /* ! 103: * Important note: ! 104: * All of these routines gain a reference to the ! 105: * object (first argument) as part of the automatic ! 106: * argument conversion. Explicit deallocation is necessary. ! 107: */ ! 108: ! 109: #if !NORMA_VM ! 110: /* ! 111: * If successful, destroys the map copy object. ! 112: */ ! 113: kern_return_t memory_object_data_provided(object, offset, data, data_cnt, ! 114: lock_value) ! 115: vm_object_t object; ! 116: vm_offset_t offset; ! 117: pointer_t data; ! 118: unsigned int data_cnt; ! 119: vm_prot_t lock_value; ! 120: { ! 121: return memory_object_data_supply(object, offset, (vm_map_copy_t) data, ! 122: data_cnt, lock_value, FALSE, IP_NULL, ! 123: 0); ! 124: } ! 125: #endif !NORMA_VM ! 126: ! 127: ! 128: kern_return_t memory_object_data_supply(object, offset, data_copy, data_cnt, ! 129: lock_value, precious, reply_to, reply_to_type) ! 130: register ! 131: vm_object_t object; ! 132: register ! 133: vm_offset_t offset; ! 134: vm_map_copy_t data_copy; ! 135: unsigned int data_cnt; ! 136: vm_prot_t lock_value; ! 137: boolean_t precious; ! 138: ipc_port_t reply_to; ! 139: mach_msg_type_name_t reply_to_type; ! 140: { ! 141: kern_return_t result = KERN_SUCCESS; ! 142: vm_offset_t error_offset = 0; ! 143: register ! 144: vm_page_t m; ! 145: register ! 146: vm_page_t data_m; ! 147: vm_size_t original_length; ! 148: vm_offset_t original_offset; ! 149: vm_page_t *page_list; ! 150: boolean_t was_absent; ! 151: vm_map_copy_t orig_copy = data_copy; ! 152: ! 153: /* ! 154: * Look for bogus arguments ! 155: */ ! 156: ! 157: if (object == VM_OBJECT_NULL) { ! 158: return(KERN_INVALID_ARGUMENT); ! 159: } ! 160: ! 161: if (lock_value & ~VM_PROT_ALL) { ! 162: vm_object_deallocate(object); ! 163: return(KERN_INVALID_ARGUMENT); ! 164: } ! 165: ! 166: if ((data_cnt % PAGE_SIZE) != 0) { ! 167: vm_object_deallocate(object); ! 168: return(KERN_INVALID_ARGUMENT); ! 169: } ! 170: ! 171: /* ! 172: * Adjust the offset from the memory object to the offset ! 173: * within the vm_object. ! 174: */ ! 175: ! 176: original_length = data_cnt; ! 177: original_offset = offset; ! 178: ! 179: assert(data_copy->type == VM_MAP_COPY_PAGE_LIST); ! 180: page_list = &data_copy->cpy_page_list[0]; ! 181: ! 182: vm_object_lock(object); ! 183: vm_object_paging_begin(object); ! 184: offset -= object->paging_offset; ! 185: ! 186: /* ! 187: * Loop over copy stealing pages for pagein. ! 188: */ ! 189: ! 190: for (; data_cnt > 0 ; data_cnt -= PAGE_SIZE, offset += PAGE_SIZE) { ! 191: ! 192: assert(data_copy->cpy_npages > 0); ! 193: data_m = *page_list; ! 194: ! 195: if (data_m == VM_PAGE_NULL || data_m->tabled || ! 196: data_m->error || data_m->absent || data_m->fictitious) { ! 197: ! 198: panic("Data_supply: bad page"); ! 199: } ! 200: ! 201: /* ! 202: * Look up target page and check its state. ! 203: */ ! 204: ! 205: retry_lookup: ! 206: m = vm_page_lookup(object,offset); ! 207: if (m == VM_PAGE_NULL) { ! 208: was_absent = FALSE; ! 209: } ! 210: else { ! 211: if (m->absent && m->busy) { ! 212: ! 213: /* ! 214: * Page was requested. Free the busy ! 215: * page waiting for it. Insertion ! 216: * of new page happens below. ! 217: */ ! 218: ! 219: VM_PAGE_FREE(m); ! 220: was_absent = TRUE; ! 221: } ! 222: else { ! 223: ! 224: /* ! 225: * Have to wait for page that is busy and ! 226: * not absent. This is probably going to ! 227: * be an error, but go back and check. ! 228: */ ! 229: if (m->busy) { ! 230: PAGE_ASSERT_WAIT(m, FALSE); ! 231: vm_object_unlock(object); ! 232: thread_block((void (*)()) 0); ! 233: vm_object_lock(object); ! 234: goto retry_lookup; ! 235: } ! 236: ! 237: /* ! 238: * Page already present; error. ! 239: * This is an error if data is precious. ! 240: */ ! 241: result = KERN_MEMORY_PRESENT; ! 242: error_offset = offset + object->paging_offset; ! 243: ! 244: break; ! 245: } ! 246: } ! 247: ! 248: /* ! 249: * Ok to pagein page. Target object now has no page ! 250: * at offset. Set the page parameters, then drop ! 251: * in new page and set up pageout state. Object is ! 252: * still locked here. ! 253: * ! 254: * Must clear busy bit in page before inserting it. ! 255: * Ok to skip wakeup logic because nobody else ! 256: * can possibly know about this page. ! 257: */ ! 258: ! 259: data_m->busy = FALSE; ! 260: data_m->dirty = FALSE; ! 261: pmap_clear_modify(data_m->phys_addr); ! 262: ! 263: data_m->page_lock = lock_value; ! 264: data_m->unlock_request = VM_PROT_NONE; ! 265: data_m->precious = precious; ! 266: ! 267: vm_page_lock_queues(); ! 268: vm_page_insert(data_m, object, offset); ! 269: ! 270: if (was_absent) ! 271: vm_page_activate(data_m); ! 272: else ! 273: vm_page_deactivate(data_m); ! 274: ! 275: vm_page_unlock_queues(); ! 276: ! 277: /* ! 278: * Null out this page list entry, and advance to next ! 279: * page. ! 280: */ ! 281: ! 282: *page_list++ = VM_PAGE_NULL; ! 283: ! 284: if (--(data_copy->cpy_npages) == 0 && ! 285: vm_map_copy_has_cont(data_copy)) { ! 286: vm_map_copy_t new_copy; ! 287: ! 288: vm_object_unlock(object); ! 289: ! 290: vm_map_copy_invoke_cont(data_copy, &new_copy, &result); ! 291: ! 292: if (result == KERN_SUCCESS) { ! 293: ! 294: /* ! 295: * Consume on success requires that ! 296: * we keep the original vm_map_copy ! 297: * around in case something fails. ! 298: * Free the old copy if it's not the original ! 299: */ ! 300: if (data_copy != orig_copy) { ! 301: vm_map_copy_discard(data_copy); ! 302: } ! 303: ! 304: if ((data_copy = new_copy) != VM_MAP_COPY_NULL) ! 305: page_list = &data_copy->cpy_page_list[0]; ! 306: ! 307: vm_object_lock(object); ! 308: } ! 309: else { ! 310: vm_object_lock(object); ! 311: error_offset = offset + object->paging_offset + ! 312: PAGE_SIZE; ! 313: break; ! 314: } ! 315: } ! 316: } ! 317: ! 318: /* ! 319: * Send reply if one was requested. ! 320: */ ! 321: vm_object_paging_end(object); ! 322: vm_object_unlock(object); ! 323: ! 324: if (vm_map_copy_has_cont(data_copy)) ! 325: vm_map_copy_abort_cont(data_copy); ! 326: ! 327: if (IP_VALID(reply_to)) { ! 328: memory_object_supply_completed( ! 329: reply_to, reply_to_type, ! 330: object->pager_request, ! 331: original_offset, ! 332: original_length, ! 333: result, ! 334: error_offset); ! 335: } ! 336: ! 337: vm_object_deallocate(object); ! 338: ! 339: /* ! 340: * Consume on success: The final data copy must be ! 341: * be discarded if it is not the original. The original ! 342: * gets discarded only if this routine succeeds. ! 343: */ ! 344: if (data_copy != orig_copy) ! 345: vm_map_copy_discard(data_copy); ! 346: if (result == KERN_SUCCESS) ! 347: vm_map_copy_discard(orig_copy); ! 348: ! 349: ! 350: return(result); ! 351: } ! 352: ! 353: kern_return_t memory_object_data_error(object, offset, size, error_value) ! 354: vm_object_t object; ! 355: vm_offset_t offset; ! 356: vm_size_t size; ! 357: kern_return_t error_value; ! 358: { ! 359: if (object == VM_OBJECT_NULL) ! 360: return(KERN_INVALID_ARGUMENT); ! 361: ! 362: if (size != round_page(size)) ! 363: return(KERN_INVALID_ARGUMENT); ! 364: ! 365: #ifdef lint ! 366: /* Error value is ignored at this time */ ! 367: error_value++; ! 368: #endif ! 369: ! 370: vm_object_lock(object); ! 371: offset -= object->paging_offset; ! 372: ! 373: while (size != 0) { ! 374: register vm_page_t m; ! 375: ! 376: m = vm_page_lookup(object, offset); ! 377: if ((m != VM_PAGE_NULL) && m->busy && m->absent) { ! 378: m->error = TRUE; ! 379: m->absent = FALSE; ! 380: vm_object_absent_release(object); ! 381: ! 382: PAGE_WAKEUP_DONE(m); ! 383: ! 384: vm_page_lock_queues(); ! 385: vm_page_activate(m); ! 386: vm_page_unlock_queues(); ! 387: } ! 388: ! 389: size -= PAGE_SIZE; ! 390: offset += PAGE_SIZE; ! 391: } ! 392: vm_object_unlock(object); ! 393: ! 394: vm_object_deallocate(object); ! 395: return(KERN_SUCCESS); ! 396: } ! 397: ! 398: kern_return_t memory_object_data_unavailable(object, offset, size) ! 399: vm_object_t object; ! 400: vm_offset_t offset; ! 401: vm_size_t size; ! 402: { ! 403: #if MACH_PAGEMAP ! 404: vm_external_t existence_info = VM_EXTERNAL_NULL; ! 405: #endif MACH_PAGEMAP ! 406: ! 407: if (object == VM_OBJECT_NULL) ! 408: return(KERN_INVALID_ARGUMENT); ! 409: ! 410: if (size != round_page(size)) ! 411: return(KERN_INVALID_ARGUMENT); ! 412: ! 413: #if MACH_PAGEMAP ! 414: if ((offset == 0) && (size > VM_EXTERNAL_LARGE_SIZE) && ! 415: (object->existence_info == VM_EXTERNAL_NULL)) { ! 416: existence_info = vm_external_create(VM_EXTERNAL_SMALL_SIZE); ! 417: } ! 418: #endif MACH_PAGEMAP ! 419: ! 420: vm_object_lock(object); ! 421: #if MACH_PAGEMAP ! 422: if (existence_info != VM_EXTERNAL_NULL) { ! 423: object->existence_info = existence_info; ! 424: } ! 425: if ((offset == 0) && (size > VM_EXTERNAL_LARGE_SIZE)) { ! 426: vm_object_unlock(object); ! 427: vm_object_deallocate(object); ! 428: return(KERN_SUCCESS); ! 429: } ! 430: #endif MACH_PAGEMAP ! 431: offset -= object->paging_offset; ! 432: ! 433: while (size != 0) { ! 434: register vm_page_t m; ! 435: ! 436: /* ! 437: * We're looking for pages that are both busy and ! 438: * absent (waiting to be filled), converting them ! 439: * to just absent. ! 440: * ! 441: * Pages that are just busy can be ignored entirely. ! 442: */ ! 443: ! 444: m = vm_page_lookup(object, offset); ! 445: if ((m != VM_PAGE_NULL) && m->busy && m->absent) { ! 446: PAGE_WAKEUP_DONE(m); ! 447: ! 448: vm_page_lock_queues(); ! 449: vm_page_activate(m); ! 450: vm_page_unlock_queues(); ! 451: } ! 452: size -= PAGE_SIZE; ! 453: offset += PAGE_SIZE; ! 454: } ! 455: ! 456: vm_object_unlock(object); ! 457: ! 458: vm_object_deallocate(object); ! 459: return(KERN_SUCCESS); ! 460: } ! 461: ! 462: /* ! 463: * Routine: memory_object_lock_page ! 464: * ! 465: * Description: ! 466: * Perform the appropriate lock operations on the ! 467: * given page. See the description of ! 468: * "memory_object_lock_request" for the meanings ! 469: * of the arguments. ! 470: * ! 471: * Returns an indication that the operation ! 472: * completed, blocked, or that the page must ! 473: * be cleaned. ! 474: */ ! 475: ! 476: #define MEMORY_OBJECT_LOCK_RESULT_DONE 0 ! 477: #define MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK 1 ! 478: #define MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN 2 ! 479: #define MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN 3 ! 480: ! 481: memory_object_lock_result_t memory_object_lock_page(m, should_return, ! 482: should_flush, prot) ! 483: vm_page_t m; ! 484: memory_object_return_t should_return; ! 485: boolean_t should_flush; ! 486: vm_prot_t prot; ! 487: { ! 488: /* ! 489: * Don't worry about pages for which the kernel ! 490: * does not have any data. ! 491: */ ! 492: ! 493: if (m->absent) ! 494: return(MEMORY_OBJECT_LOCK_RESULT_DONE); ! 495: ! 496: /* ! 497: * If we cannot change access to the page, ! 498: * either because a mapping is in progress ! 499: * (busy page) or because a mapping has been ! 500: * wired, then give up. ! 501: */ ! 502: ! 503: if (m->busy) ! 504: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK); ! 505: ! 506: assert(!m->fictitious); ! 507: ! 508: if (m->wire_count != 0) { ! 509: /* ! 510: * If no change would take place ! 511: * anyway, return successfully. ! 512: * ! 513: * No change means: ! 514: * Not flushing AND ! 515: * No change to page lock [2 checks] AND ! 516: * Don't need to send page to manager ! 517: * ! 518: * Don't need to send page to manager means: ! 519: * No clean or return request OR ( ! 520: * Page is not dirty [2 checks] AND ( ! 521: * Page is not precious OR ! 522: * No request to return precious pages )) ! 523: * ! 524: * Now isn't that straightforward and obvious ?? ;-) ! 525: * ! 526: * XXX This doesn't handle sending a copy of a wired ! 527: * XXX page to the pager, but that will require some ! 528: * XXX significant surgery. ! 529: */ ! 530: ! 531: if (!should_flush && ! 532: ((m->page_lock == prot) || (prot == VM_PROT_NO_CHANGE)) && ! 533: ((should_return == MEMORY_OBJECT_RETURN_NONE) || ! 534: (!m->dirty && !pmap_is_modified(m->phys_addr) && ! 535: (!m->precious || ! 536: should_return != MEMORY_OBJECT_RETURN_ALL)))) { ! 537: /* ! 538: * Restart page unlock requests, ! 539: * even though no change took place. ! 540: * [Memory managers may be expecting ! 541: * to see new requests.] ! 542: */ ! 543: m->unlock_request = VM_PROT_NONE; ! 544: PAGE_WAKEUP(m); ! 545: ! 546: return(MEMORY_OBJECT_LOCK_RESULT_DONE); ! 547: } ! 548: ! 549: return(MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK); ! 550: } ! 551: ! 552: /* ! 553: * If the page is to be flushed, allow ! 554: * that to be done as part of the protection. ! 555: */ ! 556: ! 557: if (should_flush) ! 558: prot = VM_PROT_ALL; ! 559: ! 560: /* ! 561: * Set the page lock. ! 562: * ! 563: * If we are decreasing permission, do it now; ! 564: * let the fault handler take care of increases ! 565: * (pmap_page_protect may not increase protection). ! 566: */ ! 567: ! 568: if (prot != VM_PROT_NO_CHANGE) { ! 569: if ((m->page_lock ^ prot) & prot) { ! 570: pmap_page_protect(m->phys_addr, VM_PROT_ALL & ~prot); ! 571: } ! 572: m->page_lock = prot; ! 573: ! 574: /* ! 575: * Restart any past unlock requests, even if no ! 576: * change resulted. If the manager explicitly ! 577: * requested no protection change, then it is assumed ! 578: * to be remembering past requests. ! 579: */ ! 580: ! 581: m->unlock_request = VM_PROT_NONE; ! 582: PAGE_WAKEUP(m); ! 583: } ! 584: ! 585: /* ! 586: * Handle cleaning. ! 587: */ ! 588: ! 589: if (should_return != MEMORY_OBJECT_RETURN_NONE) { ! 590: /* ! 591: * Check whether the page is dirty. If ! 592: * write permission has not been removed, ! 593: * this may have unpredictable results. ! 594: */ ! 595: ! 596: if (!m->dirty) ! 597: m->dirty = pmap_is_modified(m->phys_addr); ! 598: ! 599: if (m->dirty || (m->precious && ! 600: should_return == MEMORY_OBJECT_RETURN_ALL)) { ! 601: /* ! 602: * If we weren't planning ! 603: * to flush the page anyway, ! 604: * we may need to remove the ! 605: * page from the pageout ! 606: * system and from physical ! 607: * maps now. ! 608: */ ! 609: ! 610: vm_page_lock_queues(); ! 611: VM_PAGE_QUEUES_REMOVE(m); ! 612: vm_page_unlock_queues(); ! 613: ! 614: if (!should_flush) ! 615: pmap_page_protect(m->phys_addr, ! 616: VM_PROT_NONE); ! 617: ! 618: /* ! 619: * Cleaning a page will cause ! 620: * it to be flushed. ! 621: */ ! 622: ! 623: if (m->dirty) ! 624: return(MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN); ! 625: else ! 626: return(MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN); ! 627: } ! 628: } ! 629: ! 630: /* ! 631: * Handle flushing ! 632: */ ! 633: ! 634: if (should_flush) { ! 635: VM_PAGE_FREE(m); ! 636: } else { ! 637: extern boolean_t vm_page_deactivate_hint; ! 638: ! 639: /* ! 640: * XXX Make clean but not flush a paging hint, ! 641: * and deactivate the pages. This is a hack ! 642: * because it overloads flush/clean with ! 643: * implementation-dependent meaning. This only ! 644: * happens to pages that are already clean. ! 645: */ ! 646: ! 647: if (vm_page_deactivate_hint && ! 648: (should_return != MEMORY_OBJECT_RETURN_NONE)) { ! 649: vm_page_lock_queues(); ! 650: vm_page_deactivate(m); ! 651: vm_page_unlock_queues(); ! 652: } ! 653: } ! 654: ! 655: return(MEMORY_OBJECT_LOCK_RESULT_DONE); ! 656: } ! 657: ! 658: /* ! 659: * Routine: memory_object_lock_request [user interface] ! 660: * ! 661: * Description: ! 662: * Control use of the data associated with the given ! 663: * memory object. For each page in the given range, ! 664: * perform the following operations, in order: ! 665: * 1) restrict access to the page (disallow ! 666: * forms specified by "prot"); ! 667: * 2) return data to the manager (if "should_return" ! 668: * is RETURN_DIRTY and the page is dirty, or ! 669: * "should_return" is RETURN_ALL and the page ! 670: * is either dirty or precious); and, ! 671: * 3) flush the cached copy (if "should_flush" ! 672: * is asserted). ! 673: * The set of pages is defined by a starting offset ! 674: * ("offset") and size ("size"). Only pages with the ! 675: * same page alignment as the starting offset are ! 676: * considered. ! 677: * ! 678: * A single acknowledgement is sent (to the "reply_to" ! 679: * port) when these actions are complete. If successful, ! 680: * the naked send right for reply_to is consumed. ! 681: */ ! 682: ! 683: kern_return_t ! 684: memory_object_lock_request(object, offset, size, ! 685: should_return, should_flush, prot, ! 686: reply_to, reply_to_type) ! 687: register vm_object_t object; ! 688: register vm_offset_t offset; ! 689: register vm_size_t size; ! 690: memory_object_return_t should_return; ! 691: boolean_t should_flush; ! 692: vm_prot_t prot; ! 693: ipc_port_t reply_to; ! 694: mach_msg_type_name_t reply_to_type; ! 695: { ! 696: register vm_page_t m; ! 697: vm_offset_t original_offset = offset; ! 698: vm_size_t original_size = size; ! 699: vm_offset_t paging_offset = 0; ! 700: vm_object_t new_object = VM_OBJECT_NULL; ! 701: vm_offset_t new_offset = 0; ! 702: vm_offset_t last_offset = offset; ! 703: int page_lock_result; ! 704: int pageout_action = 0; /* '=0' to quiet lint */ ! 705: ! 706: #define DATA_WRITE_MAX 32 ! 707: vm_page_t holding_pages[DATA_WRITE_MAX]; ! 708: ! 709: /* ! 710: * Check for bogus arguments. ! 711: */ ! 712: if (object == VM_OBJECT_NULL || ! 713: ((prot & ~VM_PROT_ALL) != 0 && prot != VM_PROT_NO_CHANGE)) ! 714: return (KERN_INVALID_ARGUMENT); ! 715: ! 716: size = round_page(size); ! 717: ! 718: /* ! 719: * Lock the object, and acquire a paging reference to ! 720: * prevent the memory_object and control ports from ! 721: * being destroyed. ! 722: */ ! 723: ! 724: vm_object_lock(object); ! 725: vm_object_paging_begin(object); ! 726: offset -= object->paging_offset; ! 727: ! 728: /* ! 729: * To avoid blocking while scanning for pages, save ! 730: * dirty pages to be cleaned all at once. ! 731: * ! 732: * XXXO A similar strategy could be used to limit the ! 733: * number of times that a scan must be restarted for ! 734: * other reasons. Those pages that would require blocking ! 735: * could be temporarily collected in another list, or ! 736: * their offsets could be recorded in a small array. ! 737: */ ! 738: ! 739: /* ! 740: * XXX NOTE: May want to consider converting this to a page list ! 741: * XXX vm_map_copy interface. Need to understand object ! 742: * XXX coalescing implications before doing so. ! 743: */ ! 744: ! 745: #define PAGEOUT_PAGES \ ! 746: MACRO_BEGIN \ ! 747: vm_map_copy_t copy; \ ! 748: register int i; \ ! 749: register vm_page_t hp; \ ! 750: \ ! 751: vm_object_unlock(object); \ ! 752: \ ! 753: (void) vm_map_copyin_object(new_object, 0, new_offset, ©); \ ! 754: \ ! 755: if (object->use_old_pageout) { \ ! 756: assert(pageout_action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN); \ ! 757: (void) memory_object_data_write( \ ! 758: object->pager, \ ! 759: object->pager_request, \ ! 760: paging_offset, \ ! 761: (pointer_t) copy, \ ! 762: new_offset); \ ! 763: } \ ! 764: else { \ ! 765: (void) memory_object_data_return( \ ! 766: object->pager, \ ! 767: object->pager_request, \ ! 768: paging_offset, \ ! 769: (pointer_t) copy, \ ! 770: new_offset, \ ! 771: (pageout_action == MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN), \ ! 772: !should_flush); \ ! 773: } \ ! 774: \ ! 775: vm_object_lock(object); \ ! 776: \ ! 777: for (i = 0; i < atop(new_offset); i++) { \ ! 778: hp = holding_pages[i]; \ ! 779: if (hp != VM_PAGE_NULL) \ ! 780: VM_PAGE_FREE(hp); \ ! 781: } \ ! 782: \ ! 783: new_object = VM_OBJECT_NULL; \ ! 784: MACRO_END ! 785: ! 786: for (; ! 787: size != 0; ! 788: size -= PAGE_SIZE, offset += PAGE_SIZE) ! 789: { ! 790: /* ! 791: * Limit the number of pages to be cleaned at once. ! 792: */ ! 793: if (new_object != VM_OBJECT_NULL && ! 794: new_offset >= PAGE_SIZE * DATA_WRITE_MAX) ! 795: { ! 796: PAGEOUT_PAGES; ! 797: } ! 798: ! 799: while ((m = vm_page_lookup(object, offset)) != VM_PAGE_NULL) { ! 800: switch ((page_lock_result = memory_object_lock_page(m, ! 801: should_return, ! 802: should_flush, ! 803: prot))) ! 804: { ! 805: case MEMORY_OBJECT_LOCK_RESULT_DONE: ! 806: /* ! 807: * End of a cluster of dirty pages. ! 808: */ ! 809: if (new_object != VM_OBJECT_NULL) { ! 810: PAGEOUT_PAGES; ! 811: continue; ! 812: } ! 813: break; ! 814: ! 815: case MEMORY_OBJECT_LOCK_RESULT_MUST_BLOCK: ! 816: /* ! 817: * Since it is necessary to block, ! 818: * clean any dirty pages now. ! 819: */ ! 820: if (new_object != VM_OBJECT_NULL) { ! 821: PAGEOUT_PAGES; ! 822: continue; ! 823: } ! 824: ! 825: PAGE_ASSERT_WAIT(m, FALSE); ! 826: vm_object_unlock(object); ! 827: thread_block((void (*)()) 0); ! 828: vm_object_lock(object); ! 829: continue; ! 830: ! 831: case MEMORY_OBJECT_LOCK_RESULT_MUST_CLEAN: ! 832: case MEMORY_OBJECT_LOCK_RESULT_MUST_RETURN: ! 833: /* ! 834: * The clean and return cases are similar. ! 835: * ! 836: * Mark the page busy since we unlock the ! 837: * object below. ! 838: */ ! 839: m->busy = TRUE; ! 840: ! 841: /* ! 842: * if this would form a discontiguous block, ! 843: * clean the old pages and start anew. ! 844: * ! 845: * NOTE: The first time through here, new_object ! 846: * is null, hiding the fact that pageout_action ! 847: * is not initialized. ! 848: */ ! 849: if (new_object != VM_OBJECT_NULL && ! 850: (last_offset != offset || ! 851: pageout_action != page_lock_result)) { ! 852: PAGEOUT_PAGES; ! 853: } ! 854: ! 855: vm_object_unlock(object); ! 856: ! 857: /* ! 858: * If we have not already allocated an object ! 859: * for a range of pages to be written, do so ! 860: * now. ! 861: */ ! 862: if (new_object == VM_OBJECT_NULL) { ! 863: new_object = vm_object_allocate(original_size); ! 864: new_offset = 0; ! 865: paging_offset = m->offset + ! 866: object->paging_offset; ! 867: pageout_action = page_lock_result; ! 868: } ! 869: ! 870: /* ! 871: * Move or copy the dirty page into the ! 872: * new object. ! 873: */ ! 874: m = vm_pageout_setup(m, ! 875: m->offset + object->paging_offset, ! 876: new_object, ! 877: new_offset, ! 878: should_flush); ! 879: ! 880: /* ! 881: * Save the holding page if there is one. ! 882: */ ! 883: holding_pages[atop(new_offset)] = m; ! 884: new_offset += PAGE_SIZE; ! 885: last_offset = offset + PAGE_SIZE; ! 886: ! 887: vm_object_lock(object); ! 888: break; ! 889: } ! 890: break; ! 891: } ! 892: } ! 893: ! 894: /* ! 895: * We have completed the scan for applicable pages. ! 896: * Clean any pages that have been saved. ! 897: */ ! 898: if (new_object != VM_OBJECT_NULL) { ! 899: PAGEOUT_PAGES; ! 900: } ! 901: ! 902: if (IP_VALID(reply_to)) { ! 903: vm_object_unlock(object); ! 904: ! 905: /* consumes our naked send-once/send right for reply_to */ ! 906: (void) memory_object_lock_completed(reply_to, reply_to_type, ! 907: object->pager_request, original_offset, original_size); ! 908: ! 909: vm_object_lock(object); ! 910: } ! 911: ! 912: vm_object_paging_end(object); ! 913: vm_object_unlock(object); ! 914: vm_object_deallocate(object); ! 915: ! 916: return (KERN_SUCCESS); ! 917: } ! 918: ! 919: #if !NORMA_VM ! 920: /* ! 921: * Old version of memory_object_lock_request. ! 922: */ ! 923: kern_return_t ! 924: xxx_memory_object_lock_request(object, offset, size, ! 925: should_clean, should_flush, prot, ! 926: reply_to, reply_to_type) ! 927: register vm_object_t object; ! 928: register vm_offset_t offset; ! 929: register vm_size_t size; ! 930: boolean_t should_clean; ! 931: boolean_t should_flush; ! 932: vm_prot_t prot; ! 933: ipc_port_t reply_to; ! 934: mach_msg_type_name_t reply_to_type; ! 935: { ! 936: register int should_return; ! 937: ! 938: if (should_clean) ! 939: should_return = MEMORY_OBJECT_RETURN_DIRTY; ! 940: else ! 941: should_return = MEMORY_OBJECT_RETURN_NONE; ! 942: ! 943: return(memory_object_lock_request(object,offset,size, ! 944: should_return, should_flush, prot, ! 945: reply_to, reply_to_type)); ! 946: } ! 947: #endif !NORMA_VM ! 948: ! 949: kern_return_t ! 950: memory_object_set_attributes_common(object, object_ready, may_cache, ! 951: copy_strategy, use_old_pageout) ! 952: vm_object_t object; ! 953: boolean_t object_ready; ! 954: boolean_t may_cache; ! 955: memory_object_copy_strategy_t copy_strategy; ! 956: boolean_t use_old_pageout; ! 957: { ! 958: if (object == VM_OBJECT_NULL) ! 959: return(KERN_INVALID_ARGUMENT); ! 960: ! 961: /* ! 962: * Verify the attributes of importance ! 963: */ ! 964: ! 965: switch(copy_strategy) { ! 966: case MEMORY_OBJECT_COPY_NONE: ! 967: case MEMORY_OBJECT_COPY_CALL: ! 968: case MEMORY_OBJECT_COPY_DELAY: ! 969: case MEMORY_OBJECT_COPY_TEMPORARY: ! 970: break; ! 971: default: ! 972: vm_object_deallocate(object); ! 973: return(KERN_INVALID_ARGUMENT); ! 974: } ! 975: ! 976: if (object_ready) ! 977: object_ready = TRUE; ! 978: if (may_cache) ! 979: may_cache = TRUE; ! 980: ! 981: vm_object_lock(object); ! 982: ! 983: /* ! 984: * Wake up anyone waiting for the ready attribute ! 985: * to become asserted. ! 986: */ ! 987: ! 988: if (object_ready && !object->pager_ready) { ! 989: object->use_old_pageout = use_old_pageout; ! 990: vm_object_wakeup(object, VM_OBJECT_EVENT_PAGER_READY); ! 991: } ! 992: ! 993: /* ! 994: * Copy the attributes ! 995: */ ! 996: ! 997: object->can_persist = may_cache; ! 998: object->pager_ready = object_ready; ! 999: if (copy_strategy == MEMORY_OBJECT_COPY_TEMPORARY) { ! 1000: object->temporary = TRUE; ! 1001: } else { ! 1002: object->copy_strategy = copy_strategy; ! 1003: } ! 1004: ! 1005: vm_object_unlock(object); ! 1006: ! 1007: vm_object_deallocate(object); ! 1008: ! 1009: return(KERN_SUCCESS); ! 1010: } ! 1011: ! 1012: #if !NORMA_VM ! 1013: ! 1014: /* ! 1015: * XXX rpd claims that reply_to could be obviated in favor of a client ! 1016: * XXX stub that made change_attributes an RPC. Need investigation. ! 1017: */ ! 1018: ! 1019: kern_return_t memory_object_change_attributes(object, may_cache, ! 1020: copy_strategy, reply_to, reply_to_type) ! 1021: vm_object_t object; ! 1022: boolean_t may_cache; ! 1023: memory_object_copy_strategy_t copy_strategy; ! 1024: ipc_port_t reply_to; ! 1025: mach_msg_type_name_t reply_to_type; ! 1026: { ! 1027: kern_return_t result; ! 1028: ! 1029: /* ! 1030: * Do the work and throw away our object reference. It ! 1031: * is important that the object reference be deallocated ! 1032: * BEFORE sending the reply. The whole point of the reply ! 1033: * is that it shows up after the terminate message that ! 1034: * may be generated by setting the object uncacheable. ! 1035: * ! 1036: * XXX may_cache may become a tri-valued variable to handle ! 1037: * XXX uncache if not in use. ! 1038: */ ! 1039: result = memory_object_set_attributes_common(object, TRUE, ! 1040: may_cache, copy_strategy, ! 1041: FALSE); ! 1042: ! 1043: if (IP_VALID(reply_to)) { ! 1044: ! 1045: /* consumes our naked send-once/send right for reply_to */ ! 1046: (void) memory_object_change_completed(reply_to, reply_to_type, ! 1047: may_cache, copy_strategy); ! 1048: ! 1049: } ! 1050: ! 1051: return(result); ! 1052: } ! 1053: ! 1054: kern_return_t ! 1055: memory_object_set_attributes(object, object_ready, may_cache, copy_strategy) ! 1056: vm_object_t object; ! 1057: boolean_t object_ready; ! 1058: boolean_t may_cache; ! 1059: memory_object_copy_strategy_t copy_strategy; ! 1060: { ! 1061: return memory_object_set_attributes_common(object, object_ready, ! 1062: may_cache, copy_strategy, ! 1063: TRUE); ! 1064: } ! 1065: ! 1066: kern_return_t memory_object_ready(object, may_cache, copy_strategy) ! 1067: vm_object_t object; ! 1068: boolean_t may_cache; ! 1069: memory_object_copy_strategy_t copy_strategy; ! 1070: { ! 1071: return memory_object_set_attributes_common(object, TRUE, ! 1072: may_cache, copy_strategy, ! 1073: FALSE); ! 1074: } ! 1075: #endif !NORMA_VM ! 1076: ! 1077: kern_return_t memory_object_get_attributes(object, object_ready, ! 1078: may_cache, copy_strategy) ! 1079: vm_object_t object; ! 1080: boolean_t *object_ready; ! 1081: boolean_t *may_cache; ! 1082: memory_object_copy_strategy_t *copy_strategy; ! 1083: { ! 1084: if (object == VM_OBJECT_NULL) ! 1085: return(KERN_INVALID_ARGUMENT); ! 1086: ! 1087: vm_object_lock(object); ! 1088: *may_cache = object->can_persist; ! 1089: *object_ready = object->pager_ready; ! 1090: *copy_strategy = object->copy_strategy; ! 1091: vm_object_unlock(object); ! 1092: ! 1093: vm_object_deallocate(object); ! 1094: ! 1095: return(KERN_SUCCESS); ! 1096: } ! 1097: ! 1098: /* ! 1099: * If successful, consumes the supplied naked send right. ! 1100: */ ! 1101: kern_return_t vm_set_default_memory_manager(host, default_manager) ! 1102: host_t host; ! 1103: ipc_port_t *default_manager; ! 1104: { ! 1105: ipc_port_t current_manager; ! 1106: ipc_port_t new_manager; ! 1107: ipc_port_t returned_manager; ! 1108: ! 1109: if (host == HOST_NULL) ! 1110: return(KERN_INVALID_HOST); ! 1111: ! 1112: new_manager = *default_manager; ! 1113: simple_lock(&memory_manager_default_lock); ! 1114: current_manager = memory_manager_default; ! 1115: ! 1116: if (new_manager == IP_NULL) { ! 1117: /* ! 1118: * Retrieve the current value. ! 1119: */ ! 1120: ! 1121: returned_manager = ipc_port_copy_send(current_manager); ! 1122: } else { ! 1123: /* ! 1124: * Retrieve the current value, ! 1125: * and replace it with the supplied value. ! 1126: * We consume the supplied naked send right. ! 1127: */ ! 1128: ! 1129: returned_manager = current_manager; ! 1130: memory_manager_default = new_manager; ! 1131: ! 1132: /* ! 1133: * In case anyone's been waiting for a memory ! 1134: * manager to be established, wake them up. ! 1135: */ ! 1136: ! 1137: thread_wakeup((event_t) &memory_manager_default); ! 1138: } ! 1139: ! 1140: simple_unlock(&memory_manager_default_lock); ! 1141: ! 1142: *default_manager = returned_manager; ! 1143: return(KERN_SUCCESS); ! 1144: } ! 1145: ! 1146: /* ! 1147: * Routine: memory_manager_default_reference ! 1148: * Purpose: ! 1149: * Returns a naked send right for the default ! 1150: * memory manager. The returned right is always ! 1151: * valid (not IP_NULL or IP_DEAD). ! 1152: */ ! 1153: ! 1154: ipc_port_t memory_manager_default_reference() ! 1155: { ! 1156: ipc_port_t current_manager; ! 1157: ! 1158: simple_lock(&memory_manager_default_lock); ! 1159: ! 1160: while (current_manager = ipc_port_copy_send(memory_manager_default), ! 1161: !IP_VALID(current_manager)) { ! 1162: thread_sleep((event_t) &memory_manager_default, ! 1163: simple_lock_addr(memory_manager_default_lock), ! 1164: FALSE); ! 1165: simple_lock(&memory_manager_default_lock); ! 1166: } ! 1167: ! 1168: simple_unlock(&memory_manager_default_lock); ! 1169: ! 1170: return current_manager; ! 1171: } ! 1172: ! 1173: /* ! 1174: * Routine: memory_manager_default_port ! 1175: * Purpose: ! 1176: * Returns true if the receiver for the port ! 1177: * is the default memory manager. ! 1178: * ! 1179: * This is a hack to let ds_read_done ! 1180: * know when it should keep memory wired. ! 1181: */ ! 1182: ! 1183: boolean_t memory_manager_default_port(port) ! 1184: ipc_port_t port; ! 1185: { ! 1186: ipc_port_t current; ! 1187: boolean_t result; ! 1188: ! 1189: simple_lock(&memory_manager_default_lock); ! 1190: current = memory_manager_default; ! 1191: if (IP_VALID(current)) { ! 1192: /* ! 1193: * There is no point in bothering to lock ! 1194: * both ports, which would be painful to do. ! 1195: * If the receive rights are moving around, ! 1196: * we might be inaccurate. ! 1197: */ ! 1198: ! 1199: result = port->ip_receiver == current->ip_receiver; ! 1200: } else ! 1201: result = FALSE; ! 1202: simple_unlock(&memory_manager_default_lock); ! 1203: ! 1204: return result; ! 1205: } ! 1206: ! 1207: void memory_manager_default_init() ! 1208: { ! 1209: memory_manager_default = IP_NULL; ! 1210: simple_lock_init(&memory_manager_default_lock); ! 1211: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.