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*69522Spendry * @(#)vm_map.c 8.9 (Berkeley) 05/17/95
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
5045748Smckusick /*
5145748Smckusick * Virtual memory maps provide for the mapping, protection,
5245748Smckusick * and sharing of virtual memory objects. In addition,
5345748Smckusick * this module provides for an efficient virtual copy of
5445748Smckusick * memory from one map to another.
5545748Smckusick *
5645748Smckusick * Synchronization is required prior to most operations.
5745748Smckusick *
5845748Smckusick * Maps consist of an ordered doubly-linked list of simple
5945748Smckusick * entries; a single hint is used to speed up lookups.
6045748Smckusick *
6145748Smckusick * In order to properly represent the sharing of virtual
6245748Smckusick * memory regions among maps, the map structure is bi-level.
6345748Smckusick * Top-level ("address") maps refer to regions of sharable
6445748Smckusick * virtual memory. These regions are implemented as
6545748Smckusick * ("sharing") maps, which then refer to the actual virtual
6645748Smckusick * memory objects. When two address maps "share" memory,
6745748Smckusick * their top-level maps both have references to the same
6845748Smckusick * sharing map. When memory is virtual-copied from one
6945748Smckusick * address map to another, the references in the sharing
7045748Smckusick * maps are actually copied -- no copying occurs at the
7145748Smckusick * virtual memory object level.
7245748Smckusick *
7345748Smckusick * Since portions of maps are specified by start/end addreses,
7445748Smckusick * which may not align with existing map entries, all
7545748Smckusick * routines merely "clip" entries to these start/end values.
7645748Smckusick * [That is, an entry is split into two, bordering at a
7745748Smckusick * start or end value.] Note that these clippings may not
7845748Smckusick * always be necessary (as the two resulting entries are then
7945748Smckusick * not changed); however, the clipping is done for convenience.
8045748Smckusick * No attempt is currently made to "glue back together" two
8145748Smckusick * abutting entries.
8245748Smckusick *
8345748Smckusick * As mentioned above, virtual copy operations are performed
8445748Smckusick * by copying VM object references from one sharing map to
8545748Smckusick * another, and then marking both regions as copy-on-write.
8645748Smckusick * It is important to note that only one writeable reference
8745748Smckusick * to a VM object region exists in any map -- this means that
8845748Smckusick * shadow object creation can be delayed until a write operation
8945748Smckusick * occurs.
9045748Smckusick */
9145748Smckusick
9245748Smckusick /*
9348383Skarels * vm_map_startup:
9445748Smckusick *
9545748Smckusick * Initialize the vm_map module. Must be called before
9645748Smckusick * any other vm_map routines.
9745748Smckusick *
9845748Smckusick * Map and entry structures are allocated from the general
9945748Smckusick * purpose memory pool with some exceptions:
10045748Smckusick *
10145748Smckusick * - The kernel map and kmem submap are allocated statically.
10245748Smckusick * - Kernel map entries are allocated out of a static pool.
10345748Smckusick *
10445748Smckusick * These restrictions are necessary since malloc() uses the
10545748Smckusick * maps and requires map entries.
10645748Smckusick */
10745748Smckusick
10845748Smckusick vm_offset_t kentry_data;
10945748Smckusick vm_size_t kentry_data_size;
11045748Smckusick vm_map_entry_t kentry_free;
11145748Smckusick vm_map_t kmap_free;
11245748Smckusick
11353357Sbostic static void _vm_map_clip_end __P((vm_map_t, vm_map_entry_t, vm_offset_t));
11453357Sbostic static void _vm_map_clip_start __P((vm_map_t, vm_map_entry_t, vm_offset_t));
11553357Sbostic
11668162Scgd void
vm_map_startup()11768162Scgd 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 *
vmspace_alloc(min,max,pageable)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
vmspace_free(vm)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 */
19568162Scgd vm_map_t
vm_map_create(pmap,min,max,pageable)19668162Scgd vm_map_create(pmap, min, max, pageable)
19745748Smckusick pmap_t pmap;
19845748Smckusick vm_offset_t min, max;
19945748Smckusick boolean_t pageable;
20045748Smckusick {
20145748Smckusick register vm_map_t result;
20265479Sbostic extern vm_map_t kmem_map;
20345748Smckusick
20448383Skarels if (kmem_map == NULL) {
20545748Smckusick result = kmap_free;
20648383Skarels if (result == NULL)
20748383Skarels panic("vm_map_create: out of maps");
20868162Scgd kmap_free = (vm_map_t) result->header.next;
20945748Smckusick } else
21045748Smckusick MALLOC(result, vm_map_t, sizeof(struct vm_map),
21145748Smckusick M_VMMAP, M_WAITOK);
21245748Smckusick
21348383Skarels vm_map_init(result, min, max, pageable);
21445748Smckusick result->pmap = pmap;
21545748Smckusick return(result);
21645748Smckusick }
21745748Smckusick
21845748Smckusick /*
21948383Skarels * Initialize an existing vm_map structure
22048383Skarels * such as that in the vmspace structure.
22148383Skarels * The pmap is set elsewhere.
22248383Skarels */
22348383Skarels void
vm_map_init(map,min,max,pageable)22448383Skarels vm_map_init(map, min, max, pageable)
22548383Skarels register struct vm_map *map;
22648383Skarels vm_offset_t min, max;
22748383Skarels boolean_t pageable;
22848383Skarels {
22948383Skarels map->header.next = map->header.prev = &map->header;
23048383Skarels map->nentries = 0;
23148383Skarels map->size = 0;
23248383Skarels map->ref_count = 1;
23348383Skarels map->is_main_map = TRUE;
23448383Skarels map->min_offset = min;
23548383Skarels map->max_offset = max;
23648383Skarels map->entries_pageable = pageable;
23748383Skarels map->first_free = &map->header;
23848383Skarels map->hint = &map->header;
23948383Skarels map->timestamp = 0;
24069388Smckusick lockinit(&map->lock, PVM, "thrd_sleep", 0, 0);
24148383Skarels simple_lock_init(&map->ref_lock);
24248383Skarels simple_lock_init(&map->hint_lock);
24348383Skarels }
24448383Skarels
24548383Skarels /*
24645748Smckusick * vm_map_entry_create: [ internal use only ]
24745748Smckusick *
24845748Smckusick * Allocates a VM map entry for insertion.
24945748Smckusick * No entry fields are filled in. This routine is
25045748Smckusick */
25168162Scgd vm_map_entry_t
vm_map_entry_create(map)25268162Scgd vm_map_entry_create(map)
25345748Smckusick vm_map_t map;
25445748Smckusick {
25545748Smckusick vm_map_entry_t entry;
25665686Shibler #ifdef DEBUG
25758374Smckusick extern vm_map_t kernel_map, kmem_map, mb_map, pager_map;
25865686Shibler boolean_t isspecial;
25945748Smckusick
26065686Shibler isspecial = (map == kernel_map || map == kmem_map ||
26165686Shibler map == mb_map || map == pager_map);
26265686Shibler if (isspecial && map->entries_pageable ||
26365686Shibler !isspecial && !map->entries_pageable)
26465686Shibler panic("vm_map_entry_create: bogus map");
26565686Shibler #endif
26665686Shibler if (map->entries_pageable) {
26765686Shibler MALLOC(entry, vm_map_entry_t, sizeof(struct vm_map_entry),
26865686Shibler M_VMMAPENT, M_WAITOK);
26965686Shibler } else {
27045748Smckusick if (entry = kentry_free)
27145748Smckusick kentry_free = kentry_free->next;
27265686Shibler }
27348383Skarels if (entry == NULL)
27445748Smckusick panic("vm_map_entry_create: out of map entries");
27545748Smckusick
27645748Smckusick return(entry);
27745748Smckusick }
27845748Smckusick
27945748Smckusick /*
28045748Smckusick * vm_map_entry_dispose: [ internal use only ]
28145748Smckusick *
28245748Smckusick * Inverse of vm_map_entry_create.
28345748Smckusick */
28468162Scgd void
vm_map_entry_dispose(map,entry)28568162Scgd vm_map_entry_dispose(map, entry)
28645748Smckusick vm_map_t map;
28745748Smckusick vm_map_entry_t entry;
28845748Smckusick {
28965686Shibler #ifdef DEBUG
29058374Smckusick extern vm_map_t kernel_map, kmem_map, mb_map, pager_map;
29165686Shibler boolean_t isspecial;
29245748Smckusick
29365686Shibler isspecial = (map == kernel_map || map == kmem_map ||
29465686Shibler map == mb_map || map == pager_map);
29565686Shibler if (isspecial && map->entries_pageable ||
29665686Shibler !isspecial && !map->entries_pageable)
29765686Shibler panic("vm_map_entry_dispose: bogus map");
29865686Shibler #endif
29965686Shibler if (map->entries_pageable) {
30065686Shibler FREE(entry, M_VMMAPENT);
30165686Shibler } else {
30245748Smckusick entry->next = kentry_free;
30345748Smckusick kentry_free = entry;
30465686Shibler }
30545748Smckusick }
30645748Smckusick
30745748Smckusick /*
30845748Smckusick * vm_map_entry_{un,}link:
30945748Smckusick *
31045748Smckusick * Insert/remove entries from maps.
31145748Smckusick */
31245748Smckusick #define vm_map_entry_link(map, after_where, entry) \
31345748Smckusick { \
31445748Smckusick (map)->nentries++; \
31545748Smckusick (entry)->prev = (after_where); \
31645748Smckusick (entry)->next = (after_where)->next; \
31745748Smckusick (entry)->prev->next = (entry); \
31845748Smckusick (entry)->next->prev = (entry); \
31945748Smckusick }
32045748Smckusick #define vm_map_entry_unlink(map, entry) \
32145748Smckusick { \
32245748Smckusick (map)->nentries--; \
32345748Smckusick (entry)->next->prev = (entry)->prev; \
32445748Smckusick (entry)->prev->next = (entry)->next; \
32545748Smckusick }
32645748Smckusick
32745748Smckusick /*
32845748Smckusick * vm_map_reference:
32945748Smckusick *
33045748Smckusick * Creates another valid reference to the given map.
33145748Smckusick *
33245748Smckusick */
33368162Scgd void
vm_map_reference(map)33468162Scgd vm_map_reference(map)
33545748Smckusick register vm_map_t map;
33645748Smckusick {
33748383Skarels if (map == NULL)
33845748Smckusick return;
33945748Smckusick
34045748Smckusick simple_lock(&map->ref_lock);
341*69522Spendry #ifdef DEBUG
342*69522Spendry if (map->ref_count == 0)
343*69522Spendry panic("vm_map_reference: zero ref_count");
344*69522Spendry #endif
34545748Smckusick map->ref_count++;
34645748Smckusick simple_unlock(&map->ref_lock);
34745748Smckusick }
34845748Smckusick
34945748Smckusick /*
35045748Smckusick * vm_map_deallocate:
35145748Smckusick *
35245748Smckusick * Removes a reference from the specified map,
35345748Smckusick * destroying it if no references remain.
35445748Smckusick * The map should not be locked.
35545748Smckusick */
35668162Scgd void
vm_map_deallocate(map)35768162Scgd vm_map_deallocate(map)
35845748Smckusick register vm_map_t map;
35945748Smckusick {
36045748Smckusick
36148383Skarels if (map == NULL)
36245748Smckusick return;
36345748Smckusick
36445748Smckusick simple_lock(&map->ref_lock);
365*69522Spendry if (--map->ref_count > 0) {
366*69522Spendry simple_unlock(&map->ref_lock);
36745748Smckusick return;
36845748Smckusick }
36945748Smckusick
37045748Smckusick /*
37145748Smckusick * Lock the map, to wait out all other references
37245748Smckusick * to it.
37345748Smckusick */
37445748Smckusick
375*69522Spendry vm_map_lock_drain_interlock(map);
37645748Smckusick
37745748Smckusick (void) vm_map_delete(map, map->min_offset, map->max_offset);
37845748Smckusick
37945748Smckusick pmap_destroy(map->pmap);
38045748Smckusick
381*69522Spendry vm_map_unlock(map);
382*69522Spendry
38345748Smckusick FREE(map, M_VMMAP);
38445748Smckusick }
38545748Smckusick
38645748Smckusick /*
38765686Shibler * vm_map_insert:
38845748Smckusick *
38945748Smckusick * Inserts the given whole VM object into the target
39045748Smckusick * map at the specified address range. The object's
39145748Smckusick * size should match that of the address range.
39245748Smckusick *
39345748Smckusick * Requires that the map be locked, and leaves it so.
39445748Smckusick */
39553357Sbostic int
vm_map_insert(map,object,offset,start,end)39645748Smckusick vm_map_insert(map, object, offset, start, end)
39745748Smckusick vm_map_t map;
39845748Smckusick vm_object_t object;
39945748Smckusick vm_offset_t offset;
40045748Smckusick vm_offset_t start;
40145748Smckusick vm_offset_t end;
40245748Smckusick {
40345748Smckusick register vm_map_entry_t new_entry;
40445748Smckusick register vm_map_entry_t prev_entry;
40545748Smckusick vm_map_entry_t temp_entry;
40645748Smckusick
40745748Smckusick /*
40845748Smckusick * Check that the start and end points are not bogus.
40945748Smckusick */
41045748Smckusick
41145748Smckusick if ((start < map->min_offset) || (end > map->max_offset) ||
41245748Smckusick (start >= end))
41345748Smckusick return(KERN_INVALID_ADDRESS);
41445748Smckusick
41545748Smckusick /*
41645748Smckusick * Find the entry prior to the proposed
41745748Smckusick * starting address; if it's part of an
41845748Smckusick * existing entry, this range is bogus.
41945748Smckusick */
42045748Smckusick
42145748Smckusick if (vm_map_lookup_entry(map, start, &temp_entry))
42245748Smckusick return(KERN_NO_SPACE);
42345748Smckusick
42445748Smckusick prev_entry = temp_entry;
42545748Smckusick
42645748Smckusick /*
42745748Smckusick * Assert that the next entry doesn't overlap the
42845748Smckusick * end point.
42945748Smckusick */
43045748Smckusick
43145748Smckusick if ((prev_entry->next != &map->header) &&
43245748Smckusick (prev_entry->next->start < end))
43345748Smckusick return(KERN_NO_SPACE);
43445748Smckusick
43545748Smckusick /*
43645748Smckusick * See if we can avoid creating a new entry by
43745748Smckusick * extending one of our neighbors.
43845748Smckusick */
43945748Smckusick
44048383Skarels if (object == NULL) {
44145748Smckusick if ((prev_entry != &map->header) &&
44245748Smckusick (prev_entry->end == start) &&
44345748Smckusick (map->is_main_map) &&
44445748Smckusick (prev_entry->is_a_map == FALSE) &&
44545748Smckusick (prev_entry->is_sub_map == FALSE) &&
44645748Smckusick (prev_entry->inheritance == VM_INHERIT_DEFAULT) &&
44745748Smckusick (prev_entry->protection == VM_PROT_DEFAULT) &&
44845748Smckusick (prev_entry->max_protection == VM_PROT_DEFAULT) &&
44945748Smckusick (prev_entry->wired_count == 0)) {
45045748Smckusick
45145748Smckusick if (vm_object_coalesce(prev_entry->object.vm_object,
45248383Skarels NULL,
45345748Smckusick prev_entry->offset,
45445748Smckusick (vm_offset_t) 0,
45545748Smckusick (vm_size_t)(prev_entry->end
45645748Smckusick - prev_entry->start),
45745748Smckusick (vm_size_t)(end - prev_entry->end))) {
45845748Smckusick /*
45945748Smckusick * Coalesced the two objects - can extend
46045748Smckusick * the previous map entry to include the
46145748Smckusick * new range.
46245748Smckusick */
46345748Smckusick map->size += (end - prev_entry->end);
46445748Smckusick prev_entry->end = end;
46545748Smckusick return(KERN_SUCCESS);
46645748Smckusick }
46745748Smckusick }
46845748Smckusick }
46945748Smckusick
47045748Smckusick /*
47145748Smckusick * Create a new entry
47245748Smckusick */
47345748Smckusick
47445748Smckusick new_entry = vm_map_entry_create(map);
47545748Smckusick new_entry->start = start;
47645748Smckusick new_entry->end = end;
47745748Smckusick
47845748Smckusick new_entry->is_a_map = FALSE;
47945748Smckusick new_entry->is_sub_map = FALSE;
48045748Smckusick new_entry->object.vm_object = object;
48145748Smckusick new_entry->offset = offset;
48245748Smckusick
48345748Smckusick new_entry->copy_on_write = FALSE;
48445748Smckusick new_entry->needs_copy = FALSE;
48545748Smckusick
48645748Smckusick if (map->is_main_map) {
48745748Smckusick new_entry->inheritance = VM_INHERIT_DEFAULT;
48845748Smckusick new_entry->protection = VM_PROT_DEFAULT;
48945748Smckusick new_entry->max_protection = VM_PROT_DEFAULT;
49045748Smckusick new_entry->wired_count = 0;
49145748Smckusick }
49245748Smckusick
49345748Smckusick /*
49445748Smckusick * Insert the new entry into the list
49545748Smckusick */
49645748Smckusick
49745748Smckusick vm_map_entry_link(map, prev_entry, new_entry);
49845748Smckusick map->size += new_entry->end - new_entry->start;
49945748Smckusick
50045748Smckusick /*
50145748Smckusick * Update the free space hint
50245748Smckusick */
50345748Smckusick
50445748Smckusick if ((map->first_free == prev_entry) && (prev_entry->end >= new_entry->start))
50545748Smckusick map->first_free = new_entry;
50645748Smckusick
50745748Smckusick return(KERN_SUCCESS);
50845748Smckusick }
50945748Smckusick
51045748Smckusick /*
51145748Smckusick * SAVE_HINT:
51245748Smckusick *
51345748Smckusick * Saves the specified entry as the hint for
51445748Smckusick * future lookups. Performs necessary interlocks.
51545748Smckusick */
51645748Smckusick #define SAVE_HINT(map,value) \
51745748Smckusick simple_lock(&(map)->hint_lock); \
51845748Smckusick (map)->hint = (value); \
51945748Smckusick simple_unlock(&(map)->hint_lock);
52045748Smckusick
52145748Smckusick /*
52245748Smckusick * vm_map_lookup_entry: [ internal use only ]
52345748Smckusick *
52445748Smckusick * Finds the map entry containing (or
52545748Smckusick * immediately preceding) the specified address
52645748Smckusick * in the given map; the entry is returned
52745748Smckusick * in the "entry" parameter. The boolean
52845748Smckusick * result indicates whether the address is
52945748Smckusick * actually contained in the map.
53045748Smckusick */
53168162Scgd boolean_t
vm_map_lookup_entry(map,address,entry)53268162Scgd vm_map_lookup_entry(map, address, entry)
53345748Smckusick register vm_map_t map;
53445748Smckusick register vm_offset_t address;
53545748Smckusick vm_map_entry_t *entry; /* OUT */
53645748Smckusick {
53745748Smckusick register vm_map_entry_t cur;
53845748Smckusick register vm_map_entry_t last;
53945748Smckusick
54045748Smckusick /*
54145748Smckusick * Start looking either from the head of the
54245748Smckusick * list, or from the hint.
54345748Smckusick */
54445748Smckusick
54545748Smckusick simple_lock(&map->hint_lock);
54645748Smckusick cur = map->hint;
54745748Smckusick simple_unlock(&map->hint_lock);
54845748Smckusick
54945748Smckusick if (cur == &map->header)
55045748Smckusick cur = cur->next;
55145748Smckusick
55245748Smckusick if (address >= cur->start) {
55345748Smckusick /*
55445748Smckusick * Go from hint to end of list.
55545748Smckusick *
55645748Smckusick * But first, make a quick check to see if
55745748Smckusick * we are already looking at the entry we
55845748Smckusick * want (which is usually the case).
55945748Smckusick * Note also that we don't need to save the hint
56045748Smckusick * here... it is the same hint (unless we are
56145748Smckusick * at the header, in which case the hint didn't
56245748Smckusick * buy us anything anyway).
56345748Smckusick */
56445748Smckusick last = &map->header;
56545748Smckusick if ((cur != last) && (cur->end > address)) {
56645748Smckusick *entry = cur;
56745748Smckusick return(TRUE);
56845748Smckusick }
56945748Smckusick }
57045748Smckusick else {
57145748Smckusick /*
57245748Smckusick * Go from start to hint, *inclusively*
57345748Smckusick */
57445748Smckusick last = cur->next;
57545748Smckusick cur = map->header.next;
57645748Smckusick }
57745748Smckusick
57845748Smckusick /*
57945748Smckusick * Search linearly
58045748Smckusick */
58145748Smckusick
58245748Smckusick while (cur != last) {
58345748Smckusick if (cur->end > address) {
58445748Smckusick if (address >= cur->start) {
58545748Smckusick /*
58645748Smckusick * Save this lookup for future
58745748Smckusick * hints, and return
58845748Smckusick */
58945748Smckusick
59045748Smckusick *entry = cur;
59145748Smckusick SAVE_HINT(map, cur);
59245748Smckusick return(TRUE);
59345748Smckusick }
59445748Smckusick break;
59545748Smckusick }
59645748Smckusick cur = cur->next;
59745748Smckusick }
59845748Smckusick *entry = cur->prev;
59945748Smckusick SAVE_HINT(map, *entry);
60045748Smckusick return(FALSE);
60145748Smckusick }
60245748Smckusick
60345748Smckusick /*
60452610Storek * Find sufficient space for `length' bytes in the given map, starting at
60552610Storek * `start'. The map must be locked. Returns 0 on success, 1 on no space.
60652610Storek */
60752610Storek int
vm_map_findspace(map,start,length,addr)60852610Storek vm_map_findspace(map, start, length, addr)
60952610Storek register vm_map_t map;
61052610Storek register vm_offset_t start;
61152610Storek vm_size_t length;
61252610Storek vm_offset_t *addr;
61352610Storek {
61452610Storek register vm_map_entry_t entry, next;
61552610Storek register vm_offset_t end;
61652610Storek
61752610Storek if (start < map->min_offset)
61852610Storek start = map->min_offset;
61952610Storek if (start > map->max_offset)
62052610Storek return (1);
62152610Storek
62252610Storek /*
62352610Storek * Look for the first possible address; if there's already
62452610Storek * something at this address, we have to start after it.
62552610Storek */
62652610Storek if (start == map->min_offset) {
62752610Storek if ((entry = map->first_free) != &map->header)
62852610Storek start = entry->end;
62952610Storek } else {
63052610Storek vm_map_entry_t tmp;
63152610Storek if (vm_map_lookup_entry(map, start, &tmp))
63252610Storek start = tmp->end;
63352610Storek entry = tmp;
63452610Storek }
63552610Storek
63652610Storek /*
63752610Storek * Look through the rest of the map, trying to fit a new region in
63852610Storek * the gap between existing regions, or after the very last region.
63952610Storek */
64052610Storek for (;; start = (entry = next)->end) {
64152610Storek /*
64252610Storek * Find the end of the proposed new region. Be sure we didn't
64352610Storek * go beyond the end of the map, or wrap around the address;
64452610Storek * if so, we lose. Otherwise, if this is the last entry, or
64552610Storek * if the proposed new region fits before the next entry, we
64652610Storek * win.
64752610Storek */
64852610Storek end = start + length;
64952610Storek if (end > map->max_offset || end < start)
65052610Storek return (1);
65152610Storek next = entry->next;
65252610Storek if (next == &map->header || next->start >= end)
65352610Storek break;
65452610Storek }
65552610Storek SAVE_HINT(map, entry);
65652610Storek *addr = start;
65752610Storek return (0);
65852610Storek }
65952610Storek
66052610Storek /*
66145748Smckusick * vm_map_find finds an unallocated region in the target address
66245748Smckusick * map with the given length. The search is defined to be
66345748Smckusick * first-fit from the specified address; the region found is
66445748Smckusick * returned in the same parameter.
66545748Smckusick *
66645748Smckusick */
66753357Sbostic int
vm_map_find(map,object,offset,addr,length,find_space)66845748Smckusick vm_map_find(map, object, offset, addr, length, find_space)
66945748Smckusick vm_map_t map;
67045748Smckusick vm_object_t object;
67145748Smckusick vm_offset_t offset;
67245748Smckusick vm_offset_t *addr; /* IN/OUT */
67345748Smckusick vm_size_t length;
67445748Smckusick boolean_t find_space;
67545748Smckusick {
67645748Smckusick register vm_offset_t start;
67745748Smckusick int result;
67845748Smckusick
67945748Smckusick start = *addr;
68045748Smckusick vm_map_lock(map);
68145748Smckusick if (find_space) {
68252610Storek if (vm_map_findspace(map, start, length, addr)) {
68345748Smckusick vm_map_unlock(map);
68445748Smckusick return (KERN_NO_SPACE);
68545748Smckusick }
68652610Storek start = *addr;
68745748Smckusick }
68845748Smckusick result = vm_map_insert(map, object, offset, start, start + length);
68945748Smckusick vm_map_unlock(map);
69052610Storek return (result);
69145748Smckusick }
69245748Smckusick
69345748Smckusick /*
69445748Smckusick * vm_map_simplify_entry: [ internal use only ]
69545748Smckusick *
69645748Smckusick * Simplify the given map entry by:
69745748Smckusick * removing extra sharing maps
69845748Smckusick * [XXX maybe later] merging with a neighbor
69945748Smckusick */
70068162Scgd void
vm_map_simplify_entry(map,entry)70168162Scgd vm_map_simplify_entry(map, entry)
70245748Smckusick vm_map_t map;
70345748Smckusick vm_map_entry_t entry;
70445748Smckusick {
70545748Smckusick #ifdef lint
70645748Smckusick map++;
70760345Storek #endif
70845748Smckusick
70945748Smckusick /*
71045748Smckusick * If this entry corresponds to a sharing map, then
71145748Smckusick * see if we can remove the level of indirection.
71245748Smckusick * If it's not a sharing map, then it points to
71345748Smckusick * a VM object, so see if we can merge with either
71445748Smckusick * of our neighbors.
71545748Smckusick */
71645748Smckusick
71745748Smckusick if (entry->is_sub_map)
71845748Smckusick return;
71945748Smckusick if (entry->is_a_map) {
72045748Smckusick #if 0
72145748Smckusick vm_map_t my_share_map;
72245748Smckusick int count;
72345748Smckusick
72445748Smckusick my_share_map = entry->object.share_map;
72545748Smckusick simple_lock(&my_share_map->ref_lock);
72645748Smckusick count = my_share_map->ref_count;
72745748Smckusick simple_unlock(&my_share_map->ref_lock);
72845748Smckusick
72945748Smckusick if (count == 1) {
73045748Smckusick /* Can move the region from
73145748Smckusick * entry->start to entry->end (+ entry->offset)
73245748Smckusick * in my_share_map into place of entry.
73345748Smckusick * Later.
73445748Smckusick */
73545748Smckusick }
73660345Storek #endif
73745748Smckusick }
73845748Smckusick else {
73945748Smckusick /*
74045748Smckusick * Try to merge with our neighbors.
74145748Smckusick *
74245748Smckusick * Conditions for merge are:
74345748Smckusick *
74445748Smckusick * 1. entries are adjacent.
74545748Smckusick * 2. both entries point to objects
74645748Smckusick * with null pagers.
74745748Smckusick *
74845748Smckusick * If a merge is possible, we replace the two
74945748Smckusick * entries with a single entry, then merge
75045748Smckusick * the two objects into a single object.
75145748Smckusick *
75245748Smckusick * Now, all that is left to do is write the
75345748Smckusick * code!
75445748Smckusick */
75545748Smckusick }
75645748Smckusick }
75745748Smckusick
75845748Smckusick /*
75945748Smckusick * vm_map_clip_start: [ internal use only ]
76045748Smckusick *
76145748Smckusick * Asserts that the given entry begins at or after
76245748Smckusick * the specified address; if necessary,
76345748Smckusick * it splits the entry into two.
76445748Smckusick */
76545748Smckusick #define vm_map_clip_start(map, entry, startaddr) \
76645748Smckusick { \
76745748Smckusick if (startaddr > entry->start) \
76845748Smckusick _vm_map_clip_start(map, entry, startaddr); \
76945748Smckusick }
77045748Smckusick
77145748Smckusick /*
77245748Smckusick * This routine is called only when it is known that
77345748Smckusick * the entry must be split.
77445748Smckusick */
77568162Scgd static void
_vm_map_clip_start(map,entry,start)77668162Scgd _vm_map_clip_start(map, entry, start)
77745748Smckusick register vm_map_t map;
77845748Smckusick register vm_map_entry_t entry;
77945748Smckusick register vm_offset_t start;
78045748Smckusick {
78145748Smckusick register vm_map_entry_t new_entry;
78245748Smckusick
78345748Smckusick /*
78445748Smckusick * See if we can simplify this entry first
78545748Smckusick */
78645748Smckusick
78745748Smckusick vm_map_simplify_entry(map, entry);
78845748Smckusick
78945748Smckusick /*
79045748Smckusick * Split off the front portion --
79145748Smckusick * note that we must insert the new
79245748Smckusick * entry BEFORE this one, so that
79345748Smckusick * this entry has the specified starting
79445748Smckusick * address.
79545748Smckusick */
79645748Smckusick
79745748Smckusick new_entry = vm_map_entry_create(map);
79845748Smckusick *new_entry = *entry;
79945748Smckusick
80045748Smckusick new_entry->end = start;
80145748Smckusick entry->offset += (start - entry->start);
80245748Smckusick entry->start = start;
80345748Smckusick
80445748Smckusick vm_map_entry_link(map, entry->prev, new_entry);
80545748Smckusick
80645748Smckusick if (entry->is_a_map || entry->is_sub_map)
80745748Smckusick vm_map_reference(new_entry->object.share_map);
80845748Smckusick else
80945748Smckusick vm_object_reference(new_entry->object.vm_object);
81045748Smckusick }
81145748Smckusick
81245748Smckusick /*
81345748Smckusick * vm_map_clip_end: [ internal use only ]
81445748Smckusick *
81545748Smckusick * Asserts that the given entry ends at or before
81645748Smckusick * the specified address; if necessary,
81745748Smckusick * it splits the entry into two.
81845748Smckusick */
81945748Smckusick
82045748Smckusick #define vm_map_clip_end(map, entry, endaddr) \
82145748Smckusick { \
82245748Smckusick if (endaddr < entry->end) \
82345748Smckusick _vm_map_clip_end(map, entry, endaddr); \
82445748Smckusick }
82545748Smckusick
82645748Smckusick /*
82745748Smckusick * This routine is called only when it is known that
82845748Smckusick * the entry must be split.
82945748Smckusick */
83068162Scgd static void
_vm_map_clip_end(map,entry,end)83168162Scgd _vm_map_clip_end(map, entry, end)
83245748Smckusick register vm_map_t map;
83345748Smckusick register vm_map_entry_t entry;
83445748Smckusick register vm_offset_t end;
83545748Smckusick {
83645748Smckusick register vm_map_entry_t new_entry;
83745748Smckusick
83845748Smckusick /*
83945748Smckusick * Create a new entry and insert it
84045748Smckusick * AFTER the specified entry
84145748Smckusick */
84245748Smckusick
84345748Smckusick new_entry = vm_map_entry_create(map);
84445748Smckusick *new_entry = *entry;
84545748Smckusick
84645748Smckusick new_entry->start = entry->end = end;
84745748Smckusick new_entry->offset += (end - entry->start);
84845748Smckusick
84945748Smckusick vm_map_entry_link(map, entry, new_entry);
85045748Smckusick
85145748Smckusick if (entry->is_a_map || entry->is_sub_map)
85245748Smckusick vm_map_reference(new_entry->object.share_map);
85345748Smckusick else
85445748Smckusick vm_object_reference(new_entry->object.vm_object);
85545748Smckusick }
85645748Smckusick
85745748Smckusick /*
85845748Smckusick * VM_MAP_RANGE_CHECK: [ internal use only ]
85945748Smckusick *
86045748Smckusick * Asserts that the starting and ending region
86145748Smckusick * addresses fall within the valid range of the map.
86245748Smckusick */
86345748Smckusick #define VM_MAP_RANGE_CHECK(map, start, end) \
86445748Smckusick { \
86545748Smckusick if (start < vm_map_min(map)) \
86645748Smckusick start = vm_map_min(map); \
86745748Smckusick if (end > vm_map_max(map)) \
86845748Smckusick end = vm_map_max(map); \
86945748Smckusick if (start > end) \
87045748Smckusick start = end; \
87145748Smckusick }
87245748Smckusick
87345748Smckusick /*
87445748Smckusick * vm_map_submap: [ kernel use only ]
87545748Smckusick *
87645748Smckusick * Mark the given range as handled by a subordinate map.
87745748Smckusick *
87845748Smckusick * This range must have been created with vm_map_find,
87945748Smckusick * and no other operations may have been performed on this
88045748Smckusick * range prior to calling vm_map_submap.
88145748Smckusick *
88245748Smckusick * Only a limited number of operations can be performed
88345748Smckusick * within this rage after calling vm_map_submap:
88445748Smckusick * vm_fault
88545748Smckusick * [Don't try vm_map_copy!]
88645748Smckusick *
88745748Smckusick * To remove a submapping, one must first remove the
88845748Smckusick * range from the superior map, and then destroy the
88945748Smckusick * submap (if desired). [Better yet, don't try it.]
89045748Smckusick */
89153357Sbostic int
vm_map_submap(map,start,end,submap)89245748Smckusick vm_map_submap(map, start, end, submap)
89345748Smckusick register vm_map_t map;
89445748Smckusick register vm_offset_t start;
89545748Smckusick register vm_offset_t end;
89645748Smckusick vm_map_t submap;
89745748Smckusick {
89845748Smckusick vm_map_entry_t entry;
89945748Smckusick register int result = KERN_INVALID_ARGUMENT;
90045748Smckusick
90145748Smckusick vm_map_lock(map);
90245748Smckusick
90345748Smckusick VM_MAP_RANGE_CHECK(map, start, end);
90445748Smckusick
90545748Smckusick if (vm_map_lookup_entry(map, start, &entry)) {
90645748Smckusick vm_map_clip_start(map, entry, start);
90745748Smckusick }
90845748Smckusick else
90945748Smckusick entry = entry->next;
91045748Smckusick
91145748Smckusick vm_map_clip_end(map, entry, end);
91245748Smckusick
91345748Smckusick if ((entry->start == start) && (entry->end == end) &&
91445748Smckusick (!entry->is_a_map) &&
91548383Skarels (entry->object.vm_object == NULL) &&
91645748Smckusick (!entry->copy_on_write)) {
91745748Smckusick entry->is_a_map = FALSE;
91845748Smckusick entry->is_sub_map = TRUE;
91945748Smckusick vm_map_reference(entry->object.sub_map = submap);
92045748Smckusick result = KERN_SUCCESS;
92145748Smckusick }
92245748Smckusick vm_map_unlock(map);
92345748Smckusick
92445748Smckusick return(result);
92545748Smckusick }
92645748Smckusick
92745748Smckusick /*
92845748Smckusick * vm_map_protect:
92945748Smckusick *
93045748Smckusick * Sets the protection of the specified address
93145748Smckusick * region in the target map. If "set_max" is
93245748Smckusick * specified, the maximum protection is to be set;
93345748Smckusick * otherwise, only the current protection is affected.
93445748Smckusick */
93553357Sbostic int
vm_map_protect(map,start,end,new_prot,set_max)93645748Smckusick vm_map_protect(map, start, end, new_prot, set_max)
93745748Smckusick register vm_map_t map;
93845748Smckusick register vm_offset_t start;
93945748Smckusick register vm_offset_t end;
94045748Smckusick register vm_prot_t new_prot;
94145748Smckusick register boolean_t set_max;
94245748Smckusick {
94345748Smckusick register vm_map_entry_t current;
94445748Smckusick vm_map_entry_t entry;
94545748Smckusick
94645748Smckusick vm_map_lock(map);
94745748Smckusick
94845748Smckusick VM_MAP_RANGE_CHECK(map, start, end);
94945748Smckusick
95045748Smckusick if (vm_map_lookup_entry(map, start, &entry)) {
95145748Smckusick vm_map_clip_start(map, entry, start);
95245748Smckusick }
95345748Smckusick else
95445748Smckusick entry = entry->next;
95545748Smckusick
95645748Smckusick /*
95745748Smckusick * Make a first pass to check for protection
95845748Smckusick * violations.
95945748Smckusick */
96045748Smckusick
96145748Smckusick current = entry;
96245748Smckusick while ((current != &map->header) && (current->start < end)) {
96345748Smckusick if (current->is_sub_map)
96445748Smckusick return(KERN_INVALID_ARGUMENT);
96545748Smckusick if ((new_prot & current->max_protection) != new_prot) {
96645748Smckusick vm_map_unlock(map);
96745748Smckusick return(KERN_PROTECTION_FAILURE);
96845748Smckusick }
96945748Smckusick
97045748Smckusick current = current->next;
97145748Smckusick }
97245748Smckusick
97345748Smckusick /*
97445748Smckusick * Go back and fix up protections.
97545748Smckusick * [Note that clipping is not necessary the second time.]
97645748Smckusick */
97745748Smckusick
97845748Smckusick current = entry;
97945748Smckusick
98045748Smckusick while ((current != &map->header) && (current->start < end)) {
98145748Smckusick vm_prot_t old_prot;
98245748Smckusick
98345748Smckusick vm_map_clip_end(map, current, end);
98445748Smckusick
98545748Smckusick old_prot = current->protection;
98645748Smckusick if (set_max)
98745748Smckusick current->protection =
98845748Smckusick (current->max_protection = new_prot) &
98945748Smckusick old_prot;
99045748Smckusick else
99145748Smckusick current->protection = new_prot;
99245748Smckusick
99345748Smckusick /*
99445748Smckusick * Update physical map if necessary.
99545748Smckusick * Worry about copy-on-write here -- CHECK THIS XXX
99645748Smckusick */
99745748Smckusick
99845748Smckusick if (current->protection != old_prot) {
99945748Smckusick
100045748Smckusick #define MASK(entry) ((entry)->copy_on_write ? ~VM_PROT_WRITE : \
100145748Smckusick VM_PROT_ALL)
100245748Smckusick #define max(a,b) ((a) > (b) ? (a) : (b))
100345748Smckusick
100445748Smckusick if (current->is_a_map) {
100545748Smckusick vm_map_entry_t share_entry;
100645748Smckusick vm_offset_t share_end;
100745748Smckusick
100845748Smckusick vm_map_lock(current->object.share_map);
100945748Smckusick (void) vm_map_lookup_entry(
101045748Smckusick current->object.share_map,
101145748Smckusick current->offset,
101245748Smckusick &share_entry);
101345748Smckusick share_end = current->offset +
101445748Smckusick (current->end - current->start);
101545748Smckusick while ((share_entry !=
101645748Smckusick ¤t->object.share_map->header) &&
101745748Smckusick (share_entry->start < share_end)) {
101845748Smckusick
101945748Smckusick pmap_protect(map->pmap,
102045748Smckusick (max(share_entry->start,
102145748Smckusick current->offset) -
102245748Smckusick current->offset +
102345748Smckusick current->start),
102445748Smckusick min(share_entry->end,
102545748Smckusick share_end) -
102645748Smckusick current->offset +
102745748Smckusick current->start,
102845748Smckusick current->protection &
102945748Smckusick MASK(share_entry));
103045748Smckusick
103145748Smckusick share_entry = share_entry->next;
103245748Smckusick }
103345748Smckusick vm_map_unlock(current->object.share_map);
103445748Smckusick }
103545748Smckusick else
103645748Smckusick pmap_protect(map->pmap, current->start,
103745748Smckusick current->end,
103845748Smckusick current->protection & MASK(entry));
103945748Smckusick #undef max
104045748Smckusick #undef MASK
104145748Smckusick }
104245748Smckusick current = current->next;
104345748Smckusick }
104445748Smckusick
104545748Smckusick vm_map_unlock(map);
104645748Smckusick return(KERN_SUCCESS);
104745748Smckusick }
104845748Smckusick
104945748Smckusick /*
105045748Smckusick * vm_map_inherit:
105145748Smckusick *
105245748Smckusick * Sets the inheritance of the specified address
105345748Smckusick * range in the target map. Inheritance
105445748Smckusick * affects how the map will be shared with
105545748Smckusick * child maps at the time of vm_map_fork.
105645748Smckusick */
105753357Sbostic int
vm_map_inherit(map,start,end,new_inheritance)105845748Smckusick vm_map_inherit(map, start, end, new_inheritance)
105945748Smckusick register vm_map_t map;
106045748Smckusick register vm_offset_t start;
106145748Smckusick register vm_offset_t end;
106245748Smckusick register vm_inherit_t new_inheritance;
106345748Smckusick {
106445748Smckusick register vm_map_entry_t entry;
106545748Smckusick vm_map_entry_t temp_entry;
106645748Smckusick
106745748Smckusick switch (new_inheritance) {
106845748Smckusick case VM_INHERIT_NONE:
106945748Smckusick case VM_INHERIT_COPY:
107045748Smckusick case VM_INHERIT_SHARE:
107145748Smckusick break;
107245748Smckusick default:
107345748Smckusick return(KERN_INVALID_ARGUMENT);
107445748Smckusick }
107545748Smckusick
107645748Smckusick vm_map_lock(map);
107745748Smckusick
107845748Smckusick VM_MAP_RANGE_CHECK(map, start, end);
107945748Smckusick
108045748Smckusick if (vm_map_lookup_entry(map, start, &temp_entry)) {
108145748Smckusick entry = temp_entry;
108245748Smckusick vm_map_clip_start(map, entry, start);
108345748Smckusick }
108445748Smckusick else
108545748Smckusick entry = temp_entry->next;
108645748Smckusick
108745748Smckusick while ((entry != &map->header) && (entry->start < end)) {
108845748Smckusick vm_map_clip_end(map, entry, end);
108945748Smckusick
109045748Smckusick entry->inheritance = new_inheritance;
109145748Smckusick
109245748Smckusick entry = entry->next;
109345748Smckusick }
109445748Smckusick
109545748Smckusick vm_map_unlock(map);
109645748Smckusick return(KERN_SUCCESS);
109745748Smckusick }
109845748Smckusick
109945748Smckusick /*
110045748Smckusick * vm_map_pageable:
110145748Smckusick *
110245748Smckusick * Sets the pageability of the specified address
110345748Smckusick * range in the target map. Regions specified
110445748Smckusick * as not pageable require locked-down physical
110545748Smckusick * memory and physical page maps.
110645748Smckusick *
110745748Smckusick * The map must not be locked, but a reference
110845748Smckusick * must remain to the map throughout the call.
110945748Smckusick */
111053357Sbostic int
vm_map_pageable(map,start,end,new_pageable)111145748Smckusick vm_map_pageable(map, start, end, new_pageable)
111245748Smckusick register vm_map_t map;
111345748Smckusick register vm_offset_t start;
111445748Smckusick register vm_offset_t end;
111545748Smckusick register boolean_t new_pageable;
111645748Smckusick {
111745748Smckusick register vm_map_entry_t entry;
111861005Shibler vm_map_entry_t start_entry;
111958596Shibler register vm_offset_t failed;
112058596Shibler int rv;
112145748Smckusick
112245748Smckusick vm_map_lock(map);
112345748Smckusick
112445748Smckusick VM_MAP_RANGE_CHECK(map, start, end);
112545748Smckusick
112645748Smckusick /*
112745748Smckusick * Only one pageability change may take place at one
112845748Smckusick * time, since vm_fault assumes it will be called
112945748Smckusick * only once for each wiring/unwiring. Therefore, we
113045748Smckusick * have to make sure we're actually changing the pageability
113145748Smckusick * for the entire region. We do so before making any changes.
113245748Smckusick */
113345748Smckusick
113461005Shibler if (vm_map_lookup_entry(map, start, &start_entry) == FALSE) {
113561005Shibler vm_map_unlock(map);
113661005Shibler return(KERN_INVALID_ADDRESS);
113745748Smckusick }
113861005Shibler entry = start_entry;
113945748Smckusick
114045748Smckusick /*
114145748Smckusick * Actions are rather different for wiring and unwiring,
114245748Smckusick * so we have two separate cases.
114345748Smckusick */
114445748Smckusick
114545748Smckusick if (new_pageable) {
114645748Smckusick
114761005Shibler vm_map_clip_start(map, entry, start);
114861005Shibler
114945748Smckusick /*
115045748Smckusick * Unwiring. First ensure that the range to be
115161005Shibler * unwired is really wired down and that there
115261005Shibler * are no holes.
115345748Smckusick */
115445748Smckusick while ((entry != &map->header) && (entry->start < end)) {
115545748Smckusick
115661005Shibler if (entry->wired_count == 0 ||
115761005Shibler (entry->end < end &&
115861005Shibler (entry->next == &map->header ||
115961005Shibler entry->next->start > entry->end))) {
116045748Smckusick vm_map_unlock(map);
116145748Smckusick return(KERN_INVALID_ARGUMENT);
116245748Smckusick }
116345748Smckusick entry = entry->next;
116445748Smckusick }
116545748Smckusick
116645748Smckusick /*
116745748Smckusick * Now decrement the wiring count for each region.
116845748Smckusick * If a region becomes completely unwired,
116945748Smckusick * unwire its physical pages and mappings.
117045748Smckusick */
117168795Smckusick vm_map_set_recursive(&map->lock);
117245748Smckusick
117361005Shibler entry = start_entry;
117445748Smckusick while ((entry != &map->header) && (entry->start < end)) {
117545748Smckusick vm_map_clip_end(map, entry, end);
117645748Smckusick
117745748Smckusick entry->wired_count--;
117845748Smckusick if (entry->wired_count == 0)
117945748Smckusick vm_fault_unwire(map, entry->start, entry->end);
118045748Smckusick
118145748Smckusick entry = entry->next;
118245748Smckusick }
118368795Smckusick vm_map_clear_recursive(&map->lock);
118445748Smckusick }
118545748Smckusick
118645748Smckusick else {
118745748Smckusick /*
118845748Smckusick * Wiring. We must do this in two passes:
118945748Smckusick *
119061005Shibler * 1. Holding the write lock, we create any shadow
119161005Shibler * or zero-fill objects that need to be created.
119261005Shibler * Then we clip each map entry to the region to be
119361005Shibler * wired and increment its wiring count. We
119461005Shibler * create objects before clipping the map entries
119561005Shibler * to avoid object proliferation.
119645748Smckusick *
119745748Smckusick * 2. We downgrade to a read lock, and call
119845748Smckusick * vm_fault_wire to fault in the pages for any
119945748Smckusick * newly wired area (wired_count is 1).
120045748Smckusick *
120145748Smckusick * Downgrading to a read lock for vm_fault_wire avoids
120245748Smckusick * a possible deadlock with another thread that may have
120345748Smckusick * faulted on one of the pages to be wired (it would mark
120445748Smckusick * the page busy, blocking us, then in turn block on the
120545748Smckusick * map lock that we hold). Because of problems in the
120645748Smckusick * recursive lock package, we cannot upgrade to a write
120745748Smckusick * lock in vm_map_lookup. Thus, any actions that require
120845748Smckusick * the write lock must be done beforehand. Because we
120945748Smckusick * keep the read lock on the map, the copy-on-write status
121045748Smckusick * of the entries we modify here cannot change.
121145748Smckusick */
121245748Smckusick
121345748Smckusick /*
121445748Smckusick * Pass 1.
121545748Smckusick */
121645748Smckusick while ((entry != &map->header) && (entry->start < end)) {
121761005Shibler if (entry->wired_count == 0) {
121845748Smckusick
121945748Smckusick /*
122045748Smckusick * Perform actions of vm_map_lookup that need
122145748Smckusick * the write lock on the map: create a shadow
122245748Smckusick * object for a copy-on-write region, or an
122345748Smckusick * object for a zero-fill region.
122445748Smckusick *
122545748Smckusick * We don't have to do this for entries that
122645748Smckusick * point to sharing maps, because we won't hold
122745748Smckusick * the lock on the sharing map.
122845748Smckusick */
122945748Smckusick if (!entry->is_a_map) {
123045748Smckusick if (entry->needs_copy &&
123145748Smckusick ((entry->protection & VM_PROT_WRITE) != 0)) {
123245748Smckusick
123345748Smckusick vm_object_shadow(&entry->object.vm_object,
123445748Smckusick &entry->offset,
123545748Smckusick (vm_size_t)(entry->end
123645748Smckusick - entry->start));
123745748Smckusick entry->needs_copy = FALSE;
123845748Smckusick }
123948383Skarels else if (entry->object.vm_object == NULL) {
124045748Smckusick entry->object.vm_object =
124145748Smckusick vm_object_allocate((vm_size_t)(entry->end
124245748Smckusick - entry->start));
124345748Smckusick entry->offset = (vm_offset_t)0;
124445748Smckusick }
124545748Smckusick }
124645748Smckusick }
124761005Shibler vm_map_clip_start(map, entry, start);
124861005Shibler vm_map_clip_end(map, entry, end);
124961005Shibler entry->wired_count++;
125045748Smckusick
125161005Shibler /*
125261005Shibler * Check for holes
125361005Shibler */
125461005Shibler if (entry->end < end &&
125561005Shibler (entry->next == &map->header ||
125661005Shibler entry->next->start > entry->end)) {
125761005Shibler /*
125861005Shibler * Found one. Object creation actions
125961005Shibler * do not need to be undone, but the
126061005Shibler * wired counts need to be restored.
126161005Shibler */
126261005Shibler while (entry != &map->header && entry->end > start) {
126361005Shibler entry->wired_count--;
126461005Shibler entry = entry->prev;
126561005Shibler }
126661005Shibler vm_map_unlock(map);
126761005Shibler return(KERN_INVALID_ARGUMENT);
126861005Shibler }
126945748Smckusick entry = entry->next;
127045748Smckusick }
127145748Smckusick
127245748Smckusick /*
127345748Smckusick * Pass 2.
127445748Smckusick */
127545748Smckusick
127645748Smckusick /*
127745748Smckusick * HACK HACK HACK HACK
127845748Smckusick *
127945748Smckusick * If we are wiring in the kernel map or a submap of it,
128045748Smckusick * unlock the map to avoid deadlocks. We trust that the
128145748Smckusick * kernel threads are well-behaved, and therefore will
128245748Smckusick * not do anything destructive to this region of the map
128345748Smckusick * while we have it unlocked. We cannot trust user threads
128445748Smckusick * to do the same.
128545748Smckusick *
128645748Smckusick * HACK HACK HACK HACK
128745748Smckusick */
128845748Smckusick if (vm_map_pmap(map) == kernel_pmap) {
128945748Smckusick vm_map_unlock(map); /* trust me ... */
129045748Smckusick }
129145748Smckusick else {
129268795Smckusick vm_map_set_recursive(&map->lock);
129369430Smckusick lockmgr(&map->lock, LK_DOWNGRADE, (void *)0, curproc);
129445748Smckusick }
129545748Smckusick
129658596Shibler rv = 0;
129761005Shibler entry = start_entry;
129845748Smckusick while (entry != &map->header && entry->start < end) {
129958596Shibler /*
130058596Shibler * If vm_fault_wire fails for any page we need to
130158596Shibler * undo what has been done. We decrement the wiring
130258596Shibler * count for those pages which have not yet been
130358596Shibler * wired (now) and unwire those that have (later).
130458596Shibler *
130558596Shibler * XXX this violates the locking protocol on the map,
130658596Shibler * needs to be fixed.
130758596Shibler */
130858596Shibler if (rv)
130958596Shibler entry->wired_count--;
131058596Shibler else if (entry->wired_count == 1) {
131158596Shibler rv = vm_fault_wire(map, entry->start, entry->end);
131258596Shibler if (rv) {
131358596Shibler failed = entry->start;
131458596Shibler entry->wired_count--;
131558596Shibler }
131645748Smckusick }
131745748Smckusick entry = entry->next;
131845748Smckusick }
131945748Smckusick
132045748Smckusick if (vm_map_pmap(map) == kernel_pmap) {
132145748Smckusick vm_map_lock(map);
132245748Smckusick }
132345748Smckusick else {
132468795Smckusick vm_map_clear_recursive(&map->lock);
132545748Smckusick }
132658596Shibler if (rv) {
132758596Shibler vm_map_unlock(map);
132858596Shibler (void) vm_map_pageable(map, start, failed, TRUE);
132958596Shibler return(rv);
133058596Shibler }
133145748Smckusick }
133245748Smckusick
133345748Smckusick vm_map_unlock(map);
133445748Smckusick
133545748Smckusick return(KERN_SUCCESS);
133645748Smckusick }
133745748Smckusick
133845748Smckusick /*
133965686Shibler * vm_map_clean
134065686Shibler *
134165686Shibler * Push any dirty cached pages in the address range to their pager.
134265686Shibler * If syncio is TRUE, dirty pages are written synchronously.
134365686Shibler * If invalidate is TRUE, any cached pages are freed as well.
134465686Shibler *
134565686Shibler * Returns an error if any part of the specified range is not mapped.
134665686Shibler */
134765686Shibler int
vm_map_clean(map,start,end,syncio,invalidate)134865686Shibler vm_map_clean(map, start, end, syncio, invalidate)
134965686Shibler vm_map_t map;
135065686Shibler vm_offset_t start;
135165686Shibler vm_offset_t end;
135265686Shibler boolean_t syncio;
135365686Shibler boolean_t invalidate;
135465686Shibler {
135565686Shibler register vm_map_entry_t current;
135665686Shibler vm_map_entry_t entry;
135765686Shibler vm_size_t size;
135865686Shibler vm_object_t object;
135965686Shibler vm_offset_t offset;
136065686Shibler
136165686Shibler vm_map_lock_read(map);
136265686Shibler VM_MAP_RANGE_CHECK(map, start, end);
136365686Shibler if (!vm_map_lookup_entry(map, start, &entry)) {
136465686Shibler vm_map_unlock_read(map);
136565686Shibler return(KERN_INVALID_ADDRESS);
136665686Shibler }
136765686Shibler
136865686Shibler /*
136965686Shibler * Make a first pass to check for holes.
137065686Shibler */
137165686Shibler for (current = entry; current->start < end; current = current->next) {
137265686Shibler if (current->is_sub_map) {
137365686Shibler vm_map_unlock_read(map);
137465686Shibler return(KERN_INVALID_ARGUMENT);
137565686Shibler }
137665686Shibler if (end > current->end &&
137765686Shibler (current->next == &map->header ||
137865686Shibler current->end != current->next->start)) {
137965686Shibler vm_map_unlock_read(map);
138065686Shibler return(KERN_INVALID_ADDRESS);
138165686Shibler }
138265686Shibler }
138365686Shibler
138465686Shibler /*
138565686Shibler * Make a second pass, cleaning/uncaching pages from the indicated
138665686Shibler * objects as we go.
138765686Shibler */
138865686Shibler for (current = entry; current->start < end; current = current->next) {
138965686Shibler offset = current->offset + (start - current->start);
139065686Shibler size = (end <= current->end ? end : current->end) - start;
139165686Shibler if (current->is_a_map) {
139265686Shibler register vm_map_t smap;
139365686Shibler vm_map_entry_t tentry;
139465686Shibler vm_size_t tsize;
139565686Shibler
139665686Shibler smap = current->object.share_map;
139765686Shibler vm_map_lock_read(smap);
139865686Shibler (void) vm_map_lookup_entry(smap, offset, &tentry);
139965686Shibler tsize = tentry->end - offset;
140065686Shibler if (tsize < size)
140165686Shibler size = tsize;
140265686Shibler object = tentry->object.vm_object;
140365686Shibler offset = tentry->offset + (offset - tentry->start);
140465686Shibler vm_object_lock(object);
140565686Shibler vm_map_unlock_read(smap);
140665686Shibler } else {
140765686Shibler object = current->object.vm_object;
140865686Shibler vm_object_lock(object);
140965686Shibler }
141065686Shibler /*
141165686Shibler * Flush pages if writing is allowed.
141265686Shibler * XXX should we continue on an error?
141365686Shibler */
141465686Shibler if ((current->protection & VM_PROT_WRITE) &&
141565686Shibler !vm_object_page_clean(object, offset, offset+size,
141665686Shibler syncio, FALSE)) {
141765686Shibler vm_object_unlock(object);
141865686Shibler vm_map_unlock_read(map);
141965686Shibler return(KERN_FAILURE);
142065686Shibler }
142165686Shibler if (invalidate)
142265686Shibler vm_object_page_remove(object, offset, offset+size);
142365686Shibler vm_object_unlock(object);
142465686Shibler start += size;
142565686Shibler }
142665686Shibler
142765686Shibler vm_map_unlock_read(map);
142865686Shibler return(KERN_SUCCESS);
142965686Shibler }
143065686Shibler
143165686Shibler /*
143245748Smckusick * vm_map_entry_unwire: [ internal use only ]
143345748Smckusick *
143445748Smckusick * Make the region specified by this entry pageable.
143545748Smckusick *
143645748Smckusick * The map in question should be locked.
143745748Smckusick * [This is the reason for this routine's existence.]
143845748Smckusick */
143968162Scgd void
vm_map_entry_unwire(map,entry)144068162Scgd vm_map_entry_unwire(map, entry)
144145748Smckusick vm_map_t map;
144245748Smckusick register vm_map_entry_t entry;
144345748Smckusick {
144445748Smckusick vm_fault_unwire(map, entry->start, entry->end);
144545748Smckusick entry->wired_count = 0;
144645748Smckusick }
144745748Smckusick
144845748Smckusick /*
144945748Smckusick * vm_map_entry_delete: [ internal use only ]
145045748Smckusick *
145145748Smckusick * Deallocate the given entry from the target map.
145245748Smckusick */
145368162Scgd void
vm_map_entry_delete(map,entry)145468162Scgd vm_map_entry_delete(map, entry)
145545748Smckusick register vm_map_t map;
145645748Smckusick register vm_map_entry_t entry;
145745748Smckusick {
145845748Smckusick if (entry->wired_count != 0)
145945748Smckusick vm_map_entry_unwire(map, entry);
146045748Smckusick
146145748Smckusick vm_map_entry_unlink(map, entry);
146245748Smckusick map->size -= entry->end - entry->start;
146345748Smckusick
146445748Smckusick if (entry->is_a_map || entry->is_sub_map)
146545748Smckusick vm_map_deallocate(entry->object.share_map);
146645748Smckusick else
146745748Smckusick vm_object_deallocate(entry->object.vm_object);
146845748Smckusick
146945748Smckusick vm_map_entry_dispose(map, entry);
147045748Smckusick }
147145748Smckusick
147245748Smckusick /*
147345748Smckusick * vm_map_delete: [ internal use only ]
147445748Smckusick *
147545748Smckusick * Deallocates the given address range from the target
147645748Smckusick * map.
147745748Smckusick *
147845748Smckusick * When called with a sharing map, removes pages from
147945748Smckusick * that region from all physical maps.
148045748Smckusick */
148153357Sbostic int
vm_map_delete(map,start,end)148245748Smckusick vm_map_delete(map, start, end)
148345748Smckusick register vm_map_t map;
148445748Smckusick vm_offset_t start;
148545748Smckusick register vm_offset_t end;
148645748Smckusick {
148745748Smckusick register vm_map_entry_t entry;
148845748Smckusick vm_map_entry_t first_entry;
148945748Smckusick
149045748Smckusick /*
149145748Smckusick * Find the start of the region, and clip it
149245748Smckusick */
149345748Smckusick
149445748Smckusick if (!vm_map_lookup_entry(map, start, &first_entry))
149545748Smckusick entry = first_entry->next;
149645748Smckusick else {
149745748Smckusick entry = first_entry;
149845748Smckusick vm_map_clip_start(map, entry, start);
149945748Smckusick
150045748Smckusick /*
150145748Smckusick * Fix the lookup hint now, rather than each
150245748Smckusick * time though the loop.
150345748Smckusick */
150445748Smckusick
150545748Smckusick SAVE_HINT(map, entry->prev);
150645748Smckusick }
150745748Smckusick
150845748Smckusick /*
150945748Smckusick * Save the free space hint
151045748Smckusick */
151145748Smckusick
151245748Smckusick if (map->first_free->start >= start)
151345748Smckusick map->first_free = entry->prev;
151445748Smckusick
151545748Smckusick /*
151645748Smckusick * Step through all entries in this region
151745748Smckusick */
151845748Smckusick
151945748Smckusick while ((entry != &map->header) && (entry->start < end)) {
152045748Smckusick vm_map_entry_t next;
152145748Smckusick register vm_offset_t s, e;
152245748Smckusick register vm_object_t object;
152345748Smckusick
152445748Smckusick vm_map_clip_end(map, entry, end);
152545748Smckusick
152645748Smckusick next = entry->next;
152745748Smckusick s = entry->start;
152845748Smckusick e = entry->end;
152945748Smckusick
153045748Smckusick /*
153145748Smckusick * Unwire before removing addresses from the pmap;
153245748Smckusick * otherwise, unwiring will put the entries back in
153345748Smckusick * the pmap.
153445748Smckusick */
153545748Smckusick
153645748Smckusick object = entry->object.vm_object;
153745748Smckusick if (entry->wired_count != 0)
153845748Smckusick vm_map_entry_unwire(map, entry);
153945748Smckusick
154045748Smckusick /*
154145748Smckusick * If this is a sharing map, we must remove
154245748Smckusick * *all* references to this data, since we can't
154345748Smckusick * find all of the physical maps which are sharing
154445748Smckusick * it.
154545748Smckusick */
154645748Smckusick
154745748Smckusick if (object == kernel_object || object == kmem_object)
154845748Smckusick vm_object_page_remove(object, entry->offset,
154945748Smckusick entry->offset + (e - s));
155045748Smckusick else if (!map->is_main_map)
155145748Smckusick vm_object_pmap_remove(object,
155245748Smckusick entry->offset,
155345748Smckusick entry->offset + (e - s));
155445748Smckusick else
155545748Smckusick pmap_remove(map->pmap, s, e);
155645748Smckusick
155745748Smckusick /*
155845748Smckusick * Delete the entry (which may delete the object)
155945748Smckusick * only after removing all pmap entries pointing
156045748Smckusick * to its pages. (Otherwise, its page frames may
156145748Smckusick * be reallocated, and any modify bits will be
156245748Smckusick * set in the wrong object!)
156345748Smckusick */
156445748Smckusick
156545748Smckusick vm_map_entry_delete(map, entry);
156645748Smckusick entry = next;
156745748Smckusick }
156845748Smckusick return(KERN_SUCCESS);
156945748Smckusick }
157045748Smckusick
157145748Smckusick /*
157245748Smckusick * vm_map_remove:
157345748Smckusick *
157445748Smckusick * Remove the given address range from the target map.
157545748Smckusick * This is the exported form of vm_map_delete.
157645748Smckusick */
157753357Sbostic int
vm_map_remove(map,start,end)157845748Smckusick vm_map_remove(map, start, end)
157945748Smckusick register vm_map_t map;
158045748Smckusick register vm_offset_t start;
158145748Smckusick register vm_offset_t end;
158245748Smckusick {
158345748Smckusick register int result;
158445748Smckusick
158545748Smckusick vm_map_lock(map);
158645748Smckusick VM_MAP_RANGE_CHECK(map, start, end);
158745748Smckusick result = vm_map_delete(map, start, end);
158845748Smckusick vm_map_unlock(map);
158945748Smckusick
159045748Smckusick return(result);
159145748Smckusick }
159245748Smckusick
159345748Smckusick /*
159445748Smckusick * vm_map_check_protection:
159545748Smckusick *
159645748Smckusick * Assert that the target map allows the specified
159745748Smckusick * privilege on the entire address region given.
159845748Smckusick * The entire region must be allocated.
159945748Smckusick */
160068162Scgd boolean_t
vm_map_check_protection(map,start,end,protection)160168162Scgd vm_map_check_protection(map, start, end, protection)
160245748Smckusick register vm_map_t map;
160345748Smckusick register vm_offset_t start;
160445748Smckusick register vm_offset_t end;
160545748Smckusick register vm_prot_t protection;
160645748Smckusick {
160745748Smckusick register vm_map_entry_t entry;
160845748Smckusick vm_map_entry_t tmp_entry;
160945748Smckusick
161045748Smckusick if (!vm_map_lookup_entry(map, start, &tmp_entry)) {
161145748Smckusick return(FALSE);
161245748Smckusick }
161345748Smckusick
161445748Smckusick entry = tmp_entry;
161545748Smckusick
161645748Smckusick while (start < end) {
161745748Smckusick if (entry == &map->header) {
161845748Smckusick return(FALSE);
161945748Smckusick }
162045748Smckusick
162145748Smckusick /*
162245748Smckusick * No holes allowed!
162345748Smckusick */
162445748Smckusick
162545748Smckusick if (start < entry->start) {
162645748Smckusick return(FALSE);
162745748Smckusick }
162845748Smckusick
162945748Smckusick /*
163045748Smckusick * Check protection associated with entry.
163145748Smckusick */
163245748Smckusick
163345748Smckusick if ((entry->protection & protection) != protection) {
163445748Smckusick return(FALSE);
163545748Smckusick }
163645748Smckusick
163745748Smckusick /* go to next entry */
163845748Smckusick
163945748Smckusick start = entry->end;
164045748Smckusick entry = entry->next;
164145748Smckusick }
164245748Smckusick return(TRUE);
164345748Smckusick }
164445748Smckusick
164545748Smckusick /*
164645748Smckusick * vm_map_copy_entry:
164745748Smckusick *
164845748Smckusick * Copies the contents of the source entry to the destination
164945748Smckusick * entry. The entries *must* be aligned properly.
165045748Smckusick */
165168162Scgd void
vm_map_copy_entry(src_map,dst_map,src_entry,dst_entry)165268162Scgd vm_map_copy_entry(src_map, dst_map, src_entry, dst_entry)
165345748Smckusick vm_map_t src_map, dst_map;
165445748Smckusick register vm_map_entry_t src_entry, dst_entry;
165545748Smckusick {
165645748Smckusick vm_object_t temp_object;
165745748Smckusick
165845748Smckusick if (src_entry->is_sub_map || dst_entry->is_sub_map)
165945748Smckusick return;
166045748Smckusick
166148383Skarels if (dst_entry->object.vm_object != NULL &&
166250919Smckusick (dst_entry->object.vm_object->flags & OBJ_INTERNAL) == 0)
166345748Smckusick printf("vm_map_copy_entry: copying over permanent data!\n");
166445748Smckusick
166545748Smckusick /*
166645748Smckusick * If our destination map was wired down,
166745748Smckusick * unwire it now.
166845748Smckusick */
166945748Smckusick
167045748Smckusick if (dst_entry->wired_count != 0)
167145748Smckusick vm_map_entry_unwire(dst_map, dst_entry);
167245748Smckusick
167345748Smckusick /*
167445748Smckusick * If we're dealing with a sharing map, we
167545748Smckusick * must remove the destination pages from
167645748Smckusick * all maps (since we cannot know which maps
167745748Smckusick * this sharing map belongs in).
167845748Smckusick */
167945748Smckusick
168045748Smckusick if (dst_map->is_main_map)
168145748Smckusick pmap_remove(dst_map->pmap, dst_entry->start, dst_entry->end);
168245748Smckusick else
168345748Smckusick vm_object_pmap_remove(dst_entry->object.vm_object,
168445748Smckusick dst_entry->offset,
168545748Smckusick dst_entry->offset +
168645748Smckusick (dst_entry->end - dst_entry->start));
168745748Smckusick
168845748Smckusick if (src_entry->wired_count == 0) {
168945748Smckusick
169045748Smckusick boolean_t src_needs_copy;
169145748Smckusick
169245748Smckusick /*
169345748Smckusick * If the source entry is marked needs_copy,
169445748Smckusick * it is already write-protected.
169545748Smckusick */
169645748Smckusick if (!src_entry->needs_copy) {
169745748Smckusick
169845748Smckusick boolean_t su;
169945748Smckusick
170045748Smckusick /*
170145748Smckusick * If the source entry has only one mapping,
170245748Smckusick * we can just protect the virtual address
170345748Smckusick * range.
170445748Smckusick */
170545748Smckusick if (!(su = src_map->is_main_map)) {
170645748Smckusick simple_lock(&src_map->ref_lock);
170745748Smckusick su = (src_map->ref_count == 1);
170845748Smckusick simple_unlock(&src_map->ref_lock);
170945748Smckusick }
171045748Smckusick
171145748Smckusick if (su) {
171245748Smckusick pmap_protect(src_map->pmap,
171345748Smckusick src_entry->start,
171445748Smckusick src_entry->end,
171545748Smckusick src_entry->protection & ~VM_PROT_WRITE);
171645748Smckusick }
171745748Smckusick else {
171845748Smckusick vm_object_pmap_copy(src_entry->object.vm_object,
171945748Smckusick src_entry->offset,
172045748Smckusick src_entry->offset + (src_entry->end
172145748Smckusick -src_entry->start));
172245748Smckusick }
172345748Smckusick }
172445748Smckusick
172545748Smckusick /*
172645748Smckusick * Make a copy of the object.
172745748Smckusick */
172845748Smckusick temp_object = dst_entry->object.vm_object;
172945748Smckusick vm_object_copy(src_entry->object.vm_object,
173045748Smckusick src_entry->offset,
173145748Smckusick (vm_size_t)(src_entry->end -
173245748Smckusick src_entry->start),
173345748Smckusick &dst_entry->object.vm_object,
173445748Smckusick &dst_entry->offset,
173545748Smckusick &src_needs_copy);
173645748Smckusick /*
173745748Smckusick * If we didn't get a copy-object now, mark the
173845748Smckusick * source map entry so that a shadow will be created
173945748Smckusick * to hold its changed pages.
174045748Smckusick */
174145748Smckusick if (src_needs_copy)
174245748Smckusick src_entry->needs_copy = TRUE;
174345748Smckusick
174445748Smckusick /*
174545748Smckusick * The destination always needs to have a shadow
174645748Smckusick * created.
174745748Smckusick */
174845748Smckusick dst_entry->needs_copy = TRUE;
174945748Smckusick
175045748Smckusick /*
175145748Smckusick * Mark the entries copy-on-write, so that write-enabling
175245748Smckusick * the entry won't make copy-on-write pages writable.
175345748Smckusick */
175445748Smckusick src_entry->copy_on_write = TRUE;
175545748Smckusick dst_entry->copy_on_write = TRUE;
175645748Smckusick /*
175745748Smckusick * Get rid of the old object.
175845748Smckusick */
175945748Smckusick vm_object_deallocate(temp_object);
176045748Smckusick
176145748Smckusick pmap_copy(dst_map->pmap, src_map->pmap, dst_entry->start,
176245748Smckusick dst_entry->end - dst_entry->start, src_entry->start);
176345748Smckusick }
176445748Smckusick else {
176545748Smckusick /*
176645748Smckusick * Of course, wired down pages can't be set copy-on-write.
176745748Smckusick * Cause wired pages to be copied into the new
176845748Smckusick * map by simulating faults (the new pages are
176945748Smckusick * pageable)
177045748Smckusick */
177145748Smckusick vm_fault_copy_entry(dst_map, src_map, dst_entry, src_entry);
177245748Smckusick }
177345748Smckusick }
177445748Smckusick
177545748Smckusick /*
177645748Smckusick * vm_map_copy:
177745748Smckusick *
177845748Smckusick * Perform a virtual memory copy from the source
177945748Smckusick * address map/range to the destination map/range.
178045748Smckusick *
178145748Smckusick * If src_destroy or dst_alloc is requested,
178245748Smckusick * the source and destination regions should be
178345748Smckusick * disjoint, not only in the top-level map, but
178445748Smckusick * in the sharing maps as well. [The best way
178545748Smckusick * to guarantee this is to use a new intermediate
178645748Smckusick * map to make copies. This also reduces map
178745748Smckusick * fragmentation.]
178845748Smckusick */
178953357Sbostic int
vm_map_copy(dst_map,src_map,dst_addr,len,src_addr,dst_alloc,src_destroy)179045748Smckusick vm_map_copy(dst_map, src_map,
179145748Smckusick dst_addr, len, src_addr,
179245748Smckusick dst_alloc, src_destroy)
179345748Smckusick vm_map_t dst_map;
179445748Smckusick vm_map_t src_map;
179545748Smckusick vm_offset_t dst_addr;
179645748Smckusick vm_size_t len;
179745748Smckusick vm_offset_t src_addr;
179845748Smckusick boolean_t dst_alloc;
179945748Smckusick boolean_t src_destroy;
180045748Smckusick {
180145748Smckusick register
180245748Smckusick vm_map_entry_t src_entry;
180345748Smckusick register
180445748Smckusick vm_map_entry_t dst_entry;
180545748Smckusick vm_map_entry_t tmp_entry;
180645748Smckusick vm_offset_t src_start;
180745748Smckusick vm_offset_t src_end;
180845748Smckusick vm_offset_t dst_start;
180945748Smckusick vm_offset_t dst_end;
181045748Smckusick vm_offset_t src_clip;
181145748Smckusick vm_offset_t dst_clip;
181245748Smckusick int result;
181345748Smckusick boolean_t old_src_destroy;
181445748Smckusick
181545748Smckusick /*
181645748Smckusick * XXX While we figure out why src_destroy screws up,
181745748Smckusick * we'll do it by explicitly vm_map_delete'ing at the end.
181845748Smckusick */
181945748Smckusick
182045748Smckusick old_src_destroy = src_destroy;
182145748Smckusick src_destroy = FALSE;
182245748Smckusick
182345748Smckusick /*
182445748Smckusick * Compute start and end of region in both maps
182545748Smckusick */
182645748Smckusick
182745748Smckusick src_start = src_addr;
182845748Smckusick src_end = src_start + len;
182945748Smckusick dst_start = dst_addr;
183045748Smckusick dst_end = dst_start + len;
183145748Smckusick
183245748Smckusick /*
183345748Smckusick * Check that the region can exist in both source
183445748Smckusick * and destination.
183545748Smckusick */
183645748Smckusick
183745748Smckusick if ((dst_end < dst_start) || (src_end < src_start))
183845748Smckusick return(KERN_NO_SPACE);
183945748Smckusick
184045748Smckusick /*
184145748Smckusick * Lock the maps in question -- we avoid deadlock
184245748Smckusick * by ordering lock acquisition by map value
184345748Smckusick */
184445748Smckusick
184545748Smckusick if (src_map == dst_map) {
184645748Smckusick vm_map_lock(src_map);
184745748Smckusick }
184868162Scgd else if ((long) src_map < (long) dst_map) {
184945748Smckusick vm_map_lock(src_map);
185045748Smckusick vm_map_lock(dst_map);
185145748Smckusick } else {
185245748Smckusick vm_map_lock(dst_map);
185345748Smckusick vm_map_lock(src_map);
185445748Smckusick }
185545748Smckusick
185645748Smckusick result = KERN_SUCCESS;
185745748Smckusick
185845748Smckusick /*
185945748Smckusick * Check protections... source must be completely readable and
186045748Smckusick * destination must be completely writable. [Note that if we're
186145748Smckusick * allocating the destination region, we don't have to worry
186245748Smckusick * about protection, but instead about whether the region
186345748Smckusick * exists.]
186445748Smckusick */
186545748Smckusick
186645748Smckusick if (src_map->is_main_map && dst_map->is_main_map) {
186745748Smckusick if (!vm_map_check_protection(src_map, src_start, src_end,
186845748Smckusick VM_PROT_READ)) {
186945748Smckusick result = KERN_PROTECTION_FAILURE;
187045748Smckusick goto Return;
187145748Smckusick }
187245748Smckusick
187345748Smckusick if (dst_alloc) {
187445748Smckusick /* XXX Consider making this a vm_map_find instead */
187548383Skarels if ((result = vm_map_insert(dst_map, NULL,
187645748Smckusick (vm_offset_t) 0, dst_start, dst_end)) != KERN_SUCCESS)
187745748Smckusick goto Return;
187845748Smckusick }
187945748Smckusick else if (!vm_map_check_protection(dst_map, dst_start, dst_end,
188045748Smckusick VM_PROT_WRITE)) {
188145748Smckusick result = KERN_PROTECTION_FAILURE;
188245748Smckusick goto Return;
188345748Smckusick }
188445748Smckusick }
188545748Smckusick
188645748Smckusick /*
188745748Smckusick * Find the start entries and clip.
188845748Smckusick *
188945748Smckusick * Note that checking protection asserts that the
189045748Smckusick * lookup cannot fail.
189145748Smckusick *
189245748Smckusick * Also note that we wait to do the second lookup
189345748Smckusick * until we have done the first clip, as the clip
189445748Smckusick * may affect which entry we get!
189545748Smckusick */
189645748Smckusick
189745748Smckusick (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry);
189845748Smckusick src_entry = tmp_entry;
189945748Smckusick vm_map_clip_start(src_map, src_entry, src_start);
190045748Smckusick
190145748Smckusick (void) vm_map_lookup_entry(dst_map, dst_addr, &tmp_entry);
190245748Smckusick dst_entry = tmp_entry;
190345748Smckusick vm_map_clip_start(dst_map, dst_entry, dst_start);
190445748Smckusick
190545748Smckusick /*
190645748Smckusick * If both source and destination entries are the same,
190745748Smckusick * retry the first lookup, as it may have changed.
190845748Smckusick */
190945748Smckusick
191045748Smckusick if (src_entry == dst_entry) {
191145748Smckusick (void) vm_map_lookup_entry(src_map, src_addr, &tmp_entry);
191245748Smckusick src_entry = tmp_entry;
191345748Smckusick }
191445748Smckusick
191545748Smckusick /*
191645748Smckusick * If source and destination entries are still the same,
191745748Smckusick * a null copy is being performed.
191845748Smckusick */
191945748Smckusick
192045748Smckusick if (src_entry == dst_entry)
192145748Smckusick goto Return;
192245748Smckusick
192345748Smckusick /*
192445748Smckusick * Go through entries until we get to the end of the
192545748Smckusick * region.
192645748Smckusick */
192745748Smckusick
192845748Smckusick while (src_start < src_end) {
192945748Smckusick /*
193045748Smckusick * Clip the entries to the endpoint of the entire region.
193145748Smckusick */
193245748Smckusick
193345748Smckusick vm_map_clip_end(src_map, src_entry, src_end);
193445748Smckusick vm_map_clip_end(dst_map, dst_entry, dst_end);
193545748Smckusick
193645748Smckusick /*
193745748Smckusick * Clip each entry to the endpoint of the other entry.
193845748Smckusick */
193945748Smckusick
194045748Smckusick src_clip = src_entry->start + (dst_entry->end - dst_entry->start);
194145748Smckusick vm_map_clip_end(src_map, src_entry, src_clip);
194245748Smckusick
194345748Smckusick dst_clip = dst_entry->start + (src_entry->end - src_entry->start);
194445748Smckusick vm_map_clip_end(dst_map, dst_entry, dst_clip);
194545748Smckusick
194645748Smckusick /*
194745748Smckusick * Both entries now match in size and relative endpoints.
194845748Smckusick *
194945748Smckusick * If both entries refer to a VM object, we can
195045748Smckusick * deal with them now.
195145748Smckusick */
195245748Smckusick
195345748Smckusick if (!src_entry->is_a_map && !dst_entry->is_a_map) {
195445748Smckusick vm_map_copy_entry(src_map, dst_map, src_entry,
195545748Smckusick dst_entry);
195645748Smckusick }
195745748Smckusick else {
195845748Smckusick register vm_map_t new_dst_map;
195945748Smckusick vm_offset_t new_dst_start;
196045748Smckusick vm_size_t new_size;
196145748Smckusick vm_map_t new_src_map;
196245748Smckusick vm_offset_t new_src_start;
196345748Smckusick
196445748Smckusick /*
196545748Smckusick * We have to follow at least one sharing map.
196645748Smckusick */
196745748Smckusick
196845748Smckusick new_size = (dst_entry->end - dst_entry->start);
196945748Smckusick
197045748Smckusick if (src_entry->is_a_map) {
197145748Smckusick new_src_map = src_entry->object.share_map;
197245748Smckusick new_src_start = src_entry->offset;
197345748Smckusick }
197445748Smckusick else {
197545748Smckusick new_src_map = src_map;
197645748Smckusick new_src_start = src_entry->start;
197768795Smckusick vm_map_set_recursive(&src_map->lock);
197845748Smckusick }
197945748Smckusick
198045748Smckusick if (dst_entry->is_a_map) {
198145748Smckusick vm_offset_t new_dst_end;
198245748Smckusick
198345748Smckusick new_dst_map = dst_entry->object.share_map;
198445748Smckusick new_dst_start = dst_entry->offset;
198545748Smckusick
198645748Smckusick /*
198745748Smckusick * Since the destination sharing entries
198845748Smckusick * will be merely deallocated, we can
198945748Smckusick * do that now, and replace the region
199045748Smckusick * with a null object. [This prevents
199145748Smckusick * splitting the source map to match
199245748Smckusick * the form of the destination map.]
199345748Smckusick * Note that we can only do so if the
199445748Smckusick * source and destination do not overlap.
199545748Smckusick */
199645748Smckusick
199745748Smckusick new_dst_end = new_dst_start + new_size;
199845748Smckusick
199945748Smckusick if (new_dst_map != new_src_map) {
200045748Smckusick vm_map_lock(new_dst_map);
200145748Smckusick (void) vm_map_delete(new_dst_map,
200245748Smckusick new_dst_start,
200345748Smckusick new_dst_end);
200445748Smckusick (void) vm_map_insert(new_dst_map,
200548383Skarels NULL,
200645748Smckusick (vm_offset_t) 0,
200745748Smckusick new_dst_start,
200845748Smckusick new_dst_end);
200945748Smckusick vm_map_unlock(new_dst_map);
201045748Smckusick }
201145748Smckusick }
201245748Smckusick else {
201345748Smckusick new_dst_map = dst_map;
201445748Smckusick new_dst_start = dst_entry->start;
201568795Smckusick vm_map_set_recursive(&dst_map->lock);
201645748Smckusick }
201745748Smckusick
201845748Smckusick /*
201945748Smckusick * Recursively copy the sharing map.
202045748Smckusick */
202145748Smckusick
202245748Smckusick (void) vm_map_copy(new_dst_map, new_src_map,
202345748Smckusick new_dst_start, new_size, new_src_start,
202445748Smckusick FALSE, FALSE);
202545748Smckusick
202645748Smckusick if (dst_map == new_dst_map)
202768795Smckusick vm_map_clear_recursive(&dst_map->lock);
202845748Smckusick if (src_map == new_src_map)
202968795Smckusick vm_map_clear_recursive(&src_map->lock);
203045748Smckusick }
203145748Smckusick
203245748Smckusick /*
203345748Smckusick * Update variables for next pass through the loop.
203445748Smckusick */
203545748Smckusick
203645748Smckusick src_start = src_entry->end;
203745748Smckusick src_entry = src_entry->next;
203845748Smckusick dst_start = dst_entry->end;
203945748Smckusick dst_entry = dst_entry->next;
204045748Smckusick
204145748Smckusick /*
204245748Smckusick * If the source is to be destroyed, here is the
204345748Smckusick * place to do it.
204445748Smckusick */
204545748Smckusick
204645748Smckusick if (src_destroy && src_map->is_main_map &&
204745748Smckusick dst_map->is_main_map)
204845748Smckusick vm_map_entry_delete(src_map, src_entry->prev);
204945748Smckusick }
205045748Smckusick
205145748Smckusick /*
205245748Smckusick * Update the physical maps as appropriate
205345748Smckusick */
205445748Smckusick
205545748Smckusick if (src_map->is_main_map && dst_map->is_main_map) {
205645748Smckusick if (src_destroy)
205745748Smckusick pmap_remove(src_map->pmap, src_addr, src_addr + len);
205845748Smckusick }
205945748Smckusick
206045748Smckusick /*
206145748Smckusick * Unlock the maps
206245748Smckusick */
206345748Smckusick
206445748Smckusick Return: ;
206545748Smckusick
206645748Smckusick if (old_src_destroy)
206745748Smckusick vm_map_delete(src_map, src_addr, src_addr + len);
206845748Smckusick
206945748Smckusick vm_map_unlock(src_map);
207045748Smckusick if (src_map != dst_map)
207145748Smckusick vm_map_unlock(dst_map);
207245748Smckusick
207345748Smckusick return(result);
207445748Smckusick }
207545748Smckusick
207645748Smckusick /*
207748383Skarels * vmspace_fork:
207848383Skarels * Create a new process vmspace structure and vm_map
207948383Skarels * based on those of an existing process. The new map
208048383Skarels * is based on the old map, according to the inheritance
208148383Skarels * values on the regions in that map.
208245748Smckusick *
208348383Skarels * The source map must not be locked.
208445748Smckusick */
208548383Skarels struct vmspace *
vmspace_fork(vm1)208648383Skarels vmspace_fork(vm1)
208748383Skarels register struct vmspace *vm1;
208845748Smckusick {
208948383Skarels register struct vmspace *vm2;
209048383Skarels vm_map_t old_map = &vm1->vm_map;
209145748Smckusick vm_map_t new_map;
209245748Smckusick vm_map_entry_t old_entry;
209345748Smckusick vm_map_entry_t new_entry;
209445748Smckusick pmap_t new_pmap;
209545748Smckusick
209645748Smckusick vm_map_lock(old_map);
209745748Smckusick
209848383Skarels vm2 = vmspace_alloc(old_map->min_offset, old_map->max_offset,
209948383Skarels old_map->entries_pageable);
210048383Skarels bcopy(&vm1->vm_startcopy, &vm2->vm_startcopy,
210148383Skarels (caddr_t) (vm1 + 1) - (caddr_t) &vm1->vm_startcopy);
210248383Skarels new_pmap = &vm2->vm_pmap; /* XXX */
210348383Skarels new_map = &vm2->vm_map; /* XXX */
210445748Smckusick
210545748Smckusick old_entry = old_map->header.next;
210645748Smckusick
210745748Smckusick while (old_entry != &old_map->header) {
210845748Smckusick if (old_entry->is_sub_map)
210945748Smckusick panic("vm_map_fork: encountered a submap");
211045748Smckusick
211145748Smckusick switch (old_entry->inheritance) {
211245748Smckusick case VM_INHERIT_NONE:
211345748Smckusick break;
211445748Smckusick
211545748Smckusick case VM_INHERIT_SHARE:
211645748Smckusick /*
211745748Smckusick * If we don't already have a sharing map:
211845748Smckusick */
211945748Smckusick
212045748Smckusick if (!old_entry->is_a_map) {
212145748Smckusick vm_map_t new_share_map;
212245748Smckusick vm_map_entry_t new_share_entry;
212345748Smckusick
212445748Smckusick /*
212545748Smckusick * Create a new sharing map
212645748Smckusick */
212745748Smckusick
212848383Skarels new_share_map = vm_map_create(NULL,
212945748Smckusick old_entry->start,
213045748Smckusick old_entry->end,
213145748Smckusick TRUE);
213245748Smckusick new_share_map->is_main_map = FALSE;
213345748Smckusick
213445748Smckusick /*
213545748Smckusick * Create the only sharing entry from the
213645748Smckusick * old task map entry.
213745748Smckusick */
213845748Smckusick
213945748Smckusick new_share_entry =
214045748Smckusick vm_map_entry_create(new_share_map);
214145748Smckusick *new_share_entry = *old_entry;
214261005Shibler new_share_entry->wired_count = 0;
214345748Smckusick
214445748Smckusick /*
214545748Smckusick * Insert the entry into the new sharing
214645748Smckusick * map
214745748Smckusick */
214845748Smckusick
214945748Smckusick vm_map_entry_link(new_share_map,
215045748Smckusick new_share_map->header.prev,
215145748Smckusick new_share_entry);
215245748Smckusick
215345748Smckusick /*
215445748Smckusick * Fix up the task map entry to refer
215545748Smckusick * to the sharing map now.
215645748Smckusick */
215745748Smckusick
215845748Smckusick old_entry->is_a_map = TRUE;
215945748Smckusick old_entry->object.share_map = new_share_map;
216045748Smckusick old_entry->offset = old_entry->start;
216145748Smckusick }
216245748Smckusick
216345748Smckusick /*
216445748Smckusick * Clone the entry, referencing the sharing map.
216545748Smckusick */
216645748Smckusick
216745748Smckusick new_entry = vm_map_entry_create(new_map);
216845748Smckusick *new_entry = *old_entry;
216961005Shibler new_entry->wired_count = 0;
217045748Smckusick vm_map_reference(new_entry->object.share_map);
217145748Smckusick
217245748Smckusick /*
217345748Smckusick * Insert the entry into the new map -- we
217445748Smckusick * know we're inserting at the end of the new
217545748Smckusick * map.
217645748Smckusick */
217745748Smckusick
217845748Smckusick vm_map_entry_link(new_map, new_map->header.prev,
217945748Smckusick new_entry);
218045748Smckusick
218145748Smckusick /*
218245748Smckusick * Update the physical map
218345748Smckusick */
218445748Smckusick
218545748Smckusick pmap_copy(new_map->pmap, old_map->pmap,
218645748Smckusick new_entry->start,
218745748Smckusick (old_entry->end - old_entry->start),
218845748Smckusick old_entry->start);
218945748Smckusick break;
219045748Smckusick
219145748Smckusick case VM_INHERIT_COPY:
219245748Smckusick /*
219345748Smckusick * Clone the entry and link into the map.
219445748Smckusick */
219545748Smckusick
219645748Smckusick new_entry = vm_map_entry_create(new_map);
219745748Smckusick *new_entry = *old_entry;
219845748Smckusick new_entry->wired_count = 0;
219948383Skarels new_entry->object.vm_object = NULL;
220045748Smckusick new_entry->is_a_map = FALSE;
220145748Smckusick vm_map_entry_link(new_map, new_map->header.prev,
220245748Smckusick new_entry);
220345748Smckusick if (old_entry->is_a_map) {
220445748Smckusick int check;
220545748Smckusick
220645748Smckusick check = vm_map_copy(new_map,
220745748Smckusick old_entry->object.share_map,
220845748Smckusick new_entry->start,
220945748Smckusick (vm_size_t)(new_entry->end -
221045748Smckusick new_entry->start),
221145748Smckusick old_entry->offset,
221245748Smckusick FALSE, FALSE);
221345748Smckusick if (check != KERN_SUCCESS)
221445748Smckusick printf("vm_map_fork: copy in share_map region failed\n");
221545748Smckusick }
221645748Smckusick else {
221745748Smckusick vm_map_copy_entry(old_map, new_map, old_entry,
221845748Smckusick new_entry);
221945748Smckusick }
222045748Smckusick break;
222145748Smckusick }
222245748Smckusick old_entry = old_entry->next;
222345748Smckusick }
222445748Smckusick
222545748Smckusick new_map->size = old_map->size;
222645748Smckusick vm_map_unlock(old_map);
222745748Smckusick
222848383Skarels return(vm2);
222945748Smckusick }
223045748Smckusick
223145748Smckusick /*
223245748Smckusick * vm_map_lookup:
223345748Smckusick *
223445748Smckusick * Finds the VM object, offset, and
223545748Smckusick * protection for a given virtual address in the
223645748Smckusick * specified map, assuming a page fault of the
223745748Smckusick * type specified.
223845748Smckusick *
223945748Smckusick * Leaves the map in question locked for read; return
224045748Smckusick * values are guaranteed until a vm_map_lookup_done
224145748Smckusick * call is performed. Note that the map argument
224245748Smckusick * is in/out; the returned map must be used in
224345748Smckusick * the call to vm_map_lookup_done.
224445748Smckusick *
224545748Smckusick * A handle (out_entry) is returned for use in
224645748Smckusick * vm_map_lookup_done, to make that fast.
224745748Smckusick *
224845748Smckusick * If a lookup is requested with "write protection"
224945748Smckusick * specified, the map may be changed to perform virtual
225045748Smckusick * copying operations, although the data referenced will
225145748Smckusick * remain the same.
225245748Smckusick */
225353357Sbostic int
vm_map_lookup(var_map,vaddr,fault_type,out_entry,object,offset,out_prot,wired,single_use)225445748Smckusick vm_map_lookup(var_map, vaddr, fault_type, out_entry,
225545748Smckusick object, offset, out_prot, wired, single_use)
225645748Smckusick vm_map_t *var_map; /* IN/OUT */
225745748Smckusick register vm_offset_t vaddr;
225845748Smckusick register vm_prot_t fault_type;
225945748Smckusick
226045748Smckusick vm_map_entry_t *out_entry; /* OUT */
226145748Smckusick vm_object_t *object; /* OUT */
226245748Smckusick vm_offset_t *offset; /* OUT */
226345748Smckusick vm_prot_t *out_prot; /* OUT */
226445748Smckusick boolean_t *wired; /* OUT */
226545748Smckusick boolean_t *single_use; /* OUT */
226645748Smckusick {
226745748Smckusick vm_map_t share_map;
226845748Smckusick vm_offset_t share_offset;
226945748Smckusick register vm_map_entry_t entry;
227045748Smckusick register vm_map_t map = *var_map;
227145748Smckusick register vm_prot_t prot;
227245748Smckusick register boolean_t su;
227345748Smckusick
227445748Smckusick RetryLookup: ;
227545748Smckusick
227645748Smckusick /*
227745748Smckusick * Lookup the faulting address.
227845748Smckusick */
227945748Smckusick
228045748Smckusick vm_map_lock_read(map);
228145748Smckusick
228245748Smckusick #define RETURN(why) \
228345748Smckusick { \
228445748Smckusick vm_map_unlock_read(map); \
228545748Smckusick return(why); \
228645748Smckusick }
228745748Smckusick
228845748Smckusick /*
228945748Smckusick * If the map has an interesting hint, try it before calling
229045748Smckusick * full blown lookup routine.
229145748Smckusick */
229245748Smckusick
229345748Smckusick simple_lock(&map->hint_lock);
229445748Smckusick entry = map->hint;
229545748Smckusick simple_unlock(&map->hint_lock);
229645748Smckusick
229745748Smckusick *out_entry = entry;
229845748Smckusick
229945748Smckusick if ((entry == &map->header) ||
230045748Smckusick (vaddr < entry->start) || (vaddr >= entry->end)) {
230145748Smckusick vm_map_entry_t tmp_entry;
230245748Smckusick
230345748Smckusick /*
230445748Smckusick * Entry was either not a valid hint, or the vaddr
230545748Smckusick * was not contained in the entry, so do a full lookup.
230645748Smckusick */
230745748Smckusick if (!vm_map_lookup_entry(map, vaddr, &tmp_entry))
230845748Smckusick RETURN(KERN_INVALID_ADDRESS);
230945748Smckusick
231045748Smckusick entry = tmp_entry;
231145748Smckusick *out_entry = entry;
231245748Smckusick }
231345748Smckusick
231445748Smckusick /*
231545748Smckusick * Handle submaps.
231645748Smckusick */
231745748Smckusick
231845748Smckusick if (entry->is_sub_map) {
231945748Smckusick vm_map_t old_map = map;
232045748Smckusick
232145748Smckusick *var_map = map = entry->object.sub_map;
232245748Smckusick vm_map_unlock_read(old_map);
232345748Smckusick goto RetryLookup;
232445748Smckusick }
232545748Smckusick
232645748Smckusick /*
232745748Smckusick * Check whether this task is allowed to have
232845748Smckusick * this page.
232945748Smckusick */
233045748Smckusick
233145748Smckusick prot = entry->protection;
233245748Smckusick if ((fault_type & (prot)) != fault_type)
233345748Smckusick RETURN(KERN_PROTECTION_FAILURE);
233445748Smckusick
233545748Smckusick /*
233645748Smckusick * If this page is not pageable, we have to get
233745748Smckusick * it for all possible accesses.
233845748Smckusick */
233945748Smckusick
234045748Smckusick if (*wired = (entry->wired_count != 0))
234145748Smckusick prot = fault_type = entry->protection;
234245748Smckusick
234345748Smckusick /*
234445748Smckusick * If we don't already have a VM object, track
234545748Smckusick * it down.
234645748Smckusick */
234745748Smckusick
234845748Smckusick if (su = !entry->is_a_map) {
234945748Smckusick share_map = map;
235045748Smckusick share_offset = vaddr;
235145748Smckusick }
235245748Smckusick else {
235345748Smckusick vm_map_entry_t share_entry;
235445748Smckusick
235545748Smckusick /*
235645748Smckusick * Compute the sharing map, and offset into it.
235745748Smckusick */
235845748Smckusick
235945748Smckusick share_map = entry->object.share_map;
236045748Smckusick share_offset = (vaddr - entry->start) + entry->offset;
236145748Smckusick
236245748Smckusick /*
236345748Smckusick * Look for the backing store object and offset
236445748Smckusick */
236545748Smckusick
236645748Smckusick vm_map_lock_read(share_map);
236745748Smckusick
236845748Smckusick if (!vm_map_lookup_entry(share_map, share_offset,
236945748Smckusick &share_entry)) {
237045748Smckusick vm_map_unlock_read(share_map);
237145748Smckusick RETURN(KERN_INVALID_ADDRESS);
237245748Smckusick }
237345748Smckusick entry = share_entry;
237445748Smckusick }
237545748Smckusick
237645748Smckusick /*
237745748Smckusick * If the entry was copy-on-write, we either ...
237845748Smckusick */
237945748Smckusick
238045748Smckusick if (entry->needs_copy) {
238145748Smckusick /*
238245748Smckusick * If we want to write the page, we may as well
238345748Smckusick * handle that now since we've got the sharing
238445748Smckusick * map locked.
238545748Smckusick *
238645748Smckusick * If we don't need to write the page, we just
238745748Smckusick * demote the permissions allowed.
238845748Smckusick */
238945748Smckusick
239045748Smckusick if (fault_type & VM_PROT_WRITE) {
239145748Smckusick /*
239245748Smckusick * Make a new object, and place it in the
239345748Smckusick * object chain. Note that no new references
239445748Smckusick * have appeared -- one just moved from the
239545748Smckusick * share map to the new object.
239645748Smckusick */
239745748Smckusick
239868938Smckusick if (lockmgr(&share_map->lock, LK_EXCLUPGRADE,
239969430Smckusick (void *)0, curproc)) {
240045748Smckusick if (share_map != map)
240145748Smckusick vm_map_unlock_read(map);
240245748Smckusick goto RetryLookup;
240345748Smckusick }
240445748Smckusick
240545748Smckusick vm_object_shadow(
240645748Smckusick &entry->object.vm_object,
240745748Smckusick &entry->offset,
240845748Smckusick (vm_size_t) (entry->end - entry->start));
240945748Smckusick
241045748Smckusick entry->needs_copy = FALSE;
241145748Smckusick
241268938Smckusick lockmgr(&share_map->lock, LK_DOWNGRADE,
241369430Smckusick (void *)0, curproc);
241445748Smckusick }
241545748Smckusick else {
241645748Smckusick /*
241745748Smckusick * We're attempting to read a copy-on-write
241845748Smckusick * page -- don't allow writes.
241945748Smckusick */
242045748Smckusick
242145748Smckusick prot &= (~VM_PROT_WRITE);
242245748Smckusick }
242345748Smckusick }
242445748Smckusick
242545748Smckusick /*
242645748Smckusick * Create an object if necessary.
242745748Smckusick */
242848383Skarels if (entry->object.vm_object == NULL) {
242945748Smckusick
243068938Smckusick if (lockmgr(&share_map->lock, LK_EXCLUPGRADE,
243169430Smckusick (void *)0, curproc)) {
243245748Smckusick if (share_map != map)
243345748Smckusick vm_map_unlock_read(map);
243445748Smckusick goto RetryLookup;
243545748Smckusick }
243645748Smckusick
243745748Smckusick entry->object.vm_object = vm_object_allocate(
243845748Smckusick (vm_size_t)(entry->end - entry->start));
243945748Smckusick entry->offset = 0;
244069430Smckusick lockmgr(&share_map->lock, LK_DOWNGRADE, (void *)0, curproc);
244145748Smckusick }
244245748Smckusick
244345748Smckusick /*
244445748Smckusick * Return the object/offset from this entry. If the entry
244545748Smckusick * was copy-on-write or empty, it has been fixed up.
244645748Smckusick */
244745748Smckusick
244845748Smckusick *offset = (share_offset - entry->start) + entry->offset;
244945748Smckusick *object = entry->object.vm_object;
245045748Smckusick
245145748Smckusick /*
245245748Smckusick * Return whether this is the only map sharing this data.
245345748Smckusick */
245445748Smckusick
245545748Smckusick if (!su) {
245645748Smckusick simple_lock(&share_map->ref_lock);
245745748Smckusick su = (share_map->ref_count == 1);
245845748Smckusick simple_unlock(&share_map->ref_lock);
245945748Smckusick }
246045748Smckusick
246145748Smckusick *out_prot = prot;
246245748Smckusick *single_use = su;
246345748Smckusick
246445748Smckusick return(KERN_SUCCESS);
246545748Smckusick
246645748Smckusick #undef RETURN
246745748Smckusick }
246845748Smckusick
246945748Smckusick /*
247045748Smckusick * vm_map_lookup_done:
247145748Smckusick *
247245748Smckusick * Releases locks acquired by a vm_map_lookup
247345748Smckusick * (according to the handle returned by that lookup).
247445748Smckusick */
247545748Smckusick
247668162Scgd void
vm_map_lookup_done(map,entry)247768162Scgd vm_map_lookup_done(map, entry)
247845748Smckusick register vm_map_t map;
247945748Smckusick vm_map_entry_t entry;
248045748Smckusick {
248145748Smckusick /*
248245748Smckusick * If this entry references a map, unlock it first.
248345748Smckusick */
248445748Smckusick
248545748Smckusick if (entry->is_a_map)
248645748Smckusick vm_map_unlock_read(entry->object.share_map);
248745748Smckusick
248845748Smckusick /*
248945748Smckusick * Unlock the main-level map
249045748Smckusick */
249145748Smckusick
249245748Smckusick vm_map_unlock_read(map);
249345748Smckusick }
249445748Smckusick
249545748Smckusick /*
249645748Smckusick * Routine: vm_map_simplify
249745748Smckusick * Purpose:
249845748Smckusick * Attempt to simplify the map representation in
249945748Smckusick * the vicinity of the given starting address.
250045748Smckusick * Note:
250145748Smckusick * This routine is intended primarily to keep the
250245748Smckusick * kernel maps more compact -- they generally don't
250345748Smckusick * benefit from the "expand a map entry" technology
250445748Smckusick * at allocation time because the adjacent entry
250545748Smckusick * is often wired down.
250645748Smckusick */
250768162Scgd void
vm_map_simplify(map,start)250868162Scgd vm_map_simplify(map, start)
250945748Smckusick vm_map_t map;
251045748Smckusick vm_offset_t start;
251145748Smckusick {
251245748Smckusick vm_map_entry_t this_entry;
251345748Smckusick vm_map_entry_t prev_entry;
251445748Smckusick
251545748Smckusick vm_map_lock(map);
251645748Smckusick if (
251745748Smckusick (vm_map_lookup_entry(map, start, &this_entry)) &&
251845748Smckusick ((prev_entry = this_entry->prev) != &map->header) &&
251945748Smckusick
252045748Smckusick (prev_entry->end == start) &&
252145748Smckusick (map->is_main_map) &&
252245748Smckusick
252345748Smckusick (prev_entry->is_a_map == FALSE) &&
252445748Smckusick (prev_entry->is_sub_map == FALSE) &&
252545748Smckusick
252645748Smckusick (this_entry->is_a_map == FALSE) &&
252745748Smckusick (this_entry->is_sub_map == FALSE) &&
252845748Smckusick
252945748Smckusick (prev_entry->inheritance == this_entry->inheritance) &&
253045748Smckusick (prev_entry->protection == this_entry->protection) &&
253145748Smckusick (prev_entry->max_protection == this_entry->max_protection) &&
253245748Smckusick (prev_entry->wired_count == this_entry->wired_count) &&
253345748Smckusick
253445748Smckusick (prev_entry->copy_on_write == this_entry->copy_on_write) &&
253545748Smckusick (prev_entry->needs_copy == this_entry->needs_copy) &&
253645748Smckusick
253745748Smckusick (prev_entry->object.vm_object == this_entry->object.vm_object) &&
253845748Smckusick ((prev_entry->offset + (prev_entry->end - prev_entry->start))
253945748Smckusick == this_entry->offset)
254045748Smckusick ) {
254145748Smckusick if (map->first_free == this_entry)
254245748Smckusick map->first_free = prev_entry;
254345748Smckusick
254445748Smckusick SAVE_HINT(map, prev_entry);
254545748Smckusick vm_map_entry_unlink(map, this_entry);
254645748Smckusick prev_entry->end = this_entry->end;
254745748Smckusick vm_object_deallocate(this_entry->object.vm_object);
254845748Smckusick vm_map_entry_dispose(map, this_entry);
254945748Smckusick }
255045748Smckusick vm_map_unlock(map);
255145748Smckusick }
255245748Smckusick
255345748Smckusick /*
255445748Smckusick * vm_map_print: [ debug ]
255545748Smckusick */
255668162Scgd void
vm_map_print(map,full)255768162Scgd vm_map_print(map, full)
255845748Smckusick register vm_map_t map;
255945748Smckusick boolean_t full;
256045748Smckusick {
256145748Smckusick register vm_map_entry_t entry;
256245748Smckusick extern int indent;
256345748Smckusick
256445748Smckusick iprintf("%s map 0x%x: pmap=0x%x,ref=%d,nentries=%d,version=%d\n",
256545748Smckusick (map->is_main_map ? "Task" : "Share"),
256645748Smckusick (int) map, (int) (map->pmap), map->ref_count, map->nentries,
256745748Smckusick map->timestamp);
256845748Smckusick
256945748Smckusick if (!full && indent)
257045748Smckusick return;
257145748Smckusick
257245748Smckusick indent += 2;
257345748Smckusick for (entry = map->header.next; entry != &map->header;
257445748Smckusick entry = entry->next) {
257545748Smckusick iprintf("map entry 0x%x: start=0x%x, end=0x%x, ",
257645748Smckusick (int) entry, (int) entry->start, (int) entry->end);
257745748Smckusick if (map->is_main_map) {
257845748Smckusick static char *inheritance_name[4] =
257945748Smckusick { "share", "copy", "none", "donate_copy"};
258045748Smckusick printf("prot=%x/%x/%s, ",
258145748Smckusick entry->protection,
258245748Smckusick entry->max_protection,
258345748Smckusick inheritance_name[entry->inheritance]);
258445748Smckusick if (entry->wired_count != 0)
258545748Smckusick printf("wired, ");
258645748Smckusick }
258745748Smckusick
258845748Smckusick if (entry->is_a_map || entry->is_sub_map) {
258945748Smckusick printf("share=0x%x, offset=0x%x\n",
259045748Smckusick (int) entry->object.share_map,
259145748Smckusick (int) entry->offset);
259245748Smckusick if ((entry->prev == &map->header) ||
259345748Smckusick (!entry->prev->is_a_map) ||
259445748Smckusick (entry->prev->object.share_map !=
259545748Smckusick entry->object.share_map)) {
259645748Smckusick indent += 2;
259745748Smckusick vm_map_print(entry->object.share_map, full);
259845748Smckusick indent -= 2;
259945748Smckusick }
260045748Smckusick
260145748Smckusick }
260245748Smckusick else {
260345748Smckusick printf("object=0x%x, offset=0x%x",
260445748Smckusick (int) entry->object.vm_object,
260545748Smckusick (int) entry->offset);
260645748Smckusick if (entry->copy_on_write)
260745748Smckusick printf(", copy (%s)",
260845748Smckusick entry->needs_copy ? "needed" : "done");
260945748Smckusick printf("\n");
261045748Smckusick
261145748Smckusick if ((entry->prev == &map->header) ||
261245748Smckusick (entry->prev->is_a_map) ||
261345748Smckusick (entry->prev->object.vm_object !=
261445748Smckusick entry->object.vm_object)) {
261545748Smckusick indent += 2;
261645748Smckusick vm_object_print(entry->object.vm_object, full);
261745748Smckusick indent -= 2;
261845748Smckusick }
261945748Smckusick }
262045748Smckusick }
262145748Smckusick indent -= 2;
262245748Smckusick }
2623