Annotation of kernel/vm/vm_map.c, revision 1.1

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

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.