|
|
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 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_user.c ! 54: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 55: * ! 56: * User-exported virtual memory functions. ! 57: */ ! 58: #ifdef MACH_BSD ! 59: /* remove after component interface available */ ! 60: extern int vnode_pager_workaround; ! 61: #endif ! 62: ! 63: #include <vm_cpm.h> ! 64: #include <mach/boolean.h> ! 65: #include <mach/kern_return.h> ! 66: #include <mach/mach_types.h> /* to get vm_address_t */ ! 67: #include <mach/memory_object.h> ! 68: #include <mach/std_types.h> /* to get pointer_t */ ! 69: #include <mach/vm_attributes.h> ! 70: #include <mach/vm_param.h> ! 71: #include <mach/vm_statistics.h> ! 72: #include <mach/vm_task_server.h> ! 73: #include <mach/mach_syscalls.h> ! 74: #include <mach/shared_memory_server.h> ! 75: ! 76: #include <kern/host.h> ! 77: #include <kern/task.h> ! 78: #include <kern/misc_protos.h> ! 79: #include <vm/vm_map.h> ! 80: #include <vm/vm_object.h> ! 81: #include <vm/vm_page.h> ! 82: #include <vm/memory_object.h> ! 83: #include <vm/vm_pageout.h> ! 84: ! 85: ! 86: ! 87: vm_size_t upl_offset_to_pagelist = 0; ! 88: ! 89: #if VM_CPM ! 90: #include <vm/cpm.h> ! 91: #endif /* VM_CPM */ ! 92: ! 93: ipc_port_t dynamic_pager_control_port=NULL; ! 94: ! 95: /* ! 96: * vm_allocate allocates "zero fill" memory in the specfied ! 97: * map. ! 98: */ ! 99: kern_return_t ! 100: vm_allocate( ! 101: register vm_map_t map, ! 102: register vm_offset_t *addr, ! 103: register vm_size_t size, ! 104: int flags) ! 105: { ! 106: kern_return_t result; ! 107: boolean_t anywhere = VM_FLAGS_ANYWHERE & flags; ! 108: ! 109: if (map == VM_MAP_NULL) ! 110: return(KERN_INVALID_ARGUMENT); ! 111: if (size == 0) { ! 112: *addr = 0; ! 113: return(KERN_SUCCESS); ! 114: } ! 115: ! 116: if (anywhere) ! 117: *addr = vm_map_min(map); ! 118: else ! 119: *addr = trunc_page(*addr); ! 120: size = round_page(size); ! 121: ! 122: result = vm_map_enter( ! 123: map, ! 124: addr, ! 125: size, ! 126: (vm_offset_t)0, ! 127: flags, ! 128: VM_OBJECT_NULL, ! 129: (vm_offset_t)0, ! 130: FALSE, ! 131: VM_PROT_DEFAULT, ! 132: VM_PROT_ALL, ! 133: VM_INHERIT_DEFAULT); ! 134: ! 135: return(result); ! 136: } ! 137: ! 138: /* ! 139: * vm_deallocate deallocates the specified range of addresses in the ! 140: * specified address map. ! 141: */ ! 142: kern_return_t ! 143: vm_deallocate( ! 144: register vm_map_t map, ! 145: vm_offset_t start, ! 146: vm_size_t size) ! 147: { ! 148: if (map == VM_MAP_NULL) ! 149: return(KERN_INVALID_ARGUMENT); ! 150: ! 151: if (size == (vm_offset_t) 0) ! 152: return(KERN_SUCCESS); ! 153: ! 154: return(vm_map_remove(map, trunc_page(start), ! 155: round_page(start+size), VM_MAP_NO_FLAGS)); ! 156: } ! 157: ! 158: /* ! 159: * vm_inherit sets the inheritance of the specified range in the ! 160: * specified map. ! 161: */ ! 162: kern_return_t ! 163: vm_inherit( ! 164: register vm_map_t map, ! 165: vm_offset_t start, ! 166: vm_size_t size, ! 167: vm_inherit_t new_inheritance) ! 168: { ! 169: if (map == VM_MAP_NULL) ! 170: return(KERN_INVALID_ARGUMENT); ! 171: ! 172: if (new_inheritance > VM_INHERIT_LAST_VALID) ! 173: return(KERN_INVALID_ARGUMENT); ! 174: ! 175: return(vm_map_inherit(map, ! 176: trunc_page(start), ! 177: round_page(start+size), ! 178: new_inheritance)); ! 179: } ! 180: ! 181: /* ! 182: * vm_protect sets the protection of the specified range in the ! 183: * specified map. ! 184: */ ! 185: ! 186: kern_return_t ! 187: vm_protect( ! 188: register vm_map_t map, ! 189: vm_offset_t start, ! 190: vm_size_t size, ! 191: boolean_t set_maximum, ! 192: vm_prot_t new_protection) ! 193: { ! 194: if ((map == VM_MAP_NULL) || (new_protection & ~VM_PROT_ALL)) ! 195: return(KERN_INVALID_ARGUMENT); ! 196: ! 197: return(vm_map_protect(map, ! 198: trunc_page(start), ! 199: round_page(start+size), ! 200: new_protection, ! 201: set_maximum)); ! 202: } ! 203: ! 204: /* ! 205: * Handle machine-specific attributes for a mapping, such ! 206: * as cachability, migrability, etc. ! 207: */ ! 208: kern_return_t ! 209: vm_machine_attribute( ! 210: vm_map_t map, ! 211: vm_address_t address, ! 212: vm_size_t size, ! 213: vm_machine_attribute_t attribute, ! 214: vm_machine_attribute_val_t* value) /* IN/OUT */ ! 215: { ! 216: if (map == VM_MAP_NULL) ! 217: return(KERN_INVALID_ARGUMENT); ! 218: ! 219: return vm_map_machine_attribute(map, address, size, attribute, value); ! 220: } ! 221: ! 222: kern_return_t ! 223: vm_read( ! 224: vm_map_t map, ! 225: vm_address_t address, ! 226: vm_size_t size, ! 227: pointer_t *data, ! 228: mach_msg_type_number_t *data_size) ! 229: { ! 230: kern_return_t error; ! 231: vm_map_copy_t ipc_address; ! 232: ! 233: if (map == VM_MAP_NULL) ! 234: return(KERN_INVALID_ARGUMENT); ! 235: ! 236: if ((error = vm_map_copyin(map, ! 237: address, ! 238: size, ! 239: FALSE, /* src_destroy */ ! 240: &ipc_address)) == KERN_SUCCESS) { ! 241: *data = (pointer_t) ipc_address; ! 242: *data_size = size; ! 243: } ! 244: return(error); ! 245: } ! 246: ! 247: kern_return_t ! 248: vm_read_list( ! 249: vm_map_t map, ! 250: vm_read_entry_t data_list, ! 251: mach_msg_type_number_t count) ! 252: { ! 253: mach_msg_type_number_t i; ! 254: kern_return_t error; ! 255: vm_map_copy_t ipc_address; ! 256: ! 257: if (map == VM_MAP_NULL) ! 258: return(KERN_INVALID_ARGUMENT); ! 259: ! 260: for(i=0; i<count; i++) { ! 261: error = vm_map_copyin(map, ! 262: data_list[i].address, ! 263: data_list[i].size, ! 264: FALSE, /* src_destroy */ ! 265: &ipc_address); ! 266: if(error != KERN_SUCCESS) { ! 267: data_list[i].address = (vm_address_t)0; ! 268: data_list[i].size = (vm_size_t)0; ! 269: break; ! 270: } ! 271: if(data_list[i].size != 0) { ! 272: error = vm_map_copyout(current_task()->map, ! 273: &(data_list[i].address), ! 274: (vm_map_copy_t) ipc_address); ! 275: if(error != KERN_SUCCESS) { ! 276: data_list[i].address = (vm_address_t)0; ! 277: data_list[i].size = (vm_size_t)0; ! 278: break; ! 279: } ! 280: } ! 281: } ! 282: return(error); ! 283: } ! 284: ! 285: /* ! 286: * This routine reads from the specified map and overwrites part of the current ! 287: * activation's map. In making an assumption that the current thread is local, ! 288: * it is no longer cluster-safe without a fully supportive local proxy thread/ ! 289: * task (but we don't support cluster's anymore so this is moot). ! 290: */ ! 291: ! 292: #define VM_OVERWRITE_SMALL 512 ! 293: ! 294: kern_return_t ! 295: vm_read_overwrite( ! 296: vm_map_t map, ! 297: vm_address_t address, ! 298: vm_size_t size, ! 299: vm_address_t data, ! 300: vm_size_t *data_size) ! 301: { ! 302: struct { ! 303: long align; ! 304: char buf[VM_OVERWRITE_SMALL]; ! 305: } inbuf; ! 306: vm_map_t oldmap; ! 307: kern_return_t error = KERN_SUCCESS; ! 308: vm_map_copy_t copy; ! 309: ! 310: if (map == VM_MAP_NULL) ! 311: return(KERN_INVALID_ARGUMENT); ! 312: ! 313: if (size <= VM_OVERWRITE_SMALL) { ! 314: if(vm_map_read_user(map, (vm_offset_t)address, ! 315: (vm_offset_t)&inbuf, size)) { ! 316: error = KERN_INVALID_ADDRESS; ! 317: } else { ! 318: if(vm_map_write_user(current_map(), ! 319: (vm_offset_t)&inbuf, (vm_offset_t)data, size)) ! 320: error = KERN_INVALID_ADDRESS; ! 321: } ! 322: } ! 323: else { ! 324: if ((error = vm_map_copyin(map, ! 325: address, ! 326: size, ! 327: FALSE, /* src_destroy */ ! 328: ©)) == KERN_SUCCESS) { ! 329: if ((error = vm_map_copy_overwrite( ! 330: current_act()->map, ! 331: data, ! 332: copy, ! 333: FALSE)) == KERN_SUCCESS) { ! 334: } ! 335: else { ! 336: vm_map_copy_discard(copy); ! 337: } ! 338: } ! 339: } ! 340: *data_size = size; ! 341: return(error); ! 342: } ! 343: ! 344: ! 345: ! 346: ! 347: /*ARGSUSED*/ ! 348: kern_return_t ! 349: vm_write( ! 350: vm_map_t map, ! 351: vm_address_t address, ! 352: vm_offset_t data, ! 353: mach_msg_type_number_t size) ! 354: { ! 355: if (map == VM_MAP_NULL) ! 356: return KERN_INVALID_ARGUMENT; ! 357: ! 358: return vm_map_copy_overwrite(map, address, (vm_map_copy_t) data, ! 359: FALSE /* interruptible XXX */); ! 360: } ! 361: ! 362: kern_return_t ! 363: vm_copy( ! 364: vm_map_t map, ! 365: vm_address_t source_address, ! 366: vm_size_t size, ! 367: vm_address_t dest_address) ! 368: { ! 369: vm_map_copy_t copy; ! 370: kern_return_t kr; ! 371: ! 372: if (map == VM_MAP_NULL) ! 373: return KERN_INVALID_ARGUMENT; ! 374: ! 375: kr = vm_map_copyin(map, source_address, size, ! 376: FALSE, ©); ! 377: if (kr != KERN_SUCCESS) ! 378: return kr; ! 379: ! 380: kr = vm_map_copy_overwrite(map, dest_address, copy, ! 381: FALSE /* interruptible XXX */); ! 382: if (kr != KERN_SUCCESS) { ! 383: vm_map_copy_discard(copy); ! 384: return kr; ! 385: } ! 386: ! 387: return KERN_SUCCESS; ! 388: } ! 389: ! 390: /* ! 391: * Routine: vm_map ! 392: */ ! 393: kern_return_t ! 394: vm_map( ! 395: vm_map_t target_map, ! 396: vm_offset_t *address, ! 397: vm_size_t size, ! 398: vm_offset_t mask, ! 399: int flags, ! 400: ipc_port_t port, ! 401: vm_offset_t offset, ! 402: boolean_t copy, ! 403: vm_prot_t cur_protection, ! 404: vm_prot_t max_protection, ! 405: vm_inherit_t inheritance) ! 406: { ! 407: register ! 408: vm_object_t object; ! 409: vm_prot_t prot; ! 410: kern_return_t result; ! 411: ! 412: /* ! 413: * Check arguments for validity ! 414: */ ! 415: if ((target_map == VM_MAP_NULL) || ! 416: (cur_protection & ~VM_PROT_ALL) || ! 417: (max_protection & ~VM_PROT_ALL) || ! 418: (inheritance > VM_INHERIT_LAST_VALID) || ! 419: size == 0) ! 420: return(KERN_INVALID_ARGUMENT); ! 421: ! 422: /* ! 423: * Find the vm object (if any) corresponding to this port. ! 424: */ ! 425: if (!IP_VALID(port)) { ! 426: object = VM_OBJECT_NULL; ! 427: offset = 0; ! 428: copy = FALSE; ! 429: } else if (ip_kotype(port) == IKOT_NAMED_ENTRY) { ! 430: vm_named_entry_t named_entry; ! 431: ! 432: named_entry = (vm_named_entry_t)port->ip_kobject; ! 433: /* a few checks to make sure user is obeying rules */ ! 434: if(size == 0) ! 435: size = named_entry->size; ! 436: if((named_entry->protection & max_protection) != max_protection) ! 437: return(KERN_INVALID_RIGHT); ! 438: if((named_entry->protection & cur_protection) != cur_protection) ! 439: return(KERN_INVALID_RIGHT); ! 440: if(named_entry->size < (offset + size)) ! 441: return(KERN_INVALID_ARGUMENT); ! 442: ! 443: /* the callers parameter offset is defined to be the */ ! 444: /* offset from beginning of named entry offset in object */ ! 445: offset = offset + named_entry->offset; ! 446: ! 447: named_entry_lock(named_entry); ! 448: if(named_entry->is_sub_map) { ! 449: vm_map_entry_t map_entry; ! 450: ! 451: named_entry_unlock(named_entry); ! 452: *address = trunc_page(*address); ! 453: size = round_page(size); ! 454: vm_object_reference(vm_submap_object); ! 455: if ((result = vm_map_enter(target_map, ! 456: address, size, mask, flags, ! 457: vm_submap_object, 0, ! 458: FALSE, ! 459: cur_protection, max_protection, inheritance ! 460: )) != KERN_SUCCESS) { ! 461: vm_object_deallocate(vm_submap_object); ! 462: } else { ! 463: vm_map_submap(target_map, *address, ! 464: (*address) + size, ! 465: named_entry->backing.map, ! 466: offset); ! 467: if(copy) { ! 468: if(vm_map_lookup_entry( ! 469: target_map, *address, &map_entry)) { ! 470: map_entry->needs_copy = TRUE; ! 471: } ! 472: } ! 473: } ! 474: return(result); ! 475: ! 476: } else if(named_entry->object) { ! 477: /* This is the case where we are going to map */ ! 478: /* an already mapped object. If the object is */ ! 479: /* not ready it is internal. An external */ ! 480: /* object cannot be mapped until it is ready */ ! 481: /* we can therefore avoid the ready check */ ! 482: /* in this case. */ ! 483: copy = FALSE; ! 484: named_entry_unlock(named_entry); ! 485: vm_object_reference(named_entry->object); ! 486: object = named_entry->object; ! 487: } else { ! 488: object = vm_object_enter(named_entry->backing.pager, ! 489: named_entry->size, ! 490: named_entry->internal, ! 491: FALSE); ! 492: if (object == VM_OBJECT_NULL) { ! 493: named_entry_unlock(named_entry); ! 494: return(KERN_INVALID_OBJECT); ! 495: } ! 496: named_entry->object = object; ! 497: named_entry_unlock(named_entry); ! 498: /* create an extra reference for the named entry */ ! 499: vm_object_reference(named_entry->object); ! 500: /* wait for object (if any) to be ready */ ! 501: if (object != VM_OBJECT_NULL) { ! 502: vm_object_lock(object); ! 503: while (!object->pager_ready) { ! 504: vm_object_wait(object, ! 505: VM_OBJECT_EVENT_PAGER_READY, ! 506: THREAD_UNINT); ! 507: vm_object_lock(object); ! 508: } ! 509: vm_object_unlock(object); ! 510: } ! 511: } ! 512: } else { ! 513: if ((object = vm_object_enter(port, size, FALSE, FALSE)) ! 514: == VM_OBJECT_NULL) ! 515: return(KERN_INVALID_OBJECT); ! 516: ! 517: /* wait for object (if any) to be ready */ ! 518: if (object != VM_OBJECT_NULL) { ! 519: vm_object_lock(object); ! 520: while (!object->pager_ready) { ! 521: vm_object_wait(object, ! 522: VM_OBJECT_EVENT_PAGER_READY, ! 523: THREAD_UNINT); ! 524: vm_object_lock(object); ! 525: } ! 526: vm_object_unlock(object); ! 527: } ! 528: } ! 529: ! 530: *address = trunc_page(*address); ! 531: size = round_page(size); ! 532: ! 533: /* ! 534: * Perform the copy if requested ! 535: */ ! 536: ! 537: if (copy) { ! 538: vm_object_t new_object; ! 539: vm_offset_t new_offset; ! 540: ! 541: result = vm_object_copy_strategically(object, offset, size, ! 542: &new_object, &new_offset, ! 543: ©); ! 544: ! 545: ! 546: if (result == KERN_MEMORY_RESTART_COPY) { ! 547: boolean_t success; ! 548: boolean_t src_needs_copy; ! 549: ! 550: /* ! 551: * XXX ! 552: * We currently ignore src_needs_copy. ! 553: * This really is the issue of how to make ! 554: * MEMORY_OBJECT_COPY_SYMMETRIC safe for ! 555: * non-kernel users to use. Solution forthcoming. ! 556: * In the meantime, since we don't allow non-kernel ! 557: * memory managers to specify symmetric copy, ! 558: * we won't run into problems here. ! 559: */ ! 560: new_object = object; ! 561: new_offset = offset; ! 562: success = vm_object_copy_quickly(&new_object, ! 563: new_offset, size, ! 564: &src_needs_copy, ! 565: ©); ! 566: assert(success); ! 567: result = KERN_SUCCESS; ! 568: } ! 569: /* ! 570: * Throw away the reference to the ! 571: * original object, as it won't be mapped. ! 572: */ ! 573: ! 574: vm_object_deallocate(object); ! 575: ! 576: if (result != KERN_SUCCESS) ! 577: return (result); ! 578: ! 579: object = new_object; ! 580: offset = new_offset; ! 581: } ! 582: ! 583: if ((result = vm_map_enter(target_map, ! 584: address, size, mask, flags, ! 585: object, offset, ! 586: copy, ! 587: cur_protection, max_protection, inheritance ! 588: )) != KERN_SUCCESS) ! 589: vm_object_deallocate(object); ! 590: return(result); ! 591: } ! 592: ! 593: ! 594: /* ! 595: * NOTE: this routine (and this file) will no longer require mach_host_server.h ! 596: * when vm_wire is changed to use ledgers. ! 597: */ ! 598: #include <mach/mach_host_server.h> ! 599: /* ! 600: * Specify that the range of the virtual address space ! 601: * of the target task must not cause page faults for ! 602: * the indicated accesses. ! 603: * ! 604: * [ To unwire the pages, specify VM_PROT_NONE. ] ! 605: */ ! 606: kern_return_t ! 607: vm_wire( ! 608: host_t host, ! 609: register vm_map_t map, ! 610: vm_offset_t start, ! 611: vm_size_t size, ! 612: vm_prot_t access) ! 613: { ! 614: kern_return_t rc; ! 615: ! 616: if (host == HOST_NULL) ! 617: return KERN_INVALID_HOST; ! 618: ! 619: if (map == VM_MAP_NULL) ! 620: return KERN_INVALID_TASK; ! 621: ! 622: if (access & ~VM_PROT_ALL) ! 623: return KERN_INVALID_ARGUMENT; ! 624: ! 625: if (access != VM_PROT_NONE) { ! 626: rc = vm_map_wire(map, trunc_page(start), ! 627: round_page(start+size), access, TRUE); ! 628: } else { ! 629: rc = vm_map_unwire(map, trunc_page(start), ! 630: round_page(start+size), TRUE); ! 631: } ! 632: return rc; ! 633: } ! 634: ! 635: /* ! 636: * vm_msync ! 637: * ! 638: * Synchronises the memory range specified with its backing store ! 639: * image by either flushing or cleaning the contents to the appropriate ! 640: * memory manager engaging in a memory object synchronize dialog with ! 641: * the manager. The client doesn't return until the manager issues ! 642: * m_o_s_completed message. MIG Magically converts user task parameter ! 643: * to the task's address map. ! 644: * ! 645: * interpretation of sync_flags ! 646: * VM_SYNC_INVALIDATE - discard pages, only return precious ! 647: * pages to manager. ! 648: * ! 649: * VM_SYNC_INVALIDATE & (VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS) ! 650: * - discard pages, write dirty or precious ! 651: * pages back to memory manager. ! 652: * ! 653: * VM_SYNC_SYNCHRONOUS | VM_SYNC_ASYNCHRONOUS ! 654: * - write dirty or precious pages back to ! 655: * the memory manager. ! 656: * ! 657: * NOTE ! 658: * The memory object attributes have not yet been implemented, this ! 659: * function will have to deal with the invalidate attribute ! 660: * ! 661: * RETURNS ! 662: * KERN_INVALID_TASK Bad task parameter ! 663: * KERN_INVALID_ARGUMENT both sync and async were specified. ! 664: * KERN_SUCCESS The usual. ! 665: */ ! 666: ! 667: kern_return_t ! 668: vm_msync( ! 669: vm_map_t map, ! 670: vm_address_t address, ! 671: vm_size_t size, ! 672: vm_sync_t sync_flags) ! 673: { ! 674: msync_req_t msr; ! 675: msync_req_t new_msr; ! 676: queue_chain_t req_q; /* queue of requests for this msync */ ! 677: vm_map_entry_t entry; ! 678: vm_size_t amount_left; ! 679: vm_offset_t offset; ! 680: boolean_t do_sync_req; ! 681: boolean_t modifiable; ! 682: ! 683: ! 684: if ((sync_flags & VM_SYNC_ASYNCHRONOUS) && ! 685: (sync_flags & VM_SYNC_SYNCHRONOUS)) ! 686: return(KERN_INVALID_ARGUMENT); ! 687: ! 688: /* ! 689: * align address and size on page boundaries ! 690: */ ! 691: size = round_page(address + size) - trunc_page(address); ! 692: address = trunc_page(address); ! 693: ! 694: if (map == VM_MAP_NULL) ! 695: return(KERN_INVALID_TASK); ! 696: ! 697: if (size == 0) ! 698: return(KERN_SUCCESS); ! 699: ! 700: queue_init(&req_q); ! 701: amount_left = size; ! 702: ! 703: while (amount_left > 0) { ! 704: vm_size_t flush_size; ! 705: vm_object_t object; ! 706: ! 707: vm_map_lock(map); ! 708: if (!vm_map_lookup_entry(map, address, &entry)) { ! 709: vm_size_t skip; ! 710: ! 711: /* ! 712: * hole in the address map. ! 713: */ ! 714: ! 715: /* ! 716: * Check for empty map. ! 717: */ ! 718: if (entry == vm_map_to_entry(map) && ! 719: entry->vme_next == entry) { ! 720: vm_map_unlock(map); ! 721: break; ! 722: } ! 723: /* ! 724: * Check that we don't wrap and that ! 725: * we have at least one real map entry. ! 726: */ ! 727: if ((map->hdr.nentries == 0) || ! 728: (entry->vme_next->vme_start < address)) { ! 729: vm_map_unlock(map); ! 730: break; ! 731: } ! 732: /* ! 733: * Move up to the next entry if needed ! 734: */ ! 735: skip = (entry->vme_next->vme_start - address); ! 736: if (skip >= amount_left) ! 737: amount_left = 0; ! 738: else ! 739: amount_left -= skip; ! 740: address = entry->vme_next->vme_start; ! 741: vm_map_unlock(map); ! 742: continue; ! 743: } ! 744: ! 745: offset = address - entry->vme_start; ! 746: ! 747: /* ! 748: * do we have more to flush than is contained in this ! 749: * entry ? ! 750: */ ! 751: if (amount_left + entry->vme_start + offset > entry->vme_end) { ! 752: flush_size = entry->vme_end - ! 753: (entry->vme_start + offset); ! 754: } else { ! 755: flush_size = amount_left; ! 756: } ! 757: amount_left -= flush_size; ! 758: address += flush_size; ! 759: ! 760: object = entry->object.vm_object; ! 761: ! 762: /* ! 763: * We can't sync this object if the object has not been ! 764: * created yet ! 765: */ ! 766: if (object == VM_OBJECT_NULL) { ! 767: vm_map_unlock(map); ! 768: continue; ! 769: } ! 770: offset += entry->offset; ! 771: modifiable = (entry->protection & VM_PROT_WRITE) ! 772: != VM_PROT_NONE; ! 773: ! 774: vm_object_lock(object); ! 775: ! 776: if (sync_flags & VM_SYNC_KILLPAGES) { ! 777: if (object->ref_count == 1 && !object->shadow && !entry->needs_copy) ! 778: memory_object_kill_pages(object, offset, flush_size); ! 779: ! 780: vm_object_unlock(object); ! 781: vm_map_unlock(map); ! 782: continue; ! 783: } ! 784: /* ! 785: * We can't sync this object if there isn't a pager. ! 786: * Don't bother to sync internal objects, since there can't ! 787: * be any "permanent" storage for these objects anyway. ! 788: */ ! 789: if ((object->pager == IP_NULL) || (object->internal) || ! 790: (object->private)) { ! 791: vm_object_unlock(object); ! 792: vm_map_unlock(map); ! 793: continue; ! 794: } ! 795: /* ! 796: * keep reference on the object until syncing is done ! 797: */ ! 798: assert(object->ref_count > 0); ! 799: object->ref_count++; ! 800: vm_object_res_reference(object); ! 801: vm_object_unlock(object); ! 802: ! 803: vm_map_unlock(map); ! 804: ! 805: do_sync_req = memory_object_sync(object, ! 806: offset, ! 807: flush_size, ! 808: sync_flags & VM_SYNC_INVALIDATE, ! 809: (modifiable && ! 810: (sync_flags & VM_SYNC_SYNCHRONOUS || ! 811: sync_flags & VM_SYNC_ASYNCHRONOUS))); ! 812: ! 813: /* ! 814: * only send a m_o_s if we returned pages or if the entry ! 815: * is writable (ie dirty pages may have already been sent back) ! 816: */ ! 817: if (!do_sync_req && !modifiable) { ! 818: vm_object_deallocate(object); ! 819: continue; ! 820: } ! 821: msync_req_alloc(new_msr); ! 822: ! 823: vm_object_lock(object); ! 824: offset += object->paging_offset; ! 825: ! 826: new_msr->offset = offset; ! 827: new_msr->length = flush_size; ! 828: new_msr->object = object; ! 829: new_msr->flag = VM_MSYNC_SYNCHRONIZING; ! 830: re_iterate: ! 831: queue_iterate(&object->msr_q, msr, msync_req_t, msr_q) { ! 832: /* ! 833: * need to check for overlapping entry, if found, wait ! 834: * on overlapping msr to be done, then reiterate ! 835: */ ! 836: msr_lock(msr); ! 837: if (msr->flag == VM_MSYNC_SYNCHRONIZING && ! 838: ((offset >= msr->offset && ! 839: offset < (msr->offset + msr->length)) || ! 840: (msr->offset >= offset && ! 841: msr->offset < (offset + flush_size)))) ! 842: { ! 843: assert_wait((event_t) msr,THREAD_INTERRUPTIBLE); ! 844: msr_unlock(msr); ! 845: vm_object_unlock(object); ! 846: thread_block((void (*)(void))0); ! 847: if (current_act()->handlers) ! 848: act_execute_returnhandlers(); ! 849: vm_object_lock(object); ! 850: goto re_iterate; ! 851: } ! 852: msr_unlock(msr); ! 853: }/* queue_iterate */ ! 854: ! 855: queue_enter(&object->msr_q, new_msr, msync_req_t, msr_q); ! 856: vm_object_unlock(object); ! 857: ! 858: queue_enter(&req_q, new_msr, msync_req_t, req_q); ! 859: ! 860: #ifdef MACH_BSD ! 861: if(((rpc_subsystem_t)pager_mux_hash_lookup(object->pager)) == ! 862: ((rpc_subsystem_t) &vnode_pager_workaround)) { ! 863: (void) vnode_pager_synchronize( ! 864: object->pager, ! 865: object->pager_request, ! 866: offset, ! 867: flush_size, ! 868: sync_flags); ! 869: } else { ! 870: (void) memory_object_synchronize( ! 871: object->pager, ! 872: object->pager_request, ! 873: offset, ! 874: flush_size, ! 875: sync_flags); ! 876: } ! 877: #else ! 878: (void) memory_object_synchronize( ! 879: object->pager, ! 880: object->pager_request, ! 881: offset, ! 882: flush_size, ! 883: sync_flags); ! 884: #endif ! 885: }/* while */ ! 886: ! 887: /* ! 888: * wait for memory_object_sychronize_completed messages from pager(s) ! 889: */ ! 890: ! 891: while (!queue_empty(&req_q)) { ! 892: msr = (msync_req_t)queue_first(&req_q); ! 893: msr_lock(msr); ! 894: while(msr->flag != VM_MSYNC_DONE) { ! 895: assert_wait((event_t) msr, THREAD_INTERRUPTIBLE); ! 896: msr_unlock(msr); ! 897: thread_block((void (*)(void))0); ! 898: if (current_act()->handlers) ! 899: act_execute_returnhandlers(); ! 900: msr_lock(msr); ! 901: }/* while */ ! 902: queue_remove(&req_q, msr, msync_req_t, req_q); ! 903: msr_unlock(msr); ! 904: vm_object_deallocate(msr->object); ! 905: msync_req_free(msr); ! 906: }/* queue_iterate */ ! 907: ! 908: return(KERN_SUCCESS); ! 909: }/* vm_msync */ ! 910: ! 911: ! 912: /* ! 913: * task_wire ! 914: * ! 915: * Set or clear the map's wiring_required flag. This flag, if set, ! 916: * will cause all future virtual memory allocation to allocate ! 917: * user wired memory. Unwiring pages wired down as a result of ! 918: * this routine is done with the vm_wire interface. ! 919: */ ! 920: kern_return_t ! 921: task_wire( ! 922: vm_map_t map, ! 923: boolean_t must_wire) ! 924: { ! 925: if (map == VM_MAP_NULL) ! 926: return(KERN_INVALID_ARGUMENT); ! 927: ! 928: if (must_wire) ! 929: map->wiring_required = TRUE; ! 930: else ! 931: map->wiring_required = FALSE; ! 932: ! 933: return(KERN_SUCCESS); ! 934: } ! 935: ! 936: /* ! 937: * vm_behavior_set sets the paging behavior attribute for the ! 938: * specified range in the specified map. This routine will fail ! 939: * with KERN_INVALID_ADDRESS if any address in [start,start+size) ! 940: * is not a valid allocated or reserved memory region. ! 941: */ ! 942: kern_return_t ! 943: vm_behavior_set( ! 944: vm_map_t map, ! 945: vm_offset_t start, ! 946: vm_size_t size, ! 947: vm_behavior_t new_behavior) ! 948: { ! 949: if (map == VM_MAP_NULL) ! 950: return(KERN_INVALID_ARGUMENT); ! 951: ! 952: return(vm_map_behavior_set(map, trunc_page(start), ! 953: round_page(start+size), new_behavior)); ! 954: } ! 955: ! 956: #if VM_CPM ! 957: /* ! 958: * Control whether the kernel will permit use of ! 959: * vm_allocate_cpm at all. ! 960: */ ! 961: unsigned int vm_allocate_cpm_enabled = 1; ! 962: ! 963: /* ! 964: * Ordinarily, the right to allocate CPM is restricted ! 965: * to privileged applications (those that can gain access ! 966: * to the host port). Set this variable to zero if you ! 967: * want to let any application allocate CPM. ! 968: */ ! 969: unsigned int vm_allocate_cpm_privileged = 0; ! 970: ! 971: /* ! 972: * Allocate memory in the specified map, with the caveat that ! 973: * the memory is physically contiguous. This call may fail ! 974: * if the system can't find sufficient contiguous memory. ! 975: * This call may cause or lead to heart-stopping amounts of ! 976: * paging activity. ! 977: * ! 978: * Memory obtained from this call should be freed in the ! 979: * normal way, viz., via vm_deallocate. ! 980: */ ! 981: kern_return_t ! 982: vm_allocate_cpm( ! 983: host_t host, ! 984: register vm_map_t map, ! 985: register vm_offset_t *addr, ! 986: register vm_size_t size, ! 987: int flags) ! 988: { ! 989: vm_object_t cpm_obj; ! 990: pmap_t pmap; ! 991: vm_page_t m, pages; ! 992: kern_return_t kr; ! 993: vm_offset_t va, start, end, offset; ! 994: #if MACH_ASSERT ! 995: extern vm_offset_t avail_start, avail_end; ! 996: vm_offset_t prev_addr; ! 997: #endif /* MACH_ASSERT */ ! 998: ! 999: boolean_t anywhere = VM_FLAGS_ANYWHERE & flags; ! 1000: ! 1001: if (!vm_allocate_cpm_enabled) ! 1002: return KERN_FAILURE; ! 1003: ! 1004: if (vm_allocate_cpm_privileged && host == HOST_NULL) ! 1005: return KERN_INVALID_HOST; ! 1006: ! 1007: if (map == VM_MAP_NULL) ! 1008: return KERN_INVALID_ARGUMENT; ! 1009: ! 1010: if (size == 0) { ! 1011: *addr = 0; ! 1012: return KERN_SUCCESS; ! 1013: } ! 1014: ! 1015: if (anywhere) ! 1016: *addr = vm_map_min(map); ! 1017: else ! 1018: *addr = trunc_page(*addr); ! 1019: size = round_page(size); ! 1020: ! 1021: if ((kr = cpm_allocate(size, &pages, TRUE)) != KERN_SUCCESS) ! 1022: return kr; ! 1023: ! 1024: cpm_obj = vm_object_allocate(size); ! 1025: assert(cpm_obj != VM_OBJECT_NULL); ! 1026: assert(cpm_obj->internal); ! 1027: assert(cpm_obj->size == size); ! 1028: assert(cpm_obj->can_persist == FALSE); ! 1029: assert(cpm_obj->pager_created == FALSE); ! 1030: assert(cpm_obj->pageout == FALSE); ! 1031: assert(cpm_obj->shadow == VM_OBJECT_NULL); ! 1032: ! 1033: /* ! 1034: * Insert pages into object. ! 1035: */ ! 1036: ! 1037: vm_object_lock(cpm_obj); ! 1038: for (offset = 0; offset < size; offset += PAGE_SIZE) { ! 1039: m = pages; ! 1040: pages = NEXT_PAGE(m); ! 1041: ! 1042: assert(!m->gobbled); ! 1043: assert(!m->wanted); ! 1044: assert(!m->pageout); ! 1045: assert(!m->tabled); ! 1046: assert(m->busy); ! 1047: assert(m->phys_addr>=avail_start && m->phys_addr<=avail_end); ! 1048: ! 1049: m->busy = FALSE; ! 1050: vm_page_insert(m, cpm_obj, offset); ! 1051: } ! 1052: assert(cpm_obj->resident_page_count == size / PAGE_SIZE); ! 1053: vm_object_unlock(cpm_obj); ! 1054: ! 1055: /* ! 1056: * Hang onto a reference on the object in case a ! 1057: * multi-threaded application for some reason decides ! 1058: * to deallocate the portion of the address space into ! 1059: * which we will insert this object. ! 1060: * ! 1061: * Unfortunately, we must insert the object now before ! 1062: * we can talk to the pmap module about which addresses ! 1063: * must be wired down. Hence, the race with a multi- ! 1064: * threaded app. ! 1065: */ ! 1066: vm_object_reference(cpm_obj); ! 1067: ! 1068: /* ! 1069: * Insert object into map. ! 1070: */ ! 1071: ! 1072: kr = vm_map_enter( ! 1073: map, ! 1074: addr, ! 1075: size, ! 1076: (vm_offset_t)0, ! 1077: flags, ! 1078: cpm_obj, ! 1079: (vm_offset_t)0, ! 1080: FALSE, ! 1081: VM_PROT_ALL, ! 1082: VM_PROT_ALL, ! 1083: VM_INHERIT_DEFAULT); ! 1084: ! 1085: if (kr != KERN_SUCCESS) { ! 1086: /* ! 1087: * A CPM object doesn't have can_persist set, ! 1088: * so all we have to do is deallocate it to ! 1089: * free up these pages. ! 1090: */ ! 1091: assert(cpm_obj->pager_created == FALSE); ! 1092: assert(cpm_obj->can_persist == FALSE); ! 1093: assert(cpm_obj->pageout == FALSE); ! 1094: assert(cpm_obj->shadow == VM_OBJECT_NULL); ! 1095: vm_object_deallocate(cpm_obj); /* kill acquired ref */ ! 1096: vm_object_deallocate(cpm_obj); /* kill creation ref */ ! 1097: } ! 1098: ! 1099: /* ! 1100: * Inform the physical mapping system that the ! 1101: * range of addresses may not fault, so that ! 1102: * page tables and such can be locked down as well. ! 1103: */ ! 1104: start = *addr; ! 1105: end = start + size; ! 1106: pmap = vm_map_pmap(map); ! 1107: pmap_pageable(pmap, start, end, FALSE); ! 1108: ! 1109: /* ! 1110: * Enter each page into the pmap, to avoid faults. ! 1111: * Note that this loop could be coded more efficiently, ! 1112: * if the need arose, rather than looking up each page ! 1113: * again. ! 1114: */ ! 1115: for (offset = 0, va = start; offset < size; ! 1116: va += PAGE_SIZE, offset += PAGE_SIZE) { ! 1117: vm_object_lock(cpm_obj); ! 1118: m = vm_page_lookup(cpm_obj, offset); ! 1119: vm_object_unlock(cpm_obj); ! 1120: assert(m != VM_PAGE_NULL); ! 1121: PMAP_ENTER(pmap, va, m, VM_PROT_ALL, TRUE); ! 1122: } ! 1123: ! 1124: #if MACH_ASSERT ! 1125: /* ! 1126: * Verify ordering in address space. ! 1127: */ ! 1128: for (offset = 0; offset < size; offset += PAGE_SIZE) { ! 1129: vm_object_lock(cpm_obj); ! 1130: m = vm_page_lookup(cpm_obj, offset); ! 1131: vm_object_unlock(cpm_obj); ! 1132: if (m == VM_PAGE_NULL) ! 1133: panic("vm_allocate_cpm: obj 0x%x off 0x%x no page", ! 1134: cpm_obj, offset); ! 1135: assert(m->tabled); ! 1136: assert(!m->busy); ! 1137: assert(!m->wanted); ! 1138: assert(!m->fictitious); ! 1139: assert(!m->private); ! 1140: assert(!m->absent); ! 1141: assert(!m->error); ! 1142: assert(!m->cleaning); ! 1143: assert(!m->precious); ! 1144: assert(!m->clustered); ! 1145: if (offset != 0) { ! 1146: if (m->phys_addr != prev_addr + PAGE_SIZE) { ! 1147: printf("start 0x%x end 0x%x va 0x%x\n", ! 1148: start, end, va); ! 1149: printf("obj 0x%x off 0x%x\n", cpm_obj, offset); ! 1150: printf("m 0x%x prev_address 0x%x\n", m, ! 1151: prev_addr); ! 1152: panic("vm_allocate_cpm: pages not contig!"); ! 1153: } ! 1154: } ! 1155: prev_addr = m->phys_addr; ! 1156: } ! 1157: #endif /* MACH_ASSERT */ ! 1158: ! 1159: vm_object_deallocate(cpm_obj); /* kill extra ref */ ! 1160: ! 1161: return kr; ! 1162: } ! 1163: ! 1164: ! 1165: #else /* VM_CPM */ ! 1166: ! 1167: /* ! 1168: * Interface is defined in all cases, but unless the kernel ! 1169: * is built explicitly for this option, the interface does ! 1170: * nothing. ! 1171: */ ! 1172: ! 1173: kern_return_t ! 1174: vm_allocate_cpm( ! 1175: host_t host, ! 1176: register vm_map_t map, ! 1177: register vm_offset_t *addr, ! 1178: register vm_size_t size, ! 1179: int flags) ! 1180: { ! 1181: return KERN_FAILURE; ! 1182: } ! 1183: ! 1184: /* ! 1185: */ ! 1186: kern_return_t ! 1187: mach_memory_object_memory_entry( ! 1188: host_t host, ! 1189: boolean_t internal, ! 1190: vm_size_t size, ! 1191: vm_prot_t permission, ! 1192: ipc_port_t pager, ! 1193: ipc_port_t *entry_handle) ! 1194: { ! 1195: vm_named_entry_t user_object; ! 1196: ipc_port_t user_handle; ! 1197: ipc_port_t previous; ! 1198: kern_return_t kr; ! 1199: ! 1200: if (host == HOST_NULL) ! 1201: return(KERN_INVALID_HOST); ! 1202: ! 1203: user_object = (vm_named_entry_t) ! 1204: kalloc(sizeof (struct vm_named_entry)); ! 1205: if(user_object == NULL) ! 1206: return KERN_FAILURE; ! 1207: named_entry_lock_init(user_object); ! 1208: user_handle = ipc_port_alloc_kernel(); ! 1209: ip_lock(user_handle); ! 1210: ! 1211: /* make a sonce right */ ! 1212: user_handle->ip_sorights++; ! 1213: ip_reference(user_handle); ! 1214: ! 1215: user_handle->ip_destination = IP_NULL; ! 1216: user_handle->ip_receiver_name = MACH_PORT_NULL; ! 1217: user_handle->ip_receiver = ipc_space_kernel; ! 1218: ! 1219: /* make a send right */ ! 1220: user_handle->ip_mscount++; ! 1221: user_handle->ip_srights++; ! 1222: ip_reference(user_handle); ! 1223: ! 1224: ipc_port_nsrequest(user_handle, 1, user_handle, &previous); ! 1225: /* nsrequest unlocks user_handle */ ! 1226: ! 1227: user_object->object = NULL; ! 1228: user_object->size = size; ! 1229: user_object->offset = 0; ! 1230: user_object->backing.pager = pager; ! 1231: user_object->protection = permission; ! 1232: user_object->internal = internal; ! 1233: user_object->is_sub_map = FALSE; ! 1234: user_object->ref_count = 1; ! 1235: ! 1236: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object, ! 1237: IKOT_NAMED_ENTRY); ! 1238: *entry_handle = user_handle; ! 1239: return KERN_SUCCESS; ! 1240: } ! 1241: ! 1242: ! 1243: ! 1244: /* ! 1245: */ ! 1246: ! 1247: kern_return_t ! 1248: mach_make_memory_entry( ! 1249: vm_map_t target_map, ! 1250: vm_size_t *size, ! 1251: vm_offset_t offset, ! 1252: vm_prot_t permission, ! 1253: ipc_port_t *object_handle, ! 1254: ipc_port_t parent_entry) ! 1255: { ! 1256: vm_map_version_t version; ! 1257: vm_named_entry_t user_object; ! 1258: ipc_port_t user_handle; ! 1259: ipc_port_t previous; ! 1260: kern_return_t kr; ! 1261: ! 1262: /* needed for call to vm_map_lookup_locked */ ! 1263: boolean_t wired; ! 1264: vm_offset_t obj_off; ! 1265: vm_prot_t prot; ! 1266: vm_offset_t lo_offset, hi_offset; ! 1267: vm_behavior_t behavior; ! 1268: vm_object_t object; ! 1269: ! 1270: /* needed for direct map entry manipulation */ ! 1271: vm_map_entry_t map_entry; ! 1272: vm_map_t local_map; ! 1273: vm_size_t mappable_size; ! 1274: ! 1275: ! 1276: user_object = (vm_named_entry_t) ! 1277: kalloc(sizeof (struct vm_named_entry)); ! 1278: if(user_object == NULL) ! 1279: return KERN_FAILURE; ! 1280: named_entry_lock_init(user_object); ! 1281: user_handle = ipc_port_alloc_kernel(); ! 1282: ip_lock(user_handle); ! 1283: ! 1284: /* make a sonce right */ ! 1285: user_handle->ip_sorights++; ! 1286: ip_reference(user_handle); ! 1287: ! 1288: user_handle->ip_destination = IP_NULL; ! 1289: user_handle->ip_receiver_name = MACH_PORT_NULL; ! 1290: user_handle->ip_receiver = ipc_space_kernel; ! 1291: ! 1292: /* make a send right */ ! 1293: user_handle->ip_mscount++; ! 1294: user_handle->ip_srights++; ! 1295: ip_reference(user_handle); ! 1296: ! 1297: ipc_port_nsrequest(user_handle, 1, user_handle, &previous); ! 1298: /* nsrequest unlocks user_handle */ ! 1299: ! 1300: user_object->backing.pager = NULL; ! 1301: user_object->ref_count = 1; ! 1302: ! 1303: if(parent_entry == NULL) { ! 1304: /* Create a named object based on address range within the task map */ ! 1305: /* Go find the object at given address */ ! 1306: ! 1307: permission &= VM_PROT_ALL; ! 1308: vm_map_lock_read(target_map); ! 1309: ! 1310: /* get the object associated with the target address */ ! 1311: /* note we check the permission of the range against */ ! 1312: /* that requested by the caller */ ! 1313: ! 1314: kr = vm_map_lookup_locked(&target_map, offset, ! 1315: permission, &version, ! 1316: &object, &obj_off, &prot, &wired, &behavior, ! 1317: &lo_offset, &hi_offset); ! 1318: if (kr != KERN_SUCCESS) { ! 1319: vm_map_unlock_read(target_map); ! 1320: goto make_mem_done; ! 1321: } ! 1322: if ((prot & permission) != permission) { ! 1323: kr = KERN_INVALID_RIGHT; ! 1324: vm_object_unlock(object); ! 1325: vm_map_unlock_read(target_map); ! 1326: goto make_mem_done; ! 1327: } ! 1328: ! 1329: /* We have an object, now check to see if this object */ ! 1330: /* is suitable. If not, create a shadow and share that */ ! 1331: ! 1332: local_map = target_map; ! 1333: redo_lookup: ! 1334: while(TRUE) { ! 1335: if(!vm_map_lookup_entry(local_map, offset, &map_entry)) { ! 1336: kr = KERN_INVALID_ARGUMENT; ! 1337: vm_object_unlock(object); ! 1338: vm_map_unlock_read(target_map); ! 1339: goto make_mem_done; ! 1340: } ! 1341: if(!(map_entry->is_sub_map)) { ! 1342: if(map_entry->object.vm_object != object) { ! 1343: kr = KERN_INVALID_ARGUMENT; ! 1344: vm_object_unlock(object); ! 1345: vm_map_unlock_read(target_map); ! 1346: goto make_mem_done; ! 1347: } ! 1348: break; ! 1349: } else { ! 1350: local_map = map_entry->object.sub_map; ! 1351: vm_map_lock_read(local_map); ! 1352: vm_map_unlock_read(target_map); ! 1353: target_map = local_map; ! 1354: } ! 1355: } ! 1356: if(((map_entry->max_protection) & permission) != permission) { ! 1357: kr = KERN_INVALID_RIGHT; ! 1358: vm_object_unlock(object); ! 1359: vm_map_unlock_read(target_map); ! 1360: goto make_mem_done; ! 1361: } ! 1362: if(object->internal) { ! 1363: /* vm_map_lookup_locked will create a shadow if */ ! 1364: /* needs_copy is set but does not check for the */ ! 1365: /* other two conditions shown. It is important to */ ! 1366: /* set up an object which will not be pulled from */ ! 1367: /* under us. */ ! 1368: ! 1369: if (map_entry->needs_copy || object->shadowed || ! 1370: (object->size > ((vm_size_t)map_entry->vme_end - ! 1371: map_entry->vme_start))) { ! 1372: if (vm_map_lock_read_to_write(target_map)) { ! 1373: vm_map_lock_read(target_map); ! 1374: goto redo_lookup; ! 1375: } ! 1376: ! 1377: ! 1378: /* create a shadow object */ ! 1379: ! 1380: vm_object_shadow(&map_entry->object.vm_object, ! 1381: &map_entry->offset, ! 1382: (map_entry->vme_end ! 1383: - map_entry->vme_start)); ! 1384: map_entry->needs_copy = FALSE; ! 1385: vm_object_unlock(object); ! 1386: object = map_entry->object.vm_object; ! 1387: vm_object_lock(object); ! 1388: object->size = map_entry->vme_end ! 1389: - map_entry->vme_start; ! 1390: obj_off = (offset - map_entry->vme_start) + ! 1391: map_entry->offset; ! 1392: lo_offset = map_entry->offset; ! 1393: hi_offset = (map_entry->vme_end - ! 1394: map_entry->vme_start) + ! 1395: map_entry->offset; ! 1396: ! 1397: vm_map_lock_write_to_read(target_map); ! 1398: ! 1399: } ! 1400: } ! 1401: ! 1402: /* note: in the future we can (if necessary) allow for */ ! 1403: /* memory object lists, this will better support */ ! 1404: /* fragmentation, but is it necessary? The user should */ ! 1405: /* be encouraged to create address space oriented */ ! 1406: /* shared objects from CLEAN memory regions which have */ ! 1407: /* a known and defined history. i.e. no inheritence */ ! 1408: /* share, make this call before making the region the */ ! 1409: /* target of ipc's, etc. The code above, protecting */ ! 1410: /* against delayed copy, etc. is mostly defensive. */ ! 1411: ! 1412: ! 1413: ! 1414: object->true_share = TRUE; ! 1415: user_object->object = object; ! 1416: user_object->internal = object->internal; ! 1417: user_object->is_sub_map = FALSE; ! 1418: user_object->offset = obj_off; ! 1419: user_object->protection = permission; ! 1420: ! 1421: /* the size of mapped entry that overlaps with our region */ ! 1422: /* which is targeted for share. */ ! 1423: /* (entry_end - entry_start) - */ ! 1424: /* offset of our beg addr within entry */ ! 1425: /* it corresponds to this: */ ! 1426: ! 1427: mappable_size = hi_offset - obj_off; ! 1428: if(*size > mappable_size) ! 1429: *size = mappable_size; ! 1430: ! 1431: user_object->size = *size; ! 1432: ! 1433: /* user_object pager and internal fields are not used */ ! 1434: /* when the object field is filled in. */ ! 1435: ! 1436: object->ref_count++; /* we now point to this object, hold on */ ! 1437: vm_object_res_reference(object); ! 1438: vm_object_unlock(object); ! 1439: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object, ! 1440: IKOT_NAMED_ENTRY); ! 1441: *size = user_object->size; ! 1442: *object_handle = user_handle; ! 1443: vm_map_unlock_read(target_map); ! 1444: return KERN_SUCCESS; ! 1445: } else { ! 1446: ! 1447: vm_named_entry_t parent_object; ! 1448: ! 1449: /* The new object will be base on an existing named object */ ! 1450: if(ip_kotype(parent_entry) != IKOT_NAMED_ENTRY) { ! 1451: kr = KERN_INVALID_ARGUMENT; ! 1452: goto make_mem_done; ! 1453: } ! 1454: parent_object = (vm_named_entry_t)parent_entry->ip_kobject; ! 1455: if(permission & parent_object->protection != permission) { ! 1456: kr = KERN_INVALID_ARGUMENT; ! 1457: goto make_mem_done; ! 1458: } ! 1459: if((offset + *size) > parent_object->size) { ! 1460: kr = KERN_INVALID_ARGUMENT; ! 1461: goto make_mem_done; ! 1462: } ! 1463: ! 1464: user_object->object = parent_object->object; ! 1465: user_object->size = *size; ! 1466: user_object->offset = parent_object->offset + offset; ! 1467: user_object->protection = permission; ! 1468: if(parent_object->is_sub_map) { ! 1469: user_object->backing.map = parent_object->backing.map; ! 1470: vm_map_lock(user_object->backing.map); ! 1471: user_object->backing.map->ref_count++; ! 1472: vm_map_unlock(user_object->backing.map); ! 1473: } ! 1474: else { ! 1475: user_object->backing.pager = parent_object->backing.pager; ! 1476: } ! 1477: user_object->internal = parent_object->internal; ! 1478: user_object->is_sub_map = parent_object->is_sub_map; ! 1479: ! 1480: if(parent_object->object != NULL) { ! 1481: /* we now point to this object, hold on */ ! 1482: vm_object_reference(parent_object->object); ! 1483: vm_object_lock(parent_object->object); ! 1484: parent_object->object->true_share = TRUE; ! 1485: vm_object_unlock(parent_object->object); ! 1486: } ! 1487: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object, ! 1488: IKOT_NAMED_ENTRY); ! 1489: *object_handle = user_handle; ! 1490: return KERN_SUCCESS; ! 1491: } ! 1492: ! 1493: ! 1494: ! 1495: make_mem_done: ! 1496: ipc_port_dealloc_kernel(user_handle); ! 1497: kfree((vm_offset_t)user_object, sizeof (struct vm_named_entry)); ! 1498: return kr; ! 1499: } ! 1500: ! 1501: /* ! 1502: */ ! 1503: ! 1504: kern_return_t ! 1505: vm_region_object_create( ! 1506: vm_map_t target_map, ! 1507: vm_size_t size, ! 1508: ipc_port_t *object_handle) ! 1509: { ! 1510: vm_named_entry_t user_object; ! 1511: ipc_port_t user_handle; ! 1512: kern_return_t kr; ! 1513: ! 1514: pmap_t new_pmap = pmap_create((vm_size_t) 0); ! 1515: ipc_port_t previous; ! 1516: vm_map_t new_map; ! 1517: ! 1518: if(new_pmap == PMAP_NULL) ! 1519: return KERN_FAILURE; ! 1520: user_object = (vm_named_entry_t) ! 1521: kalloc(sizeof (struct vm_named_entry)); ! 1522: if(user_object == NULL) { ! 1523: pmap_destroy(new_pmap); ! 1524: return KERN_FAILURE; ! 1525: } ! 1526: named_entry_lock_init(user_object); ! 1527: user_handle = ipc_port_alloc_kernel(); ! 1528: ! 1529: ! 1530: ip_lock(user_handle); ! 1531: ! 1532: /* make a sonce right */ ! 1533: user_handle->ip_sorights++; ! 1534: ip_reference(user_handle); ! 1535: ! 1536: user_handle->ip_destination = IP_NULL; ! 1537: user_handle->ip_receiver_name = MACH_PORT_NULL; ! 1538: user_handle->ip_receiver = ipc_space_kernel; ! 1539: ! 1540: /* make a send right */ ! 1541: user_handle->ip_mscount++; ! 1542: user_handle->ip_srights++; ! 1543: ip_reference(user_handle); ! 1544: ! 1545: ipc_port_nsrequest(user_handle, 1, user_handle, &previous); ! 1546: /* nsrequest unlocks user_handle */ ! 1547: ! 1548: /* Create a named object based on a submap of specified size */ ! 1549: ! 1550: new_map = vm_map_create(new_pmap, 0, size, TRUE); ! 1551: user_object->backing.map = new_map; ! 1552: ! 1553: ! 1554: user_object->object = VM_OBJECT_NULL; ! 1555: user_object->internal = TRUE; ! 1556: user_object->is_sub_map = TRUE; ! 1557: user_object->offset = 0; ! 1558: user_object->protection = VM_PROT_ALL; ! 1559: user_object->size = size; ! 1560: user_object->ref_count = 1; ! 1561: ! 1562: ipc_kobject_set(user_handle, (ipc_kobject_t) user_object, ! 1563: IKOT_NAMED_ENTRY); ! 1564: *object_handle = user_handle; ! 1565: return KERN_SUCCESS; ! 1566: ! 1567: } ! 1568: ! 1569: void ! 1570: mach_destroy_memory_entry( ! 1571: ipc_port_t port) ! 1572: { ! 1573: vm_named_entry_t named_entry; ! 1574: #if MACH_ASSERT ! 1575: assert(ip_kotype(port) == IKOT_NAMED_ENTRY); ! 1576: #endif /* MACH_ASSERT */ ! 1577: named_entry = (vm_named_entry_t)port->ip_kobject; ! 1578: mutex_lock(&(named_entry)->Lock); ! 1579: named_entry->ref_count-=1; ! 1580: if(named_entry->ref_count == 0) { ! 1581: if(named_entry->object) { ! 1582: /* release the memory object we've been pointing to */ ! 1583: vm_object_deallocate(named_entry->object); ! 1584: } ! 1585: if(named_entry->is_sub_map) { ! 1586: vm_map_deallocate(named_entry->backing.map); ! 1587: } ! 1588: kfree((vm_offset_t)port->ip_kobject, ! 1589: sizeof (struct vm_named_entry)); ! 1590: } else ! 1591: mutex_unlock(&(named_entry)->Lock); ! 1592: } ! 1593: ! 1594: ! 1595: kern_return_t ! 1596: vm_map_page_query( ! 1597: vm_map_t target_map, ! 1598: vm_offset_t offset, ! 1599: int *disposition, ! 1600: int *ref_count) ! 1601: { ! 1602: vm_map_entry_t map_entry; ! 1603: vm_object_t object; ! 1604: vm_page_t m; ! 1605: ! 1606: restart_page_query: ! 1607: *disposition = 0; ! 1608: *ref_count = 0; ! 1609: vm_map_lock(target_map); ! 1610: if(!vm_map_lookup_entry(target_map, offset, &map_entry)) { ! 1611: vm_map_unlock(target_map); ! 1612: return KERN_FAILURE; ! 1613: } ! 1614: offset -= map_entry->vme_start; /* adjust to offset within entry */ ! 1615: offset += map_entry->offset; /* adjust to target object offset */ ! 1616: if(map_entry->object.vm_object != VM_OBJECT_NULL) { ! 1617: if(!map_entry->is_sub_map) { ! 1618: object = map_entry->object.vm_object; ! 1619: } else { ! 1620: vm_map_unlock(target_map); ! 1621: target_map = map_entry->object.sub_map; ! 1622: goto restart_page_query; ! 1623: } ! 1624: } else { ! 1625: vm_map_unlock(target_map); ! 1626: return KERN_FAILURE; ! 1627: } ! 1628: vm_object_lock(object); ! 1629: vm_map_unlock(target_map); ! 1630: while(TRUE) { ! 1631: m = vm_page_lookup(object, offset); ! 1632: if (m != VM_PAGE_NULL) { ! 1633: *disposition |= VM_PAGE_QUERY_PAGE_PRESENT; ! 1634: break; ! 1635: } else { ! 1636: if(object->shadow) { ! 1637: offset += object->shadow_offset; ! 1638: vm_object_unlock(object); ! 1639: object = object->shadow; ! 1640: vm_object_lock(object); ! 1641: continue; ! 1642: } ! 1643: vm_object_unlock(object); ! 1644: return KERN_FAILURE; ! 1645: } ! 1646: } ! 1647: ! 1648: /* The ref_count is not strictly accurate, it measures the number */ ! 1649: /* of entities holding a ref on the object, they may not be mapping */ ! 1650: /* the object or may not be mapping the section holding the */ ! 1651: /* target page but its still a ball park number and though an over- */ ! 1652: /* count, it picks up the copy-on-write cases */ ! 1653: ! 1654: /* We could also get a picture of page sharing from pmap_attributes */ ! 1655: /* but this would under count as only faulted-in mappings would */ ! 1656: /* show up. */ ! 1657: ! 1658: *ref_count = object->ref_count; ! 1659: ! 1660: if (m->fictitious) { ! 1661: *disposition |= VM_PAGE_QUERY_PAGE_FICTITIOUS; ! 1662: vm_object_unlock(object); ! 1663: return KERN_SUCCESS; ! 1664: } ! 1665: ! 1666: if (m->dirty) ! 1667: *disposition |= VM_PAGE_QUERY_PAGE_DIRTY; ! 1668: else if(pmap_is_modified(m->phys_addr)) ! 1669: *disposition |= VM_PAGE_QUERY_PAGE_DIRTY; ! 1670: ! 1671: if (m->reference) ! 1672: *disposition |= VM_PAGE_QUERY_PAGE_REF; ! 1673: else if(pmap_is_referenced(m->phys_addr)) ! 1674: *disposition |= VM_PAGE_QUERY_PAGE_REF; ! 1675: ! 1676: vm_object_unlock(object); ! 1677: return KERN_SUCCESS; ! 1678: ! 1679: } ! 1680: ! 1681: kern_return_t ! 1682: set_dp_control_port( ! 1683: host_t host, ! 1684: ipc_port_t control_port) ! 1685: { ! 1686: if (host == HOST_NULL) ! 1687: return (KERN_INVALID_HOST); ! 1688: dynamic_pager_control_port = control_port; ! 1689: return KERN_SUCCESS; ! 1690: } ! 1691: ! 1692: kern_return_t ! 1693: get_dp_control_port( ! 1694: host_t host, ! 1695: ipc_port_t *control_port) ! 1696: { ! 1697: if (host == HOST_NULL) ! 1698: return (KERN_INVALID_HOST); ! 1699: *control_port = dynamic_pager_control_port; ! 1700: return KERN_SUCCESS; ! 1701: ! 1702: } ! 1703: ! 1704: void ! 1705: mach_destroy_upl( ! 1706: ipc_port_t port) ! 1707: { ! 1708: upl_t upl; ! 1709: #if MACH_ASSERT ! 1710: assert(ip_kotype(port) == IKOT_NAMED_ENTRY); ! 1711: #endif /* MACH_ASSERT */ ! 1712: upl = (upl_t)port->ip_kobject; ! 1713: mutex_lock(&(upl)->Lock); ! 1714: upl->ref_count-=1; ! 1715: if(upl->ref_count == 0) { ! 1716: mutex_unlock(&(upl)->Lock); ! 1717: upl_abort(upl, UPL_ABORT_ERROR); ! 1718: } else ! 1719: mutex_unlock(&(upl)->Lock); ! 1720: } ! 1721: ! 1722: kern_return_t ! 1723: vm_object_upl_request( ! 1724: vm_object_t object, ! 1725: vm_object_offset_t offset, ! 1726: vm_size_t size, ! 1727: ipc_port_t *upl, ! 1728: upl_page_info_t *page_list, ! 1729: mach_msg_type_number_t *count, ! 1730: int cntrl_flags) ! 1731: { ! 1732: upl_t upl_object; ! 1733: ipc_port_t upl_port; ! 1734: ipc_port_t previous; ! 1735: upl_page_info_t *pl; ! 1736: kern_return_t kr; ! 1737: ! 1738: pl = page_list; ! 1739: kr = vm_fault_list_request(object, offset, size, &upl_object, ! 1740: &pl, *count, cntrl_flags); ! 1741: ! 1742: ! 1743: if(kr != KERN_SUCCESS) { ! 1744: *upl = MACH_PORT_NULL; ! 1745: return KERN_FAILURE; ! 1746: } ! 1747: ! 1748: upl_port = ipc_port_alloc_kernel(); ! 1749: ! 1750: ! 1751: ip_lock(upl_port); ! 1752: ! 1753: /* make a sonce right */ ! 1754: upl_port->ip_sorights++; ! 1755: ip_reference(upl_port); ! 1756: ! 1757: upl_port->ip_destination = IP_NULL; ! 1758: upl_port->ip_receiver_name = MACH_PORT_NULL; ! 1759: upl_port->ip_receiver = ipc_space_kernel; ! 1760: ! 1761: /* make a send right */ ! 1762: upl_port->ip_mscount++; ! 1763: upl_port->ip_srights++; ! 1764: ip_reference(upl_port); ! 1765: ! 1766: ipc_port_nsrequest(upl_port, 1, upl_port, &previous); ! 1767: /* nsrequest unlocks user_handle */ ! 1768: ! 1769: /* Create a named object based on a submap of specified size */ ! 1770: ! 1771: ! 1772: ipc_kobject_set(upl_port, (ipc_kobject_t) upl_object, IKOT_UPL); ! 1773: *upl = upl_port; ! 1774: return KERN_SUCCESS; ! 1775: } ! 1776: ! 1777: kern_return_t ! 1778: vm_pager_upl_request( ! 1779: vm_object_t object, ! 1780: vm_object_offset_t offset, ! 1781: vm_size_t size, ! 1782: vm_size_t super_size, ! 1783: ipc_port_t *upl, ! 1784: upl_page_info_t *page_list, ! 1785: mach_msg_type_number_t *count, ! 1786: int cntrl_flags) ! 1787: { ! 1788: upl_t upl_object; ! 1789: ipc_port_t upl_port; ! 1790: ipc_port_t previous; ! 1791: upl_page_info_t *pl; ! 1792: kern_return_t kr; ! 1793: ! 1794: pl = page_list; ! 1795: kr = upl_system_list_request(object, offset, size, super_size, ! 1796: &upl_object, &pl, *count, cntrl_flags); ! 1797: ! 1798: if(kr != KERN_SUCCESS) { ! 1799: *upl = MACH_PORT_NULL; ! 1800: return KERN_FAILURE; ! 1801: } ! 1802: ! 1803: ! 1804: upl_port = ipc_port_alloc_kernel(); ! 1805: ! 1806: ! 1807: ip_lock(upl_port); ! 1808: ! 1809: /* make a sonce right */ ! 1810: upl_port->ip_sorights++; ! 1811: ip_reference(upl_port); ! 1812: ! 1813: upl_port->ip_destination = IP_NULL; ! 1814: upl_port->ip_receiver_name = MACH_PORT_NULL; ! 1815: upl_port->ip_receiver = ipc_space_kernel; ! 1816: ! 1817: /* make a send right */ ! 1818: upl_port->ip_mscount++; ! 1819: upl_port->ip_srights++; ! 1820: ip_reference(upl_port); ! 1821: ! 1822: ipc_port_nsrequest(upl_port, 1, upl_port, &previous); ! 1823: /* nsrequest unlocks user_handle */ ! 1824: ! 1825: /* Create a named object based on a submap of specified size */ ! 1826: ! 1827: ! 1828: ipc_kobject_set(upl_port, (ipc_kobject_t) upl_object, IKOT_UPL); ! 1829: *upl = upl_port; ! 1830: return KERN_SUCCESS; ! 1831: } ! 1832: ! 1833: kern_return_t ! 1834: vm_upl_map( ! 1835: vm_map_t map, ! 1836: ipc_port_t upl_port, ! 1837: vm_offset_t *dst_addr) ! 1838: { ! 1839: upl_t upl; ! 1840: kern_return_t kr; ! 1841: ! 1842: if (!IP_VALID(upl_port)) { ! 1843: return KERN_INVALID_ARGUMENT; ! 1844: } else if (ip_kotype(upl_port) == IKOT_UPL) { ! 1845: upl_lock(upl); ! 1846: upl = (upl_t)upl_port->ip_kobject; ! 1847: kr = upl_map(map, upl, dst_addr); ! 1848: upl_unlock(upl); ! 1849: return kr; ! 1850: } else { ! 1851: return KERN_FAILURE; ! 1852: } ! 1853: } ! 1854: ! 1855: ! 1856: kern_return_t ! 1857: vm_upl_unmap( ! 1858: vm_map_t map, ! 1859: ipc_port_t upl_port) ! 1860: { ! 1861: upl_t upl; ! 1862: kern_return_t kr; ! 1863: ! 1864: if (!IP_VALID(upl_port)) { ! 1865: return KERN_INVALID_ARGUMENT; ! 1866: } else if (ip_kotype(upl_port) == IKOT_UPL) { ! 1867: upl_lock(upl); ! 1868: upl = (upl_t)upl_port->ip_kobject; ! 1869: kr = upl_un_map(map, upl); ! 1870: upl_unlock(upl); ! 1871: return kr; ! 1872: } else { ! 1873: return KERN_FAILURE; ! 1874: } ! 1875: } ! 1876: ! 1877: kern_return_t ! 1878: vm_upl_commit( ! 1879: upl_t upl, ! 1880: upl_page_list_ptr_t page_list, ! 1881: mach_msg_type_number_t count) ! 1882: { ! 1883: kern_return_t kr; ! 1884: upl_lock(upl); ! 1885: if(count) { ! 1886: kr = upl_commit(upl, (upl_page_info_t *)page_list); ! 1887: } else { ! 1888: kr = upl_commit(upl, (upl_page_info_t *) NULL); ! 1889: } ! 1890: upl_unlock(upl); ! 1891: return kr; ! 1892: } ! 1893: ! 1894: kern_return_t ! 1895: vm_upl_commit_range( ! 1896: upl_t upl, ! 1897: vm_offset_t offset, ! 1898: vm_size_t size, ! 1899: upl_page_list_ptr_t page_list, ! 1900: boolean_t free_on_empty, ! 1901: mach_msg_type_number_t count) ! 1902: { ! 1903: kern_return_t kr; ! 1904: upl_lock(upl); ! 1905: if(count) { ! 1906: kr = upl_commit_range(upl, offset, size, free_on_empty, ! 1907: (upl_page_info_t *)page_list); ! 1908: } else { ! 1909: kr = upl_commit_range(upl, offset, size, free_on_empty, ! 1910: (upl_page_info_t *) NULL); ! 1911: } ! 1912: upl_unlock(upl); ! 1913: return kr; ! 1914: } ! 1915: ! 1916: kern_return_t ! 1917: vm_upl_abort_range( ! 1918: upl_t upl, ! 1919: vm_offset_t offset, ! 1920: vm_size_t size, ! 1921: int abort_flags) ! 1922: { ! 1923: kern_return_t kr; ! 1924: upl_lock(upl); ! 1925: kr = upl_abort_range(upl, offset, size, abort_flags); ! 1926: upl_unlock(upl); ! 1927: return kr; ! 1928: } ! 1929: ! 1930: kern_return_t ! 1931: vm_upl_abort( ! 1932: upl_t upl, ! 1933: int abort_type) ! 1934: { ! 1935: kern_return_t kr; ! 1936: upl_lock(upl); ! 1937: kr = upl_abort(upl, abort_type); ! 1938: upl_unlock(upl); ! 1939: return kr; ! 1940: } ! 1941: ! 1942: #endif /* VM_CPM */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.