145748Smckusick /* 263379Sbostic * Copyright (c) 1991, 1993 363379Sbostic * The Regents of the University of California. All rights reserved. 445748Smckusick * 545748Smckusick * This code is derived from software contributed to Berkeley by 645748Smckusick * The Mach Operating System project at Carnegie-Mellon University. 745748Smckusick * 848493Smckusick * %sccs.include.redist.c% 945748Smckusick * 10*65686Shibler * @(#)vm_map.c 8.3 (Berkeley) 01/12/94 1148493Smckusick * 1248493Smckusick * 1348493Smckusick * Copyright (c) 1987, 1990 Carnegie-Mellon University. 1448493Smckusick * All rights reserved. 1548493Smckusick * 1648493Smckusick * Authors: Avadis Tevanian, Jr., Michael Wayne Young 1748493Smckusick * 1848493Smckusick * Permission to use, copy, modify and distribute this software and 1948493Smckusick * its documentation is hereby granted, provided that both the copyright 2048493Smckusick * notice and this permission notice appear in all copies of the 2148493Smckusick * software, derivative works or modified versions, and any portions 2248493Smckusick * thereof, and that both notices appear in supporting documentation. 2348493Smckusick * 2448493Smckusick * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 2548493Smckusick * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 2648493Smckusick * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 2748493Smckusick * 2848493Smckusick * Carnegie Mellon requests users of this software to return to 2948493Smckusick * 3048493Smckusick * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 3148493Smckusick * School of Computer Science 3248493Smckusick * Carnegie Mellon University 3348493Smckusick * Pittsburgh PA 15213-3890 3448493Smckusick * 3548493Smckusick * any improvements or extensions that they make and grant Carnegie the 3648493Smckusick * rights to redistribute these changes. 3745748Smckusick */ 3845748Smckusick 3945748Smckusick /* 4045748Smckusick * Virtual memory mapping module. 4145748Smckusick */ 4245748Smckusick 4353357Sbostic #include <sys/param.h> 4453357Sbostic #include <sys/systm.h> 4553357Sbostic #include <sys/malloc.h> 4645748Smckusick 4753357Sbostic #include <vm/vm.h> 4853357Sbostic #include <vm/vm_page.h> 4953357Sbostic #include <vm/vm_object.h> 5053357Sbostic 5145748Smckusick /* 5245748Smckusick * Virtual memory maps provide for the mapping, protection, 5345748Smckusick * and sharing of virtual memory objects. In addition, 5445748Smckusick * this module provides for an efficient virtual copy of 5545748Smckusick * memory from one map to another. 5645748Smckusick * 5745748Smckusick * Synchronization is required prior to most operations. 5845748Smckusick * 5945748Smckusick * Maps consist of an ordered doubly-linked list of simple 6045748Smckusick * entries; a single hint is used to speed up lookups. 6145748Smckusick * 6245748Smckusick * In order to properly represent the sharing of virtual 6345748Smckusick * memory regions among maps, the map structure is bi-level. 6445748Smckusick * Top-level ("address") maps refer to regions of sharable 6545748Smckusick * virtual memory. These regions are implemented as 6645748Smckusick * ("sharing") maps, which then refer to the actual virtual 6745748Smckusick * memory objects. When two address maps "share" memory, 6845748Smckusick * their top-level maps both have references to the same 6945748Smckusick * sharing map. When memory is virtual-copied from one 7045748Smckusick * address map to another, the references in the sharing 7145748Smckusick * maps are actually copied -- no copying occurs at the 7245748Smckusick * virtual memory object level. 7345748Smckusick * 7445748Smckusick * Since portions of maps are specified by start/end addreses, 7545748Smckusick * which may not align with existing map entries, all 7645748Smckusick * routines merely "clip" entries to these start/end values. 7745748Smckusick * [That is, an entry is split into two, bordering at a 7845748Smckusick * start or end value.] Note that these clippings may not 7945748Smckusick * always be necessary (as the two resulting entries are then 8045748Smckusick * not changed); however, the clipping is done for convenience. 8145748Smckusick * No attempt is currently made to "glue back together" two 8245748Smckusick * abutting entries. 8345748Smckusick * 8445748Smckusick * As mentioned above, virtual copy operations are performed 8545748Smckusick * by copying VM object references from one sharing map to 8645748Smckusick * another, and then marking both regions as copy-on-write. 8745748Smckusick * It is important to note that only one writeable reference 8845748Smckusick * to a VM object region exists in any map -- this means that 8945748Smckusick * shadow object creation can be delayed until a write operation 9045748Smckusick * occurs. 9145748Smckusick */ 9245748Smckusick 9345748Smckusick /* 9448383Skarels * vm_map_startup: 9545748Smckusick * 9645748Smckusick * Initialize the vm_map module. Must be called before 9745748Smckusick * any other vm_map routines. 9845748Smckusick * 9945748Smckusick * Map and entry structures are allocated from the general 10045748Smckusick * purpose memory pool with some exceptions: 10145748Smckusick * 10245748Smckusick * - The kernel map and kmem submap are allocated statically. 10345748Smckusick * - Kernel map entries are allocated out of a static pool. 10445748Smckusick * 10545748Smckusick * These restrictions are necessary since malloc() uses the 10645748Smckusick * maps and requires map entries. 10745748Smckusick */ 10845748Smckusick 10945748Smckusick vm_offset_t kentry_data; 11045748Smckusick vm_size_t kentry_data_size; 11145748Smckusick vm_map_entry_t kentry_free; 11245748Smckusick vm_map_t kmap_free; 11345748Smckusick 11453357Sbostic static void _vm_map_clip_end __P((vm_map_t, vm_map_entry_t, vm_offset_t)); 11553357Sbostic static void _vm_map_clip_start __P((vm_map_t, vm_map_entry_t, vm_offset_t)); 11653357Sbostic 11748383Skarels void vm_map_startup() 11845748Smckusick { 11945748Smckusick register int i; 12045748Smckusick register vm_map_entry_t mep; 12145748Smckusick vm_map_t mp; 12245748Smckusick 12345748Smckusick /* 12445748Smckusick * Static map structures for allocation before initialization of 12545748Smckusick * kernel map or kmem map. vm_map_create knows how to deal with them. 12645748Smckusick */ 12745748Smckusick kmap_free = mp = (vm_map_t) kentry_data; 12845748Smckusick i = MAX_KMAP; 12945748Smckusick while (--i > 0) { 13045748Smckusick mp->header.next = (vm_map_entry_t) (mp + 1); 13145748Smckusick mp++; 13245748Smckusick } 13348383Skarels mp++->header.next = NULL; 13445748Smckusick 13545748Smckusick /* 13645748Smckusick * Form a free list of statically allocated kernel map entries 13745748Smckusick * with the rest. 13845748Smckusick */ 13945748Smckusick kentry_free = mep = (vm_map_entry_t) mp; 14045748Smckusick i = (kentry_data_size - MAX_KMAP * sizeof *mp) / sizeof *mep; 14145748Smckusick while (--i > 0) { 14245748Smckusick mep->next = mep + 1; 14345748Smckusick mep++; 14445748Smckusick } 14548383Skarels mep->next = NULL; 14645748Smckusick } 14745748Smckusick 14845748Smckusick /* 14948383Skarels * Allocate a vmspace structure, including a vm_map and pmap, 15048383Skarels * and initialize those structures. The refcnt is set to 1. 15148383Skarels * The remaining fields must be initialized by the caller. 15248383Skarels */ 15348383Skarels struct vmspace * 15448383Skarels vmspace_alloc(min, max, pageable) 15548383Skarels vm_offset_t min, max; 15648383Skarels int pageable; 15748383Skarels { 15848383Skarels register struct vmspace *vm; 15948383Skarels 16048383Skarels MALLOC(vm, struct vmspace *, sizeof(struct vmspace), M_VMMAP, M_WAITOK); 16148383Skarels bzero(vm, (caddr_t) &vm->vm_startcopy - (caddr_t) vm); 16248383Skarels vm_map_init(&vm->vm_map, min, max, pageable); 16348383Skarels pmap_pinit(&vm->vm_pmap); 16448383Skarels vm->vm_map.pmap = &vm->vm_pmap; /* XXX */ 16548383Skarels vm->vm_refcnt = 1; 16648383Skarels return (vm); 16748383Skarels } 16848383Skarels 16948383Skarels void 17048383Skarels vmspace_free(vm) 17148383Skarels register struct vmspace *vm; 17248383Skarels { 17348383Skarels 17448383Skarels if (--vm->vm_refcnt == 0) { 17548383Skarels /* 17648383Skarels * Lock the map, to wait out all other references to it. 17748383Skarels * Delete all of the mappings and pages they hold, 17848383Skarels * then call the pmap module to reclaim anything left. 17948383Skarels */ 18048383Skarels vm_map_lock(&vm->vm_map); 18148383Skarels (void) vm_map_delete(&vm->vm_map, vm->vm_map.min_offset, 18248383Skarels vm->vm_map.max_offset); 18348383Skarels pmap_release(&vm->vm_pmap); 18448383Skarels FREE(vm, M_VMMAP); 18548383Skarels } 18648383Skarels } 18748383Skarels 18848383Skarels /* 18945748Smckusick * vm_map_create: 19045748Smckusick * 19145748Smckusick * Creates and returns a new empty VM map with 19245748Smckusick * the given physical map structure, and having 19345748Smckusick * the given lower and upper address bounds. 19445748Smckusick */ 19545748Smckusick vm_map_t vm_map_create(pmap, min, max, pageable) 19645748Smckusick pmap_t pmap; 19745748Smckusick vm_offset_t min, max; 19845748Smckusick boolean_t pageable; 19945748Smckusick { 20045748Smckusick register vm_map_t result; 20165479Sbostic extern vm_map_t kmem_map; 20245748Smckusick 20348383Skarels if (kmem_map == NULL) { 20445748Smckusick result = kmap_free; 20545748Smckusick kmap_free = (vm_map_t) result->header.next; 20648383Skarels if (result == NULL) 20748383Skarels panic("vm_map_create: out of maps"); 20845748Smckusick } else 20945748Smckusick MALLOC(result, vm_map_t, sizeof(struct vm_map), 21045748Smckusick M_VMMAP, M_WAITOK); 21145748Smckusick 21248383Skarels vm_map_init(result, min, max, pageable); 21345748Smckusick result->pmap = pmap; 21445748Smckusick return(result); 21545748Smckusick } 21645748Smckusick 21745748Smckusick /* 21848383Skarels * Initialize an existing vm_map structure 21948383Skarels * such as that in the vmspace structure. 22048383Skarels * The pmap is set elsewhere. 22148383Skarels */ 22248383Skarels void 22348383Skarels vm_map_init(map, min, max, pageable) 22448383Skarels register struct vm_map *map; 22548383Skarels vm_offset_t min, max; 22648383Skarels boolean_t pageable; 22748383Skarels { 22848383Skarels map->header.next = map->header.prev = &map->header; 22948383Skarels map->nentries = 0; 23048383Skarels map->size = 0; 23148383Skarels map->ref_count = 1; 23248383Skarels map->is_main_map = TRUE; 23348383Skarels map->min_offset = min; 23448383Skarels map->max_offset = max; 23548383Skarels map->entries_pageable = pageable; 23648383Skarels map->first_free = &map->header; 23748383Skarels map->hint = &map->header; 23848383Skarels map->timestamp = 0; 23948383Skarels lock_init(&map->lock, TRUE); 24048383Skarels simple_lock_init(&map->ref_lock); 24148383Skarels simple_lock_init(&map->hint_lock); 24248383Skarels } 24348383Skarels 24448383Skarels /* 24545748Smckusick * vm_map_entry_create: [ internal use only ] 24645748Smckusick * 24745748Smckusick * Allocates a VM map entry for insertion. 24845748Smckusick * No entry fields are filled in. This routine is 24945748Smckusick */ 25045748Smckusick vm_map_entry_t vm_map_entry_create(map) 25145748Smckusick vm_map_t map; 25245748Smckusick { 25345748Smckusick vm_map_entry_t entry; 254*65686Shibler #ifdef DEBUG 25558374Smckusick extern vm_map_t kernel_map, kmem_map, mb_map, pager_map; 256*65686Shibler boolean_t isspecial; 25745748Smckusick 258*65686Shibler isspecial = (map == kernel_map || map == kmem_map || 259*65686Shibler map == mb_map || map == pager_map); 260*65686Shibler if (isspecial && map->entries_pageable || 261*65686Shibler !isspecial && !map->entries_pageable) 262*65686Shibler panic("vm_map_entry_create: bogus map"); 263*65686Shibler #endif 264*65686Shibler if (map->entries_pageable) { 265*65686Shibler MALLOC(entry, vm_map_entry_t, sizeof(struct vm_map_entry), 266*65686Shibler M_VMMAPENT, M_WAITOK); 267*65686Shibler } else { 26845748Smckusick if (entry = kentry_free) 26945748Smckusick kentry_free = kentry_free->next; 270*65686Shibler } 27148383Skarels if (entry == NULL) 27245748Smckusick panic("vm_map_entry_create: out of map entries"); 27345748Smckusick 27445748Smckusick return(entry); 27545748Smckusick } 27645748Smckusick 27745748Smckusick /* 27845748Smckusick * vm_map_entry_dispose: [ internal use only ] 27945748Smckusick * 28045748Smckusick * Inverse of vm_map_entry_create. 28145748Smckusick */ 28245748Smckusick void vm_map_entry_dispose(map, entry) 28345748Smckusick vm_map_t map; 28445748Smckusick vm_map_entry_t entry; 28545748Smckusick { 286*65686Shibler #ifdef DEBUG 28758374Smckusick extern vm_map_t kernel_map, kmem_map, mb_map, pager_map; 288*65686Shibler boolean_t isspecial; 28945748Smckusick 290*65686Shibler isspecial = (map == kernel_map || map == kmem_map || 291*65686Shibler map == mb_map || map == pager_map); 292*65686Shibler if (isspecial && map->entries_pageable || 293*65686Shibler !isspecial && !map->entries_pageable) 294*65686Shibler panic("vm_map_entry_dispose: bogus map"); 295*65686Shibler #endif 296*65686Shibler if (map->entries_pageable) { 297*65686Shibler FREE(entry, M_VMMAPENT); 298*65686Shibler } else { 29945748Smckusick entry->next = kentry_free; 30045748Smckusick kentry_free = entry; 301*65686Shibler } 30245748Smckusick } 30345748Smckusick 30445748Smckusick /* 30545748Smckusick * vm_map_entry_{un,}link: 30645748Smckusick * 30745748Smckusick * Insert/remove entries from maps. 30845748Smckusick */ 30945748Smckusick #define vm_map_entry_link(map, after_where, entry) \ 31045748Smckusick { \ 31145748Smckusick (map)->nentries++; \ 31245748Smckusick (entry)->prev = (after_where); \ 31345748Smckusick (entry)->next = (after_where)->next; \ 31445748Smckusick (entry)->prev->next = (entry); \ 31545748Smckusick (entry)->next->prev = (entry); \ 31645748Smckusick } 31745748Smckusick #define vm_map_entry_unlink(map, entry) \ 31845748Smckusick { \ 31945748Smckusick (map)->nentries--; \ 32045748Smckusick (entry)->next->prev = (entry)->prev; \ 32145748Smckusick (entry)->prev->next = (entry)->next; \ 32245748Smckusick } 32345748Smckusick 32445748Smckusick /* 32545748Smckusick * vm_map_reference: 32645748Smckusick * 32745748Smckusick * Creates another valid reference to the given map. 32845748Smckusick * 32945748Smckusick */ 33045748Smckusick void vm_map_reference(map) 33145748Smckusick register vm_map_t map; 33245748Smckusick { 33348383Skarels if (map == NULL) 33445748Smckusick return; 33545748Smckusick 33645748Smckusick simple_lock(&map->ref_lock); 33745748Smckusick map->ref_count++; 33845748Smckusick simple_unlock(&map->ref_lock); 33945748Smckusick } 34045748Smckusick 34145748Smckusick /* 34245748Smckusick * vm_map_deallocate: 34345748Smckusick * 34445748Smckusick * Removes a reference from the specified map, 34545748Smckusick * destroying it if no references remain. 34645748Smckusick * The map should not be locked. 34745748Smckusick */ 34845748Smckusick void vm_map_deallocate(map) 34945748Smckusick register vm_map_t map; 35045748Smckusick { 35145748Smckusick register int c; 35245748Smckusick 35348383Skarels if (map == NULL) 35445748Smckusick return; 35545748Smckusick 35645748Smckusick simple_lock(&map->ref_lock); 35745748Smckusick c = --map->ref_count; 35845748Smckusick simple_unlock(&map->ref_lock); 35945748Smckusick 36045748Smckusick if (c > 0) { 36145748Smckusick return; 36245748Smckusick } 36345748Smckusick 36445748Smckusick /* 36545748Smckusick * Lock the map, to wait out all other references 36645748Smckusick * to it. 36745748Smckusick */ 36845748Smckusick 36945748Smckusick vm_map_lock(map); 37045748Smckusick 37145748Smckusick (void) vm_map_delete(map, map->min_offset, map->max_offset); 37245748Smckusick 37345748Smckusick pmap_destroy(map->pmap); 37445748Smckusick 37545748Smckusick FREE(map, M_VMMAP); 37645748Smckusick } 37745748Smckusick 37845748Smckusick /* 379*65686Shibler * vm_map_insert: 38045748Smckusick * 38145748Smckusick * Inserts the given whole VM object into the target 38245748Smckusick * map at the specified address range. The object's 38345748Smckusick * size should match that of the address range. 38445748Smckusick * 38545748Smckusick * Requires that the map be locked, and leaves it so. 38645748Smckusick */ 38753357Sbostic int 38845748Smckusick vm_map_insert(map, object, offset, start, end) 38945748Smckusick vm_map_t map; 39045748Smckusick vm_object_t object; 39145748Smckusick vm_offset_t offset; 39245748Smckusick vm_offset_t start; 39345748Smckusick vm_offset_t end; 39445748Smckusick { 39545748Smckusick register vm_map_entry_t new_entry; 39645748Smckusick register vm_map_entry_t prev_entry; 39745748Smckusick vm_map_entry_t temp_entry; 39845748Smckusick 39945748Smckusick /* 40045748Smckusick * Check that the start and end points are not bogus. 40145748Smckusick */ 40245748Smckusick 40345748Smckusick if ((start < map->min_offset) || (end > map->max_offset) || 40445748Smckusick (start >= end)) 40545748Smckusick return(KERN_INVALID_ADDRESS); 40645748Smckusick 40745748Smckusick /* 40845748Smckusick * Find the entry prior to the proposed 40945748Smckusick * starting address; if it's part of an 41045748Smckusick * existing entry, this range is bogus. 41145748Smckusick */ 41245748Smckusick 41345748Smckusick if (vm_map_lookup_entry(map, start, &temp_entry)) 41445748Smckusick return(KERN_NO_SPACE); 41545748Smckusick 41645748Smckusick prev_entry = temp_entry; 41745748Smckusick 41845748Smckusick /* 41945748Smckusick * Assert that the next entry doesn't overlap the 42045748Smckusick * end point. 42145748Smckusick */ 42245748Smckusick 42345748Smckusick if ((prev_entry->next != &map->header) && 42445748Smckusick (prev_entry->next->start < end)) 42545748Smckusick return(KERN_NO_SPACE); 42645748Smckusick 42745748Smckusick /* 42845748Smckusick * See if we can avoid creating a new entry by 42945748Smckusick * extending one of our neighbors. 43045748Smckusick */ 43145748Smckusick 43248383Skarels if (object == NULL) { 43345748Smckusick if ((prev_entry != &map->header) && 43445748Smckusick (prev_entry->end == start) && 43545748Smckusick (map->is_main_map) && 43645748Smckusick (prev_entry->is_a_map == FALSE) && 43745748Smckusick (prev_entry->is_sub_map == FALSE) && 43845748Smckusick (prev_entry->inheritance == VM_INHERIT_DEFAULT) && 43945748Smckusick (prev_entry->protection == VM_PROT_DEFAULT) && 44045748Smckusick (prev_entry->max_protection == VM_PROT_DEFAULT) && 44145748Smckusick (prev_entry->wired_count == 0)) { 44245748Smckusick 44345748Smckusick if (vm_object_coalesce(prev_entry->object.vm_object, 44448383Skarels NULL, 44545748Smckusick prev_entry->offset, 44645748Smckusick (vm_offset_t) 0, 44745748Smckusick (vm_size_t)(prev_entry->end 44845748Smckusick - prev_entry->start), 44945748Smckusick (vm_size_t)(end - prev_entry->end))) { 45045748Smckusick /* 45145748Smckusick * Coalesced the two objects - can extend 45245748Smckusick * the previous map entry to include the 45345748Smckusick * new range. 45445748Smckusick */ 45545748Smckusick map->size += (end - prev_entry->end); 45645748Smckusick prev_entry->end = end; 45745748Smckusick return(KERN_SUCCESS); 45845748Smckusick } 45945748Smckusick } 46045748Smckusick } 46145748Smckusick 46245748Smckusick /* 46345748Smckusick * Create a new entry 46445748Smckusick */ 46545748Smckusick 46645748Smckusick new_entry = vm_map_entry_create(map); 46745748Smckusick new_entry->start = start; 46845748Smckusick new_entry->end = end; 46945748Smckusick 47045748Smckusick new_entry->is_a_map = FALSE; 47145748Smckusick new_entry->is_sub_map = FALSE; 47245748Smckusick new_entry->object.vm_object = object; 47345748Smckusick new_entry->offset = offset; 47445748Smckusick 47545748Smckusick new_entry->copy_on_write = FALSE; 47645748Smckusick new_entry->needs_copy = FALSE; 47745748Smckusick 47845748Smckusick if (map->is_main_map) { 47945748Smckusick new_entry->inheritance = VM_INHERIT_DEFAULT; 48045748Smckusick new_entry->protection = VM_PROT_DEFAULT; 48145748Smckusick new_entry->max_protection = VM_PROT_DEFAULT; 48245748Smckusick new_entry->wired_count = 0; 48345748Smckusick } 48445748Smckusick 48545748Smckusick /* 48645748Smckusick * Insert the new entry into the list 48745748Smckusick */ 48845748Smckusick 48945748Smckusick vm_map_entry_link(map, prev_entry, new_entry); 49045748Smckusick map->size += new_entry->end - new_entry->start; 49145748Smckusick 49245748Smckusick /* 49345748Smckusick * Update the free space hint 49445748Smckusick */ 49545748Smckusick 49645748Smckusick if ((map->first_free == prev_entry) && (prev_entry->end >= new_entry->start)) 49745748Smckusick map->first_free = new_entry; 49845748Smckusick 49945748Smckusick return(KERN_SUCCESS); 50045748Smckusick } 50145748Smckusick 50245748Smckusick /* 50345748Smckusick * SAVE_HINT: 50445748Smckusick * 50545748Smckusick * Saves the specified entry as the hint for 50645748Smckusick * future lookups. Performs necessary interlocks. 50745748Smckusick */ 50845748Smckusick #define SAVE_HINT(map,value) \ 50945748Smckusick simple_lock(&(map)->hint_lock); \ 51045748Smckusick (map)->hint = (value); \ 51145748Smckusick simple_unlock(&(map)->hint_lock); 51245748Smckusick 51345748Smckusick /* 51445748Smckusick * vm_map_lookup_entry: [ internal use only ] 51545748Smckusick * 51645748Smckusick * Finds the map entry containing (or 51745748Smckusick * immediately preceding) the specified address 51845748Smckusick * in the given map; the entry is returned 51945748Smckusick * in the "entry" parameter. The boolean 52045748Smckusick * result indicates whether the address is 52145748Smckusick * actually contained in the map. 52245748Smckusick */ 52345748Smckusick boolean_t vm_map_lookup_entry(map, address, entry) 52445748Smckusick register vm_map_t map; 52545748Smckusick register vm_offset_t address; 52645748Smckusick vm_map_entry_t *entry; /* OUT */ 52745748Smckusick { 52845748Smckusick register vm_map_entry_t cur; 52945748Smckusick register vm_map_entry_t last; 53045748Smckusick 53145748Smckusick /* 53245748Smckusick * Start looking either from the head of the 53345748Smckusick * list, or from the hint. 53445748Smckusick */ 53545748Smckusick 53645748Smckusick simple_lock(&map->hint_lock); 53745748Smckusick cur = map->hint; 53845748Smckusick simple_unlock(&map->hint_lock); 53945748Smckusick 54045748Smckusick if (cur == &map->header) 54145748Smckusick cur = cur->next; 54245748Smckusick 54345748Smckusick if (address >= cur->start) { 54445748Smckusick /* 54545748Smckusick * Go from hint to end of list. 54645748Smckusick * 54745748Smckusick * But first, make a quick check to see if 54845748Smckusick * we are already looking at the entry we 54945748Smckusick * want (which is usually the case). 55045748Smckusick * Note also that we don't need to save the hint 55145748Smckusick * here... it is the same hint (unless we are 55245748Smckusick * at the header, in which case the hint didn't 55345748Smckusick * buy us anything anyway). 55445748Smckusick */ 55545748Smckusick last = &map->header; 55645748Smckusick if ((cur != last) && (cur->end > address)) { 55745748Smckusick *entry = cur; 55845748Smckusick return(TRUE); 55945748Smckusick } 56045748Smckusick } 56145748Smckusick else { 56245748Smckusick /* 56345748Smckusick * Go from start to hint, *inclusively* 56445748Smckusick */ 56545748Smckusick last = cur->next; 56645748Smckusick cur = map->header.next; 56745748Smckusick } 56845748Smckusick 56945748Smckusick /* 57045748Smckusick * Search linearly 57145748Smckusick */ 57245748Smckusick 57345748Smckusick while (cur != last) { 57445748Smckusick if (cur->end > address) { 57545748Smckusick if (address >= cur->start) { 57645748Smckusick /* 57745748Smckusick * Save this lookup for future 57845748Smckusick * hints, and return 57945748Smckusick */ 58045748Smckusick 58145748Smckusick *entry = cur; 58245748Smckusick SAVE_HINT(map, cur); 58345748Smckusick return(TRUE); 58445748Smckusick } 58545748Smckusick break; 58645748Smckusick } 58745748Smckusick cur = cur->next; 58845748Smckusick } 58945748Smckusick *entry = cur->prev; 59045748Smckusick SAVE_HINT(map, *entry); 59145748Smckusick return(FALSE); 59245748Smckusick } 59345748Smckusick 59445748Smckusick /* 59552610Storek * Find sufficient space for `length' bytes in the given map, starting at 59652610Storek * `start'. The map must be locked. Returns 0 on success, 1 on no space. 59752610Storek */ 59852610Storek int 59952610Storek vm_map_findspace(map, start, length, addr) 60052610Storek register vm_map_t map; 60152610Storek register vm_offset_t start; 60252610Storek vm_size_t length; 60352610Storek vm_offset_t *addr; 60452610Storek { 60552610Storek register vm_map_entry_t entry, next; 60652610Storek register vm_offset_t end; 60752610Storek 60852610Storek if (start < map->min_offset) 60952610Storek start = map->min_offset; 61052610Storek if (start > map->max_offset) 61152610Storek return (1); 61252610Storek 61352610Storek /* 61452610Storek * Look for the first possible address; if there's already 61552610Storek * something at this address, we have to start after it. 61652610Storek */ 61752610Storek if (start == map->min_offset) { 61852610Storek if ((entry = map->first_free) != &map->header) 61952610Storek start = entry->end; 62052610Storek } else { 62152610Storek vm_map_entry_t tmp; 62252610Storek if (vm_map_lookup_entry(map, start, &tmp)) 62352610Storek start = tmp->end; 62452610Storek entry = tmp; 62552610Storek } 62652610Storek 62752610Storek /* 62852610Storek * Look through the rest of the map, trying to fit a new region in 62952610Storek * the gap between existing regions, or after the very last region. 63052610Storek */ 63152610Storek for (;; start = (entry = next)->end) { 63252610Storek /* 63352610Storek * Find the end of the proposed new region. Be sure we didn't 63452610Storek * go beyond the end of the map, or wrap around the address; 63552610Storek * if so, we lose. Otherwise, if this is the last entry, or 63652610Storek * if the proposed new region fits before the next entry, we 63752610Storek * win. 63852610Storek */ 63952610Storek end = start + length; 64052610Storek if (end > map->max_offset || end < start) 64152610Storek return (1); 64252610Storek next = entry->next; 64352610Storek if (next == &map->header || next->start >= end) 64452610Storek break; 64552610Storek } 64652610Storek SAVE_HINT(map, entry); 64752610Storek *addr = start; 64852610Storek return (0); 64952610Storek } 65052610Storek 65152610Storek /* 65245748Smckusick * vm_map_find finds an unallocated region in the target address 65345748Smckusick * map with the given length. The search is defined to be 65445748Smckusick * first-fit from the specified address; the region found is 65545748Smckusick * returned in the same parameter. 65645748Smckusick * 65745748Smckusick */ 65853357Sbostic int 65945748Smckusick vm_map_find(map, object, offset, addr, length, find_space) 66045748Smckusick vm_map_t map; 66145748Smckusick vm_object_t object; 66245748Smckusick vm_offset_t offset; 66345748Smckusick vm_offset_t *addr; /* IN/OUT */ 66445748Smckusick vm_size_t length; 66545748Smckusick boolean_t find_space; 66645748Smckusick { 66745748Smckusick register vm_offset_t start; 66845748Smckusick int result; 66945748Smckusick 67045748Smckusick start = *addr; 67145748Smckusick vm_map_lock(map); 67245748Smckusick if (find_space) { 67352610Storek if (vm_map_findspace(map, start, length, addr)) { 67445748Smckusick vm_map_unlock(map); 67545748Smckusick return (KERN_NO_SPACE); 67645748Smckusick } 67752610Storek start = *addr; 67845748Smckusick } 67945748Smckusick result = vm_map_insert(map, object, offset, start, start + length); 68045748Smckusick vm_map_unlock(map); 68152610Storek return (result); 68245748Smckusick } 68345748Smckusick 68445748Smckusick /* 68545748Smckusick * vm_map_simplify_entry: [ internal use only ] 68645748Smckusick * 68745748Smckusick * Simplify the given map entry by: 68845748Smckusick * removing extra sharing maps 68945748Smckusick * [XXX maybe later] merging with a neighbor 69045748Smckusick */ 69145748Smckusick void vm_map_simplify_entry(map, entry) 69245748Smckusick vm_map_t map; 69345748Smckusick vm_map_entry_t entry; 69445748Smckusick { 69545748Smckusick #ifdef lint 69645748Smckusick map++; 69760345Storek #endif 69845748Smckusick 69945748Smckusick /* 70045748Smckusick * If this entry corresponds to a sharing map, then 70145748Smckusick * see if we can remove the level of indirection. 70245748Smckusick * If it's not a sharing map, then it points to 70345748Smckusick * a VM object, so see if we can merge with either 70445748Smckusick * of our neighbors. 70545748Smckusick */ 70645748Smckusick 70745748Smckusick if (entry->is_sub_map) 70845748Smckusick return; 70945748Smckusick if (entry->is_a_map) { 71045748Smckusick #if 0 71145748Smckusick vm_map_t my_share_map; 71245748Smckusick int count; 71345748Smckusick 71445748Smckusick my_share_map = entry->object.share_map; 71545748Smckusick simple_lock(&my_share_map->ref_lock); 71645748Smckusick count = my_share_map->ref_count; 71745748Smckusick simple_unlock(&my_share_map->ref_lock); 71845748Smckusick 71945748Smckusick if (count == 1) { 72045748Smckusick /* Can move the region from 72145748Smckusick * entry->start to entry->end (+ entry->offset) 72245748Smckusick * in my_share_map into place of entry. 72345748Smckusick * Later. 72445748Smckusick */ 72545748Smckusick } 72660345Storek #endif 72745748Smckusick } 72845748Smckusick else { 72945748Smckusick /* 73045748Smckusick * Try to merge with our neighbors. 73145748Smckusick * 73245748Smckusick * Conditions for merge are: 73345748Smckusick * 73445748Smckusick * 1. entries are adjacent. 73545748Smckusick * 2. both entries point to objects 73645748Smckusick * with null pagers. 73745748Smckusick * 73845748Smckusick * If a merge is possible, we replace the two 73945748Smckusick * entries with a single entry, then merge 74045748Smckusick * the two objects into a single object. 74145748Smckusick * 74245748Smckusick * Now, all that is left to do is write the 74345748Smckusick * code! 74445748Smckusick */ 74545748Smckusick } 74645748Smckusick } 74745748Smckusick 74845748Smckusick /* 74945748Smckusick * vm_map_clip_start: [ internal use only ] 75045748Smckusick * 75145748Smckusick * Asserts that the given entry begins at or after 75245748Smckusick * the specified address; if necessary, 75345748Smckusick * it splits the entry into two. 75445748Smckusick */ 75545748Smckusick #define vm_map_clip_start(map, entry, startaddr) \ 75645748Smckusick { \ 75745748Smckusick if (startaddr > entry->start) \ 75845748Smckusick _vm_map_clip_start(map, entry, startaddr); \ 75945748Smckusick } 76045748Smckusick 76145748Smckusick /* 76245748Smckusick * This routine is called only when it is known that 76345748Smckusick * the entry must be split. 76445748Smckusick */ 76553357Sbostic static void _vm_map_clip_start(map, entry, start) 76645748Smckusick register vm_map_t map; 76745748Smckusick register vm_map_entry_t entry; 76845748Smckusick register vm_offset_t start; 76945748Smckusick { 77045748Smckusick register vm_map_entry_t new_entry; 77145748Smckusick 77245748Smckusick /* 77345748Smckusick * See if we can simplify this entry first 77445748Smckusick */ 77545748Smckusick 77645748Smckusick vm_map_simplify_entry(map, entry); 77745748Smckusick 77845748Smckusick /* 77945748Smckusick * Split off the front portion -- 78045748Smckusick * note that we must insert the new 78145748Smckusick * entry BEFORE this one, so that 78245748Smckusick * this entry has the specified starting 78345748Smckusick * address. 78445748Smckusick */ 78545748Smckusick 78645748Smckusick new_entry = vm_map_entry_create(map); 78745748Smckusick *new_entry = *entry; 78845748Smckusick 78945748Smckusick new_entry->end = start; 79045748Smckusick entry->offset += (start - entry->start); 79145748Smckusick entry->start = start; 79245748Smckusick 79345748Smckusick vm_map_entry_link(map, entry->prev, new_entry); 79445748Smckusick 79545748Smckusick if (entry->is_a_map || entry->is_sub_map) 79645748Smckusick vm_map_reference(new_entry->object.share_map); 79745748Smckusick else 79845748Smckusick vm_object_reference(new_entry->object.vm_object); 79945748Smckusick } 80045748Smckusick 80145748Smckusick /* 80245748Smckusick * vm_map_clip_end: [ internal use only ] 80345748Smckusick * 80445748Smckusick * Asserts that the given entry ends at or before 80545748Smckusick * the specified address; if necessary, 80645748Smckusick * it splits the entry into two. 80745748Smckusick */ 80845748Smckusick 80945748Smckusick #define vm_map_clip_end(map, entry, endaddr) \ 81045748Smckusick { \ 81145748Smckusick if (endaddr < entry->end) \ 81245748Smckusick _vm_map_clip_end(map, entry, endaddr); \ 81345748Smckusick } 81445748Smckusick 81545748Smckusick /* 81645748Smckusick * This routine is called only when it is known that 81745748Smckusick * the entry must be split. 81845748Smckusick */ 81953357Sbostic static void _vm_map_clip_end(map, entry, end) 82045748Smckusick register vm_map_t map; 82145748Smckusick register vm_map_entry_t entry; 82245748Smckusick register vm_offset_t end; 82345748Smckusick { 82445748Smckusick register vm_map_entry_t new_entry; 82545748Smckusick 82645748Smckusick /* 82745748Smckusick * Create a new entry and insert it 82845748Smckusick * AFTER the specified entry 82945748Smckusick */ 83045748Smckusick 83145748Smckusick new_entry = vm_map_entry_create(map); 83245748Smckusick *new_entry = *entry; 83345748Smckusick 83445748Smckusick new_entry->start = entry->end = end; 83545748Smckusick new_entry->offset += (end - entry->start); 83645748Smckusick 83745748Smckusick vm_map_entry_link(map, entry, new_entry); 83845748Smckusick 83945748Smckusick if (entry->is_a_map || entry->is_sub_map) 84045748Smckusick vm_map_reference(new_entry->object.share_map); 84145748Smckusick else 84245748Smckusick vm_object_reference(new_entry->object.vm_object); 84345748Smckusick } 84445748Smckusick 84545748Smckusick /* 84645748Smckusick * VM_MAP_RANGE_CHECK: [ internal use only ] 84745748Smckusick * 84845748Smckusick * Asserts that the starting and ending region 84945748Smckusick * addresses fall within the valid range of the map. 85045748Smckusick */ 85145748Smckusick #define VM_MAP_RANGE_CHECK(map, start, end) \ 85245748Smckusick { \ 85345748Smckusick if (start < vm_map_min(map)) \ 85445748Smckusick start = vm_map_min(map); \ 85545748Smckusick if (end > vm_map_max(map)) \ 85645748Smckusick end = vm_map_max(map); \ 85745748Smckusick if (start > end) \ 85845748Smckusick start = end; \ 85945748Smckusick } 86045748Smckusick 86145748Smckusick /* 86245748Smckusick * vm_map_submap: [ kernel use only ] 86345748Smckusick * 86445748Smckusick * Mark the given range as handled by a subordinate map. 86545748Smckusick * 86645748Smckusick * This range must have been created with vm_map_find, 86745748Smckusick * and no other operations may have been performed on this 86845748Smckusick * range prior to calling vm_map_submap. 86945748Smckusick * 87045748Smckusick * Only a limited number of operations can be performed 87145748Smckusick * within this rage after calling vm_map_submap: 87245748Smckusick * vm_fault 87345748Smckusick * [Don't try vm_map_copy!] 87445748Smckusick * 87545748Smckusick * To remove a submapping, one must first remove the 87645748Smckusick * range from the superior map, and then destroy the 87745748Smckusick * submap (if desired). [Better yet, don't try it.] 87845748Smckusick */ 87953357Sbostic int 88045748Smckusick vm_map_submap(map, start, end, submap) 88145748Smckusick register vm_map_t map; 88245748Smckusick register vm_offset_t start; 88345748Smckusick register vm_offset_t end; 88445748Smckusick vm_map_t submap; 88545748Smckusick { 88645748Smckusick vm_map_entry_t entry; 88745748Smckusick register int result = KERN_INVALID_ARGUMENT; 88845748Smckusick 88945748Smckusick vm_map_lock(map); 89045748Smckusick 89145748Smckusick VM_MAP_RANGE_CHECK(map, start, end); 89245748Smckusick 89345748Smckusick if (vm_map_lookup_entry(map, start, &entry)) { 89445748Smckusick vm_map_clip_start(map, entry, start); 89545748Smckusick } 89645748Smckusick else 89745748Smckusick entry = entry->next; 89845748Smckusick 89945748Smckusick vm_map_clip_end(map, entry, end); 90045748Smckusick 90145748Smckusick if ((entry->start == start) && (entry->end == end) && 90245748Smckusick (!entry->is_a_map) && 90348383Skarels (entry->object.vm_object == NULL) && 90445748Smckusick (!entry->copy_on_write)) { 90545748Smckusick entry->is_a_map = FALSE; 90645748Smckusick entry->is_sub_map = TRUE; 90745748Smckusick vm_map_reference(entry->object.sub_map = submap); 90845748Smckusick result = KERN_SUCCESS; 90945748Smckusick } 91045748Smckusick vm_map_unlock(map); 91145748Smckusick 91245748Smckusick return(result); 91345748Smckusick } 91445748Smckusick 91545748Smckusick /* 91645748Smckusick * vm_map_protect: 91745748Smckusick * 91845748Smckusick * Sets the protection of the specified address 91945748Smckusick * region in the target map. If "set_max" is 92045748Smckusick * specified, the maximum protection is to be set; 92145748Smckusick * otherwise, only the current protection is affected. 92245748Smckusick */ 92353357Sbostic int 92445748Smckusick vm_map_protect(map, start, end, new_prot, set_max) 92545748Smckusick register vm_map_t map; 92645748Smckusick register vm_offset_t start; 92745748Smckusick register vm_offset_t end; 92845748Smckusick register vm_prot_t new_prot; 92945748Smckusick register boolean_t set_max; 93045748Smckusick { 93145748Smckusick register vm_map_entry_t current; 93245748Smckusick vm_map_entry_t entry; 93345748Smckusick 93445748Smckusick vm_map_lock(map); 93545748Smckusick 93645748Smckusick VM_MAP_RANGE_CHECK(map, start, end); 93745748Smckusick 93845748Smckusick if (vm_map_lookup_entry(map, start, &entry)) { 93945748Smckusick vm_map_clip_start(map, entry, start); 94045748Smckusick } 94145748Smckusick else 94245748Smckusick entry = entry->next; 94345748Smckusick 94445748Smckusick /* 94545748Smckusick * Make a first pass to check for protection 94645748Smckusick * violations. 94745748Smckusick */ 94845748Smckusick 94945748Smckusick current = entry; 95045748Smckusick while ((current != &map->header) && (current->start < end)) { 95145748Smckusick if (current->is_sub_map) 95245748Smckusick return(KERN_INVALID_ARGUMENT); 95345748Smckusick if ((new_prot & current->max_protection) != new_prot) { 95445748Smckusick vm_map_unlock(map); 95545748Smckusick return(KERN_PROTECTION_FAILURE); 95645748Smckusick } 95745748Smckusick 95845748Smckusick current = current->next; 95945748Smckusick } 96045748Smckusick 96145748Smckusick /* 96245748Smckusick * Go back and fix up protections. 96345748Smckusick * [Note that clipping is not necessary the second time.] 96445748Smckusick */ 96545748Smckusick 96645748Smckusick current = entry; 96745748Smckusick 96845748Smckusick while ((current != &map->header) && (current->start < end)) { 96945748Smckusick vm_prot_t old_prot; 97045748Smckusick 97145748Smckusick vm_map_clip_end(map, current, end); 97245748Smckusick 97345748Smckusick old_prot = current->protection; 97445748Smckusick if (set_max) 97545748Smckusick current->protection = 97645748Smckusick (current->max_protection = new_prot) & 97745748Smckusick old_prot; 97845748Smckusick else 97945748Smckusick current->protection = new_prot; 98045748Smckusick 98145748Smckusick /* 98245748Smckusick * Update physical map if necessary. 98345748Smckusick * Worry about copy-on-write here -- CHECK THIS XXX 98445748Smckusick */ 98545748Smckusick 98645748Smckusick if (current->protection != old_prot) { 98745748Smckusick 98845748Smckusick #define MASK(entry) ((entry)->copy_on_write ? ~VM_PROT_WRITE : \ 98945748Smckusick VM_PROT_ALL) 99045748Smckusick #define max(a,b) ((a) > (b) ? (a) : (b)) 99145748Smckusick 99245748Smckusick if (current->is_a_map) { 99345748Smckusick vm_map_entry_t share_entry; 99445748Smckusick vm_offset_t share_end; 99545748Smckusick 99645748Smckusick vm_map_lock(current->object.share_map); 99745748Smckusick (void) vm_map_lookup_entry( 99845748Smckusick current->object.share_map, 99945748Smckusick current->offset, 100045748Smckusick &share_entry); 100145748Smckusick share_end = current->offset + 100245748Smckusick (current->end - current->start); 100345748Smckusick while ((share_entry != 100445748Smckusick ¤t->object.share_map->header) && 100545748Smckusick (share_entry->start < share_end)) { 100645748Smckusick 100745748Smckusick pmap_protect(map->pmap, 100845748Smckusick (max(share_entry->start, 100945748Smckusick current->offset) - 101045748Smckusick current->offset + 101145748Smckusick current->start), 101245748Smckusick min(share_entry->end, 101345748Smckusick share_end) - 101445748Smckusick current->offset + 101545748Smckusick current->start, 101645748Smckusick current->protection & 101745748Smckusick MASK(share_entry)); 101845748Smckusick 101945748Smckusick share_entry = share_entry->next; 102045748Smckusick } 102145748Smckusick vm_map_unlock(current->object.share_map); 102245748Smckusick } 102345748Smckusick else 102445748Smckusick pmap_protect(map->pmap, current->start, 102545748Smckusick current->end, 102645748Smckusick current->protection & MASK(entry)); 102745748Smckusick #undef max 102845748Smckusick #undef MASK 102945748Smckusick } 103045748Smckusick current = current->next; 103145748Smckusick } 103245748Smckusick 103345748Smckusick vm_map_unlock(map); 103445748Smckusick return(KERN_SUCCESS); 103545748Smckusick } 103645748Smckusick 103745748Smckusick /* 103845748Smckusick * vm_map_inherit: 103945748Smckusick * 104045748Smckusick * Sets the inheritance of the specified address 104145748Smckusick * range in the target map. Inheritance 104245748Smckusick * affects how the map will be shared with 104345748Smckusick * child maps at the time of vm_map_fork. 104445748Smckusick */ 104553357Sbostic int 104645748Smckusick vm_map_inherit(map, start, end, new_inheritance) 104745748Smckusick register vm_map_t map; 104845748Smckusick register vm_offset_t start; 104945748Smckusick register vm_offset_t end; 105045748Smckusick register vm_inherit_t new_inheritance; 105145748Smckusick { 105245748Smckusick register vm_map_entry_t entry; 105345748Smckusick vm_map_entry_t temp_entry; 105445748Smckusick 105545748Smckusick switch (new_inheritance) { 105645748Smckusick case VM_INHERIT_NONE: 105745748Smckusick case VM_INHERIT_COPY: 105845748Smckusick case VM_INHERIT_SHARE: 105945748Smckusick break; 106045748Smckusick default: 106145748Smckusick return(KERN_INVALID_ARGUMENT); 106245748Smckusick } 106345748Smckusick 106445748Smckusick vm_map_lock(map); 106545748Smckusick 106645748Smckusick VM_MAP_RANGE_CHECK(map, start, end); 106745748Smckusick 106845748Smckusick if (vm_map_lookup_entry(map, start, &temp_entry)) { 106945748Smckusick entry = temp_entry; 107045748Smckusick vm_map_clip_start(map, entry, start); 107145748Smckusick } 107245748Smckusick else 107345748Smckusick entry = temp_entry->next; 107445748Smckusick 107545748Smckusick while ((entry != &map->header) && (entry->start < end)) { 107645748Smckusick vm_map_clip_end(map, entry, end); 107745748Smckusick 107845748Smckusick entry->inheritance = new_inheritance; 107945748Smckusick 108045748Smckusick entry = entry->next; 108145748Smckusick } 108245748Smckusick 108345748Smckusick vm_map_unlock(map); 108445748Smckusick return(KERN_SUCCESS); 108545748Smckusick } 108645748Smckusick 108745748Smckusick /* 108845748Smckusick * vm_map_pageable: 108945748Smckusick * 109045748Smckusick * Sets the pageability of the specified address 109145748Smckusick * range in the target map. Regions specified 109245748Smckusick * as not pageable require locked-down physical 109345748Smckusick * memory and physical page maps. 109445748Smckusick * 109545748Smckusick * The map must not be locked, but a reference 109645748Smckusick * must remain to the map throughout the call. 109745748Smckusick */ 109853357Sbostic int 109945748Smckusick vm_map_pageable(map, start, end, new_pageable) 110045748Smckusick register vm_map_t map; 110145748Smckusick register vm_offset_t start; 110245748Smckusick register vm_offset_t end; 110345748Smckusick register boolean_t new_pageable; 110445748Smckusick { 110545748Smckusick register vm_map_entry_t entry; 110661005Shibler vm_map_entry_t start_entry; 110758596Shibler register vm_offset_t failed; 110858596Shibler int rv; 110945748Smckusick 111045748Smckusick vm_map_lock(map); 111145748Smckusick 111245748Smckusick VM_MAP_RANGE_CHECK(map, start, end); 111345748Smckusick 111445748Smckusick /* 111545748Smckusick * Only one pageability change may take place at one 111645748Smckusick * time, since vm_fault assumes it will be called 111745748Smckusick * only once for each wiring/unwiring. Therefore, we 111845748Smckusick * have to make sure we're actually changing the pageability 111945748Smckusick * for the entire region. We do so before making any changes. 112045748Smckusick */ 112145748Smckusick 112261005Shibler if (vm_map_lookup_entry(map, start, &start_entry) == FALSE) { 112361005Shibler vm_map_unlock(map); 112461005Shibler return(KERN_INVALID_ADDRESS); 112545748Smckusick } 112661005Shibler entry = start_entry; 112745748Smckusick 112845748Smckusick /* 112945748Smckusick * Actions are rather different for wiring and unwiring, 113045748Smckusick * so we have two separate cases. 113145748Smckusick */ 113245748Smckusick 113345748Smckusick if (new_pageable) { 113445748Smckusick 113561005Shibler vm_map_clip_start(map, entry, start); 113661005Shibler 113745748Smckusick /* 113845748Smckusick * Unwiring. First ensure that the range to be 113961005Shibler * unwired is really wired down and that there 114061005Shibler * are no holes. 114145748Smckusick */ 114245748Smckusick while ((entry != &map->header) && (entry->start < end)) { 114345748Smckusick 114461005Shibler if (entry->wired_count == 0 || 114561005Shibler (entry->end < end && 114661005Shibler (entry->next == &map->header || 114761005Shibler entry->next->start > entry->end))) { 114845748Smckusick vm_map_unlock(map); 114945748Smckusick return(KERN_INVALID_ARGUMENT); 115045748Smckusick } 115145748Smckusick entry = entry->next; 115245748Smckusick } 115345748Smckusick 115445748Smckusick /* 115545748Smckusick * Now decrement the wiring count for each region. 115645748Smckusick * If a region becomes completely unwired, 115745748Smckusick * unwire its physical pages and mappings. 115845748Smckusick */ 115945748Smckusick lock_set_recursive(&map->lock); 116045748Smckusick 116161005Shibler entry = start_entry; 116245748Smckusick while ((entry != &map->header) && (entry->start < end)) { 116345748Smckusick vm_map_clip_end(map, entry, end); 116445748Smckusick 116545748Smckusick entry->wired_count--; 116645748Smckusick if (entry->wired_count == 0) 116745748Smckusick vm_fault_unwire(map, entry->start, entry->end); 116845748Smckusick 116945748Smckusick entry = entry->next; 117045748Smckusick } 117145748Smckusick lock_clear_recursive(&map->lock); 117245748Smckusick } 117345748Smckusick 117445748Smckusick else { 117545748Smckusick /* 117645748Smckusick * Wiring. We must do this in two passes: 117745748Smckusick * 117861005Shibler * 1. Holding the write lock, we create any shadow 117961005Shibler * or zero-fill objects that need to be created. 118061005Shibler * Then we clip each map entry to the region to be 118161005Shibler * wired and increment its wiring count. We 118261005Shibler * create objects before clipping the map entries 118361005Shibler * to avoid object proliferation. 118445748Smckusick * 118545748Smckusick * 2. We downgrade to a read lock, and call 118645748Smckusick * vm_fault_wire to fault in the pages for any 118745748Smckusick * newly wired area (wired_count is 1). 118845748Smckusick * 118945748Smckusick * Downgrading to a read lock for vm_fault_wire avoids 119045748Smckusick * a possible deadlock with another thread that may have 119145748Smckusick * faulted on one of the pages to be wired (it would mark 119245748Smckusick * the page busy, blocking us, then in turn block on the 119345748Smckusick * map lock that we hold). Because of problems in the 119445748Smckusick * recursive lock package, we cannot upgrade to a write 119545748Smckusick * lock in vm_map_lookup. Thus, any actions that require 119645748Smckusick * the write lock must be done beforehand. Because we 119745748Smckusick * keep the read lock on the map, the copy-on-write status 119845748Smckusick * of the entries we modify here cannot change. 119945748Smckusick */ 120045748Smckusick 120145748Smckusick /* 120245748Smckusick * Pass 1. 120345748Smckusick */ 120445748Smckusick while ((entry != &map->header) && (entry->start < end)) { 120561005Shibler if (entry->wired_count == 0) { 120645748Smckusick 120745748Smckusick /* 120845748Smckusick * Perform actions of vm_map_lookup that need 120945748Smckusick * the write lock on the map: create a shadow 121045748Smckusick * object for a copy-on-write region, or an 121145748Smckusick * object for a zero-fill region. 121245748Smckusick * 121345748Smckusick * We don't have to do this for entries that 121445748Smckusick * point to sharing maps, because we won't hold 121545748Smckusick * the lock on the sharing map. 121645748Smckusick */ 121745748Smckusick if (!entry->is_a_map) { 121845748Smckusick if (entry->needs_copy && 121945748Smckusick ((entry->protection & VM_PROT_WRITE) != 0)) { 122045748Smckusick 122145748Smckusick vm_object_shadow(&entry->object.vm_object, 122245748Smckusick &entry->offset, 122345748Smckusick (vm_size_t)(entry->end 122445748Smckusick - entry->start)); 122545748Smckusick entry->needs_copy = FALSE; 122645748Smckusick } 122748383Skarels else if (entry->object.vm_object == NULL) { 122845748Smckusick entry->object.vm_object = 122945748Smckusick vm_object_allocate((vm_size_t)(entry->end 123045748Smckusick - entry->start)); 123145748Smckusick entry->offset = (vm_offset_t)0; 123245748Smckusick } 123345748Smckusick } 123445748Smckusick } 123561005Shibler vm_map_clip_start(map, entry, start); 123661005Shibler vm_map_clip_end(map, entry, end); 123761005Shibler entry->wired_count++; 123845748Smckusick 123961005Shibler /* 124061005Shibler * Check for holes 124161005Shibler */ 124261005Shibler if (entry->end < end && 124361005Shibler (entry->next == &map->header || 124461005Shibler entry->next->start > entry->end)) { 124561005Shibler /* 124661005Shibler * Found one. Object creation actions 124761005Shibler * do not need to be undone, but the 124861005Shibler * wired counts need to be restored. 124961005Shibler */ 125061005Shibler while (entry != &map->header && entry->end > start) { 125161005Shibler entry->wired_count--; 125261005Shibler entry = entry->prev; 125361005Shibler } 125461005Shibler vm_map_unlock(map); 125561005Shibler return(KERN_INVALID_ARGUMENT); 125661005Shibler } 125745748Smckusick entry = entry->next; 125845748Smckusick } 125945748Smckusick 126045748Smckusick /* 126145748Smckusick * Pass 2. 126245748Smckusick */ 126345748Smckusick 126445748Smckusick /* 126545748Smckusick * HACK HACK HACK HACK 126645748Smckusick * 126745748Smckusick * If we are wiring in the kernel map or a submap of it, 126845748Smckusick * unlock the map to avoid deadlocks. We trust that the 126945748Smckusick * kernel threads are well-behaved, and therefore will 127045748Smckusick * not do anything destructive to this region of the map 127145748Smckusick * while we have it unlocked. We cannot trust user threads 127245748Smckusick * to do the same. 127345748Smckusick * 127445748Smckusick * HACK HACK HACK HACK 127545748Smckusick */ 127645748Smckusick if (vm_map_pmap(map) == kernel_pmap) { 127745748Smckusick vm_map_unlock(map); /* trust me ... */ 127845748Smckusick } 127945748Smckusick else { 128045748Smckusick lock_set_recursive(&map->lock); 128145748Smckusick lock_write_to_read(&map->lock); 128245748Smckusick } 128345748Smckusick 128458596Shibler rv = 0; 128561005Shibler entry = start_entry; 128645748Smckusick while (entry != &map->header && entry->start < end) { 128758596Shibler /* 128858596Shibler * If vm_fault_wire fails for any page we need to 128958596Shibler * undo what has been done. We decrement the wiring 129058596Shibler * count for those pages which have not yet been 129158596Shibler * wired (now) and unwire those that have (later). 129258596Shibler * 129358596Shibler * XXX this violates the locking protocol on the map, 129458596Shibler * needs to be fixed. 129558596Shibler */ 129658596Shibler if (rv) 129758596Shibler entry->wired_count--; 129858596Shibler else if (entry->wired_count == 1) { 129958596Shibler rv = vm_fault_wire(map, entry->start, entry->end); 130058596Shibler if (rv) { 130158596Shibler failed = entry->start; 130258596Shibler entry->wired_count--; 130358596Shibler } 130445748Smckusick } 130545748Smckusick entry = entry->next; 130645748Smckusick } 130745748Smckusick 130845748Smckusick if (vm_map_pmap(map) == kernel_pmap) { 130945748Smckusick vm_map_lock(map); 131045748Smckusick } 131145748Smckusick else { 131245748Smckusick lock_clear_recursive(&map->lock); 131345748Smckusick } 131458596Shibler if (rv) { 131558596Shibler vm_map_unlock(map); 131658596Shibler (void) vm_map_pageable(map, start, failed, TRUE); 131758596Shibler return(rv); 131858596Shibler } 131945748Smckusick } 132045748Smckusick 132145748Smckusick vm_map_unlock(map); 132245748Smckusick 132345748Smckusick return(KERN_SUCCESS); 132445748Smckusick } 132545748Smckusick 132645748Smckusick /* 1327*65686Shibler * vm_map_clean 1328*65686Shibler * 1329*65686Shibler * Push any dirty cached pages in the address range to their pager. 1330*65686Shibler * If syncio is TRUE, dirty pages are written synchronously. 1331*65686Shibler * If invalidate is TRUE, any cached pages are freed as well. 1332*65686Shibler * 1333*65686Shibler * Returns an error if any part of the specified range is not mapped. 1334*65686Shibler */ 1335*65686Shibler int 1336*65686Shibler vm_map_clean(map, start, end, syncio, invalidate) 1337*65686Shibler vm_map_t map; 1338*65686Shibler vm_offset_t start; 1339*65686Shibler vm_offset_t end; 1340*65686Shibler boolean_t syncio; 1341*65686Shibler boolean_t invalidate; 1342*65686Shibler { 1343*65686Shibler register vm_map_entry_t current; 1344*65686Shibler vm_map_entry_t entry; 1345*65686Shibler vm_size_t size; 1346*65686Shibler vm_object_t object; 1347*65686Shibler vm_offset_t offset; 1348*65686Shibler 1349*65686Shibler vm_map_lock_read(map); 1350*65686Shibler VM_MAP_RANGE_CHECK(map, start, end); 1351*65686Shibler if (!vm_map_lookup_entry(map, start, &entry)) { 1352*65686Shibler vm_map_unlock_read(map); 1353*65686Shibler return(KERN_INVALID_ADDRESS); 1354*65686Shibler } 1355*65686Shibler 1356*65686Shibler /* 1357*65686Shibler * Make a first pass to check for holes. 1358*65686Shibler */ 1359*65686Shibler for (current = entry; current->start < end; current = current->next) { 1360*65686Shibler if (current->is_sub_map) { 1361*65686Shibler vm_map_unlock_read(map); 1362*65686Shibler return(KERN_INVALID_ARGUMENT); 1363*65686Shibler } 1364*65686Shibler if (end > current->end && 1365*65686Shibler (current->next == &map->header || 1366*65686Shibler current->end != current->next->start)) { 1367*65686Shibler vm_map_unlock_read(map); 1368*65686Shibler return(KERN_INVALID_ADDRESS); 1369*65686Shibler } 1370*65686Shibler } 1371*65686Shibler 1372*65686Shibler /* 1373*65686Shibler * Make a second pass, cleaning/uncaching pages from the indicated 1374*65686Shibler * objects as we go. 1375*65686Shibler */ 1376*65686Shibler for (current = entry; current->start < end; current = current->next) { 1377*65686Shibler offset = current->offset + (start - current->start); 1378*65686Shibler size = (end <= current->end ? end : current->end) - start; 1379*65686Shibler if (current->is_a_map) { 1380*65686Shibler register vm_map_t smap; 1381*65686Shibler vm_map_entry_t tentry; 1382*65686Shibler vm_size_t tsize; 1383*65686Shibler 1384*65686Shibler smap = current->object.share_map; 1385*65686Shibler vm_map_lock_read(smap); 1386*65686Shibler (void) vm_map_lookup_entry(smap, offset, &tentry); 1387*65686Shibler tsize = tentry->end - offset; 1388*65686Shibler if (tsize < size) 1389*65686Shibler size = tsize; 1390*65686Shibler object = tentry->object.vm_object; 1391*65686Shibler offset = tentry->offset + (offset - tentry->start); 1392*65686Shibler vm_object_lock(object); 1393*65686Shibler vm_map_unlock_read(smap); 1394*65686Shibler } else { 1395*65686Shibler object = current->object.vm_object; 1396*65686Shibler vm_object_lock(object); 1397*65686Shibler } 1398*65686Shibler /* 1399*65686Shibler * Flush pages if writing is allowed. 1400*65686Shibler * XXX should we continue on an error? 1401*65686Shibler */ 1402*65686Shibler if ((current->protection & VM_PROT_WRITE) && 1403*65686Shibler !vm_object_page_clean(object, offset, offset+size, 1404*65686Shibler syncio, FALSE)) { 1405*65686Shibler vm_object_unlock(object); 1406*65686Shibler vm_map_unlock_read(map); 1407*65686Shibler return(KERN_FAILURE); 1408*65686Shibler } 1409*65686Shibler if (invalidate) 1410*65686Shibler vm_object_page_remove(object, offset, offset+size); 1411*65686Shibler vm_object_unlock(object); 1412*65686Shibler start += size; 1413*65686Shibler } 1414*65686Shibler 1415*65686Shibler vm_map_unlock_read(map); 1416*65686Shibler return(KERN_SUCCESS); 1417*65686Shibler } 1418*65686Shibler 1419*65686Shibler /* 142045748Smckusick * vm_map_entry_unwire: [ internal use only ] 142145748Smckusick * 142245748Smckusick * Make the region specified by this entry pageable. 142345748Smckusick * 142445748Smckusick * The map in question should be locked. 142545748Smckusick * [This is the reason for this routine's existence.] 142645748Smckusick */ 142745748Smckusick void vm_map_entry_unwire(map, entry) 142845748Smckusick vm_map_t map; 142945748Smckusick register vm_map_entry_t entry; 143045748Smckusick { 143145748Smckusick vm_fault_unwire(map, entry->start, entry->end); 143245748Smckusick entry->wired_count = 0; 143345748Smckusick } 143445748Smckusick 143545748Smckusick /* 143645748Smckusick * vm_map_entry_delete: [ internal use only ] 143745748Smckusick * 143845748Smckusick * Deallocate the given entry from the target map. 143945748Smckusick */ 144045748Smckusick void vm_map_entry_delete(map, entry) 144145748Smckusick register vm_map_t map; 144245748Smckusick register vm_map_entry_t entry; 144345748Smckusick { 144445748Smckusick if (entry->wired_count != 0) 144545748Smckusick vm_map_entry_unwire(map, entry); 144645748Smckusick 144745748Smckusick vm_map_entry_unlink(map, entry); 144845748Smckusick map->size -= entry->end - entry->start; 144945748Smckusick 145045748Smckusick if (entry->is_a_map || entry->is_sub_map) 145145748Smckusick vm_map_deallocate(entry->object.share_map); 145245748Smckusick else 145345748Smckusick vm_object_deallocate(entry->object.vm_object); 145445748Smckusick 145545748Smckusick vm_map_entry_dispose(map, entry); 145645748Smckusick } 145745748Smckusick 145845748Smckusick /* 145945748Smckusick * vm_map_delete: [ internal use only ] 146045748Smckusick * 146145748Smckusick * Deallocates the given address range from the target 146245748Smckusick * map. 146345748Smckusick * 146445748Smckusick * When called with a sharing map, removes pages from 146545748Smckusick * that region from all physical maps. 146645748Smckusick */ 146753357Sbostic int 146845748Smckusick vm_map_delete(map, start, end) 146945748Smckusick register vm_map_t map; 147045748Smckusick vm_offset_t start; 147145748Smckusick register vm_offset_t end; 147245748Smckusick { 147345748Smckusick register vm_map_entry_t entry; 147445748Smckusick vm_map_entry_t first_entry; 147545748Smckusick 147645748Smckusick /* 147745748Smckusick * Find the start of the region, and clip it 147845748Smckusick */ 147945748Smckusick 148045748Smckusick if (!vm_map_lookup_entry(map, start, &first_entry)) 148145748Smckusick entry = first_entry->next; 148245748Smckusick else { 148345748Smckusick entry = first_entry; 148445748Smckusick vm_map_clip_start(map, entry, start); 148545748Smckusick 148645748Smckusick /* 148745748Smckusick * Fix the lookup hint now, rather than each 148845748Smckusick * time though the loop. 148945748Smckusick */ 149045748Smckusick 149145748Smckusick SAVE_HINT(map, entry->prev); 149245748Smckusick } 149345748Smckusick 149445748Smckusick /* 149545748Smckusick * Save the free space hint 149645748Smckusick */ 149745748Smckusick 149845748Smckusick if (map->first_free->start >= start) 149945748Smckusick map->first_free = entry->prev; 150045748Smckusick 150145748Smckusick /* 150245748Smckusick * Step through all entries in this region 150345748Smckusick */ 150445748Smckusick 150545748Smckusick while ((entry != &map->header) && (entry->start < end)) { 150645748Smckusick vm_map_entry_t next; 150745748Smckusick register vm_offset_t s, e; 150845748Smckusick register vm_object_t object; 150945748Smckusick 151045748Smckusick vm_map_clip_end(map, entry, end); 151145748Smckusick 151245748Smckusick next = entry->next; 151345748Smckusick s = entry->start; 151445748Smckusick e = entry->end; 151545748Smckusick 151645748Smckusick /* 151745748Smckusick * Unwire before removing addresses from the pmap; 151845748Smckusick * otherwise, unwiring will put the entries back in 151945748Smckusick * the pmap. 152045748Smckusick */ 152145748Smckusick 152245748Smckusick object = entry->object.vm_object; 152345748Smckusick if (entry->wired_count != 0) 152445748Smckusick vm_map_entry_unwire(map, entry); 152545748Smckusick 152645748Smckusick /* 152745748Smckusick * If this is a sharing map, we must remove 152845748Smckusick * *all* references to this data, since we can't 152945748Smckusick * find all of the physical maps which are sharing 153045748Smckusick * it. 153145748Smckusick */ 153245748Smckusick 153345748Smckusick if (object == kernel_object || object == kmem_object) 153445748Smckusick vm_object_page_remove(object, entry->offset, 153545748Smckusick entry->offset + (e - s)); 153645748Smckusick else if (!map->is_main_map) 153745748Smckusick vm_object_pmap_remove(object, 153845748Smckusick entry->offset, 153945748Smckusick entry->offset + (e - s)); 154045748Smckusick else 154145748Smckusick pmap_remove(map->pmap, s, e); 154245748Smckusick 154345748Smckusick /* 154445748Smckusick * Delete the entry (which may delete the object) 154545748Smckusick * only after removing all pmap entries pointing 154645748Smckusick * to its pages. (Otherwise, its page frames may 154745748Smckusick * be reallocated, and any modify bits will be 154845748Smckusick * set in the wrong object!) 154945748Smckusick */ 155045748Smckusick 155145748Smckusick vm_map_entry_delete(map, entry); 155245748Smckusick entry = next; 155345748Smckusick } 155445748Smckusick return(KERN_SUCCESS); 155545748Smckusick } 155645748Smckusick 155745748Smckusick /* 155845748Smckusick * vm_map_remove: 155945748Smckusick * 156045748Smckusick * Remove the given address range from the target map. 156145748Smckusick * This is the exported form of vm_map_delete. 156245748Smckusick */ 156353357Sbostic int 156445748Smckusick vm_map_remove(map, start, end) 156545748Smckusick register vm_map_t map; 156645748Smckusick register vm_offset_t start; 156745748Smckusick register vm_offset_t end; 156845748Smckusick { 156945748Smckusick register int result; 157045748Smckusick 157145748Smckusick vm_map_lock(map); 157245748Smckusick VM_MAP_RANGE_CHECK(map, start, end); 157345748Smckusick result = vm_map_delete(map, start, end); 157445748Smckusick vm_map_unlock(map); 157545748Smckusick 157645748Smckusick return(result); 157745748Smckusick } 157845748Smckusick 157945748Smckusick /* 158045748Smckusick * vm_map_check_protection: 158145748Smckusick * 158245748Smckusick * Assert that the target map allows the specified 158345748Smckusick * privilege on the entire address region given. 158445748Smckusick * The entire region must be allocated. 158545748Smckusick */ 158645748Smckusick boolean_t vm_map_check_protection(map, start, end, protection) 158745748Smckusick register vm_map_t map; 158845748Smckusick register vm_offset_t start; 158945748Smckusick register vm_offset_t end; 159045748Smckusick register vm_prot_t protection; 159145748Smckusick { 159245748Smckusick register vm_map_entry_t entry; 159345748Smckusick vm_map_entry_t tmp_entry; 159445748Smckusick 159545748Smckusick if (!vm_map_lookup_entry(map, start, &tmp_entry)) { 159645748Smckusick return(FALSE); 159745748Smckusick } 159845748Smckusick 159945748Smckusick entry = tmp_entry; 160045748Smckusick 160145748Smckusick while (start < end) { 160245748Smckusick if (entry == &map->header) { 160345748Smckusick return(FALSE); 160445748Smckusick } 160545748Smckusick 160645748Smckusick /* 160745748Smckusick * No holes allowed! 160845748Smckusick */ 160945748Smckusick 161045748Smckusick if (start < entry->start) { 161145748Smckusick return(FALSE); 161245748Smckusick } 161345748Smckusick 161445748Smckusick /* 161545748Smckusick * Check protection associated with entry. 161645748Smckusick */ 161745748Smckusick 161845748Smckusick if ((entry->protection & protection) != protection) { 161945748Smckusick return(FALSE); 162045748Smckusick } 162145748Smckusick 162245748Smckusick /* go to next entry */ 162345748Smckusick 162445748Smckusick start = entry->end; 162545748Smckusick entry = entry->next; 162645748Smckusick } 162745748Smckusick return(TRUE); 162845748Smckusick } 162945748Smckusick 163045748Smckusick /* 163145748Smckusick * vm_map_copy_entry: 163245748Smckusick * 163345748Smckusick * Copies the contents of the source entry to the destination 163445748Smckusick * entry. The entries *must* be aligned properly. 163545748Smckusick */ 163645748Smckusick void vm_map_copy_entry(src_map, dst_map, src_entry, dst_entry) 163745748Smckusick vm_map_t src_map, dst_map; 163845748Smckusick register vm_map_entry_t src_entry, dst_entry; 163945748Smckusick { 164045748Smckusick vm_object_t temp_object; 164145748Smckusick 164245748Smckusick if (src_entry->is_sub_map || dst_entry->is_sub_map) 164345748Smckusick return; 164445748Smckusick 164548383Skarels if (dst_entry->object.vm_object != NULL && 164650919Smckusick (dst_entry->object.vm_object->flags & OBJ_INTERNAL) == 0) 164745748Smckusick printf("vm_map_copy_entry: copying over permanent data!\n"); 164845748Smckusick 164945748Smckusick /* 165045748Smckusick * If our destination map was wired down, 165145748Smckusick * unwire it now. 165245748Smckusick */ 165345748Smckusick 165445748Smckusick if (dst_entry->wired_count != 0) 165545748Smckusick vm_map_entry_unwire(dst_map, dst_entry); 165645748Smckusick 165745748Smckusick /* 165845748Smckusick * If we're dealing with a sharing map, we 165945748Smckusick * must remove the destination pages from 166045748Smckusick * all maps (since we cannot know which maps 166145748Smckusick * this sharing map belongs in). 166245748Smckusick */ 166345748Smckusick 166445748Smckusick if (dst_map->is_main_map) 166545748Smckusick pmap_remove(dst_map->pmap, dst_entry->start, dst_entry->end); 166645748Smckusick else 166745748Smckusick vm_object_pmap_remove(dst_entry->object.vm_object, 166845748Smckusick dst_entry->offset, 166945748Smckusick dst_entry->offset + 167045748Smckusick (dst_entry->end - dst_entry->start)); 167145748Smckusick 167245748Smckusick if (src_entry->wired_count == 0) { 167345748Smckusick 167445748Smckusick boolean_t src_needs_copy; 167545748Smckusick 167645748Smckusick /* 167745748Smckusick * If the source entry is marked needs_copy, 167845748Smckusick * it is already write-protected. 167945748Smckusick */ 168045748Smckusick if (!src_entry->needs_copy) { 168145748Smckusick 168245748Smckusick boolean_t su; 168345748Smckusick 168445748Smckusick /* 168545748Smckusick * If the source entry has only one mapping, 168645748Smckusick * we can just protect the virtual address 168745748Smckusick * range. 168845748Smckusick */ 168945748Smckusick if (!(su = src_map->is_main_map)) { 169045748Smckusick simple_lock(&src_map->ref_lock); 169145748Smckusick su = (src_map->ref_count == 1); 169245748Smckusick simple_unlock(&src_map->ref_lock); 169345748Smckusick } 169445748Smckusick 169545748Smckusick if (su) { 169645748Smckusick pmap_protect(src_map->pmap, 169745748Smckusick src_entry->start, 169845748Smckusick src_entry->end, 169945748Smckusick src_entry->protection & ~VM_PROT_WRITE); 170045748Smckusick } 170145748Smckusick else { 170245748Smckusick vm_object_pmap_copy(src_entry->object.vm_object, 170345748Smckusick src_entry->offset, 170445748Smckusick src_entry->offset + (src_entry->end 170545748Smckusick -src_entry->start)); 170645748Smckusick } 170745748Smckusick } 170845748Smckusick 170945748Smckusick /* 171045748Smckusick * Make a copy of the object. 171145748Smckusick */ 171245748Smckusick temp_object = dst_entry->object.vm_object; 171345748Smckusick vm_object_copy(src_entry->object.vm_object, 171445748Smckusick src_entry->offset, 171545748Smckusick (vm_size_t)(src_entry->end - 171645748Smckusick src_entry->start), 171745748Smckusick &dst_entry->object.vm_object, 171845748Smckusick &dst_entry->offset, 171945748Smckusick &src_needs_copy); 172045748Smckusick /* 172145748Smckusick * If we didn't get a copy-object now, mark the 172245748Smckusick * source map entry so that a shadow will be created 172345748Smckusick * to hold its changed pages. 172445748Smckusick */ 172545748Smckusick if (src_needs_copy) 172645748Smckusick src_entry->needs_copy = TRUE; 172745748Smckusick 172845748Smckusick /* 172945748Smckusick * The destination always needs to have a shadow 173045748Smckusick * created. 173145748Smckusick */ 173245748Smckusick dst_entry->needs_copy = TRUE; 173345748Smckusick 173445748Smckusick /* 173545748Smckusick * Mark the entries copy-on-write, so that write-enabling 173645748Smckusick * the entry won't make copy-on-write pages writable. 173745748Smckusick */ 173845748Smckusick src_entry->copy_on_write = TRUE; 173945748Smckusick dst_entry->copy_on_write = TRUE; 174045748Smckusick /* 174145748Smckusick * Get rid of the old object. 174245748Smckusick */ 174345748Smckusick vm_object_deallocate(temp_object); 174445748Smckusick 174545748Smckusick pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start, 174645748Smckusick dst_entry->end - dst_entry->start, src_entry->start); 174745748Smckusick } 174845748Smckusick else { 174945748Smckusick /* 175045748Smckusick * Of course, wired down pages can't be set copy-on-write. 175145748Smckusick * Cause wired pages to be copied into the new 175245748Smckusick * map by simulating faults (the new pages are 175345748Smckusick * pageable) 175445748Smckusick */ 175545748Smckusick vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry); 175645748Smckusick } 175745748Smckusick } 175845748Smckusick 175945748Smckusick /* 176045748Smckusick * vm_map_copy: 176145748Smckusick * 176245748Smckusick * Perform a virtual memory copy from the source 176345748Smckusick * address map/range to the destination map/range. 176445748Smckusick * 176545748Smckusick * If src_destroy or dst_alloc is requested, 176645748Smckusick * the source and destination regions should be 176745748Smckusick * disjoint, not only in the top-level map, but 176845748Smckusick * in the sharing maps as well. [The best way 176945748Smckusick * to guarantee this is to use a new intermediate 177045748Smckusick * map to make copies. This also reduces map 177145748Smckusick * fragmentation.] 177245748Smckusick */ 177353357Sbostic int 177445748Smckusick vm_map_copy(dst_map, src_map, 177545748Smckusick dst_addr, len, src_addr, 177645748Smckusick dst_alloc, src_destroy) 177745748Smckusick vm_map_t dst_map; 177845748Smckusick vm_map_t src_map; 177945748Smckusick vm_offset_t dst_addr; 178045748Smckusick vm_size_t len; 178145748Smckusick vm_offset_t src_addr; 178245748Smckusick boolean_t dst_alloc; 178345748Smckusick boolean_t src_destroy; 178445748Smckusick { 178545748Smckusick register 178645748Smckusick vm_map_entry_t src_entry; 178745748Smckusick register 178845748Smckusick vm_map_entry_t dst_entry; 178945748Smckusick vm_map_entry_t tmp_entry; 179045748Smckusick vm_offset_t src_start; 179145748Smckusick vm_offset_t src_end; 179245748Smckusick vm_offset_t dst_start; 179345748Smckusick vm_offset_t dst_end; 179445748Smckusick vm_offset_t src_clip; 179545748Smckusick vm_offset_t dst_clip; 179645748Smckusick int result; 179745748Smckusick boolean_t old_src_destroy; 179845748Smckusick 179945748Smckusick /* 180045748Smckusick * XXX While we figure out why src_destroy screws up, 180145748Smckusick * we'll do it by explicitly vm_map_delete'ing at the end. 180245748Smckusick */ 180345748Smckusick 180445748Smckusick old_src_destroy = src_destroy; 180545748Smckusick src_destroy = FALSE; 180645748Smckusick 180745748Smckusick /* 180845748Smckusick * Compute start and end of region in both maps 180945748Smckusick */ 181045748Smckusick 181145748Smckusick src_start = src_addr; 181245748Smckusick src_end = src_start + len; 181345748Smckusick dst_start = dst_addr; 181445748Smckusick dst_end = dst_start + len; 181545748Smckusick 181645748Smckusick /* 181745748Smckusick * Check that the region can exist in both source 181845748Smckusick * and destination. 181945748Smckusick */ 182045748Smckusick 182145748Smckusick if ((dst_end < dst_start) || (src_end < src_start)) 182245748Smckusick return(KERN_NO_SPACE); 182345748Smckusick 182445748Smckusick /* 182545748Smckusick * Lock the maps in question -- we avoid deadlock 182645748Smckusick * by ordering lock acquisition by map value 182745748Smckusick */ 182845748Smckusick 182945748Smckusick if (src_map == dst_map) { 183045748Smckusick vm_map_lock(src_map); 183145748Smckusick } 183245748Smckusick else if ((int) src_map < (int) dst_map) { 183345748Smckusick vm_map_lock(src_map); 183445748Smckusick vm_map_lock(dst_map); 183545748Smckusick } else { 183645748Smckusick vm_map_lock(dst_map); 183745748Smckusick vm_map_lock(src_map); 183845748Smckusick } 183945748Smckusick 184045748Smckusick result = KERN_SUCCESS; 184145748Smckusick 184245748Smckusick /* 184345748Smckusick * Check protections... source must be completely readable and 184445748Smckusick * destination must be completely writable. [Note that if we're 184545748Smckusick * allocating the destination region, we don't have to worry 184645748Smckusick * about protection, but instead about whether the region 184745748Smckusick * exists.] 184845748Smckusick */ 184945748Smckusick 185045748Smckusick if (src_map->is_main_map && dst_map->is_main_map) { 185145748Smckusick if (!vm_map_check_protection(src_map, src_start, src_end, 185245748Smckusick VM_PROT_READ)) { 185345748Smckusick result = KERN_PROTECTION_FAILURE; 185445748Smckusick goto Return; 185545748Smckusick } 185645748Smckusick 185745748Smckusick if (dst_alloc) { 185845748Smckusick /* XXX Consider making this a vm_map_find instead */ 185948383Skarels if ((result = vm_map_insert(dst_map, NULL, 186045748Smckusick (vm_offset_t) 0, dst_start, dst_end)) != KERN_SUCCESS) 186145748Smckusick goto Return; 186245748Smckusick } 186345748Smckusick else if (!vm_map_check_protection(dst_map, dst_start, dst_end, 186445748Smckusick VM_PROT_WRITE)) { 186545748Smckusick result = KERN_PROTECTION_FAILURE; 186645748Smckusick goto Return; 186745748Smckusick } 186845748Smckusick } 186945748Smckusick 187045748Smckusick /* 187145748Smckusick * Find the start entries and clip. 187245748Smckusick * 187345748Smckusick * Note that checking protection asserts that the 187445748Smckusick * lookup cannot fail. 187545748Smckusick * 187645748Smckusick * Also note that we wait to do the second lookup 187745748Smckusick * until we have done the first clip, as the clip 187845748Smckusick * may affect which entry we get! 187945748Smckusick */ 188045748Smckusick 188145748Smckusick (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); 188245748Smckusick src_entry = tmp_entry; 188345748Smckusick vm_map_clip_start(src_map, src_entry, src_start); 188445748Smckusick 188545748Smckusick (void) vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry); 188645748Smckusick dst_entry = tmp_entry; 188745748Smckusick vm_map_clip_start(dst_map, dst_entry, dst_start); 188845748Smckusick 188945748Smckusick /* 189045748Smckusick * If both source and destination entries are the same, 189145748Smckusick * retry the first lookup, as it may have changed. 189245748Smckusick */ 189345748Smckusick 189445748Smckusick if (src_entry == dst_entry) { 189545748Smckusick (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry); 189645748Smckusick src_entry = tmp_entry; 189745748Smckusick } 189845748Smckusick 189945748Smckusick /* 190045748Smckusick * If source and destination entries are still the same, 190145748Smckusick * a null copy is being performed. 190245748Smckusick */ 190345748Smckusick 190445748Smckusick if (src_entry == dst_entry) 190545748Smckusick goto Return; 190645748Smckusick 190745748Smckusick /* 190845748Smckusick * Go through entries until we get to the end of the 190945748Smckusick * region. 191045748Smckusick */ 191145748Smckusick 191245748Smckusick while (src_start < src_end) { 191345748Smckusick /* 191445748Smckusick * Clip the entries to the endpoint of the entire region. 191545748Smckusick */ 191645748Smckusick 191745748Smckusick vm_map_clip_end(src_map, src_entry, src_end); 191845748Smckusick vm_map_clip_end(dst_map, dst_entry, dst_end); 191945748Smckusick 192045748Smckusick /* 192145748Smckusick * Clip each entry to the endpoint of the other entry. 192245748Smckusick */ 192345748Smckusick 192445748Smckusick src_clip = src_entry->start + (dst_entry->end - dst_entry->start); 192545748Smckusick vm_map_clip_end(src_map, src_entry, src_clip); 192645748Smckusick 192745748Smckusick dst_clip = dst_entry->start + (src_entry->end - src_entry->start); 192845748Smckusick vm_map_clip_end(dst_map, dst_entry, dst_clip); 192945748Smckusick 193045748Smckusick /* 193145748Smckusick * Both entries now match in size and relative endpoints. 193245748Smckusick * 193345748Smckusick * If both entries refer to a VM object, we can 193445748Smckusick * deal with them now. 193545748Smckusick */ 193645748Smckusick 193745748Smckusick if (!src_entry->is_a_map && !dst_entry->is_a_map) { 193845748Smckusick vm_map_copy_entry(src_map, dst_map, src_entry, 193945748Smckusick dst_entry); 194045748Smckusick } 194145748Smckusick else { 194245748Smckusick register vm_map_t new_dst_map; 194345748Smckusick vm_offset_t new_dst_start; 194445748Smckusick vm_size_t new_size; 194545748Smckusick vm_map_t new_src_map; 194645748Smckusick vm_offset_t new_src_start; 194745748Smckusick 194845748Smckusick /* 194945748Smckusick * We have to follow at least one sharing map. 195045748Smckusick */ 195145748Smckusick 195245748Smckusick new_size = (dst_entry->end - dst_entry->start); 195345748Smckusick 195445748Smckusick if (src_entry->is_a_map) { 195545748Smckusick new_src_map = src_entry->object.share_map; 195645748Smckusick new_src_start = src_entry->offset; 195745748Smckusick } 195845748Smckusick else { 195945748Smckusick new_src_map = src_map; 196045748Smckusick new_src_start = src_entry->start; 196145748Smckusick lock_set_recursive(&src_map->lock); 196245748Smckusick } 196345748Smckusick 196445748Smckusick if (dst_entry->is_a_map) { 196545748Smckusick vm_offset_t new_dst_end; 196645748Smckusick 196745748Smckusick new_dst_map = dst_entry->object.share_map; 196845748Smckusick new_dst_start = dst_entry->offset; 196945748Smckusick 197045748Smckusick /* 197145748Smckusick * Since the destination sharing entries 197245748Smckusick * will be merely deallocated, we can 197345748Smckusick * do that now, and replace the region 197445748Smckusick * with a null object. [This prevents 197545748Smckusick * splitting the source map to match 197645748Smckusick * the form of the destination map.] 197745748Smckusick * Note that we can only do so if the 197845748Smckusick * source and destination do not overlap. 197945748Smckusick */ 198045748Smckusick 198145748Smckusick new_dst_end = new_dst_start + new_size; 198245748Smckusick 198345748Smckusick if (new_dst_map != new_src_map) { 198445748Smckusick vm_map_lock(new_dst_map); 198545748Smckusick (void) vm_map_delete(new_dst_map, 198645748Smckusick new_dst_start, 198745748Smckusick new_dst_end); 198845748Smckusick (void) vm_map_insert(new_dst_map, 198948383Skarels NULL, 199045748Smckusick (vm_offset_t) 0, 199145748Smckusick new_dst_start, 199245748Smckusick new_dst_end); 199345748Smckusick vm_map_unlock(new_dst_map); 199445748Smckusick } 199545748Smckusick } 199645748Smckusick else { 199745748Smckusick new_dst_map = dst_map; 199845748Smckusick new_dst_start = dst_entry->start; 199945748Smckusick lock_set_recursive(&dst_map->lock); 200045748Smckusick } 200145748Smckusick 200245748Smckusick /* 200345748Smckusick * Recursively copy the sharing map. 200445748Smckusick */ 200545748Smckusick 200645748Smckusick (void) vm_map_copy(new_dst_map, new_src_map, 200745748Smckusick new_dst_start, new_size, new_src_start, 200845748Smckusick FALSE, FALSE); 200945748Smckusick 201045748Smckusick if (dst_map == new_dst_map) 201145748Smckusick lock_clear_recursive(&dst_map->lock); 201245748Smckusick if (src_map == new_src_map) 201345748Smckusick lock_clear_recursive(&src_map->lock); 201445748Smckusick } 201545748Smckusick 201645748Smckusick /* 201745748Smckusick * Update variables for next pass through the loop. 201845748Smckusick */ 201945748Smckusick 202045748Smckusick src_start = src_entry->end; 202145748Smckusick src_entry = src_entry->next; 202245748Smckusick dst_start = dst_entry->end; 202345748Smckusick dst_entry = dst_entry->next; 202445748Smckusick 202545748Smckusick /* 202645748Smckusick * If the source is to be destroyed, here is the 202745748Smckusick * place to do it. 202845748Smckusick */ 202945748Smckusick 203045748Smckusick if (src_destroy && src_map->is_main_map && 203145748Smckusick dst_map->is_main_map) 203245748Smckusick vm_map_entry_delete(src_map, src_entry->prev); 203345748Smckusick } 203445748Smckusick 203545748Smckusick /* 203645748Smckusick * Update the physical maps as appropriate 203745748Smckusick */ 203845748Smckusick 203945748Smckusick if (src_map->is_main_map && dst_map->is_main_map) { 204045748Smckusick if (src_destroy) 204145748Smckusick pmap_remove(src_map->pmap, src_addr, src_addr + len); 204245748Smckusick } 204345748Smckusick 204445748Smckusick /* 204545748Smckusick * Unlock the maps 204645748Smckusick */ 204745748Smckusick 204845748Smckusick Return: ; 204945748Smckusick 205045748Smckusick if (old_src_destroy) 205145748Smckusick vm_map_delete(src_map, src_addr, src_addr + len); 205245748Smckusick 205345748Smckusick vm_map_unlock(src_map); 205445748Smckusick if (src_map != dst_map) 205545748Smckusick vm_map_unlock(dst_map); 205645748Smckusick 205745748Smckusick return(result); 205845748Smckusick } 205945748Smckusick 206045748Smckusick /* 206148383Skarels * vmspace_fork: 206248383Skarels * Create a new process vmspace structure and vm_map 206348383Skarels * based on those of an existing process. The new map 206448383Skarels * is based on the old map, according to the inheritance 206548383Skarels * values on the regions in that map. 206645748Smckusick * 206748383Skarels * The source map must not be locked. 206845748Smckusick */ 206948383Skarels struct vmspace * 207048383Skarels vmspace_fork(vm1) 207148383Skarels register struct vmspace *vm1; 207245748Smckusick { 207348383Skarels register struct vmspace *vm2; 207448383Skarels vm_map_t old_map = &vm1->vm_map; 207545748Smckusick vm_map_t new_map; 207645748Smckusick vm_map_entry_t old_entry; 207745748Smckusick vm_map_entry_t new_entry; 207845748Smckusick pmap_t new_pmap; 207945748Smckusick 208045748Smckusick vm_map_lock(old_map); 208145748Smckusick 208248383Skarels vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset, 208348383Skarels old_map->entries_pageable); 208448383Skarels bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy, 208548383Skarels (caddr_t) (vm1 + 1) - (caddr_t) &vm1->vm_startcopy); 208648383Skarels new_pmap = &vm2->vm_pmap; /* XXX */ 208748383Skarels new_map = &vm2->vm_map; /* XXX */ 208845748Smckusick 208945748Smckusick old_entry = old_map->header.next; 209045748Smckusick 209145748Smckusick while (old_entry != &old_map->header) { 209245748Smckusick if (old_entry->is_sub_map) 209345748Smckusick panic("vm_map_fork: encountered a submap"); 209445748Smckusick 209545748Smckusick switch (old_entry->inheritance) { 209645748Smckusick case VM_INHERIT_NONE: 209745748Smckusick break; 209845748Smckusick 209945748Smckusick case VM_INHERIT_SHARE: 210045748Smckusick /* 210145748Smckusick * If we don't already have a sharing map: 210245748Smckusick */ 210345748Smckusick 210445748Smckusick if (!old_entry->is_a_map) { 210545748Smckusick vm_map_t new_share_map; 210645748Smckusick vm_map_entry_t new_share_entry; 210745748Smckusick 210845748Smckusick /* 210945748Smckusick * Create a new sharing map 211045748Smckusick */ 211145748Smckusick 211248383Skarels new_share_map = vm_map_create(NULL, 211345748Smckusick old_entry->start, 211445748Smckusick old_entry->end, 211545748Smckusick TRUE); 211645748Smckusick new_share_map->is_main_map = FALSE; 211745748Smckusick 211845748Smckusick /* 211945748Smckusick * Create the only sharing entry from the 212045748Smckusick * old task map entry. 212145748Smckusick */ 212245748Smckusick 212345748Smckusick new_share_entry = 212445748Smckusick vm_map_entry_create(new_share_map); 212545748Smckusick *new_share_entry = *old_entry; 212661005Shibler new_share_entry->wired_count = 0; 212745748Smckusick 212845748Smckusick /* 212945748Smckusick * Insert the entry into the new sharing 213045748Smckusick * map 213145748Smckusick */ 213245748Smckusick 213345748Smckusick vm_map_entry_link(new_share_map, 213445748Smckusick new_share_map->header.prev, 213545748Smckusick new_share_entry); 213645748Smckusick 213745748Smckusick /* 213845748Smckusick * Fix up the task map entry to refer 213945748Smckusick * to the sharing map now. 214045748Smckusick */ 214145748Smckusick 214245748Smckusick old_entry->is_a_map = TRUE; 214345748Smckusick old_entry->object.share_map = new_share_map; 214445748Smckusick old_entry->offset = old_entry->start; 214545748Smckusick } 214645748Smckusick 214745748Smckusick /* 214845748Smckusick * Clone the entry, referencing the sharing map. 214945748Smckusick */ 215045748Smckusick 215145748Smckusick new_entry = vm_map_entry_create(new_map); 215245748Smckusick *new_entry = *old_entry; 215361005Shibler new_entry->wired_count = 0; 215445748Smckusick vm_map_reference(new_entry->object.share_map); 215545748Smckusick 215645748Smckusick /* 215745748Smckusick * Insert the entry into the new map -- we 215845748Smckusick * know we're inserting at the end of the new 215945748Smckusick * map. 216045748Smckusick */ 216145748Smckusick 216245748Smckusick vm_map_entry_link(new_map, new_map->header.prev, 216345748Smckusick new_entry); 216445748Smckusick 216545748Smckusick /* 216645748Smckusick * Update the physical map 216745748Smckusick */ 216845748Smckusick 216945748Smckusick pmap_copy(new_map->pmap, old_map->pmap, 217045748Smckusick new_entry->start, 217145748Smckusick (old_entry->end - old_entry->start), 217245748Smckusick old_entry->start); 217345748Smckusick break; 217445748Smckusick 217545748Smckusick case VM_INHERIT_COPY: 217645748Smckusick /* 217745748Smckusick * Clone the entry and link into the map. 217845748Smckusick */ 217945748Smckusick 218045748Smckusick new_entry = vm_map_entry_create(new_map); 218145748Smckusick *new_entry = *old_entry; 218245748Smckusick new_entry->wired_count = 0; 218348383Skarels new_entry->object.vm_object = NULL; 218445748Smckusick new_entry->is_a_map = FALSE; 218545748Smckusick vm_map_entry_link(new_map, new_map->header.prev, 218645748Smckusick new_entry); 218745748Smckusick if (old_entry->is_a_map) { 218845748Smckusick int check; 218945748Smckusick 219045748Smckusick check = vm_map_copy(new_map, 219145748Smckusick old_entry->object.share_map, 219245748Smckusick new_entry->start, 219345748Smckusick (vm_size_t)(new_entry->end - 219445748Smckusick new_entry->start), 219545748Smckusick old_entry->offset, 219645748Smckusick FALSE, FALSE); 219745748Smckusick if (check != KERN_SUCCESS) 219845748Smckusick printf("vm_map_fork: copy in share_map region failed\n"); 219945748Smckusick } 220045748Smckusick else { 220145748Smckusick vm_map_copy_entry(old_map, new_map, old_entry, 220245748Smckusick new_entry); 220345748Smckusick } 220445748Smckusick break; 220545748Smckusick } 220645748Smckusick old_entry = old_entry->next; 220745748Smckusick } 220845748Smckusick 220945748Smckusick new_map->size = old_map->size; 221045748Smckusick vm_map_unlock(old_map); 221145748Smckusick 221248383Skarels return(vm2); 221345748Smckusick } 221445748Smckusick 221545748Smckusick /* 221645748Smckusick * vm_map_lookup: 221745748Smckusick * 221845748Smckusick * Finds the VM object, offset, and 221945748Smckusick * protection for a given virtual address in the 222045748Smckusick * specified map, assuming a page fault of the 222145748Smckusick * type specified. 222245748Smckusick * 222345748Smckusick * Leaves the map in question locked for read; return 222445748Smckusick * values are guaranteed until a vm_map_lookup_done 222545748Smckusick * call is performed. Note that the map argument 222645748Smckusick * is in/out; the returned map must be used in 222745748Smckusick * the call to vm_map_lookup_done. 222845748Smckusick * 222945748Smckusick * A handle (out_entry) is returned for use in 223045748Smckusick * vm_map_lookup_done, to make that fast. 223145748Smckusick * 223245748Smckusick * If a lookup is requested with "write protection" 223345748Smckusick * specified, the map may be changed to perform virtual 223445748Smckusick * copying operations, although the data referenced will 223545748Smckusick * remain the same. 223645748Smckusick */ 223753357Sbostic int 223845748Smckusick vm_map_lookup(var_map, vaddr, fault_type, out_entry, 223945748Smckusick object, offset, out_prot, wired, single_use) 224045748Smckusick vm_map_t *var_map; /* IN/OUT */ 224145748Smckusick register vm_offset_t vaddr; 224245748Smckusick register vm_prot_t fault_type; 224345748Smckusick 224445748Smckusick vm_map_entry_t *out_entry; /* OUT */ 224545748Smckusick vm_object_t *object; /* OUT */ 224645748Smckusick vm_offset_t *offset; /* OUT */ 224745748Smckusick vm_prot_t *out_prot; /* OUT */ 224845748Smckusick boolean_t *wired; /* OUT */ 224945748Smckusick boolean_t *single_use; /* OUT */ 225045748Smckusick { 225145748Smckusick vm_map_t share_map; 225245748Smckusick vm_offset_t share_offset; 225345748Smckusick register vm_map_entry_t entry; 225445748Smckusick register vm_map_t map = *var_map; 225545748Smckusick register vm_prot_t prot; 225645748Smckusick register boolean_t su; 225745748Smckusick 225845748Smckusick RetryLookup: ; 225945748Smckusick 226045748Smckusick /* 226145748Smckusick * Lookup the faulting address. 226245748Smckusick */ 226345748Smckusick 226445748Smckusick vm_map_lock_read(map); 226545748Smckusick 226645748Smckusick #define RETURN(why) \ 226745748Smckusick { \ 226845748Smckusick vm_map_unlock_read(map); \ 226945748Smckusick return(why); \ 227045748Smckusick } 227145748Smckusick 227245748Smckusick /* 227345748Smckusick * If the map has an interesting hint, try it before calling 227445748Smckusick * full blown lookup routine. 227545748Smckusick */ 227645748Smckusick 227745748Smckusick simple_lock(&map->hint_lock); 227845748Smckusick entry = map->hint; 227945748Smckusick simple_unlock(&map->hint_lock); 228045748Smckusick 228145748Smckusick *out_entry = entry; 228245748Smckusick 228345748Smckusick if ((entry == &map->header) || 228445748Smckusick (vaddr < entry->start) || (vaddr >= entry->end)) { 228545748Smckusick vm_map_entry_t tmp_entry; 228645748Smckusick 228745748Smckusick /* 228845748Smckusick * Entry was either not a valid hint, or the vaddr 228945748Smckusick * was not contained in the entry, so do a full lookup. 229045748Smckusick */ 229145748Smckusick if (!vm_map_lookup_entry(map, vaddr, &tmp_entry)) 229245748Smckusick RETURN(KERN_INVALID_ADDRESS); 229345748Smckusick 229445748Smckusick entry = tmp_entry; 229545748Smckusick *out_entry = entry; 229645748Smckusick } 229745748Smckusick 229845748Smckusick /* 229945748Smckusick * Handle submaps. 230045748Smckusick */ 230145748Smckusick 230245748Smckusick if (entry->is_sub_map) { 230345748Smckusick vm_map_t old_map = map; 230445748Smckusick 230545748Smckusick *var_map = map = entry->object.sub_map; 230645748Smckusick vm_map_unlock_read(old_map); 230745748Smckusick goto RetryLookup; 230845748Smckusick } 230945748Smckusick 231045748Smckusick /* 231145748Smckusick * Check whether this task is allowed to have 231245748Smckusick * this page. 231345748Smckusick */ 231445748Smckusick 231545748Smckusick prot = entry->protection; 231645748Smckusick if ((fault_type & (prot)) != fault_type) 231745748Smckusick RETURN(KERN_PROTECTION_FAILURE); 231845748Smckusick 231945748Smckusick /* 232045748Smckusick * If this page is not pageable, we have to get 232145748Smckusick * it for all possible accesses. 232245748Smckusick */ 232345748Smckusick 232445748Smckusick if (*wired = (entry->wired_count != 0)) 232545748Smckusick prot = fault_type = entry->protection; 232645748Smckusick 232745748Smckusick /* 232845748Smckusick * If we don't already have a VM object, track 232945748Smckusick * it down. 233045748Smckusick */ 233145748Smckusick 233245748Smckusick if (su = !entry->is_a_map) { 233345748Smckusick share_map = map; 233445748Smckusick share_offset = vaddr; 233545748Smckusick } 233645748Smckusick else { 233745748Smckusick vm_map_entry_t share_entry; 233845748Smckusick 233945748Smckusick /* 234045748Smckusick * Compute the sharing map, and offset into it. 234145748Smckusick */ 234245748Smckusick 234345748Smckusick share_map = entry->object.share_map; 234445748Smckusick share_offset = (vaddr - entry->start) + entry->offset; 234545748Smckusick 234645748Smckusick /* 234745748Smckusick * Look for the backing store object and offset 234845748Smckusick */ 234945748Smckusick 235045748Smckusick vm_map_lock_read(share_map); 235145748Smckusick 235245748Smckusick if (!vm_map_lookup_entry(share_map, share_offset, 235345748Smckusick &share_entry)) { 235445748Smckusick vm_map_unlock_read(share_map); 235545748Smckusick RETURN(KERN_INVALID_ADDRESS); 235645748Smckusick } 235745748Smckusick entry = share_entry; 235845748Smckusick } 235945748Smckusick 236045748Smckusick /* 236145748Smckusick * If the entry was copy-on-write, we either ... 236245748Smckusick */ 236345748Smckusick 236445748Smckusick if (entry->needs_copy) { 236545748Smckusick /* 236645748Smckusick * If we want to write the page, we may as well 236745748Smckusick * handle that now since we've got the sharing 236845748Smckusick * map locked. 236945748Smckusick * 237045748Smckusick * If we don't need to write the page, we just 237145748Smckusick * demote the permissions allowed. 237245748Smckusick */ 237345748Smckusick 237445748Smckusick if (fault_type & VM_PROT_WRITE) { 237545748Smckusick /* 237645748Smckusick * Make a new object, and place it in the 237745748Smckusick * object chain. Note that no new references 237845748Smckusick * have appeared -- one just moved from the 237945748Smckusick * share map to the new object. 238045748Smckusick */ 238145748Smckusick 238245748Smckusick if (lock_read_to_write(&share_map->lock)) { 238345748Smckusick if (share_map != map) 238445748Smckusick vm_map_unlock_read(map); 238545748Smckusick goto RetryLookup; 238645748Smckusick } 238745748Smckusick 238845748Smckusick vm_object_shadow( 238945748Smckusick &entry->object.vm_object, 239045748Smckusick &entry->offset, 239145748Smckusick (vm_size_t) (entry->end - entry->start)); 239245748Smckusick 239345748Smckusick entry->needs_copy = FALSE; 239445748Smckusick 239545748Smckusick lock_write_to_read(&share_map->lock); 239645748Smckusick } 239745748Smckusick else { 239845748Smckusick /* 239945748Smckusick * We're attempting to read a copy-on-write 240045748Smckusick * page -- don't allow writes. 240145748Smckusick */ 240245748Smckusick 240345748Smckusick prot &= (~VM_PROT_WRITE); 240445748Smckusick } 240545748Smckusick } 240645748Smckusick 240745748Smckusick /* 240845748Smckusick * Create an object if necessary. 240945748Smckusick */ 241048383Skarels if (entry->object.vm_object == NULL) { 241145748Smckusick 241245748Smckusick if (lock_read_to_write(&share_map->lock)) { 241345748Smckusick if (share_map != map) 241445748Smckusick vm_map_unlock_read(map); 241545748Smckusick goto RetryLookup; 241645748Smckusick } 241745748Smckusick 241845748Smckusick entry->object.vm_object = vm_object_allocate( 241945748Smckusick (vm_size_t)(entry->end - entry->start)); 242045748Smckusick entry->offset = 0; 242145748Smckusick lock_write_to_read(&share_map->lock); 242245748Smckusick } 242345748Smckusick 242445748Smckusick /* 242545748Smckusick * Return the object/offset from this entry. If the entry 242645748Smckusick * was copy-on-write or empty, it has been fixed up. 242745748Smckusick */ 242845748Smckusick 242945748Smckusick *offset = (share_offset - entry->start) + entry->offset; 243045748Smckusick *object = entry->object.vm_object; 243145748Smckusick 243245748Smckusick /* 243345748Smckusick * Return whether this is the only map sharing this data. 243445748Smckusick */ 243545748Smckusick 243645748Smckusick if (!su) { 243745748Smckusick simple_lock(&share_map->ref_lock); 243845748Smckusick su = (share_map->ref_count == 1); 243945748Smckusick simple_unlock(&share_map->ref_lock); 244045748Smckusick } 244145748Smckusick 244245748Smckusick *out_prot = prot; 244345748Smckusick *single_use = su; 244445748Smckusick 244545748Smckusick return(KERN_SUCCESS); 244645748Smckusick 244745748Smckusick #undef RETURN 244845748Smckusick } 244945748Smckusick 245045748Smckusick /* 245145748Smckusick * vm_map_lookup_done: 245245748Smckusick * 245345748Smckusick * Releases locks acquired by a vm_map_lookup 245445748Smckusick * (according to the handle returned by that lookup). 245545748Smckusick */ 245645748Smckusick 245745748Smckusick void vm_map_lookup_done(map, entry) 245845748Smckusick register vm_map_t map; 245945748Smckusick vm_map_entry_t entry; 246045748Smckusick { 246145748Smckusick /* 246245748Smckusick * If this entry references a map, unlock it first. 246345748Smckusick */ 246445748Smckusick 246545748Smckusick if (entry->is_a_map) 246645748Smckusick vm_map_unlock_read(entry->object.share_map); 246745748Smckusick 246845748Smckusick /* 246945748Smckusick * Unlock the main-level map 247045748Smckusick */ 247145748Smckusick 247245748Smckusick vm_map_unlock_read(map); 247345748Smckusick } 247445748Smckusick 247545748Smckusick /* 247645748Smckusick * Routine: vm_map_simplify 247745748Smckusick * Purpose: 247845748Smckusick * Attempt to simplify the map representation in 247945748Smckusick * the vicinity of the given starting address. 248045748Smckusick * Note: 248145748Smckusick * This routine is intended primarily to keep the 248245748Smckusick * kernel maps more compact -- they generally don't 248345748Smckusick * benefit from the "expand a map entry" technology 248445748Smckusick * at allocation time because the adjacent entry 248545748Smckusick * is often wired down. 248645748Smckusick */ 248745748Smckusick void vm_map_simplify(map, start) 248845748Smckusick vm_map_t map; 248945748Smckusick vm_offset_t start; 249045748Smckusick { 249145748Smckusick vm_map_entry_t this_entry; 249245748Smckusick vm_map_entry_t prev_entry; 249345748Smckusick 249445748Smckusick vm_map_lock(map); 249545748Smckusick if ( 249645748Smckusick (vm_map_lookup_entry(map, start, &this_entry)) && 249745748Smckusick ((prev_entry = this_entry->prev) != &map->header) && 249845748Smckusick 249945748Smckusick (prev_entry->end == start) && 250045748Smckusick (map->is_main_map) && 250145748Smckusick 250245748Smckusick (prev_entry->is_a_map == FALSE) && 250345748Smckusick (prev_entry->is_sub_map == FALSE) && 250445748Smckusick 250545748Smckusick (this_entry->is_a_map == FALSE) && 250645748Smckusick (this_entry->is_sub_map == FALSE) && 250745748Smckusick 250845748Smckusick (prev_entry->inheritance == this_entry->inheritance) && 250945748Smckusick (prev_entry->protection == this_entry->protection) && 251045748Smckusick (prev_entry->max_protection == this_entry->max_protection) && 251145748Smckusick (prev_entry->wired_count == this_entry->wired_count) && 251245748Smckusick 251345748Smckusick (prev_entry->copy_on_write == this_entry->copy_on_write) && 251445748Smckusick (prev_entry->needs_copy == this_entry->needs_copy) && 251545748Smckusick 251645748Smckusick (prev_entry->object.vm_object == this_entry->object.vm_object) && 251745748Smckusick ((prev_entry->offset + (prev_entry->end - prev_entry->start)) 251845748Smckusick == this_entry->offset) 251945748Smckusick ) { 252045748Smckusick if (map->first_free == this_entry) 252145748Smckusick map->first_free = prev_entry; 252245748Smckusick 252345748Smckusick SAVE_HINT(map, prev_entry); 252445748Smckusick vm_map_entry_unlink(map, this_entry); 252545748Smckusick prev_entry->end = this_entry->end; 252645748Smckusick vm_object_deallocate(this_entry->object.vm_object); 252745748Smckusick vm_map_entry_dispose(map, this_entry); 252845748Smckusick } 252945748Smckusick vm_map_unlock(map); 253045748Smckusick } 253145748Smckusick 253245748Smckusick /* 253345748Smckusick * vm_map_print: [ debug ] 253445748Smckusick */ 253545748Smckusick void vm_map_print(map, full) 253645748Smckusick register vm_map_t map; 253745748Smckusick boolean_t full; 253845748Smckusick { 253945748Smckusick register vm_map_entry_t entry; 254045748Smckusick extern int indent; 254145748Smckusick 254245748Smckusick iprintf("%s map 0x%x: pmap=0x%x,ref=%d,nentries=%d,version=%d\n", 254345748Smckusick (map->is_main_map ? "Task" : "Share"), 254445748Smckusick (int) map, (int) (map->pmap), map->ref_count, map->nentries, 254545748Smckusick map->timestamp); 254645748Smckusick 254745748Smckusick if (!full && indent) 254845748Smckusick return; 254945748Smckusick 255045748Smckusick indent += 2; 255145748Smckusick for (entry = map->header.next; entry != &map->header; 255245748Smckusick entry = entry->next) { 255345748Smckusick iprintf("map entry 0x%x: start=0x%x, end=0x%x, ", 255445748Smckusick (int) entry, (int) entry->start, (int) entry->end); 255545748Smckusick if (map->is_main_map) { 255645748Smckusick static char *inheritance_name[4] = 255745748Smckusick { "share", "copy", "none", "donate_copy"}; 255845748Smckusick printf("prot=%x/%x/%s, ", 255945748Smckusick entry->protection, 256045748Smckusick entry->max_protection, 256145748Smckusick inheritance_name[entry->inheritance]); 256245748Smckusick if (entry->wired_count != 0) 256345748Smckusick printf("wired, "); 256445748Smckusick } 256545748Smckusick 256645748Smckusick if (entry->is_a_map || entry->is_sub_map) { 256745748Smckusick printf("share=0x%x, offset=0x%x\n", 256845748Smckusick (int) entry->object.share_map, 256945748Smckusick (int) entry->offset); 257045748Smckusick if ((entry->prev == &map->header) || 257145748Smckusick (!entry->prev->is_a_map) || 257245748Smckusick (entry->prev->object.share_map != 257345748Smckusick entry->object.share_map)) { 257445748Smckusick indent += 2; 257545748Smckusick vm_map_print(entry->object.share_map, full); 257645748Smckusick indent -= 2; 257745748Smckusick } 257845748Smckusick 257945748Smckusick } 258045748Smckusick else { 258145748Smckusick printf("object=0x%x, offset=0x%x", 258245748Smckusick (int) entry->object.vm_object, 258345748Smckusick (int) entry->offset); 258445748Smckusick if (entry->copy_on_write) 258545748Smckusick printf(", copy (%s)", 258645748Smckusick entry->needs_copy ? "needed" : "done"); 258745748Smckusick printf("\n"); 258845748Smckusick 258945748Smckusick if ((entry->prev == &map->header) || 259045748Smckusick (entry->prev->is_a_map) || 259145748Smckusick (entry->prev->object.vm_object != 259245748Smckusick entry->object.vm_object)) { 259345748Smckusick indent += 2; 259445748Smckusick vm_object_print(entry->object.vm_object, full); 259545748Smckusick indent -= 2; 259645748Smckusick } 259745748Smckusick } 259845748Smckusick } 259945748Smckusick indent -= 2; 260045748Smckusick } 2601