Annotation of XNU/osfmk/vm/vm_kern.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  * @OSF_COPYRIGHT@
        !            24:  */
        !            25: /* 
        !            26:  * Mach Operating System
        !            27:  * Copyright (c) 1991,1990,1989,1988,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:  */
        !            52: /*
        !            53:  *     File:   vm/vm_kern.c
        !            54:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            55:  *     Date:   1985
        !            56:  *
        !            57:  *     Kernel memory management.
        !            58:  */
        !            59: 
        !            60: #include <cpus.h>
        !            61: #include <mach/kern_return.h>
        !            62: #include <mach/vm_param.h>
        !            63: #include <kern/assert.h>
        !            64: #include <kern/lock.h>
        !            65: #include <kern/thread.h>
        !            66: #include <vm/vm_kern.h>
        !            67: #include <vm/vm_map.h>
        !            68: #include <vm/vm_object.h>
        !            69: #include <vm/vm_page.h>
        !            70: #include <vm/vm_pageout.h>
        !            71: #include <kern/misc_protos.h>
        !            72: #include <vm/cpm.h>
        !            73: 
        !            74: #include <string.h>
        !            75: /*
        !            76:  *     Variables exported by this module.
        !            77:  */
        !            78: 
        !            79: vm_map_t       kernel_map;
        !            80: vm_map_t       kernel_pageable_map;
        !            81: 
        !            82: /*
        !            83:  * Forward declarations for internal functions.
        !            84:  */
        !            85: extern kern_return_t kmem_alloc_pages(
        !            86:        register vm_object_t    object,
        !            87:        register vm_offset_t    offset,
        !            88:        register vm_offset_t    start,
        !            89:        register vm_offset_t    end,
        !            90:        vm_prot_t               protection);
        !            91: 
        !            92: extern void kmem_remap_pages(
        !            93:        register vm_object_t    object,
        !            94:        register vm_offset_t    offset,
        !            95:        register vm_offset_t    start,
        !            96:        register vm_offset_t    end,
        !            97:        vm_prot_t               protection);
        !            98: 
        !            99: kern_return_t
        !           100: kmem_alloc_contig(
        !           101:        vm_map_t        map,
        !           102:        vm_offset_t     *addrp,
        !           103:        vm_size_t       size,
        !           104:        vm_offset_t     mask,
        !           105:        int             flags)
        !           106: {
        !           107:        vm_object_t             object;
        !           108:        vm_page_t               m, pages;
        !           109:        kern_return_t           kr;
        !           110:        vm_offset_t             addr, i, offset;
        !           111:        vm_map_entry_t          entry;
        !           112: 
        !           113:        if (map == VM_MAP_NULL || (flags && (flags ^ KMA_KOBJECT))) 
        !           114:                return KERN_INVALID_ARGUMENT;
        !           115:        
        !           116:        if (size == 0) {
        !           117:                *addrp = 0;
        !           118:                return KERN_INVALID_ARGUMENT;
        !           119:        }
        !           120: 
        !           121:        size = round_page(size);
        !           122:        if ((flags & KMA_KOBJECT) == 0) {
        !           123:                object = vm_object_allocate(size);
        !           124:                kr = vm_map_find_space(map, &addr, size, mask, &entry);
        !           125:        }
        !           126:        else {
        !           127:                object = kernel_object;
        !           128:                kr = vm_map_find_space(map, &addr, size, mask, &entry);
        !           129:        }
        !           130: 
        !           131:        if ((flags & KMA_KOBJECT) == 0) {
        !           132:                entry->object.vm_object = object;
        !           133:                entry->offset = offset = 0;
        !           134:        } else {
        !           135:                offset = addr - VM_MIN_KERNEL_ADDRESS;
        !           136: 
        !           137:                if (entry->object.vm_object == VM_OBJECT_NULL) {
        !           138:                        vm_object_reference(object);
        !           139:                        entry->object.vm_object = object;
        !           140:                        entry->offset = offset;
        !           141:                }
        !           142:        }
        !           143: 
        !           144:        if (kr != KERN_SUCCESS) {
        !           145:                if ((flags & KMA_KOBJECT) == 0)
        !           146:                        vm_object_deallocate(object);
        !           147:                return kr;
        !           148:        }
        !           149: 
        !           150:        vm_map_unlock(map);
        !           151: 
        !           152:        kr = cpm_allocate(size, &pages, FALSE);
        !           153: 
        !           154:        if (kr != KERN_SUCCESS) {
        !           155:                vm_map_remove(map, addr, addr + size, 0);
        !           156:                *addrp = 0;
        !           157:                return kr;
        !           158:        }
        !           159: 
        !           160:        vm_object_lock(object);
        !           161:        for (i = 0; i < size; i += PAGE_SIZE) {
        !           162:                m = pages;
        !           163:                pages = NEXT_PAGE(m);
        !           164:                m->busy = FALSE;
        !           165:                vm_page_insert(m, object, offset + i);
        !           166:        }
        !           167:        vm_object_unlock(object);
        !           168: 
        !           169:        if ((kr = vm_map_wire(map, addr, addr + size, VM_PROT_DEFAULT, FALSE)) 
        !           170:                != KERN_SUCCESS) {
        !           171:                if (object == kernel_object) {
        !           172:                        vm_object_lock(object);
        !           173:                        vm_object_page_remove(object, offset, offset + size);
        !           174:                        vm_object_unlock(object);
        !           175:                }
        !           176:                vm_map_remove(map, addr, addr + size, 0);
        !           177:                return kr;
        !           178:        }
        !           179:        if (object == kernel_object)
        !           180:                vm_map_simplify(map, addr);
        !           181: 
        !           182:        *addrp = addr;
        !           183:        return KERN_SUCCESS;
        !           184: }
        !           185: 
        !           186: /*
        !           187:  * Master entry point for allocating kernel memory.
        !           188:  * NOTE: this routine is _never_ interrupt safe.
        !           189:  *
        !           190:  * map         : map to allocate into
        !           191:  * addrp       : pointer to start address of new memory
        !           192:  * size                : size of memory requested
        !           193:  * flags       : options
        !           194:  *               KMA_HERE              *addrp is base address, else "anywhere"
        !           195:  *               KMA_NOPAGEWAIT        don't wait for pages if unavailable
        !           196:  *               KMA_KOBJECT           use kernel_object
        !           197:  */
        !           198: 
        !           199: kern_return_t
        !           200: kernel_memory_allocate(
        !           201:        register vm_map_t       map,
        !           202:        register vm_offset_t    *addrp,
        !           203:        register vm_size_t      size,
        !           204:        register vm_offset_t    mask,
        !           205:        int                     flags)
        !           206: {
        !           207:        vm_object_t object = VM_OBJECT_NULL;
        !           208:        vm_map_entry_t entry;
        !           209:        vm_offset_t offset;
        !           210:        vm_offset_t addr;
        !           211:        vm_offset_t i;
        !           212:        kern_return_t kr;
        !           213: 
        !           214:        size = round_page(size);
        !           215:        if ((flags & KMA_KOBJECT) == 0) {
        !           216:                /*
        !           217:                 *      Allocate a new object.  We must do this before locking
        !           218:                 *      the map, or risk deadlock with the default pager:
        !           219:                 *              device_read_alloc uses kmem_alloc,
        !           220:                 *              which tries to allocate an object,
        !           221:                 *              which uses kmem_alloc_wired to get memory,
        !           222:                 *              which blocks for pages.
        !           223:                 *              then the default pager needs to read a block
        !           224:                 *              to process a memory_object_data_write,
        !           225:                 *              and device_read_alloc calls kmem_alloc
        !           226:                 *              and deadlocks on the map lock.
        !           227:                 */
        !           228:                object = vm_object_allocate(size);
        !           229:                kr = vm_map_find_space(map, &addr, size, mask, &entry);
        !           230:        }
        !           231:        else {
        !           232:                object = kernel_object;
        !           233:                kr = vm_map_find_space(map, &addr, size, mask, &entry);
        !           234:        }
        !           235:        if (kr != KERN_SUCCESS) {
        !           236:                if ((flags & KMA_KOBJECT) == 0)
        !           237:                        vm_object_deallocate(object);
        !           238:                return kr;
        !           239:        }
        !           240: 
        !           241:        if ((flags & KMA_KOBJECT) == 0) {
        !           242:                entry->object.vm_object = object;
        !           243:                entry->offset = offset = 0;
        !           244:        } else {
        !           245:                offset = addr - VM_MIN_KERNEL_ADDRESS;
        !           246: 
        !           247:                if (entry->object.vm_object == VM_OBJECT_NULL) {
        !           248:                        vm_object_reference(object);
        !           249:                        entry->object.vm_object = object;
        !           250:                        entry->offset = offset;
        !           251:                }
        !           252:        }
        !           253: 
        !           254:        /*
        !           255:         *      Since we have not given out this address yet,
        !           256:         *      it is safe to unlock the map.
        !           257:         */
        !           258:        vm_map_unlock(map);
        !           259: 
        !           260:        vm_object_lock(object);
        !           261:        for (i = 0; i < size; i += PAGE_SIZE) {
        !           262:                vm_page_t       mem;
        !           263: 
        !           264:                while ((mem = vm_page_alloc(object, offset + i))
        !           265:                            == VM_PAGE_NULL) {
        !           266:                        if (flags & KMA_NOPAGEWAIT) {
        !           267:                                if (object == kernel_object)
        !           268:                                        vm_object_page_remove(object, offset,
        !           269:                                                offset + i);
        !           270:                                vm_object_unlock(object);
        !           271:                                vm_map_remove(map, addr, addr + size, 0);
        !           272:                                return KERN_RESOURCE_SHORTAGE;
        !           273:                        }
        !           274:                        vm_object_unlock(object);
        !           275:                        VM_PAGE_WAIT();
        !           276:                        vm_object_lock(object);
        !           277:                }
        !           278:                mem->busy = FALSE;
        !           279:        }
        !           280:        vm_object_unlock(object);
        !           281: 
        !           282:        if ((kr = vm_map_wire(map, addr, addr + size, VM_PROT_DEFAULT, FALSE)) 
        !           283:                != KERN_SUCCESS) {
        !           284:                if (object == kernel_object) {
        !           285:                        vm_object_lock(object);
        !           286:                        vm_object_page_remove(object, offset, offset + size);
        !           287:                        vm_object_unlock(object);
        !           288:                }
        !           289:                vm_map_remove(map, addr, addr + size, 0);
        !           290:                return (kr);
        !           291:        }
        !           292:        if (object == kernel_object)
        !           293:                vm_map_simplify(map, addr);
        !           294: 
        !           295:        /*
        !           296:         *      Return the memory, not zeroed.
        !           297:         */
        !           298: #if    (NCPUS > 1)  &&  i860
        !           299:        bzero( addr, size );
        !           300: #endif                                  /* #if (NCPUS > 1)  &&  i860 */
        !           301:        *addrp = addr;
        !           302:        return KERN_SUCCESS;
        !           303: }
        !           304: 
        !           305: /*
        !           306:  *     kmem_alloc:
        !           307:  *
        !           308:  *     Allocate wired-down memory in the kernel's address map
        !           309:  *     or a submap.  The memory is not zero-filled.
        !           310:  */
        !           311: 
        !           312: kern_return_t
        !           313: kmem_alloc(
        !           314:        vm_map_t        map,
        !           315:        vm_offset_t     *addrp,
        !           316:        vm_size_t       size)
        !           317: {
        !           318:        return kernel_memory_allocate(map, addrp, size, 0, 0);
        !           319: }
        !           320: 
        !           321: /*
        !           322:  *     kmem_realloc:
        !           323:  *
        !           324:  *     Reallocate wired-down memory in the kernel's address map
        !           325:  *     or a submap.  Newly allocated pages are not zeroed.
        !           326:  *     This can only be used on regions allocated with kmem_alloc.
        !           327:  *
        !           328:  *     If successful, the pages in the old region are mapped twice.
        !           329:  *     The old region is unchanged.  Use kmem_free to get rid of it.
        !           330:  */
        !           331: kern_return_t
        !           332: kmem_realloc(
        !           333:        vm_map_t        map,
        !           334:        vm_offset_t     oldaddr,
        !           335:        vm_size_t       oldsize,
        !           336:        vm_offset_t     *newaddrp,
        !           337:        vm_size_t       newsize)
        !           338: {
        !           339:        vm_offset_t oldmin, oldmax;
        !           340:        vm_offset_t newaddr;
        !           341:        vm_object_t object;
        !           342:        vm_map_entry_t oldentry, newentry;
        !           343:        kern_return_t kr;
        !           344: 
        !           345:        oldmin = trunc_page(oldaddr);
        !           346:        oldmax = round_page(oldaddr + oldsize);
        !           347:        oldsize = oldmax - oldmin;
        !           348:        newsize = round_page(newsize);
        !           349: 
        !           350:        /*
        !           351:         *      Find space for the new region.
        !           352:         */
        !           353: 
        !           354:        kr = vm_map_find_space(map, &newaddr, newsize, (vm_offset_t) 0,
        !           355:                               &newentry);
        !           356:        if (kr != KERN_SUCCESS) {
        !           357:                return kr;
        !           358:        }
        !           359: 
        !           360:        /*
        !           361:         *      Find the VM object backing the old region.
        !           362:         */
        !           363: 
        !           364:        if (!vm_map_lookup_entry(map, oldmin, &oldentry))
        !           365:                panic("kmem_realloc");
        !           366:        object = oldentry->object.vm_object;
        !           367: 
        !           368:        /*
        !           369:         *      Increase the size of the object and
        !           370:         *      fill in the new region.
        !           371:         */
        !           372: 
        !           373:        vm_object_reference(object);
        !           374:        vm_object_lock(object);
        !           375:        if (object->size != oldsize)
        !           376:                panic("kmem_realloc");
        !           377:        object->size = newsize;
        !           378:        vm_object_unlock(object);
        !           379: 
        !           380:        newentry->object.vm_object = object;
        !           381:        newentry->offset = 0;
        !           382:        assert (newentry->wired_count == 0);
        !           383:        newentry->wired_count = 1;
        !           384: 
        !           385:        /*
        !           386:         *      Since we have not given out this address yet,
        !           387:         *      it is safe to unlock the map.  We are trusting
        !           388:         *      that nobody will play with either region.
        !           389:         */
        !           390: 
        !           391:        vm_map_unlock(map);
        !           392: 
        !           393:        /*
        !           394:         *      Remap the pages in the old region and
        !           395:         *      allocate more pages for the new region.
        !           396:         */
        !           397: 
        !           398:        kmem_remap_pages(object, 0,
        !           399:                         newaddr, newaddr + oldsize,
        !           400:                         VM_PROT_DEFAULT);
        !           401:        kmem_alloc_pages(object, oldsize,
        !           402:                         newaddr + oldsize, newaddr + newsize,
        !           403:                         VM_PROT_DEFAULT);
        !           404: 
        !           405:        *newaddrp = newaddr;
        !           406:        return KERN_SUCCESS;
        !           407: }
        !           408: 
        !           409: /*
        !           410:  *     kmem_alloc_wired:
        !           411:  *
        !           412:  *     Allocate wired-down memory in the kernel's address map
        !           413:  *     or a submap.  The memory is not zero-filled.
        !           414:  *
        !           415:  *     The memory is allocated in the kernel_object.
        !           416:  *     It may not be copied with vm_map_copy, and
        !           417:  *     it may not be reallocated with kmem_realloc.
        !           418:  */
        !           419: 
        !           420: kern_return_t
        !           421: kmem_alloc_wired(
        !           422:        vm_map_t        map,
        !           423:        vm_offset_t     *addrp,
        !           424:        vm_size_t       size)
        !           425: {
        !           426:        return kernel_memory_allocate(map, addrp, size, 0, KMA_KOBJECT);
        !           427: }
        !           428: 
        !           429: /*
        !           430:  *     kmem_alloc_aligned:
        !           431:  *
        !           432:  *     Like kmem_alloc_wired, except that the memory is aligned.
        !           433:  *     The size should be a power-of-2.
        !           434:  */
        !           435: 
        !           436: kern_return_t
        !           437: kmem_alloc_aligned(
        !           438:        vm_map_t        map,
        !           439:        vm_offset_t     *addrp,
        !           440:        vm_size_t       size)
        !           441: {
        !           442:        if ((size & (size - 1)) != 0)
        !           443:                panic("kmem_alloc_aligned: size not aligned");
        !           444:        return kernel_memory_allocate(map, addrp, size, size - 1, KMA_KOBJECT);
        !           445: }
        !           446: 
        !           447: /*
        !           448:  *     kmem_alloc_pageable:
        !           449:  *
        !           450:  *     Allocate pageable memory in the kernel's address map.
        !           451:  */
        !           452: 
        !           453: kern_return_t
        !           454: kmem_alloc_pageable(
        !           455:        vm_map_t        map,
        !           456:        vm_offset_t     *addrp,
        !           457:        vm_size_t       size)
        !           458: {
        !           459:        vm_offset_t addr;
        !           460:        kern_return_t kr;
        !           461: 
        !           462:        addr = vm_map_min(map);
        !           463:        kr = vm_map_enter(map, &addr, round_page(size),
        !           464:                          (vm_offset_t) 0, TRUE,
        !           465:                          VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           466:                          VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
        !           467:        if (kr != KERN_SUCCESS)
        !           468:                return kr;
        !           469: 
        !           470:        *addrp = addr;
        !           471:        return KERN_SUCCESS;
        !           472: }
        !           473: 
        !           474: /*
        !           475:  *     kmem_free:
        !           476:  *
        !           477:  *     Release a region of kernel virtual memory allocated
        !           478:  *     with kmem_alloc, kmem_alloc_wired, or kmem_alloc_pageable,
        !           479:  *     and return the physical pages associated with that region.
        !           480:  */
        !           481: 
        !           482: void
        !           483: kmem_free(
        !           484:        vm_map_t        map,
        !           485:        vm_offset_t     addr,
        !           486:        vm_size_t       size)
        !           487: {
        !           488:        kern_return_t kr;
        !           489: 
        !           490:        kr = vm_map_remove(map, trunc_page(addr),
        !           491:                           round_page(addr + size), VM_MAP_REMOVE_KUNWIRE);
        !           492:        if (kr != KERN_SUCCESS)
        !           493:                panic("kmem_free");
        !           494: }
        !           495: 
        !           496: /*
        !           497:  *     Allocate new wired pages in an object.
        !           498:  *     The object is assumed to be mapped into the kernel map or
        !           499:  *     a submap.
        !           500:  */
        !           501: 
        !           502: kern_return_t
        !           503: kmem_alloc_pages(
        !           504:        register vm_object_t    object,
        !           505:        register vm_offset_t    offset,
        !           506:        register vm_offset_t    start,
        !           507:        register vm_offset_t    end,
        !           508:        vm_prot_t               protection)
        !           509: {
        !           510:        /*
        !           511:         *      Mark the pmap region as not pageable.
        !           512:         */
        !           513:        pmap_pageable(kernel_pmap, start, end, FALSE);
        !           514: 
        !           515:        while (start < end) {
        !           516:            register vm_page_t  mem;
        !           517: 
        !           518:            vm_object_lock(object);
        !           519: 
        !           520:            /*
        !           521:             *  Allocate a page
        !           522:             */
        !           523:            while ((mem = vm_page_alloc(object, offset))
        !           524:                         == VM_PAGE_NULL) {
        !           525:                vm_object_unlock(object);
        !           526:                VM_PAGE_WAIT();
        !           527:                vm_object_lock(object);
        !           528:            }
        !           529: 
        !           530:            /*
        !           531:             *  Wire it down
        !           532:             */
        !           533:            vm_page_lock_queues();
        !           534:            vm_page_wire(mem);
        !           535:            vm_page_unlock_queues();
        !           536:            vm_object_unlock(object);
        !           537: 
        !           538:            /*
        !           539:             *  Enter it in the kernel pmap
        !           540:             */
        !           541:            PMAP_ENTER(kernel_pmap, start, mem,
        !           542:                       protection, TRUE);
        !           543: 
        !           544:            vm_object_lock(object);
        !           545:            PAGE_WAKEUP_DONE(mem);
        !           546:            vm_object_unlock(object);
        !           547: 
        !           548:            start += PAGE_SIZE;
        !           549:            offset += PAGE_SIZE;
        !           550:        }
        !           551:        return KERN_SUCCESS;
        !           552: }
        !           553: 
        !           554: /*
        !           555:  *     Remap wired pages in an object into a new region.
        !           556:  *     The object is assumed to be mapped into the kernel map or
        !           557:  *     a submap.
        !           558:  */
        !           559: void
        !           560: kmem_remap_pages(
        !           561:        register vm_object_t    object,
        !           562:        register vm_offset_t    offset,
        !           563:        register vm_offset_t    start,
        !           564:        register vm_offset_t    end,
        !           565:        vm_prot_t               protection)
        !           566: {
        !           567:        /*
        !           568:         *      Mark the pmap region as not pageable.
        !           569:         */
        !           570:        pmap_pageable(kernel_pmap, start, end, FALSE);
        !           571: 
        !           572:        while (start < end) {
        !           573:            register vm_page_t  mem;
        !           574: 
        !           575:            vm_object_lock(object);
        !           576: 
        !           577:            /*
        !           578:             *  Find a page
        !           579:             */
        !           580:            if ((mem = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
        !           581:                panic("kmem_remap_pages");
        !           582: 
        !           583:            /*
        !           584:             *  Wire it down (again)
        !           585:             */
        !           586:            vm_page_lock_queues();
        !           587:            vm_page_wire(mem);
        !           588:            vm_page_unlock_queues();
        !           589:            vm_object_unlock(object);
        !           590: 
        !           591:            /*
        !           592:             *  Enter it in the kernel pmap.  The page isn't busy,
        !           593:             *  but this shouldn't be a problem because it is wired.
        !           594:             */
        !           595:            PMAP_ENTER(kernel_pmap, start, mem,
        !           596:                       protection, TRUE);
        !           597: 
        !           598:            start += PAGE_SIZE;
        !           599:            offset += PAGE_SIZE;
        !           600:        }
        !           601: }
        !           602: 
        !           603: /*
        !           604:  *     kmem_suballoc:
        !           605:  *
        !           606:  *     Allocates a map to manage a subrange
        !           607:  *     of the kernel virtual address space.
        !           608:  *
        !           609:  *     Arguments are as follows:
        !           610:  *
        !           611:  *     parent          Map to take range from
        !           612:  *     addr            Address of start of range (IN/OUT)
        !           613:  *     size            Size of range to find
        !           614:  *     pageable        Can region be paged
        !           615:  *     anywhere        Can region be located anywhere in map
        !           616:  *     new_map         Pointer to new submap
        !           617:  */
        !           618: kern_return_t
        !           619: kmem_suballoc(
        !           620:        vm_map_t        parent,
        !           621:        vm_offset_t     *addr,
        !           622:        vm_size_t       size,
        !           623:        boolean_t       pageable,
        !           624:        boolean_t       anywhere,
        !           625:        vm_map_t        *new_map)
        !           626: {
        !           627:        vm_map_t map;
        !           628:        kern_return_t kr;
        !           629: 
        !           630:        size = round_page(size);
        !           631: 
        !           632:        /*
        !           633:         *      Need reference on submap object because it is internal
        !           634:         *      to the vm_system.  vm_object_enter will never be called
        !           635:         *      on it (usual source of reference for vm_map_enter).
        !           636:         */
        !           637:        vm_object_reference(vm_submap_object);
        !           638: 
        !           639:        if (anywhere == TRUE)
        !           640:                *addr = (vm_offset_t)vm_map_min(parent);
        !           641:        kr = vm_map_enter(parent, addr, size,
        !           642:                          (vm_offset_t) 0, anywhere,
        !           643:                          vm_submap_object, (vm_offset_t) 0, FALSE,
        !           644:                          VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
        !           645:        if (kr != KERN_SUCCESS) {
        !           646:                vm_object_deallocate(vm_submap_object);
        !           647:                return (kr);
        !           648:        }
        !           649: 
        !           650:        pmap_reference(vm_map_pmap(parent));
        !           651:        map = vm_map_create(vm_map_pmap(parent), *addr, *addr + size, pageable);
        !           652:        if (map == VM_MAP_NULL)
        !           653:                panic("kmem_suballoc: vm_map_create failed");   /* "can't happen" */
        !           654: 
        !           655:        kr = vm_map_submap(parent, *addr, *addr + size, map, *addr);
        !           656:        if (kr != KERN_SUCCESS) {
        !           657:                /*
        !           658:                 * See comment preceding vm_map_submap().
        !           659:                 */
        !           660:                vm_map_remove(parent, *addr, *addr + size, VM_MAP_NO_FLAGS);
        !           661:                vm_map_deallocate(map); /* also removes ref to pmap */
        !           662:                vm_object_deallocate(vm_submap_object);
        !           663:                return (kr);
        !           664:        }
        !           665: 
        !           666:        *new_map = map;
        !           667:        return (KERN_SUCCESS);
        !           668: }
        !           669: 
        !           670: /*
        !           671:  *     kmem_init:
        !           672:  *
        !           673:  *     Initialize the kernel's virtual memory map, taking
        !           674:  *     into account all memory allocated up to this time.
        !           675:  */
        !           676: void
        !           677: kmem_init(
        !           678:        vm_offset_t     start,
        !           679:        vm_offset_t     end)
        !           680: {
        !           681:        kernel_map = vm_map_create(pmap_kernel(),
        !           682:                                   VM_MIN_KERNEL_ADDRESS, end,
        !           683:                                   FALSE);
        !           684: 
        !           685:        /*
        !           686:         *      Reserve virtual memory allocated up to this time.
        !           687:         */
        !           688: 
        !           689:        if (start != VM_MIN_KERNEL_ADDRESS) {
        !           690:                vm_offset_t addr = VM_MIN_KERNEL_ADDRESS;
        !           691:                (void) vm_map_enter(kernel_map,
        !           692:                                    &addr, start - VM_MIN_KERNEL_ADDRESS,
        !           693:                                    (vm_offset_t) 0, TRUE,
        !           694:                                    VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           695:                                    VM_PROT_DEFAULT, VM_PROT_ALL,
        !           696:                                    VM_INHERIT_DEFAULT);
        !           697:        }
        !           698: 
        !           699:         /*
        !           700:          * Account for kernel memory (text, data, bss, vm shenanigans).
        !           701:          * This may include inaccessible "holes" as determined by what
        !           702:          * the machine-dependent init code includes in mem_size.
        !           703:          */
        !           704:         vm_page_wire_count = (atop(mem_size) - (vm_page_free_count
        !           705:                                                 + vm_page_active_count
        !           706:                                                 + vm_page_inactive_count));
        !           707: }
        !           708: 
        !           709: /*
        !           710:  *     kmem_io_map_copyout:
        !           711:  *
        !           712:  *     Establish temporary mapping in designated map for the memory
        !           713:  *     passed in.  Memory format must be a page_list vm_map_copy.
        !           714:  */
        !           715: 
        !           716: kern_return_t
        !           717: kmem_io_map_copyout(
        !           718:        vm_map_t        map,
        !           719:        vm_offset_t     *addr,          /* actual addr of data */
        !           720:        vm_size_t       *alloc_size,    /* size allocated */
        !           721:        vm_map_copy_t   copy,
        !           722:        vm_size_t       min_size,       /* Do at least this much */
        !           723:        vm_prot_t       prot)           /* Protection of mapping */
        !           724: {
        !           725:        vm_offset_t     myaddr, offset;
        !           726:        vm_size_t       mysize, copy_size;
        !           727:        kern_return_t   ret;
        !           728:        register
        !           729:        vm_page_t       *page_list;
        !           730:        vm_map_copy_t   new_copy;
        !           731:        register
        !           732:        int             i;
        !           733: 
        !           734:        assert(copy->type == VM_MAP_COPY_PAGE_LIST);
        !           735:        assert(min_size != 0);
        !           736: 
        !           737:        /*
        !           738:         *      Figure out the size in vm pages.
        !           739:         */
        !           740:        min_size += copy->offset - trunc_page(copy->offset);
        !           741:        min_size = round_page(min_size);
        !           742:        mysize = round_page(copy->offset + copy->size) -
        !           743:                trunc_page(copy->offset);
        !           744: 
        !           745:        /*
        !           746:         *      If total size is larger than one page list and
        !           747:         *      we don't have to do more than one page list, then
        !           748:         *      only do one page list.  
        !           749:         *
        !           750:         * XXX  Could be much smarter about this ... like trimming length
        !           751:         * XXX  if we need more than one page list but not all of them.
        !           752:         */
        !           753: 
        !           754:        copy_size = ptoa(copy->cpy_npages);
        !           755:        if (mysize > copy_size && copy_size > min_size)
        !           756:                mysize = copy_size;
        !           757: 
        !           758:        /*
        !           759:         *      Allocate some address space in the map (must be kernel
        !           760:         *      space).
        !           761:         */
        !           762:        myaddr = vm_map_min(map);
        !           763:        ret = vm_map_enter(map, &myaddr, mysize,
        !           764:                          (vm_offset_t) 0, TRUE,
        !           765:                          VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           766:                          prot, prot, VM_INHERIT_DEFAULT);
        !           767: 
        !           768:        if (ret != KERN_SUCCESS)
        !           769:                return(ret);
        !           770: 
        !           771:        /*
        !           772:         *      Tell the pmap module that this will be wired, and
        !           773:         *      enter the mappings.
        !           774:         */
        !           775:        pmap_pageable(vm_map_pmap(map), myaddr, myaddr + mysize, TRUE);
        !           776: 
        !           777:        *addr = myaddr + (copy->offset - trunc_page(copy->offset));
        !           778:        *alloc_size = mysize;
        !           779: 
        !           780:        offset = myaddr;
        !           781:        page_list = &copy->cpy_page_list[0];
        !           782:        while (TRUE) {
        !           783:                for ( i = 0; i < copy->cpy_npages; i++, offset += PAGE_SIZE) {
        !           784:                        PMAP_ENTER(vm_map_pmap(map), offset, *page_list,
        !           785:                                   prot, TRUE);
        !           786:                        page_list++;
        !           787:                }
        !           788: 
        !           789:                if (offset == (myaddr + mysize))
        !           790:                        break;
        !           791: 
        !           792:                /*
        !           793:                 *      Onward to the next page_list.  The extend_cont
        !           794:                 *      leaves the current page list's pages alone; 
        !           795:                 *      they'll be cleaned up at discard.  Reset this
        !           796:                 *      copy's continuation to discard the next one.
        !           797:                 */
        !           798:                vm_map_copy_invoke_extend_cont(copy, &new_copy, &ret);
        !           799: 
        !           800:                if (ret != KERN_SUCCESS) {
        !           801:                        kmem_io_map_deallocate(map, myaddr, mysize);
        !           802:                        return(ret);
        !           803:                }
        !           804:                copy->cpy_cont = vm_map_copy_discard_cont;
        !           805:                copy->cpy_cont_args = (vm_map_copyin_args_t) new_copy;
        !           806:                assert(new_copy != VM_MAP_COPY_NULL);
        !           807:                assert(new_copy->type == VM_MAP_COPY_PAGE_LIST);
        !           808:                copy = new_copy;
        !           809:                page_list = &copy->cpy_page_list[0];
        !           810:        }
        !           811: 
        !           812:        return(ret);
        !           813: }
        !           814: 
        !           815: /*
        !           816:  *     kmem_io_map_deallocate:
        !           817:  *
        !           818:  *     Get rid of the mapping established by kmem_io_map_copyout.
        !           819:  *     Assumes that addr and size have been rounded to page boundaries.
        !           820:  */
        !           821: 
        !           822: void
        !           823: kmem_io_map_deallocate(
        !           824:        vm_map_t        map,
        !           825:        vm_offset_t     addr,
        !           826:        vm_size_t       size)
        !           827: {
        !           828: 
        !           829:        register vm_offset_t    va, end;
        !           830: 
        !           831:        end = round_page(addr + size);
        !           832:        for (va = trunc_page(addr); va < end; va += PAGE_SIZE)
        !           833:            pmap_change_wiring(vm_map_pmap(map), va, FALSE);
        !           834: 
        !           835:        /*
        !           836:         *      Remove the mappings.  The pmap_remove is needed.
        !           837:         */
        !           838:        
        !           839:        pmap_remove(vm_map_pmap(map), addr, addr + size);
        !           840:        vm_map_remove(map, addr, addr + size, VM_MAP_REMOVE_KUNWIRE);
        !           841: }
        !           842: 
        !           843: 
        !           844: /*
        !           845:  *     kmem_io_object_trunc:
        !           846:  *
        !           847:  *     Truncate an object vm_map_copy_t.
        !           848:  *     Called by the scatter/gather list network code to remove pages from
        !           849:  *     the tail end of a packet. Also unwires the objects pages.
        !           850:  */
        !           851: 
        !           852: kern_return_t
        !           853: kmem_io_object_trunc(copy, new_size)
        !           854:      vm_map_copy_t     copy;           /* IN/OUT copy object */
        !           855:      register vm_size_t new_size;      /* IN new object size */
        !           856: {
        !           857:        register vm_size_t      offset, old_size;
        !           858: 
        !           859:        assert(copy->type == VM_MAP_COPY_OBJECT);
        !           860: 
        !           861:        old_size = round_page(copy->size);
        !           862:        copy->size = new_size;
        !           863:        new_size = round_page(new_size);
        !           864: 
        !           865:         vm_object_lock(copy->cpy_object);
        !           866:         vm_object_page_remove(copy->cpy_object,
        !           867:                               (vm_offset_t)new_size, (vm_offset_t)old_size);
        !           868:         for (offset = 0; offset < new_size; offset += PAGE_SIZE) {
        !           869:                register vm_page_t      mem;
        !           870: 
        !           871:                if ((mem = vm_page_lookup(copy->cpy_object, offset)) == VM_PAGE_NULL)
        !           872:                    panic("kmem_io_object_trunc: unable to find object page");
        !           873: 
        !           874:                /*
        !           875:                 * Make sure these pages are marked dirty
        !           876:                 */
        !           877:                mem->dirty = TRUE;
        !           878:                vm_page_lock_queues();
        !           879:                vm_page_unwire(mem);
        !           880:                vm_page_unlock_queues();
        !           881:        }
        !           882:         copy->cpy_object->size = new_size;     /*  adjust size of object */
        !           883:         vm_object_unlock(copy->cpy_object);
        !           884:         return(KERN_SUCCESS);
        !           885: }
        !           886: 
        !           887: /*
        !           888:  *     kmem_io_object_deallocate:
        !           889:  *
        !           890:  *     Free an vm_map_copy_t.
        !           891:  *     Called by the scatter/gather list network code to free a packet.
        !           892:  */
        !           893: 
        !           894: void
        !           895: kmem_io_object_deallocate(
        !           896:      vm_map_copy_t     copy)           /* IN/OUT copy object */
        !           897: {
        !           898:        kern_return_t   ret;
        !           899: 
        !           900:        /*
        !           901:         * Clear out all the object pages (this will leave an empty object).
        !           902:         */
        !           903:        ret = kmem_io_object_trunc(copy, 0);
        !           904:        if (ret != KERN_SUCCESS)
        !           905:                panic("kmem_io_object_deallocate: unable to truncate object");
        !           906:        /*
        !           907:         * ...and discard the copy object.
        !           908:         */
        !           909:        vm_map_copy_discard(copy);
        !           910: }
        !           911: 
        !           912: /*
        !           913:  *     Routine:        copyinmap
        !           914:  *     Purpose:
        !           915:  *             Like copyin, except that fromaddr is an address
        !           916:  *             in the specified VM map.  This implementation
        !           917:  *             is incomplete; it handles the current user map
        !           918:  *             and the kernel map/submaps.
        !           919:  */
        !           920: boolean_t
        !           921: copyinmap(
        !           922:        vm_map_t        map,
        !           923:        vm_offset_t     fromaddr,
        !           924:        vm_offset_t     toaddr,
        !           925:        vm_size_t       length)
        !           926: {
        !           927:        if (vm_map_pmap(map) == pmap_kernel()) {
        !           928:                /* assume a correct copy */
        !           929:                memcpy((void *)toaddr, (void *)fromaddr, length);
        !           930:                return FALSE;
        !           931:        }
        !           932: 
        !           933:        if (current_map() == map)
        !           934:                return copyin((char *)fromaddr, (char *)toaddr, length);
        !           935: 
        !           936:        return TRUE;
        !           937: }
        !           938: 
        !           939: /*
        !           940:  *     Routine:        copyoutmap
        !           941:  *     Purpose:
        !           942:  *             Like copyout, except that toaddr is an address
        !           943:  *             in the specified VM map.  This implementation
        !           944:  *             is incomplete; it handles the current user map
        !           945:  *             and the kernel map/submaps.
        !           946:  */
        !           947: boolean_t
        !           948: copyoutmap(
        !           949:        vm_map_t        map,
        !           950:        vm_offset_t     fromaddr,
        !           951:        vm_offset_t     toaddr,
        !           952:        vm_size_t       length)
        !           953: {
        !           954:        if (vm_map_pmap(map) == pmap_kernel()) {
        !           955:                /* assume a correct copy */
        !           956:                memcpy((void *)toaddr, (void *)fromaddr, length);
        !           957:                return FALSE;
        !           958:        }
        !           959: 
        !           960:        if (current_map() == map)
        !           961:                return copyout((char *)fromaddr, (char *)toaddr, length);
        !           962: 
        !           963:        return TRUE;
        !           964: }

unix.superglobalmegacorp.com

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