|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1993-1987 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: * File: vm/vm_map.c ! 52: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 53: * Date: 1985 ! 54: * ! 55: * Virtual memory mapping module. ! 56: */ ! 57: ! 58: #import <mach/features.h> ! 59: ! 60: #define USE_VERSIONS MACH_XP ! 61: ! 62: #import <mach/vm_param.h> ! 63: #import <vm/vm_map.h> ! 64: #import <kern/zalloc.h> ! 65: #import <mach/kern_return.h> ! 66: #import <vm/vm_page.h> ! 67: #import <vm/vm_object.h> ! 68: #import <mach/port.h> ! 69: #import <mach/vm_attributes.h> ! 70: ! 71: ! 72: /* ! 73: * Macros to copy a vm_map_entry. We must be careful to correctly ! 74: * manage the wired page count. vm_map_entry_copy() creates a new ! 75: * map entry to the same memory - the wired count in the new entry ! 76: * must be set to zero. vm_map_entry_copy_full() creates a new ! 77: * entry that is identical to the old entry. This preserves the ! 78: * wire count; it's used for map splitting and zone changing in ! 79: * vm_map_copyout. ! 80: */ ! 81: #define vm_map_entry_copy(NEW,OLD) \ ! 82: MACRO_BEGIN \ ! 83: *(NEW) = *(OLD); \ ! 84: (NEW)->is_shared = FALSE; \ ! 85: (NEW)->needs_wakeup = FALSE; \ ! 86: (NEW)->in_transition = FALSE; \ ! 87: (NEW)->wired_count = 0; \ ! 88: (NEW)->user_wired_count = 0; \ ! 89: MACRO_END ! 90: ! 91: #define vm_map_entry_copy_full(NEW,OLD) (*(NEW) = *(OLD)) ! 92: ! 93: /* ! 94: * Virtual memory maps provide for the mapping, protection, ! 95: * and sharing of virtual memory objects. In addition, ! 96: * this module provides for an efficient virtual copy of ! 97: * memory from one map to another. ! 98: * ! 99: * Synchronization is required prior to most operations. ! 100: * ! 101: * Maps consist of an ordered doubly-linked list of simple ! 102: * entries; a single hint is used to speed up lookups. ! 103: * ! 104: * In order to properly represent the sharing of virtual ! 105: * memory regions among maps, the map structure is bi-level. ! 106: * Top-level ("address") maps refer to regions of sharable ! 107: * virtual memory. These regions are implemented as ! 108: * ("sharing") maps, which then refer to the actual virtual ! 109: * memory objects. When two address maps "share" memory, ! 110: * their top-level maps both have references to the same ! 111: * sharing map. When memory is virtual-copied from one ! 112: * address map to another, the references in the sharing ! 113: * maps are actually copied -- no copying occurs at the ! 114: * virtual memory object level. ! 115: * ! 116: * Since portions of maps are specified by start/end addreses, ! 117: * which may not align with existing map entries, all ! 118: * routines merely "clip" entries to these start/end values. ! 119: * [That is, an entry is split into two, bordering at a ! 120: * start or end value.] Note that these clippings may not ! 121: * always be necessary (as the two resulting entries are then ! 122: * not changed); however, the clipping is done for convenience. ! 123: * No attempt is currently made to "glue back together" two ! 124: * abutting entries. ! 125: * ! 126: * As mentioned above, virtual copy operations are performed ! 127: * by copying VM object references from one sharing map to ! 128: * another, and then marking both regions as copy-on-write. ! 129: * It is important to note that only one writeable reference ! 130: * to a VM object region exists in any map -- this means that ! 131: * shadow object creation can be delayed until a write operation ! 132: * occurs. ! 133: */ ! 134: ! 135: zone_t vm_map_zone; /* zone for vm_map structures */ ! 136: zone_t vm_map_entry_zone; /* zone for vm_map_entry structures */ ! 137: zone_t vm_map_kentry_zone; /* zone for kernel entry structures */ ! 138: ! 139: vm_object_t vm_submap_object; ! 140: ! 141: /* ! 142: * vm_map_init: ! 143: * ! 144: * Initialize the vm_map module. Must be called before ! 145: * any other vm_map routines. ! 146: * ! 147: * Map and entry structures are allocated from zones -- we must ! 148: * initialize those zones. ! 149: * ! 150: * There are three zones of interest: ! 151: * ! 152: * vm_map_zone: used to allocate maps. ! 153: * vm_map_entry_zone: used to allocate map entries. ! 154: * vm_map_kentry_zone: used to allocate map entries for the kernel. ! 155: * ! 156: * The kernel allocates map entries from a special zone that is initially ! 157: * "crammed" with memory. It would be difficult (perhaps impossible) for ! 158: * the kernel to allocate more memory to a entry zone when it became ! 159: * empty since the very act of allocating memory implies the creatio ! 160: * of a new entry. Further, since the kernel map is created from the ! 161: * map zone, the map zone is initially "crammed" with enough memory ! 162: * to fullfill that need. ! 163: */ ! 164: ! 165: void vm_map_init() ! 166: { ! 167: extern vm_offset_t map_data, kentry_data; ! 168: extern vm_size_t map_data_size, kentry_data_size; ! 169: ! 170: vm_map_zone = zinit((vm_size_t) sizeof(struct vm_map), 100*1024, ! 171: 0, FALSE, "maps"); ! 172: vm_map_entry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry), ! 173: 1024*1024, 0, ! 174: FALSE, "non-kernel map entries"); ! 175: vm_map_kentry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry), ! 176: kentry_data_size, 0, ! 177: FALSE, "kernel map entries"); ! 178: zchange(vm_map_kentry_zone, FALSE, FALSE, FALSE, FALSE); ! 179: ! 180: /* ! 181: * Cram the map and kentry zones with initial data. ! 182: */ ! 183: zcram(vm_map_zone, map_data, map_data_size); ! 184: zcram(vm_map_kentry_zone, kentry_data, kentry_data_size); ! 185: } ! 186: ! 187: /* ! 188: * vm_map_create: ! 189: * ! 190: * Creates and returns a new empty VM map with ! 191: * the given physical map structure, and having ! 192: * the given lower and upper address bounds. ! 193: */ ! 194: vm_map_t vm_map_create(pmap, min, max, pageable) ! 195: pmap_t pmap; ! 196: vm_offset_t min, max; ! 197: boolean_t pageable; ! 198: { ! 199: register vm_map_t result; ! 200: ! 201: result = (vm_map_t) zalloc(vm_map_zone); ! 202: if (result == VM_MAP_NULL) ! 203: panic("vm_map_create"); ! 204: ! 205: vm_map_first_entry(result) = vm_map_to_entry(result); ! 206: vm_map_last_entry(result) = vm_map_to_entry(result); ! 207: result->hdr.nentries = 0; ! 208: result->hdr.entries_pageable = pageable; ! 209: ! 210: result->size = 0; ! 211: result->ref_count = 1; ! 212: result->pmap = pmap; ! 213: #if OLD_VM_CODE ! 214: result->is_main_map = TRUE; ! 215: #endif ! 216: result->min_offset = min; ! 217: result->max_offset = max; ! 218: result->wiring_required = FALSE; ! 219: result->wait_for_space = FALSE; ! 220: result->first_free = vm_map_to_entry(result); ! 221: result->hint = vm_map_to_entry(result); ! 222: #if OLD_VM_CODE ! 223: result->timestamp = 0; ! 224: #endif ! 225: vm_map_lock_init(result); ! 226: simple_lock_init(&result->ref_lock); ! 227: simple_lock_init(&result->hint_lock); ! 228: ! 229: return(result); ! 230: } ! 231: ! 232: /* ! 233: * vm_map_entry_create: [ internal use only ] ! 234: * ! 235: * Allocates a VM map entry for insertion in the ! 236: * given map (or map copy). No fields are filled. ! 237: */ ! 238: #define vm_map_entry_create(map) \ ! 239: _vm_map_entry_create(&(map)->hdr) ! 240: ! 241: #define vm_map_copy_entry_create(copy) \ ! 242: _vm_map_entry_create(&(copy)->cpy_hdr) ! 243: ! 244: vm_map_entry_t _vm_map_entry_create(map_header) ! 245: register struct vm_map_header *map_header; ! 246: { ! 247: register zone_t zone; ! 248: register vm_map_entry_t entry; ! 249: ! 250: if (map_header->entries_pageable) ! 251: zone = vm_map_entry_zone; ! 252: else ! 253: zone = vm_map_kentry_zone; ! 254: ! 255: entry = (vm_map_entry_t) zalloc(zone); ! 256: if (entry == VM_MAP_ENTRY_NULL) ! 257: panic("vm_map_entry_create"); ! 258: ! 259: return(entry); ! 260: } ! 261: ! 262: /* ! 263: * vm_map_entry_dispose: [ internal use only ] ! 264: * ! 265: * Inverse of vm_map_entry_create. ! 266: */ ! 267: #define vm_map_entry_dispose(map, entry) \ ! 268: _vm_map_entry_dispose(&(map)->hdr, (entry)) ! 269: ! 270: #define vm_map_copy_entry_dispose(map, entry) \ ! 271: _vm_map_entry_dispose(&(copy)->cpy_hdr, (entry)) ! 272: ! 273: void _vm_map_entry_dispose(map_header, entry) ! 274: register struct vm_map_header *map_header; ! 275: register vm_map_entry_t entry; ! 276: { ! 277: register zone_t zone; ! 278: ! 279: if (map_header->entries_pageable) ! 280: zone = vm_map_entry_zone; ! 281: else ! 282: zone = vm_map_kentry_zone; ! 283: ! 284: zfree(zone, (vm_offset_t) entry); ! 285: } ! 286: ! 287: /* ! 288: * vm_map_entry_{un,}link: ! 289: * ! 290: * Insert/remove entries from maps (or map copies). ! 291: */ ! 292: #define vm_map_entry_link(map, after_where, entry) \ ! 293: _vm_map_entry_link(&(map)->hdr, after_where, entry) ! 294: ! 295: #define vm_map_copy_entry_link(copy, after_where, entry) \ ! 296: _vm_map_entry_link(&(copy)->cpy_hdr, after_where, entry) ! 297: ! 298: #define _vm_map_entry_link(hdr, after_where, entry) \ ! 299: MACRO_BEGIN \ ! 300: (hdr)->nentries++; \ ! 301: (entry)->vme_prev = (after_where); \ ! 302: (entry)->vme_next = (after_where)->vme_next; \ ! 303: (entry)->vme_prev->vme_next = \ ! 304: (entry)->vme_next->vme_prev = (entry); \ ! 305: MACRO_END ! 306: ! 307: #define vm_map_entry_unlink(map, entry) \ ! 308: _vm_map_entry_unlink(&(map)->hdr, entry) ! 309: ! 310: #define vm_map_copy_entry_unlink(copy, entry) \ ! 311: _vm_map_entry_unlink(&(copy)->cpy_hdr, entry) ! 312: ! 313: #define _vm_map_entry_unlink(hdr, entry) \ ! 314: MACRO_BEGIN \ ! 315: (hdr)->nentries--; \ ! 316: (entry)->vme_next->vme_prev = (entry)->vme_prev; \ ! 317: (entry)->vme_prev->vme_next = (entry)->vme_next; \ ! 318: MACRO_END ! 319: ! 320: /* ! 321: * vm_map_reference: ! 322: * ! 323: * Creates another valid reference to the given map. ! 324: * ! 325: */ ! 326: void vm_map_reference(map) ! 327: register vm_map_t map; ! 328: { ! 329: if (map == VM_MAP_NULL) ! 330: return; ! 331: ! 332: simple_lock(&map->ref_lock); ! 333: map->ref_count++; ! 334: simple_unlock(&map->ref_lock); ! 335: } ! 336: ! 337: /* ! 338: * vm_map_deallocate: ! 339: * ! 340: * Removes a reference from the specified map, ! 341: * destroying it if no references remain. ! 342: * The map should not be locked. ! 343: */ ! 344: void vm_map_deallocate(map) ! 345: register vm_map_t map; ! 346: { ! 347: register int c; ! 348: ! 349: if (map == VM_MAP_NULL) ! 350: return; ! 351: ! 352: simple_lock(&map->ref_lock); ! 353: c = --map->ref_count; ! 354: simple_unlock(&map->ref_lock); ! 355: ! 356: if (c > 0) { ! 357: return; ! 358: } ! 359: ! 360: /* ! 361: * Lock the map, to wait out all other references ! 362: * to it. ! 363: */ ! 364: ! 365: vm_map_lock(map); ! 366: ! 367: (void) vm_map_delete(map, map->min_offset, map->max_offset); ! 368: ! 369: pmap_destroy(map->pmap); ! 370: ! 371: zfree(vm_map_zone, (vm_offset_t) map); ! 372: } ! 373: ! 374: /* ! 375: * vm_map_insert: [ internal use only ] ! 376: * ! 377: * Inserts the given whole VM object into the target ! 378: * map at the specified address range. The object's ! 379: * size should match that of the address range. ! 380: * ! 381: * Requires that the map be locked, and leaves it so. ! 382: */ ! 383: kern_return_t vm_map_insert(map, object, offset, start, end) ! 384: vm_map_t map; ! 385: vm_object_t object; ! 386: vm_offset_t offset; ! 387: vm_offset_t start; ! 388: vm_offset_t end; ! 389: { ! 390: vm_map_entry_t new_entry; ! 391: vm_map_entry_t prev_entry; ! 392: boolean_t vm_map_lookup_entry(); ! 393: ! 394: /* ! 395: * Check that the start and end points are not bogus. ! 396: */ ! 397: ! 398: if ((start < map->min_offset) || (end > map->max_offset) || ! 399: (start >= end)) ! 400: return(KERN_INVALID_ADDRESS); ! 401: ! 402: /* ! 403: * Find the entry prior to the proposed ! 404: * starting address; if it's part of an ! 405: * existing entry, this range is bogus. ! 406: */ ! 407: ! 408: if (vm_map_lookup_entry(map, start, &prev_entry)) ! 409: return(KERN_NO_SPACE); ! 410: ! 411: /* ! 412: * Assert that the next entry doesn't overlap the ! 413: * end point. ! 414: */ ! 415: ! 416: if ((prev_entry->vme_next != vm_map_to_entry(map)) && ! 417: (prev_entry->vme_next->vme_start < end)) ! 418: return(KERN_NO_SPACE); ! 419: ! 420: /* ! 421: * See if we can avoid creating a new entry by ! 422: * extending one of our neighbors. ! 423: */ ! 424: ! 425: if (object == VM_OBJECT_NULL) { ! 426: if ((prev_entry != vm_map_to_entry(map)) && ! 427: (prev_entry->vme_end == start) && ! 428: (prev_entry->is_a_map == FALSE) && ! 429: (prev_entry->is_sub_map == FALSE) && ! 430: (prev_entry->inheritance == VM_INHERIT_DEFAULT) && ! 431: (prev_entry->protection == VM_PROT_DEFAULT) && ! 432: (prev_entry->max_protection == VM_PROT_ALL) && ! 433: (prev_entry->wired_count == 0)) { ! 434: ! 435: if (vm_object_coalesce(prev_entry->object.vm_object, ! 436: VM_OBJECT_NULL, ! 437: prev_entry->offset, ! 438: (vm_offset_t) 0, ! 439: (vm_size_t)(prev_entry->vme_end ! 440: - prev_entry->vme_start), ! 441: (vm_size_t)(end - ! 442: prev_entry->vme_end))) { ! 443: /* ! 444: * Coalesced the two objects - can extend ! 445: * the previous map entry to include the ! 446: * new range. ! 447: */ ! 448: map->size += (end - prev_entry->vme_end); ! 449: prev_entry->vme_end = end; ! 450: return(KERN_SUCCESS); ! 451: } ! 452: } ! 453: } ! 454: ! 455: /* ! 456: * Create a new entry ! 457: */ ! 458: ! 459: new_entry = vm_map_entry_create(map); ! 460: new_entry->vme_start = start; ! 461: new_entry->vme_end = end; ! 462: ! 463: new_entry->is_a_map = FALSE; ! 464: new_entry->is_sub_map = FALSE; ! 465: new_entry->object.vm_object = object; ! 466: new_entry->offset = offset; ! 467: ! 468: new_entry->copy_on_write = FALSE; ! 469: new_entry->needs_copy = FALSE; ! 470: ! 471: if (map->is_main_map) { ! 472: new_entry->inheritance = VM_INHERIT_DEFAULT; ! 473: new_entry->protection = VM_PROT_DEFAULT; ! 474: new_entry->max_protection = VM_PROT_ALL; ! 475: new_entry->wired_count = 0; ! 476: } ! 477: ! 478: /* ! 479: * Insert the new entry into the list ! 480: */ ! 481: ! 482: vm_map_entry_link(map, prev_entry, new_entry); ! 483: map->size += new_entry->vme_end - new_entry->vme_start; ! 484: ! 485: /* ! 486: * Update the free space hint ! 487: */ ! 488: ! 489: if ((map->first_free == prev_entry) && (prev_entry->vme_end >= new_entry->vme_start)) ! 490: map->first_free = new_entry; ! 491: ! 492: return(KERN_SUCCESS); ! 493: } ! 494: ! 495: /* ! 496: * SAVE_HINT: ! 497: * ! 498: * Saves the specified entry as the hint for ! 499: * future lookups. Performs necessary interlocks. ! 500: */ ! 501: #define SAVE_HINT(map,value) \ ! 502: simple_lock(&(map)->hint_lock); \ ! 503: (map)->hint = (value); \ ! 504: simple_unlock(&(map)->hint_lock); ! 505: ! 506: /* ! 507: * vm_map_lookup_entry: [ internal use only ] ! 508: * ! 509: * Finds the map entry containing (or ! 510: * immediately preceding) the specified address ! 511: * in the given map; the entry is returned ! 512: * in the "entry" parameter. The boolean ! 513: * result indicates whether the address is ! 514: * actually contained in the map. ! 515: */ ! 516: boolean_t vm_map_lookup_entry(map, address, entry) ! 517: register vm_map_t map; ! 518: register vm_offset_t address; ! 519: vm_map_entry_t *entry; /* OUT */ ! 520: { ! 521: register vm_map_entry_t cur; ! 522: register vm_map_entry_t last; ! 523: ! 524: /* ! 525: * Start looking either from the head of the ! 526: * list, or from the hint. ! 527: */ ! 528: ! 529: simple_lock(&map->hint_lock); ! 530: cur = map->hint; ! 531: simple_unlock(&map->hint_lock); ! 532: ! 533: if (cur == vm_map_to_entry(map)) ! 534: cur = cur->vme_next; ! 535: ! 536: if (address >= cur->vme_start) { ! 537: /* ! 538: * Go from hint to end of list. ! 539: * ! 540: * But first, make a quick check to see if ! 541: * we are already looking at the entry we ! 542: * want (which is usually the case). ! 543: * Note also that we don't need to save the hint ! 544: * here... it is the same hint (unless we are ! 545: * at the header, in which case the hint didn't ! 546: * buy us anything anyway). ! 547: */ ! 548: last = vm_map_to_entry(map); ! 549: if ((cur != last) && (cur->vme_end > address)) { ! 550: *entry = cur; ! 551: return(TRUE); ! 552: } ! 553: } ! 554: else { ! 555: /* ! 556: * Go from start to hint, *inclusively* ! 557: */ ! 558: last = cur->vme_next; ! 559: cur = vm_map_first_entry(map); ! 560: } ! 561: ! 562: /* ! 563: * Search linearly ! 564: */ ! 565: ! 566: while (cur != last) { ! 567: if (cur->vme_end > address) { ! 568: if (address >= cur->vme_start) { ! 569: /* ! 570: * Save this lookup for future ! 571: * hints, and return ! 572: */ ! 573: ! 574: *entry = cur; ! 575: SAVE_HINT(map, cur); ! 576: return(TRUE); ! 577: } ! 578: break; ! 579: } ! 580: cur = cur->vme_next; ! 581: } ! 582: *entry = cur->vme_prev; ! 583: SAVE_HINT(map, *entry); ! 584: return(FALSE); ! 585: } ! 586: ! 587: /* ! 588: * Routine: vm_map_find_entry ! 589: * Purpose: ! 590: * Allocate a range in the specified virtual address map, ! 591: * returning the entry allocated for that range. ! 592: * Used by kmem_alloc, etc. Returns wired entries. ! 593: * ! 594: * The map must be locked. ! 595: * ! 596: * If an entry is allocated, the object/offset fields ! 597: * are initialized to zero. If an object is supplied, ! 598: * then an existing entry may be extended. ! 599: */ ! 600: kern_return_t vm_map_find_entry(map, address, size, mask, object, o_entry) ! 601: register vm_map_t map; ! 602: vm_offset_t *address; /* OUT */ ! 603: vm_size_t size; ! 604: vm_offset_t mask; ! 605: vm_object_t object; ! 606: vm_map_entry_t *o_entry; /* OUT */ ! 607: { ! 608: register vm_map_entry_t entry, new_entry; ! 609: register vm_offset_t start; ! 610: register vm_offset_t end; ! 611: ! 612: /* ! 613: * Look for the first possible address; ! 614: * if there's already something at this ! 615: * address, we have to start after it. ! 616: */ ! 617: ! 618: if ((entry = map->first_free) == vm_map_to_entry(map)) ! 619: start = map->min_offset; ! 620: else ! 621: start = entry->vme_end; ! 622: ! 623: /* ! 624: * In any case, the "entry" always precedes ! 625: * the proposed new region throughout the loop: ! 626: */ ! 627: ! 628: while (TRUE) { ! 629: register vm_map_entry_t next; ! 630: ! 631: /* ! 632: * Find the end of the proposed new region. ! 633: * Be sure we didn't go beyond the end, or ! 634: * wrap around the address. ! 635: */ ! 636: ! 637: start = ((start + mask) & ~mask); ! 638: end = start + size; ! 639: ! 640: if ((end > map->max_offset) || (end < start)) ! 641: return(KERN_NO_SPACE); ! 642: ! 643: /* ! 644: * If there are no more entries, we must win. ! 645: */ ! 646: ! 647: next = entry->vme_next; ! 648: if (next == vm_map_to_entry(map)) ! 649: break; ! 650: ! 651: /* ! 652: * If there is another entry, it must be ! 653: * after the end of the potential new region. ! 654: */ ! 655: ! 656: if (next->vme_start >= end) ! 657: break; ! 658: ! 659: /* ! 660: * Didn't fit -- move to the next entry. ! 661: */ ! 662: ! 663: entry = next; ! 664: start = entry->vme_end; ! 665: } ! 666: ! 667: /* ! 668: * At this point, ! 669: * "start" and "end" should define the endpoints of the ! 670: * available new range, and ! 671: * "entry" should refer to the region before the new ! 672: * range, and ! 673: * ! 674: * the map should be locked. ! 675: */ ! 676: ! 677: *address = start; ! 678: ! 679: /* ! 680: * See whether we can avoid creating a new entry by ! 681: * extending one of our neighbors. [So far, we only attempt to ! 682: * extend from below.] ! 683: */ ! 684: ! 685: if ((object != VM_OBJECT_NULL) && ! 686: (entry != vm_map_to_entry(map)) && ! 687: (entry->vme_end == start) && ! 688: (!entry->is_shared) && ! 689: (!entry->is_sub_map) && ! 690: (entry->object.vm_object == object) && ! 691: (entry->needs_copy == FALSE) && ! 692: (entry->inheritance == VM_INHERIT_DEFAULT) && ! 693: (entry->protection == VM_PROT_DEFAULT) && ! 694: (entry->max_protection == VM_PROT_ALL) && ! 695: (entry->wired_count == 1) && ! 696: (entry->user_wired_count == 0)) { ! 697: /* ! 698: * Because this is a special case, ! 699: * we don't need to use vm_object_coalesce. ! 700: */ ! 701: ! 702: entry->vme_end = end; ! 703: new_entry = entry; ! 704: } else { ! 705: new_entry = vm_map_entry_create(map); ! 706: ! 707: new_entry->vme_start = start; ! 708: new_entry->vme_end = end; ! 709: ! 710: new_entry->is_shared = FALSE; ! 711: new_entry->is_sub_map = FALSE; ! 712: new_entry->object.vm_object = VM_OBJECT_NULL; ! 713: new_entry->offset = (vm_offset_t) 0; ! 714: ! 715: new_entry->needs_copy = FALSE; ! 716: ! 717: new_entry->inheritance = VM_INHERIT_DEFAULT; ! 718: new_entry->protection = VM_PROT_DEFAULT; ! 719: new_entry->max_protection = VM_PROT_ALL; ! 720: new_entry->wired_count = 1; ! 721: new_entry->user_wired_count = 0; ! 722: ! 723: new_entry->in_transition = FALSE; ! 724: new_entry->needs_wakeup = FALSE; ! 725: ! 726: /* ! 727: * Insert the new entry into the list ! 728: */ ! 729: ! 730: vm_map_entry_link(map, entry, new_entry); ! 731: } ! 732: ! 733: map->size += size; ! 734: ! 735: /* ! 736: * Update the free space hint and the lookup hint ! 737: */ ! 738: ! 739: map->first_free = new_entry; ! 740: SAVE_HINT(map, new_entry); ! 741: ! 742: *o_entry = new_entry; ! 743: return(KERN_SUCCESS); ! 744: } ! 745: ! 746: /* ! 747: * vm_map_find finds an unallocated region in the target address ! 748: * map with the given length. The search is defined to be ! 749: * first-fit from the specified address; the region found is ! 750: * returned in the same parameter. ! 751: * ! 752: */ ! 753: kern_return_t vm_map_find(map, object, offset, addr, length, find_space) ! 754: vm_map_t map; ! 755: vm_object_t object; ! 756: vm_offset_t offset; ! 757: vm_offset_t *addr; /* IN/OUT */ ! 758: vm_size_t length; ! 759: boolean_t find_space; ! 760: { ! 761: register vm_map_entry_t entry; ! 762: register vm_offset_t start; ! 763: register vm_offset_t end; ! 764: kern_return_t result; ! 765: ! 766: start = *addr; ! 767: ! 768: vm_map_lock(map); ! 769: ! 770: if (find_space) { ! 771: /* ! 772: * Calculate the first possible address. ! 773: */ ! 774: ! 775: if (start < map->min_offset) ! 776: start = map->min_offset; ! 777: if (start > map->max_offset) { ! 778: vm_map_unlock(map); ! 779: return (KERN_NO_SPACE); ! 780: } ! 781: ! 782: /* ! 783: * Look for the first possible address; ! 784: * if there's already something at this ! 785: * address, we have to start after it. ! 786: */ ! 787: ! 788: if (start == map->min_offset) { ! 789: if ((entry = map->first_free) != vm_map_to_entry(map)) ! 790: start = entry->vme_end; ! 791: } else { ! 792: vm_map_entry_t tmp_entry; ! 793: if (vm_map_lookup_entry(map, start, &tmp_entry)) ! 794: start = tmp_entry->vme_end; ! 795: entry = tmp_entry; ! 796: } ! 797: ! 798: /* ! 799: * In any case, the "entry" always precedes ! 800: * the proposed new region throughout the ! 801: * loop: ! 802: */ ! 803: ! 804: while (TRUE) { ! 805: register vm_map_entry_t next; ! 806: ! 807: /* ! 808: * Find the end of the proposed new region. ! 809: * Be sure we didn't go beyond the end, or ! 810: * wrap around the address. ! 811: */ ! 812: ! 813: end = start + length; ! 814: ! 815: if ((end > map->max_offset) || (end < start)) { ! 816: vm_map_unlock(map); ! 817: return (KERN_NO_SPACE); ! 818: } ! 819: ! 820: /* ! 821: * If there are no more entries, we must win. ! 822: */ ! 823: ! 824: next = entry->vme_next; ! 825: if (next == vm_map_to_entry(map)) ! 826: break; ! 827: ! 828: /* ! 829: * If there is another entry, it must be ! 830: * after the end of the potential new region. ! 831: */ ! 832: ! 833: if (next->vme_start >= end) ! 834: break; ! 835: ! 836: /* ! 837: * Didn't fit -- move to the next entry. ! 838: */ ! 839: ! 840: entry = next; ! 841: start = entry->vme_end; ! 842: } ! 843: *addr = start; ! 844: ! 845: SAVE_HINT(map, entry); ! 846: } ! 847: ! 848: result = vm_map_insert(map, object, offset, start, start + length); ! 849: ! 850: vm_map_unlock(map); ! 851: return(result); ! 852: } ! 853: ! 854: /* ! 855: * vm_map_clip_start: [ internal use only ] ! 856: * ! 857: * Asserts that the given entry begins at or after ! 858: * the specified address; if necessary, ! 859: * it splits the entry into two. ! 860: */ ! 861: void _vm_map_clip_start(); ! 862: #define vm_map_clip_start(map, entry, startaddr) \ ! 863: MACRO_BEGIN \ ! 864: if ((startaddr) > (entry)->vme_start) \ ! 865: _vm_map_clip_start(&(map)->hdr,(entry),(startaddr)); \ ! 866: MACRO_END ! 867: ! 868: void _vm_map_copy_clip_start(); ! 869: #define vm_map_copy_clip_start(copy, entry, startaddr) \ ! 870: MACRO_BEGIN \ ! 871: if ((startaddr) > (entry)->vme_start) \ ! 872: _vm_map_clip_start(&(copy)->cpy_hdr,(entry),(startaddr)); \ ! 873: MACRO_END ! 874: ! 875: /* ! 876: * This routine is called only when it is known that ! 877: * the entry must be split. ! 878: */ ! 879: void _vm_map_clip_start(map_header, entry, start) ! 880: register struct vm_map_header *map_header; ! 881: register vm_map_entry_t entry; ! 882: register vm_offset_t start; ! 883: { ! 884: register vm_map_entry_t new_entry; ! 885: ! 886: /* ! 887: * Split off the front portion -- ! 888: * note that we must insert the new ! 889: * entry BEFORE this one, so that ! 890: * this entry has the specified starting ! 891: * address. ! 892: */ ! 893: ! 894: new_entry = _vm_map_entry_create(map_header); ! 895: vm_map_entry_copy_full(new_entry, entry); ! 896: ! 897: new_entry->vme_end = start; ! 898: entry->offset += (start - entry->vme_start); ! 899: entry->vme_start = start; ! 900: ! 901: _vm_map_entry_link(map_header, entry->vme_prev, new_entry); ! 902: ! 903: if (entry->is_a_map || entry->is_sub_map) ! 904: vm_map_reference(new_entry->object.share_map); ! 905: else ! 906: vm_object_reference(new_entry->object.vm_object); ! 907: } ! 908: ! 909: /* ! 910: * vm_map_clip_end: [ internal use only ] ! 911: * ! 912: * Asserts that the given entry ends at or before ! 913: * the specified address; if necessary, ! 914: * it splits the entry into two. ! 915: */ ! 916: void _vm_map_clip_end(); ! 917: #define vm_map_clip_end(map, entry, endaddr) \ ! 918: MACRO_BEGIN \ ! 919: if ((endaddr) < (entry)->vme_end) \ ! 920: _vm_map_clip_end(&(map)->hdr,(entry),(endaddr)); \ ! 921: MACRO_END ! 922: ! 923: void _vm_map_copy_clip_end(); ! 924: #define vm_map_copy_clip_end(copy, entry, endaddr) \ ! 925: MACRO_BEGIN \ ! 926: if ((endaddr) < (entry)->vme_end) \ ! 927: _vm_map_clip_end(&(copy)->cpy_hdr,(entry),(endaddr)); \ ! 928: MACRO_END ! 929: ! 930: /* ! 931: * This routine is called only when it is known that ! 932: * the entry must be split. ! 933: */ ! 934: void _vm_map_clip_end(map_header, entry, end) ! 935: register struct vm_map_header *map_header; ! 936: register vm_map_entry_t entry; ! 937: register vm_offset_t end; ! 938: { ! 939: register vm_map_entry_t new_entry; ! 940: ! 941: /* ! 942: * Create a new entry and insert it ! 943: * AFTER the specified entry ! 944: */ ! 945: ! 946: new_entry = _vm_map_entry_create(map_header); ! 947: vm_map_entry_copy_full(new_entry, entry); ! 948: ! 949: new_entry->vme_start = entry->vme_end = end; ! 950: new_entry->offset += (end - entry->vme_start); ! 951: ! 952: _vm_map_entry_link(map_header, entry, new_entry); ! 953: ! 954: if (entry->is_a_map || entry->is_sub_map) ! 955: vm_map_reference(new_entry->object.share_map); ! 956: else ! 957: vm_object_reference(new_entry->object.vm_object); ! 958: } ! 959: ! 960: /* ! 961: * VM_MAP_RANGE_CHECK: [ internal use only ] ! 962: * ! 963: * Asserts that the starting and ending region ! 964: * addresses fall within the valid range of the map. ! 965: */ ! 966: #define VM_MAP_RANGE_CHECK(map, start, end) \ ! 967: { \ ! 968: if (start < vm_map_min(map)) \ ! 969: start = vm_map_min(map); \ ! 970: if (end > vm_map_max(map)) \ ! 971: end = vm_map_max(map); \ ! 972: if (start > end) \ ! 973: start = end; \ ! 974: } ! 975: ! 976: /* ! 977: * vm_map_submap: [ kernel use only ] ! 978: * ! 979: * Mark the given range as handled by a subordinate map. ! 980: * ! 981: * This range must have been created with vm_map_find, ! 982: * and no other operations may have been performed on this ! 983: * range prior to calling vm_map_submap. ! 984: * ! 985: * Only a limited number of operations can be performed ! 986: * within this rage after calling vm_map_submap: ! 987: * vm_fault ! 988: * [Don't try vm_map_copy!] ! 989: * ! 990: * To remove a submapping, one must first remove the ! 991: * range from the superior map, and then destroy the ! 992: * submap (if desired). [Better yet, don't try it.] ! 993: */ ! 994: kern_return_t vm_map_submap(map, start, end, submap) ! 995: register vm_map_t map; ! 996: register vm_offset_t start; ! 997: register vm_offset_t end; ! 998: vm_map_t submap; ! 999: { ! 1000: vm_map_entry_t entry; ! 1001: register kern_return_t result = KERN_INVALID_ARGUMENT; ! 1002: register vm_object_t object; ! 1003: ! 1004: vm_map_lock(map); ! 1005: ! 1006: VM_MAP_RANGE_CHECK(map, start, end); ! 1007: ! 1008: if (vm_map_lookup_entry(map, start, &entry)) { ! 1009: vm_map_clip_start(map, entry, start); ! 1010: } ! 1011: else ! 1012: entry = entry->vme_next; ! 1013: ! 1014: vm_map_clip_end(map, entry, end); ! 1015: ! 1016: if ((entry->vme_start == start) && (entry->vme_end == end) && ! 1017: (!entry->is_a_map) && ! 1018: ((object = entry->object.vm_object) == vm_submap_object) && ! 1019: (!entry->copy_on_write)) { ! 1020: entry->object.vm_object = VM_OBJECT_NULL; ! 1021: vm_object_deallocate(object); ! 1022: entry->is_sub_map = TRUE; ! 1023: vm_map_reference(entry->object.sub_map = submap); ! 1024: result = KERN_SUCCESS; ! 1025: } ! 1026: vm_map_unlock(map); ! 1027: ! 1028: return(result); ! 1029: } ! 1030: ! 1031: /* ! 1032: * vm_map_protect: ! 1033: * ! 1034: * Sets the protection of the specified address ! 1035: * region in the target map. If "set_max" is ! 1036: * specified, the maximum protection is to be set; ! 1037: * otherwise, only the current protection is affected. ! 1038: */ ! 1039: kern_return_t vm_map_protect(map, start, end, new_prot, set_max) ! 1040: register vm_map_t map; ! 1041: register vm_offset_t start; ! 1042: register vm_offset_t end; ! 1043: register vm_prot_t new_prot; ! 1044: register boolean_t set_max; ! 1045: { ! 1046: register vm_map_entry_t current; ! 1047: vm_map_entry_t entry; ! 1048: ! 1049: vm_map_lock(map); ! 1050: ! 1051: VM_MAP_RANGE_CHECK(map, start, end); ! 1052: ! 1053: if (vm_map_lookup_entry(map, start, &entry)) { ! 1054: vm_map_clip_start(map, entry, start); ! 1055: } ! 1056: else ! 1057: entry = entry->vme_next; ! 1058: ! 1059: /* ! 1060: * Make a first pass to check for protection ! 1061: * violations. ! 1062: */ ! 1063: ! 1064: current = entry; ! 1065: while ((current != vm_map_to_entry(map)) && ! 1066: (current->vme_start < end)) { ! 1067: if (current->is_sub_map) { ! 1068: vm_map_unlock(map); ! 1069: return(KERN_INVALID_ARGUMENT); ! 1070: } ! 1071: if ((new_prot & current->max_protection) != new_prot) { ! 1072: vm_map_unlock(map); ! 1073: return(KERN_PROTECTION_FAILURE); ! 1074: } ! 1075: ! 1076: current = current->vme_next; ! 1077: } ! 1078: ! 1079: /* ! 1080: * Go back and fix up protections. ! 1081: * [Note that clipping is not necessary the second time.] ! 1082: */ ! 1083: ! 1084: current = entry; ! 1085: ! 1086: while ((current != vm_map_to_entry(map)) && ! 1087: (current->vme_start < end)) { ! 1088: vm_prot_t old_prot; ! 1089: ! 1090: vm_map_clip_end(map, current, end); ! 1091: ! 1092: old_prot = current->protection; ! 1093: if (set_max) ! 1094: current->protection = ! 1095: (current->max_protection = new_prot) & ! 1096: old_prot; ! 1097: else ! 1098: current->protection = new_prot; ! 1099: ! 1100: /* ! 1101: * Update physical map if necessary. ! 1102: * Worry about copy-on-write here -- CHECK THIS XXX ! 1103: */ ! 1104: ! 1105: if (current->protection != old_prot) { ! 1106: ! 1107: #define MASK(entry) ((entry)->copy_on_write ? ~VM_PROT_WRITE : \ ! 1108: VM_PROT_ALL) ! 1109: #define max(a,b) ((a) > (b) ? (a) : (b)) ! 1110: ! 1111: if (current->is_a_map) { ! 1112: vm_map_entry_t share_entry; ! 1113: vm_offset_t share_end; ! 1114: ! 1115: vm_map_lock(current->object.share_map); ! 1116: (void) vm_map_lookup_entry( ! 1117: current->object.share_map, ! 1118: current->offset, ! 1119: &share_entry); ! 1120: share_end = current->offset + ! 1121: (current->vme_end - ! 1122: current->vme_start); ! 1123: while ((share_entry != ! 1124: vm_map_to_entry( ! 1125: current->object.share_map)) && ! 1126: (share_entry->vme_start < share_end)) { ! 1127: ! 1128: pmap_protect(map->pmap, ! 1129: (max(share_entry->vme_start, ! 1130: current->offset) - ! 1131: current->offset + ! 1132: current->vme_start), ! 1133: max(share_entry->vme_end, ! 1134: share_end) - ! 1135: current->offset + ! 1136: current->vme_start, ! 1137: current->protection & ! 1138: MASK(share_entry)); ! 1139: ! 1140: share_entry = share_entry->vme_next; ! 1141: } ! 1142: vm_map_unlock(current->object.share_map); ! 1143: } ! 1144: else ! 1145: pmap_protect(map->pmap, current->vme_start, ! 1146: current->vme_end, ! 1147: current->protection & MASK(entry)); ! 1148: #undef max ! 1149: #undef MASK ! 1150: } ! 1151: current = current->vme_next; ! 1152: } ! 1153: ! 1154: vm_map_unlock(map); ! 1155: return(KERN_SUCCESS); ! 1156: } ! 1157: ! 1158: /* ! 1159: * vm_map_inherit: ! 1160: * ! 1161: * Sets the inheritance of the specified address ! 1162: * range in the target map. Inheritance ! 1163: * affects how the map will be shared with ! 1164: * child maps at the time of vm_map_fork. ! 1165: */ ! 1166: kern_return_t vm_map_inherit(map, start, end, new_inheritance) ! 1167: register vm_map_t map; ! 1168: register vm_offset_t start; ! 1169: register vm_offset_t end; ! 1170: register vm_inherit_t new_inheritance; ! 1171: { ! 1172: register vm_map_entry_t entry; ! 1173: vm_map_entry_t temp_entry; ! 1174: ! 1175: switch (new_inheritance) { ! 1176: case VM_INHERIT_NONE: ! 1177: case VM_INHERIT_COPY: ! 1178: case VM_INHERIT_SHARE: ! 1179: break; ! 1180: default: ! 1181: return(KERN_INVALID_ARGUMENT); ! 1182: } ! 1183: ! 1184: vm_map_lock(map); ! 1185: ! 1186: VM_MAP_RANGE_CHECK(map, start, end); ! 1187: ! 1188: if (vm_map_lookup_entry(map, start, &temp_entry)) { ! 1189: entry = temp_entry; ! 1190: vm_map_clip_start(map, entry, start); ! 1191: } ! 1192: else ! 1193: entry = temp_entry->vme_next; ! 1194: ! 1195: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) { ! 1196: vm_map_clip_end(map, entry, end); ! 1197: ! 1198: entry->inheritance = new_inheritance; ! 1199: ! 1200: entry = entry->vme_next; ! 1201: } ! 1202: ! 1203: vm_map_unlock(map); ! 1204: return(KERN_SUCCESS); ! 1205: } ! 1206: ! 1207: #if NeXT ! 1208: extern vm_map_t kernel_map; ! 1209: #endif ! 1210: ! 1211: /* ! 1212: * vm_map_pageable: ! 1213: * ! 1214: * Sets the pageability of the specified address ! 1215: * range in the target map. Regions specified ! 1216: * as not pageable require locked-down physical ! 1217: * memory and physical page maps. ! 1218: * ! 1219: * The map must not be locked, but a reference ! 1220: * must remain to the map throughout the call. ! 1221: */ ! 1222: kern_return_t vm_map_pageable(map, start, end, new_pageable) ! 1223: register vm_map_t map; ! 1224: register vm_offset_t start; ! 1225: register vm_offset_t end; ! 1226: register boolean_t new_pageable; ! 1227: { ! 1228: register vm_map_entry_t entry; ! 1229: vm_map_entry_t temp_entry; ! 1230: #if NeXT ! 1231: int map_locked = 1; ! 1232: #endif ! 1233: ! 1234: vm_map_lock(map); ! 1235: ! 1236: VM_MAP_RANGE_CHECK(map, start, end); ! 1237: ! 1238: /* ! 1239: * Only one pageability change may take place at one ! 1240: * time, since vm_fault assumes it will be called ! 1241: * only once for each wiring/unwiring. Therefore, we ! 1242: * have to make sure we're actually changing the pageability ! 1243: * for the entire region. We do so before making any changes. ! 1244: */ ! 1245: ! 1246: if (vm_map_lookup_entry(map, start, &temp_entry)) { ! 1247: entry = temp_entry; ! 1248: vm_map_clip_start(map, entry, start); ! 1249: } ! 1250: else ! 1251: entry = temp_entry->vme_next; ! 1252: temp_entry = entry; ! 1253: ! 1254: /* ! 1255: * Actions are rather different for wiring and unwiring, ! 1256: * so we have two separate cases. ! 1257: */ ! 1258: ! 1259: if (new_pageable) { ! 1260: ! 1261: /* ! 1262: * Unwiring. First ensure that the range to be ! 1263: * unwired is really wired down. ! 1264: */ ! 1265: while ((entry != vm_map_to_entry(map)) && ! 1266: (entry->vme_start < end)) { ! 1267: ! 1268: if (entry->wired_count == 0) { ! 1269: vm_map_unlock(map); ! 1270: return(KERN_INVALID_ARGUMENT); ! 1271: } ! 1272: entry = entry->vme_next; ! 1273: } ! 1274: ! 1275: /* ! 1276: * Now decrement the wiring count for each region. ! 1277: * If a region becomes completely unwired, ! 1278: * unwire its physical pages and mappings. ! 1279: */ ! 1280: entry = temp_entry; ! 1281: while ((entry != vm_map_to_entry(map)) && ! 1282: (entry->vme_start < end)) { ! 1283: vm_map_clip_end(map, entry, end); ! 1284: ! 1285: entry->wired_count--; ! 1286: if (entry->wired_count == 0) ! 1287: vm_fault_unwire(map, entry); ! 1288: ! 1289: entry = entry->vme_next; ! 1290: } ! 1291: } ! 1292: ! 1293: else { ! 1294: /* ! 1295: * Wiring. We must do this in two passes: ! 1296: * ! 1297: * 1. Holding the write lock, we increment the ! 1298: * wiring count. For any area that is not already ! 1299: * wired, we create any shadow objects that need ! 1300: * to be created. ! 1301: * ! 1302: * 2. We downgrade to a read lock, and call ! 1303: * vm_fault_wire to fault in the pages for any ! 1304: * newly wired area (wired_count is 1). ! 1305: * ! 1306: * Downgrading to a read lock for vm_fault_wire avoids ! 1307: * a possible deadlock with another thread that may have ! 1308: * faulted on one of the pages to be wired (it would mark ! 1309: * the page busy, blocking us, then in turn block on the ! 1310: * map lock that we hold). Because of problems in the ! 1311: * recursive lock package, we cannot upgrade to a write ! 1312: * lock in vm_map_lookup. Thus, any actions that require ! 1313: * the write lock must be done beforehand. Because we ! 1314: * keep the read lock on the map, the copy-on-write status ! 1315: * of the entries we modify here cannot change. ! 1316: */ ! 1317: ! 1318: /* ! 1319: * Pass 1. ! 1320: */ ! 1321: entry = temp_entry; ! 1322: while ((entry != vm_map_to_entry(map)) && ! 1323: (entry->vme_start < end)) { ! 1324: vm_map_clip_end(map, entry, end); ! 1325: ! 1326: entry->wired_count++; ! 1327: if (entry->wired_count == 1) { ! 1328: ! 1329: /* ! 1330: * Perform actions of vm_map_lookup that need ! 1331: * the write lock on the map: create a shadow ! 1332: * object for a copy-on-write region, or an ! 1333: * object for a zero-fill region. ! 1334: * ! 1335: * We don't have to do this for entries that ! 1336: * point to sharing maps, because we won't hold ! 1337: * the lock on the sharing map. ! 1338: */ ! 1339: if (!entry->is_a_map) { ! 1340: if (entry->needs_copy && ! 1341: ((entry->protection & VM_PROT_WRITE) != 0)) { ! 1342: ! 1343: vm_object_shadow(&entry->object.vm_object, ! 1344: &entry->offset, ! 1345: (vm_size_t)(entry->vme_end ! 1346: - entry->vme_start)); ! 1347: entry->needs_copy = FALSE; ! 1348: } ! 1349: else if (entry->object.vm_object == VM_OBJECT_NULL) { ! 1350: entry->object.vm_object = ! 1351: vm_object_allocate( ! 1352: (vm_size_t)(entry->vme_end ! 1353: - entry->vme_start)); ! 1354: entry->offset = (vm_offset_t)0; ! 1355: } ! 1356: } ! 1357: } ! 1358: ! 1359: entry = entry->vme_next; ! 1360: } ! 1361: ! 1362: /* ! 1363: * Pass 2. ! 1364: */ ! 1365: ! 1366: /* If we are wiring pages in the kernel map ! 1367: * we know that the map will not be modified in a ! 1368: * destructive way. Drivers call us to wire in ! 1369: * pages after they do a vm_map_copy into the ! 1370: * kernel. Enhancing submaps to allow vm_map_copies ! 1371: * is a better long term solution. For now we will ! 1372: * release the lock to prevent deadlock. ! 1373: */ ! 1374: if (map == kernel_map){ ! 1375: map_locked = 0; ! 1376: vm_map_unlock(map); ! 1377: } else { ! 1378: lock_set_recursive(&map->lock); ! 1379: lock_write_to_read(&map->lock); ! 1380: } ! 1381: ! 1382: entry = temp_entry; ! 1383: while ((entry != vm_map_to_entry(map)) && ! 1384: (entry->vme_start < end)) { ! 1385: if (entry->wired_count == 1) { ! 1386: vm_fault_wire(map, entry); ! 1387: } ! 1388: entry = entry->vme_next; ! 1389: } ! 1390: ! 1391: if (map_locked){ ! 1392: lock_clear_recursive(&map->lock); ! 1393: } ! 1394: } ! 1395: ! 1396: if (map_locked){ ! 1397: vm_map_unlock(map); ! 1398: } ! 1399: ! 1400: return(KERN_SUCCESS); ! 1401: } ! 1402: ! 1403: /* ! 1404: * vm_map_entry_unwire: [ internal use only ] ! 1405: * ! 1406: * Make the region specified by this entry pageable. ! 1407: * ! 1408: * The map in question should be locked. ! 1409: * [This is the reason for this routine's existence.] ! 1410: */ ! 1411: void vm_map_entry_unwire(map, entry) ! 1412: vm_map_t map; ! 1413: register vm_map_entry_t entry; ! 1414: { ! 1415: vm_fault_unwire(map, entry); ! 1416: entry->wired_count = 0; ! 1417: } ! 1418: ! 1419: /* ! 1420: * vm_map_entry_delete: [ internal use only ] ! 1421: * ! 1422: * Deallocate the given entry from the target map. ! 1423: */ ! 1424: void vm_map_entry_delete(map, entry) ! 1425: register vm_map_t map; ! 1426: register vm_map_entry_t entry; ! 1427: { ! 1428: if (entry->wired_count != 0) ! 1429: vm_map_entry_unwire(map, entry); ! 1430: ! 1431: vm_map_entry_unlink(map, entry); ! 1432: map->size -= entry->vme_end - entry->vme_start; ! 1433: ! 1434: if (entry->is_a_map || entry->is_sub_map) ! 1435: vm_map_deallocate(entry->object.share_map); ! 1436: else ! 1437: vm_object_deallocate(entry->object.vm_object); ! 1438: ! 1439: vm_map_entry_dispose(map, entry); ! 1440: } ! 1441: ! 1442: /* ! 1443: * vm_map_delete: [ internal use only ] ! 1444: * ! 1445: * Deallocates the given address range from the target ! 1446: * map. ! 1447: * ! 1448: * When called with a sharing map, removes pages from ! 1449: * that region from all physical maps. ! 1450: */ ! 1451: kern_return_t vm_map_delete(map, start, end) ! 1452: register vm_map_t map; ! 1453: vm_offset_t start; ! 1454: register vm_offset_t end; ! 1455: { ! 1456: register vm_map_entry_t entry; ! 1457: vm_map_entry_t first_entry; ! 1458: ! 1459: /* ! 1460: * Find the start of the region, and clip it ! 1461: */ ! 1462: ! 1463: if (!vm_map_lookup_entry(map, start, &first_entry)) ! 1464: entry = first_entry->vme_next; ! 1465: else { ! 1466: entry = first_entry; ! 1467: vm_map_clip_start(map, entry, start); ! 1468: ! 1469: /* ! 1470: * Fix the lookup hint now, rather than each ! 1471: * time though the loop. ! 1472: */ ! 1473: ! 1474: SAVE_HINT(map, entry->vme_prev); ! 1475: } ! 1476: ! 1477: /* ! 1478: * Save the free space hint ! 1479: */ ! 1480: ! 1481: if (map->first_free->vme_start >= start) ! 1482: map->first_free = entry->vme_prev; ! 1483: ! 1484: /* ! 1485: * Step through all entries in this region ! 1486: */ ! 1487: ! 1488: while ((entry != vm_map_to_entry(map)) && ! 1489: (entry->vme_start < end)) { ! 1490: vm_map_entry_t next; ! 1491: register vm_offset_t s, e; ! 1492: register vm_object_t object; ! 1493: extern vm_object_t kernel_object; ! 1494: ! 1495: vm_map_clip_end(map, entry, end); ! 1496: ! 1497: next = entry->vme_next; ! 1498: s = entry->vme_start; ! 1499: e = entry->vme_end; ! 1500: ! 1501: /* ! 1502: * Unwire before removing addresses from the pmap; ! 1503: * otherwise, unwiring will put the entries back in ! 1504: * the pmap. ! 1505: */ ! 1506: ! 1507: object = entry->object.vm_object; ! 1508: if (entry->wired_count != 0) ! 1509: vm_map_entry_unwire(map, entry); ! 1510: ! 1511: if (object == kernel_object) ! 1512: vm_object_page_remove(object, entry->offset, ! 1513: entry->offset + (e - s)); ! 1514: ! 1515: /* ! 1516: * If this is a sharing map, we must remove ! 1517: * *all* references to this data, since we can't ! 1518: * find all of the physical maps which are sharing ! 1519: * it. ! 1520: */ ! 1521: ! 1522: if (!map->is_main_map) ! 1523: vm_object_pmap_remove(object, ! 1524: entry->offset, ! 1525: entry->offset + (e - s)); ! 1526: ! 1527: pmap_remove(map->pmap, s, e); ! 1528: ! 1529: /* ! 1530: * Delete the entry (which may delete the object) ! 1531: * only after removing all pmap entries pointing ! 1532: * to its pages. (Otherwise, its page frames may ! 1533: * be reallocated, and any modify bits will be ! 1534: * set in the wrong object!) ! 1535: */ ! 1536: ! 1537: vm_map_entry_delete(map, entry); ! 1538: entry = next; ! 1539: } ! 1540: return(KERN_SUCCESS); ! 1541: } ! 1542: ! 1543: /* ! 1544: * vm_map_remove: ! 1545: * ! 1546: * Remove the given address range from the target map. ! 1547: * This is the exported form of vm_map_delete. ! 1548: */ ! 1549: kern_return_t vm_map_remove(map, start, end) ! 1550: register vm_map_t map; ! 1551: register vm_offset_t start; ! 1552: register vm_offset_t end; ! 1553: { ! 1554: register kern_return_t result; ! 1555: ! 1556: vm_map_lock(map); ! 1557: VM_MAP_RANGE_CHECK(map, start, end); ! 1558: result = vm_map_delete(map, start, end); ! 1559: vm_map_unlock(map); ! 1560: ! 1561: return(result); ! 1562: } ! 1563: ! 1564: kern_return_t vm_map_reallocate(map, start, end) ! 1565: register vm_map_t map; ! 1566: register vm_offset_t start; ! 1567: register vm_offset_t end; ! 1568: { ! 1569: register vm_map_entry_t entry; ! 1570: vm_map_entry_t first_entry; ! 1571: ! 1572: vm_map_lock(map); ! 1573: VM_MAP_RANGE_CHECK(map, start, end); ! 1574: ! 1575: /* ! 1576: * Find the start of the region, and clip it ! 1577: */ ! 1578: ! 1579: if (!vm_map_lookup_entry(map, start, &first_entry)) ! 1580: entry = first_entry->vme_next; ! 1581: else { ! 1582: entry = first_entry; ! 1583: vm_map_clip_start(map, entry, start); ! 1584: ! 1585: /* ! 1586: * Fix the lookup hint now, rather than each ! 1587: * time though the loop. ! 1588: */ ! 1589: ! 1590: SAVE_HINT(map, entry->vme_prev); ! 1591: } ! 1592: ! 1593: /* ! 1594: * Step through all entries in this region ! 1595: */ ! 1596: ! 1597: while ((entry != vm_map_to_entry(map)) && ! 1598: (entry->vme_start < end)) { ! 1599: vm_map_entry_t next; ! 1600: register vm_offset_t s, e; ! 1601: register vm_object_t object; ! 1602: extern vm_object_t kernel_object; ! 1603: ! 1604: vm_map_clip_end(map, entry, end); ! 1605: ! 1606: next = entry->vme_next; ! 1607: s = entry->vme_start; ! 1608: e = entry->vme_end; ! 1609: ! 1610: /* ! 1611: * Unwire before removing addresses from the pmap; ! 1612: * otherwise, unwiring will put the entries back in ! 1613: * the pmap. ! 1614: */ ! 1615: ! 1616: object = entry->object.vm_object; ! 1617: if (entry->wired_count != 0) ! 1618: vm_map_entry_unwire(map, entry); ! 1619: ! 1620: if (object == kernel_object) ! 1621: vm_object_page_remove(object, entry->offset, ! 1622: entry->offset + (e - s)); ! 1623: ! 1624: /* ! 1625: * If this is a sharing map, we must remove ! 1626: * *all* references to this data, since we can't ! 1627: * find all of the physical maps which are sharing ! 1628: * it. ! 1629: */ ! 1630: ! 1631: if (!map->is_main_map) ! 1632: vm_object_pmap_remove(object, ! 1633: entry->offset, ! 1634: entry->offset + (e - s)); ! 1635: ! 1636: pmap_remove(map->pmap, s, e); ! 1637: ! 1638: /* ! 1639: * Release the reference to the underlying object ! 1640: * only after removing all pmap entries pointing ! 1641: * to its pages. (Otherwise, its page frames may ! 1642: * be reallocated, and any modify bits will be ! 1643: * set in the wrong object!) ! 1644: */ ! 1645: ! 1646: if (entry->is_a_map || entry->is_sub_map) ! 1647: vm_map_deallocate(entry->object.share_map); ! 1648: else ! 1649: vm_object_deallocate(entry->object.vm_object); ! 1650: ! 1651: entry->is_a_map = FALSE; ! 1652: entry->is_sub_map = FALSE; ! 1653: entry->object.vm_object = VM_OBJECT_NULL; ! 1654: entry->offset = 0; ! 1655: ! 1656: entry->copy_on_write = FALSE; ! 1657: entry->needs_copy = FALSE; ! 1658: ! 1659: if (map->is_main_map) { ! 1660: entry->protection = ! 1661: (entry->max_protection & VM_PROT_DEFAULT); ! 1662: entry->wired_count = 0; ! 1663: } ! 1664: ! 1665: entry = next; ! 1666: } ! 1667: ! 1668: vm_map_unlock(map); ! 1669: ! 1670: return(KERN_SUCCESS); ! 1671: } ! 1672: ! 1673: /* ! 1674: * vm_map_check_protection: ! 1675: * ! 1676: * Assert that the target map allows the specified ! 1677: * privilege on the entire address region given. ! 1678: * The entire region must be allocated. ! 1679: */ ! 1680: boolean_t vm_map_check_protection(map, start, end, protection) ! 1681: register vm_map_t map; ! 1682: register vm_offset_t start; ! 1683: register vm_offset_t end; ! 1684: register vm_prot_t protection; ! 1685: { ! 1686: register vm_map_entry_t entry; ! 1687: vm_map_entry_t tmp_entry; ! 1688: ! 1689: if (!vm_map_lookup_entry(map, start, &tmp_entry)) { ! 1690: return(FALSE); ! 1691: } ! 1692: ! 1693: entry = tmp_entry; ! 1694: ! 1695: while (start < end) { ! 1696: if (entry == vm_map_to_entry(map)) { ! 1697: return(FALSE); ! 1698: } ! 1699: ! 1700: /* ! 1701: * No holes allowed! ! 1702: */ ! 1703: ! 1704: if (start < entry->vme_start) { ! 1705: return(FALSE); ! 1706: } ! 1707: ! 1708: /* ! 1709: * Check protection associated with entry. ! 1710: */ ! 1711: ! 1712: if ((entry->protection & protection) != protection) { ! 1713: return(FALSE); ! 1714: } ! 1715: ! 1716: /* go to next entry */ ! 1717: ! 1718: start = entry->vme_end; ! 1719: entry = entry->vme_next; ! 1720: } ! 1721: return(TRUE); ! 1722: } ! 1723: ! 1724: /* ! 1725: * vm_map_copy_entry: ! 1726: * ! 1727: * Copies the contents of the source entry to the destination ! 1728: * entry. The entries *must* be aligned properly. ! 1729: */ ! 1730: void vm_map_copy_entry(src_map, dst_map, src_entry, dst_entry) ! 1731: vm_map_t src_map, dst_map; ! 1732: register vm_map_entry_t src_entry, dst_entry; ! 1733: { ! 1734: vm_object_t temp_object; ! 1735: ! 1736: if (src_entry->is_sub_map || dst_entry->is_sub_map) ! 1737: return; ! 1738: ! 1739: /* ! 1740: * If our destination map was wired down, ! 1741: * unwire it now. ! 1742: */ ! 1743: ! 1744: if (dst_entry->wired_count != 0) ! 1745: vm_map_entry_unwire(dst_map, dst_entry); ! 1746: ! 1747: /* ! 1748: * If we're dealing with a sharing map, we ! 1749: * must remove the destination pages from ! 1750: * all maps (since we cannot know which maps ! 1751: * this sharing map belongs in). ! 1752: */ ! 1753: ! 1754: if (!dst_map->is_main_map) ! 1755: vm_object_pmap_remove(dst_entry->object.vm_object, ! 1756: dst_entry->offset, ! 1757: dst_entry->offset + ! 1758: (dst_entry->vme_end - dst_entry->vme_start)); ! 1759: ! 1760: pmap_remove(dst_map->pmap, dst_entry->vme_start, dst_entry->vme_end); ! 1761: ! 1762: if (src_entry->wired_count == 0) { ! 1763: ! 1764: boolean_t src_needs_copy; ! 1765: ! 1766: /* ! 1767: * If the source entry is marked needs_copy, ! 1768: * it is already write-protected. ! 1769: */ ! 1770: if (!src_entry->needs_copy) { ! 1771: ! 1772: boolean_t su; ! 1773: ! 1774: /* ! 1775: * If the source entry has only one mapping, ! 1776: * we can just protect the virtual address ! 1777: * range. ! 1778: */ ! 1779: if (!(su = src_map->is_main_map)) { ! 1780: simple_lock(&src_map->ref_lock); ! 1781: su = (src_map->ref_count == 1); ! 1782: simple_unlock(&src_map->ref_lock); ! 1783: } ! 1784: ! 1785: if (su) { ! 1786: pmap_protect(src_map->pmap, ! 1787: src_entry->vme_start, ! 1788: src_entry->vme_end, ! 1789: src_entry->protection & ~VM_PROT_WRITE); ! 1790: } ! 1791: else { ! 1792: vm_object_pmap_copy(src_entry->object.vm_object, ! 1793: src_entry->offset, ! 1794: src_entry->offset + (src_entry->vme_end ! 1795: -src_entry->vme_start)); ! 1796: } ! 1797: } ! 1798: ! 1799: /* ! 1800: * Make a copy of the object. ! 1801: */ ! 1802: temp_object = dst_entry->object.vm_object; ! 1803: vm_object_copy(src_entry->object.vm_object, ! 1804: src_entry->offset, ! 1805: (vm_size_t)(src_entry->vme_end - ! 1806: src_entry->vme_start), ! 1807: &dst_entry->object.vm_object, ! 1808: &dst_entry->offset, ! 1809: &src_needs_copy); ! 1810: /* ! 1811: * If we didn't get a copy-object now, mark the ! 1812: * source map entry so that a shadow will be created ! 1813: * to hold its changed pages. ! 1814: */ ! 1815: if (src_needs_copy) ! 1816: src_entry->needs_copy = TRUE; ! 1817: ! 1818: /* ! 1819: * The destination always needs to have a shadow ! 1820: * created. ! 1821: */ ! 1822: dst_entry->needs_copy = TRUE; ! 1823: ! 1824: /* ! 1825: * Mark the entries copy-on-write, so that write-enabling ! 1826: * the entry won't make copy-on-write pages writable. ! 1827: */ ! 1828: src_entry->copy_on_write = TRUE; ! 1829: dst_entry->copy_on_write = TRUE; ! 1830: /* XXX */ ! 1831: if (src_entry->protection & VM_PROT_EXECUTE) ! 1832: dst_entry->protection |= (VM_PROT_EXECUTE & dst_entry->max_protection); ! 1833: /* XXX */ ! 1834: /* ! 1835: * Get rid of the old object. ! 1836: */ ! 1837: vm_object_deallocate(temp_object); ! 1838: ! 1839: pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->vme_start, ! 1840: dst_entry->vme_end - dst_entry->vme_start, src_entry->vme_start); ! 1841: } ! 1842: else { ! 1843: /* ! 1844: * Of course, wired down pages can't be set copy-on-write. ! 1845: * Cause wired pages to be copied into the new ! 1846: * map by simulating faults (the new pages are ! 1847: * pageable) ! 1848: */ ! 1849: vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry); ! 1850: } ! 1851: } ! 1852: ! 1853: /* ! 1854: * vm_map_copy: ! 1855: * ! 1856: * Perform a virtual memory copy from the source ! 1857: * address map/range to the destination map/range. ! 1858: * ! 1859: * If src_destroy or dst_alloc is requested, ! 1860: * the source and destination regions should be ! 1861: * disjoint, not only in the top-level map, but ! 1862: * in the sharing maps as well. [The best way ! 1863: * to guarantee this is to use a new intermediate ! 1864: * map to make copies. This also reduces map ! 1865: * fragmentation.] ! 1866: */ ! 1867: kern_return_t vm_map_copy(dst_map, src_map, ! 1868: dst_addr, len, src_addr, ! 1869: dst_alloc, src_destroy) ! 1870: vm_map_t dst_map; ! 1871: vm_map_t src_map; ! 1872: vm_offset_t dst_addr; ! 1873: vm_size_t len; ! 1874: vm_offset_t src_addr; ! 1875: boolean_t dst_alloc; ! 1876: boolean_t src_destroy; ! 1877: { ! 1878: register ! 1879: vm_map_entry_t src_entry; ! 1880: register ! 1881: vm_map_entry_t dst_entry; ! 1882: vm_map_entry_t tmp_entry; ! 1883: vm_offset_t src_start; ! 1884: vm_offset_t src_end; ! 1885: vm_offset_t dst_start; ! 1886: vm_offset_t dst_end; ! 1887: vm_offset_t src_clip; ! 1888: vm_offset_t dst_clip; ! 1889: kern_return_t result; ! 1890: boolean_t old_src_destroy; ! 1891: ! 1892: /* ! 1893: * XXX While we figure out why src_destroy screws up, ! 1894: * we'll do it by explicitly vm_map_delete'ing at the end. ! 1895: */ ! 1896: ! 1897: old_src_destroy = src_destroy; ! 1898: src_destroy = FALSE; ! 1899: ! 1900: /* ! 1901: * Compute start and end of region in both maps ! 1902: */ ! 1903: ! 1904: src_start = src_addr; ! 1905: src_end = src_start + len; ! 1906: dst_start = dst_addr; ! 1907: dst_end = dst_start + len; ! 1908: ! 1909: /* ! 1910: * Check that the region can exist in both source ! 1911: * and destination. ! 1912: */ ! 1913: ! 1914: if ((dst_end < dst_start) || (src_end < src_start)) ! 1915: return(KERN_NO_SPACE); ! 1916: ! 1917: /* ! 1918: * Lock the maps in question -- we avoid deadlock ! 1919: * by ordering lock acquisition by map value ! 1920: */ ! 1921: ! 1922: if (src_map == dst_map) { ! 1923: vm_map_lock(src_map); ! 1924: } ! 1925: else if ((int) src_map < (int) dst_map) { ! 1926: vm_map_lock(src_map); ! 1927: vm_map_lock(dst_map); ! 1928: } else { ! 1929: vm_map_lock(dst_map); ! 1930: vm_map_lock(src_map); ! 1931: } ! 1932: ! 1933: result = KERN_SUCCESS; ! 1934: ! 1935: /* ! 1936: * Check protections... source must be completely readable and ! 1937: * destination must be completely writable. [Note that if we're ! 1938: * allocating the destination region, we don't have to worry ! 1939: * about protection, but instead about whether the region ! 1940: * exists.] ! 1941: */ ! 1942: ! 1943: if (src_map->is_main_map && dst_map->is_main_map) { ! 1944: if (!vm_map_check_protection(src_map, src_start, src_end, ! 1945: VM_PROT_READ)) { ! 1946: result = KERN_PROTECTION_FAILURE; ! 1947: goto Return; ! 1948: } ! 1949: ! 1950: if (dst_alloc) { ! 1951: /* XXX Consider making this a vm_map_find instead */ ! 1952: if ((result = vm_map_insert(dst_map, VM_OBJECT_NULL, ! 1953: (vm_offset_t) 0, dst_start, dst_end)) != KERN_SUCCESS) ! 1954: goto Return; ! 1955: } ! 1956: else if (!vm_map_check_protection(dst_map, dst_start, dst_end, ! 1957: VM_PROT_WRITE)) { ! 1958: result = KERN_PROTECTION_FAILURE; ! 1959: goto Return; ! 1960: } ! 1961: } ! 1962: ! 1963: /* ! 1964: * Find the start entries and clip. ! 1965: * ! 1966: * Note that checking protection asserts that the ! 1967: * lookup cannot fail. ! 1968: * ! 1969: * Also note that we wait to do the second lookup ! 1970: * until we have done the first clip, as the clip ! 1971: * may affect which entry we get! ! 1972: */ ! 1973: ! 1974: (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); ! 1975: src_entry = tmp_entry; ! 1976: vm_map_clip_start(src_map, src_entry, src_start); ! 1977: ! 1978: (void) vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry); ! 1979: dst_entry = tmp_entry; ! 1980: vm_map_clip_start(dst_map, dst_entry, dst_start); ! 1981: ! 1982: /* ! 1983: * If both source and destination entries are the same, ! 1984: * retry the first lookup, as it may have changed. ! 1985: */ ! 1986: ! 1987: if (src_entry == dst_entry) { ! 1988: (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); ! 1989: src_entry = tmp_entry; ! 1990: } ! 1991: ! 1992: /* ! 1993: * If source and destination entries are still the same, ! 1994: * a null copy is being performed. ! 1995: */ ! 1996: ! 1997: if (src_entry == dst_entry) ! 1998: goto Return; ! 1999: ! 2000: /* ! 2001: * Go through entries until we get to the end of the ! 2002: * region. ! 2003: */ ! 2004: ! 2005: while (src_start < src_end) { ! 2006: /* ! 2007: * Clip the entries to the endpoint of the entire region. ! 2008: */ ! 2009: ! 2010: vm_map_clip_end(src_map, src_entry, src_end); ! 2011: vm_map_clip_end(dst_map, dst_entry, dst_end); ! 2012: ! 2013: /* ! 2014: * Clip each entry to the endpoint of the other entry. ! 2015: */ ! 2016: ! 2017: src_clip = src_entry->vme_start + (dst_entry->vme_end - dst_entry->vme_start); ! 2018: vm_map_clip_end(src_map, src_entry, src_clip); ! 2019: ! 2020: dst_clip = dst_entry->vme_start + (src_entry->vme_end - src_entry->vme_start); ! 2021: vm_map_clip_end(dst_map, dst_entry, dst_clip); ! 2022: ! 2023: /* ! 2024: * Both entries now match in size and relative endpoints. ! 2025: * ! 2026: * If both entries refer to a VM object, we can ! 2027: * deal with them now. ! 2028: */ ! 2029: ! 2030: if (!src_entry->is_a_map && !dst_entry->is_a_map) { ! 2031: vm_map_copy_entry(src_map, dst_map, src_entry, ! 2032: dst_entry); ! 2033: } ! 2034: else { ! 2035: register vm_map_t new_dst_map; ! 2036: vm_offset_t new_dst_start; ! 2037: vm_size_t new_size; ! 2038: vm_map_t new_src_map; ! 2039: vm_offset_t new_src_start; ! 2040: ! 2041: /* ! 2042: * We have to follow at least one sharing map. ! 2043: */ ! 2044: ! 2045: new_size = (dst_entry->vme_end - dst_entry->vme_start); ! 2046: ! 2047: if (src_entry->is_a_map) { ! 2048: new_src_map = src_entry->object.share_map; ! 2049: new_src_start = src_entry->offset; ! 2050: } ! 2051: else { ! 2052: new_src_map = src_map; ! 2053: new_src_start = src_entry->vme_start; ! 2054: lock_set_recursive(&src_map->lock); ! 2055: } ! 2056: ! 2057: if (dst_entry->is_a_map) { ! 2058: vm_offset_t new_dst_end; ! 2059: ! 2060: new_dst_map = dst_entry->object.share_map; ! 2061: new_dst_start = dst_entry->offset; ! 2062: ! 2063: /* ! 2064: * Since the destination sharing entries ! 2065: * will be merely deallocated, we can ! 2066: * do that now, and replace the region ! 2067: * with a null object. [This prevents ! 2068: * splitting the source map to match ! 2069: * the form of the destination map.] ! 2070: * Note that we can only do so if the ! 2071: * source and destination do not overlap. ! 2072: */ ! 2073: ! 2074: new_dst_end = new_dst_start + new_size; ! 2075: ! 2076: if (new_dst_map != new_src_map) { ! 2077: vm_map_lock(new_dst_map); ! 2078: (void) vm_map_delete(new_dst_map, ! 2079: new_dst_start, ! 2080: new_dst_end); ! 2081: (void) vm_map_insert(new_dst_map, ! 2082: VM_OBJECT_NULL, ! 2083: (vm_offset_t) 0, ! 2084: new_dst_start, ! 2085: new_dst_end); ! 2086: vm_map_unlock(new_dst_map); ! 2087: } ! 2088: } ! 2089: else { ! 2090: new_dst_map = dst_map; ! 2091: new_dst_start = dst_entry->vme_start; ! 2092: lock_set_recursive(&dst_map->lock); ! 2093: } ! 2094: ! 2095: /* ! 2096: * Recursively copy the sharing map. ! 2097: */ ! 2098: ! 2099: (void) vm_map_copy(new_dst_map, new_src_map, ! 2100: new_dst_start, new_size, new_src_start, ! 2101: FALSE, FALSE); ! 2102: ! 2103: if (dst_map == new_dst_map) ! 2104: lock_clear_recursive(&dst_map->lock); ! 2105: if (src_map == new_src_map) ! 2106: lock_clear_recursive(&src_map->lock); ! 2107: } ! 2108: ! 2109: /* ! 2110: * Update variables for next pass through the loop. ! 2111: */ ! 2112: ! 2113: src_start = src_entry->vme_end; ! 2114: src_entry = src_entry->vme_next; ! 2115: dst_start = dst_entry->vme_end; ! 2116: dst_entry = dst_entry->vme_next; ! 2117: ! 2118: /* ! 2119: * If the source is to be destroyed, here is the ! 2120: * place to do it. ! 2121: */ ! 2122: ! 2123: if (src_destroy && src_map->is_main_map && ! 2124: dst_map->is_main_map) ! 2125: vm_map_entry_delete(src_map, src_entry->vme_prev); ! 2126: } ! 2127: ! 2128: /* ! 2129: * Update the physical maps as appropriate ! 2130: */ ! 2131: ! 2132: if (src_map->is_main_map && dst_map->is_main_map) { ! 2133: if (src_destroy) ! 2134: pmap_remove(src_map->pmap, src_addr, src_addr + len); ! 2135: } ! 2136: ! 2137: /* ! 2138: * Unlock the maps ! 2139: */ ! 2140: ! 2141: Return: ; ! 2142: ! 2143: if (old_src_destroy) ! 2144: vm_map_delete(src_map, src_addr, src_addr + len); ! 2145: ! 2146: vm_map_unlock(src_map); ! 2147: if (src_map != dst_map) ! 2148: vm_map_unlock(dst_map); ! 2149: ! 2150: return(result); ! 2151: } ! 2152: ! 2153: /* ! 2154: * vm_map_fork: ! 2155: * ! 2156: * Create and return a new map based on the old ! 2157: * map, according to the inheritance values on the ! 2158: * regions in that map. ! 2159: * ! 2160: * The source map must not be locked. ! 2161: */ ! 2162: vm_map_t vm_map_fork(old_map) ! 2163: vm_map_t old_map; ! 2164: { ! 2165: vm_map_t new_map; ! 2166: vm_map_entry_t old_entry; ! 2167: vm_map_entry_t new_entry; ! 2168: pmap_t new_pmap; ! 2169: ! 2170: vm_map_lock(old_map); ! 2171: ! 2172: new_pmap = pmap_create((vm_size_t) 0); ! 2173: new_map = vm_map_create(new_pmap, ! 2174: old_map->min_offset, ! 2175: old_map->max_offset, ! 2176: old_map->hdr.entries_pageable); ! 2177: ! 2178: old_entry = vm_map_first_entry(old_map); ! 2179: ! 2180: while (old_entry != vm_map_to_entry(old_map)) { ! 2181: if (old_entry->is_sub_map) ! 2182: panic("vm_map_fork: encountered a submap"); ! 2183: ! 2184: switch (old_entry->inheritance) { ! 2185: case VM_INHERIT_NONE: ! 2186: break; ! 2187: ! 2188: case VM_INHERIT_SHARE: ! 2189: /* ! 2190: * If we don't already have a sharing map: ! 2191: */ ! 2192: ! 2193: if (!old_entry->is_a_map) { ! 2194: vm_map_t new_share_map; ! 2195: vm_map_entry_t new_share_entry; ! 2196: ! 2197: /* ! 2198: * Create a new sharing map ! 2199: */ ! 2200: ! 2201: new_share_map = vm_map_create(PMAP_NULL, ! 2202: old_entry->vme_start, ! 2203: old_entry->vme_end, ! 2204: TRUE); ! 2205: new_share_map->is_main_map = FALSE; ! 2206: ! 2207: /* ! 2208: * Create the only sharing entry from the ! 2209: * old task map entry. ! 2210: */ ! 2211: ! 2212: new_share_entry = ! 2213: vm_map_entry_create(new_share_map); ! 2214: *new_share_entry = *old_entry; ! 2215: ! 2216: /* ! 2217: * Insert the entry into the new sharing ! 2218: * map ! 2219: */ ! 2220: ! 2221: vm_map_entry_link(new_share_map, ! 2222: vm_map_last_entry(new_share_map), ! 2223: new_share_entry); ! 2224: ! 2225: /* ! 2226: * Fix up the task map entry to refer ! 2227: * to the sharing map now. ! 2228: */ ! 2229: ! 2230: old_entry->is_a_map = TRUE; ! 2231: old_entry->object.share_map = new_share_map; ! 2232: old_entry->offset = old_entry->vme_start; ! 2233: } ! 2234: ! 2235: /* ! 2236: * Clone the entry, referencing the sharing map. ! 2237: */ ! 2238: ! 2239: new_entry = vm_map_entry_create(new_map); ! 2240: *new_entry = *old_entry; ! 2241: vm_map_reference(new_entry->object.share_map); ! 2242: ! 2243: /* ! 2244: * Insert the entry into the new map -- we ! 2245: * know we're inserting at the end of the new ! 2246: * map. ! 2247: */ ! 2248: ! 2249: vm_map_entry_link(new_map, ! 2250: vm_map_last_entry(new_map), ! 2251: new_entry); ! 2252: ! 2253: /* ! 2254: * Update the physical map ! 2255: */ ! 2256: ! 2257: pmap_copy(new_map->pmap, old_map->pmap, ! 2258: new_entry->vme_start, ! 2259: (old_entry->vme_end - old_entry->vme_start), ! 2260: old_entry->vme_start); ! 2261: break; ! 2262: ! 2263: case VM_INHERIT_COPY: ! 2264: /* ! 2265: * Clone the entry and link into the map. ! 2266: */ ! 2267: ! 2268: new_entry = vm_map_entry_create(new_map); ! 2269: *new_entry = *old_entry; ! 2270: new_entry->wired_count = 0; ! 2271: new_entry->object.vm_object = VM_OBJECT_NULL; ! 2272: new_entry->is_a_map = FALSE; ! 2273: vm_map_entry_link(new_map, ! 2274: vm_map_last_entry(new_map), ! 2275: new_entry); ! 2276: if (old_entry->is_a_map) { ! 2277: kern_return_t check; ! 2278: ! 2279: check = vm_map_copy(new_map, ! 2280: old_entry->object.share_map, ! 2281: new_entry->vme_start, ! 2282: (vm_size_t) ! 2283: (new_entry->vme_end - ! 2284: new_entry->vme_start), ! 2285: old_entry->offset, ! 2286: FALSE, FALSE); ! 2287: if (check != KERN_SUCCESS) ! 2288: kprintf("vm_map_fork: copy in share_map region failed\n"); ! 2289: } ! 2290: else { ! 2291: vm_map_copy_entry(old_map, new_map, old_entry, ! 2292: new_entry); ! 2293: } ! 2294: break; ! 2295: } ! 2296: old_entry = old_entry->vme_next; ! 2297: } ! 2298: ! 2299: new_map->size = old_map->size; ! 2300: vm_map_unlock(old_map); ! 2301: ! 2302: return(new_map); ! 2303: } ! 2304: ! 2305: /* ! 2306: * vm_map_lookup: ! 2307: * ! 2308: * Finds the VM object, offset, and ! 2309: * protection for a given virtual address in the ! 2310: * specified map, assuming a page fault of the ! 2311: * type specified. ! 2312: * ! 2313: #if USE_VERSIONS ! 2314: * Returns the (object, offset, protection) for ! 2315: * this address, whether it is wired down, and whether ! 2316: * this map has the only reference to the data in question. ! 2317: * In order to later verify this lookup, a "version" ! 2318: * is returned. ! 2319: * ! 2320: * The map should not be locked; it will not be ! 2321: * locked on exit. In order to guarantee the ! 2322: * existence of the returned object, it is returned ! 2323: * locked. ! 2324: #else USE_VERSIONS ! 2325: * Leaves the map in question locked for read; return ! 2326: * values are guaranteed until a vm_map_lookup_done ! 2327: * call is performed. Note that the map argument ! 2328: * is in/out; the returned map must be used in ! 2329: * the call to vm_map_lookup_done. ! 2330: * ! 2331: * A handle (out_entry) is returned for use in ! 2332: * vm_map_lookup_done, to make that fast. ! 2333: #endif USE_VERSIONS ! 2334: * ! 2335: * If a lookup is requested with "write protection" ! 2336: * specified, the map may be changed to perform virtual ! 2337: * copying operations, although the data referenced will ! 2338: * remain the same. ! 2339: */ ! 2340: #if USE_VERSIONS ! 2341: kern_return_t vm_map_lookup(var_map, vaddr, fault_type, out_version, ! 2342: object, offset, out_prot, wired, single_use) ! 2343: #else USE_VERSIONS ! 2344: kern_return_t vm_map_lookup(var_map, vaddr, fault_type, out_entry, ! 2345: object, offset, out_prot, wired, single_use) ! 2346: #endif USE_VERSIONS ! 2347: vm_map_t *var_map; /* IN/OUT */ ! 2348: register vm_offset_t vaddr; ! 2349: register vm_prot_t fault_type; ! 2350: ! 2351: #if USE_VERSIONS ! 2352: vm_map_version_t *out_version; /* OUT */ ! 2353: #else USE_VERSIONS ! 2354: vm_map_entry_t *out_entry; /* OUT */ ! 2355: #endif USE_VERSIONS ! 2356: vm_object_t *object; /* OUT */ ! 2357: vm_offset_t *offset; /* OUT */ ! 2358: vm_prot_t *out_prot; /* OUT */ ! 2359: boolean_t *wired; /* OUT */ ! 2360: boolean_t *single_use; /* OUT */ ! 2361: { ! 2362: vm_map_t share_map; ! 2363: vm_offset_t share_offset; ! 2364: register vm_map_entry_t entry; ! 2365: register vm_map_t map = *var_map; ! 2366: register vm_prot_t prot; ! 2367: register boolean_t su; ! 2368: ! 2369: RetryLookup: ; ! 2370: ! 2371: /* ! 2372: * Lookup the faulting address. ! 2373: */ ! 2374: ! 2375: vm_map_lock_read(map); ! 2376: ! 2377: #define L_RETURN(why) \ ! 2378: { \ ! 2379: vm_map_unlock_read(map); \ ! 2380: return(why); \ ! 2381: } ! 2382: ! 2383: /* ! 2384: * If the map has an interesting hint, try it before calling ! 2385: * full blown lookup routine. ! 2386: */ ! 2387: ! 2388: simple_lock(&map->hint_lock); ! 2389: entry = map->hint; ! 2390: simple_unlock(&map->hint_lock); ! 2391: ! 2392: #if !USE_VERSIONS ! 2393: *out_entry = entry; ! 2394: #endif !USE_VERSIONS ! 2395: ! 2396: if ((entry == vm_map_to_entry(map)) || ! 2397: (vaddr < entry->vme_start) || (vaddr >= entry->vme_end)) { ! 2398: vm_map_entry_t tmp_entry; ! 2399: ! 2400: /* ! 2401: * Entry was either not a valid hint, or the vaddr ! 2402: * was not contained in the entry, so do a full lookup. ! 2403: */ ! 2404: if (!vm_map_lookup_entry(map, vaddr, &tmp_entry)) ! 2405: L_RETURN(KERN_INVALID_ADDRESS); ! 2406: ! 2407: entry = tmp_entry; ! 2408: #if !USE_VERSIONS ! 2409: *out_entry = entry; ! 2410: #endif !USE_VERSIONS ! 2411: } ! 2412: ! 2413: /* ! 2414: * Handle submaps. ! 2415: */ ! 2416: ! 2417: if (entry->is_sub_map) { ! 2418: vm_map_t old_map = map; ! 2419: ! 2420: *var_map = map = entry->object.sub_map; ! 2421: vm_map_unlock_read(old_map); ! 2422: goto RetryLookup; ! 2423: } ! 2424: ! 2425: /* ! 2426: * Check whether this task is allowed to have ! 2427: * this page. ! 2428: */ ! 2429: ! 2430: prot = entry->protection; ! 2431: if ((fault_type & (prot)) != fault_type) ! 2432: L_RETURN(KERN_PROTECTION_FAILURE); ! 2433: ! 2434: /* ! 2435: * If this page is not pageable, we have to get ! 2436: * it for all possible accesses. ! 2437: */ ! 2438: ! 2439: if (*wired = (entry->wired_count != 0)) ! 2440: prot = fault_type = entry->protection; ! 2441: ! 2442: /* ! 2443: * If we don't already have a VM object, track ! 2444: * it down. ! 2445: */ ! 2446: ! 2447: if (su = !entry->is_a_map) { ! 2448: share_map = map; ! 2449: share_offset = vaddr; ! 2450: } ! 2451: else { ! 2452: vm_map_entry_t share_entry; ! 2453: ! 2454: /* ! 2455: * Compute the sharing map, and offset into it. ! 2456: */ ! 2457: ! 2458: share_map = entry->object.share_map; ! 2459: share_offset = (vaddr - entry->vme_start) + entry->offset; ! 2460: ! 2461: /* ! 2462: * Look for the backing store object and offset ! 2463: */ ! 2464: ! 2465: vm_map_lock_read(share_map); ! 2466: ! 2467: if (!vm_map_lookup_entry(share_map, share_offset, ! 2468: &share_entry)) { ! 2469: vm_map_unlock_read(share_map); ! 2470: L_RETURN(KERN_INVALID_ADDRESS); ! 2471: } ! 2472: entry = share_entry; ! 2473: } ! 2474: ! 2475: /* ! 2476: * If the entry was copy-on-write, we either ... ! 2477: */ ! 2478: ! 2479: if (entry->needs_copy) { ! 2480: /* ! 2481: * If we want to write the page, we may as well ! 2482: * handle that now since we've got the sharing ! 2483: * map locked. ! 2484: * ! 2485: * If we don't need to write the page, we just ! 2486: * demote the permissions allowed. ! 2487: */ ! 2488: ! 2489: if (fault_type & VM_PROT_WRITE) { ! 2490: /* ! 2491: * Make a new object, and place it in the ! 2492: * object chain. Note that no new references ! 2493: * have appeared -- one just moved from the ! 2494: * share map to the new object. ! 2495: */ ! 2496: ! 2497: if (lock_read_to_write(&share_map->lock)) { ! 2498: if (share_map != map) ! 2499: vm_map_unlock_read(map); ! 2500: goto RetryLookup; ! 2501: } ! 2502: ! 2503: vm_object_shadow( ! 2504: &entry->object.vm_object, ! 2505: &entry->offset, ! 2506: (vm_size_t) (entry->vme_end - ! 2507: entry->vme_start)); ! 2508: ! 2509: entry->needs_copy = FALSE; ! 2510: ! 2511: lock_write_to_read(&share_map->lock); ! 2512: } ! 2513: else { ! 2514: /* ! 2515: * We're attempting to read a copy-on-write ! 2516: * page -- don't allow writes. ! 2517: */ ! 2518: ! 2519: prot &= (~VM_PROT_WRITE); ! 2520: } ! 2521: } ! 2522: ! 2523: /* ! 2524: * Create an object if necessary. ! 2525: */ ! 2526: if (entry->object.vm_object == VM_OBJECT_NULL) { ! 2527: ! 2528: if (lock_read_to_write(&share_map->lock)) { ! 2529: if (share_map != map) ! 2530: vm_map_unlock_read(map); ! 2531: goto RetryLookup; ! 2532: } ! 2533: ! 2534: entry->object.vm_object = vm_object_allocate( ! 2535: (vm_size_t)(entry->vme_end - ! 2536: entry->vme_start)); ! 2537: entry->offset = 0; ! 2538: lock_write_to_read(&share_map->lock); ! 2539: } ! 2540: ! 2541: /* ! 2542: * Return the object/offset from this entry. If the entry ! 2543: * was copy-on-write or empty, it has been fixed up. ! 2544: */ ! 2545: ! 2546: *offset = (share_offset - entry->vme_start) + entry->offset; ! 2547: *object = entry->object.vm_object; ! 2548: ! 2549: /* ! 2550: * Return whether this is the only map sharing this data. ! 2551: */ ! 2552: ! 2553: if (!su) { ! 2554: simple_lock(&share_map->ref_lock); ! 2555: su = (share_map->ref_count == 1); ! 2556: simple_unlock(&share_map->ref_lock); ! 2557: } ! 2558: ! 2559: *out_prot = prot; ! 2560: *single_use = su; ! 2561: ! 2562: #if USE_VERSIONS ! 2563: /* ! 2564: * Lock the object to prevent it from disappearing ! 2565: */ ! 2566: ! 2567: vm_object_lock(*object); ! 2568: ! 2569: /* ! 2570: * Save the version numbers and unlock the map(s). ! 2571: */ ! 2572: ! 2573: if (share_map != map) { ! 2574: out_version->share_timestamp = share_map->timestamp; ! 2575: vm_map_unlock_read(share_map); ! 2576: } ! 2577: out_version->share_map = share_map; ! 2578: out_version->main_timestamp = map->timestamp; ! 2579: ! 2580: vm_map_unlock_read(map); ! 2581: #endif USE_VERSIONS ! 2582: ! 2583: return(KERN_SUCCESS); ! 2584: ! 2585: #undef L_RETURN ! 2586: } ! 2587: ! 2588: #if USE_VERSIONS ! 2589: /* ! 2590: * vm_map_verify: ! 2591: * ! 2592: * Verifies that the map in question has not changed ! 2593: * since the given version. If successful, the map ! 2594: * will not change until vm_map_verify_done() is called. ! 2595: */ ! 2596: boolean_t vm_map_verify(map, version) ! 2597: register ! 2598: vm_map_t map; ! 2599: register ! 2600: vm_map_version_t *version; /* REF */ ! 2601: { ! 2602: boolean_t result; ! 2603: ! 2604: vm_map_lock_read(map); ! 2605: if (result = (map->timestamp == version->main_timestamp)) { ! 2606: register ! 2607: vm_map_t share_map = version->share_map; ! 2608: ! 2609: if (share_map != map) { ! 2610: vm_map_lock_read(version->share_map); ! 2611: if (!(result = (share_map->timestamp == version->share_timestamp))) { ! 2612: vm_map_unlock_read(share_map); ! 2613: } ! 2614: } ! 2615: } ! 2616: ! 2617: if (!result) ! 2618: vm_map_unlock_read(map); ! 2619: ! 2620: return(result); ! 2621: } ! 2622: ! 2623: /* ! 2624: * vm_map_verify_done: ! 2625: * ! 2626: * Releases locks acquired by a vm_map_verify. ! 2627: */ ! 2628: void vm_map_verify_done(map, version) ! 2629: register vm_map_t map; ! 2630: vm_map_version_t *version; /* REF */ ! 2631: { ! 2632: if (version->share_map != map) ! 2633: vm_map_unlock_read(version->share_map); ! 2634: vm_map_unlock_read(map); ! 2635: } ! 2636: ! 2637: #else USE_VERSIONS ! 2638: ! 2639: /* ! 2640: * vm_map_lookup_done: ! 2641: * ! 2642: * Releases locks acquired by a vm_map_lookup ! 2643: * (according to the handle returned by that lookup). ! 2644: */ ! 2645: ! 2646: void vm_map_lookup_done(map, entry) ! 2647: register vm_map_t map; ! 2648: vm_map_entry_t entry; ! 2649: { ! 2650: /* ! 2651: * If this entry references a map, unlock it first. ! 2652: */ ! 2653: ! 2654: if (entry->is_a_map) ! 2655: vm_map_unlock_read(entry->object.share_map); ! 2656: ! 2657: /* ! 2658: * Unlock the main-level map ! 2659: */ ! 2660: ! 2661: vm_map_unlock_read(map); ! 2662: } ! 2663: #endif USE_VERSIONS ! 2664: ! 2665: /* ! 2666: * Routine: vm_map_machine_attribute ! 2667: * Purpose: ! 2668: * Provide machine-specific attributes to mappings, ! 2669: * such as cachability etc. for machines that provide ! 2670: * them. NUMA architectures and machines with big/strange ! 2671: * caches will use this. ! 2672: * Note: ! 2673: * Responsibilities for locking and checking are handled here, ! 2674: * everything else in the pmap module. If any non-volatile ! 2675: * information must be kept, the pmap module should handle ! 2676: * it itself. [This assumes that attributes do not ! 2677: * need to be inherited, which seems ok to me] ! 2678: */ ! 2679: kern_return_t vm_map_machine_attribute(map, address, size, attribute, value) ! 2680: vm_map_t map; ! 2681: vm_offset_t address; ! 2682: vm_size_t size; ! 2683: vm_machine_attribute_t attribute; ! 2684: vm_machine_attribute_val_t* value; /* IN/OUT */ ! 2685: { ! 2686: kern_return_t ret; ! 2687: ! 2688: if (address < vm_map_min(map) || ! 2689: (address + size) > vm_map_max(map)) ! 2690: return KERN_INVALID_ARGUMENT; ! 2691: ! 2692: vm_map_lock(map); ! 2693: ! 2694: ret = pmap_attribute(map->pmap, address, size, attribute, value); ! 2695: ! 2696: vm_map_unlock(map); ! 2697: ! 2698: return ret; ! 2699: } ! 2700: ! 2701: #if DEBUG ! 2702: /* ! 2703: * vm_map_print: [ debug ] ! 2704: */ ! 2705: #if 1 ! 2706: /* ! 2707: * vm_map_print() is way out of date... ! 2708: */ ! 2709: void vm_map_print(vm_map_t map) ! 2710: { ! 2711: ! 2712: } ! 2713: #else 1 ! 2714: void vm_map_print(map) ! 2715: register vm_map_t map; ! 2716: { ! 2717: register vm_map_entry_t entry; ! 2718: extern int indent; ! 2719: ! 2720: iprintf("%s map 0x%x: pmap=0x%x,ref=%d,nentries=%d,version=%d\n", ! 2721: (map->is_main_map ? "Task" : "Share"), ! 2722: (int) map, (int) (map->pmap), map->ref_count, map->nentries, ! 2723: map->timestamp); ! 2724: indent += 2; ! 2725: for (entry = map->header.next; entry != &map->header; ! 2726: entry = entry->next) { ! 2727: iprintf("map entry 0x%x: start=0x%x, end=0x%x, ", ! 2728: (int) entry, (int) entry->start, (int) entry->end); ! 2729: if (map->is_main_map) { ! 2730: static char *inheritance_name[4] = ! 2731: { "share", "copy", "none", "donate_copy"}; ! 2732: printf("prot=%x/%x/%s, ", ! 2733: entry->protection, ! 2734: entry->max_protection, ! 2735: inheritance_name[entry->inheritance]); ! 2736: if (entry->wired_count != 0) ! 2737: printf("wired, "); ! 2738: } ! 2739: ! 2740: if (entry->is_a_map) { ! 2741: printf("share=0x%x, offset=0x%x\n", ! 2742: (int) entry->object.share_map, ! 2743: (int) entry->offset); ! 2744: if ((entry->prev == &map->header) || (!entry->prev->is_a_map) || ! 2745: (entry->prev->object.share_map != entry->object.share_map)) { ! 2746: indent += 2; ! 2747: vm_map_print(entry->object.share_map); ! 2748: indent -= 2; ! 2749: } ! 2750: ! 2751: } ! 2752: else { ! 2753: printf("object=0x%x, offset=0x%x", ! 2754: (int) entry->object.vm_object, ! 2755: (int) entry->offset); ! 2756: if (entry->copy_on_write) ! 2757: printf(", copy (%s)", entry->needs_copy ? "needed" : "done"); ! 2758: printf("\n"); ! 2759: ! 2760: if ((entry->prev == &map->header) || (entry->prev->is_a_map) || ! 2761: (entry->prev->object.vm_object != entry->object.vm_object)) { ! 2762: indent += 2; ! 2763: vm_object_print(entry->object.vm_object); ! 2764: indent -= 2; ! 2765: } ! 2766: } ! 2767: } ! 2768: indent -= 2; ! 2769: } ! 2770: #endif 1 ! 2771: #endif DEBUG ! 2772: ! 2773: kern_return_t vm_region(map, address, size, ! 2774: protection, max_protection, ! 2775: inheritance, is_shared, ! 2776: object_name, offset_in_object) ! 2777: vm_map_t map; ! 2778: vm_offset_t *address; /* IN/OUT */ ! 2779: vm_size_t *size; /* OUT */ ! 2780: vm_prot_t *protection; /* OUT */ ! 2781: vm_prot_t *max_protection; /* OUT */ ! 2782: vm_inherit_t *inheritance; /* OUT */ ! 2783: boolean_t *is_shared; /* OUT */ ! 2784: port_t *object_name; /* OUT */ ! 2785: vm_offset_t *offset_in_object; /* OUT */ ! 2786: { ! 2787: vm_map_entry_t tmp_entry; ! 2788: register ! 2789: vm_map_entry_t entry; ! 2790: register ! 2791: vm_offset_t tmp_offset; ! 2792: vm_offset_t start, inaddress = *address; ! 2793: ! 2794: if (map == VM_MAP_NULL) ! 2795: return(KERN_INVALID_ARGUMENT); ! 2796: ! 2797: again_after_submap: ! 2798: start = *address; ! 2799: ! 2800: vm_map_lock_read(map); ! 2801: if (!vm_map_lookup_entry(map, start, &tmp_entry)) { ! 2802: if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) { ! 2803: vm_map_unlock_read(map); ! 2804: return(KERN_NO_SPACE); ! 2805: } ! 2806: } else { ! 2807: entry = tmp_entry; ! 2808: } ! 2809: ! 2810: start = entry->vme_start; ! 2811: *protection = entry->protection; ! 2812: *max_protection = entry->max_protection; ! 2813: *inheritance = entry->inheritance; ! 2814: *address = start; ! 2815: *size = (entry->vme_end - start); ! 2816: ! 2817: tmp_offset = entry->offset; ! 2818: #define VM_OBJECT_NAME(object) \ ! 2819: vm_object_name((map == kernel_map) ? object : VM_OBJECT_NULL) ! 2820: ! 2821: if (entry->is_a_map) { ! 2822: register ! 2823: vm_map_t share_map; ! 2824: vm_size_t share_size; ! 2825: ! 2826: share_map = entry->object.share_map; ! 2827: ! 2828: vm_map_lock_read(share_map); ! 2829: (void) vm_map_lookup_entry(share_map, tmp_offset, &tmp_entry); ! 2830: ! 2831: if ((share_size = (tmp_entry->vme_end - tmp_offset)) < *size) ! 2832: *size = share_size; ! 2833: ! 2834: *object_name = VM_OBJECT_NAME(tmp_entry->object.vm_object); ! 2835: *offset_in_object = tmp_entry->offset + ! 2836: (tmp_offset - tmp_entry->vme_start); ! 2837: ! 2838: *is_shared = (share_map->ref_count != 1); ! 2839: vm_map_unlock_read(share_map); ! 2840: } else if (entry->is_sub_map) { ! 2841: vm_map_t sub_map; ! 2842: vm_offset_t oldstart = start; ! 2843: ! 2844: sub_map = entry->object.sub_map; ! 2845: vm_map_reference(sub_map); ! 2846: vm_map_unlock_read(map); ! 2847: ! 2848: vm_map_lock_read(sub_map); ! 2849: ! 2850: if (!vm_map_lookup_entry(sub_map, inaddress, &tmp_entry)) { ! 2851: if ((entry = tmp_entry->vme_next) == ! 2852: vm_map_to_entry(sub_map)) { ! 2853: vm_map_unlock_read(sub_map); ! 2854: vm_map_deallocate(sub_map); ! 2855: inaddress = *address = oldstart + *size; ! 2856: goto again_after_submap; ! 2857: } ! 2858: } ! 2859: else ! 2860: entry = tmp_entry; ! 2861: ! 2862: start = entry->vme_start; ! 2863: *protection = entry->protection; ! 2864: *max_protection = entry->max_protection; ! 2865: *inheritance = entry->inheritance; ! 2866: *address = start; ! 2867: *size = (entry->vme_end - start); ! 2868: ! 2869: *is_shared = sub_map->hdr.entries_pageable; ! 2870: *object_name = VM_OBJECT_NAME(entry->object.vm_object); ! 2871: *offset_in_object = entry->offset; ! 2872: ! 2873: vm_map_unlock_read(sub_map); ! 2874: ! 2875: vm_map_deallocate(sub_map); ! 2876: ! 2877: return(KERN_SUCCESS); ! 2878: } else { ! 2879: *is_shared = FALSE; ! 2880: *object_name = VM_OBJECT_NAME(entry->object.vm_object); ! 2881: *offset_in_object = tmp_offset; ! 2882: } ! 2883: #undef VM_OBJECT_NAME ! 2884: ! 2885: vm_map_unlock_read(map); ! 2886: ! 2887: return(KERN_SUCCESS); ! 2888: } ! 2889: ! 2890: #if MACH_DEBUG ! 2891: #include <kern/host.h> ! 2892: ! 2893: kern_return_t host_vm_region( ! 2894: host_t host, ! 2895: vm_offset_t *address, /* IN/OUT */ ! 2896: vm_size_t *size, /* OUT */ ! 2897: vm_prot_t *protection, /* OUT */ ! 2898: vm_prot_t *max_protection, /* OUT */ ! 2899: vm_inherit_t *inheritance, /* OUT */ ! 2900: boolean_t *is_pageable, /* OUT */ ! 2901: port_t *object_name, /* OUT */ ! 2902: vm_offset_t *offset_in_object /* OUT */ ! 2903: ) ! 2904: { ! 2905: if (host == HOST_NULL) ! 2906: return(KERN_INVALID_ARGUMENT); ! 2907: ! 2908: return vm_region(kernel_map, address, size, ! 2909: protection, max_protection, ! 2910: inheritance, is_pageable, ! 2911: object_name, offset_in_object); ! 2912: } ! 2913: #endif /* MACH_DEBUG */ ! 2914: ! 2915: /* ! 2916: * vm_move: ! 2917: * ! 2918: * Move memory from source to destination map, possibly deallocating ! 2919: * the source map reference to the memory. ! 2920: * ! 2921: * Parameters are as follows: ! 2922: * ! 2923: * src_map Source address map ! 2924: * src_addr Address within source map ! 2925: * dst_map Destination address map ! 2926: * num_bytes Amount of data (in bytes) to copy/move ! 2927: * src_dealloc Should source be removed after copy? ! 2928: * ! 2929: * Assumes the src and dst maps are not already locked. ! 2930: * ! 2931: * If successful, returns destination address in dst_addr. ! 2932: */ ! 2933: kern_return_t vm_move(src_map,src_addr,dst_map,num_bytes,src_dealloc,dst_addr) ! 2934: vm_map_t src_map; ! 2935: register vm_offset_t src_addr; ! 2936: register vm_map_t dst_map; ! 2937: vm_offset_t num_bytes; ! 2938: boolean_t src_dealloc; ! 2939: vm_offset_t *dst_addr; ! 2940: { ! 2941: register vm_offset_t src_start; /* Beginning of region */ ! 2942: register vm_size_t src_size; /* Size of rounded region */ ! 2943: vm_offset_t dst_start; /* destination address */ ! 2944: register kern_return_t result; ! 2945: ! 2946: if (num_bytes == 0) { ! 2947: *dst_addr = 0; ! 2948: return KERN_SUCCESS; ! 2949: } ! 2950: ! 2951: /* ! 2952: * Page-align the source region ! 2953: */ ! 2954: ! 2955: src_start = trunc_page(src_addr); ! 2956: src_size = round_page(src_addr + num_bytes) - src_start; ! 2957: ! 2958: /* ! 2959: * Allocate a place to put the copy ! 2960: */ ! 2961: ! 2962: dst_start = (vm_offset_t) 0; ! 2963: result = vm_allocate(dst_map, &dst_start, src_size, TRUE); ! 2964: if (result == KERN_SUCCESS) { ! 2965: /* ! 2966: * Perform the copy, asking for deallocation if desired ! 2967: */ ! 2968: result = vm_map_copy(dst_map, src_map, dst_start, src_size, ! 2969: src_start, FALSE, src_dealloc); ! 2970: ! 2971: /* ! 2972: * Return the destination address corresponding to ! 2973: * the source address given (rather than the front ! 2974: * of the newly-allocated page). ! 2975: */ ! 2976: ! 2977: if (result == KERN_SUCCESS) ! 2978: *dst_addr = dst_start + (src_addr - src_start); ! 2979: else ! 2980: (void) vm_deallocate(dst_map, dst_start, src_size); ! 2981: } ! 2982: ! 2983: return(result); ! 2984: } ! 2985: ! 2986: pmap_t ! 2987: vm_map_pmap_EXTERNAL( ! 2988: vm_map_t map ! 2989: ) ! 2990: { ! 2991: return (vm_map_pmap(map)); ! 2992: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.