|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1991 Regents of the University of California. ! 3: * All rights reserved. ! 4: * ! 5: * This code is derived from software contributed to Berkeley by ! 6: * The Mach Operating System project at Carnegie-Mellon University. ! 7: * ! 8: * Redistribution and use in source and binary forms, with or without ! 9: * modification, are permitted provided that the following conditions ! 10: * are met: ! 11: * 1. Redistributions of source code must retain the above copyright ! 12: * notice, this list of conditions and the following disclaimer. ! 13: * 2. Redistributions in binary form must reproduce the above copyright ! 14: * notice, this list of conditions and the following disclaimer in the ! 15: * documentation and/or other materials provided with the distribution. ! 16: * 3. All advertising materials mentioning features or use of this software ! 17: * must display the following acknowledgement: ! 18: * This product includes software developed by the University of ! 19: * California, Berkeley and its contributors. ! 20: * 4. Neither the name of the University nor the names of its contributors ! 21: * may be used to endorse or promote products derived from this software ! 22: * without specific prior written permission. ! 23: * ! 24: * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND ! 25: * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE ! 26: * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ! 27: * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE ! 28: * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL ! 29: * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS ! 30: * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) ! 31: * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT ! 32: * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY ! 33: * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF ! 34: * SUCH DAMAGE. ! 35: * ! 36: * @(#)vm_map.c 7.3 (Berkeley) 4/21/91 ! 37: * ! 38: * ! 39: * Copyright (c) 1987, 1990 Carnegie-Mellon University. ! 40: * All rights reserved. ! 41: * ! 42: * Authors: Avadis Tevanian, Jr., Michael Wayne Young ! 43: * ! 44: * Permission to use, copy, modify and distribute this software and ! 45: * its documentation is hereby granted, provided that both the copyright ! 46: * notice and this permission notice appear in all copies of the ! 47: * software, derivative works or modified versions, and any portions ! 48: * thereof, and that both notices appear in supporting documentation. ! 49: * ! 50: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 51: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND ! 52: * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 53: * ! 54: * Carnegie Mellon requests users of this software to return to ! 55: * ! 56: * Software Distribution Coordinator or [email protected] ! 57: * School of Computer Science ! 58: * Carnegie Mellon University ! 59: * Pittsburgh PA 15213-3890 ! 60: * ! 61: * any improvements or extensions that they make and grant Carnegie the ! 62: * rights to redistribute these changes. ! 63: */ ! 64: ! 65: /* ! 66: * Virtual memory mapping module. ! 67: */ ! 68: ! 69: #include "param.h" ! 70: #include "malloc.h" ! 71: #include "vm.h" ! 72: #include "vm_page.h" ! 73: #include "vm_object.h" ! 74: ! 75: /* ! 76: * Virtual memory maps provide for the mapping, protection, ! 77: * and sharing of virtual memory objects. In addition, ! 78: * this module provides for an efficient virtual copy of ! 79: * memory from one map to another. ! 80: * ! 81: * Synchronization is required prior to most operations. ! 82: * ! 83: * Maps consist of an ordered doubly-linked list of simple ! 84: * entries; a single hint is used to speed up lookups. ! 85: * ! 86: * In order to properly represent the sharing of virtual ! 87: * memory regions among maps, the map structure is bi-level. ! 88: * Top-level ("address") maps refer to regions of sharable ! 89: * virtual memory. These regions are implemented as ! 90: * ("sharing") maps, which then refer to the actual virtual ! 91: * memory objects. When two address maps "share" memory, ! 92: * their top-level maps both have references to the same ! 93: * sharing map. When memory is virtual-copied from one ! 94: * address map to another, the references in the sharing ! 95: * maps are actually copied -- no copying occurs at the ! 96: * virtual memory object level. ! 97: * ! 98: * Since portions of maps are specified by start/end addreses, ! 99: * which may not align with existing map entries, all ! 100: * routines merely "clip" entries to these start/end values. ! 101: * [That is, an entry is split into two, bordering at a ! 102: * start or end value.] Note that these clippings may not ! 103: * always be necessary (as the two resulting entries are then ! 104: * not changed); however, the clipping is done for convenience. ! 105: * No attempt is currently made to "glue back together" two ! 106: * abutting entries. ! 107: * ! 108: * As mentioned above, virtual copy operations are performed ! 109: * by copying VM object references from one sharing map to ! 110: * another, and then marking both regions as copy-on-write. ! 111: * It is important to note that only one writeable reference ! 112: * to a VM object region exists in any map -- this means that ! 113: * shadow object creation can be delayed until a write operation ! 114: * occurs. ! 115: */ ! 116: ! 117: /* ! 118: * vm_map_startup: ! 119: * ! 120: * Initialize the vm_map module. Must be called before ! 121: * any other vm_map routines. ! 122: * ! 123: * Map and entry structures are allocated from the general ! 124: * purpose memory pool with some exceptions: ! 125: * ! 126: * - The kernel map and kmem submap are allocated statically. ! 127: * - Kernel map entries are allocated out of a static pool. ! 128: * ! 129: * These restrictions are necessary since malloc() uses the ! 130: * maps and requires map entries. ! 131: */ ! 132: ! 133: vm_offset_t kentry_data; ! 134: vm_size_t kentry_data_size; ! 135: vm_map_entry_t kentry_free; ! 136: vm_map_t kmap_free; ! 137: ! 138: void vm_map_startup() ! 139: { ! 140: register int i; ! 141: register vm_map_entry_t mep; ! 142: vm_map_t mp; ! 143: ! 144: /* ! 145: * Static map structures for allocation before initialization of ! 146: * kernel map or kmem map. vm_map_create knows how to deal with them. ! 147: */ ! 148: kmap_free = mp = (vm_map_t) kentry_data; ! 149: i = MAX_KMAP; ! 150: while (--i > 0) { ! 151: mp->header.next = (vm_map_entry_t) (mp + 1); ! 152: mp++; ! 153: } ! 154: mp++->header.next = NULL; ! 155: ! 156: /* ! 157: * Form a free list of statically allocated kernel map entries ! 158: * with the rest. ! 159: */ ! 160: kentry_free = mep = (vm_map_entry_t) mp; ! 161: i = (kentry_data_size - MAX_KMAP * sizeof *mp) / sizeof *mep; ! 162: while (--i > 0) { ! 163: mep->next = mep + 1; ! 164: mep++; ! 165: } ! 166: mep->next = NULL; ! 167: } ! 168: ! 169: /* ! 170: * Allocate a vmspace structure, including a vm_map and pmap, ! 171: * and initialize those structures. The refcnt is set to 1. ! 172: * The remaining fields must be initialized by the caller. ! 173: */ ! 174: struct vmspace * ! 175: vmspace_alloc(min, max, pageable) ! 176: vm_offset_t min, max; ! 177: int pageable; ! 178: { ! 179: register struct vmspace *vm; ! 180: ! 181: MALLOC(vm, struct vmspace *, sizeof(struct vmspace), M_VMMAP, M_WAITOK); ! 182: bzero(vm, (caddr_t) &vm->vm_startcopy - (caddr_t) vm); ! 183: vm_map_init(&vm->vm_map, min, max, pageable); ! 184: pmap_pinit(&vm->vm_pmap); ! 185: vm->vm_map.pmap = &vm->vm_pmap; /* XXX */ ! 186: vm->vm_refcnt = 1; ! 187: return (vm); ! 188: } ! 189: ! 190: void ! 191: vmspace_free(vm) ! 192: register struct vmspace *vm; ! 193: { ! 194: ! 195: if (--vm->vm_refcnt == 0) { ! 196: /* ! 197: * Lock the map, to wait out all other references to it. ! 198: * Delete all of the mappings and pages they hold, ! 199: * then call the pmap module to reclaim anything left. ! 200: */ ! 201: vm_map_lock(&vm->vm_map); ! 202: (void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset, ! 203: vm->vm_map.max_offset); ! 204: pmap_release(&vm->vm_pmap); ! 205: FREE(vm, M_VMMAP); ! 206: } ! 207: } ! 208: ! 209: /* ! 210: * vm_map_create: ! 211: * ! 212: * Creates and returns a new empty VM map with ! 213: * the given physical map structure, and having ! 214: * the given lower and upper address bounds. ! 215: */ ! 216: vm_map_t vm_map_create(pmap, min, max, pageable) ! 217: pmap_t pmap; ! 218: vm_offset_t min, max; ! 219: boolean_t pageable; ! 220: { ! 221: register vm_map_t result; ! 222: extern vm_map_t kernel_map, kmem_map; ! 223: ! 224: if (kmem_map == NULL) { ! 225: result = kmap_free; ! 226: kmap_free = (vm_map_t) result->header.next; ! 227: if (result == NULL) ! 228: panic("vm_map_create: out of maps"); ! 229: } else ! 230: MALLOC(result, vm_map_t, sizeof(struct vm_map), ! 231: M_VMMAP, M_WAITOK); ! 232: ! 233: vm_map_init(result, min, max, pageable); ! 234: result->pmap = pmap; ! 235: return(result); ! 236: } ! 237: ! 238: /* ! 239: * Initialize an existing vm_map structure ! 240: * such as that in the vmspace structure. ! 241: * The pmap is set elsewhere. ! 242: */ ! 243: void ! 244: vm_map_init(map, min, max, pageable) ! 245: register struct vm_map *map; ! 246: vm_offset_t min, max; ! 247: boolean_t pageable; ! 248: { ! 249: map->header.next = map->header.prev = &map->header; ! 250: map->nentries = 0; ! 251: map->size = 0; ! 252: map->ref_count = 1; ! 253: map->is_main_map = TRUE; ! 254: map->min_offset = min; ! 255: map->max_offset = max; ! 256: map->entries_pageable = pageable; ! 257: map->first_free = &map->header; ! 258: map->hint = &map->header; ! 259: map->timestamp = 0; ! 260: lock_init(&map->lock, TRUE); ! 261: simple_lock_init(&map->ref_lock); ! 262: simple_lock_init(&map->hint_lock); ! 263: } ! 264: ! 265: /* ! 266: * vm_map_entry_create: [ internal use only ] ! 267: * ! 268: * Allocates a VM map entry for insertion. ! 269: * No entry fields are filled in. This routine is ! 270: */ ! 271: vm_map_entry_t vm_map_entry_create(map) ! 272: vm_map_t map; ! 273: { ! 274: vm_map_entry_t entry; ! 275: extern vm_map_t kernel_map, kmem_map, mb_map; ! 276: ! 277: if (map == kernel_map || map == kmem_map || map == mb_map) { ! 278: if (entry = kentry_free) ! 279: kentry_free = kentry_free->next; ! 280: } else ! 281: MALLOC(entry, vm_map_entry_t, sizeof(struct vm_map_entry), ! 282: M_VMMAPENT, M_WAITOK); ! 283: if (entry == NULL) ! 284: panic("vm_map_entry_create: out of map entries"); ! 285: ! 286: return(entry); ! 287: } ! 288: ! 289: /* ! 290: * vm_map_entry_dispose: [ internal use only ] ! 291: * ! 292: * Inverse of vm_map_entry_create. ! 293: */ ! 294: void vm_map_entry_dispose(map, entry) ! 295: vm_map_t map; ! 296: vm_map_entry_t entry; ! 297: { ! 298: extern vm_map_t kernel_map, kmem_map, mb_map; ! 299: ! 300: if (map == kernel_map || map == kmem_map || map == mb_map) { ! 301: entry->next = kentry_free; ! 302: kentry_free = entry; ! 303: } else ! 304: FREE(entry, M_VMMAPENT); ! 305: } ! 306: ! 307: /* ! 308: * vm_map_entry_{un,}link: ! 309: * ! 310: * Insert/remove entries from maps. ! 311: */ ! 312: #define vm_map_entry_link(map, after_where, entry) \ ! 313: { \ ! 314: (map)->nentries++; \ ! 315: (entry)->prev = (after_where); \ ! 316: (entry)->next = (after_where)->next; \ ! 317: (entry)->prev->next = (entry); \ ! 318: (entry)->next->prev = (entry); \ ! 319: } ! 320: #define vm_map_entry_unlink(map, entry) \ ! 321: { \ ! 322: (map)->nentries--; \ ! 323: (entry)->next->prev = (entry)->prev; \ ! 324: (entry)->prev->next = (entry)->next; \ ! 325: } ! 326: ! 327: /* ! 328: * vm_map_reference: ! 329: * ! 330: * Creates another valid reference to the given map. ! 331: * ! 332: */ ! 333: void vm_map_reference(map) ! 334: register vm_map_t map; ! 335: { ! 336: if (map == NULL) ! 337: return; ! 338: ! 339: simple_lock(&map->ref_lock); ! 340: map->ref_count++; ! 341: simple_unlock(&map->ref_lock); ! 342: } ! 343: ! 344: /* ! 345: * vm_map_deallocate: ! 346: * ! 347: * Removes a reference from the specified map, ! 348: * destroying it if no references remain. ! 349: * The map should not be locked. ! 350: */ ! 351: void vm_map_deallocate(map) ! 352: register vm_map_t map; ! 353: { ! 354: register int c; ! 355: ! 356: if (map == NULL) ! 357: return; ! 358: ! 359: simple_lock(&map->ref_lock); ! 360: c = --map->ref_count; ! 361: simple_unlock(&map->ref_lock); ! 362: ! 363: if (c > 0) { ! 364: return; ! 365: } ! 366: ! 367: /* ! 368: * Lock the map, to wait out all other references ! 369: * to it. ! 370: */ ! 371: ! 372: vm_map_lock(map); ! 373: ! 374: (void) vm_map_delete(map, map->min_offset, map->max_offset); ! 375: ! 376: pmap_destroy(map->pmap); ! 377: ! 378: FREE(map, M_VMMAP); ! 379: } ! 380: ! 381: /* ! 382: * vm_map_insert: [ internal use only ] ! 383: * ! 384: * Inserts the given whole VM object into the target ! 385: * map at the specified address range. The object's ! 386: * size should match that of the address range. ! 387: * ! 388: * Requires that the map be locked, and leaves it so. ! 389: */ ! 390: vm_map_insert(map, object, offset, start, end) ! 391: vm_map_t map; ! 392: vm_object_t object; ! 393: vm_offset_t offset; ! 394: vm_offset_t start; ! 395: vm_offset_t end; ! 396: { ! 397: register vm_map_entry_t new_entry; ! 398: register vm_map_entry_t prev_entry; ! 399: vm_map_entry_t temp_entry; ! 400: ! 401: /* ! 402: * Check that the start and end points are not bogus. ! 403: */ ! 404: ! 405: if ((start < map->min_offset) || (end > map->max_offset) || ! 406: (start >= end)) ! 407: return(KERN_INVALID_ADDRESS); ! 408: ! 409: /* ! 410: * Find the entry prior to the proposed ! 411: * starting address; if it's part of an ! 412: * existing entry, this range is bogus. ! 413: */ ! 414: ! 415: if (vm_map_lookup_entry(map, start, &temp_entry)) ! 416: return(KERN_NO_SPACE); ! 417: ! 418: prev_entry = temp_entry; ! 419: ! 420: /* ! 421: * Assert that the next entry doesn't overlap the ! 422: * end point. ! 423: */ ! 424: ! 425: if ((prev_entry->next != &map->header) && ! 426: (prev_entry->next->start < end)) ! 427: return(KERN_NO_SPACE); ! 428: ! 429: /* ! 430: * See if we can avoid creating a new entry by ! 431: * extending one of our neighbors. ! 432: */ ! 433: ! 434: if (object == NULL) { ! 435: if ((prev_entry != &map->header) && ! 436: (prev_entry->end == start) && ! 437: (map->is_main_map) && ! 438: (prev_entry->is_a_map == FALSE) && ! 439: (prev_entry->is_sub_map == FALSE) && ! 440: (prev_entry->inheritance == VM_INHERIT_DEFAULT) && ! 441: (prev_entry->protection == VM_PROT_DEFAULT) && ! 442: (prev_entry->max_protection == VM_PROT_DEFAULT) && ! 443: (prev_entry->wired_count == 0)) { ! 444: ! 445: if (vm_object_coalesce(prev_entry->object.vm_object, ! 446: NULL, ! 447: prev_entry->offset, ! 448: (vm_offset_t) 0, ! 449: (vm_size_t)(prev_entry->end ! 450: - prev_entry->start), ! 451: (vm_size_t)(end - prev_entry->end))) { ! 452: /* ! 453: * Coalesced the two objects - can extend ! 454: * the previous map entry to include the ! 455: * new range. ! 456: */ ! 457: map->size += (end - prev_entry->end); ! 458: prev_entry->end = end; ! 459: return(KERN_SUCCESS); ! 460: } ! 461: } ! 462: } ! 463: ! 464: /* ! 465: * Create a new entry ! 466: */ ! 467: ! 468: new_entry = vm_map_entry_create(map); ! 469: new_entry->start = start; ! 470: new_entry->end = end; ! 471: ! 472: new_entry->is_a_map = FALSE; ! 473: new_entry->is_sub_map = FALSE; ! 474: new_entry->object.vm_object = object; ! 475: new_entry->offset = offset; ! 476: ! 477: new_entry->copy_on_write = FALSE; ! 478: new_entry->needs_copy = FALSE; ! 479: ! 480: if (map->is_main_map) { ! 481: new_entry->inheritance = VM_INHERIT_DEFAULT; ! 482: new_entry->protection = VM_PROT_DEFAULT; ! 483: new_entry->max_protection = VM_PROT_DEFAULT; ! 484: new_entry->wired_count = 0; ! 485: } ! 486: ! 487: /* ! 488: * Insert the new entry into the list ! 489: */ ! 490: ! 491: vm_map_entry_link(map, prev_entry, new_entry); ! 492: map->size += new_entry->end - new_entry->start; ! 493: ! 494: /* ! 495: * Update the free space hint ! 496: */ ! 497: ! 498: if ((map->first_free == prev_entry) && (prev_entry->end >= new_entry->start)) ! 499: map->first_free = new_entry; ! 500: ! 501: return(KERN_SUCCESS); ! 502: } ! 503: ! 504: /* ! 505: * SAVE_HINT: ! 506: * ! 507: * Saves the specified entry as the hint for ! 508: * future lookups. Performs necessary interlocks. ! 509: */ ! 510: #define SAVE_HINT(map,value) \ ! 511: simple_lock(&(map)->hint_lock); \ ! 512: (map)->hint = (value); \ ! 513: simple_unlock(&(map)->hint_lock); ! 514: ! 515: /* ! 516: * vm_map_lookup_entry: [ internal use only ] ! 517: * ! 518: * Finds the map entry containing (or ! 519: * immediately preceding) the specified address ! 520: * in the given map; the entry is returned ! 521: * in the "entry" parameter. The boolean ! 522: * result indicates whether the address is ! 523: * actually contained in the map. ! 524: */ ! 525: boolean_t vm_map_lookup_entry(map, address, entry) ! 526: register vm_map_t map; ! 527: register vm_offset_t address; ! 528: vm_map_entry_t *entry; /* OUT */ ! 529: { ! 530: register vm_map_entry_t cur; ! 531: register vm_map_entry_t last; ! 532: ! 533: /* ! 534: * Start looking either from the head of the ! 535: * list, or from the hint. ! 536: */ ! 537: ! 538: simple_lock(&map->hint_lock); ! 539: cur = map->hint; ! 540: simple_unlock(&map->hint_lock); ! 541: ! 542: if (cur == &map->header) ! 543: cur = cur->next; ! 544: ! 545: if (address >= cur->start) { ! 546: /* ! 547: * Go from hint to end of list. ! 548: * ! 549: * But first, make a quick check to see if ! 550: * we are already looking at the entry we ! 551: * want (which is usually the case). ! 552: * Note also that we don't need to save the hint ! 553: * here... it is the same hint (unless we are ! 554: * at the header, in which case the hint didn't ! 555: * buy us anything anyway). ! 556: */ ! 557: last = &map->header; ! 558: if ((cur != last) && (cur->end > address)) { ! 559: *entry = cur; ! 560: return(TRUE); ! 561: } ! 562: } ! 563: else { ! 564: /* ! 565: * Go from start to hint, *inclusively* ! 566: */ ! 567: last = cur->next; ! 568: cur = map->header.next; ! 569: } ! 570: ! 571: /* ! 572: * Search linearly ! 573: */ ! 574: ! 575: while (cur != last) { ! 576: if (cur->end > address) { ! 577: if (address >= cur->start) { ! 578: /* ! 579: * Save this lookup for future ! 580: * hints, and return ! 581: */ ! 582: ! 583: *entry = cur; ! 584: SAVE_HINT(map, cur); ! 585: return(TRUE); ! 586: } ! 587: break; ! 588: } ! 589: cur = cur->next; ! 590: } ! 591: *entry = cur->prev; ! 592: SAVE_HINT(map, *entry); ! 593: return(FALSE); ! 594: } ! 595: ! 596: /* ! 597: * vm_map_find finds an unallocated region in the target address ! 598: * map with the given length. The search is defined to be ! 599: * first-fit from the specified address; the region found is ! 600: * returned in the same parameter. ! 601: * ! 602: */ ! 603: vm_map_find(map, object, offset, addr, length, find_space) ! 604: vm_map_t map; ! 605: vm_object_t object; ! 606: vm_offset_t offset; ! 607: vm_offset_t *addr; /* IN/OUT */ ! 608: vm_size_t length; ! 609: boolean_t find_space; ! 610: { ! 611: register vm_map_entry_t entry; ! 612: register vm_offset_t start; ! 613: register vm_offset_t end; ! 614: int result; ! 615: ! 616: start = *addr; ! 617: ! 618: vm_map_lock(map); ! 619: ! 620: if (find_space) { ! 621: /* ! 622: * Calculate the first possible address. ! 623: */ ! 624: ! 625: if (start < map->min_offset) ! 626: start = map->min_offset; ! 627: if (start > map->max_offset) { ! 628: vm_map_unlock(map); ! 629: return (KERN_NO_SPACE); ! 630: } ! 631: ! 632: /* ! 633: * Look for the first possible address; ! 634: * if there's already something at this ! 635: * address, we have to start after it. ! 636: */ ! 637: ! 638: if (start == map->min_offset) { ! 639: if ((entry = map->first_free) != &map->header) ! 640: start = entry->end; ! 641: } else { ! 642: vm_map_entry_t tmp_entry; ! 643: if (vm_map_lookup_entry(map, start, &tmp_entry)) ! 644: start = tmp_entry->end; ! 645: entry = tmp_entry; ! 646: } ! 647: ! 648: /* ! 649: * In any case, the "entry" always precedes ! 650: * the proposed new region throughout the ! 651: * loop: ! 652: */ ! 653: ! 654: while (TRUE) { ! 655: register vm_map_entry_t next; ! 656: ! 657: /* ! 658: * Find the end of the proposed new region. ! 659: * Be sure we didn't go beyond the end, or ! 660: * wrap around the address. ! 661: */ ! 662: ! 663: end = start + length; ! 664: ! 665: if ((end > map->max_offset) || (end < start)) { ! 666: vm_map_unlock(map); ! 667: return (KERN_NO_SPACE); ! 668: } ! 669: ! 670: /* ! 671: * If there are no more entries, we must win. ! 672: */ ! 673: ! 674: next = entry->next; ! 675: if (next == &map->header) ! 676: break; ! 677: ! 678: /* ! 679: * If there is another entry, it must be ! 680: * after the end of the potential new region. ! 681: */ ! 682: ! 683: if (next->start >= end) ! 684: break; ! 685: ! 686: /* ! 687: * Didn't fit -- move to the next entry. ! 688: */ ! 689: ! 690: entry = next; ! 691: start = entry->end; ! 692: } ! 693: *addr = start; ! 694: ! 695: SAVE_HINT(map, entry); ! 696: } ! 697: ! 698: result = vm_map_insert(map, object, offset, start, start + length); ! 699: ! 700: vm_map_unlock(map); ! 701: return(result); ! 702: } ! 703: ! 704: /* ! 705: * vm_map_simplify_entry: [ internal use only ] ! 706: * ! 707: * Simplify the given map entry by: ! 708: * removing extra sharing maps ! 709: * [XXX maybe later] merging with a neighbor ! 710: */ ! 711: void vm_map_simplify_entry(map, entry) ! 712: vm_map_t map; ! 713: vm_map_entry_t entry; ! 714: { ! 715: #ifdef lint ! 716: map++; ! 717: #endif lint ! 718: ! 719: /* ! 720: * If this entry corresponds to a sharing map, then ! 721: * see if we can remove the level of indirection. ! 722: * If it's not a sharing map, then it points to ! 723: * a VM object, so see if we can merge with either ! 724: * of our neighbors. ! 725: */ ! 726: ! 727: if (entry->is_sub_map) ! 728: return; ! 729: if (entry->is_a_map) { ! 730: #if 0 ! 731: vm_map_t my_share_map; ! 732: int count; ! 733: ! 734: my_share_map = entry->object.share_map; ! 735: simple_lock(&my_share_map->ref_lock); ! 736: count = my_share_map->ref_count; ! 737: simple_unlock(&my_share_map->ref_lock); ! 738: ! 739: if (count == 1) { ! 740: /* Can move the region from ! 741: * entry->start to entry->end (+ entry->offset) ! 742: * in my_share_map into place of entry. ! 743: * Later. ! 744: */ ! 745: } ! 746: #endif 0 ! 747: } ! 748: else { ! 749: /* ! 750: * Try to merge with our neighbors. ! 751: * ! 752: * Conditions for merge are: ! 753: * ! 754: * 1. entries are adjacent. ! 755: * 2. both entries point to objects ! 756: * with null pagers. ! 757: * ! 758: * If a merge is possible, we replace the two ! 759: * entries with a single entry, then merge ! 760: * the two objects into a single object. ! 761: * ! 762: * Now, all that is left to do is write the ! 763: * code! ! 764: */ ! 765: } ! 766: } ! 767: ! 768: /* ! 769: * vm_map_clip_start: [ internal use only ] ! 770: * ! 771: * Asserts that the given entry begins at or after ! 772: * the specified address; if necessary, ! 773: * it splits the entry into two. ! 774: */ ! 775: #define vm_map_clip_start(map, entry, startaddr) \ ! 776: { \ ! 777: if (startaddr > entry->start) \ ! 778: _vm_map_clip_start(map, entry, startaddr); \ ! 779: } ! 780: ! 781: /* ! 782: * This routine is called only when it is known that ! 783: * the entry must be split. ! 784: */ ! 785: void _vm_map_clip_start(map, entry, start) ! 786: register vm_map_t map; ! 787: register vm_map_entry_t entry; ! 788: register vm_offset_t start; ! 789: { ! 790: register vm_map_entry_t new_entry; ! 791: ! 792: /* ! 793: * See if we can simplify this entry first ! 794: */ ! 795: ! 796: vm_map_simplify_entry(map, entry); ! 797: ! 798: /* ! 799: * Split off the front portion -- ! 800: * note that we must insert the new ! 801: * entry BEFORE this one, so that ! 802: * this entry has the specified starting ! 803: * address. ! 804: */ ! 805: ! 806: new_entry = vm_map_entry_create(map); ! 807: *new_entry = *entry; ! 808: ! 809: new_entry->end = start; ! 810: entry->offset += (start - entry->start); ! 811: entry->start = start; ! 812: ! 813: vm_map_entry_link(map, entry->prev, new_entry); ! 814: ! 815: if (entry->is_a_map || entry->is_sub_map) ! 816: vm_map_reference(new_entry->object.share_map); ! 817: else ! 818: vm_object_reference(new_entry->object.vm_object); ! 819: } ! 820: ! 821: /* ! 822: * vm_map_clip_end: [ internal use only ] ! 823: * ! 824: * Asserts that the given entry ends at or before ! 825: * the specified address; if necessary, ! 826: * it splits the entry into two. ! 827: */ ! 828: ! 829: void _vm_map_clip_end(); ! 830: #define vm_map_clip_end(map, entry, endaddr) \ ! 831: { \ ! 832: if (endaddr < entry->end) \ ! 833: _vm_map_clip_end(map, entry, endaddr); \ ! 834: } ! 835: ! 836: /* ! 837: * This routine is called only when it is known that ! 838: * the entry must be split. ! 839: */ ! 840: void _vm_map_clip_end(map, entry, end) ! 841: register vm_map_t map; ! 842: register vm_map_entry_t entry; ! 843: register vm_offset_t end; ! 844: { ! 845: register vm_map_entry_t new_entry; ! 846: ! 847: /* ! 848: * Create a new entry and insert it ! 849: * AFTER the specified entry ! 850: */ ! 851: ! 852: new_entry = vm_map_entry_create(map); ! 853: *new_entry = *entry; ! 854: ! 855: new_entry->start = entry->end = end; ! 856: new_entry->offset += (end - entry->start); ! 857: ! 858: vm_map_entry_link(map, entry, new_entry); ! 859: ! 860: if (entry->is_a_map || entry->is_sub_map) ! 861: vm_map_reference(new_entry->object.share_map); ! 862: else ! 863: vm_object_reference(new_entry->object.vm_object); ! 864: } ! 865: ! 866: /* ! 867: * VM_MAP_RANGE_CHECK: [ internal use only ] ! 868: * ! 869: * Asserts that the starting and ending region ! 870: * addresses fall within the valid range of the map. ! 871: */ ! 872: #define VM_MAP_RANGE_CHECK(map, start, end) \ ! 873: { \ ! 874: if (start < vm_map_min(map)) \ ! 875: start = vm_map_min(map); \ ! 876: if (end > vm_map_max(map)) \ ! 877: end = vm_map_max(map); \ ! 878: if (start > end) \ ! 879: start = end; \ ! 880: } ! 881: ! 882: /* ! 883: * vm_map_submap: [ kernel use only ] ! 884: * ! 885: * Mark the given range as handled by a subordinate map. ! 886: * ! 887: * This range must have been created with vm_map_find, ! 888: * and no other operations may have been performed on this ! 889: * range prior to calling vm_map_submap. ! 890: * ! 891: * Only a limited number of operations can be performed ! 892: * within this rage after calling vm_map_submap: ! 893: * vm_fault ! 894: * [Don't try vm_map_copy!] ! 895: * ! 896: * To remove a submapping, one must first remove the ! 897: * range from the superior map, and then destroy the ! 898: * submap (if desired). [Better yet, don't try it.] ! 899: */ ! 900: vm_map_submap(map, start, end, submap) ! 901: register vm_map_t map; ! 902: register vm_offset_t start; ! 903: register vm_offset_t end; ! 904: vm_map_t submap; ! 905: { ! 906: vm_map_entry_t entry; ! 907: register int result = KERN_INVALID_ARGUMENT; ! 908: ! 909: vm_map_lock(map); ! 910: ! 911: VM_MAP_RANGE_CHECK(map, start, end); ! 912: ! 913: if (vm_map_lookup_entry(map, start, &entry)) { ! 914: vm_map_clip_start(map, entry, start); ! 915: } ! 916: else ! 917: entry = entry->next; ! 918: ! 919: vm_map_clip_end(map, entry, end); ! 920: ! 921: if ((entry->start == start) && (entry->end == end) && ! 922: (!entry->is_a_map) && ! 923: (entry->object.vm_object == NULL) && ! 924: (!entry->copy_on_write)) { ! 925: entry->is_a_map = FALSE; ! 926: entry->is_sub_map = TRUE; ! 927: vm_map_reference(entry->object.sub_map = submap); ! 928: result = KERN_SUCCESS; ! 929: } ! 930: vm_map_unlock(map); ! 931: ! 932: return(result); ! 933: } ! 934: ! 935: /* ! 936: * vm_map_protect: ! 937: * ! 938: * Sets the protection of the specified address ! 939: * region in the target map. If "set_max" is ! 940: * specified, the maximum protection is to be set; ! 941: * otherwise, only the current protection is affected. ! 942: */ ! 943: vm_map_protect(map, start, end, new_prot, set_max) ! 944: register vm_map_t map; ! 945: register vm_offset_t start; ! 946: register vm_offset_t end; ! 947: register vm_prot_t new_prot; ! 948: register boolean_t set_max; ! 949: { ! 950: register vm_map_entry_t current; ! 951: vm_map_entry_t entry; ! 952: ! 953: vm_map_lock(map); ! 954: ! 955: VM_MAP_RANGE_CHECK(map, start, end); ! 956: ! 957: if (vm_map_lookup_entry(map, start, &entry)) { ! 958: vm_map_clip_start(map, entry, start); ! 959: } ! 960: else ! 961: entry = entry->next; ! 962: ! 963: /* ! 964: * Make a first pass to check for protection ! 965: * violations. ! 966: */ ! 967: ! 968: current = entry; ! 969: while ((current != &map->header) && (current->start < end)) { ! 970: if (current->is_sub_map) ! 971: return(KERN_INVALID_ARGUMENT); ! 972: if ((new_prot & current->max_protection) != new_prot) { ! 973: vm_map_unlock(map); ! 974: return(KERN_PROTECTION_FAILURE); ! 975: } ! 976: ! 977: current = current->next; ! 978: } ! 979: ! 980: /* ! 981: * Go back and fix up protections. ! 982: * [Note that clipping is not necessary the second time.] ! 983: */ ! 984: ! 985: current = entry; ! 986: ! 987: while ((current != &map->header) && (current->start < end)) { ! 988: vm_prot_t old_prot; ! 989: ! 990: vm_map_clip_end(map, current, end); ! 991: ! 992: old_prot = current->protection; ! 993: if (set_max) ! 994: current->protection = ! 995: (current->max_protection = new_prot) & ! 996: old_prot; ! 997: else ! 998: current->protection = new_prot; ! 999: ! 1000: /* ! 1001: * Update physical map if necessary. ! 1002: * Worry about copy-on-write here -- CHECK THIS XXX ! 1003: */ ! 1004: ! 1005: if (current->protection != old_prot) { ! 1006: ! 1007: #define MASK(entry) ((entry)->copy_on_write ? ~VM_PROT_WRITE : \ ! 1008: VM_PROT_ALL) ! 1009: #define max(a,b) ((a) > (b) ? (a) : (b)) ! 1010: ! 1011: if (current->is_a_map) { ! 1012: vm_map_entry_t share_entry; ! 1013: vm_offset_t share_end; ! 1014: ! 1015: vm_map_lock(current->object.share_map); ! 1016: (void) vm_map_lookup_entry( ! 1017: current->object.share_map, ! 1018: current->offset, ! 1019: &share_entry); ! 1020: share_end = current->offset + ! 1021: (current->end - current->start); ! 1022: while ((share_entry != ! 1023: ¤t->object.share_map->header) && ! 1024: (share_entry->start < share_end)) { ! 1025: ! 1026: pmap_protect(map->pmap, ! 1027: (max(share_entry->start, ! 1028: current->offset) - ! 1029: current->offset + ! 1030: current->start), ! 1031: min(share_entry->end, ! 1032: share_end) - ! 1033: current->offset + ! 1034: current->start, ! 1035: current->protection & ! 1036: MASK(share_entry)); ! 1037: ! 1038: share_entry = share_entry->next; ! 1039: } ! 1040: vm_map_unlock(current->object.share_map); ! 1041: } ! 1042: else ! 1043: pmap_protect(map->pmap, current->start, ! 1044: current->end, ! 1045: current->protection & MASK(entry)); ! 1046: #undef max ! 1047: #undef MASK ! 1048: } ! 1049: current = current->next; ! 1050: } ! 1051: ! 1052: vm_map_unlock(map); ! 1053: return(KERN_SUCCESS); ! 1054: } ! 1055: ! 1056: /* ! 1057: * vm_map_inherit: ! 1058: * ! 1059: * Sets the inheritance of the specified address ! 1060: * range in the target map. Inheritance ! 1061: * affects how the map will be shared with ! 1062: * child maps at the time of vm_map_fork. ! 1063: */ ! 1064: vm_map_inherit(map, start, end, new_inheritance) ! 1065: register vm_map_t map; ! 1066: register vm_offset_t start; ! 1067: register vm_offset_t end; ! 1068: register vm_inherit_t new_inheritance; ! 1069: { ! 1070: register vm_map_entry_t entry; ! 1071: vm_map_entry_t temp_entry; ! 1072: ! 1073: switch (new_inheritance) { ! 1074: case VM_INHERIT_NONE: ! 1075: case VM_INHERIT_COPY: ! 1076: case VM_INHERIT_SHARE: ! 1077: break; ! 1078: default: ! 1079: return(KERN_INVALID_ARGUMENT); ! 1080: } ! 1081: ! 1082: vm_map_lock(map); ! 1083: ! 1084: VM_MAP_RANGE_CHECK(map, start, end); ! 1085: ! 1086: if (vm_map_lookup_entry(map, start, &temp_entry)) { ! 1087: entry = temp_entry; ! 1088: vm_map_clip_start(map, entry, start); ! 1089: } ! 1090: else ! 1091: entry = temp_entry->next; ! 1092: ! 1093: while ((entry != &map->header) && (entry->start < end)) { ! 1094: vm_map_clip_end(map, entry, end); ! 1095: ! 1096: entry->inheritance = new_inheritance; ! 1097: ! 1098: entry = entry->next; ! 1099: } ! 1100: ! 1101: vm_map_unlock(map); ! 1102: return(KERN_SUCCESS); ! 1103: } ! 1104: ! 1105: /* ! 1106: * vm_map_pageable: ! 1107: * ! 1108: * Sets the pageability of the specified address ! 1109: * range in the target map. Regions specified ! 1110: * as not pageable require locked-down physical ! 1111: * memory and physical page maps. ! 1112: * ! 1113: * The map must not be locked, but a reference ! 1114: * must remain to the map throughout the call. ! 1115: */ ! 1116: vm_map_pageable(map, start, end, new_pageable) ! 1117: register vm_map_t map; ! 1118: register vm_offset_t start; ! 1119: register vm_offset_t end; ! 1120: register boolean_t new_pageable; ! 1121: { ! 1122: register vm_map_entry_t entry; ! 1123: vm_map_entry_t temp_entry; ! 1124: ! 1125: vm_map_lock(map); ! 1126: ! 1127: VM_MAP_RANGE_CHECK(map, start, end); ! 1128: ! 1129: /* ! 1130: * Only one pageability change may take place at one ! 1131: * time, since vm_fault assumes it will be called ! 1132: * only once for each wiring/unwiring. Therefore, we ! 1133: * have to make sure we're actually changing the pageability ! 1134: * for the entire region. We do so before making any changes. ! 1135: */ ! 1136: ! 1137: if (vm_map_lookup_entry(map, start, &temp_entry)) { ! 1138: entry = temp_entry; ! 1139: vm_map_clip_start(map, entry, start); ! 1140: } ! 1141: else ! 1142: entry = temp_entry->next; ! 1143: temp_entry = entry; ! 1144: ! 1145: /* ! 1146: * Actions are rather different for wiring and unwiring, ! 1147: * so we have two separate cases. ! 1148: */ ! 1149: ! 1150: if (new_pageable) { ! 1151: ! 1152: /* ! 1153: * Unwiring. First ensure that the range to be ! 1154: * unwired is really wired down. ! 1155: */ ! 1156: while ((entry != &map->header) && (entry->start < end)) { ! 1157: ! 1158: if (entry->wired_count == 0) { ! 1159: vm_map_unlock(map); ! 1160: return(KERN_INVALID_ARGUMENT); ! 1161: } ! 1162: entry = entry->next; ! 1163: } ! 1164: ! 1165: /* ! 1166: * Now decrement the wiring count for each region. ! 1167: * If a region becomes completely unwired, ! 1168: * unwire its physical pages and mappings. ! 1169: */ ! 1170: lock_set_recursive(&map->lock); ! 1171: ! 1172: entry = temp_entry; ! 1173: while ((entry != &map->header) && (entry->start < end)) { ! 1174: vm_map_clip_end(map, entry, end); ! 1175: ! 1176: entry->wired_count--; ! 1177: if (entry->wired_count == 0) ! 1178: vm_fault_unwire(map, entry->start, entry->end); ! 1179: ! 1180: entry = entry->next; ! 1181: } ! 1182: lock_clear_recursive(&map->lock); ! 1183: } ! 1184: ! 1185: else { ! 1186: /* ! 1187: * Wiring. We must do this in two passes: ! 1188: * ! 1189: * 1. Holding the write lock, we increment the ! 1190: * wiring count. For any area that is not already ! 1191: * wired, we create any shadow objects that need ! 1192: * to be created. ! 1193: * ! 1194: * 2. We downgrade to a read lock, and call ! 1195: * vm_fault_wire to fault in the pages for any ! 1196: * newly wired area (wired_count is 1). ! 1197: * ! 1198: * Downgrading to a read lock for vm_fault_wire avoids ! 1199: * a possible deadlock with another thread that may have ! 1200: * faulted on one of the pages to be wired (it would mark ! 1201: * the page busy, blocking us, then in turn block on the ! 1202: * map lock that we hold). Because of problems in the ! 1203: * recursive lock package, we cannot upgrade to a write ! 1204: * lock in vm_map_lookup. Thus, any actions that require ! 1205: * the write lock must be done beforehand. Because we ! 1206: * keep the read lock on the map, the copy-on-write status ! 1207: * of the entries we modify here cannot change. ! 1208: */ ! 1209: ! 1210: /* ! 1211: * Pass 1. ! 1212: */ ! 1213: entry = temp_entry; ! 1214: while ((entry != &map->header) && (entry->start < end)) { ! 1215: vm_map_clip_end(map, entry, end); ! 1216: ! 1217: entry->wired_count++; ! 1218: if (entry->wired_count == 1) { ! 1219: ! 1220: /* ! 1221: * Perform actions of vm_map_lookup that need ! 1222: * the write lock on the map: create a shadow ! 1223: * object for a copy-on-write region, or an ! 1224: * object for a zero-fill region. ! 1225: * ! 1226: * We don't have to do this for entries that ! 1227: * point to sharing maps, because we won't hold ! 1228: * the lock on the sharing map. ! 1229: */ ! 1230: if (!entry->is_a_map) { ! 1231: if (entry->needs_copy && ! 1232: ((entry->protection & VM_PROT_WRITE) != 0)) { ! 1233: ! 1234: vm_object_shadow(&entry->object.vm_object, ! 1235: &entry->offset, ! 1236: (vm_size_t)(entry->end ! 1237: - entry->start)); ! 1238: entry->needs_copy = FALSE; ! 1239: } ! 1240: else if (entry->object.vm_object == NULL) { ! 1241: entry->object.vm_object = ! 1242: vm_object_allocate((vm_size_t)(entry->end ! 1243: - entry->start)); ! 1244: entry->offset = (vm_offset_t)0; ! 1245: } ! 1246: } ! 1247: } ! 1248: ! 1249: entry = entry->next; ! 1250: } ! 1251: ! 1252: /* ! 1253: * Pass 2. ! 1254: */ ! 1255: ! 1256: /* ! 1257: * HACK HACK HACK HACK ! 1258: * ! 1259: * If we are wiring in the kernel map or a submap of it, ! 1260: * unlock the map to avoid deadlocks. We trust that the ! 1261: * kernel threads are well-behaved, and therefore will ! 1262: * not do anything destructive to this region of the map ! 1263: * while we have it unlocked. We cannot trust user threads ! 1264: * to do the same. ! 1265: * ! 1266: * HACK HACK HACK HACK ! 1267: */ ! 1268: if (vm_map_pmap(map) == kernel_pmap) { ! 1269: vm_map_unlock(map); /* trust me ... */ ! 1270: } ! 1271: else { ! 1272: lock_set_recursive(&map->lock); ! 1273: lock_write_to_read(&map->lock); ! 1274: } ! 1275: ! 1276: entry = temp_entry; ! 1277: while (entry != &map->header && entry->start < end) { ! 1278: if (entry->wired_count == 1) { ! 1279: vm_fault_wire(map, entry->start, entry->end); ! 1280: } ! 1281: entry = entry->next; ! 1282: } ! 1283: ! 1284: if (vm_map_pmap(map) == kernel_pmap) { ! 1285: vm_map_lock(map); ! 1286: } ! 1287: else { ! 1288: lock_clear_recursive(&map->lock); ! 1289: } ! 1290: } ! 1291: ! 1292: vm_map_unlock(map); ! 1293: ! 1294: return(KERN_SUCCESS); ! 1295: } ! 1296: ! 1297: /* ! 1298: * vm_map_entry_unwire: [ internal use only ] ! 1299: * ! 1300: * Make the region specified by this entry pageable. ! 1301: * ! 1302: * The map in question should be locked. ! 1303: * [This is the reason for this routine's existence.] ! 1304: */ ! 1305: void vm_map_entry_unwire(map, entry) ! 1306: vm_map_t map; ! 1307: register vm_map_entry_t entry; ! 1308: { ! 1309: vm_fault_unwire(map, entry->start, entry->end); ! 1310: entry->wired_count = 0; ! 1311: } ! 1312: ! 1313: /* ! 1314: * vm_map_entry_delete: [ internal use only ] ! 1315: * ! 1316: * Deallocate the given entry from the target map. ! 1317: */ ! 1318: void vm_map_entry_delete(map, entry) ! 1319: register vm_map_t map; ! 1320: register vm_map_entry_t entry; ! 1321: { ! 1322: if (entry->wired_count != 0) ! 1323: vm_map_entry_unwire(map, entry); ! 1324: ! 1325: vm_map_entry_unlink(map, entry); ! 1326: map->size -= entry->end - entry->start; ! 1327: ! 1328: if (entry->is_a_map || entry->is_sub_map) ! 1329: vm_map_deallocate(entry->object.share_map); ! 1330: else ! 1331: vm_object_deallocate(entry->object.vm_object); ! 1332: ! 1333: vm_map_entry_dispose(map, entry); ! 1334: } ! 1335: ! 1336: /* ! 1337: * vm_map_delete: [ internal use only ] ! 1338: * ! 1339: * Deallocates the given address range from the target ! 1340: * map. ! 1341: * ! 1342: * When called with a sharing map, removes pages from ! 1343: * that region from all physical maps. ! 1344: */ ! 1345: vm_map_delete(map, start, end) ! 1346: register vm_map_t map; ! 1347: vm_offset_t start; ! 1348: register vm_offset_t end; ! 1349: { ! 1350: register vm_map_entry_t entry; ! 1351: vm_map_entry_t first_entry; ! 1352: ! 1353: /* ! 1354: * Find the start of the region, and clip it ! 1355: */ ! 1356: ! 1357: if (!vm_map_lookup_entry(map, start, &first_entry)) ! 1358: entry = first_entry->next; ! 1359: else { ! 1360: entry = first_entry; ! 1361: vm_map_clip_start(map, entry, start); ! 1362: ! 1363: /* ! 1364: * Fix the lookup hint now, rather than each ! 1365: * time though the loop. ! 1366: */ ! 1367: ! 1368: SAVE_HINT(map, entry->prev); ! 1369: } ! 1370: ! 1371: /* ! 1372: * Save the free space hint ! 1373: */ ! 1374: ! 1375: if (map->first_free->start >= start) ! 1376: map->first_free = entry->prev; ! 1377: ! 1378: /* ! 1379: * Step through all entries in this region ! 1380: */ ! 1381: ! 1382: while ((entry != &map->header) && (entry->start < end)) { ! 1383: vm_map_entry_t next; ! 1384: register vm_offset_t s, e; ! 1385: register vm_object_t object; ! 1386: ! 1387: vm_map_clip_end(map, entry, end); ! 1388: ! 1389: next = entry->next; ! 1390: s = entry->start; ! 1391: e = entry->end; ! 1392: ! 1393: /* ! 1394: * Unwire before removing addresses from the pmap; ! 1395: * otherwise, unwiring will put the entries back in ! 1396: * the pmap. ! 1397: */ ! 1398: ! 1399: object = entry->object.vm_object; ! 1400: if (entry->wired_count != 0) ! 1401: vm_map_entry_unwire(map, entry); ! 1402: ! 1403: /* ! 1404: * If this is a sharing map, we must remove ! 1405: * *all* references to this data, since we can't ! 1406: * find all of the physical maps which are sharing ! 1407: * it. ! 1408: */ ! 1409: ! 1410: if (object == kernel_object || object == kmem_object) ! 1411: vm_object_page_remove(object, entry->offset, ! 1412: entry->offset + (e - s)); ! 1413: else if (!map->is_main_map) ! 1414: vm_object_pmap_remove(object, ! 1415: entry->offset, ! 1416: entry->offset + (e - s)); ! 1417: else ! 1418: pmap_remove(map->pmap, s, e); ! 1419: ! 1420: /* ! 1421: * Delete the entry (which may delete the object) ! 1422: * only after removing all pmap entries pointing ! 1423: * to its pages. (Otherwise, its page frames may ! 1424: * be reallocated, and any modify bits will be ! 1425: * set in the wrong object!) ! 1426: */ ! 1427: ! 1428: vm_map_entry_delete(map, entry); ! 1429: entry = next; ! 1430: } ! 1431: return(KERN_SUCCESS); ! 1432: } ! 1433: ! 1434: /* ! 1435: * vm_map_remove: ! 1436: * ! 1437: * Remove the given address range from the target map. ! 1438: * This is the exported form of vm_map_delete. ! 1439: */ ! 1440: vm_map_remove(map, start, end) ! 1441: register vm_map_t map; ! 1442: register vm_offset_t start; ! 1443: register vm_offset_t end; ! 1444: { ! 1445: register int result; ! 1446: ! 1447: vm_map_lock(map); ! 1448: VM_MAP_RANGE_CHECK(map, start, end); ! 1449: result = vm_map_delete(map, start, end); ! 1450: vm_map_unlock(map); ! 1451: ! 1452: return(result); ! 1453: } ! 1454: ! 1455: /* ! 1456: * vm_map_check_protection: ! 1457: * ! 1458: * Assert that the target map allows the specified ! 1459: * privilege on the entire address region given. ! 1460: * The entire region must be allocated. ! 1461: */ ! 1462: boolean_t vm_map_check_protection(map, start, end, protection) ! 1463: register vm_map_t map; ! 1464: register vm_offset_t start; ! 1465: register vm_offset_t end; ! 1466: register vm_prot_t protection; ! 1467: { ! 1468: register vm_map_entry_t entry; ! 1469: vm_map_entry_t tmp_entry; ! 1470: ! 1471: if (!vm_map_lookup_entry(map, start, &tmp_entry)) { ! 1472: return(FALSE); ! 1473: } ! 1474: ! 1475: entry = tmp_entry; ! 1476: ! 1477: while (start < end) { ! 1478: if (entry == &map->header) { ! 1479: return(FALSE); ! 1480: } ! 1481: ! 1482: /* ! 1483: * No holes allowed! ! 1484: */ ! 1485: ! 1486: if (start < entry->start) { ! 1487: return(FALSE); ! 1488: } ! 1489: ! 1490: /* ! 1491: * Check protection associated with entry. ! 1492: */ ! 1493: ! 1494: if ((entry->protection & protection) != protection) { ! 1495: return(FALSE); ! 1496: } ! 1497: ! 1498: /* go to next entry */ ! 1499: ! 1500: start = entry->end; ! 1501: entry = entry->next; ! 1502: } ! 1503: return(TRUE); ! 1504: } ! 1505: ! 1506: /* ! 1507: * vm_map_copy_entry: ! 1508: * ! 1509: * Copies the contents of the source entry to the destination ! 1510: * entry. The entries *must* be aligned properly. ! 1511: */ ! 1512: void vm_map_copy_entry(src_map, dst_map, src_entry, dst_entry) ! 1513: vm_map_t src_map, dst_map; ! 1514: register vm_map_entry_t src_entry, dst_entry; ! 1515: { ! 1516: vm_object_t temp_object; ! 1517: ! 1518: if (src_entry->is_sub_map || dst_entry->is_sub_map) ! 1519: return; ! 1520: ! 1521: if (dst_entry->object.vm_object != NULL && ! 1522: !dst_entry->object.vm_object->internal) ! 1523: printf("vm_map_copy_entry: copying over permanent data!\n"); ! 1524: ! 1525: /* ! 1526: * If our destination map was wired down, ! 1527: * unwire it now. ! 1528: */ ! 1529: ! 1530: if (dst_entry->wired_count != 0) ! 1531: vm_map_entry_unwire(dst_map, dst_entry); ! 1532: ! 1533: /* ! 1534: * If we're dealing with a sharing map, we ! 1535: * must remove the destination pages from ! 1536: * all maps (since we cannot know which maps ! 1537: * this sharing map belongs in). ! 1538: */ ! 1539: ! 1540: if (dst_map->is_main_map) ! 1541: pmap_remove(dst_map->pmap, dst_entry->start, dst_entry->end); ! 1542: else ! 1543: vm_object_pmap_remove(dst_entry->object.vm_object, ! 1544: dst_entry->offset, ! 1545: dst_entry->offset + ! 1546: (dst_entry->end - dst_entry->start)); ! 1547: ! 1548: if (src_entry->wired_count == 0) { ! 1549: ! 1550: boolean_t src_needs_copy; ! 1551: ! 1552: /* ! 1553: * If the source entry is marked needs_copy, ! 1554: * it is already write-protected. ! 1555: */ ! 1556: if (!src_entry->needs_copy) { ! 1557: ! 1558: boolean_t su; ! 1559: ! 1560: /* ! 1561: * If the source entry has only one mapping, ! 1562: * we can just protect the virtual address ! 1563: * range. ! 1564: */ ! 1565: if (!(su = src_map->is_main_map)) { ! 1566: simple_lock(&src_map->ref_lock); ! 1567: su = (src_map->ref_count == 1); ! 1568: simple_unlock(&src_map->ref_lock); ! 1569: } ! 1570: ! 1571: if (su) { ! 1572: pmap_protect(src_map->pmap, ! 1573: src_entry->start, ! 1574: src_entry->end, ! 1575: src_entry->protection & ~VM_PROT_WRITE); ! 1576: } ! 1577: else { ! 1578: vm_object_pmap_copy(src_entry->object.vm_object, ! 1579: src_entry->offset, ! 1580: src_entry->offset + (src_entry->end ! 1581: -src_entry->start)); ! 1582: } ! 1583: } ! 1584: ! 1585: /* ! 1586: * Make a copy of the object. ! 1587: */ ! 1588: temp_object = dst_entry->object.vm_object; ! 1589: vm_object_copy(src_entry->object.vm_object, ! 1590: src_entry->offset, ! 1591: (vm_size_t)(src_entry->end - ! 1592: src_entry->start), ! 1593: &dst_entry->object.vm_object, ! 1594: &dst_entry->offset, ! 1595: &src_needs_copy); ! 1596: /* ! 1597: * If we didn't get a copy-object now, mark the ! 1598: * source map entry so that a shadow will be created ! 1599: * to hold its changed pages. ! 1600: */ ! 1601: if (src_needs_copy) ! 1602: src_entry->needs_copy = TRUE; ! 1603: ! 1604: /* ! 1605: * The destination always needs to have a shadow ! 1606: * created. ! 1607: */ ! 1608: dst_entry->needs_copy = TRUE; ! 1609: ! 1610: /* ! 1611: * Mark the entries copy-on-write, so that write-enabling ! 1612: * the entry won't make copy-on-write pages writable. ! 1613: */ ! 1614: src_entry->copy_on_write = TRUE; ! 1615: dst_entry->copy_on_write = TRUE; ! 1616: /* ! 1617: * Get rid of the old object. ! 1618: */ ! 1619: vm_object_deallocate(temp_object); ! 1620: ! 1621: pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start, ! 1622: dst_entry->end - dst_entry->start, src_entry->start); ! 1623: } ! 1624: else { ! 1625: /* ! 1626: * Of course, wired down pages can't be set copy-on-write. ! 1627: * Cause wired pages to be copied into the new ! 1628: * map by simulating faults (the new pages are ! 1629: * pageable) ! 1630: */ ! 1631: vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry); ! 1632: } ! 1633: } ! 1634: ! 1635: /* ! 1636: * vm_map_copy: ! 1637: * ! 1638: * Perform a virtual memory copy from the source ! 1639: * address map/range to the destination map/range. ! 1640: * ! 1641: * If src_destroy or dst_alloc is requested, ! 1642: * the source and destination regions should be ! 1643: * disjoint, not only in the top-level map, but ! 1644: * in the sharing maps as well. [The best way ! 1645: * to guarantee this is to use a new intermediate ! 1646: * map to make copies. This also reduces map ! 1647: * fragmentation.] ! 1648: */ ! 1649: vm_map_copy(dst_map, src_map, ! 1650: dst_addr, len, src_addr, ! 1651: dst_alloc, src_destroy) ! 1652: vm_map_t dst_map; ! 1653: vm_map_t src_map; ! 1654: vm_offset_t dst_addr; ! 1655: vm_size_t len; ! 1656: vm_offset_t src_addr; ! 1657: boolean_t dst_alloc; ! 1658: boolean_t src_destroy; ! 1659: { ! 1660: register ! 1661: vm_map_entry_t src_entry; ! 1662: register ! 1663: vm_map_entry_t dst_entry; ! 1664: vm_map_entry_t tmp_entry; ! 1665: vm_offset_t src_start; ! 1666: vm_offset_t src_end; ! 1667: vm_offset_t dst_start; ! 1668: vm_offset_t dst_end; ! 1669: vm_offset_t src_clip; ! 1670: vm_offset_t dst_clip; ! 1671: int result; ! 1672: boolean_t old_src_destroy; ! 1673: ! 1674: /* ! 1675: * XXX While we figure out why src_destroy screws up, ! 1676: * we'll do it by explicitly vm_map_delete'ing at the end. ! 1677: */ ! 1678: ! 1679: old_src_destroy = src_destroy; ! 1680: src_destroy = FALSE; ! 1681: ! 1682: /* ! 1683: * Compute start and end of region in both maps ! 1684: */ ! 1685: ! 1686: src_start = src_addr; ! 1687: src_end = src_start + len; ! 1688: dst_start = dst_addr; ! 1689: dst_end = dst_start + len; ! 1690: ! 1691: /* ! 1692: * Check that the region can exist in both source ! 1693: * and destination. ! 1694: */ ! 1695: ! 1696: if ((dst_end < dst_start) || (src_end < src_start)) ! 1697: return(KERN_NO_SPACE); ! 1698: ! 1699: /* ! 1700: * Lock the maps in question -- we avoid deadlock ! 1701: * by ordering lock acquisition by map value ! 1702: */ ! 1703: ! 1704: if (src_map == dst_map) { ! 1705: vm_map_lock(src_map); ! 1706: } ! 1707: else if ((int) src_map < (int) dst_map) { ! 1708: vm_map_lock(src_map); ! 1709: vm_map_lock(dst_map); ! 1710: } else { ! 1711: vm_map_lock(dst_map); ! 1712: vm_map_lock(src_map); ! 1713: } ! 1714: ! 1715: result = KERN_SUCCESS; ! 1716: ! 1717: /* ! 1718: * Check protections... source must be completely readable and ! 1719: * destination must be completely writable. [Note that if we're ! 1720: * allocating the destination region, we don't have to worry ! 1721: * about protection, but instead about whether the region ! 1722: * exists.] ! 1723: */ ! 1724: ! 1725: if (src_map->is_main_map && dst_map->is_main_map) { ! 1726: if (!vm_map_check_protection(src_map, src_start, src_end, ! 1727: VM_PROT_READ)) { ! 1728: result = KERN_PROTECTION_FAILURE; ! 1729: goto Return; ! 1730: } ! 1731: ! 1732: if (dst_alloc) { ! 1733: /* XXX Consider making this a vm_map_find instead */ ! 1734: if ((result = vm_map_insert(dst_map, NULL, ! 1735: (vm_offset_t) 0, dst_start, dst_end)) != KERN_SUCCESS) ! 1736: goto Return; ! 1737: } ! 1738: else if (!vm_map_check_protection(dst_map, dst_start, dst_end, ! 1739: VM_PROT_WRITE)) { ! 1740: result = KERN_PROTECTION_FAILURE; ! 1741: goto Return; ! 1742: } ! 1743: } ! 1744: ! 1745: /* ! 1746: * Find the start entries and clip. ! 1747: * ! 1748: * Note that checking protection asserts that the ! 1749: * lookup cannot fail. ! 1750: * ! 1751: * Also note that we wait to do the second lookup ! 1752: * until we have done the first clip, as the clip ! 1753: * may affect which entry we get! ! 1754: */ ! 1755: ! 1756: (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); ! 1757: src_entry = tmp_entry; ! 1758: vm_map_clip_start(src_map, src_entry, src_start); ! 1759: ! 1760: (void) vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry); ! 1761: dst_entry = tmp_entry; ! 1762: vm_map_clip_start(dst_map, dst_entry, dst_start); ! 1763: ! 1764: /* ! 1765: * If both source and destination entries are the same, ! 1766: * retry the first lookup, as it may have changed. ! 1767: */ ! 1768: ! 1769: if (src_entry == dst_entry) { ! 1770: (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); ! 1771: src_entry = tmp_entry; ! 1772: } ! 1773: ! 1774: /* ! 1775: * If source and destination entries are still the same, ! 1776: * a null copy is being performed. ! 1777: */ ! 1778: ! 1779: if (src_entry == dst_entry) ! 1780: goto Return; ! 1781: ! 1782: /* ! 1783: * Go through entries until we get to the end of the ! 1784: * region. ! 1785: */ ! 1786: ! 1787: while (src_start < src_end) { ! 1788: /* ! 1789: * Clip the entries to the endpoint of the entire region. ! 1790: */ ! 1791: ! 1792: vm_map_clip_end(src_map, src_entry, src_end); ! 1793: vm_map_clip_end(dst_map, dst_entry, dst_end); ! 1794: ! 1795: /* ! 1796: * Clip each entry to the endpoint of the other entry. ! 1797: */ ! 1798: ! 1799: src_clip = src_entry->start + (dst_entry->end - dst_entry->start); ! 1800: vm_map_clip_end(src_map, src_entry, src_clip); ! 1801: ! 1802: dst_clip = dst_entry->start + (src_entry->end - src_entry->start); ! 1803: vm_map_clip_end(dst_map, dst_entry, dst_clip); ! 1804: ! 1805: /* ! 1806: * Both entries now match in size and relative endpoints. ! 1807: * ! 1808: * If both entries refer to a VM object, we can ! 1809: * deal with them now. ! 1810: */ ! 1811: ! 1812: if (!src_entry->is_a_map && !dst_entry->is_a_map) { ! 1813: vm_map_copy_entry(src_map, dst_map, src_entry, ! 1814: dst_entry); ! 1815: } ! 1816: else { ! 1817: register vm_map_t new_dst_map; ! 1818: vm_offset_t new_dst_start; ! 1819: vm_size_t new_size; ! 1820: vm_map_t new_src_map; ! 1821: vm_offset_t new_src_start; ! 1822: ! 1823: /* ! 1824: * We have to follow at least one sharing map. ! 1825: */ ! 1826: ! 1827: new_size = (dst_entry->end - dst_entry->start); ! 1828: ! 1829: if (src_entry->is_a_map) { ! 1830: new_src_map = src_entry->object.share_map; ! 1831: new_src_start = src_entry->offset; ! 1832: } ! 1833: else { ! 1834: new_src_map = src_map; ! 1835: new_src_start = src_entry->start; ! 1836: lock_set_recursive(&src_map->lock); ! 1837: } ! 1838: ! 1839: if (dst_entry->is_a_map) { ! 1840: vm_offset_t new_dst_end; ! 1841: ! 1842: new_dst_map = dst_entry->object.share_map; ! 1843: new_dst_start = dst_entry->offset; ! 1844: ! 1845: /* ! 1846: * Since the destination sharing entries ! 1847: * will be merely deallocated, we can ! 1848: * do that now, and replace the region ! 1849: * with a null object. [This prevents ! 1850: * splitting the source map to match ! 1851: * the form of the destination map.] ! 1852: * Note that we can only do so if the ! 1853: * source and destination do not overlap. ! 1854: */ ! 1855: ! 1856: new_dst_end = new_dst_start + new_size; ! 1857: ! 1858: if (new_dst_map != new_src_map) { ! 1859: vm_map_lock(new_dst_map); ! 1860: (void) vm_map_delete(new_dst_map, ! 1861: new_dst_start, ! 1862: new_dst_end); ! 1863: (void) vm_map_insert(new_dst_map, ! 1864: NULL, ! 1865: (vm_offset_t) 0, ! 1866: new_dst_start, ! 1867: new_dst_end); ! 1868: vm_map_unlock(new_dst_map); ! 1869: } ! 1870: } ! 1871: else { ! 1872: new_dst_map = dst_map; ! 1873: new_dst_start = dst_entry->start; ! 1874: lock_set_recursive(&dst_map->lock); ! 1875: } ! 1876: ! 1877: /* ! 1878: * Recursively copy the sharing map. ! 1879: */ ! 1880: ! 1881: (void) vm_map_copy(new_dst_map, new_src_map, ! 1882: new_dst_start, new_size, new_src_start, ! 1883: FALSE, FALSE); ! 1884: ! 1885: if (dst_map == new_dst_map) ! 1886: lock_clear_recursive(&dst_map->lock); ! 1887: if (src_map == new_src_map) ! 1888: lock_clear_recursive(&src_map->lock); ! 1889: } ! 1890: ! 1891: /* ! 1892: * Update variables for next pass through the loop. ! 1893: */ ! 1894: ! 1895: src_start = src_entry->end; ! 1896: src_entry = src_entry->next; ! 1897: dst_start = dst_entry->end; ! 1898: dst_entry = dst_entry->next; ! 1899: ! 1900: /* ! 1901: * If the source is to be destroyed, here is the ! 1902: * place to do it. ! 1903: */ ! 1904: ! 1905: if (src_destroy && src_map->is_main_map && ! 1906: dst_map->is_main_map) ! 1907: vm_map_entry_delete(src_map, src_entry->prev); ! 1908: } ! 1909: ! 1910: /* ! 1911: * Update the physical maps as appropriate ! 1912: */ ! 1913: ! 1914: if (src_map->is_main_map && dst_map->is_main_map) { ! 1915: if (src_destroy) ! 1916: pmap_remove(src_map->pmap, src_addr, src_addr + len); ! 1917: } ! 1918: ! 1919: /* ! 1920: * Unlock the maps ! 1921: */ ! 1922: ! 1923: Return: ; ! 1924: ! 1925: if (old_src_destroy) ! 1926: vm_map_delete(src_map, src_addr, src_addr + len); ! 1927: ! 1928: vm_map_unlock(src_map); ! 1929: if (src_map != dst_map) ! 1930: vm_map_unlock(dst_map); ! 1931: ! 1932: return(result); ! 1933: } ! 1934: ! 1935: /* ! 1936: * vmspace_fork: ! 1937: * Create a new process vmspace structure and vm_map ! 1938: * based on those of an existing process. The new map ! 1939: * is based on the old map, according to the inheritance ! 1940: * values on the regions in that map. ! 1941: * ! 1942: * The source map must not be locked. ! 1943: */ ! 1944: struct vmspace * ! 1945: vmspace_fork(vm1) ! 1946: register struct vmspace *vm1; ! 1947: { ! 1948: register struct vmspace *vm2; ! 1949: vm_map_t old_map = &vm1->vm_map; ! 1950: vm_map_t new_map; ! 1951: vm_map_entry_t old_entry; ! 1952: vm_map_entry_t new_entry; ! 1953: pmap_t new_pmap; ! 1954: ! 1955: vm_map_lock(old_map); ! 1956: ! 1957: vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset, ! 1958: old_map->entries_pageable); ! 1959: bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy, ! 1960: (caddr_t) (vm1 + 1) - (caddr_t) &vm1->vm_startcopy); ! 1961: new_pmap = &vm2->vm_pmap; /* XXX */ ! 1962: new_map = &vm2->vm_map; /* XXX */ ! 1963: ! 1964: old_entry = old_map->header.next; ! 1965: ! 1966: while (old_entry != &old_map->header) { ! 1967: if (old_entry->is_sub_map) ! 1968: panic("vm_map_fork: encountered a submap"); ! 1969: ! 1970: switch (old_entry->inheritance) { ! 1971: case VM_INHERIT_NONE: ! 1972: break; ! 1973: ! 1974: case VM_INHERIT_SHARE: ! 1975: /* ! 1976: * If we don't already have a sharing map: ! 1977: */ ! 1978: ! 1979: if (!old_entry->is_a_map) { ! 1980: vm_map_t new_share_map; ! 1981: vm_map_entry_t new_share_entry; ! 1982: ! 1983: /* ! 1984: * Create a new sharing map ! 1985: */ ! 1986: ! 1987: new_share_map = vm_map_create(NULL, ! 1988: old_entry->start, ! 1989: old_entry->end, ! 1990: TRUE); ! 1991: new_share_map->is_main_map = FALSE; ! 1992: ! 1993: /* ! 1994: * Create the only sharing entry from the ! 1995: * old task map entry. ! 1996: */ ! 1997: ! 1998: new_share_entry = ! 1999: vm_map_entry_create(new_share_map); ! 2000: *new_share_entry = *old_entry; ! 2001: ! 2002: /* ! 2003: * Insert the entry into the new sharing ! 2004: * map ! 2005: */ ! 2006: ! 2007: vm_map_entry_link(new_share_map, ! 2008: new_share_map->header.prev, ! 2009: new_share_entry); ! 2010: ! 2011: /* ! 2012: * Fix up the task map entry to refer ! 2013: * to the sharing map now. ! 2014: */ ! 2015: ! 2016: old_entry->is_a_map = TRUE; ! 2017: old_entry->object.share_map = new_share_map; ! 2018: old_entry->offset = old_entry->start; ! 2019: } ! 2020: ! 2021: /* ! 2022: * Clone the entry, referencing the sharing map. ! 2023: */ ! 2024: ! 2025: new_entry = vm_map_entry_create(new_map); ! 2026: *new_entry = *old_entry; ! 2027: vm_map_reference(new_entry->object.share_map); ! 2028: ! 2029: /* ! 2030: * Insert the entry into the new map -- we ! 2031: * know we're inserting at the end of the new ! 2032: * map. ! 2033: */ ! 2034: ! 2035: vm_map_entry_link(new_map, new_map->header.prev, ! 2036: new_entry); ! 2037: ! 2038: /* ! 2039: * Update the physical map ! 2040: */ ! 2041: ! 2042: pmap_copy(new_map->pmap, old_map->pmap, ! 2043: new_entry->start, ! 2044: (old_entry->end - old_entry->start), ! 2045: old_entry->start); ! 2046: break; ! 2047: ! 2048: case VM_INHERIT_COPY: ! 2049: /* ! 2050: * Clone the entry and link into the map. ! 2051: */ ! 2052: ! 2053: new_entry = vm_map_entry_create(new_map); ! 2054: *new_entry = *old_entry; ! 2055: new_entry->wired_count = 0; ! 2056: new_entry->object.vm_object = NULL; ! 2057: new_entry->is_a_map = FALSE; ! 2058: vm_map_entry_link(new_map, new_map->header.prev, ! 2059: new_entry); ! 2060: if (old_entry->is_a_map) { ! 2061: int check; ! 2062: ! 2063: check = vm_map_copy(new_map, ! 2064: old_entry->object.share_map, ! 2065: new_entry->start, ! 2066: (vm_size_t)(new_entry->end - ! 2067: new_entry->start), ! 2068: old_entry->offset, ! 2069: FALSE, FALSE); ! 2070: if (check != KERN_SUCCESS) ! 2071: printf("vm_map_fork: copy in share_map region failed\n"); ! 2072: } ! 2073: else { ! 2074: vm_map_copy_entry(old_map, new_map, old_entry, ! 2075: new_entry); ! 2076: } ! 2077: break; ! 2078: } ! 2079: old_entry = old_entry->next; ! 2080: } ! 2081: ! 2082: new_map->size = old_map->size; ! 2083: vm_map_unlock(old_map); ! 2084: ! 2085: return(vm2); ! 2086: } ! 2087: ! 2088: /* ! 2089: * vm_map_lookup: ! 2090: * ! 2091: * Finds the VM object, offset, and ! 2092: * protection for a given virtual address in the ! 2093: * specified map, assuming a page fault of the ! 2094: * type specified. ! 2095: * ! 2096: * Leaves the map in question locked for read; return ! 2097: * values are guaranteed until a vm_map_lookup_done ! 2098: * call is performed. Note that the map argument ! 2099: * is in/out; the returned map must be used in ! 2100: * the call to vm_map_lookup_done. ! 2101: * ! 2102: * A handle (out_entry) is returned for use in ! 2103: * vm_map_lookup_done, to make that fast. ! 2104: * ! 2105: * If a lookup is requested with "write protection" ! 2106: * specified, the map may be changed to perform virtual ! 2107: * copying operations, although the data referenced will ! 2108: * remain the same. ! 2109: */ ! 2110: vm_map_lookup(var_map, vaddr, fault_type, out_entry, ! 2111: object, offset, out_prot, wired, single_use) ! 2112: vm_map_t *var_map; /* IN/OUT */ ! 2113: register vm_offset_t vaddr; ! 2114: register vm_prot_t fault_type; ! 2115: ! 2116: vm_map_entry_t *out_entry; /* OUT */ ! 2117: vm_object_t *object; /* OUT */ ! 2118: vm_offset_t *offset; /* OUT */ ! 2119: vm_prot_t *out_prot; /* OUT */ ! 2120: boolean_t *wired; /* OUT */ ! 2121: boolean_t *single_use; /* OUT */ ! 2122: { ! 2123: vm_map_t share_map; ! 2124: vm_offset_t share_offset; ! 2125: register vm_map_entry_t entry; ! 2126: register vm_map_t map = *var_map; ! 2127: register vm_prot_t prot; ! 2128: register boolean_t su; ! 2129: ! 2130: RetryLookup: ; ! 2131: ! 2132: /* ! 2133: * Lookup the faulting address. ! 2134: */ ! 2135: ! 2136: vm_map_lock_read(map); ! 2137: ! 2138: #define RETURN(why) \ ! 2139: { \ ! 2140: vm_map_unlock_read(map); \ ! 2141: return(why); \ ! 2142: } ! 2143: ! 2144: /* ! 2145: * If the map has an interesting hint, try it before calling ! 2146: * full blown lookup routine. ! 2147: */ ! 2148: ! 2149: simple_lock(&map->hint_lock); ! 2150: entry = map->hint; ! 2151: simple_unlock(&map->hint_lock); ! 2152: ! 2153: *out_entry = entry; ! 2154: ! 2155: if ((entry == &map->header) || ! 2156: (vaddr < entry->start) || (vaddr >= entry->end)) { ! 2157: vm_map_entry_t tmp_entry; ! 2158: ! 2159: /* ! 2160: * Entry was either not a valid hint, or the vaddr ! 2161: * was not contained in the entry, so do a full lookup. ! 2162: */ ! 2163: if (!vm_map_lookup_entry(map, vaddr, &tmp_entry)) ! 2164: RETURN(KERN_INVALID_ADDRESS); ! 2165: ! 2166: entry = tmp_entry; ! 2167: *out_entry = entry; ! 2168: } ! 2169: ! 2170: /* ! 2171: * Handle submaps. ! 2172: */ ! 2173: ! 2174: if (entry->is_sub_map) { ! 2175: vm_map_t old_map = map; ! 2176: ! 2177: *var_map = map = entry->object.sub_map; ! 2178: vm_map_unlock_read(old_map); ! 2179: goto RetryLookup; ! 2180: } ! 2181: ! 2182: /* ! 2183: * Check whether this task is allowed to have ! 2184: * this page. ! 2185: */ ! 2186: ! 2187: prot = entry->protection; ! 2188: if ((fault_type & (prot)) != fault_type) ! 2189: RETURN(KERN_PROTECTION_FAILURE); ! 2190: ! 2191: /* ! 2192: * If this page is not pageable, we have to get ! 2193: * it for all possible accesses. ! 2194: */ ! 2195: ! 2196: if (*wired = (entry->wired_count != 0)) ! 2197: prot = fault_type = entry->protection; ! 2198: ! 2199: /* ! 2200: * If we don't already have a VM object, track ! 2201: * it down. ! 2202: */ ! 2203: ! 2204: if (su = !entry->is_a_map) { ! 2205: share_map = map; ! 2206: share_offset = vaddr; ! 2207: } ! 2208: else { ! 2209: vm_map_entry_t share_entry; ! 2210: ! 2211: /* ! 2212: * Compute the sharing map, and offset into it. ! 2213: */ ! 2214: ! 2215: share_map = entry->object.share_map; ! 2216: share_offset = (vaddr - entry->start) + entry->offset; ! 2217: ! 2218: /* ! 2219: * Look for the backing store object and offset ! 2220: */ ! 2221: ! 2222: vm_map_lock_read(share_map); ! 2223: ! 2224: if (!vm_map_lookup_entry(share_map, share_offset, ! 2225: &share_entry)) { ! 2226: vm_map_unlock_read(share_map); ! 2227: RETURN(KERN_INVALID_ADDRESS); ! 2228: } ! 2229: entry = share_entry; ! 2230: } ! 2231: ! 2232: /* ! 2233: * If the entry was copy-on-write, we either ... ! 2234: */ ! 2235: ! 2236: if (entry->needs_copy) { ! 2237: /* ! 2238: * If we want to write the page, we may as well ! 2239: * handle that now since we've got the sharing ! 2240: * map locked. ! 2241: * ! 2242: * If we don't need to write the page, we just ! 2243: * demote the permissions allowed. ! 2244: */ ! 2245: ! 2246: if (fault_type & VM_PROT_WRITE) { ! 2247: /* ! 2248: * Make a new object, and place it in the ! 2249: * object chain. Note that no new references ! 2250: * have appeared -- one just moved from the ! 2251: * share map to the new object. ! 2252: */ ! 2253: ! 2254: if (lock_read_to_write(&share_map->lock)) { ! 2255: if (share_map != map) ! 2256: vm_map_unlock_read(map); ! 2257: goto RetryLookup; ! 2258: } ! 2259: ! 2260: vm_object_shadow( ! 2261: &entry->object.vm_object, ! 2262: &entry->offset, ! 2263: (vm_size_t) (entry->end - entry->start)); ! 2264: ! 2265: entry->needs_copy = FALSE; ! 2266: ! 2267: lock_write_to_read(&share_map->lock); ! 2268: } ! 2269: else { ! 2270: /* ! 2271: * We're attempting to read a copy-on-write ! 2272: * page -- don't allow writes. ! 2273: */ ! 2274: ! 2275: prot &= (~VM_PROT_WRITE); ! 2276: } ! 2277: } ! 2278: ! 2279: /* ! 2280: * Create an object if necessary. ! 2281: */ ! 2282: if (entry->object.vm_object == NULL) { ! 2283: ! 2284: if (lock_read_to_write(&share_map->lock)) { ! 2285: if (share_map != map) ! 2286: vm_map_unlock_read(map); ! 2287: goto RetryLookup; ! 2288: } ! 2289: ! 2290: entry->object.vm_object = vm_object_allocate( ! 2291: (vm_size_t)(entry->end - entry->start)); ! 2292: entry->offset = 0; ! 2293: lock_write_to_read(&share_map->lock); ! 2294: } ! 2295: ! 2296: /* ! 2297: * Return the object/offset from this entry. If the entry ! 2298: * was copy-on-write or empty, it has been fixed up. ! 2299: */ ! 2300: ! 2301: *offset = (share_offset - entry->start) + entry->offset; ! 2302: *object = entry->object.vm_object; ! 2303: ! 2304: /* ! 2305: * Return whether this is the only map sharing this data. ! 2306: */ ! 2307: ! 2308: if (!su) { ! 2309: simple_lock(&share_map->ref_lock); ! 2310: su = (share_map->ref_count == 1); ! 2311: simple_unlock(&share_map->ref_lock); ! 2312: } ! 2313: ! 2314: *out_prot = prot; ! 2315: *single_use = su; ! 2316: ! 2317: return(KERN_SUCCESS); ! 2318: ! 2319: #undef RETURN ! 2320: } ! 2321: ! 2322: /* ! 2323: * vm_map_lookup_done: ! 2324: * ! 2325: * Releases locks acquired by a vm_map_lookup ! 2326: * (according to the handle returned by that lookup). ! 2327: */ ! 2328: ! 2329: void vm_map_lookup_done(map, entry) ! 2330: register vm_map_t map; ! 2331: vm_map_entry_t entry; ! 2332: { ! 2333: /* ! 2334: * If this entry references a map, unlock it first. ! 2335: */ ! 2336: ! 2337: if (entry->is_a_map) ! 2338: vm_map_unlock_read(entry->object.share_map); ! 2339: ! 2340: /* ! 2341: * Unlock the main-level map ! 2342: */ ! 2343: ! 2344: vm_map_unlock_read(map); ! 2345: } ! 2346: ! 2347: /* ! 2348: * Routine: vm_map_simplify ! 2349: * Purpose: ! 2350: * Attempt to simplify the map representation in ! 2351: * the vicinity of the given starting address. ! 2352: * Note: ! 2353: * This routine is intended primarily to keep the ! 2354: * kernel maps more compact -- they generally don't ! 2355: * benefit from the "expand a map entry" technology ! 2356: * at allocation time because the adjacent entry ! 2357: * is often wired down. ! 2358: */ ! 2359: void vm_map_simplify(map, start) ! 2360: vm_map_t map; ! 2361: vm_offset_t start; ! 2362: { ! 2363: vm_map_entry_t this_entry; ! 2364: vm_map_entry_t prev_entry; ! 2365: ! 2366: vm_map_lock(map); ! 2367: if ( ! 2368: (vm_map_lookup_entry(map, start, &this_entry)) && ! 2369: ((prev_entry = this_entry->prev) != &map->header) && ! 2370: ! 2371: (prev_entry->end == start) && ! 2372: (map->is_main_map) && ! 2373: ! 2374: (prev_entry->is_a_map == FALSE) && ! 2375: (prev_entry->is_sub_map == FALSE) && ! 2376: ! 2377: (this_entry->is_a_map == FALSE) && ! 2378: (this_entry->is_sub_map == FALSE) && ! 2379: ! 2380: (prev_entry->inheritance == this_entry->inheritance) && ! 2381: (prev_entry->protection == this_entry->protection) && ! 2382: (prev_entry->max_protection == this_entry->max_protection) && ! 2383: (prev_entry->wired_count == this_entry->wired_count) && ! 2384: ! 2385: (prev_entry->copy_on_write == this_entry->copy_on_write) && ! 2386: (prev_entry->needs_copy == this_entry->needs_copy) && ! 2387: ! 2388: (prev_entry->object.vm_object == this_entry->object.vm_object) && ! 2389: ((prev_entry->offset + (prev_entry->end - prev_entry->start)) ! 2390: == this_entry->offset) ! 2391: ) { ! 2392: if (map->first_free == this_entry) ! 2393: map->first_free = prev_entry; ! 2394: ! 2395: SAVE_HINT(map, prev_entry); ! 2396: vm_map_entry_unlink(map, this_entry); ! 2397: prev_entry->end = this_entry->end; ! 2398: vm_object_deallocate(this_entry->object.vm_object); ! 2399: vm_map_entry_dispose(map, this_entry); ! 2400: } ! 2401: vm_map_unlock(map); ! 2402: } ! 2403: ! 2404: /* ! 2405: * vm_map_print: [ debug ] ! 2406: */ ! 2407: void vm_map_print(map, full) ! 2408: register vm_map_t map; ! 2409: boolean_t full; ! 2410: { ! 2411: register vm_map_entry_t entry; ! 2412: extern int indent; ! 2413: ! 2414: iprintf("%s map 0x%x: pmap=0x%x,ref=%d,nentries=%d,version=%d\n", ! 2415: (map->is_main_map ? "Task" : "Share"), ! 2416: (int) map, (int) (map->pmap), map->ref_count, map->nentries, ! 2417: map->timestamp); ! 2418: ! 2419: if (!full && indent) ! 2420: return; ! 2421: ! 2422: indent += 2; ! 2423: for (entry = map->header.next; entry != &map->header; ! 2424: entry = entry->next) { ! 2425: iprintf("map entry 0x%x: start=0x%x, end=0x%x, ", ! 2426: (int) entry, (int) entry->start, (int) entry->end); ! 2427: if (map->is_main_map) { ! 2428: static char *inheritance_name[4] = ! 2429: { "share", "copy", "none", "donate_copy"}; ! 2430: printf("prot=%x/%x/%s, ", ! 2431: entry->protection, ! 2432: entry->max_protection, ! 2433: inheritance_name[entry->inheritance]); ! 2434: if (entry->wired_count != 0) ! 2435: printf("wired, "); ! 2436: } ! 2437: ! 2438: if (entry->is_a_map || entry->is_sub_map) { ! 2439: printf("share=0x%x, offset=0x%x\n", ! 2440: (int) entry->object.share_map, ! 2441: (int) entry->offset); ! 2442: if ((entry->prev == &map->header) || ! 2443: (!entry->prev->is_a_map) || ! 2444: (entry->prev->object.share_map != ! 2445: entry->object.share_map)) { ! 2446: indent += 2; ! 2447: vm_map_print(entry->object.share_map, full); ! 2448: indent -= 2; ! 2449: } ! 2450: ! 2451: } ! 2452: else { ! 2453: printf("object=0x%x, offset=0x%x", ! 2454: (int) entry->object.vm_object, ! 2455: (int) entry->offset); ! 2456: if (entry->copy_on_write) ! 2457: printf(", copy (%s)", ! 2458: entry->needs_copy ? "needed" : "done"); ! 2459: printf("\n"); ! 2460: ! 2461: if ((entry->prev == &map->header) || ! 2462: (entry->prev->is_a_map) || ! 2463: (entry->prev->object.vm_object != ! 2464: entry->object.vm_object)) { ! 2465: indent += 2; ! 2466: vm_object_print(entry->object.vm_object, full); ! 2467: indent -= 2; ! 2468: } ! 2469: } ! 2470: } ! 2471: indent -= 2; ! 2472: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.