|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: vm/vm_map.c ! 31: * Author: Avadis Tevanian, Jr., Michael Wayne Young ! 32: * Date: 1985 ! 33: * ! 34: * Virtual memory mapping module. ! 35: */ ! 36: ! 37: #include <norma_ipc.h> ! 38: ! 39: #include <mach/kern_return.h> ! 40: #include <mach/port.h> ! 41: #include <mach/vm_attributes.h> ! 42: #include <mach/vm_param.h> ! 43: #include <kern/assert.h> ! 44: #include <kern/zalloc.h> ! 45: #include <vm/vm_fault.h> ! 46: #include <vm/vm_map.h> ! 47: #include <vm/vm_object.h> ! 48: #include <vm/vm_page.h> ! 49: #include <vm/vm_kern.h> ! 50: #include <ipc/ipc_port.h> ! 51: ! 52: /* ! 53: * Macros to copy a vm_map_entry. We must be careful to correctly ! 54: * manage the wired page count. vm_map_entry_copy() creates a new ! 55: * map entry to the same memory - the wired count in the new entry ! 56: * must be set to zero. vm_map_entry_copy_full() creates a new ! 57: * entry that is identical to the old entry. This preserves the ! 58: * wire count; it's used for map splitting and zone changing in ! 59: * vm_map_copyout. ! 60: */ ! 61: #define vm_map_entry_copy(NEW,OLD) \ ! 62: MACRO_BEGIN \ ! 63: *(NEW) = *(OLD); \ ! 64: (NEW)->is_shared = FALSE; \ ! 65: (NEW)->needs_wakeup = FALSE; \ ! 66: (NEW)->in_transition = FALSE; \ ! 67: (NEW)->wired_count = 0; \ ! 68: (NEW)->user_wired_count = 0; \ ! 69: MACRO_END ! 70: ! 71: #define vm_map_entry_copy_full(NEW,OLD) (*(NEW) = *(OLD)) ! 72: ! 73: /* ! 74: * Virtual memory maps provide for the mapping, protection, ! 75: * and sharing of virtual memory objects. In addition, ! 76: * this module provides for an efficient virtual copy of ! 77: * memory from one map to another. ! 78: * ! 79: * Synchronization is required prior to most operations. ! 80: * ! 81: * Maps consist of an ordered doubly-linked list of simple ! 82: * entries; a single hint is used to speed up lookups. ! 83: * ! 84: * Sharing maps have been deleted from this version of Mach. ! 85: * All shared objects are now mapped directly into the respective ! 86: * maps. This requires a change in the copy on write strategy; ! 87: * the asymmetric (delayed) strategy is used for shared temporary ! 88: * objects instead of the symmetric (shadow) strategy. This is ! 89: * selected by the (new) use_shared_copy bit in the object. See ! 90: * vm_object_copy_temporary in vm_object.c for details. All maps ! 91: * are now "top level" maps (either task map, kernel map or submap ! 92: * of the kernel map). ! 93: * ! 94: * Since portions of maps are specified by start/end addreses, ! 95: * which may not align with existing map entries, all ! 96: * routines merely "clip" entries to these start/end values. ! 97: * [That is, an entry is split into two, bordering at a ! 98: * start or end value.] Note that these clippings may not ! 99: * always be necessary (as the two resulting entries are then ! 100: * not changed); however, the clipping is done for convenience. ! 101: * No attempt is currently made to "glue back together" two ! 102: * abutting entries. ! 103: * ! 104: * The symmetric (shadow) copy strategy implements virtual copy ! 105: * by copying VM object references from one map to ! 106: * another, and then marking both regions as copy-on-write. ! 107: * It is important to note that only one writeable reference ! 108: * to a VM object region exists in any map when this strategy ! 109: * is used -- this means that shadow object creation can be ! 110: * delayed until a write operation occurs. The asymmetric (delayed) ! 111: * strategy allows multiple maps to have writeable references to ! 112: * the same region of a vm object, and hence cannot delay creating ! 113: * its copy objects. See vm_object_copy_temporary() in vm_object.c. ! 114: * Copying of permanent objects is completely different; see ! 115: * vm_object_copy_strategically() in vm_object.c. ! 116: */ ! 117: ! 118: zone_t vm_map_zone; /* zone for vm_map structures */ ! 119: zone_t vm_map_entry_zone; /* zone for vm_map_entry structures */ ! 120: zone_t vm_map_kentry_zone; /* zone for kernel entry structures */ ! 121: zone_t vm_map_copy_zone; /* zone for vm_map_copy structures */ ! 122: ! 123: boolean_t vm_map_lookup_entry(); /* forward declaration */ ! 124: ! 125: /* ! 126: * Placeholder object for submap operations. This object is dropped ! 127: * into the range by a call to vm_map_find, and removed when ! 128: * vm_map_submap creates the submap. ! 129: */ ! 130: ! 131: vm_object_t vm_submap_object; ! 132: ! 133: /* ! 134: * vm_map_init: ! 135: * ! 136: * Initialize the vm_map module. Must be called before ! 137: * any other vm_map routines. ! 138: * ! 139: * Map and entry structures are allocated from zones -- we must ! 140: * initialize those zones. ! 141: * ! 142: * There are three zones of interest: ! 143: * ! 144: * vm_map_zone: used to allocate maps. ! 145: * vm_map_entry_zone: used to allocate map entries. ! 146: * vm_map_kentry_zone: used to allocate map entries for the kernel. ! 147: * ! 148: * The kernel allocates map entries from a special zone that is initially ! 149: * "crammed" with memory. It would be difficult (perhaps impossible) for ! 150: * the kernel to allocate more memory to a entry zone when it became ! 151: * empty since the very act of allocating memory implies the creation ! 152: * of a new entry. ! 153: */ ! 154: ! 155: vm_offset_t kentry_data; ! 156: vm_size_t kentry_data_size; ! 157: int kentry_count = 256; /* to init kentry_data_size */ ! 158: ! 159: void vm_map_init() ! 160: { ! 161: vm_map_zone = zinit((vm_size_t) sizeof(struct vm_map), 40*1024, ! 162: PAGE_SIZE, 0, "maps"); ! 163: vm_map_entry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry), ! 164: 1024*1024, PAGE_SIZE*5, ! 165: 0, "non-kernel map entries"); ! 166: vm_map_kentry_zone = zinit((vm_size_t) sizeof(struct vm_map_entry), ! 167: kentry_data_size, kentry_data_size, ! 168: ZONE_FIXED /* XXX */, "kernel map entries"); ! 169: ! 170: vm_map_copy_zone = zinit((vm_size_t) sizeof(struct vm_map_copy), ! 171: 16*1024, PAGE_SIZE, 0, ! 172: "map copies"); ! 173: ! 174: /* ! 175: * Cram the kentry zone with initial data. ! 176: */ ! 177: zcram(vm_map_kentry_zone, kentry_data, kentry_data_size); ! 178: ! 179: /* ! 180: * Submap object is initialized by vm_object_init. ! 181: */ ! 182: } ! 183: ! 184: /* ! 185: * vm_map_create: ! 186: * ! 187: * Creates and returns a new empty VM map with ! 188: * the given physical map structure, and having ! 189: * the given lower and upper address bounds. ! 190: */ ! 191: vm_map_t vm_map_create(pmap, min, max, pageable) ! 192: pmap_t pmap; ! 193: vm_offset_t min, max; ! 194: boolean_t pageable; ! 195: { ! 196: register vm_map_t result; ! 197: ! 198: result = (vm_map_t) zalloc(vm_map_zone); ! 199: if (result == VM_MAP_NULL) ! 200: panic("vm_map_create"); ! 201: ! 202: vm_map_first_entry(result) = vm_map_to_entry(result); ! 203: vm_map_last_entry(result) = vm_map_to_entry(result); ! 204: result->hdr.nentries = 0; ! 205: result->hdr.entries_pageable = pageable; ! 206: ! 207: result->size = 0; ! 208: result->ref_count = 1; ! 209: result->pmap = pmap; ! 210: result->min_offset = min; ! 211: result->max_offset = max; ! 212: result->wiring_required = FALSE; ! 213: result->wait_for_space = FALSE; ! 214: result->first_free = vm_map_to_entry(result); ! 215: result->hint = vm_map_to_entry(result); ! 216: vm_map_lock_init(result); ! 217: simple_lock_init(&result->ref_lock); ! 218: simple_lock_init(&result->hint_lock); ! 219: ! 220: return(result); ! 221: } ! 222: ! 223: /* ! 224: * vm_map_entry_create: [ internal use only ] ! 225: * ! 226: * Allocates a VM map entry for insertion in the ! 227: * given map (or map copy). No fields are filled. ! 228: */ ! 229: #define vm_map_entry_create(map) \ ! 230: _vm_map_entry_create(&(map)->hdr) ! 231: ! 232: #define vm_map_copy_entry_create(copy) \ ! 233: _vm_map_entry_create(&(copy)->cpy_hdr) ! 234: ! 235: vm_map_entry_t _vm_map_entry_create(map_header) ! 236: register struct vm_map_header *map_header; ! 237: { ! 238: register zone_t zone; ! 239: register vm_map_entry_t entry; ! 240: ! 241: if (map_header->entries_pageable) ! 242: zone = vm_map_entry_zone; ! 243: else ! 244: zone = vm_map_kentry_zone; ! 245: ! 246: entry = (vm_map_entry_t) zalloc(zone); ! 247: if (entry == VM_MAP_ENTRY_NULL) ! 248: panic("vm_map_entry_create"); ! 249: ! 250: return(entry); ! 251: } ! 252: ! 253: /* ! 254: * vm_map_entry_dispose: [ internal use only ] ! 255: * ! 256: * Inverse of vm_map_entry_create. ! 257: */ ! 258: #define vm_map_entry_dispose(map, entry) \ ! 259: _vm_map_entry_dispose(&(map)->hdr, (entry)) ! 260: ! 261: #define vm_map_copy_entry_dispose(map, entry) \ ! 262: _vm_map_entry_dispose(&(copy)->cpy_hdr, (entry)) ! 263: ! 264: void _vm_map_entry_dispose(map_header, entry) ! 265: register struct vm_map_header *map_header; ! 266: register vm_map_entry_t entry; ! 267: { ! 268: register zone_t zone; ! 269: ! 270: if (map_header->entries_pageable) ! 271: zone = vm_map_entry_zone; ! 272: else ! 273: zone = vm_map_kentry_zone; ! 274: ! 275: zfree(zone, (vm_offset_t) entry); ! 276: } ! 277: ! 278: /* ! 279: * vm_map_entry_{un,}link: ! 280: * ! 281: * Insert/remove entries from maps (or map copies). ! 282: */ ! 283: #define vm_map_entry_link(map, after_where, entry) \ ! 284: _vm_map_entry_link(&(map)->hdr, after_where, entry) ! 285: ! 286: #define vm_map_copy_entry_link(copy, after_where, entry) \ ! 287: _vm_map_entry_link(&(copy)->cpy_hdr, after_where, entry) ! 288: ! 289: #define _vm_map_entry_link(hdr, after_where, entry) \ ! 290: MACRO_BEGIN \ ! 291: (hdr)->nentries++; \ ! 292: (entry)->vme_prev = (after_where); \ ! 293: (entry)->vme_next = (after_where)->vme_next; \ ! 294: (entry)->vme_prev->vme_next = \ ! 295: (entry)->vme_next->vme_prev = (entry); \ ! 296: MACRO_END ! 297: ! 298: #define vm_map_entry_unlink(map, entry) \ ! 299: _vm_map_entry_unlink(&(map)->hdr, entry) ! 300: ! 301: #define vm_map_copy_entry_unlink(copy, entry) \ ! 302: _vm_map_entry_unlink(&(copy)->cpy_hdr, entry) ! 303: ! 304: #define _vm_map_entry_unlink(hdr, entry) \ ! 305: MACRO_BEGIN \ ! 306: (hdr)->nentries--; \ ! 307: (entry)->vme_next->vme_prev = (entry)->vme_prev; \ ! 308: (entry)->vme_prev->vme_next = (entry)->vme_next; \ ! 309: MACRO_END ! 310: ! 311: /* ! 312: * vm_map_reference: ! 313: * ! 314: * Creates another valid reference to the given map. ! 315: * ! 316: */ ! 317: void vm_map_reference(map) ! 318: register vm_map_t map; ! 319: { ! 320: if (map == VM_MAP_NULL) ! 321: return; ! 322: ! 323: simple_lock(&map->ref_lock); ! 324: map->ref_count++; ! 325: simple_unlock(&map->ref_lock); ! 326: } ! 327: ! 328: /* ! 329: * vm_map_deallocate: ! 330: * ! 331: * Removes a reference from the specified map, ! 332: * destroying it if no references remain. ! 333: * The map should not be locked. ! 334: */ ! 335: void vm_map_deallocate(map) ! 336: register vm_map_t map; ! 337: { ! 338: register int c; ! 339: ! 340: if (map == VM_MAP_NULL) ! 341: return; ! 342: ! 343: simple_lock(&map->ref_lock); ! 344: c = --map->ref_count; ! 345: simple_unlock(&map->ref_lock); ! 346: ! 347: if (c > 0) { ! 348: return; ! 349: } ! 350: ! 351: projected_buffer_collect(map); ! 352: (void) vm_map_delete(map, map->min_offset, map->max_offset); ! 353: ! 354: pmap_destroy(map->pmap); ! 355: ! 356: zfree(vm_map_zone, (vm_offset_t) map); ! 357: } ! 358: ! 359: /* ! 360: * SAVE_HINT: ! 361: * ! 362: * Saves the specified entry as the hint for ! 363: * future lookups. Performs necessary interlocks. ! 364: */ ! 365: #define SAVE_HINT(map,value) \ ! 366: simple_lock(&(map)->hint_lock); \ ! 367: (map)->hint = (value); \ ! 368: simple_unlock(&(map)->hint_lock); ! 369: ! 370: /* ! 371: * vm_map_lookup_entry: [ internal use only ] ! 372: * ! 373: * Finds the map entry containing (or ! 374: * immediately preceding) the specified address ! 375: * in the given map; the entry is returned ! 376: * in the "entry" parameter. The boolean ! 377: * result indicates whether the address is ! 378: * actually contained in the map. ! 379: */ ! 380: boolean_t vm_map_lookup_entry(map, address, entry) ! 381: register vm_map_t map; ! 382: register vm_offset_t address; ! 383: vm_map_entry_t *entry; /* OUT */ ! 384: { ! 385: register vm_map_entry_t cur; ! 386: register vm_map_entry_t last; ! 387: ! 388: /* ! 389: * Start looking either from the head of the ! 390: * list, or from the hint. ! 391: */ ! 392: ! 393: simple_lock(&map->hint_lock); ! 394: cur = map->hint; ! 395: simple_unlock(&map->hint_lock); ! 396: ! 397: if (cur == vm_map_to_entry(map)) ! 398: cur = cur->vme_next; ! 399: ! 400: if (address >= cur->vme_start) { ! 401: /* ! 402: * Go from hint to end of list. ! 403: * ! 404: * But first, make a quick check to see if ! 405: * we are already looking at the entry we ! 406: * want (which is usually the case). ! 407: * Note also that we don't need to save the hint ! 408: * here... it is the same hint (unless we are ! 409: * at the header, in which case the hint didn't ! 410: * buy us anything anyway). ! 411: */ ! 412: last = vm_map_to_entry(map); ! 413: if ((cur != last) && (cur->vme_end > address)) { ! 414: *entry = cur; ! 415: return(TRUE); ! 416: } ! 417: } ! 418: else { ! 419: /* ! 420: * Go from start to hint, *inclusively* ! 421: */ ! 422: last = cur->vme_next; ! 423: cur = vm_map_first_entry(map); ! 424: } ! 425: ! 426: /* ! 427: * Search linearly ! 428: */ ! 429: ! 430: while (cur != last) { ! 431: if (cur->vme_end > address) { ! 432: if (address >= cur->vme_start) { ! 433: /* ! 434: * Save this lookup for future ! 435: * hints, and return ! 436: */ ! 437: ! 438: *entry = cur; ! 439: SAVE_HINT(map, cur); ! 440: return(TRUE); ! 441: } ! 442: break; ! 443: } ! 444: cur = cur->vme_next; ! 445: } ! 446: *entry = cur->vme_prev; ! 447: SAVE_HINT(map, *entry); ! 448: return(FALSE); ! 449: } ! 450: ! 451: /* ! 452: * Routine: invalid_user_access ! 453: * ! 454: * Verifies whether user access is valid. ! 455: */ ! 456: ! 457: boolean_t ! 458: invalid_user_access(map, start, end, prot) ! 459: vm_map_t map; ! 460: vm_offset_t start, end; ! 461: vm_prot_t prot; ! 462: { ! 463: vm_map_entry_t entry; ! 464: ! 465: return (map == VM_MAP_NULL || map == kernel_map || ! 466: !vm_map_lookup_entry(map, start, &entry) || ! 467: entry->vme_end < end || ! 468: (prot & ~(entry->protection))); ! 469: } ! 470: ! 471: ! 472: /* ! 473: * Routine: vm_map_find_entry ! 474: * Purpose: ! 475: * Allocate a range in the specified virtual address map, ! 476: * returning the entry allocated for that range. ! 477: * Used by kmem_alloc, etc. Returns wired entries. ! 478: * ! 479: * The map must be locked. ! 480: * ! 481: * If an entry is allocated, the object/offset fields ! 482: * are initialized to zero. If an object is supplied, ! 483: * then an existing entry may be extended. ! 484: */ ! 485: kern_return_t vm_map_find_entry(map, address, size, mask, object, o_entry) ! 486: register vm_map_t map; ! 487: vm_offset_t *address; /* OUT */ ! 488: vm_size_t size; ! 489: vm_offset_t mask; ! 490: vm_object_t object; ! 491: vm_map_entry_t *o_entry; /* OUT */ ! 492: { ! 493: register vm_map_entry_t entry, new_entry; ! 494: register vm_offset_t start; ! 495: register vm_offset_t end; ! 496: ! 497: /* ! 498: * Look for the first possible address; ! 499: * if there's already something at this ! 500: * address, we have to start after it. ! 501: */ ! 502: ! 503: if ((entry = map->first_free) == vm_map_to_entry(map)) ! 504: start = map->min_offset; ! 505: else ! 506: start = entry->vme_end; ! 507: ! 508: /* ! 509: * In any case, the "entry" always precedes ! 510: * the proposed new region throughout the loop: ! 511: */ ! 512: ! 513: while (TRUE) { ! 514: register vm_map_entry_t next; ! 515: ! 516: /* ! 517: * Find the end of the proposed new region. ! 518: * Be sure we didn't go beyond the end, or ! 519: * wrap around the address. ! 520: */ ! 521: ! 522: if (((start + mask) & ~mask) < start) ! 523: return(KERN_NO_SPACE); ! 524: start = ((start + mask) & ~mask); ! 525: end = start + size; ! 526: ! 527: if ((end > map->max_offset) || (end < start)) ! 528: return(KERN_NO_SPACE); ! 529: ! 530: /* ! 531: * If there are no more entries, we must win. ! 532: */ ! 533: ! 534: next = entry->vme_next; ! 535: if (next == vm_map_to_entry(map)) ! 536: break; ! 537: ! 538: /* ! 539: * If there is another entry, it must be ! 540: * after the end of the potential new region. ! 541: */ ! 542: ! 543: if (next->vme_start >= end) ! 544: break; ! 545: ! 546: /* ! 547: * Didn't fit -- move to the next entry. ! 548: */ ! 549: ! 550: entry = next; ! 551: start = entry->vme_end; ! 552: } ! 553: ! 554: /* ! 555: * At this point, ! 556: * "start" and "end" should define the endpoints of the ! 557: * available new range, and ! 558: * "entry" should refer to the region before the new ! 559: * range, and ! 560: * ! 561: * the map should be locked. ! 562: */ ! 563: ! 564: *address = start; ! 565: ! 566: /* ! 567: * See whether we can avoid creating a new entry by ! 568: * extending one of our neighbors. [So far, we only attempt to ! 569: * extend from below.] ! 570: */ ! 571: ! 572: if ((object != VM_OBJECT_NULL) && ! 573: (entry != vm_map_to_entry(map)) && ! 574: (entry->vme_end == start) && ! 575: (!entry->is_shared) && ! 576: (!entry->is_sub_map) && ! 577: (entry->object.vm_object == object) && ! 578: (entry->needs_copy == FALSE) && ! 579: (entry->inheritance == VM_INHERIT_DEFAULT) && ! 580: (entry->protection == VM_PROT_DEFAULT) && ! 581: (entry->max_protection == VM_PROT_ALL) && ! 582: (entry->wired_count == 1) && ! 583: (entry->user_wired_count == 0) && ! 584: (entry->projected_on == 0)) { ! 585: /* ! 586: * Because this is a special case, ! 587: * we don't need to use vm_object_coalesce. ! 588: */ ! 589: ! 590: entry->vme_end = end; ! 591: new_entry = entry; ! 592: } else { ! 593: new_entry = vm_map_entry_create(map); ! 594: ! 595: new_entry->vme_start = start; ! 596: new_entry->vme_end = end; ! 597: ! 598: new_entry->is_shared = FALSE; ! 599: new_entry->is_sub_map = FALSE; ! 600: new_entry->object.vm_object = VM_OBJECT_NULL; ! 601: new_entry->offset = (vm_offset_t) 0; ! 602: ! 603: new_entry->needs_copy = FALSE; ! 604: ! 605: new_entry->inheritance = VM_INHERIT_DEFAULT; ! 606: new_entry->protection = VM_PROT_DEFAULT; ! 607: new_entry->max_protection = VM_PROT_ALL; ! 608: new_entry->wired_count = 1; ! 609: new_entry->user_wired_count = 0; ! 610: ! 611: new_entry->in_transition = FALSE; ! 612: new_entry->needs_wakeup = FALSE; ! 613: new_entry->projected_on = 0; ! 614: ! 615: /* ! 616: * Insert the new entry into the list ! 617: */ ! 618: ! 619: vm_map_entry_link(map, entry, new_entry); ! 620: } ! 621: ! 622: map->size += size; ! 623: ! 624: /* ! 625: * Update the free space hint and the lookup hint ! 626: */ ! 627: ! 628: map->first_free = new_entry; ! 629: SAVE_HINT(map, new_entry); ! 630: ! 631: *o_entry = new_entry; ! 632: return(KERN_SUCCESS); ! 633: } ! 634: ! 635: int vm_map_pmap_enter_print = FALSE; ! 636: int vm_map_pmap_enter_enable = FALSE; ! 637: ! 638: /* ! 639: * Routine: vm_map_pmap_enter ! 640: * ! 641: * Description: ! 642: * Force pages from the specified object to be entered into ! 643: * the pmap at the specified address if they are present. ! 644: * As soon as a page not found in the object the scan ends. ! 645: * ! 646: * Returns: ! 647: * Nothing. ! 648: * ! 649: * In/out conditions: ! 650: * The source map should not be locked on entry. ! 651: */ ! 652: void ! 653: vm_map_pmap_enter(map, addr, end_addr, object, offset, protection) ! 654: vm_map_t map; ! 655: register ! 656: vm_offset_t addr; ! 657: register ! 658: vm_offset_t end_addr; ! 659: register ! 660: vm_object_t object; ! 661: vm_offset_t offset; ! 662: vm_prot_t protection; ! 663: { ! 664: while (addr < end_addr) { ! 665: register vm_page_t m; ! 666: ! 667: vm_object_lock(object); ! 668: vm_object_paging_begin(object); ! 669: ! 670: m = vm_page_lookup(object, offset); ! 671: if (m == VM_PAGE_NULL || m->absent) { ! 672: vm_object_paging_end(object); ! 673: vm_object_unlock(object); ! 674: return; ! 675: } ! 676: ! 677: if (vm_map_pmap_enter_print) { ! 678: printf("vm_map_pmap_enter:"); ! 679: printf("map: %x, addr: %x, object: %x, offset: %x\n", ! 680: map, addr, object, offset); ! 681: } ! 682: ! 683: m->busy = TRUE; ! 684: vm_object_unlock(object); ! 685: ! 686: PMAP_ENTER(map->pmap, addr, m, ! 687: protection, FALSE); ! 688: ! 689: vm_object_lock(object); ! 690: PAGE_WAKEUP_DONE(m); ! 691: vm_page_lock_queues(); ! 692: if (!m->active && !m->inactive) ! 693: vm_page_activate(m); ! 694: vm_page_unlock_queues(); ! 695: vm_object_paging_end(object); ! 696: vm_object_unlock(object); ! 697: ! 698: offset += PAGE_SIZE; ! 699: addr += PAGE_SIZE; ! 700: } ! 701: } ! 702: ! 703: /* ! 704: * Routine: vm_map_enter ! 705: * ! 706: * Description: ! 707: * Allocate a range in the specified virtual address map. ! 708: * The resulting range will refer to memory defined by ! 709: * the given memory object and offset into that object. ! 710: * ! 711: * Arguments are as defined in the vm_map call. ! 712: */ ! 713: kern_return_t vm_map_enter( ! 714: map, ! 715: address, size, mask, anywhere, ! 716: object, offset, needs_copy, ! 717: cur_protection, max_protection, inheritance) ! 718: register ! 719: vm_map_t map; ! 720: vm_offset_t *address; /* IN/OUT */ ! 721: vm_size_t size; ! 722: vm_offset_t mask; ! 723: boolean_t anywhere; ! 724: vm_object_t object; ! 725: vm_offset_t offset; ! 726: boolean_t needs_copy; ! 727: vm_prot_t cur_protection; ! 728: vm_prot_t max_protection; ! 729: vm_inherit_t inheritance; ! 730: { ! 731: register vm_map_entry_t entry; ! 732: register vm_offset_t start; ! 733: register vm_offset_t end; ! 734: kern_return_t result = KERN_SUCCESS; ! 735: ! 736: #define RETURN(value) { result = value; goto BailOut; } ! 737: ! 738: StartAgain: ; ! 739: ! 740: start = *address; ! 741: ! 742: if (anywhere) { ! 743: vm_map_lock(map); ! 744: ! 745: /* ! 746: * Calculate the first possible address. ! 747: */ ! 748: ! 749: if (start < map->min_offset) ! 750: start = map->min_offset; ! 751: if (start > map->max_offset) ! 752: RETURN(KERN_NO_SPACE); ! 753: ! 754: /* ! 755: * Look for the first possible address; ! 756: * if there's already something at this ! 757: * address, we have to start after it. ! 758: */ ! 759: ! 760: if (start == map->min_offset) { ! 761: if ((entry = map->first_free) != vm_map_to_entry(map)) ! 762: start = entry->vme_end; ! 763: } else { ! 764: vm_map_entry_t tmp_entry; ! 765: if (vm_map_lookup_entry(map, start, &tmp_entry)) ! 766: start = tmp_entry->vme_end; ! 767: entry = tmp_entry; ! 768: } ! 769: ! 770: /* ! 771: * In any case, the "entry" always precedes ! 772: * the proposed new region throughout the ! 773: * loop: ! 774: */ ! 775: ! 776: while (TRUE) { ! 777: register vm_map_entry_t next; ! 778: ! 779: /* ! 780: * Find the end of the proposed new region. ! 781: * Be sure we didn't go beyond the end, or ! 782: * wrap around the address. ! 783: */ ! 784: ! 785: if (((start + mask) & ~mask) < start) ! 786: return(KERN_NO_SPACE); ! 787: start = ((start + mask) & ~mask); ! 788: end = start + size; ! 789: ! 790: if ((end > map->max_offset) || (end < start)) { ! 791: if (map->wait_for_space) { ! 792: if (size <= (map->max_offset - ! 793: map->min_offset)) { ! 794: assert_wait((event_t) map, TRUE); ! 795: vm_map_unlock(map); ! 796: thread_block((void (*)()) 0); ! 797: goto StartAgain; ! 798: } ! 799: } ! 800: ! 801: RETURN(KERN_NO_SPACE); ! 802: } ! 803: ! 804: /* ! 805: * If there are no more entries, we must win. ! 806: */ ! 807: ! 808: next = entry->vme_next; ! 809: if (next == vm_map_to_entry(map)) ! 810: break; ! 811: ! 812: /* ! 813: * If there is another entry, it must be ! 814: * after the end of the potential new region. ! 815: */ ! 816: ! 817: if (next->vme_start >= end) ! 818: break; ! 819: ! 820: /* ! 821: * Didn't fit -- move to the next entry. ! 822: */ ! 823: ! 824: entry = next; ! 825: start = entry->vme_end; ! 826: } ! 827: *address = start; ! 828: } else { ! 829: vm_map_entry_t temp_entry; ! 830: ! 831: /* ! 832: * Verify that: ! 833: * the address doesn't itself violate ! 834: * the mask requirement. ! 835: */ ! 836: ! 837: if ((start & mask) != 0) ! 838: return(KERN_NO_SPACE); ! 839: ! 840: vm_map_lock(map); ! 841: ! 842: /* ! 843: * ... the address is within bounds ! 844: */ ! 845: ! 846: end = start + size; ! 847: ! 848: if ((start < map->min_offset) || ! 849: (end > map->max_offset) || ! 850: (start >= end)) { ! 851: RETURN(KERN_INVALID_ADDRESS); ! 852: } ! 853: ! 854: /* ! 855: * ... the starting address isn't allocated ! 856: */ ! 857: ! 858: if (vm_map_lookup_entry(map, start, &temp_entry)) ! 859: RETURN(KERN_NO_SPACE); ! 860: ! 861: entry = temp_entry; ! 862: ! 863: /* ! 864: * ... the next region doesn't overlap the ! 865: * end point. ! 866: */ ! 867: ! 868: if ((entry->vme_next != vm_map_to_entry(map)) && ! 869: (entry->vme_next->vme_start < end)) ! 870: RETURN(KERN_NO_SPACE); ! 871: } ! 872: ! 873: /* ! 874: * At this point, ! 875: * "start" and "end" should define the endpoints of the ! 876: * available new range, and ! 877: * "entry" should refer to the region before the new ! 878: * range, and ! 879: * ! 880: * the map should be locked. ! 881: */ ! 882: ! 883: /* ! 884: * See whether we can avoid creating a new entry (and object) by ! 885: * extending one of our neighbors. [So far, we only attempt to ! 886: * extend from below.] ! 887: */ ! 888: ! 889: if ((object == VM_OBJECT_NULL) && ! 890: (entry != vm_map_to_entry(map)) && ! 891: (entry->vme_end == start) && ! 892: (!entry->is_shared) && ! 893: (!entry->is_sub_map) && ! 894: (entry->inheritance == inheritance) && ! 895: (entry->protection == cur_protection) && ! 896: (entry->max_protection == max_protection) && ! 897: (entry->wired_count == 0) && /* implies user_wired_count == 0 */ ! 898: (entry->projected_on == 0)) { ! 899: if (vm_object_coalesce(entry->object.vm_object, ! 900: VM_OBJECT_NULL, ! 901: entry->offset, ! 902: (vm_offset_t) 0, ! 903: (vm_size_t)(entry->vme_end - entry->vme_start), ! 904: (vm_size_t)(end - entry->vme_end))) { ! 905: ! 906: /* ! 907: * Coalesced the two objects - can extend ! 908: * the previous map entry to include the ! 909: * new range. ! 910: */ ! 911: map->size += (end - entry->vme_end); ! 912: entry->vme_end = end; ! 913: RETURN(KERN_SUCCESS); ! 914: } ! 915: } ! 916: ! 917: /* ! 918: * Create a new entry ! 919: */ ! 920: ! 921: /**/ { ! 922: register vm_map_entry_t new_entry; ! 923: ! 924: new_entry = vm_map_entry_create(map); ! 925: ! 926: new_entry->vme_start = start; ! 927: new_entry->vme_end = end; ! 928: ! 929: new_entry->is_shared = FALSE; ! 930: new_entry->is_sub_map = FALSE; ! 931: new_entry->object.vm_object = object; ! 932: new_entry->offset = offset; ! 933: ! 934: new_entry->needs_copy = needs_copy; ! 935: ! 936: new_entry->inheritance = inheritance; ! 937: new_entry->protection = cur_protection; ! 938: new_entry->max_protection = max_protection; ! 939: new_entry->wired_count = 0; ! 940: new_entry->user_wired_count = 0; ! 941: ! 942: new_entry->in_transition = FALSE; ! 943: new_entry->needs_wakeup = FALSE; ! 944: new_entry->projected_on = 0; ! 945: ! 946: /* ! 947: * Insert the new entry into the list ! 948: */ ! 949: ! 950: vm_map_entry_link(map, entry, new_entry); ! 951: map->size += size; ! 952: ! 953: /* ! 954: * Update the free space hint and the lookup hint ! 955: */ ! 956: ! 957: if ((map->first_free == entry) && ! 958: ((entry == vm_map_to_entry(map) ? map->min_offset : entry->vme_end) ! 959: >= new_entry->vme_start)) ! 960: map->first_free = new_entry; ! 961: ! 962: SAVE_HINT(map, new_entry); ! 963: ! 964: vm_map_unlock(map); ! 965: ! 966: if ((object != VM_OBJECT_NULL) && ! 967: (vm_map_pmap_enter_enable) && ! 968: (!anywhere) && ! 969: (!needs_copy) && ! 970: (size < (128*1024))) { ! 971: vm_map_pmap_enter(map, start, end, ! 972: object, offset, cur_protection); ! 973: } ! 974: ! 975: return(result); ! 976: /**/ } ! 977: ! 978: BailOut: ; ! 979: ! 980: vm_map_unlock(map); ! 981: return(result); ! 982: ! 983: #undef RETURN ! 984: } ! 985: ! 986: /* ! 987: * vm_map_clip_start: [ internal use only ] ! 988: * ! 989: * Asserts that the given entry begins at or after ! 990: * the specified address; if necessary, ! 991: * it splits the entry into two. ! 992: */ ! 993: void _vm_map_clip_start(); ! 994: #define vm_map_clip_start(map, entry, startaddr) \ ! 995: MACRO_BEGIN \ ! 996: if ((startaddr) > (entry)->vme_start) \ ! 997: _vm_map_clip_start(&(map)->hdr,(entry),(startaddr)); \ ! 998: MACRO_END ! 999: ! 1000: void _vm_map_copy_clip_start(); ! 1001: #define vm_map_copy_clip_start(copy, entry, startaddr) \ ! 1002: MACRO_BEGIN \ ! 1003: if ((startaddr) > (entry)->vme_start) \ ! 1004: _vm_map_clip_start(&(copy)->cpy_hdr,(entry),(startaddr)); \ ! 1005: MACRO_END ! 1006: ! 1007: /* ! 1008: * This routine is called only when it is known that ! 1009: * the entry must be split. ! 1010: */ ! 1011: void _vm_map_clip_start(map_header, entry, start) ! 1012: register struct vm_map_header *map_header; ! 1013: register vm_map_entry_t entry; ! 1014: register vm_offset_t start; ! 1015: { ! 1016: register vm_map_entry_t new_entry; ! 1017: ! 1018: /* ! 1019: * Split off the front portion -- ! 1020: * note that we must insert the new ! 1021: * entry BEFORE this one, so that ! 1022: * this entry has the specified starting ! 1023: * address. ! 1024: */ ! 1025: ! 1026: new_entry = _vm_map_entry_create(map_header); ! 1027: vm_map_entry_copy_full(new_entry, entry); ! 1028: ! 1029: new_entry->vme_end = start; ! 1030: entry->offset += (start - entry->vme_start); ! 1031: entry->vme_start = start; ! 1032: ! 1033: _vm_map_entry_link(map_header, entry->vme_prev, new_entry); ! 1034: ! 1035: if (entry->is_sub_map) ! 1036: vm_map_reference(new_entry->object.sub_map); ! 1037: else ! 1038: vm_object_reference(new_entry->object.vm_object); ! 1039: } ! 1040: ! 1041: /* ! 1042: * vm_map_clip_end: [ internal use only ] ! 1043: * ! 1044: * Asserts that the given entry ends at or before ! 1045: * the specified address; if necessary, ! 1046: * it splits the entry into two. ! 1047: */ ! 1048: void _vm_map_clip_end(); ! 1049: #define vm_map_clip_end(map, entry, endaddr) \ ! 1050: MACRO_BEGIN \ ! 1051: if ((endaddr) < (entry)->vme_end) \ ! 1052: _vm_map_clip_end(&(map)->hdr,(entry),(endaddr)); \ ! 1053: MACRO_END ! 1054: ! 1055: void _vm_map_copy_clip_end(); ! 1056: #define vm_map_copy_clip_end(copy, entry, endaddr) \ ! 1057: MACRO_BEGIN \ ! 1058: if ((endaddr) < (entry)->vme_end) \ ! 1059: _vm_map_clip_end(&(copy)->cpy_hdr,(entry),(endaddr)); \ ! 1060: MACRO_END ! 1061: ! 1062: /* ! 1063: * This routine is called only when it is known that ! 1064: * the entry must be split. ! 1065: */ ! 1066: void _vm_map_clip_end(map_header, entry, end) ! 1067: register struct vm_map_header *map_header; ! 1068: register vm_map_entry_t entry; ! 1069: register vm_offset_t end; ! 1070: { ! 1071: register vm_map_entry_t new_entry; ! 1072: ! 1073: /* ! 1074: * Create a new entry and insert it ! 1075: * AFTER the specified entry ! 1076: */ ! 1077: ! 1078: new_entry = _vm_map_entry_create(map_header); ! 1079: vm_map_entry_copy_full(new_entry, entry); ! 1080: ! 1081: new_entry->vme_start = entry->vme_end = end; ! 1082: new_entry->offset += (end - entry->vme_start); ! 1083: ! 1084: _vm_map_entry_link(map_header, entry, new_entry); ! 1085: ! 1086: if (entry->is_sub_map) ! 1087: vm_map_reference(new_entry->object.sub_map); ! 1088: else ! 1089: vm_object_reference(new_entry->object.vm_object); ! 1090: } ! 1091: ! 1092: /* ! 1093: * VM_MAP_RANGE_CHECK: [ internal use only ] ! 1094: * ! 1095: * Asserts that the starting and ending region ! 1096: * addresses fall within the valid range of the map. ! 1097: */ ! 1098: #define VM_MAP_RANGE_CHECK(map, start, end) \ ! 1099: { \ ! 1100: if (start < vm_map_min(map)) \ ! 1101: start = vm_map_min(map); \ ! 1102: if (end > vm_map_max(map)) \ ! 1103: end = vm_map_max(map); \ ! 1104: if (start > end) \ ! 1105: start = end; \ ! 1106: } ! 1107: ! 1108: /* ! 1109: * vm_map_submap: [ kernel use only ] ! 1110: * ! 1111: * Mark the given range as handled by a subordinate map. ! 1112: * ! 1113: * This range must have been created with vm_map_find using ! 1114: * the vm_submap_object, and no other operations may have been ! 1115: * performed on this range prior to calling vm_map_submap. ! 1116: * ! 1117: * Only a limited number of operations can be performed ! 1118: * within this rage after calling vm_map_submap: ! 1119: * vm_fault ! 1120: * [Don't try vm_map_copyin!] ! 1121: * ! 1122: * To remove a submapping, one must first remove the ! 1123: * range from the superior map, and then destroy the ! 1124: * submap (if desired). [Better yet, don't try it.] ! 1125: */ ! 1126: kern_return_t vm_map_submap(map, start, end, submap) ! 1127: register vm_map_t map; ! 1128: register vm_offset_t start; ! 1129: register vm_offset_t end; ! 1130: vm_map_t submap; ! 1131: { ! 1132: vm_map_entry_t entry; ! 1133: register kern_return_t result = KERN_INVALID_ARGUMENT; ! 1134: register vm_object_t object; ! 1135: ! 1136: vm_map_lock(map); ! 1137: ! 1138: VM_MAP_RANGE_CHECK(map, start, end); ! 1139: ! 1140: if (vm_map_lookup_entry(map, start, &entry)) { ! 1141: vm_map_clip_start(map, entry, start); ! 1142: } ! 1143: else ! 1144: entry = entry->vme_next; ! 1145: ! 1146: vm_map_clip_end(map, entry, end); ! 1147: ! 1148: if ((entry->vme_start == start) && (entry->vme_end == end) && ! 1149: (!entry->is_sub_map) && ! 1150: ((object = entry->object.vm_object) == vm_submap_object) && ! 1151: (object->resident_page_count == 0) && ! 1152: (object->copy == VM_OBJECT_NULL) && ! 1153: (object->shadow == VM_OBJECT_NULL) && ! 1154: (!object->pager_created)) { ! 1155: entry->object.vm_object = VM_OBJECT_NULL; ! 1156: vm_object_deallocate(object); ! 1157: entry->is_sub_map = TRUE; ! 1158: vm_map_reference(entry->object.sub_map = submap); ! 1159: result = KERN_SUCCESS; ! 1160: } ! 1161: vm_map_unlock(map); ! 1162: ! 1163: return(result); ! 1164: } ! 1165: ! 1166: /* ! 1167: * vm_map_protect: ! 1168: * ! 1169: * Sets the protection of the specified address ! 1170: * region in the target map. If "set_max" is ! 1171: * specified, the maximum protection is to be set; ! 1172: * otherwise, only the current protection is affected. ! 1173: */ ! 1174: kern_return_t vm_map_protect(map, start, end, new_prot, set_max) ! 1175: register vm_map_t map; ! 1176: register vm_offset_t start; ! 1177: register vm_offset_t end; ! 1178: register vm_prot_t new_prot; ! 1179: register boolean_t set_max; ! 1180: { ! 1181: register vm_map_entry_t current; ! 1182: vm_map_entry_t entry; ! 1183: ! 1184: vm_map_lock(map); ! 1185: ! 1186: VM_MAP_RANGE_CHECK(map, start, end); ! 1187: ! 1188: if (vm_map_lookup_entry(map, start, &entry)) { ! 1189: vm_map_clip_start(map, entry, start); ! 1190: } ! 1191: else ! 1192: entry = entry->vme_next; ! 1193: ! 1194: /* ! 1195: * Make a first pass to check for protection ! 1196: * violations. ! 1197: */ ! 1198: ! 1199: current = entry; ! 1200: while ((current != vm_map_to_entry(map)) && ! 1201: (current->vme_start < end)) { ! 1202: ! 1203: if (current->is_sub_map) { ! 1204: vm_map_unlock(map); ! 1205: return(KERN_INVALID_ARGUMENT); ! 1206: } ! 1207: if ((new_prot & (VM_PROT_NOTIFY | current->max_protection)) ! 1208: != new_prot) { ! 1209: vm_map_unlock(map); ! 1210: return(KERN_PROTECTION_FAILURE); ! 1211: } ! 1212: ! 1213: current = current->vme_next; ! 1214: } ! 1215: ! 1216: /* ! 1217: * Go back and fix up protections. ! 1218: * [Note that clipping is not necessary the second time.] ! 1219: */ ! 1220: ! 1221: current = entry; ! 1222: ! 1223: while ((current != vm_map_to_entry(map)) && ! 1224: (current->vme_start < end)) { ! 1225: ! 1226: vm_prot_t old_prot; ! 1227: ! 1228: vm_map_clip_end(map, current, end); ! 1229: ! 1230: old_prot = current->protection; ! 1231: if (set_max) ! 1232: current->protection = ! 1233: (current->max_protection = new_prot) & ! 1234: old_prot; ! 1235: else ! 1236: current->protection = new_prot; ! 1237: ! 1238: /* ! 1239: * Update physical map if necessary. ! 1240: */ ! 1241: ! 1242: if (current->protection != old_prot) { ! 1243: pmap_protect(map->pmap, current->vme_start, ! 1244: current->vme_end, ! 1245: current->protection); ! 1246: } ! 1247: current = current->vme_next; ! 1248: } ! 1249: ! 1250: vm_map_unlock(map); ! 1251: return(KERN_SUCCESS); ! 1252: } ! 1253: ! 1254: /* ! 1255: * vm_map_inherit: ! 1256: * ! 1257: * Sets the inheritance of the specified address ! 1258: * range in the target map. Inheritance ! 1259: * affects how the map will be shared with ! 1260: * child maps at the time of vm_map_fork. ! 1261: */ ! 1262: kern_return_t vm_map_inherit(map, start, end, new_inheritance) ! 1263: register vm_map_t map; ! 1264: register vm_offset_t start; ! 1265: register vm_offset_t end; ! 1266: register vm_inherit_t new_inheritance; ! 1267: { ! 1268: register vm_map_entry_t entry; ! 1269: vm_map_entry_t temp_entry; ! 1270: ! 1271: vm_map_lock(map); ! 1272: ! 1273: VM_MAP_RANGE_CHECK(map, start, end); ! 1274: ! 1275: if (vm_map_lookup_entry(map, start, &temp_entry)) { ! 1276: entry = temp_entry; ! 1277: vm_map_clip_start(map, entry, start); ! 1278: } ! 1279: else ! 1280: entry = temp_entry->vme_next; ! 1281: ! 1282: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) { ! 1283: vm_map_clip_end(map, entry, end); ! 1284: ! 1285: entry->inheritance = new_inheritance; ! 1286: ! 1287: entry = entry->vme_next; ! 1288: } ! 1289: ! 1290: vm_map_unlock(map); ! 1291: return(KERN_SUCCESS); ! 1292: } ! 1293: ! 1294: /* ! 1295: * vm_map_pageable_common: ! 1296: * ! 1297: * Sets the pageability of the specified address ! 1298: * range in the target map. Regions specified ! 1299: * as not pageable require locked-down physical ! 1300: * memory and physical page maps. access_type indicates ! 1301: * types of accesses that must not generate page faults. ! 1302: * This is checked against protection of memory being locked-down. ! 1303: * access_type of VM_PROT_NONE makes memory pageable. ! 1304: * ! 1305: * The map must not be locked, but a reference ! 1306: * must remain to the map throughout the call. ! 1307: * ! 1308: * Callers should use macros in vm/vm_map.h (i.e. vm_map_pageable, ! 1309: * or vm_map_pageable_user); don't call vm_map_pageable directly. ! 1310: */ ! 1311: kern_return_t vm_map_pageable_common(map, start, end, access_type, user_wire) ! 1312: register vm_map_t map; ! 1313: register vm_offset_t start; ! 1314: register vm_offset_t end; ! 1315: register vm_prot_t access_type; ! 1316: boolean_t user_wire; ! 1317: { ! 1318: register vm_map_entry_t entry; ! 1319: vm_map_entry_t start_entry; ! 1320: ! 1321: vm_map_lock(map); ! 1322: ! 1323: VM_MAP_RANGE_CHECK(map, start, end); ! 1324: ! 1325: if (vm_map_lookup_entry(map, start, &start_entry)) { ! 1326: entry = start_entry; ! 1327: /* ! 1328: * vm_map_clip_start will be done later. ! 1329: */ ! 1330: } ! 1331: else { ! 1332: /* ! 1333: * Start address is not in map; this is fatal. ! 1334: */ ! 1335: vm_map_unlock(map); ! 1336: return(KERN_FAILURE); ! 1337: } ! 1338: ! 1339: /* ! 1340: * Actions are rather different for wiring and unwiring, ! 1341: * so we have two separate cases. ! 1342: */ ! 1343: ! 1344: if (access_type == VM_PROT_NONE) { ! 1345: ! 1346: vm_map_clip_start(map, entry, start); ! 1347: ! 1348: /* ! 1349: * Unwiring. First ensure that the range to be ! 1350: * unwired is really wired down. ! 1351: */ ! 1352: while ((entry != vm_map_to_entry(map)) && ! 1353: (entry->vme_start < end)) { ! 1354: ! 1355: if ((entry->wired_count == 0) || ! 1356: ((entry->vme_end < end) && ! 1357: ((entry->vme_next == vm_map_to_entry(map)) || ! 1358: (entry->vme_next->vme_start > entry->vme_end))) || ! 1359: (user_wire && (entry->user_wired_count == 0))) { ! 1360: vm_map_unlock(map); ! 1361: return(KERN_INVALID_ARGUMENT); ! 1362: } ! 1363: entry = entry->vme_next; ! 1364: } ! 1365: ! 1366: /* ! 1367: * Now decrement the wiring count for each region. ! 1368: * If a region becomes completely unwired, ! 1369: * unwire its physical pages and mappings. ! 1370: */ ! 1371: entry = start_entry; ! 1372: while ((entry != vm_map_to_entry(map)) && ! 1373: (entry->vme_start < end)) { ! 1374: vm_map_clip_end(map, entry, end); ! 1375: ! 1376: if (user_wire) { ! 1377: if (--(entry->user_wired_count) == 0) ! 1378: entry->wired_count--; ! 1379: } ! 1380: else { ! 1381: entry->wired_count--; ! 1382: } ! 1383: ! 1384: if (entry->wired_count == 0) ! 1385: vm_fault_unwire(map, entry); ! 1386: ! 1387: entry = entry->vme_next; ! 1388: } ! 1389: } ! 1390: ! 1391: else { ! 1392: /* ! 1393: * Wiring. We must do this in two passes: ! 1394: * ! 1395: * 1. Holding the write lock, we create any shadow ! 1396: * or zero-fill objects that need to be created. ! 1397: * Then we clip each map entry to the region to be ! 1398: * wired and increment its wiring count. We ! 1399: * create objects before clipping the map entries ! 1400: * to avoid object proliferation. ! 1401: * ! 1402: * 2. We downgrade to a read lock, and call ! 1403: * vm_fault_wire to fault in the pages for any ! 1404: * newly wired area (wired_count is 1). ! 1405: * ! 1406: * Downgrading to a read lock for vm_fault_wire avoids ! 1407: * a possible deadlock with another thread that may have ! 1408: * faulted on one of the pages to be wired (it would mark ! 1409: * the page busy, blocking us, then in turn block on the ! 1410: * map lock that we hold). Because of problems in the ! 1411: * recursive lock package, we cannot upgrade to a write ! 1412: * lock in vm_map_lookup. Thus, any actions that require ! 1413: * the write lock must be done beforehand. Because we ! 1414: * keep the read lock on the map, the copy-on-write ! 1415: * status of the entries we modify here cannot change. ! 1416: */ ! 1417: ! 1418: /* ! 1419: * Pass 1. ! 1420: */ ! 1421: while ((entry != vm_map_to_entry(map)) && ! 1422: (entry->vme_start < end)) { ! 1423: vm_map_clip_end(map, entry, end); ! 1424: ! 1425: if (entry->wired_count == 0) { ! 1426: ! 1427: /* ! 1428: * Perform actions of vm_map_lookup that need ! 1429: * the write lock on the map: create a shadow ! 1430: * object for a copy-on-write region, or an ! 1431: * object for a zero-fill region. ! 1432: */ ! 1433: if (entry->needs_copy && ! 1434: ((entry->protection & VM_PROT_WRITE) != 0)) { ! 1435: ! 1436: vm_object_shadow(&entry->object.vm_object, ! 1437: &entry->offset, ! 1438: (vm_size_t)(entry->vme_end ! 1439: - entry->vme_start)); ! 1440: entry->needs_copy = FALSE; ! 1441: } ! 1442: if (entry->object.vm_object == VM_OBJECT_NULL) { ! 1443: entry->object.vm_object = ! 1444: vm_object_allocate( ! 1445: (vm_size_t)(entry->vme_end ! 1446: - entry->vme_start)); ! 1447: entry->offset = (vm_offset_t)0; ! 1448: } ! 1449: } ! 1450: vm_map_clip_start(map, entry, start); ! 1451: vm_map_clip_end(map, entry, end); ! 1452: ! 1453: if (user_wire) { ! 1454: if ((entry->user_wired_count)++ == 0) ! 1455: entry->wired_count++; ! 1456: } ! 1457: else { ! 1458: entry->wired_count++; ! 1459: } ! 1460: ! 1461: /* ! 1462: * Check for holes and protection mismatch. ! 1463: * Holes: Next entry should be contiguous unless ! 1464: * this is the end of the region. ! 1465: * Protection: Access requested must be allowed. ! 1466: */ ! 1467: if (((entry->vme_end < end) && ! 1468: ((entry->vme_next == vm_map_to_entry(map)) || ! 1469: (entry->vme_next->vme_start > entry->vme_end))) || ! 1470: ((entry->protection & access_type) != access_type)) { ! 1471: /* ! 1472: * Found a hole or protection problem. ! 1473: * Object creation actions ! 1474: * do not need to be undone, but the ! 1475: * wired counts need to be restored. ! 1476: */ ! 1477: while ((entry != vm_map_to_entry(map)) && ! 1478: (entry->vme_end > start)) { ! 1479: if (user_wire) { ! 1480: if (--(entry->user_wired_count) == 0) ! 1481: entry->wired_count--; ! 1482: } ! 1483: else { ! 1484: entry->wired_count--; ! 1485: } ! 1486: ! 1487: entry = entry->vme_prev; ! 1488: } ! 1489: ! 1490: vm_map_unlock(map); ! 1491: return(KERN_FAILURE); ! 1492: } ! 1493: entry = entry->vme_next; ! 1494: } ! 1495: ! 1496: /* ! 1497: * Pass 2. ! 1498: */ ! 1499: ! 1500: /* ! 1501: * HACK HACK HACK HACK ! 1502: * ! 1503: * If we are wiring in the kernel map or a submap of it, ! 1504: * unlock the map to avoid deadlocks. We trust that the ! 1505: * kernel threads are well-behaved, and therefore will ! 1506: * not do anything destructive to this region of the map ! 1507: * while we have it unlocked. We cannot trust user threads ! 1508: * to do the same. ! 1509: * ! 1510: * HACK HACK HACK HACK ! 1511: */ ! 1512: if (vm_map_pmap(map) == kernel_pmap) { ! 1513: vm_map_unlock(map); /* trust me ... */ ! 1514: } ! 1515: else { ! 1516: vm_map_lock_set_recursive(map); ! 1517: vm_map_lock_write_to_read(map); ! 1518: } ! 1519: ! 1520: entry = start_entry; ! 1521: while (entry != vm_map_to_entry(map) && ! 1522: entry->vme_start < end) { ! 1523: /* ! 1524: * Wiring cases: ! 1525: * Kernel: wired == 1 && user_wired == 0 ! 1526: * User: wired == 1 && user_wired == 1 ! 1527: * ! 1528: * Don't need to wire if either is > 1. wired = 0 && ! 1529: * user_wired == 1 can't happen. ! 1530: */ ! 1531: ! 1532: /* ! 1533: * XXX This assumes that the faults always succeed. ! 1534: */ ! 1535: if ((entry->wired_count == 1) && ! 1536: (entry->user_wired_count <= 1)) { ! 1537: vm_fault_wire(map, entry); ! 1538: } ! 1539: entry = entry->vme_next; ! 1540: } ! 1541: ! 1542: if (vm_map_pmap(map) == kernel_pmap) { ! 1543: vm_map_lock(map); ! 1544: } ! 1545: else { ! 1546: vm_map_lock_clear_recursive(map); ! 1547: } ! 1548: } ! 1549: ! 1550: vm_map_unlock(map); ! 1551: ! 1552: return(KERN_SUCCESS); ! 1553: } ! 1554: ! 1555: /* ! 1556: * vm_map_entry_delete: [ internal use only ] ! 1557: * ! 1558: * Deallocate the given entry from the target map. ! 1559: */ ! 1560: void vm_map_entry_delete(map, entry) ! 1561: register vm_map_t map; ! 1562: register vm_map_entry_t entry; ! 1563: { ! 1564: register vm_offset_t s, e; ! 1565: register vm_object_t object; ! 1566: extern vm_object_t kernel_object; ! 1567: ! 1568: s = entry->vme_start; ! 1569: e = entry->vme_end; ! 1570: ! 1571: /*Check if projected buffer*/ ! 1572: if (map != kernel_map && entry->projected_on != 0) { ! 1573: /*Check if projected kernel entry is persistent; ! 1574: may only manipulate directly if it is*/ ! 1575: if (entry->projected_on->projected_on == 0) ! 1576: entry->wired_count = 0; /*Avoid unwire fault*/ ! 1577: else ! 1578: return; ! 1579: } ! 1580: ! 1581: /* ! 1582: * Get the object. Null objects cannot have pmap entries. ! 1583: */ ! 1584: ! 1585: if ((object = entry->object.vm_object) != VM_OBJECT_NULL) { ! 1586: ! 1587: /* ! 1588: * Unwire before removing addresses from the pmap; ! 1589: * otherwise, unwiring will put the entries back in ! 1590: * the pmap. ! 1591: */ ! 1592: ! 1593: if (entry->wired_count != 0) { ! 1594: vm_fault_unwire(map, entry); ! 1595: entry->wired_count = 0; ! 1596: entry->user_wired_count = 0; ! 1597: } ! 1598: ! 1599: /* ! 1600: * If the object is shared, we must remove ! 1601: * *all* references to this data, since we can't ! 1602: * find all of the physical maps which are sharing ! 1603: * it. ! 1604: */ ! 1605: ! 1606: if (object == kernel_object) { ! 1607: vm_object_lock(object); ! 1608: vm_object_page_remove(object, entry->offset, ! 1609: entry->offset + (e - s)); ! 1610: vm_object_unlock(object); ! 1611: } else if (entry->is_shared) { ! 1612: vm_object_pmap_remove(object, ! 1613: entry->offset, ! 1614: entry->offset + (e - s)); ! 1615: } ! 1616: else { ! 1617: pmap_remove(map->pmap, s, e); ! 1618: } ! 1619: } ! 1620: ! 1621: /* ! 1622: * Deallocate the object only after removing all ! 1623: * pmap entries pointing to its pages. ! 1624: */ ! 1625: ! 1626: if (entry->is_sub_map) ! 1627: vm_map_deallocate(entry->object.sub_map); ! 1628: else ! 1629: vm_object_deallocate(entry->object.vm_object); ! 1630: ! 1631: vm_map_entry_unlink(map, entry); ! 1632: map->size -= e - s; ! 1633: ! 1634: vm_map_entry_dispose(map, entry); ! 1635: } ! 1636: ! 1637: /* ! 1638: * vm_map_delete: [ internal use only ] ! 1639: * ! 1640: * Deallocates the given address range from the target ! 1641: * map. ! 1642: */ ! 1643: ! 1644: kern_return_t vm_map_delete(map, start, end) ! 1645: register vm_map_t map; ! 1646: register vm_offset_t start; ! 1647: register vm_offset_t end; ! 1648: { ! 1649: vm_map_entry_t entry; ! 1650: vm_map_entry_t first_entry; ! 1651: ! 1652: /* ! 1653: * Find the start of the region, and clip it ! 1654: */ ! 1655: ! 1656: if (!vm_map_lookup_entry(map, start, &first_entry)) ! 1657: entry = first_entry->vme_next; ! 1658: else { ! 1659: entry = first_entry; ! 1660: #if NORMA_IPC_xxx ! 1661: /* ! 1662: * XXX Had to disable this code because: ! 1663: ! 1664: _vm_map_delete(c0804b78,c2198000,c219a000,0,c219a000)+df ! 1665: [vm/vm_map.c:2007] ! 1666: _vm_map_remove(c0804b78,c2198000,c219a000,c0817834, ! 1667: c081786c)+42 [vm/vm_map.c:2094] ! 1668: _kmem_io_map_deallocate(c0804b78,c2198000,2000,c0817834, ! 1669: c081786c)+43 [vm/vm_kern.c:818] ! 1670: _device_write_dealloc(c081786c)+117 [device/ds_routines.c:814] ! 1671: _ds_write_done(c081786c,0)+2e [device/ds_routines.c:848] ! 1672: _io_done_thread_continue(c08150c0,c21d4e14,c21d4e30,c08150c0, ! 1673: c080c114)+14 [device/ds_routines.c:1350] ! 1674: ! 1675: */ ! 1676: if (start > entry->vme_start ! 1677: && end == entry->vme_end ! 1678: && ! entry->wired_count /* XXX ??? */ ! 1679: && ! entry->is_shared ! 1680: && ! entry->projected_on ! 1681: && ! entry->is_sub_map) { ! 1682: extern vm_object_t kernel_object; ! 1683: register vm_object_t object = entry->object.vm_object; ! 1684: ! 1685: /* ! 1686: * The region to be deleted lives at the end ! 1687: * of this entry, and thus all we have to do is ! 1688: * truncate the entry. ! 1689: * ! 1690: * This special case is necessary if we want ! 1691: * coalescing to do us any good. ! 1692: * ! 1693: * XXX Do we have to adjust object size? ! 1694: */ ! 1695: if (object == kernel_object) { ! 1696: vm_object_lock(object); ! 1697: vm_object_page_remove(object, ! 1698: entry->offset + start, ! 1699: entry->offset + ! 1700: (end - start)); ! 1701: vm_object_unlock(object); ! 1702: } else if (entry->is_shared) { ! 1703: vm_object_pmap_remove(object, ! 1704: entry->offset + start, ! 1705: entry->offset + ! 1706: (end - start)); ! 1707: } else { ! 1708: pmap_remove(map->pmap, start, end); ! 1709: } ! 1710: object->size -= (end - start); /* XXX */ ! 1711: ! 1712: entry->vme_end = start; ! 1713: map->size -= (end - start); ! 1714: ! 1715: if (map->wait_for_space) { ! 1716: thread_wakeup((event_t) map); ! 1717: } ! 1718: return KERN_SUCCESS; ! 1719: } ! 1720: #endif /* NORMA_IPC */ ! 1721: vm_map_clip_start(map, entry, start); ! 1722: ! 1723: /* ! 1724: * Fix the lookup hint now, rather than each ! 1725: * time though the loop. ! 1726: */ ! 1727: ! 1728: SAVE_HINT(map, entry->vme_prev); ! 1729: } ! 1730: ! 1731: /* ! 1732: * Save the free space hint ! 1733: */ ! 1734: ! 1735: if (map->first_free->vme_start >= start) ! 1736: map->first_free = entry->vme_prev; ! 1737: ! 1738: /* ! 1739: * Step through all entries in this region ! 1740: */ ! 1741: ! 1742: while ((entry != vm_map_to_entry(map)) && (entry->vme_start < end)) { ! 1743: vm_map_entry_t next; ! 1744: ! 1745: vm_map_clip_end(map, entry, end); ! 1746: ! 1747: /* ! 1748: * If the entry is in transition, we must wait ! 1749: * for it to exit that state. It could be clipped ! 1750: * while we leave the map unlocked. ! 1751: */ ! 1752: if(entry->in_transition) { ! 1753: /* ! 1754: * Say that we are waiting, and wait for entry. ! 1755: */ ! 1756: entry->needs_wakeup = TRUE; ! 1757: vm_map_entry_wait(map, FALSE); ! 1758: vm_map_lock(map); ! 1759: ! 1760: /* ! 1761: * The entry could have been clipped or it ! 1762: * may not exist anymore. look it up again. ! 1763: */ ! 1764: if(!vm_map_lookup_entry(map, start, &entry)) { ! 1765: entry = entry->vme_next; ! 1766: } ! 1767: continue; ! 1768: } ! 1769: ! 1770: next = entry->vme_next; ! 1771: ! 1772: vm_map_entry_delete(map, entry); ! 1773: entry = next; ! 1774: } ! 1775: ! 1776: if (map->wait_for_space) ! 1777: thread_wakeup((event_t) map); ! 1778: ! 1779: return(KERN_SUCCESS); ! 1780: } ! 1781: ! 1782: /* ! 1783: * vm_map_remove: ! 1784: * ! 1785: * Remove the given address range from the target map. ! 1786: * This is the exported form of vm_map_delete. ! 1787: */ ! 1788: kern_return_t vm_map_remove(map, start, end) ! 1789: register vm_map_t map; ! 1790: register vm_offset_t start; ! 1791: register vm_offset_t end; ! 1792: { ! 1793: register kern_return_t result; ! 1794: ! 1795: vm_map_lock(map); ! 1796: VM_MAP_RANGE_CHECK(map, start, end); ! 1797: result = vm_map_delete(map, start, end); ! 1798: vm_map_unlock(map); ! 1799: ! 1800: return(result); ! 1801: } ! 1802: ! 1803: ! 1804: /* ! 1805: * vm_map_copy_steal_pages: ! 1806: * ! 1807: * Steal all the pages from a vm_map_copy page_list by copying ones ! 1808: * that have not already been stolen. ! 1809: */ ! 1810: void ! 1811: vm_map_copy_steal_pages(copy) ! 1812: vm_map_copy_t copy; ! 1813: { ! 1814: register vm_page_t m, new_m; ! 1815: register int i; ! 1816: vm_object_t object; ! 1817: ! 1818: for (i = 0; i < copy->cpy_npages; i++) { ! 1819: ! 1820: /* ! 1821: * If the page is not tabled, then it's already stolen. ! 1822: */ ! 1823: m = copy->cpy_page_list[i]; ! 1824: if (!m->tabled) ! 1825: continue; ! 1826: ! 1827: /* ! 1828: * Page was not stolen, get a new ! 1829: * one and do the copy now. ! 1830: */ ! 1831: while ((new_m = vm_page_grab(FALSE)) == VM_PAGE_NULL) { ! 1832: VM_PAGE_WAIT((void(*)()) 0); ! 1833: } ! 1834: ! 1835: vm_page_copy(m, new_m); ! 1836: ! 1837: object = m->object; ! 1838: vm_object_lock(object); ! 1839: vm_page_lock_queues(); ! 1840: if (!m->active && !m->inactive) ! 1841: vm_page_activate(m); ! 1842: vm_page_unlock_queues(); ! 1843: PAGE_WAKEUP_DONE(m); ! 1844: vm_object_paging_end(object); ! 1845: vm_object_unlock(object); ! 1846: ! 1847: copy->cpy_page_list[i] = new_m; ! 1848: } ! 1849: } ! 1850: ! 1851: /* ! 1852: * vm_map_copy_page_discard: ! 1853: * ! 1854: * Get rid of the pages in a page_list copy. If the pages are ! 1855: * stolen, they are freed. If the pages are not stolen, they ! 1856: * are unbusied, and associated state is cleaned up. ! 1857: */ ! 1858: void vm_map_copy_page_discard(copy) ! 1859: vm_map_copy_t copy; ! 1860: { ! 1861: while (copy->cpy_npages > 0) { ! 1862: vm_page_t m; ! 1863: ! 1864: if((m = copy->cpy_page_list[--(copy->cpy_npages)]) != ! 1865: VM_PAGE_NULL) { ! 1866: ! 1867: /* ! 1868: * If it's not in the table, then it's ! 1869: * a stolen page that goes back ! 1870: * to the free list. Else it belongs ! 1871: * to some object, and we hold a ! 1872: * paging reference on that object. ! 1873: */ ! 1874: if (!m->tabled) { ! 1875: VM_PAGE_FREE(m); ! 1876: } ! 1877: else { ! 1878: vm_object_t object; ! 1879: ! 1880: object = m->object; ! 1881: ! 1882: vm_object_lock(object); ! 1883: vm_page_lock_queues(); ! 1884: if (!m->active && !m->inactive) ! 1885: vm_page_activate(m); ! 1886: vm_page_unlock_queues(); ! 1887: ! 1888: PAGE_WAKEUP_DONE(m); ! 1889: vm_object_paging_end(object); ! 1890: vm_object_unlock(object); ! 1891: } ! 1892: } ! 1893: } ! 1894: } ! 1895: ! 1896: /* ! 1897: * Routine: vm_map_copy_discard ! 1898: * ! 1899: * Description: ! 1900: * Dispose of a map copy object (returned by ! 1901: * vm_map_copyin). ! 1902: */ ! 1903: void ! 1904: vm_map_copy_discard(copy) ! 1905: vm_map_copy_t copy; ! 1906: { ! 1907: free_next_copy: ! 1908: if (copy == VM_MAP_COPY_NULL) ! 1909: return; ! 1910: ! 1911: switch (copy->type) { ! 1912: case VM_MAP_COPY_ENTRY_LIST: ! 1913: while (vm_map_copy_first_entry(copy) != ! 1914: vm_map_copy_to_entry(copy)) { ! 1915: vm_map_entry_t entry = vm_map_copy_first_entry(copy); ! 1916: ! 1917: vm_map_copy_entry_unlink(copy, entry); ! 1918: vm_object_deallocate(entry->object.vm_object); ! 1919: vm_map_copy_entry_dispose(copy, entry); ! 1920: } ! 1921: break; ! 1922: case VM_MAP_COPY_OBJECT: ! 1923: vm_object_deallocate(copy->cpy_object); ! 1924: break; ! 1925: case VM_MAP_COPY_PAGE_LIST: ! 1926: ! 1927: /* ! 1928: * To clean this up, we have to unbusy all the pages ! 1929: * and release the paging references in their objects. ! 1930: */ ! 1931: if (copy->cpy_npages > 0) ! 1932: vm_map_copy_page_discard(copy); ! 1933: ! 1934: /* ! 1935: * If there's a continuation, abort it. The ! 1936: * abort routine releases any storage. ! 1937: */ ! 1938: if (vm_map_copy_has_cont(copy)) { ! 1939: ! 1940: /* ! 1941: * Special case: recognize ! 1942: * vm_map_copy_discard_cont and optimize ! 1943: * here to avoid tail recursion. ! 1944: */ ! 1945: if (copy->cpy_cont == vm_map_copy_discard_cont) { ! 1946: register vm_map_copy_t new_copy; ! 1947: ! 1948: new_copy = (vm_map_copy_t) copy->cpy_cont_args; ! 1949: zfree(vm_map_copy_zone, (vm_offset_t) copy); ! 1950: copy = new_copy; ! 1951: goto free_next_copy; ! 1952: } ! 1953: else { ! 1954: vm_map_copy_abort_cont(copy); ! 1955: } ! 1956: } ! 1957: ! 1958: break; ! 1959: } ! 1960: zfree(vm_map_copy_zone, (vm_offset_t) copy); ! 1961: } ! 1962: ! 1963: /* ! 1964: * Routine: vm_map_copy_copy ! 1965: * ! 1966: * Description: ! 1967: * Move the information in a map copy object to ! 1968: * a new map copy object, leaving the old one ! 1969: * empty. ! 1970: * ! 1971: * This is used by kernel routines that need ! 1972: * to look at out-of-line data (in copyin form) ! 1973: * before deciding whether to return SUCCESS. ! 1974: * If the routine returns FAILURE, the original ! 1975: * copy object will be deallocated; therefore, ! 1976: * these routines must make a copy of the copy ! 1977: * object and leave the original empty so that ! 1978: * deallocation will not fail. ! 1979: */ ! 1980: vm_map_copy_t ! 1981: vm_map_copy_copy(copy) ! 1982: vm_map_copy_t copy; ! 1983: { ! 1984: vm_map_copy_t new_copy; ! 1985: ! 1986: if (copy == VM_MAP_COPY_NULL) ! 1987: return VM_MAP_COPY_NULL; ! 1988: ! 1989: /* ! 1990: * Allocate a new copy object, and copy the information ! 1991: * from the old one into it. ! 1992: */ ! 1993: ! 1994: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 1995: *new_copy = *copy; ! 1996: ! 1997: if (copy->type == VM_MAP_COPY_ENTRY_LIST) { ! 1998: /* ! 1999: * The links in the entry chain must be ! 2000: * changed to point to the new copy object. ! 2001: */ ! 2002: vm_map_copy_first_entry(copy)->vme_prev ! 2003: = vm_map_copy_to_entry(new_copy); ! 2004: vm_map_copy_last_entry(copy)->vme_next ! 2005: = vm_map_copy_to_entry(new_copy); ! 2006: } ! 2007: ! 2008: /* ! 2009: * Change the old copy object into one that contains ! 2010: * nothing to be deallocated. ! 2011: */ ! 2012: copy->type = VM_MAP_COPY_OBJECT; ! 2013: copy->cpy_object = VM_OBJECT_NULL; ! 2014: ! 2015: /* ! 2016: * Return the new object. ! 2017: */ ! 2018: return new_copy; ! 2019: } ! 2020: ! 2021: /* ! 2022: * Routine: vm_map_copy_discard_cont ! 2023: * ! 2024: * Description: ! 2025: * A version of vm_map_copy_discard that can be called ! 2026: * as a continuation from a vm_map_copy page list. ! 2027: */ ! 2028: kern_return_t vm_map_copy_discard_cont(cont_args, copy_result) ! 2029: vm_map_copyin_args_t cont_args; ! 2030: vm_map_copy_t *copy_result; /* OUT */ ! 2031: { ! 2032: vm_map_copy_discard((vm_map_copy_t) cont_args); ! 2033: if (copy_result != (vm_map_copy_t *)0) ! 2034: *copy_result = VM_MAP_COPY_NULL; ! 2035: return(KERN_SUCCESS); ! 2036: } ! 2037: ! 2038: /* ! 2039: * Routine: vm_map_copy_overwrite ! 2040: * ! 2041: * Description: ! 2042: * Copy the memory described by the map copy ! 2043: * object (copy; returned by vm_map_copyin) onto ! 2044: * the specified destination region (dst_map, dst_addr). ! 2045: * The destination must be writeable. ! 2046: * ! 2047: * Unlike vm_map_copyout, this routine actually ! 2048: * writes over previously-mapped memory. If the ! 2049: * previous mapping was to a permanent (user-supplied) ! 2050: * memory object, it is preserved. ! 2051: * ! 2052: * The attributes (protection and inheritance) of the ! 2053: * destination region are preserved. ! 2054: * ! 2055: * If successful, consumes the copy object. ! 2056: * Otherwise, the caller is responsible for it. ! 2057: * ! 2058: * Implementation notes: ! 2059: * To overwrite temporary virtual memory, it is ! 2060: * sufficient to remove the previous mapping and insert ! 2061: * the new copy. This replacement is done either on ! 2062: * the whole region (if no permanent virtual memory ! 2063: * objects are embedded in the destination region) or ! 2064: * in individual map entries. ! 2065: * ! 2066: * To overwrite permanent virtual memory, it is ! 2067: * necessary to copy each page, as the external ! 2068: * memory management interface currently does not ! 2069: * provide any optimizations. ! 2070: * ! 2071: * Once a page of permanent memory has been overwritten, ! 2072: * it is impossible to interrupt this function; otherwise, ! 2073: * the call would be neither atomic nor location-independent. ! 2074: * The kernel-state portion of a user thread must be ! 2075: * interruptible. ! 2076: * ! 2077: * It may be expensive to forward all requests that might ! 2078: * overwrite permanent memory (vm_write, vm_copy) to ! 2079: * uninterruptible kernel threads. This routine may be ! 2080: * called by interruptible threads; however, success is ! 2081: * not guaranteed -- if the request cannot be performed ! 2082: * atomically and interruptibly, an error indication is ! 2083: * returned. ! 2084: */ ! 2085: kern_return_t vm_map_copy_overwrite(dst_map, dst_addr, copy, interruptible) ! 2086: vm_map_t dst_map; ! 2087: vm_offset_t dst_addr; ! 2088: vm_map_copy_t copy; ! 2089: boolean_t interruptible; ! 2090: { ! 2091: vm_size_t size; ! 2092: vm_offset_t start; ! 2093: vm_map_entry_t tmp_entry; ! 2094: vm_map_entry_t entry; ! 2095: ! 2096: boolean_t contains_permanent_objects = FALSE; ! 2097: ! 2098: interruptible = FALSE; /* XXX */ ! 2099: ! 2100: /* ! 2101: * Check for null copy object. ! 2102: */ ! 2103: ! 2104: if (copy == VM_MAP_COPY_NULL) ! 2105: return(KERN_SUCCESS); ! 2106: ! 2107: /* ! 2108: * Only works for entry lists at the moment. Will ! 2109: * support page lists LATER. ! 2110: */ ! 2111: ! 2112: #if NORMA_IPC ! 2113: vm_map_convert_from_page_list(copy); ! 2114: #else ! 2115: assert(copy->type == VM_MAP_COPY_ENTRY_LIST); ! 2116: #endif ! 2117: ! 2118: /* ! 2119: * Currently this routine only handles page-aligned ! 2120: * regions. Eventually, it should handle misalignments ! 2121: * by actually copying pages. ! 2122: */ ! 2123: ! 2124: if (!page_aligned(copy->offset) || ! 2125: !page_aligned(copy->size) || ! 2126: !page_aligned(dst_addr)) ! 2127: return(KERN_INVALID_ARGUMENT); ! 2128: ! 2129: size = copy->size; ! 2130: ! 2131: if (size == 0) { ! 2132: vm_map_copy_discard(copy); ! 2133: return(KERN_SUCCESS); ! 2134: } ! 2135: ! 2136: /* ! 2137: * Verify that the destination is all writeable ! 2138: * initially. ! 2139: */ ! 2140: start_pass_1: ! 2141: vm_map_lock(dst_map); ! 2142: if (!vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry)) { ! 2143: vm_map_unlock(dst_map); ! 2144: return(KERN_INVALID_ADDRESS); ! 2145: } ! 2146: vm_map_clip_start(dst_map, tmp_entry, dst_addr); ! 2147: for (entry = tmp_entry;;) { ! 2148: vm_size_t sub_size = (entry->vme_end - entry->vme_start); ! 2149: vm_map_entry_t next = entry->vme_next; ! 2150: ! 2151: if ( ! (entry->protection & VM_PROT_WRITE)) { ! 2152: vm_map_unlock(dst_map); ! 2153: return(KERN_PROTECTION_FAILURE); ! 2154: } ! 2155: ! 2156: /* ! 2157: * If the entry is in transition, we must wait ! 2158: * for it to exit that state. Anything could happen ! 2159: * when we unlock the map, so start over. ! 2160: */ ! 2161: if (entry->in_transition) { ! 2162: ! 2163: /* ! 2164: * Say that we are waiting, and wait for entry. ! 2165: */ ! 2166: entry->needs_wakeup = TRUE; ! 2167: vm_map_entry_wait(dst_map, FALSE); ! 2168: ! 2169: goto start_pass_1; ! 2170: } ! 2171: ! 2172: if (size <= sub_size) ! 2173: break; ! 2174: ! 2175: if ((next == vm_map_to_entry(dst_map)) || ! 2176: (next->vme_start != entry->vme_end)) { ! 2177: vm_map_unlock(dst_map); ! 2178: return(KERN_INVALID_ADDRESS); ! 2179: } ! 2180: ! 2181: ! 2182: /* ! 2183: * Check for permanent objects in the destination. ! 2184: */ ! 2185: ! 2186: if ((entry->object.vm_object != VM_OBJECT_NULL) && ! 2187: !entry->object.vm_object->temporary) ! 2188: contains_permanent_objects = TRUE; ! 2189: ! 2190: size -= sub_size; ! 2191: entry = next; ! 2192: } ! 2193: ! 2194: /* ! 2195: * If there are permanent objects in the destination, then ! 2196: * the copy cannot be interrupted. ! 2197: */ ! 2198: ! 2199: if (interruptible && contains_permanent_objects) ! 2200: return(KERN_FAILURE); /* XXX */ ! 2201: ! 2202: /* ! 2203: * XXXO If there are no permanent objects in the destination, ! 2204: * XXXO and the source and destination map entry zones match, ! 2205: * XXXO and the destination map entry is not shared, ! 2206: * XXXO then the map entries can be deleted and replaced ! 2207: * XXXO with those from the copy. The following code is the ! 2208: * XXXO basic idea of what to do, but there are lots of annoying ! 2209: * XXXO little details about getting protection and inheritance ! 2210: * XXXO right. Should add protection, inheritance, and sharing checks ! 2211: * XXXO to the above pass and make sure that no wiring is involved. ! 2212: */ ! 2213: /* ! 2214: * if (!contains_permanent_objects && ! 2215: * copy->cpy_hdr.entries_pageable == dst_map->hdr.entries_pageable) { ! 2216: * ! 2217: * * ! 2218: * * Run over copy and adjust entries. Steal code ! 2219: * * from vm_map_copyout() to do this. ! 2220: * * ! 2221: * ! 2222: * tmp_entry = tmp_entry->vme_prev; ! 2223: * vm_map_delete(dst_map, dst_addr, dst_addr + copy->size); ! 2224: * vm_map_copy_insert(dst_map, tmp_entry, copy); ! 2225: * ! 2226: * vm_map_unlock(dst_map); ! 2227: * vm_map_copy_discard(copy); ! 2228: * } ! 2229: */ ! 2230: /* ! 2231: * ! 2232: * Make a second pass, overwriting the data ! 2233: * At the beginning of each loop iteration, ! 2234: * the next entry to be overwritten is "tmp_entry" ! 2235: * (initially, the value returned from the lookup above), ! 2236: * and the starting address expected in that entry ! 2237: * is "start". ! 2238: */ ! 2239: ! 2240: start = dst_addr; ! 2241: ! 2242: while (vm_map_copy_first_entry(copy) != vm_map_copy_to_entry(copy)) { ! 2243: vm_map_entry_t copy_entry = vm_map_copy_first_entry(copy); ! 2244: vm_size_t copy_size = (copy_entry->vme_end - copy_entry->vme_start); ! 2245: vm_object_t object; ! 2246: ! 2247: entry = tmp_entry; ! 2248: size = (entry->vme_end - entry->vme_start); ! 2249: /* ! 2250: * Make sure that no holes popped up in the ! 2251: * address map, and that the protection is ! 2252: * still valid, in case the map was unlocked ! 2253: * earlier. ! 2254: */ ! 2255: ! 2256: if (entry->vme_start != start) { ! 2257: vm_map_unlock(dst_map); ! 2258: return(KERN_INVALID_ADDRESS); ! 2259: } ! 2260: assert(entry != vm_map_to_entry(dst_map)); ! 2261: ! 2262: /* ! 2263: * Check protection again ! 2264: */ ! 2265: ! 2266: if ( ! (entry->protection & VM_PROT_WRITE)) { ! 2267: vm_map_unlock(dst_map); ! 2268: return(KERN_PROTECTION_FAILURE); ! 2269: } ! 2270: ! 2271: /* ! 2272: * Adjust to source size first ! 2273: */ ! 2274: ! 2275: if (copy_size < size) { ! 2276: vm_map_clip_end(dst_map, entry, entry->vme_start + copy_size); ! 2277: size = copy_size; ! 2278: } ! 2279: ! 2280: /* ! 2281: * Adjust to destination size ! 2282: */ ! 2283: ! 2284: if (size < copy_size) { ! 2285: vm_map_copy_clip_end(copy, copy_entry, ! 2286: copy_entry->vme_start + size); ! 2287: copy_size = size; ! 2288: } ! 2289: ! 2290: assert((entry->vme_end - entry->vme_start) == size); ! 2291: assert((tmp_entry->vme_end - tmp_entry->vme_start) == size); ! 2292: assert((copy_entry->vme_end - copy_entry->vme_start) == size); ! 2293: ! 2294: /* ! 2295: * If the destination contains temporary unshared memory, ! 2296: * we can perform the copy by throwing it away and ! 2297: * installing the source data. ! 2298: */ ! 2299: ! 2300: object = entry->object.vm_object; ! 2301: if (!entry->is_shared && ! 2302: ((object == VM_OBJECT_NULL) || object->temporary)) { ! 2303: vm_object_t old_object = entry->object.vm_object; ! 2304: vm_offset_t old_offset = entry->offset; ! 2305: ! 2306: entry->object = copy_entry->object; ! 2307: entry->offset = copy_entry->offset; ! 2308: entry->needs_copy = copy_entry->needs_copy; ! 2309: entry->wired_count = 0; ! 2310: entry->user_wired_count = 0; ! 2311: ! 2312: vm_map_copy_entry_unlink(copy, copy_entry); ! 2313: vm_map_copy_entry_dispose(copy, copy_entry); ! 2314: ! 2315: vm_object_pmap_protect( ! 2316: old_object, ! 2317: old_offset, ! 2318: size, ! 2319: dst_map->pmap, ! 2320: tmp_entry->vme_start, ! 2321: VM_PROT_NONE); ! 2322: ! 2323: vm_object_deallocate(old_object); ! 2324: ! 2325: /* ! 2326: * Set up for the next iteration. The map ! 2327: * has not been unlocked, so the next ! 2328: * address should be at the end of this ! 2329: * entry, and the next map entry should be ! 2330: * the one following it. ! 2331: */ ! 2332: ! 2333: start = tmp_entry->vme_end; ! 2334: tmp_entry = tmp_entry->vme_next; ! 2335: } else { ! 2336: vm_map_version_t version; ! 2337: vm_object_t dst_object = entry->object.vm_object; ! 2338: vm_offset_t dst_offset = entry->offset; ! 2339: kern_return_t r; ! 2340: ! 2341: /* ! 2342: * Take an object reference, and record ! 2343: * the map version information so that the ! 2344: * map can be safely unlocked. ! 2345: */ ! 2346: ! 2347: vm_object_reference(dst_object); ! 2348: ! 2349: version.main_timestamp = dst_map->timestamp; ! 2350: ! 2351: vm_map_unlock(dst_map); ! 2352: ! 2353: /* ! 2354: * Copy as much as possible in one pass ! 2355: */ ! 2356: ! 2357: copy_size = size; ! 2358: r = vm_fault_copy( ! 2359: copy_entry->object.vm_object, ! 2360: copy_entry->offset, ! 2361: ©_size, ! 2362: dst_object, ! 2363: dst_offset, ! 2364: dst_map, ! 2365: &version, ! 2366: FALSE /* XXX interruptible */ ); ! 2367: ! 2368: /* ! 2369: * Release the object reference ! 2370: */ ! 2371: ! 2372: vm_object_deallocate(dst_object); ! 2373: ! 2374: /* ! 2375: * If a hard error occurred, return it now ! 2376: */ ! 2377: ! 2378: if (r != KERN_SUCCESS) ! 2379: return(r); ! 2380: ! 2381: if (copy_size != 0) { ! 2382: /* ! 2383: * Dispose of the copied region ! 2384: */ ! 2385: ! 2386: vm_map_copy_clip_end(copy, copy_entry, ! 2387: copy_entry->vme_start + copy_size); ! 2388: vm_map_copy_entry_unlink(copy, copy_entry); ! 2389: vm_object_deallocate(copy_entry->object.vm_object); ! 2390: vm_map_copy_entry_dispose(copy, copy_entry); ! 2391: } ! 2392: ! 2393: /* ! 2394: * Pick up in the destination map where we left off. ! 2395: * ! 2396: * Use the version information to avoid a lookup ! 2397: * in the normal case. ! 2398: */ ! 2399: ! 2400: start += copy_size; ! 2401: vm_map_lock(dst_map); ! 2402: if ((version.main_timestamp + 1) == dst_map->timestamp) { ! 2403: /* We can safely use saved tmp_entry value */ ! 2404: ! 2405: vm_map_clip_end(dst_map, tmp_entry, start); ! 2406: tmp_entry = tmp_entry->vme_next; ! 2407: } else { ! 2408: /* Must do lookup of tmp_entry */ ! 2409: ! 2410: if (!vm_map_lookup_entry(dst_map, start, &tmp_entry)) { ! 2411: vm_map_unlock(dst_map); ! 2412: return(KERN_INVALID_ADDRESS); ! 2413: } ! 2414: vm_map_clip_start(dst_map, tmp_entry, start); ! 2415: } ! 2416: } ! 2417: ! 2418: } ! 2419: vm_map_unlock(dst_map); ! 2420: ! 2421: /* ! 2422: * Throw away the vm_map_copy object ! 2423: */ ! 2424: vm_map_copy_discard(copy); ! 2425: ! 2426: return(KERN_SUCCESS); ! 2427: } ! 2428: ! 2429: /* ! 2430: * Macro: vm_map_copy_insert ! 2431: * ! 2432: * Description: ! 2433: * Link a copy chain ("copy") into a map at the ! 2434: * specified location (after "where"). ! 2435: * Side effects: ! 2436: * The copy chain is destroyed. ! 2437: * Warning: ! 2438: * The arguments are evaluated multiple times. ! 2439: */ ! 2440: #define vm_map_copy_insert(map, where, copy) \ ! 2441: MACRO_BEGIN \ ! 2442: (((where)->vme_next)->vme_prev = vm_map_copy_last_entry(copy)) \ ! 2443: ->vme_next = ((where)->vme_next); \ ! 2444: ((where)->vme_next = vm_map_copy_first_entry(copy)) \ ! 2445: ->vme_prev = (where); \ ! 2446: (map)->hdr.nentries += (copy)->cpy_hdr.nentries; \ ! 2447: zfree(vm_map_copy_zone, (vm_offset_t) copy); \ ! 2448: MACRO_END ! 2449: ! 2450: /* ! 2451: * Routine: vm_map_copyout ! 2452: * ! 2453: * Description: ! 2454: * Copy out a copy chain ("copy") into newly-allocated ! 2455: * space in the destination map. ! 2456: * ! 2457: * If successful, consumes the copy object. ! 2458: * Otherwise, the caller is responsible for it. ! 2459: */ ! 2460: kern_return_t vm_map_copyout(dst_map, dst_addr, copy) ! 2461: register ! 2462: vm_map_t dst_map; ! 2463: vm_offset_t *dst_addr; /* OUT */ ! 2464: register ! 2465: vm_map_copy_t copy; ! 2466: { ! 2467: vm_size_t size; ! 2468: vm_size_t adjustment; ! 2469: vm_offset_t start; ! 2470: vm_offset_t vm_copy_start; ! 2471: vm_map_entry_t last; ! 2472: register ! 2473: vm_map_entry_t entry; ! 2474: ! 2475: /* ! 2476: * Check for null copy object. ! 2477: */ ! 2478: ! 2479: if (copy == VM_MAP_COPY_NULL) { ! 2480: *dst_addr = 0; ! 2481: return(KERN_SUCCESS); ! 2482: } ! 2483: ! 2484: /* ! 2485: * Check for special copy object, created ! 2486: * by vm_map_copyin_object. ! 2487: */ ! 2488: ! 2489: if (copy->type == VM_MAP_COPY_OBJECT) { ! 2490: vm_object_t object = copy->cpy_object; ! 2491: vm_size_t offset = copy->offset; ! 2492: vm_size_t tmp_size = copy->size; ! 2493: kern_return_t kr; ! 2494: ! 2495: *dst_addr = 0; ! 2496: kr = vm_map_enter(dst_map, dst_addr, tmp_size, ! 2497: (vm_offset_t) 0, TRUE, ! 2498: object, offset, FALSE, ! 2499: VM_PROT_DEFAULT, VM_PROT_ALL, ! 2500: VM_INHERIT_DEFAULT); ! 2501: if (kr != KERN_SUCCESS) ! 2502: return(kr); ! 2503: zfree(vm_map_copy_zone, (vm_offset_t) copy); ! 2504: return(KERN_SUCCESS); ! 2505: } ! 2506: ! 2507: if (copy->type == VM_MAP_COPY_PAGE_LIST) ! 2508: return(vm_map_copyout_page_list(dst_map, dst_addr, copy)); ! 2509: ! 2510: /* ! 2511: * Find space for the data ! 2512: */ ! 2513: ! 2514: vm_copy_start = trunc_page(copy->offset); ! 2515: size = round_page(copy->offset + copy->size) - vm_copy_start; ! 2516: ! 2517: StartAgain: ; ! 2518: ! 2519: vm_map_lock(dst_map); ! 2520: start = ((last = dst_map->first_free) == vm_map_to_entry(dst_map)) ? ! 2521: vm_map_min(dst_map) : last->vme_end; ! 2522: ! 2523: while (TRUE) { ! 2524: vm_map_entry_t next = last->vme_next; ! 2525: vm_offset_t end = start + size; ! 2526: ! 2527: if ((end > dst_map->max_offset) || (end < start)) { ! 2528: if (dst_map->wait_for_space) { ! 2529: if (size <= (dst_map->max_offset - dst_map->min_offset)) { ! 2530: assert_wait((event_t) dst_map, TRUE); ! 2531: vm_map_unlock(dst_map); ! 2532: thread_block((void (*)()) 0); ! 2533: goto StartAgain; ! 2534: } ! 2535: } ! 2536: vm_map_unlock(dst_map); ! 2537: return(KERN_NO_SPACE); ! 2538: } ! 2539: ! 2540: if ((next == vm_map_to_entry(dst_map)) || ! 2541: (next->vme_start >= end)) ! 2542: break; ! 2543: ! 2544: last = next; ! 2545: start = last->vme_end; ! 2546: } ! 2547: ! 2548: /* ! 2549: * Since we're going to just drop the map ! 2550: * entries from the copy into the destination ! 2551: * map, they must come from the same pool. ! 2552: */ ! 2553: ! 2554: if (copy->cpy_hdr.entries_pageable != dst_map->hdr.entries_pageable) { ! 2555: /* ! 2556: * Mismatches occur when dealing with the default ! 2557: * pager. ! 2558: */ ! 2559: zone_t old_zone; ! 2560: vm_map_entry_t next, new; ! 2561: ! 2562: /* ! 2563: * Find the zone that the copies were allocated from ! 2564: */ ! 2565: old_zone = (copy->cpy_hdr.entries_pageable) ! 2566: ? vm_map_entry_zone ! 2567: : vm_map_kentry_zone; ! 2568: entry = vm_map_copy_first_entry(copy); ! 2569: ! 2570: /* ! 2571: * Reinitialize the copy so that vm_map_copy_entry_link ! 2572: * will work. ! 2573: */ ! 2574: copy->cpy_hdr.nentries = 0; ! 2575: copy->cpy_hdr.entries_pageable = dst_map->hdr.entries_pageable; ! 2576: vm_map_copy_first_entry(copy) = ! 2577: vm_map_copy_last_entry(copy) = ! 2578: vm_map_copy_to_entry(copy); ! 2579: ! 2580: /* ! 2581: * Copy each entry. ! 2582: */ ! 2583: while (entry != vm_map_copy_to_entry(copy)) { ! 2584: new = vm_map_copy_entry_create(copy); ! 2585: vm_map_entry_copy_full(new, entry); ! 2586: vm_map_copy_entry_link(copy, ! 2587: vm_map_copy_last_entry(copy), ! 2588: new); ! 2589: next = entry->vme_next; ! 2590: zfree(old_zone, (vm_offset_t) entry); ! 2591: entry = next; ! 2592: } ! 2593: } ! 2594: ! 2595: /* ! 2596: * Adjust the addresses in the copy chain, and ! 2597: * reset the region attributes. ! 2598: */ ! 2599: ! 2600: adjustment = start - vm_copy_start; ! 2601: for (entry = vm_map_copy_first_entry(copy); ! 2602: entry != vm_map_copy_to_entry(copy); ! 2603: entry = entry->vme_next) { ! 2604: entry->vme_start += adjustment; ! 2605: entry->vme_end += adjustment; ! 2606: ! 2607: entry->inheritance = VM_INHERIT_DEFAULT; ! 2608: entry->protection = VM_PROT_DEFAULT; ! 2609: entry->max_protection = VM_PROT_ALL; ! 2610: entry->projected_on = 0; ! 2611: ! 2612: /* ! 2613: * If the entry is now wired, ! 2614: * map the pages into the destination map. ! 2615: */ ! 2616: if (entry->wired_count != 0) { ! 2617: register vm_offset_t va; ! 2618: vm_offset_t offset; ! 2619: register vm_object_t object; ! 2620: ! 2621: object = entry->object.vm_object; ! 2622: offset = entry->offset; ! 2623: va = entry->vme_start; ! 2624: ! 2625: pmap_pageable(dst_map->pmap, ! 2626: entry->vme_start, ! 2627: entry->vme_end, ! 2628: TRUE); ! 2629: ! 2630: while (va < entry->vme_end) { ! 2631: register vm_page_t m; ! 2632: ! 2633: /* ! 2634: * Look up the page in the object. ! 2635: * Assert that the page will be found in the ! 2636: * top object: ! 2637: * either ! 2638: * the object was newly created by ! 2639: * vm_object_copy_slowly, and has ! 2640: * copies of all of the pages from ! 2641: * the source object ! 2642: * or ! 2643: * the object was moved from the old ! 2644: * map entry; because the old map ! 2645: * entry was wired, all of the pages ! 2646: * were in the top-level object. ! 2647: * (XXX not true if we wire pages for ! 2648: * reading) ! 2649: */ ! 2650: vm_object_lock(object); ! 2651: vm_object_paging_begin(object); ! 2652: ! 2653: m = vm_page_lookup(object, offset); ! 2654: if (m == VM_PAGE_NULL || m->wire_count == 0 || ! 2655: m->absent) ! 2656: panic("vm_map_copyout: wiring 0x%x", m); ! 2657: ! 2658: m->busy = TRUE; ! 2659: vm_object_unlock(object); ! 2660: ! 2661: PMAP_ENTER(dst_map->pmap, va, m, ! 2662: entry->protection, TRUE); ! 2663: ! 2664: vm_object_lock(object); ! 2665: PAGE_WAKEUP_DONE(m); ! 2666: /* the page is wired, so we don't have to activate */ ! 2667: vm_object_paging_end(object); ! 2668: vm_object_unlock(object); ! 2669: ! 2670: offset += PAGE_SIZE; ! 2671: va += PAGE_SIZE; ! 2672: } ! 2673: } ! 2674: ! 2675: ! 2676: } ! 2677: ! 2678: /* ! 2679: * Correct the page alignment for the result ! 2680: */ ! 2681: ! 2682: *dst_addr = start + (copy->offset - vm_copy_start); ! 2683: ! 2684: /* ! 2685: * Update the hints and the map size ! 2686: */ ! 2687: ! 2688: if (dst_map->first_free == last) ! 2689: dst_map->first_free = vm_map_copy_last_entry(copy); ! 2690: SAVE_HINT(dst_map, vm_map_copy_last_entry(copy)); ! 2691: ! 2692: dst_map->size += size; ! 2693: ! 2694: /* ! 2695: * Link in the copy ! 2696: */ ! 2697: ! 2698: vm_map_copy_insert(dst_map, last, copy); ! 2699: ! 2700: vm_map_unlock(dst_map); ! 2701: ! 2702: /* ! 2703: * XXX If wiring_required, call vm_map_pageable ! 2704: */ ! 2705: ! 2706: return(KERN_SUCCESS); ! 2707: } ! 2708: ! 2709: /* ! 2710: * ! 2711: * vm_map_copyout_page_list: ! 2712: * ! 2713: * Version of vm_map_copyout() for page list vm map copies. ! 2714: * ! 2715: */ ! 2716: kern_return_t vm_map_copyout_page_list(dst_map, dst_addr, copy) ! 2717: register ! 2718: vm_map_t dst_map; ! 2719: vm_offset_t *dst_addr; /* OUT */ ! 2720: register ! 2721: vm_map_copy_t copy; ! 2722: { ! 2723: vm_size_t size; ! 2724: vm_offset_t start; ! 2725: vm_offset_t end; ! 2726: vm_offset_t offset; ! 2727: vm_map_entry_t last; ! 2728: register ! 2729: vm_object_t object; ! 2730: vm_page_t *page_list, m; ! 2731: vm_map_entry_t entry; ! 2732: vm_offset_t old_last_offset; ! 2733: boolean_t cont_invoked, needs_wakeup = FALSE; ! 2734: kern_return_t result = KERN_SUCCESS; ! 2735: vm_map_copy_t orig_copy; ! 2736: vm_offset_t dst_offset; ! 2737: boolean_t must_wire; ! 2738: ! 2739: /* ! 2740: * Make sure the pages are stolen, because we are ! 2741: * going to put them in a new object. Assume that ! 2742: * all pages are identical to first in this regard. ! 2743: */ ! 2744: ! 2745: page_list = ©->cpy_page_list[0]; ! 2746: if ((*page_list)->tabled) ! 2747: vm_map_copy_steal_pages(copy); ! 2748: ! 2749: /* ! 2750: * Find space for the data ! 2751: */ ! 2752: ! 2753: size = round_page(copy->offset + copy->size) - ! 2754: trunc_page(copy->offset); ! 2755: StartAgain: ! 2756: vm_map_lock(dst_map); ! 2757: must_wire = dst_map->wiring_required; ! 2758: ! 2759: last = dst_map->first_free; ! 2760: if (last == vm_map_to_entry(dst_map)) { ! 2761: start = vm_map_min(dst_map); ! 2762: } else { ! 2763: start = last->vme_end; ! 2764: } ! 2765: ! 2766: while (TRUE) { ! 2767: vm_map_entry_t next = last->vme_next; ! 2768: end = start + size; ! 2769: ! 2770: if ((end > dst_map->max_offset) || (end < start)) { ! 2771: if (dst_map->wait_for_space) { ! 2772: if (size <= (dst_map->max_offset - ! 2773: dst_map->min_offset)) { ! 2774: assert_wait((event_t) dst_map, TRUE); ! 2775: vm_map_unlock(dst_map); ! 2776: thread_block((void (*)()) 0); ! 2777: goto StartAgain; ! 2778: } ! 2779: } ! 2780: vm_map_unlock(dst_map); ! 2781: return(KERN_NO_SPACE); ! 2782: } ! 2783: ! 2784: if ((next == vm_map_to_entry(dst_map)) || ! 2785: (next->vme_start >= end)) { ! 2786: break; ! 2787: } ! 2788: ! 2789: last = next; ! 2790: start = last->vme_end; ! 2791: } ! 2792: ! 2793: /* ! 2794: * See whether we can avoid creating a new entry (and object) by ! 2795: * extending one of our neighbors. [So far, we only attempt to ! 2796: * extend from below.] ! 2797: * ! 2798: * The code path below here is a bit twisted. If any of the ! 2799: * extension checks fails, we branch to create_object. If ! 2800: * it all works, we fall out the bottom and goto insert_pages. ! 2801: */ ! 2802: if (last == vm_map_to_entry(dst_map) || ! 2803: last->vme_end != start || ! 2804: last->is_shared != FALSE || ! 2805: last->is_sub_map != FALSE || ! 2806: last->inheritance != VM_INHERIT_DEFAULT || ! 2807: last->protection != VM_PROT_DEFAULT || ! 2808: last->max_protection != VM_PROT_ALL || ! 2809: (must_wire ? (last->wired_count != 1 || ! 2810: last->user_wired_count != 1) : ! 2811: (last->wired_count != 0))) { ! 2812: goto create_object; ! 2813: } ! 2814: ! 2815: /* ! 2816: * If this entry needs an object, make one. ! 2817: */ ! 2818: if (last->object.vm_object == VM_OBJECT_NULL) { ! 2819: object = vm_object_allocate( ! 2820: (vm_size_t)(last->vme_end - last->vme_start + size)); ! 2821: last->object.vm_object = object; ! 2822: last->offset = 0; ! 2823: vm_object_lock(object); ! 2824: } ! 2825: else { ! 2826: vm_offset_t prev_offset = last->offset; ! 2827: vm_size_t prev_size = start - last->vme_start; ! 2828: vm_size_t new_size; ! 2829: ! 2830: /* ! 2831: * This is basically vm_object_coalesce. ! 2832: */ ! 2833: ! 2834: object = last->object.vm_object; ! 2835: vm_object_lock(object); ! 2836: ! 2837: /* ! 2838: * Try to collapse the object first ! 2839: */ ! 2840: vm_object_collapse(object); ! 2841: ! 2842: /* ! 2843: * Can't coalesce if pages not mapped to ! 2844: * last may be in use anyway: ! 2845: * . more than one reference ! 2846: * . paged out ! 2847: * . shadows another object ! 2848: * . has a copy elsewhere ! 2849: * . paging references (pages might be in page-list) ! 2850: */ ! 2851: ! 2852: if ((object->ref_count > 1) || ! 2853: object->pager_created || ! 2854: (object->shadow != VM_OBJECT_NULL) || ! 2855: (object->copy != VM_OBJECT_NULL) || ! 2856: (object->paging_in_progress != 0)) { ! 2857: vm_object_unlock(object); ! 2858: goto create_object; ! 2859: } ! 2860: ! 2861: /* ! 2862: * Extend the object if necessary. Don't have to call ! 2863: * vm_object_page_remove because the pages aren't mapped, ! 2864: * and vm_page_replace will free up any old ones it encounters. ! 2865: */ ! 2866: new_size = prev_offset + prev_size + size; ! 2867: if (new_size > object->size) ! 2868: object->size = new_size; ! 2869: } ! 2870: ! 2871: /* ! 2872: * Coalesced the two objects - can extend ! 2873: * the previous map entry to include the ! 2874: * new range. ! 2875: */ ! 2876: dst_map->size += size; ! 2877: last->vme_end = end; ! 2878: ! 2879: SAVE_HINT(dst_map, last); ! 2880: ! 2881: goto insert_pages; ! 2882: ! 2883: create_object: ! 2884: ! 2885: /* ! 2886: * Create object ! 2887: */ ! 2888: object = vm_object_allocate(size); ! 2889: ! 2890: /* ! 2891: * Create entry ! 2892: */ ! 2893: ! 2894: entry = vm_map_entry_create(dst_map); ! 2895: ! 2896: entry->object.vm_object = object; ! 2897: entry->offset = 0; ! 2898: ! 2899: entry->is_shared = FALSE; ! 2900: entry->is_sub_map = FALSE; ! 2901: entry->needs_copy = FALSE; ! 2902: ! 2903: if (must_wire) { ! 2904: entry->wired_count = 1; ! 2905: entry->user_wired_count = 1; ! 2906: } else { ! 2907: entry->wired_count = 0; ! 2908: entry->user_wired_count = 0; ! 2909: } ! 2910: ! 2911: entry->in_transition = TRUE; ! 2912: entry->needs_wakeup = FALSE; ! 2913: ! 2914: entry->vme_start = start; ! 2915: entry->vme_end = start + size; ! 2916: ! 2917: entry->inheritance = VM_INHERIT_DEFAULT; ! 2918: entry->protection = VM_PROT_DEFAULT; ! 2919: entry->max_protection = VM_PROT_ALL; ! 2920: entry->projected_on = 0; ! 2921: ! 2922: vm_object_lock(object); ! 2923: ! 2924: /* ! 2925: * Update the hints and the map size ! 2926: */ ! 2927: if (dst_map->first_free == last) { ! 2928: dst_map->first_free = entry; ! 2929: } ! 2930: SAVE_HINT(dst_map, entry); ! 2931: dst_map->size += size; ! 2932: ! 2933: /* ! 2934: * Link in the entry ! 2935: */ ! 2936: vm_map_entry_link(dst_map, last, entry); ! 2937: last = entry; ! 2938: ! 2939: /* ! 2940: * Transfer pages into new object. ! 2941: * Scan page list in vm_map_copy. ! 2942: */ ! 2943: insert_pages: ! 2944: dst_offset = copy->offset & PAGE_MASK; ! 2945: cont_invoked = FALSE; ! 2946: orig_copy = copy; ! 2947: last->in_transition = TRUE; ! 2948: old_last_offset = last->offset ! 2949: + (start - last->vme_start); ! 2950: ! 2951: vm_page_lock_queues(); ! 2952: ! 2953: for (offset = 0; offset < size; offset += PAGE_SIZE) { ! 2954: m = *page_list; ! 2955: assert(m && !m->tabled); ! 2956: ! 2957: /* ! 2958: * Must clear busy bit in page before inserting it. ! 2959: * Ok to skip wakeup logic because nobody else ! 2960: * can possibly know about this page. ! 2961: * The page is dirty in its new object. ! 2962: */ ! 2963: ! 2964: assert(!m->wanted); ! 2965: ! 2966: m->busy = FALSE; ! 2967: m->dirty = TRUE; ! 2968: vm_page_replace(m, object, old_last_offset + offset); ! 2969: if (must_wire) { ! 2970: vm_page_wire(m); ! 2971: PMAP_ENTER(dst_map->pmap, ! 2972: last->vme_start + m->offset - last->offset, ! 2973: m, last->protection, TRUE); ! 2974: } else { ! 2975: vm_page_activate(m); ! 2976: } ! 2977: ! 2978: *page_list++ = VM_PAGE_NULL; ! 2979: if (--(copy->cpy_npages) == 0 && ! 2980: vm_map_copy_has_cont(copy)) { ! 2981: vm_map_copy_t new_copy; ! 2982: ! 2983: /* ! 2984: * Ok to unlock map because entry is ! 2985: * marked in_transition. ! 2986: */ ! 2987: cont_invoked = TRUE; ! 2988: vm_page_unlock_queues(); ! 2989: vm_object_unlock(object); ! 2990: vm_map_unlock(dst_map); ! 2991: vm_map_copy_invoke_cont(copy, &new_copy, &result); ! 2992: ! 2993: if (result == KERN_SUCCESS) { ! 2994: ! 2995: /* ! 2996: * If we got back a copy with real pages, ! 2997: * steal them now. Either all of the ! 2998: * pages in the list are tabled or none ! 2999: * of them are; mixtures are not possible. ! 3000: * ! 3001: * Save original copy for consume on ! 3002: * success logic at end of routine. ! 3003: */ ! 3004: if (copy != orig_copy) ! 3005: vm_map_copy_discard(copy); ! 3006: ! 3007: if ((copy = new_copy) != VM_MAP_COPY_NULL) { ! 3008: page_list = ©->cpy_page_list[0]; ! 3009: if ((*page_list)->tabled) ! 3010: vm_map_copy_steal_pages(copy); ! 3011: } ! 3012: } ! 3013: else { ! 3014: /* ! 3015: * Continuation failed. ! 3016: */ ! 3017: vm_map_lock(dst_map); ! 3018: goto error; ! 3019: } ! 3020: ! 3021: vm_map_lock(dst_map); ! 3022: vm_object_lock(object); ! 3023: vm_page_lock_queues(); ! 3024: } ! 3025: } ! 3026: ! 3027: vm_page_unlock_queues(); ! 3028: vm_object_unlock(object); ! 3029: ! 3030: *dst_addr = start + dst_offset; ! 3031: ! 3032: /* ! 3033: * Clear the in transition bits. This is easy if we ! 3034: * didn't have a continuation. ! 3035: */ ! 3036: error: ! 3037: if (!cont_invoked) { ! 3038: /* ! 3039: * We didn't unlock the map, so nobody could ! 3040: * be waiting. ! 3041: */ ! 3042: last->in_transition = FALSE; ! 3043: assert(!last->needs_wakeup); ! 3044: needs_wakeup = FALSE; ! 3045: } ! 3046: else { ! 3047: if (!vm_map_lookup_entry(dst_map, start, &entry)) ! 3048: panic("vm_map_copyout_page_list: missing entry"); ! 3049: ! 3050: /* ! 3051: * Clear transition bit for all constituent entries that ! 3052: * were in the original entry. Also check for waiters. ! 3053: */ ! 3054: while((entry != vm_map_to_entry(dst_map)) && ! 3055: (entry->vme_start < end)) { ! 3056: assert(entry->in_transition); ! 3057: entry->in_transition = FALSE; ! 3058: if(entry->needs_wakeup) { ! 3059: entry->needs_wakeup = FALSE; ! 3060: needs_wakeup = TRUE; ! 3061: } ! 3062: entry = entry->vme_next; ! 3063: } ! 3064: } ! 3065: ! 3066: if (result != KERN_SUCCESS) ! 3067: vm_map_delete(dst_map, start, end); ! 3068: ! 3069: vm_map_unlock(dst_map); ! 3070: ! 3071: if (needs_wakeup) ! 3072: vm_map_entry_wakeup(dst_map); ! 3073: ! 3074: /* ! 3075: * Consume on success logic. ! 3076: */ ! 3077: if (copy != orig_copy) { ! 3078: zfree(vm_map_copy_zone, (vm_offset_t) copy); ! 3079: } ! 3080: if (result == KERN_SUCCESS) { ! 3081: zfree(vm_map_copy_zone, (vm_offset_t) orig_copy); ! 3082: } ! 3083: ! 3084: return(result); ! 3085: } ! 3086: ! 3087: /* ! 3088: * Routine: vm_map_copyin ! 3089: * ! 3090: * Description: ! 3091: * Copy the specified region (src_addr, len) from the ! 3092: * source address space (src_map), possibly removing ! 3093: * the region from the source address space (src_destroy). ! 3094: * ! 3095: * Returns: ! 3096: * A vm_map_copy_t object (copy_result), suitable for ! 3097: * insertion into another address space (using vm_map_copyout), ! 3098: * copying over another address space region (using ! 3099: * vm_map_copy_overwrite). If the copy is unused, it ! 3100: * should be destroyed (using vm_map_copy_discard). ! 3101: * ! 3102: * In/out conditions: ! 3103: * The source map should not be locked on entry. ! 3104: */ ! 3105: kern_return_t vm_map_copyin(src_map, src_addr, len, src_destroy, copy_result) ! 3106: vm_map_t src_map; ! 3107: vm_offset_t src_addr; ! 3108: vm_size_t len; ! 3109: boolean_t src_destroy; ! 3110: vm_map_copy_t *copy_result; /* OUT */ ! 3111: { ! 3112: vm_map_entry_t tmp_entry; /* Result of last map lookup -- ! 3113: * in multi-level lookup, this ! 3114: * entry contains the actual ! 3115: * vm_object/offset. ! 3116: */ ! 3117: ! 3118: vm_offset_t src_start; /* Start of current entry -- ! 3119: * where copy is taking place now ! 3120: */ ! 3121: vm_offset_t src_end; /* End of entire region to be ! 3122: * copied */ ! 3123: ! 3124: register ! 3125: vm_map_copy_t copy; /* Resulting copy */ ! 3126: ! 3127: /* ! 3128: * Check for copies of zero bytes. ! 3129: */ ! 3130: ! 3131: if (len == 0) { ! 3132: *copy_result = VM_MAP_COPY_NULL; ! 3133: return(KERN_SUCCESS); ! 3134: } ! 3135: ! 3136: /* ! 3137: * Compute start and end of region ! 3138: */ ! 3139: ! 3140: src_start = trunc_page(src_addr); ! 3141: src_end = round_page(src_addr + len); ! 3142: ! 3143: /* ! 3144: * Check that the end address doesn't overflow ! 3145: */ ! 3146: ! 3147: if (src_end <= src_start) ! 3148: if ((src_end < src_start) || (src_start != 0)) ! 3149: return(KERN_INVALID_ADDRESS); ! 3150: ! 3151: /* ! 3152: * Allocate a header element for the list. ! 3153: * ! 3154: * Use the start and end in the header to ! 3155: * remember the endpoints prior to rounding. ! 3156: */ ! 3157: ! 3158: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 3159: vm_map_copy_first_entry(copy) = ! 3160: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy); ! 3161: copy->type = VM_MAP_COPY_ENTRY_LIST; ! 3162: copy->cpy_hdr.nentries = 0; ! 3163: copy->cpy_hdr.entries_pageable = TRUE; ! 3164: ! 3165: copy->offset = src_addr; ! 3166: copy->size = len; ! 3167: ! 3168: #define RETURN(x) \ ! 3169: MACRO_BEGIN \ ! 3170: vm_map_unlock(src_map); \ ! 3171: vm_map_copy_discard(copy); \ ! 3172: MACRO_RETURN(x); \ ! 3173: MACRO_END ! 3174: ! 3175: /* ! 3176: * Find the beginning of the region. ! 3177: */ ! 3178: ! 3179: vm_map_lock(src_map); ! 3180: ! 3181: if (!vm_map_lookup_entry(src_map, src_start, &tmp_entry)) ! 3182: RETURN(KERN_INVALID_ADDRESS); ! 3183: vm_map_clip_start(src_map, tmp_entry, src_start); ! 3184: ! 3185: /* ! 3186: * Go through entries until we get to the end. ! 3187: */ ! 3188: ! 3189: while (TRUE) { ! 3190: register ! 3191: vm_map_entry_t src_entry = tmp_entry; /* Top-level entry */ ! 3192: vm_size_t src_size; /* Size of source ! 3193: * map entry (in both ! 3194: * maps) ! 3195: */ ! 3196: ! 3197: register ! 3198: vm_object_t src_object; /* Object to copy */ ! 3199: vm_offset_t src_offset; ! 3200: ! 3201: boolean_t src_needs_copy; /* Should source map ! 3202: * be made read-only ! 3203: * for copy-on-write? ! 3204: */ ! 3205: ! 3206: register ! 3207: vm_map_entry_t new_entry; /* Map entry for copy */ ! 3208: boolean_t new_entry_needs_copy; /* Will new entry be COW? */ ! 3209: ! 3210: boolean_t was_wired; /* Was source wired? */ ! 3211: vm_map_version_t version; /* Version before locks ! 3212: * dropped to make copy ! 3213: */ ! 3214: ! 3215: /* ! 3216: * Verify that the region can be read. ! 3217: */ ! 3218: ! 3219: if (! (src_entry->protection & VM_PROT_READ)) ! 3220: RETURN(KERN_PROTECTION_FAILURE); ! 3221: ! 3222: /* ! 3223: * Clip against the endpoints of the entire region. ! 3224: */ ! 3225: ! 3226: vm_map_clip_end(src_map, src_entry, src_end); ! 3227: ! 3228: src_size = src_entry->vme_end - src_start; ! 3229: src_object = src_entry->object.vm_object; ! 3230: src_offset = src_entry->offset; ! 3231: was_wired = (src_entry->wired_count != 0); ! 3232: ! 3233: /* ! 3234: * Create a new address map entry to ! 3235: * hold the result. Fill in the fields from ! 3236: * the appropriate source entries. ! 3237: */ ! 3238: ! 3239: new_entry = vm_map_copy_entry_create(copy); ! 3240: vm_map_entry_copy(new_entry, src_entry); ! 3241: ! 3242: /* ! 3243: * Attempt non-blocking copy-on-write optimizations. ! 3244: */ ! 3245: ! 3246: if (src_destroy && ! 3247: (src_object == VM_OBJECT_NULL || ! 3248: (src_object->temporary && !src_object->use_shared_copy))) ! 3249: { ! 3250: /* ! 3251: * If we are destroying the source, and the object ! 3252: * is temporary, and not shared writable, ! 3253: * we can move the object reference ! 3254: * from the source to the copy. The copy is ! 3255: * copy-on-write only if the source is. ! 3256: * We make another reference to the object, because ! 3257: * destroying the source entry will deallocate it. ! 3258: */ ! 3259: vm_object_reference(src_object); ! 3260: ! 3261: /* ! 3262: * Copy is always unwired. vm_map_copy_entry ! 3263: * set its wired count to zero. ! 3264: */ ! 3265: ! 3266: goto CopySuccessful; ! 3267: } ! 3268: ! 3269: if (!was_wired && ! 3270: vm_object_copy_temporary( ! 3271: &new_entry->object.vm_object, ! 3272: &new_entry->offset, ! 3273: &src_needs_copy, ! 3274: &new_entry_needs_copy)) { ! 3275: ! 3276: new_entry->needs_copy = new_entry_needs_copy; ! 3277: ! 3278: /* ! 3279: * Handle copy-on-write obligations ! 3280: */ ! 3281: ! 3282: if (src_needs_copy && !tmp_entry->needs_copy) { ! 3283: vm_object_pmap_protect( ! 3284: src_object, ! 3285: src_offset, ! 3286: src_size, ! 3287: (src_entry->is_shared ? PMAP_NULL ! 3288: : src_map->pmap), ! 3289: src_entry->vme_start, ! 3290: src_entry->protection & ! 3291: ~VM_PROT_WRITE); ! 3292: ! 3293: tmp_entry->needs_copy = TRUE; ! 3294: } ! 3295: ! 3296: /* ! 3297: * The map has never been unlocked, so it's safe to ! 3298: * move to the next entry rather than doing another ! 3299: * lookup. ! 3300: */ ! 3301: ! 3302: goto CopySuccessful; ! 3303: } ! 3304: ! 3305: new_entry->needs_copy = FALSE; ! 3306: ! 3307: /* ! 3308: * Take an object reference, so that we may ! 3309: * release the map lock(s). ! 3310: */ ! 3311: ! 3312: assert(src_object != VM_OBJECT_NULL); ! 3313: vm_object_reference(src_object); ! 3314: ! 3315: /* ! 3316: * Record the timestamp for later verification. ! 3317: * Unlock the map. ! 3318: */ ! 3319: ! 3320: version.main_timestamp = src_map->timestamp; ! 3321: vm_map_unlock(src_map); ! 3322: ! 3323: /* ! 3324: * Perform the copy ! 3325: */ ! 3326: ! 3327: if (was_wired) { ! 3328: vm_object_lock(src_object); ! 3329: (void) vm_object_copy_slowly( ! 3330: src_object, ! 3331: src_offset, ! 3332: src_size, ! 3333: FALSE, ! 3334: &new_entry->object.vm_object); ! 3335: new_entry->offset = 0; ! 3336: new_entry->needs_copy = FALSE; ! 3337: } else { ! 3338: kern_return_t result; ! 3339: ! 3340: result = vm_object_copy_strategically(src_object, ! 3341: src_offset, ! 3342: src_size, ! 3343: &new_entry->object.vm_object, ! 3344: &new_entry->offset, ! 3345: &new_entry_needs_copy); ! 3346: ! 3347: new_entry->needs_copy = new_entry_needs_copy; ! 3348: ! 3349: ! 3350: if (result != KERN_SUCCESS) { ! 3351: vm_map_copy_entry_dispose(copy, new_entry); ! 3352: ! 3353: vm_map_lock(src_map); ! 3354: RETURN(result); ! 3355: } ! 3356: ! 3357: } ! 3358: ! 3359: /* ! 3360: * Throw away the extra reference ! 3361: */ ! 3362: ! 3363: vm_object_deallocate(src_object); ! 3364: ! 3365: /* ! 3366: * Verify that the map has not substantially ! 3367: * changed while the copy was being made. ! 3368: */ ! 3369: ! 3370: vm_map_lock(src_map); /* Increments timestamp once! */ ! 3371: ! 3372: if ((version.main_timestamp + 1) == src_map->timestamp) ! 3373: goto CopySuccessful; ! 3374: ! 3375: /* ! 3376: * Simple version comparison failed. ! 3377: * ! 3378: * Retry the lookup and verify that the ! 3379: * same object/offset are still present. ! 3380: * ! 3381: * [Note: a memory manager that colludes with ! 3382: * the calling task can detect that we have ! 3383: * cheated. While the map was unlocked, the ! 3384: * mapping could have been changed and restored.] ! 3385: */ ! 3386: ! 3387: if (!vm_map_lookup_entry(src_map, src_start, &tmp_entry)) { ! 3388: vm_map_copy_entry_dispose(copy, new_entry); ! 3389: RETURN(KERN_INVALID_ADDRESS); ! 3390: } ! 3391: ! 3392: src_entry = tmp_entry; ! 3393: vm_map_clip_start(src_map, src_entry, src_start); ! 3394: ! 3395: if ((src_entry->protection & VM_PROT_READ) == VM_PROT_NONE) ! 3396: goto VerificationFailed; ! 3397: ! 3398: if (src_entry->vme_end < new_entry->vme_end) ! 3399: src_size = (new_entry->vme_end = src_entry->vme_end) - src_start; ! 3400: ! 3401: if ((src_entry->object.vm_object != src_object) || ! 3402: (src_entry->offset != src_offset) ) { ! 3403: ! 3404: /* ! 3405: * Verification failed. ! 3406: * ! 3407: * Start over with this top-level entry. ! 3408: */ ! 3409: ! 3410: VerificationFailed: ; ! 3411: ! 3412: vm_object_deallocate(new_entry->object.vm_object); ! 3413: vm_map_copy_entry_dispose(copy, new_entry); ! 3414: tmp_entry = src_entry; ! 3415: continue; ! 3416: } ! 3417: ! 3418: /* ! 3419: * Verification succeeded. ! 3420: */ ! 3421: ! 3422: CopySuccessful: ; ! 3423: ! 3424: /* ! 3425: * Link in the new copy entry. ! 3426: */ ! 3427: ! 3428: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy), ! 3429: new_entry); ! 3430: ! 3431: /* ! 3432: * Determine whether the entire region ! 3433: * has been copied. ! 3434: */ ! 3435: src_start = new_entry->vme_end; ! 3436: if ((src_start >= src_end) && (src_end != 0)) ! 3437: break; ! 3438: ! 3439: /* ! 3440: * Verify that there are no gaps in the region ! 3441: */ ! 3442: ! 3443: tmp_entry = src_entry->vme_next; ! 3444: if (tmp_entry->vme_start != src_start) ! 3445: RETURN(KERN_INVALID_ADDRESS); ! 3446: } ! 3447: ! 3448: /* ! 3449: * If the source should be destroyed, do it now, since the ! 3450: * copy was successful. ! 3451: */ ! 3452: if (src_destroy) ! 3453: (void) vm_map_delete(src_map, trunc_page(src_addr), src_end); ! 3454: ! 3455: vm_map_unlock(src_map); ! 3456: ! 3457: *copy_result = copy; ! 3458: return(KERN_SUCCESS); ! 3459: ! 3460: #undef RETURN ! 3461: } ! 3462: ! 3463: /* ! 3464: * vm_map_copyin_object: ! 3465: * ! 3466: * Create a copy object from an object. ! 3467: * Our caller donates an object reference. ! 3468: */ ! 3469: ! 3470: kern_return_t vm_map_copyin_object(object, offset, size, copy_result) ! 3471: vm_object_t object; ! 3472: vm_offset_t offset; /* offset of region in object */ ! 3473: vm_size_t size; /* size of region in object */ ! 3474: vm_map_copy_t *copy_result; /* OUT */ ! 3475: { ! 3476: vm_map_copy_t copy; /* Resulting copy */ ! 3477: ! 3478: /* ! 3479: * We drop the object into a special copy object ! 3480: * that contains the object directly. These copy objects ! 3481: * are distinguished by entries_pageable == FALSE ! 3482: * and null links. ! 3483: */ ! 3484: ! 3485: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 3486: vm_map_copy_first_entry(copy) = ! 3487: vm_map_copy_last_entry(copy) = VM_MAP_ENTRY_NULL; ! 3488: copy->type = VM_MAP_COPY_OBJECT; ! 3489: copy->cpy_object = object; ! 3490: copy->offset = offset; ! 3491: copy->size = size; ! 3492: ! 3493: *copy_result = copy; ! 3494: return(KERN_SUCCESS); ! 3495: } ! 3496: ! 3497: /* ! 3498: * vm_map_copyin_page_list_cont: ! 3499: * ! 3500: * Continuation routine for vm_map_copyin_page_list. ! 3501: * ! 3502: * If vm_map_copyin_page_list can't fit the entire vm range ! 3503: * into a single page list object, it creates a continuation. ! 3504: * When the target of the operation has used the pages in the ! 3505: * initial page list, it invokes the continuation, which calls ! 3506: * this routine. If an error happens, the continuation is aborted ! 3507: * (abort arg to this routine is TRUE). To avoid deadlocks, the ! 3508: * pages are discarded from the initial page list before invoking ! 3509: * the continuation. ! 3510: * ! 3511: * NOTE: This is not the same sort of continuation used by ! 3512: * the scheduler. ! 3513: */ ! 3514: ! 3515: kern_return_t vm_map_copyin_page_list_cont(cont_args, copy_result) ! 3516: vm_map_copyin_args_t cont_args; ! 3517: vm_map_copy_t *copy_result; /* OUT */ ! 3518: { ! 3519: kern_return_t result = 0; /* '=0' to quiet gcc warnings */ ! 3520: register boolean_t do_abort, src_destroy, src_destroy_only; ! 3521: ! 3522: /* ! 3523: * Check for cases that only require memory destruction. ! 3524: */ ! 3525: do_abort = (copy_result == (vm_map_copy_t *) 0); ! 3526: src_destroy = (cont_args->destroy_len != (vm_size_t) 0); ! 3527: src_destroy_only = (cont_args->src_len == (vm_size_t) 0); ! 3528: ! 3529: if (do_abort || src_destroy_only) { ! 3530: if (src_destroy) ! 3531: result = vm_map_remove(cont_args->map, ! 3532: cont_args->destroy_addr, ! 3533: cont_args->destroy_addr + cont_args->destroy_len); ! 3534: if (!do_abort) ! 3535: *copy_result = VM_MAP_COPY_NULL; ! 3536: } ! 3537: else { ! 3538: result = vm_map_copyin_page_list(cont_args->map, ! 3539: cont_args->src_addr, cont_args->src_len, src_destroy, ! 3540: cont_args->steal_pages, copy_result, TRUE); ! 3541: ! 3542: if (src_destroy && !cont_args->steal_pages && ! 3543: vm_map_copy_has_cont(*copy_result)) { ! 3544: vm_map_copyin_args_t new_args; ! 3545: /* ! 3546: * Transfer old destroy info. ! 3547: */ ! 3548: new_args = (vm_map_copyin_args_t) ! 3549: (*copy_result)->cpy_cont_args; ! 3550: new_args->destroy_addr = cont_args->destroy_addr; ! 3551: new_args->destroy_len = cont_args->destroy_len; ! 3552: } ! 3553: } ! 3554: ! 3555: vm_map_deallocate(cont_args->map); ! 3556: kfree((vm_offset_t)cont_args, sizeof(vm_map_copyin_args_data_t)); ! 3557: ! 3558: return(result); ! 3559: } ! 3560: ! 3561: /* ! 3562: * vm_map_copyin_page_list: ! 3563: * ! 3564: * This is a variant of vm_map_copyin that copies in a list of pages. ! 3565: * If steal_pages is TRUE, the pages are only in the returned list. ! 3566: * If steal_pages is FALSE, the pages are busy and still in their ! 3567: * objects. A continuation may be returned if not all the pages fit: ! 3568: * the recipient of this copy_result must be prepared to deal with it. ! 3569: */ ! 3570: ! 3571: kern_return_t vm_map_copyin_page_list(src_map, src_addr, len, src_destroy, ! 3572: steal_pages, copy_result, is_cont) ! 3573: vm_map_t src_map; ! 3574: vm_offset_t src_addr; ! 3575: vm_size_t len; ! 3576: boolean_t src_destroy; ! 3577: boolean_t steal_pages; ! 3578: vm_map_copy_t *copy_result; /* OUT */ ! 3579: boolean_t is_cont; ! 3580: { ! 3581: vm_map_entry_t src_entry; ! 3582: vm_page_t m; ! 3583: vm_offset_t src_start; ! 3584: vm_offset_t src_end; ! 3585: vm_size_t src_size; ! 3586: register ! 3587: vm_object_t src_object; ! 3588: register ! 3589: vm_offset_t src_offset; ! 3590: vm_offset_t src_last_offset; ! 3591: register ! 3592: vm_map_copy_t copy; /* Resulting copy */ ! 3593: kern_return_t result = KERN_SUCCESS; ! 3594: boolean_t need_map_lookup; ! 3595: vm_map_copyin_args_t cont_args; ! 3596: ! 3597: /* ! 3598: * If steal_pages is FALSE, this leaves busy pages in ! 3599: * the object. A continuation must be used if src_destroy ! 3600: * is true in this case (!steal_pages && src_destroy). ! 3601: * ! 3602: * XXX Still have a more general problem of what happens ! 3603: * XXX if the same page occurs twice in a list. Deadlock ! 3604: * XXX can happen if vm_fault_page was called. A ! 3605: * XXX possible solution is to use a continuation if vm_fault_page ! 3606: * XXX is called and we cross a map entry boundary. ! 3607: */ ! 3608: ! 3609: /* ! 3610: * Check for copies of zero bytes. ! 3611: */ ! 3612: ! 3613: if (len == 0) { ! 3614: *copy_result = VM_MAP_COPY_NULL; ! 3615: return(KERN_SUCCESS); ! 3616: } ! 3617: ! 3618: /* ! 3619: * Compute start and end of region ! 3620: */ ! 3621: ! 3622: src_start = trunc_page(src_addr); ! 3623: src_end = round_page(src_addr + len); ! 3624: ! 3625: /* ! 3626: * Check that the end address doesn't overflow ! 3627: */ ! 3628: ! 3629: if (src_end <= src_start && (src_end < src_start || src_start != 0)) { ! 3630: return KERN_INVALID_ADDRESS; ! 3631: } ! 3632: ! 3633: /* ! 3634: * Allocate a header element for the page list. ! 3635: * ! 3636: * Record original offset and size, as caller may not ! 3637: * be page-aligned. ! 3638: */ ! 3639: ! 3640: copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 3641: copy->type = VM_MAP_COPY_PAGE_LIST; ! 3642: copy->cpy_npages = 0; ! 3643: copy->offset = src_addr; ! 3644: copy->size = len; ! 3645: copy->cpy_cont = ((kern_return_t (*)()) 0); ! 3646: copy->cpy_cont_args = (char *) VM_MAP_COPYIN_ARGS_NULL; ! 3647: ! 3648: /* ! 3649: * Find the beginning of the region. ! 3650: */ ! 3651: ! 3652: do_map_lookup: ! 3653: ! 3654: vm_map_lock(src_map); ! 3655: ! 3656: if (!vm_map_lookup_entry(src_map, src_start, &src_entry)) { ! 3657: result = KERN_INVALID_ADDRESS; ! 3658: goto error; ! 3659: } ! 3660: need_map_lookup = FALSE; ! 3661: ! 3662: /* ! 3663: * Go through entries until we get to the end. ! 3664: */ ! 3665: ! 3666: while (TRUE) { ! 3667: ! 3668: if (! (src_entry->protection & VM_PROT_READ)) { ! 3669: result = KERN_PROTECTION_FAILURE; ! 3670: goto error; ! 3671: } ! 3672: ! 3673: if (src_end > src_entry->vme_end) ! 3674: src_size = src_entry->vme_end - src_start; ! 3675: else ! 3676: src_size = src_end - src_start; ! 3677: ! 3678: src_object = src_entry->object.vm_object; ! 3679: src_offset = src_entry->offset + ! 3680: (src_start - src_entry->vme_start); ! 3681: ! 3682: /* ! 3683: * If src_object is NULL, allocate it now; ! 3684: * we're going to fault on it shortly. ! 3685: */ ! 3686: if (src_object == VM_OBJECT_NULL) { ! 3687: src_object = vm_object_allocate((vm_size_t) ! 3688: src_entry->vme_end - ! 3689: src_entry->vme_start); ! 3690: src_entry->object.vm_object = src_object; ! 3691: } ! 3692: ! 3693: /* ! 3694: * Iterate over pages. Fault in ones that aren't present. ! 3695: */ ! 3696: src_last_offset = src_offset + src_size; ! 3697: for (; (src_offset < src_last_offset && !need_map_lookup); ! 3698: src_offset += PAGE_SIZE, src_start += PAGE_SIZE) { ! 3699: ! 3700: if (copy->cpy_npages == VM_MAP_COPY_PAGE_LIST_MAX) { ! 3701: make_continuation: ! 3702: /* ! 3703: * At this point we have the max number of ! 3704: * pages busy for this thread that we're ! 3705: * willing to allow. Stop here and record ! 3706: * arguments for the remainder. Note: ! 3707: * this means that this routine isn't atomic, ! 3708: * but that's the breaks. Note that only ! 3709: * the first vm_map_copy_t that comes back ! 3710: * from this routine has the right offset ! 3711: * and size; those from continuations are ! 3712: * page rounded, and short by the amount ! 3713: * already done. ! 3714: * ! 3715: * Reset src_end so the src_destroy ! 3716: * code at the bottom doesn't do ! 3717: * something stupid. ! 3718: */ ! 3719: ! 3720: cont_args = (vm_map_copyin_args_t) ! 3721: kalloc(sizeof(vm_map_copyin_args_data_t)); ! 3722: cont_args->map = src_map; ! 3723: vm_map_reference(src_map); ! 3724: cont_args->src_addr = src_start; ! 3725: cont_args->src_len = len - (src_start - src_addr); ! 3726: if (src_destroy) { ! 3727: cont_args->destroy_addr = cont_args->src_addr; ! 3728: cont_args->destroy_len = cont_args->src_len; ! 3729: } ! 3730: else { ! 3731: cont_args->destroy_addr = (vm_offset_t) 0; ! 3732: cont_args->destroy_len = (vm_offset_t) 0; ! 3733: } ! 3734: cont_args->steal_pages = steal_pages; ! 3735: ! 3736: copy->cpy_cont_args = (char *) cont_args; ! 3737: copy->cpy_cont = vm_map_copyin_page_list_cont; ! 3738: ! 3739: src_end = src_start; ! 3740: vm_map_clip_end(src_map, src_entry, src_end); ! 3741: break; ! 3742: } ! 3743: ! 3744: /* ! 3745: * Try to find the page of data. ! 3746: */ ! 3747: vm_object_lock(src_object); ! 3748: vm_object_paging_begin(src_object); ! 3749: if (((m = vm_page_lookup(src_object, src_offset)) != ! 3750: VM_PAGE_NULL) && !m->busy && !m->fictitious && ! 3751: !m->absent && !m->error) { ! 3752: ! 3753: /* ! 3754: * This is the page. Mark it busy ! 3755: * and keep the paging reference on ! 3756: * the object whilst we do our thing. ! 3757: */ ! 3758: m->busy = TRUE; ! 3759: ! 3760: /* ! 3761: * Also write-protect the page, so ! 3762: * that the map`s owner cannot change ! 3763: * the data. The busy bit will prevent ! 3764: * faults on the page from succeeding ! 3765: * until the copy is released; after ! 3766: * that, the page can be re-entered ! 3767: * as writable, since we didn`t alter ! 3768: * the map entry. This scheme is a ! 3769: * cheap copy-on-write. ! 3770: * ! 3771: * Don`t forget the protection and ! 3772: * the page_lock value! ! 3773: * ! 3774: * If the source is being destroyed ! 3775: * AND not shared writable, we don`t ! 3776: * have to protect the page, since ! 3777: * we will destroy the (only) ! 3778: * writable mapping later. ! 3779: */ ! 3780: if (!src_destroy || ! 3781: src_object->use_shared_copy) ! 3782: { ! 3783: pmap_page_protect(m->phys_addr, ! 3784: src_entry->protection ! 3785: & ~m->page_lock ! 3786: & ~VM_PROT_WRITE); ! 3787: } ! 3788: ! 3789: } ! 3790: else { ! 3791: vm_prot_t result_prot; ! 3792: vm_page_t top_page; ! 3793: kern_return_t kr; ! 3794: ! 3795: /* ! 3796: * Have to fault the page in; must ! 3797: * unlock the map to do so. While ! 3798: * the map is unlocked, anything ! 3799: * can happen, we must lookup the ! 3800: * map entry before continuing. ! 3801: */ ! 3802: vm_map_unlock(src_map); ! 3803: need_map_lookup = TRUE; ! 3804: retry: ! 3805: result_prot = VM_PROT_READ; ! 3806: ! 3807: kr = vm_fault_page(src_object, src_offset, ! 3808: VM_PROT_READ, FALSE, FALSE, ! 3809: &result_prot, &m, &top_page, ! 3810: FALSE, (void (*)()) 0); ! 3811: /* ! 3812: * Cope with what happened. ! 3813: */ ! 3814: switch (kr) { ! 3815: case VM_FAULT_SUCCESS: ! 3816: break; ! 3817: case VM_FAULT_INTERRUPTED: /* ??? */ ! 3818: case VM_FAULT_RETRY: ! 3819: vm_object_lock(src_object); ! 3820: vm_object_paging_begin(src_object); ! 3821: goto retry; ! 3822: case VM_FAULT_MEMORY_SHORTAGE: ! 3823: VM_PAGE_WAIT((void (*)()) 0); ! 3824: vm_object_lock(src_object); ! 3825: vm_object_paging_begin(src_object); ! 3826: goto retry; ! 3827: case VM_FAULT_FICTITIOUS_SHORTAGE: ! 3828: vm_page_more_fictitious(); ! 3829: vm_object_lock(src_object); ! 3830: vm_object_paging_begin(src_object); ! 3831: goto retry; ! 3832: case VM_FAULT_MEMORY_ERROR: ! 3833: /* ! 3834: * Something broke. If this ! 3835: * is a continuation, return ! 3836: * a partial result if possible, ! 3837: * else fail the whole thing. ! 3838: * In the continuation case, the ! 3839: * next continuation call will ! 3840: * get this error if it persists. ! 3841: */ ! 3842: vm_map_lock(src_map); ! 3843: if (is_cont && ! 3844: copy->cpy_npages != 0) ! 3845: goto make_continuation; ! 3846: ! 3847: result = KERN_MEMORY_ERROR; ! 3848: goto error; ! 3849: } ! 3850: ! 3851: if (top_page != VM_PAGE_NULL) { ! 3852: vm_object_lock(src_object); ! 3853: VM_PAGE_FREE(top_page); ! 3854: vm_object_paging_end(src_object); ! 3855: vm_object_unlock(src_object); ! 3856: } ! 3857: ! 3858: /* ! 3859: * We do not need to write-protect ! 3860: * the page, since it cannot have ! 3861: * been in the pmap (and we did not ! 3862: * enter it above). The busy bit ! 3863: * will protect the page from being ! 3864: * entered as writable until it is ! 3865: * unlocked. ! 3866: */ ! 3867: ! 3868: } ! 3869: ! 3870: /* ! 3871: * The page is busy, its object is locked, and ! 3872: * we have a paging reference on it. Either ! 3873: * the map is locked, or need_map_lookup is ! 3874: * TRUE. ! 3875: * ! 3876: * Put the page in the page list. ! 3877: */ ! 3878: copy->cpy_page_list[copy->cpy_npages++] = m; ! 3879: vm_object_unlock(m->object); ! 3880: } ! 3881: ! 3882: /* ! 3883: * DETERMINE whether the entire region ! 3884: * has been copied. ! 3885: */ ! 3886: if (src_start >= src_end && src_end != 0) { ! 3887: if (need_map_lookup) ! 3888: vm_map_lock(src_map); ! 3889: break; ! 3890: } ! 3891: ! 3892: /* ! 3893: * If need_map_lookup is TRUE, have to start over with ! 3894: * another map lookup. Note that we dropped the map ! 3895: * lock (to call vm_fault_page) above only in this case. ! 3896: */ ! 3897: if (need_map_lookup) ! 3898: goto do_map_lookup; ! 3899: ! 3900: /* ! 3901: * Verify that there are no gaps in the region ! 3902: */ ! 3903: ! 3904: src_start = src_entry->vme_end; ! 3905: src_entry = src_entry->vme_next; ! 3906: if (src_entry->vme_start != src_start) { ! 3907: result = KERN_INVALID_ADDRESS; ! 3908: goto error; ! 3909: } ! 3910: } ! 3911: ! 3912: /* ! 3913: * If steal_pages is true, make sure all ! 3914: * pages in the copy are not in any object ! 3915: * We try to remove them from the original ! 3916: * object, but we may have to copy them. ! 3917: * ! 3918: * At this point every page in the list is busy ! 3919: * and holds a paging reference to its object. ! 3920: * When we're done stealing, every page is busy, ! 3921: * and in no object (m->tabled == FALSE). ! 3922: */ ! 3923: src_start = trunc_page(src_addr); ! 3924: if (steal_pages) { ! 3925: register int i; ! 3926: vm_offset_t unwire_end; ! 3927: ! 3928: unwire_end = src_start; ! 3929: for (i = 0; i < copy->cpy_npages; i++) { ! 3930: ! 3931: /* ! 3932: * Remove the page from its object if it ! 3933: * can be stolen. It can be stolen if: ! 3934: * ! 3935: * (1) The source is being destroyed, ! 3936: * the object is temporary, and ! 3937: * not shared. ! 3938: * (2) The page is not precious. ! 3939: * ! 3940: * The not shared check consists of two ! 3941: * parts: (a) there are no objects that ! 3942: * shadow this object. (b) it is not the ! 3943: * object in any shared map entries (i.e., ! 3944: * use_shared_copy is not set). ! 3945: * ! 3946: * The first check (a) means that we can't ! 3947: * steal pages from objects that are not ! 3948: * at the top of their shadow chains. This ! 3949: * should not be a frequent occurrence. ! 3950: * ! 3951: * Stealing wired pages requires telling the ! 3952: * pmap module to let go of them. ! 3953: * ! 3954: * NOTE: stealing clean pages from objects ! 3955: * whose mappings survive requires a call to ! 3956: * the pmap module. Maybe later. ! 3957: */ ! 3958: m = copy->cpy_page_list[i]; ! 3959: src_object = m->object; ! 3960: vm_object_lock(src_object); ! 3961: ! 3962: if (src_destroy && ! 3963: src_object->temporary && ! 3964: (!src_object->shadowed) && ! 3965: (!src_object->use_shared_copy) && ! 3966: !m->precious) { ! 3967: vm_offset_t page_vaddr; ! 3968: ! 3969: page_vaddr = src_start + (i * PAGE_SIZE); ! 3970: if (m->wire_count > 0) { ! 3971: ! 3972: assert(m->wire_count == 1); ! 3973: /* ! 3974: * In order to steal a wired ! 3975: * page, we have to unwire it ! 3976: * first. We do this inline ! 3977: * here because we have the page. ! 3978: * ! 3979: * Step 1: Unwire the map entry. ! 3980: * Also tell the pmap module ! 3981: * that this piece of the ! 3982: * pmap is pageable. ! 3983: */ ! 3984: vm_object_unlock(src_object); ! 3985: if (page_vaddr >= unwire_end) { ! 3986: if (!vm_map_lookup_entry(src_map, ! 3987: page_vaddr, &src_entry)) ! 3988: panic("vm_map_copyin_page_list: missing wired map entry"); ! 3989: ! 3990: vm_map_clip_start(src_map, src_entry, ! 3991: page_vaddr); ! 3992: vm_map_clip_end(src_map, src_entry, ! 3993: src_start + src_size); ! 3994: ! 3995: assert(src_entry->wired_count > 0); ! 3996: src_entry->wired_count = 0; ! 3997: src_entry->user_wired_count = 0; ! 3998: unwire_end = src_entry->vme_end; ! 3999: pmap_pageable(vm_map_pmap(src_map), ! 4000: page_vaddr, unwire_end, TRUE); ! 4001: } ! 4002: ! 4003: /* ! 4004: * Step 2: Unwire the page. ! 4005: * pmap_remove handles this for us. ! 4006: */ ! 4007: vm_object_lock(src_object); ! 4008: } ! 4009: ! 4010: /* ! 4011: * Don't need to remove the mapping; ! 4012: * vm_map_delete will handle it. ! 4013: * ! 4014: * Steal the page. Setting the wire count ! 4015: * to zero is vm_page_unwire without ! 4016: * activating the page. ! 4017: */ ! 4018: vm_page_lock_queues(); ! 4019: vm_page_remove(m); ! 4020: if (m->wire_count > 0) { ! 4021: m->wire_count = 0; ! 4022: vm_page_wire_count--; ! 4023: } else { ! 4024: VM_PAGE_QUEUES_REMOVE(m); ! 4025: } ! 4026: vm_page_unlock_queues(); ! 4027: } ! 4028: else { ! 4029: /* ! 4030: * Have to copy this page. Have to ! 4031: * unlock the map while copying, ! 4032: * hence no further page stealing. ! 4033: * Hence just copy all the pages. ! 4034: * Unlock the map while copying; ! 4035: * This means no further page stealing. ! 4036: */ ! 4037: vm_object_unlock(src_object); ! 4038: vm_map_unlock(src_map); ! 4039: ! 4040: vm_map_copy_steal_pages(copy); ! 4041: ! 4042: vm_map_lock(src_map); ! 4043: break; ! 4044: } ! 4045: ! 4046: vm_object_paging_end(src_object); ! 4047: vm_object_unlock(src_object); ! 4048: } ! 4049: ! 4050: /* ! 4051: * If the source should be destroyed, do it now, since the ! 4052: * copy was successful. ! 4053: */ ! 4054: ! 4055: if (src_destroy) { ! 4056: (void) vm_map_delete(src_map, src_start, src_end); ! 4057: } ! 4058: } ! 4059: else { ! 4060: /* ! 4061: * !steal_pages leaves busy pages in the map. ! 4062: * This will cause src_destroy to hang. Use ! 4063: * a continuation to prevent this. ! 4064: */ ! 4065: if (src_destroy && !vm_map_copy_has_cont(copy)) { ! 4066: cont_args = (vm_map_copyin_args_t) ! 4067: kalloc(sizeof(vm_map_copyin_args_data_t)); ! 4068: vm_map_reference(src_map); ! 4069: cont_args->map = src_map; ! 4070: cont_args->src_addr = (vm_offset_t) 0; ! 4071: cont_args->src_len = (vm_size_t) 0; ! 4072: cont_args->destroy_addr = src_start; ! 4073: cont_args->destroy_len = src_end - src_start; ! 4074: cont_args->steal_pages = FALSE; ! 4075: ! 4076: copy->cpy_cont_args = (char *) cont_args; ! 4077: copy->cpy_cont = vm_map_copyin_page_list_cont; ! 4078: } ! 4079: ! 4080: } ! 4081: ! 4082: vm_map_unlock(src_map); ! 4083: ! 4084: *copy_result = copy; ! 4085: return(result); ! 4086: ! 4087: error: ! 4088: vm_map_unlock(src_map); ! 4089: vm_map_copy_discard(copy); ! 4090: return(result); ! 4091: } ! 4092: ! 4093: /* ! 4094: * vm_map_fork: ! 4095: * ! 4096: * Create and return a new map based on the old ! 4097: * map, according to the inheritance values on the ! 4098: * regions in that map. ! 4099: * ! 4100: * The source map must not be locked. ! 4101: */ ! 4102: vm_map_t vm_map_fork(old_map) ! 4103: vm_map_t old_map; ! 4104: { ! 4105: vm_map_t new_map; ! 4106: register ! 4107: vm_map_entry_t old_entry; ! 4108: register ! 4109: vm_map_entry_t new_entry; ! 4110: pmap_t new_pmap = pmap_create((vm_size_t) 0); ! 4111: vm_size_t new_size = 0; ! 4112: vm_size_t entry_size; ! 4113: register ! 4114: vm_object_t object; ! 4115: ! 4116: vm_map_lock(old_map); ! 4117: ! 4118: new_map = vm_map_create(new_pmap, ! 4119: old_map->min_offset, ! 4120: old_map->max_offset, ! 4121: old_map->hdr.entries_pageable); ! 4122: ! 4123: for ( ! 4124: old_entry = vm_map_first_entry(old_map); ! 4125: old_entry != vm_map_to_entry(old_map); ! 4126: ) { ! 4127: if (old_entry->is_sub_map) ! 4128: panic("vm_map_fork: encountered a submap"); ! 4129: ! 4130: entry_size = (old_entry->vme_end - old_entry->vme_start); ! 4131: ! 4132: switch (old_entry->inheritance) { ! 4133: case VM_INHERIT_NONE: ! 4134: break; ! 4135: ! 4136: case VM_INHERIT_SHARE: ! 4137: /* ! 4138: * New sharing code. New map entry ! 4139: * references original object. Temporary ! 4140: * objects use asynchronous copy algorithm for ! 4141: * future copies. First make sure we have ! 4142: * the right object. If we need a shadow, ! 4143: * or someone else already has one, then ! 4144: * make a new shadow and share it. ! 4145: */ ! 4146: ! 4147: object = old_entry->object.vm_object; ! 4148: if (object == VM_OBJECT_NULL) { ! 4149: object = vm_object_allocate( ! 4150: (vm_size_t)(old_entry->vme_end - ! 4151: old_entry->vme_start)); ! 4152: old_entry->offset = 0; ! 4153: old_entry->object.vm_object = object; ! 4154: assert(!old_entry->needs_copy); ! 4155: } ! 4156: else if (old_entry->needs_copy || object->shadowed || ! 4157: (object->temporary && !old_entry->is_shared && ! 4158: object->size > (vm_size_t)(old_entry->vme_end - ! 4159: old_entry->vme_start))) { ! 4160: ! 4161: assert(object->temporary); ! 4162: assert(!(object->shadowed && old_entry->is_shared)); ! 4163: vm_object_shadow( ! 4164: &old_entry->object.vm_object, ! 4165: &old_entry->offset, ! 4166: (vm_size_t) (old_entry->vme_end - ! 4167: old_entry->vme_start)); ! 4168: ! 4169: /* ! 4170: * If we're making a shadow for other than ! 4171: * copy on write reasons, then we have ! 4172: * to remove write permission. ! 4173: */ ! 4174: ! 4175: if (!old_entry->needs_copy && ! 4176: (old_entry->protection & VM_PROT_WRITE)) { ! 4177: pmap_protect(vm_map_pmap(old_map), ! 4178: old_entry->vme_start, ! 4179: old_entry->vme_end, ! 4180: old_entry->protection & ! 4181: ~VM_PROT_WRITE); ! 4182: } ! 4183: old_entry->needs_copy = FALSE; ! 4184: object = old_entry->object.vm_object; ! 4185: } ! 4186: ! 4187: /* ! 4188: * Set use_shared_copy to indicate that ! 4189: * object must use shared (delayed) copy-on ! 4190: * write. This is ignored for permanent objects. ! 4191: * Bump the reference count for the new entry ! 4192: */ ! 4193: ! 4194: vm_object_lock(object); ! 4195: object->use_shared_copy = TRUE; ! 4196: object->ref_count++; ! 4197: vm_object_unlock(object); ! 4198: ! 4199: if (old_entry->projected_on != 0) { ! 4200: /* ! 4201: * If entry is projected buffer, clone the ! 4202: * entry exactly. ! 4203: */ ! 4204: ! 4205: vm_map_entry_copy_full(new_entry, old_entry); ! 4206: ! 4207: } else { ! 4208: /* ! 4209: * Clone the entry, using object ref from above. ! 4210: * Mark both entries as shared. ! 4211: */ ! 4212: ! 4213: new_entry = vm_map_entry_create(new_map); ! 4214: vm_map_entry_copy(new_entry, old_entry); ! 4215: old_entry->is_shared = TRUE; ! 4216: new_entry->is_shared = TRUE; ! 4217: } ! 4218: ! 4219: /* ! 4220: * Insert the entry into the new map -- we ! 4221: * know we're inserting at the end of the new ! 4222: * map. ! 4223: */ ! 4224: ! 4225: vm_map_entry_link( ! 4226: new_map, ! 4227: vm_map_last_entry(new_map), ! 4228: new_entry); ! 4229: ! 4230: /* ! 4231: * Update the physical map ! 4232: */ ! 4233: ! 4234: pmap_copy(new_map->pmap, old_map->pmap, ! 4235: new_entry->vme_start, ! 4236: entry_size, ! 4237: old_entry->vme_start); ! 4238: ! 4239: new_size += entry_size; ! 4240: break; ! 4241: ! 4242: case VM_INHERIT_COPY: ! 4243: if (old_entry->wired_count == 0) { ! 4244: boolean_t src_needs_copy; ! 4245: boolean_t new_entry_needs_copy; ! 4246: ! 4247: new_entry = vm_map_entry_create(new_map); ! 4248: vm_map_entry_copy(new_entry, old_entry); ! 4249: ! 4250: if (vm_object_copy_temporary( ! 4251: &new_entry->object.vm_object, ! 4252: &new_entry->offset, ! 4253: &src_needs_copy, ! 4254: &new_entry_needs_copy)) { ! 4255: ! 4256: /* ! 4257: * Handle copy-on-write obligations ! 4258: */ ! 4259: ! 4260: if (src_needs_copy && !old_entry->needs_copy) { ! 4261: vm_object_pmap_protect( ! 4262: old_entry->object.vm_object, ! 4263: old_entry->offset, ! 4264: entry_size, ! 4265: (old_entry->is_shared ? ! 4266: PMAP_NULL : ! 4267: old_map->pmap), ! 4268: old_entry->vme_start, ! 4269: old_entry->protection & ! 4270: ~VM_PROT_WRITE); ! 4271: ! 4272: old_entry->needs_copy = TRUE; ! 4273: } ! 4274: ! 4275: new_entry->needs_copy = new_entry_needs_copy; ! 4276: ! 4277: /* ! 4278: * Insert the entry at the end ! 4279: * of the map. ! 4280: */ ! 4281: ! 4282: vm_map_entry_link(new_map, ! 4283: vm_map_last_entry(new_map), ! 4284: new_entry); ! 4285: ! 4286: ! 4287: new_size += entry_size; ! 4288: break; ! 4289: } ! 4290: ! 4291: vm_map_entry_dispose(new_map, new_entry); ! 4292: } ! 4293: ! 4294: /* INNER BLOCK (copy cannot be optimized) */ { ! 4295: ! 4296: vm_offset_t start = old_entry->vme_start; ! 4297: vm_map_copy_t copy; ! 4298: vm_map_entry_t last = vm_map_last_entry(new_map); ! 4299: ! 4300: vm_map_unlock(old_map); ! 4301: if (vm_map_copyin(old_map, ! 4302: start, ! 4303: entry_size, ! 4304: FALSE, ! 4305: ©) ! 4306: != KERN_SUCCESS) { ! 4307: vm_map_lock(old_map); ! 4308: if (!vm_map_lookup_entry(old_map, start, &last)) ! 4309: last = last->vme_next; ! 4310: old_entry = last; ! 4311: /* ! 4312: * For some error returns, want to ! 4313: * skip to the next element. ! 4314: */ ! 4315: ! 4316: continue; ! 4317: } ! 4318: ! 4319: /* ! 4320: * Insert the copy into the new map ! 4321: */ ! 4322: ! 4323: vm_map_copy_insert(new_map, last, copy); ! 4324: new_size += entry_size; ! 4325: ! 4326: /* ! 4327: * Pick up the traversal at the end of ! 4328: * the copied region. ! 4329: */ ! 4330: ! 4331: vm_map_lock(old_map); ! 4332: start += entry_size; ! 4333: if (!vm_map_lookup_entry(old_map, start, &last)) ! 4334: last = last->vme_next; ! 4335: else ! 4336: vm_map_clip_start(old_map, last, start); ! 4337: old_entry = last; ! 4338: ! 4339: continue; ! 4340: /* INNER BLOCK (copy cannot be optimized) */ } ! 4341: } ! 4342: old_entry = old_entry->vme_next; ! 4343: } ! 4344: ! 4345: new_map->size = new_size; ! 4346: vm_map_unlock(old_map); ! 4347: ! 4348: return(new_map); ! 4349: } ! 4350: ! 4351: /* ! 4352: * vm_map_lookup: ! 4353: * ! 4354: * Finds the VM object, offset, and ! 4355: * protection for a given virtual address in the ! 4356: * specified map, assuming a page fault of the ! 4357: * type specified. ! 4358: * ! 4359: * Returns the (object, offset, protection) for ! 4360: * this address, whether it is wired down, and whether ! 4361: * this map has the only reference to the data in question. ! 4362: * In order to later verify this lookup, a "version" ! 4363: * is returned. ! 4364: * ! 4365: * The map should not be locked; it will not be ! 4366: * locked on exit. In order to guarantee the ! 4367: * existence of the returned object, it is returned ! 4368: * locked. ! 4369: * ! 4370: * If a lookup is requested with "write protection" ! 4371: * specified, the map may be changed to perform virtual ! 4372: * copying operations, although the data referenced will ! 4373: * remain the same. ! 4374: */ ! 4375: kern_return_t vm_map_lookup(var_map, vaddr, fault_type, out_version, ! 4376: object, offset, out_prot, wired) ! 4377: vm_map_t *var_map; /* IN/OUT */ ! 4378: register vm_offset_t vaddr; ! 4379: register vm_prot_t fault_type; ! 4380: ! 4381: vm_map_version_t *out_version; /* OUT */ ! 4382: vm_object_t *object; /* OUT */ ! 4383: vm_offset_t *offset; /* OUT */ ! 4384: vm_prot_t *out_prot; /* OUT */ ! 4385: boolean_t *wired; /* OUT */ ! 4386: { ! 4387: register vm_map_entry_t entry; ! 4388: register vm_map_t map = *var_map; ! 4389: register vm_prot_t prot; ! 4390: ! 4391: RetryLookup: ; ! 4392: ! 4393: /* ! 4394: * Lookup the faulting address. ! 4395: */ ! 4396: ! 4397: vm_map_lock_read(map); ! 4398: ! 4399: #define RETURN(why) \ ! 4400: { \ ! 4401: vm_map_unlock_read(map); \ ! 4402: return(why); \ ! 4403: } ! 4404: ! 4405: /* ! 4406: * If the map has an interesting hint, try it before calling ! 4407: * full blown lookup routine. ! 4408: */ ! 4409: ! 4410: simple_lock(&map->hint_lock); ! 4411: entry = map->hint; ! 4412: simple_unlock(&map->hint_lock); ! 4413: ! 4414: if ((entry == vm_map_to_entry(map)) || ! 4415: (vaddr < entry->vme_start) || (vaddr >= entry->vme_end)) { ! 4416: vm_map_entry_t tmp_entry; ! 4417: ! 4418: /* ! 4419: * Entry was either not a valid hint, or the vaddr ! 4420: * was not contained in the entry, so do a full lookup. ! 4421: */ ! 4422: if (!vm_map_lookup_entry(map, vaddr, &tmp_entry)) ! 4423: RETURN(KERN_INVALID_ADDRESS); ! 4424: ! 4425: entry = tmp_entry; ! 4426: } ! 4427: ! 4428: /* ! 4429: * Handle submaps. ! 4430: */ ! 4431: ! 4432: if (entry->is_sub_map) { ! 4433: vm_map_t old_map = map; ! 4434: ! 4435: *var_map = map = entry->object.sub_map; ! 4436: vm_map_unlock_read(old_map); ! 4437: goto RetryLookup; ! 4438: } ! 4439: ! 4440: /* ! 4441: * Check whether this task is allowed to have ! 4442: * this page. ! 4443: */ ! 4444: ! 4445: prot = entry->protection; ! 4446: ! 4447: if ((fault_type & (prot)) != fault_type) ! 4448: if ((prot & VM_PROT_NOTIFY) && (fault_type & VM_PROT_WRITE)) { ! 4449: RETURN(KERN_WRITE_PROTECTION_FAILURE); ! 4450: } else { ! 4451: RETURN(KERN_PROTECTION_FAILURE); ! 4452: } ! 4453: ! 4454: /* ! 4455: * If this page is not pageable, we have to get ! 4456: * it for all possible accesses. ! 4457: */ ! 4458: ! 4459: if (*wired = (entry->wired_count != 0)) ! 4460: prot = fault_type = entry->protection; ! 4461: ! 4462: /* ! 4463: * If the entry was copy-on-write, we either ... ! 4464: */ ! 4465: ! 4466: if (entry->needs_copy) { ! 4467: /* ! 4468: * If we want to write the page, we may as well ! 4469: * handle that now since we've got the map locked. ! 4470: * ! 4471: * If we don't need to write the page, we just ! 4472: * demote the permissions allowed. ! 4473: */ ! 4474: ! 4475: if (fault_type & VM_PROT_WRITE) { ! 4476: /* ! 4477: * Make a new object, and place it in the ! 4478: * object chain. Note that no new references ! 4479: * have appeared -- one just moved from the ! 4480: * map to the new object. ! 4481: */ ! 4482: ! 4483: if (vm_map_lock_read_to_write(map)) { ! 4484: goto RetryLookup; ! 4485: } ! 4486: map->timestamp++; ! 4487: ! 4488: vm_object_shadow( ! 4489: &entry->object.vm_object, ! 4490: &entry->offset, ! 4491: (vm_size_t) (entry->vme_end - entry->vme_start)); ! 4492: ! 4493: entry->needs_copy = FALSE; ! 4494: ! 4495: vm_map_lock_write_to_read(map); ! 4496: } ! 4497: else { ! 4498: /* ! 4499: * We're attempting to read a copy-on-write ! 4500: * page -- don't allow writes. ! 4501: */ ! 4502: ! 4503: prot &= (~VM_PROT_WRITE); ! 4504: } ! 4505: } ! 4506: ! 4507: /* ! 4508: * Create an object if necessary. ! 4509: */ ! 4510: if (entry->object.vm_object == VM_OBJECT_NULL) { ! 4511: ! 4512: if (vm_map_lock_read_to_write(map)) { ! 4513: goto RetryLookup; ! 4514: } ! 4515: ! 4516: entry->object.vm_object = vm_object_allocate( ! 4517: (vm_size_t)(entry->vme_end - entry->vme_start)); ! 4518: entry->offset = 0; ! 4519: vm_map_lock_write_to_read(map); ! 4520: } ! 4521: ! 4522: /* ! 4523: * Return the object/offset from this entry. If the entry ! 4524: * was copy-on-write or empty, it has been fixed up. Also ! 4525: * return the protection. ! 4526: */ ! 4527: ! 4528: *offset = (vaddr - entry->vme_start) + entry->offset; ! 4529: *object = entry->object.vm_object; ! 4530: *out_prot = prot; ! 4531: ! 4532: /* ! 4533: * Lock the object to prevent it from disappearing ! 4534: */ ! 4535: ! 4536: vm_object_lock(*object); ! 4537: ! 4538: /* ! 4539: * Save the version number and unlock the map. ! 4540: */ ! 4541: ! 4542: out_version->main_timestamp = map->timestamp; ! 4543: ! 4544: RETURN(KERN_SUCCESS); ! 4545: ! 4546: #undef RETURN ! 4547: } ! 4548: ! 4549: /* ! 4550: * vm_map_verify: ! 4551: * ! 4552: * Verifies that the map in question has not changed ! 4553: * since the given version. If successful, the map ! 4554: * will not change until vm_map_verify_done() is called. ! 4555: */ ! 4556: boolean_t vm_map_verify(map, version) ! 4557: register ! 4558: vm_map_t map; ! 4559: register ! 4560: vm_map_version_t *version; /* REF */ ! 4561: { ! 4562: boolean_t result; ! 4563: ! 4564: vm_map_lock_read(map); ! 4565: result = (map->timestamp == version->main_timestamp); ! 4566: ! 4567: if (!result) ! 4568: vm_map_unlock_read(map); ! 4569: ! 4570: return(result); ! 4571: } ! 4572: ! 4573: /* ! 4574: * vm_map_verify_done: ! 4575: * ! 4576: * Releases locks acquired by a vm_map_verify. ! 4577: * ! 4578: * This is now a macro in vm/vm_map.h. It does a ! 4579: * vm_map_unlock_read on the map. ! 4580: */ ! 4581: ! 4582: /* ! 4583: * vm_region: ! 4584: * ! 4585: * User call to obtain information about a region in ! 4586: * a task's address map. ! 4587: */ ! 4588: ! 4589: kern_return_t vm_region(map, address, size, ! 4590: protection, max_protection, ! 4591: inheritance, is_shared, ! 4592: object_name, offset_in_object) ! 4593: vm_map_t map; ! 4594: vm_offset_t *address; /* IN/OUT */ ! 4595: vm_size_t *size; /* OUT */ ! 4596: vm_prot_t *protection; /* OUT */ ! 4597: vm_prot_t *max_protection; /* OUT */ ! 4598: vm_inherit_t *inheritance; /* OUT */ ! 4599: boolean_t *is_shared; /* OUT */ ! 4600: ipc_port_t *object_name; /* OUT */ ! 4601: vm_offset_t *offset_in_object; /* OUT */ ! 4602: { ! 4603: vm_map_entry_t tmp_entry; ! 4604: register ! 4605: vm_map_entry_t entry; ! 4606: register ! 4607: vm_offset_t tmp_offset; ! 4608: vm_offset_t start; ! 4609: ! 4610: if (map == VM_MAP_NULL) ! 4611: return(KERN_INVALID_ARGUMENT); ! 4612: ! 4613: start = *address; ! 4614: ! 4615: vm_map_lock_read(map); ! 4616: if (!vm_map_lookup_entry(map, start, &tmp_entry)) { ! 4617: if ((entry = tmp_entry->vme_next) == vm_map_to_entry(map)) { ! 4618: vm_map_unlock_read(map); ! 4619: return(KERN_NO_SPACE); ! 4620: } ! 4621: } else { ! 4622: entry = tmp_entry; ! 4623: } ! 4624: ! 4625: start = entry->vme_start; ! 4626: *protection = entry->protection; ! 4627: *max_protection = entry->max_protection; ! 4628: *inheritance = entry->inheritance; ! 4629: *address = start; ! 4630: *size = (entry->vme_end - start); ! 4631: ! 4632: tmp_offset = entry->offset; ! 4633: ! 4634: ! 4635: if (entry->is_sub_map) { ! 4636: *is_shared = FALSE; ! 4637: *object_name = IP_NULL; ! 4638: *offset_in_object = tmp_offset; ! 4639: } else { ! 4640: *is_shared = entry->is_shared; ! 4641: *object_name = vm_object_name(entry->object.vm_object); ! 4642: *offset_in_object = tmp_offset; ! 4643: } ! 4644: ! 4645: vm_map_unlock_read(map); ! 4646: ! 4647: return(KERN_SUCCESS); ! 4648: } ! 4649: ! 4650: /* ! 4651: * Routine: vm_map_simplify ! 4652: * ! 4653: * Description: ! 4654: * Attempt to simplify the map representation in ! 4655: * the vicinity of the given starting address. ! 4656: * Note: ! 4657: * This routine is intended primarily to keep the ! 4658: * kernel maps more compact -- they generally don't ! 4659: * benefit from the "expand a map entry" technology ! 4660: * at allocation time because the adjacent entry ! 4661: * is often wired down. ! 4662: */ ! 4663: void vm_map_simplify(map, start) ! 4664: vm_map_t map; ! 4665: vm_offset_t start; ! 4666: { ! 4667: vm_map_entry_t this_entry; ! 4668: vm_map_entry_t prev_entry; ! 4669: ! 4670: vm_map_lock(map); ! 4671: if ( ! 4672: (vm_map_lookup_entry(map, start, &this_entry)) && ! 4673: ((prev_entry = this_entry->vme_prev) != vm_map_to_entry(map)) && ! 4674: ! 4675: (prev_entry->vme_end == start) && ! 4676: ! 4677: (prev_entry->is_shared == FALSE) && ! 4678: (prev_entry->is_sub_map == FALSE) && ! 4679: ! 4680: (this_entry->is_shared == FALSE) && ! 4681: (this_entry->is_sub_map == FALSE) && ! 4682: ! 4683: (prev_entry->inheritance == this_entry->inheritance) && ! 4684: (prev_entry->protection == this_entry->protection) && ! 4685: (prev_entry->max_protection == this_entry->max_protection) && ! 4686: (prev_entry->wired_count == this_entry->wired_count) && ! 4687: (prev_entry->user_wired_count == this_entry->user_wired_count) && ! 4688: ! 4689: (prev_entry->needs_copy == this_entry->needs_copy) && ! 4690: ! 4691: (prev_entry->object.vm_object == this_entry->object.vm_object) && ! 4692: ((prev_entry->offset + (prev_entry->vme_end - prev_entry->vme_start)) ! 4693: == this_entry->offset) && ! 4694: (prev_entry->projected_on == 0) && ! 4695: (this_entry->projected_on == 0) ! 4696: ) { ! 4697: if (map->first_free == this_entry) ! 4698: map->first_free = prev_entry; ! 4699: ! 4700: SAVE_HINT(map, prev_entry); ! 4701: vm_map_entry_unlink(map, this_entry); ! 4702: prev_entry->vme_end = this_entry->vme_end; ! 4703: vm_object_deallocate(this_entry->object.vm_object); ! 4704: vm_map_entry_dispose(map, this_entry); ! 4705: } ! 4706: vm_map_unlock(map); ! 4707: } ! 4708: ! 4709: ! 4710: /* ! 4711: * Routine: vm_map_machine_attribute ! 4712: * Purpose: ! 4713: * Provide machine-specific attributes to mappings, ! 4714: * such as cachability etc. for machines that provide ! 4715: * them. NUMA architectures and machines with big/strange ! 4716: * caches will use this. ! 4717: * Note: ! 4718: * Responsibilities for locking and checking are handled here, ! 4719: * everything else in the pmap module. If any non-volatile ! 4720: * information must be kept, the pmap module should handle ! 4721: * it itself. [This assumes that attributes do not ! 4722: * need to be inherited, which seems ok to me] ! 4723: */ ! 4724: kern_return_t vm_map_machine_attribute(map, address, size, attribute, value) ! 4725: vm_map_t map; ! 4726: vm_offset_t address; ! 4727: vm_size_t size; ! 4728: vm_machine_attribute_t attribute; ! 4729: vm_machine_attribute_val_t* value; /* IN/OUT */ ! 4730: { ! 4731: kern_return_t ret; ! 4732: ! 4733: if (address < vm_map_min(map) || ! 4734: (address + size) > vm_map_max(map)) ! 4735: return KERN_INVALID_ARGUMENT; ! 4736: ! 4737: vm_map_lock(map); ! 4738: ! 4739: ret = pmap_attribute(map->pmap, address, size, attribute, value); ! 4740: ! 4741: vm_map_unlock(map); ! 4742: ! 4743: return ret; ! 4744: } ! 4745: ! 4746: #include <mach_kdb.h> ! 4747: ! 4748: ! 4749: #if MACH_KDB ! 4750: ! 4751: #define printf kdbprintf ! 4752: ! 4753: /* ! 4754: * vm_map_print: [ debug ] ! 4755: */ ! 4756: void vm_map_print(map) ! 4757: register vm_map_t map; ! 4758: { ! 4759: register vm_map_entry_t entry; ! 4760: extern int indent; ! 4761: ! 4762: iprintf("Task map 0x%X: pmap=0x%X,", ! 4763: (vm_offset_t) map, (vm_offset_t) (map->pmap)); ! 4764: printf("ref=%d,nentries=%d,", map->ref_count, map->hdr.nentries); ! 4765: printf("version=%d\n", map->timestamp); ! 4766: indent += 2; ! 4767: for (entry = vm_map_first_entry(map); ! 4768: entry != vm_map_to_entry(map); ! 4769: entry = entry->vme_next) { ! 4770: static char *inheritance_name[3] = { "share", "copy", "none"}; ! 4771: ! 4772: iprintf("map entry 0x%X: ", (vm_offset_t) entry); ! 4773: printf("start=0x%X, end=0x%X, ", ! 4774: (vm_offset_t) entry->vme_start, (vm_offset_t) entry->vme_end); ! 4775: printf("prot=%X/%X/%s, ", ! 4776: entry->protection, ! 4777: entry->max_protection, ! 4778: inheritance_name[entry->inheritance]); ! 4779: if (entry->wired_count != 0) { ! 4780: printf("wired("); ! 4781: if (entry->user_wired_count != 0) ! 4782: printf("u"); ! 4783: if (entry->wired_count > ! 4784: ((entry->user_wired_count == 0) ? 0 : 1)) ! 4785: printf("k"); ! 4786: printf(") "); ! 4787: } ! 4788: if (entry->in_transition) { ! 4789: printf("in transition"); ! 4790: if (entry->needs_wakeup) ! 4791: printf("(wake request)"); ! 4792: printf(", "); ! 4793: } ! 4794: if (entry->is_sub_map) { ! 4795: printf("submap=0x%X, offset=0x%X\n", ! 4796: (vm_offset_t) entry->object.sub_map, ! 4797: (vm_offset_t) entry->offset); ! 4798: } else { ! 4799: printf("object=0x%X, offset=0x%X", ! 4800: (vm_offset_t) entry->object.vm_object, ! 4801: (vm_offset_t) entry->offset); ! 4802: if (entry->is_shared) ! 4803: printf(", shared"); ! 4804: if (entry->needs_copy) ! 4805: printf(", copy needed"); ! 4806: printf("\n"); ! 4807: ! 4808: if ((entry->vme_prev == vm_map_to_entry(map)) || ! 4809: (entry->vme_prev->object.vm_object != entry->object.vm_object)) { ! 4810: indent += 2; ! 4811: vm_object_print(entry->object.vm_object); ! 4812: indent -= 2; ! 4813: } ! 4814: } ! 4815: } ! 4816: indent -= 2; ! 4817: } ! 4818: ! 4819: /* ! 4820: * Routine: vm_map_copy_print ! 4821: * Purpose: ! 4822: * Pretty-print a copy object for ddb. ! 4823: */ ! 4824: ! 4825: void vm_map_copy_print(copy) ! 4826: vm_map_copy_t copy; ! 4827: { ! 4828: extern int indent; ! 4829: int i, npages; ! 4830: ! 4831: printf("copy object 0x%x\n", copy); ! 4832: ! 4833: indent += 2; ! 4834: ! 4835: iprintf("type=%d", copy->type); ! 4836: switch (copy->type) { ! 4837: case VM_MAP_COPY_ENTRY_LIST: ! 4838: printf("[entry_list]"); ! 4839: break; ! 4840: ! 4841: case VM_MAP_COPY_OBJECT: ! 4842: printf("[object]"); ! 4843: break; ! 4844: ! 4845: case VM_MAP_COPY_PAGE_LIST: ! 4846: printf("[page_list]"); ! 4847: break; ! 4848: ! 4849: default: ! 4850: printf("[bad type]"); ! 4851: break; ! 4852: } ! 4853: printf(", offset=0x%x", copy->offset); ! 4854: printf(", size=0x%x\n", copy->size); ! 4855: ! 4856: switch (copy->type) { ! 4857: case VM_MAP_COPY_ENTRY_LIST: ! 4858: /* XXX add stuff here */ ! 4859: break; ! 4860: ! 4861: case VM_MAP_COPY_OBJECT: ! 4862: iprintf("object=0x%x\n", copy->cpy_object); ! 4863: break; ! 4864: ! 4865: case VM_MAP_COPY_PAGE_LIST: ! 4866: iprintf("npages=%d", copy->cpy_npages); ! 4867: printf(", cont=%x", copy->cpy_cont); ! 4868: printf(", cont_args=%x\n", copy->cpy_cont_args); ! 4869: if (copy->cpy_npages < 0) { ! 4870: npages = 0; ! 4871: } else if (copy->cpy_npages > VM_MAP_COPY_PAGE_LIST_MAX) { ! 4872: npages = VM_MAP_COPY_PAGE_LIST_MAX; ! 4873: } else { ! 4874: npages = copy->cpy_npages; ! 4875: } ! 4876: iprintf("copy->cpy_page_list[0..%d] = {", npages); ! 4877: for (i = 0; i < npages - 1; i++) { ! 4878: printf("0x%x, ", copy->cpy_page_list[i]); ! 4879: } ! 4880: if (npages > 0) { ! 4881: printf("0x%x", copy->cpy_page_list[npages - 1]); ! 4882: } ! 4883: printf("}\n"); ! 4884: break; ! 4885: } ! 4886: ! 4887: indent -=2; ! 4888: } ! 4889: #endif /* MACH_KDB */ ! 4890: ! 4891: #if NORMA_IPC ! 4892: /* ! 4893: * This should one day be eliminated; ! 4894: * we should always construct the right flavor of copy object ! 4895: * the first time. Troublesome areas include vm_read, where vm_map_copyin ! 4896: * is called without knowing whom the copy object is for. ! 4897: * There are also situations where we do want a lazy data structure ! 4898: * even if we are sending to a remote port... ! 4899: */ ! 4900: ! 4901: /* ! 4902: * Convert a copy to a page list. The copy argument is in/out ! 4903: * because we probably have to allocate a new vm_map_copy structure. ! 4904: * We take responsibility for discarding the old structure and ! 4905: * use a continuation to do so. Postponing this discard ensures ! 4906: * that the objects containing the pages we've marked busy will stick ! 4907: * around. ! 4908: */ ! 4909: kern_return_t ! 4910: vm_map_convert_to_page_list(caller_copy) ! 4911: vm_map_copy_t *caller_copy; ! 4912: { ! 4913: vm_map_entry_t entry, next_entry; ! 4914: vm_offset_t va; ! 4915: vm_offset_t offset; ! 4916: vm_object_t object; ! 4917: kern_return_t result; ! 4918: vm_map_copy_t copy, new_copy; ! 4919: int i, num_pages = 0; ! 4920: ! 4921: zone_t entry_zone; ! 4922: ! 4923: copy = *caller_copy; ! 4924: ! 4925: /* ! 4926: * We may not have to do anything, ! 4927: * or may not be able to do anything. ! 4928: */ ! 4929: if (copy == VM_MAP_COPY_NULL || copy->type == VM_MAP_COPY_PAGE_LIST) { ! 4930: return KERN_SUCCESS; ! 4931: } ! 4932: if (copy->type == VM_MAP_COPY_OBJECT) { ! 4933: return vm_map_convert_to_page_list_from_object(caller_copy); ! 4934: } ! 4935: if (copy->type != VM_MAP_COPY_ENTRY_LIST) { ! 4936: panic("vm_map_convert_to_page_list: copy type %d!\n", ! 4937: copy->type); ! 4938: } ! 4939: ! 4940: /* ! 4941: * Allocate the new copy. Set its continuation to ! 4942: * discard the old one. ! 4943: */ ! 4944: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 4945: new_copy->type = VM_MAP_COPY_PAGE_LIST; ! 4946: new_copy->cpy_npages = 0; ! 4947: new_copy->offset = copy->offset; ! 4948: new_copy->size = copy->size; ! 4949: new_copy->cpy_cont = vm_map_copy_discard_cont; ! 4950: new_copy->cpy_cont_args = (char *) copy; ! 4951: ! 4952: /* ! 4953: * Iterate over entries. ! 4954: */ ! 4955: for (entry = vm_map_copy_first_entry(copy); ! 4956: entry != vm_map_copy_to_entry(copy); ! 4957: entry = entry->vme_next) { ! 4958: ! 4959: object = entry->object.vm_object; ! 4960: offset = entry->offset; ! 4961: /* ! 4962: * Iterate over pages. ! 4963: */ ! 4964: for (va = entry->vme_start; ! 4965: va < entry->vme_end; ! 4966: va += PAGE_SIZE, offset += PAGE_SIZE) { ! 4967: ! 4968: vm_page_t m; ! 4969: ! 4970: if (new_copy->cpy_npages == VM_MAP_COPY_PAGE_LIST_MAX) { ! 4971: /* ! 4972: * What a mess. We need a continuation ! 4973: * to do the page list, but also one ! 4974: * to discard the old copy. The right ! 4975: * thing to do is probably to copy ! 4976: * out the old copy into the kernel ! 4977: * map (or some temporary task holding ! 4978: * map if we're paranoid about large ! 4979: * copies), and then copyin the page ! 4980: * list that we really wanted with ! 4981: * src_destroy. LATER. ! 4982: */ ! 4983: panic("vm_map_convert_to_page_list: num\n"); ! 4984: } ! 4985: ! 4986: /* ! 4987: * Try to find the page of data. ! 4988: */ ! 4989: vm_object_lock(object); ! 4990: vm_object_paging_begin(object); ! 4991: if (((m = vm_page_lookup(object, offset)) != ! 4992: VM_PAGE_NULL) && !m->busy && !m->fictitious && ! 4993: !m->absent && !m->error) { ! 4994: ! 4995: /* ! 4996: * This is the page. Mark it busy ! 4997: * and keep the paging reference on ! 4998: * the object whilst we do our thing. ! 4999: */ ! 5000: m->busy = TRUE; ! 5001: ! 5002: /* ! 5003: * Also write-protect the page, so ! 5004: * that the map`s owner cannot change ! 5005: * the data. The busy bit will prevent ! 5006: * faults on the page from succeeding ! 5007: * until the copy is released; after ! 5008: * that, the page can be re-entered ! 5009: * as writable, since we didn`t alter ! 5010: * the map entry. This scheme is a ! 5011: * cheap copy-on-write. ! 5012: * ! 5013: * Don`t forget the protection and ! 5014: * the page_lock value! ! 5015: */ ! 5016: ! 5017: pmap_page_protect(m->phys_addr, ! 5018: entry->protection ! 5019: & ~m->page_lock ! 5020: & ~VM_PROT_WRITE); ! 5021: ! 5022: } ! 5023: else { ! 5024: vm_prot_t result_prot; ! 5025: vm_page_t top_page; ! 5026: kern_return_t kr; ! 5027: ! 5028: retry: ! 5029: result_prot = VM_PROT_READ; ! 5030: ! 5031: kr = vm_fault_page(object, offset, ! 5032: VM_PROT_READ, FALSE, FALSE, ! 5033: &result_prot, &m, &top_page, ! 5034: FALSE, (void (*)()) 0); ! 5035: if (kr == VM_FAULT_MEMORY_SHORTAGE) { ! 5036: VM_PAGE_WAIT((void (*)()) 0); ! 5037: vm_object_lock(object); ! 5038: vm_object_paging_begin(object); ! 5039: goto retry; ! 5040: } ! 5041: if (kr != VM_FAULT_SUCCESS) { ! 5042: /* XXX what about data_error? */ ! 5043: vm_object_lock(object); ! 5044: vm_object_paging_begin(object); ! 5045: goto retry; ! 5046: } ! 5047: if (top_page != VM_PAGE_NULL) { ! 5048: vm_object_lock(object); ! 5049: VM_PAGE_FREE(top_page); ! 5050: vm_object_paging_end(object); ! 5051: vm_object_unlock(object); ! 5052: } ! 5053: } ! 5054: assert(m); ! 5055: m->busy = TRUE; ! 5056: new_copy->cpy_page_list[new_copy->cpy_npages++] = m; ! 5057: vm_object_unlock(object); ! 5058: } ! 5059: } ! 5060: ! 5061: *caller_copy = new_copy; ! 5062: return KERN_SUCCESS; ! 5063: } ! 5064: ! 5065: kern_return_t ! 5066: vm_map_convert_to_page_list_from_object(caller_copy) ! 5067: vm_map_copy_t *caller_copy; ! 5068: { ! 5069: vm_object_t object; ! 5070: vm_offset_t offset; ! 5071: vm_map_copy_t copy, new_copy; ! 5072: ! 5073: copy = *caller_copy; ! 5074: assert(copy->type == VM_MAP_COPY_OBJECT); ! 5075: object = copy->cpy_object; ! 5076: assert(object->size == round_page(object->size)); ! 5077: ! 5078: /* ! 5079: * Allocate the new copy. Set its continuation to ! 5080: * discard the old one. ! 5081: */ ! 5082: new_copy = (vm_map_copy_t) zalloc(vm_map_copy_zone); ! 5083: new_copy->type = VM_MAP_COPY_PAGE_LIST; ! 5084: new_copy->cpy_npages = 0; ! 5085: new_copy->offset = copy->offset; ! 5086: new_copy->size = copy->size; ! 5087: new_copy->cpy_cont = vm_map_copy_discard_cont; ! 5088: new_copy->cpy_cont_args = (char *) copy; ! 5089: ! 5090: /* ! 5091: * XXX memory_object_lock_request can probably bust this ! 5092: * XXX See continuation comment in previous routine for solution. ! 5093: */ ! 5094: assert(object->size <= VM_MAP_COPY_PAGE_LIST_MAX * PAGE_SIZE); ! 5095: ! 5096: for (offset = 0; offset < object->size; offset += PAGE_SIZE) { ! 5097: vm_page_t m; ! 5098: ! 5099: /* ! 5100: * Try to find the page of data. ! 5101: */ ! 5102: vm_object_lock(object); ! 5103: vm_object_paging_begin(object); ! 5104: m = vm_page_lookup(object, offset); ! 5105: if ((m != VM_PAGE_NULL) && !m->busy && !m->fictitious && ! 5106: !m->absent && !m->error) { ! 5107: ! 5108: /* ! 5109: * This is the page. Mark it busy ! 5110: * and keep the paging reference on ! 5111: * the object whilst we do our thing. ! 5112: */ ! 5113: m->busy = TRUE; ! 5114: } ! 5115: else { ! 5116: vm_prot_t result_prot; ! 5117: vm_page_t top_page; ! 5118: kern_return_t kr; ! 5119: ! 5120: retry: ! 5121: result_prot = VM_PROT_READ; ! 5122: ! 5123: kr = vm_fault_page(object, offset, ! 5124: VM_PROT_READ, FALSE, FALSE, ! 5125: &result_prot, &m, &top_page, ! 5126: FALSE, (void (*)()) 0); ! 5127: if (kr == VM_FAULT_MEMORY_SHORTAGE) { ! 5128: VM_PAGE_WAIT((void (*)()) 0); ! 5129: vm_object_lock(object); ! 5130: vm_object_paging_begin(object); ! 5131: goto retry; ! 5132: } ! 5133: if (kr != VM_FAULT_SUCCESS) { ! 5134: /* XXX what about data_error? */ ! 5135: vm_object_lock(object); ! 5136: vm_object_paging_begin(object); ! 5137: goto retry; ! 5138: } ! 5139: ! 5140: if (top_page != VM_PAGE_NULL) { ! 5141: vm_object_lock(object); ! 5142: VM_PAGE_FREE(top_page); ! 5143: vm_object_paging_end(object); ! 5144: vm_object_unlock(object); ! 5145: } ! 5146: } ! 5147: assert(m); ! 5148: m->busy = TRUE; ! 5149: new_copy->cpy_page_list[new_copy->cpy_npages++] = m; ! 5150: vm_object_unlock(object); ! 5151: } ! 5152: ! 5153: *caller_copy = new_copy; ! 5154: return (KERN_SUCCESS); ! 5155: } ! 5156: ! 5157: kern_return_t ! 5158: vm_map_convert_from_page_list(copy) ! 5159: vm_map_copy_t copy; ! 5160: { ! 5161: vm_object_t object; ! 5162: int i; ! 5163: vm_map_entry_t new_entry; ! 5164: vm_page_t *page_list; ! 5165: ! 5166: /* ! 5167: * Check type of copy object. ! 5168: */ ! 5169: if (copy->type == VM_MAP_COPY_ENTRY_LIST) { ! 5170: return KERN_SUCCESS; ! 5171: } ! 5172: if (copy->type == VM_MAP_COPY_OBJECT) { ! 5173: printf("vm_map_convert_from_page_list: COPY_OBJECT?"); ! 5174: return KERN_SUCCESS; ! 5175: } ! 5176: if (copy->type != VM_MAP_COPY_PAGE_LIST) { ! 5177: panic("vm_map_convert_from_page_list 0x%x %d", ! 5178: copy, ! 5179: copy->type); ! 5180: } ! 5181: ! 5182: /* ! 5183: * Make sure the pages are loose. This may be ! 5184: * a "Can't Happen", but just to be safe ... ! 5185: */ ! 5186: page_list = ©->cpy_page_list[0]; ! 5187: if ((*page_list)->tabled) ! 5188: vm_map_copy_steal_pages(copy); ! 5189: ! 5190: /* ! 5191: * Create object, and stuff pages into it. ! 5192: */ ! 5193: object = vm_object_allocate(copy->cpy_npages); ! 5194: for (i = 0; i < copy->cpy_npages; i++) { ! 5195: register vm_page_t m = *page_list++; ! 5196: vm_page_insert(m, object, i * PAGE_SIZE); ! 5197: m->busy = FALSE; ! 5198: m->dirty = TRUE; ! 5199: vm_page_activate(m); ! 5200: } ! 5201: ! 5202: /* ! 5203: * XXX If this page list contained a continuation, then ! 5204: * XXX we're screwed. The right thing to do is probably do ! 5205: * XXX the copyout, and then copyin the entry list we really ! 5206: * XXX wanted. ! 5207: */ ! 5208: if (vm_map_copy_has_cont(copy)) ! 5209: panic("convert_from_page_list: continuation"); ! 5210: ! 5211: /* ! 5212: * Change type of copy object ! 5213: */ ! 5214: vm_map_copy_first_entry(copy) = ! 5215: vm_map_copy_last_entry(copy) = vm_map_copy_to_entry(copy); ! 5216: copy->type = VM_MAP_COPY_ENTRY_LIST; ! 5217: copy->cpy_hdr.nentries = 0; ! 5218: copy->cpy_hdr.entries_pageable = TRUE; ! 5219: ! 5220: /* ! 5221: * Allocate and initialize an entry for object ! 5222: */ ! 5223: new_entry = vm_map_copy_entry_create(copy); ! 5224: new_entry->vme_start = trunc_page(copy->offset); ! 5225: new_entry->vme_end = round_page(copy->offset + copy->size); ! 5226: new_entry->object.vm_object = object; ! 5227: new_entry->offset = 0; ! 5228: new_entry->is_shared = FALSE; ! 5229: new_entry->is_sub_map = FALSE; ! 5230: new_entry->needs_copy = FALSE; ! 5231: new_entry->protection = VM_PROT_DEFAULT; ! 5232: new_entry->max_protection = VM_PROT_ALL; ! 5233: new_entry->inheritance = VM_INHERIT_DEFAULT; ! 5234: new_entry->wired_count = 0; ! 5235: new_entry->user_wired_count = 0; ! 5236: new_entry->projected_on = 0; ! 5237: ! 5238: /* ! 5239: * Insert entry into copy object, and return. ! 5240: */ ! 5241: vm_map_copy_entry_link(copy, vm_map_copy_last_entry(copy), new_entry); ! 5242: return(KERN_SUCCESS); ! 5243: } ! 5244: #endif /* NORMA_IPC */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.