Annotation of Net2/vm/vm_kern.c, revision 1.1

1.1     ! root        1: /* 
        !             2:  * Copyright (c) 1991 Regents of the University of California.
        !             3:  * All rights reserved.
        !             4:  *
        !             5:  * This code is derived from software contributed to Berkeley by
        !             6:  * The Mach Operating System project at Carnegie-Mellon University.
        !             7:  *
        !             8:  * Redistribution and use in source and binary forms, with or without
        !             9:  * modification, are permitted provided that the following conditions
        !            10:  * are met:
        !            11:  * 1. Redistributions of source code must retain the above copyright
        !            12:  *    notice, this list of conditions and the following disclaimer.
        !            13:  * 2. Redistributions in binary form must reproduce the above copyright
        !            14:  *    notice, this list of conditions and the following disclaimer in the
        !            15:  *    documentation and/or other materials provided with the distribution.
        !            16:  * 3. All advertising materials mentioning features or use of this software
        !            17:  *    must display the following acknowledgement:
        !            18:  *     This product includes software developed by the University of
        !            19:  *     California, Berkeley and its contributors.
        !            20:  * 4. Neither the name of the University nor the names of its contributors
        !            21:  *    may be used to endorse or promote products derived from this software
        !            22:  *    without specific prior written permission.
        !            23:  *
        !            24:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
        !            25:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
        !            26:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
        !            27:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
        !            28:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
        !            29:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
        !            30:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
        !            31:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
        !            32:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
        !            33:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
        !            34:  * SUCH DAMAGE.
        !            35:  *
        !            36:  *     @(#)vm_kern.c   7.4 (Berkeley) 5/7/91
        !            37:  *
        !            38:  *
        !            39:  * Copyright (c) 1987, 1990 Carnegie-Mellon University.
        !            40:  * All rights reserved.
        !            41:  *
        !            42:  * Authors: Avadis Tevanian, Jr., Michael Wayne Young
        !            43:  * 
        !            44:  * Permission to use, copy, modify and distribute this software and
        !            45:  * its documentation is hereby granted, provided that both the copyright
        !            46:  * notice and this permission notice appear in all copies of the
        !            47:  * software, derivative works or modified versions, and any portions
        !            48:  * thereof, and that both notices appear in supporting documentation.
        !            49:  * 
        !            50:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 
        !            51:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND 
        !            52:  * FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
        !            53:  * 
        !            54:  * Carnegie Mellon requests users of this software to return to
        !            55:  *
        !            56:  *  Software Distribution Coordinator  or  [email protected]
        !            57:  *  School of Computer Science
        !            58:  *  Carnegie Mellon University
        !            59:  *  Pittsburgh PA 15213-3890
        !            60:  *
        !            61:  * any improvements or extensions that they make and grant Carnegie the
        !            62:  * rights to redistribute these changes.
        !            63:  */
        !            64: 
        !            65: /*
        !            66:  *     Kernel memory management.
        !            67:  */
        !            68: 
        !            69: #include "param.h"
        !            70: 
        !            71: #include "vm.h"
        !            72: #include "vm_page.h"
        !            73: #include "vm_pageout.h"
        !            74: #include "vm_kern.h"
        !            75: 
        !            76: /*
        !            77:  *     kmem_alloc_pageable:
        !            78:  *
        !            79:  *     Allocate pageable memory to the kernel's address map.
        !            80:  *     map must be "kernel_map" below.
        !            81:  */
        !            82: 
        !            83: vm_offset_t kmem_alloc_pageable(map, size)
        !            84:        vm_map_t                map;
        !            85:        register vm_size_t      size;
        !            86: {
        !            87:        vm_offset_t             addr;
        !            88:        register int            result;
        !            89: 
        !            90: #if    0
        !            91:        if (map != kernel_map)
        !            92:                panic("kmem_alloc_pageable: not called with kernel_map");
        !            93: #endif 0
        !            94: 
        !            95:        size = round_page(size);
        !            96: 
        !            97:        addr = vm_map_min(map);
        !            98:        result = vm_map_find(map, NULL, (vm_offset_t) 0,
        !            99:                                &addr, size, TRUE);
        !           100:        if (result != KERN_SUCCESS) {
        !           101:                return(0);
        !           102:        }
        !           103: 
        !           104:        return(addr);
        !           105: }
        !           106: 
        !           107: /*
        !           108:  *     Allocate wired-down memory in the kernel's address map
        !           109:  *     or a submap.
        !           110:  */
        !           111: vm_offset_t kmem_alloc(map, size)
        !           112:        register vm_map_t       map;
        !           113:        register vm_size_t      size;
        !           114: {
        !           115:        vm_offset_t             addr;
        !           116:        register int            result;
        !           117:        register vm_offset_t    offset;
        !           118:        extern vm_object_t      kernel_object;
        !           119:        vm_offset_t             i;
        !           120: 
        !           121:        size = round_page(size);
        !           122: 
        !           123:        /*
        !           124:         *      Use the kernel object for wired-down kernel pages.
        !           125:         *      Assume that no region of the kernel object is
        !           126:         *      referenced more than once.
        !           127:         */
        !           128: 
        !           129:        addr = vm_map_min(map);
        !           130:        result = vm_map_find(map, NULL, (vm_offset_t) 0,
        !           131:                                 &addr, size, TRUE);
        !           132:        if (result != KERN_SUCCESS) {
        !           133:                return(0);
        !           134:        }
        !           135: 
        !           136:        /*
        !           137:         *      Since we didn't know where the new region would
        !           138:         *      start, we couldn't supply the correct offset into
        !           139:         *      the kernel object.  Re-allocate that address
        !           140:         *      region with the correct offset.
        !           141:         */
        !           142: 
        !           143:        offset = addr - VM_MIN_KERNEL_ADDRESS;
        !           144:        vm_object_reference(kernel_object);
        !           145: 
        !           146:        vm_map_lock(map);
        !           147:        vm_map_delete(map, addr, addr + size);
        !           148:        vm_map_insert(map, kernel_object, offset, addr, addr + size);
        !           149:        vm_map_unlock(map);
        !           150: 
        !           151:        /*
        !           152:         *      Guarantee that there are pages already in this object
        !           153:         *      before calling vm_map_pageable.  This is to prevent the
        !           154:         *      following scenario:
        !           155:         *
        !           156:         *              1) Threads have swapped out, so that there is a
        !           157:         *                 pager for the kernel_object.
        !           158:         *              2) The kmsg zone is empty, and so we are kmem_allocing
        !           159:         *                 a new page for it.
        !           160:         *              3) vm_map_pageable calls vm_fault; there is no page,
        !           161:         *                 but there is a pager, so we call
        !           162:         *                 pager_data_request.  But the kmsg zone is empty,
        !           163:         *                 so we must kmem_alloc.
        !           164:         *              4) goto 1
        !           165:         *              5) Even if the kmsg zone is not empty: when we get
        !           166:         *                 the data back from the pager, it will be (very
        !           167:         *                 stale) non-zero data.  kmem_alloc is defined to
        !           168:         *                 return zero-filled memory.
        !           169:         *
        !           170:         *      We're intentionally not activating the pages we allocate
        !           171:         *      to prevent a race with page-out.  vm_map_pageable will wire
        !           172:         *      the pages.
        !           173:         */
        !           174: 
        !           175:        vm_object_lock(kernel_object);
        !           176:        for (i = 0 ; i < size; i+= PAGE_SIZE) {
        !           177:                vm_page_t       mem;
        !           178: 
        !           179:                while ((mem = vm_page_alloc(kernel_object, offset+i)) == NULL) {
        !           180:                        vm_object_unlock(kernel_object);
        !           181:                        VM_WAIT;
        !           182:                        vm_object_lock(kernel_object);
        !           183:                }
        !           184:                vm_page_zero_fill(mem);
        !           185:                mem->busy = FALSE;
        !           186:        }
        !           187:        vm_object_unlock(kernel_object);
        !           188:                
        !           189:        /*
        !           190:         *      And finally, mark the data as non-pageable.
        !           191:         */
        !           192: 
        !           193:        (void) vm_map_pageable(map, (vm_offset_t) addr, addr + size, FALSE);
        !           194: 
        !           195:        /*
        !           196:         *      Try to coalesce the map
        !           197:         */
        !           198: 
        !           199:        vm_map_simplify(map, addr);
        !           200: 
        !           201:        return(addr);
        !           202: }
        !           203: 
        !           204: /*
        !           205:  *     kmem_free:
        !           206:  *
        !           207:  *     Release a region of kernel virtual memory allocated
        !           208:  *     with kmem_alloc, and return the physical pages
        !           209:  *     associated with that region.
        !           210:  */
        !           211: void kmem_free(map, addr, size)
        !           212:        vm_map_t                map;
        !           213:        register vm_offset_t    addr;
        !           214:        vm_size_t               size;
        !           215: {
        !           216:        (void) vm_map_remove(map, trunc_page(addr), round_page(addr + size));
        !           217: }
        !           218: 
        !           219: /*
        !           220:  *     kmem_suballoc:
        !           221:  *
        !           222:  *     Allocates a map to manage a subrange
        !           223:  *     of the kernel virtual address space.
        !           224:  *
        !           225:  *     Arguments are as follows:
        !           226:  *
        !           227:  *     parent          Map to take range from
        !           228:  *     size            Size of range to find
        !           229:  *     min, max        Returned endpoints of map
        !           230:  *     pageable        Can the region be paged
        !           231:  */
        !           232: vm_map_t kmem_suballoc(parent, min, max, size, pageable)
        !           233:        register vm_map_t       parent;
        !           234:        vm_offset_t             *min, *max;
        !           235:        register vm_size_t      size;
        !           236:        boolean_t               pageable;
        !           237: {
        !           238:        register int    ret;
        !           239:        vm_map_t        result;
        !           240: 
        !           241:        size = round_page(size);
        !           242: 
        !           243:        *min = (vm_offset_t) vm_map_min(parent);
        !           244:        ret = vm_map_find(parent, NULL, (vm_offset_t) 0,
        !           245:                                min, size, TRUE);
        !           246:        if (ret != KERN_SUCCESS) {
        !           247:                printf("kmem_suballoc: bad status return of %d.\n", ret);
        !           248:                panic("kmem_suballoc");
        !           249:        }
        !           250:        *max = *min + size;
        !           251:        pmap_reference(vm_map_pmap(parent));
        !           252:        result = vm_map_create(vm_map_pmap(parent), *min, *max, pageable);
        !           253:        if (result == NULL)
        !           254:                panic("kmem_suballoc: cannot create submap");
        !           255:        if ((ret = vm_map_submap(parent, *min, *max, result)) != KERN_SUCCESS)
        !           256:                panic("kmem_suballoc: unable to change range to submap");
        !           257:        return(result);
        !           258: }
        !           259: 
        !           260: /*
        !           261:  *     vm_move:
        !           262:  *
        !           263:  *     Move memory from source to destination map, possibly deallocating
        !           264:  *     the source map reference to the memory.
        !           265:  *
        !           266:  *     Parameters are as follows:
        !           267:  *
        !           268:  *     src_map         Source address map
        !           269:  *     src_addr        Address within source map
        !           270:  *     dst_map         Destination address map
        !           271:  *     num_bytes       Amount of data (in bytes) to copy/move
        !           272:  *     src_dealloc     Should source be removed after copy?
        !           273:  *
        !           274:  *     Assumes the src and dst maps are not already locked.
        !           275:  *
        !           276:  *     Returns new destination address or 0 (if a failure occurs).
        !           277:  */
        !           278: vm_offset_t vm_move(src_map,src_addr,dst_map,num_bytes,src_dealloc)
        !           279:        vm_map_t                src_map;
        !           280:        register vm_offset_t    src_addr;
        !           281:        register vm_map_t       dst_map;
        !           282:        vm_offset_t             num_bytes;
        !           283:        boolean_t               src_dealloc;
        !           284: {
        !           285:        register vm_offset_t    src_start;      /* Beginning of region */
        !           286:        register vm_size_t      src_size;       /* Size of rounded region */
        !           287:        vm_offset_t             dst_start;      /* destination address */
        !           288:        register int            result;
        !           289: 
        !           290:        /*
        !           291:         *      Page-align the source region
        !           292:         */
        !           293: 
        !           294:        src_start = trunc_page(src_addr);
        !           295:        src_size = round_page(src_addr + num_bytes) - src_start;
        !           296: 
        !           297:        /*
        !           298:         *      If there's no destination, we can be at most deallocating
        !           299:         *      the source range.
        !           300:         */
        !           301:        if (dst_map == NULL) {
        !           302:                if (src_dealloc)
        !           303:                        if (vm_deallocate(src_map, src_start, src_size)
        !           304:                                        != KERN_SUCCESS) {
        !           305:                                printf("vm_move: deallocate of source");
        !           306:                                printf(" failed, dealloc_only clause\n");
        !           307:                        }
        !           308:                return(0);
        !           309:        }
        !           310: 
        !           311:        /*
        !           312:         *      Allocate a place to put the copy
        !           313:         */
        !           314: 
        !           315:        dst_start = (vm_offset_t) 0;
        !           316:        if ((result = vm_allocate(dst_map, &dst_start, src_size, TRUE))
        !           317:                                == KERN_SUCCESS) {
        !           318:                /*
        !           319:                 *      Perform the copy, asking for deallocation if desired
        !           320:                 */
        !           321:                result = vm_map_copy(dst_map, src_map, dst_start, src_size,
        !           322:                                        src_start, FALSE, src_dealloc);
        !           323:        }
        !           324: 
        !           325:        /*
        !           326:         *      Return the destination address corresponding to
        !           327:         *      the source address given (rather than the front
        !           328:         *      of the newly-allocated page).
        !           329:         */
        !           330: 
        !           331:        if (result == KERN_SUCCESS)
        !           332:                return(dst_start + (src_addr - src_start));
        !           333:        return(0);
        !           334: }
        !           335: 
        !           336: /*
        !           337:  * Allocate wired-down memory in the kernel's address map for the higher
        !           338:  * level kernel memory allocator (kern/kern_malloc.c).  We cannot use
        !           339:  * kmem_alloc() because we may need to allocate memory at interrupt
        !           340:  * level where we cannot block (canwait == FALSE).
        !           341:  *
        !           342:  * This routine has its own private kernel submap (kmem_map) and object
        !           343:  * (kmem_object).  This, combined with the fact that only malloc uses
        !           344:  * this routine, ensures that we will never block in map or object waits.
        !           345:  *
        !           346:  * Note that this still only works in a uni-processor environment and
        !           347:  * when called at splhigh().
        !           348:  *
        !           349:  * We don't worry about expanding the map (adding entries) since entries
        !           350:  * for wired maps are statically allocated.
        !           351:  */
        !           352: vm_offset_t
        !           353: kmem_malloc(map, size, canwait)
        !           354:        register vm_map_t       map;
        !           355:        register vm_size_t      size;
        !           356:        boolean_t               canwait;
        !           357: {
        !           358:        register vm_offset_t    offset, i;
        !           359:        vm_map_entry_t          entry;
        !           360:        vm_offset_t             addr;
        !           361:        vm_page_t               m;
        !           362:        extern vm_object_t      kmem_object;
        !           363: 
        !           364:        if (map != kmem_map && map != mb_map)
        !           365:                panic("kern_malloc_alloc: map != {kmem,mb}_map");
        !           366: 
        !           367:        size = round_page(size);
        !           368:        addr = vm_map_min(map);
        !           369: 
        !           370:        if (vm_map_find(map, NULL, (vm_offset_t)0,
        !           371:                        &addr, size, TRUE) != KERN_SUCCESS) {
        !           372:                if (canwait)
        !           373:                        panic("kmem_malloc: kmem_map too small");
        !           374:                return(0);
        !           375:        }
        !           376: 
        !           377:        /*
        !           378:         * Since we didn't know where the new region would start,
        !           379:         * we couldn't supply the correct offset into the kmem object.
        !           380:         * Re-allocate that address region with the correct offset.
        !           381:         */
        !           382:        offset = addr - vm_map_min(kmem_map);
        !           383:        vm_object_reference(kmem_object);
        !           384: 
        !           385:        vm_map_lock(map);
        !           386:        vm_map_delete(map, addr, addr + size);
        !           387:        vm_map_insert(map, kmem_object, offset, addr, addr + size);
        !           388: 
        !           389:        /*
        !           390:         * If we can wait, just mark the range as wired
        !           391:         * (will fault pages as necessary).
        !           392:         */
        !           393:        if (canwait) {
        !           394:                vm_map_unlock(map);
        !           395:                (void) vm_map_pageable(map, (vm_offset_t) addr, addr + size,
        !           396:                                       FALSE);
        !           397:                vm_map_simplify(map, addr);
        !           398:                return(addr);
        !           399:        }
        !           400: 
        !           401:        /*
        !           402:         * If we cannot wait then we must allocate all memory up front,
        !           403:         * pulling it off the active queue to prevent pageout.
        !           404:         */
        !           405:        vm_object_lock(kmem_object);
        !           406:        for (i = 0; i < size; i += PAGE_SIZE) {
        !           407:                m = vm_page_alloc(kmem_object, offset + i);
        !           408: 
        !           409:                /*
        !           410:                 * Ran out of space, free everything up and return.
        !           411:                 * Don't need to lock page queues here as we know
        !           412:                 * that the pages we got aren't on any queues.
        !           413:                 */
        !           414:                if (m == NULL) {
        !           415:                        while (i != 0) {
        !           416:                                i -= PAGE_SIZE;
        !           417:                                m = vm_page_lookup(kmem_object, offset + i);
        !           418:                                vm_page_free(m);
        !           419:                        }
        !           420:                        vm_object_unlock(kmem_object);
        !           421:                        vm_map_delete(map, addr, addr + size);
        !           422:                        vm_map_unlock(map);
        !           423:                        return(0);
        !           424:                }
        !           425: #if 0
        !           426:                vm_page_zero_fill(m);
        !           427: #endif
        !           428:                m->busy = FALSE;
        !           429:        }
        !           430:        vm_object_unlock(kmem_object);
        !           431: 
        !           432:        /*
        !           433:         * Mark map entry as non-pageable.
        !           434:         * Assert: vm_map_insert() will never be able to extend the previous
        !           435:         * entry so there will be a new entry exactly corresponding to this
        !           436:         * address range and it will have wired_count == 0.
        !           437:         */
        !           438:        if (!vm_map_lookup_entry(map, addr, &entry) ||
        !           439:            entry->start != addr || entry->end != addr + size ||
        !           440:            entry->wired_count)
        !           441:                panic("kmem_malloc: entry not found or misaligned");
        !           442:        entry->wired_count++;
        !           443: 
        !           444:        /*
        !           445:         * Loop thru pages, entering them in the pmap.
        !           446:         * (We cannot add them to the wired count without
        !           447:         * wrapping the vm_page_queue_lock in splimp...)
        !           448:         */
        !           449:        for (i = 0; i < size; i += PAGE_SIZE) {
        !           450:                vm_object_lock(kmem_object);
        !           451:                m = vm_page_lookup(kmem_object, offset + i);
        !           452:                vm_object_unlock(kmem_object);
        !           453:                pmap_enter(map->pmap, addr + i, VM_PAGE_TO_PHYS(m),
        !           454:                           VM_PROT_DEFAULT, TRUE);
        !           455:        }
        !           456:        vm_map_unlock(map);
        !           457: 
        !           458:        vm_map_simplify(map, addr);
        !           459:        return(addr);
        !           460: }
        !           461: 
        !           462: /*
        !           463:  *     kmem_alloc_wait
        !           464:  *
        !           465:  *     Allocates pageable memory from a sub-map of the kernel.  If the submap
        !           466:  *     has no room, the caller sleeps waiting for more memory in the submap.
        !           467:  *
        !           468:  */
        !           469: vm_offset_t kmem_alloc_wait(map, size)
        !           470:        vm_map_t        map;
        !           471:        vm_size_t       size;
        !           472: {
        !           473:        vm_offset_t     addr;
        !           474:        int             result;
        !           475: 
        !           476:        size = round_page(size);
        !           477: 
        !           478:        do {
        !           479:                /*
        !           480:                 *      To make this work for more than one map,
        !           481:                 *      use the map's lock to lock out sleepers/wakers.
        !           482:                 *      Unfortunately, vm_map_find also grabs the map lock.
        !           483:                 */
        !           484:                vm_map_lock(map);
        !           485:                lock_set_recursive(&map->lock);
        !           486: 
        !           487:                addr = vm_map_min(map);
        !           488:                result = vm_map_find(map, NULL, (vm_offset_t) 0,
        !           489:                                &addr, size, TRUE);
        !           490: 
        !           491:                lock_clear_recursive(&map->lock);
        !           492:                if (result != KERN_SUCCESS) {
        !           493: 
        !           494:                        if ( (vm_map_max(map) - vm_map_min(map)) < size ) {
        !           495:                                vm_map_unlock(map);
        !           496:                                return(0);
        !           497:                        }
        !           498: 
        !           499:                        assert_wait((int)map, TRUE);
        !           500:                        vm_map_unlock(map);
        !           501:                        thread_block();
        !           502:                }
        !           503:                else {
        !           504:                        vm_map_unlock(map);
        !           505:                }
        !           506: 
        !           507:        } while (result != KERN_SUCCESS);
        !           508: 
        !           509:        return(addr);
        !           510: }
        !           511: 
        !           512: /*
        !           513:  *     kmem_free_wakeup
        !           514:  *
        !           515:  *     Returns memory to a submap of the kernel, and wakes up any threads
        !           516:  *     waiting for memory in that map.
        !           517:  */
        !           518: void   kmem_free_wakeup(map, addr, size)
        !           519:        vm_map_t        map;
        !           520:        vm_offset_t     addr;
        !           521:        vm_size_t       size;
        !           522: {
        !           523:        vm_map_lock(map);
        !           524:        (void) vm_map_delete(map, trunc_page(addr), round_page(addr + size));
        !           525:        thread_wakeup((int)map);
        !           526:        vm_map_unlock(map);
        !           527: }
        !           528: 
        !           529: /*
        !           530:  *     kmem_init:
        !           531:  *
        !           532:  *     Initialize the kernel's virtual memory map, taking
        !           533:  *     into account all memory allocated up to this time.
        !           534:  */
        !           535: void kmem_init(start, end)
        !           536:        vm_offset_t     start;
        !           537:        vm_offset_t     end;
        !           538: {
        !           539:        vm_offset_t     addr;
        !           540:        extern vm_map_t kernel_map;
        !           541: 
        !           542:        addr = VM_MIN_KERNEL_ADDRESS;
        !           543:        kernel_map = vm_map_create(pmap_kernel(), addr, end, FALSE);
        !           544:        (void) vm_map_find(kernel_map, NULL, (vm_offset_t) 0,
        !           545:                                &addr, (start - VM_MIN_KERNEL_ADDRESS),
        !           546:                                FALSE);
        !           547: }

unix.superglobalmegacorp.com

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