Annotation of OSKit-Mach/vm/vm_kern.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Mach Operating System
        !             3:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University.
        !             4:  * Copyright (c) 1993,1994 The University of Utah and
        !             5:  * the Computer Systems Laboratory (CSL).
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Permission to use, copy, modify and distribute this software and its
        !             9:  * documentation is hereby granted, provided that both the copyright
        !            10:  * notice and this permission notice appear in all copies of the
        !            11:  * software, derivative works or modified versions, and any portions
        !            12:  * thereof, and that both notices appear in supporting documentation.
        !            13:  *
        !            14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
        !            15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
        !            16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
        !            17:  * THIS SOFTWARE.
        !            18:  *
        !            19:  * Carnegie Mellon requests users of this software to return to
        !            20:  *
        !            21:  *  Software Distribution Coordinator  or  [email protected]
        !            22:  *  School of Computer Science
        !            23:  *  Carnegie Mellon University
        !            24:  *  Pittsburgh PA 15213-3890
        !            25:  *
        !            26:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            27:  * the rights to redistribute these changes.
        !            28:  */
        !            29: /*
        !            30:  *     File:   vm/vm_kern.c
        !            31:  *     Author: Avadis Tevanian, Jr., Michael Wayne Young
        !            32:  *     Date:   1985
        !            33:  *
        !            34:  *     Kernel memory management.
        !            35:  */
        !            36: 
        !            37: #include <mach/kern_return.h>
        !            38: #include "vm_param.h"
        !            39: #include <kern/assert.h>
        !            40: #include <kern/lock.h>
        !            41: #include <kern/thread.h>
        !            42: #include <vm/vm_fault.h>
        !            43: #include <vm/vm_kern.h>
        !            44: #include <vm/vm_map.h>
        !            45: #include <vm/vm_object.h>
        !            46: #include <vm/vm_page.h>
        !            47: #include <vm/vm_pageout.h>
        !            48: 
        !            49: 
        !            50: 
        !            51: /*
        !            52:  *     Variables exported by this module.
        !            53:  */
        !            54: 
        !            55: vm_map_t       kernel_map;
        !            56: vm_map_t       kernel_pageable_map;
        !            57: 
        !            58: extern void kmem_alloc_pages();
        !            59: extern void kmem_remap_pages();
        !            60: 
        !            61: /*
        !            62:  *     projected_buffer_allocate
        !            63:  *
        !            64:  *     Allocate a wired-down buffer shared between kernel and user task.  
        !            65:  *      Fresh, zero-filled memory is allocated.
        !            66:  *      If persistence is false, this buffer can only be deallocated from
        !            67:  *      user task using projected_buffer_deallocate, and deallocation 
        !            68:  *      from user task also deallocates the buffer from the kernel map.
        !            69:  *      projected_buffer_collect is called from vm_map_deallocate to
        !            70:  *      automatically deallocate projected buffers on task_deallocate.
        !            71:  *      Sharing with more than one user task is achieved by using 
        !            72:  *      projected_buffer_map for the second and subsequent tasks.
        !            73:  *      The user is precluded from manipulating the VM entry of this buffer
        !            74:  *      (i.e. changing protection, inheritance or machine attributes).
        !            75:  */
        !            76: 
        !            77: kern_return_t
        !            78: projected_buffer_allocate(map, size, persistence, kernel_p, 
        !            79:                           user_p, protection, inheritance)
        !            80:        vm_map_t map;
        !            81:        vm_size_t size;
        !            82:         int persistence;
        !            83:        vm_offset_t *kernel_p;
        !            84:        vm_offset_t *user_p;
        !            85:         vm_prot_t protection;
        !            86:         vm_inherit_t inheritance;  /*Currently only VM_INHERIT_NONE supported*/
        !            87: {
        !            88:        vm_object_t object;
        !            89:        vm_map_entry_t u_entry, k_entry;
        !            90:        vm_offset_t addr;
        !            91:        vm_size_t r_size;
        !            92:        kern_return_t kr;
        !            93: 
        !            94:        if (map == VM_MAP_NULL || map == kernel_map)
        !            95:          return(KERN_INVALID_ARGUMENT);
        !            96: 
        !            97:        /*
        !            98:         *      Allocate a new object. 
        !            99:         */
        !           100: 
        !           101:        size = round_page(size);
        !           102:        object = vm_object_allocate(size);
        !           103: 
        !           104:        vm_map_lock(kernel_map);
        !           105:        kr = vm_map_find_entry(kernel_map, &addr, size, (vm_offset_t) 0,
        !           106:                               VM_OBJECT_NULL, &k_entry);
        !           107:        if (kr != KERN_SUCCESS) {
        !           108:          vm_map_unlock(kernel_map);
        !           109:          vm_object_deallocate(object);
        !           110:          return kr;
        !           111:        }
        !           112: 
        !           113:        k_entry->object.vm_object = object;
        !           114:        if (!persistence)
        !           115:          k_entry->projected_on = (vm_map_entry_t) -1;
        !           116:               /*Mark entry so as to automatically deallocate it when
        !           117:                 last corresponding user entry is deallocated*/
        !           118:        vm_map_unlock(kernel_map);
        !           119:        *kernel_p = addr;
        !           120: 
        !           121:        vm_map_lock(map);
        !           122:        kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0,
        !           123:                               VM_OBJECT_NULL, &u_entry);
        !           124:        if (kr != KERN_SUCCESS) {
        !           125:          vm_map_unlock(map);
        !           126:          vm_map_lock(kernel_map);
        !           127:          vm_map_entry_delete(kernel_map, k_entry);
        !           128:          vm_map_unlock(kernel_map);
        !           129:          vm_object_deallocate(object);
        !           130:          return kr;
        !           131:        }
        !           132: 
        !           133:        u_entry->object.vm_object = object;
        !           134:        vm_object_reference(object);
        !           135:        u_entry->projected_on = k_entry;
        !           136:              /*Creates coupling with kernel mapping of the buffer, and
        !           137:                also guarantees that user cannot directly manipulate
        !           138:                buffer VM entry*/
        !           139:        u_entry->protection = protection;
        !           140:        u_entry->max_protection = protection;
        !           141:        u_entry->inheritance = inheritance;
        !           142:        vm_map_unlock(map);
        !           143:                *user_p = addr;
        !           144: 
        !           145:        /*
        !           146:         *      Allocate wired-down memory in the object,
        !           147:         *      and enter it in the kernel pmap.
        !           148:         */
        !           149:        kmem_alloc_pages(object, 0,
        !           150:                         *kernel_p, *kernel_p + size,
        !           151:                         VM_PROT_READ | VM_PROT_WRITE);
        !           152:        bzero(*kernel_p, size);         /*Zero fill*/
        !           153: 
        !           154:        /* Set up physical mappings for user pmap */
        !           155: 
        !           156:        pmap_pageable(map->pmap, *user_p, *user_p + size, FALSE);
        !           157:        for (r_size = 0; r_size < size; r_size += PAGE_SIZE) {
        !           158:          addr = pmap_extract(kernel_pmap, *kernel_p + r_size);
        !           159:          pmap_enter(map->pmap, *user_p + r_size, addr,
        !           160:                     protection, TRUE);
        !           161:        }
        !           162: 
        !           163:        return(KERN_SUCCESS);
        !           164: }
        !           165: 
        !           166: 
        !           167: /*
        !           168:  *     projected_buffer_map
        !           169:  *
        !           170:  *     Map an area of kernel memory onto a task's address space.
        !           171:  *      No new memory is allocated; the area must previously exist in the
        !           172:  *      kernel memory map.
        !           173:  */
        !           174: 
        !           175: kern_return_t
        !           176: projected_buffer_map(map, kernel_addr, size, user_p, protection, inheritance)
        !           177:        vm_map_t map;
        !           178:        vm_offset_t kernel_addr;
        !           179:        vm_size_t size;
        !           180:        vm_offset_t *user_p;
        !           181:         vm_prot_t protection;
        !           182:         vm_inherit_t inheritance;  /*Currently only VM_INHERIT_NONE supported*/
        !           183: {
        !           184:        vm_object_t object;
        !           185:        vm_map_entry_t u_entry, k_entry;
        !           186:        vm_offset_t physical_addr, user_addr;
        !           187:        vm_size_t r_size;
        !           188:        kern_return_t kr;
        !           189: 
        !           190:        /*
        !           191:         *      Find entry in kernel map 
        !           192:         */
        !           193: 
        !           194:        size = round_page(size);
        !           195:        if (map == VM_MAP_NULL || map == kernel_map ||
        !           196:            !vm_map_lookup_entry(kernel_map, kernel_addr, &k_entry) ||
        !           197:            kernel_addr + size > k_entry->vme_end)
        !           198:          return(KERN_INVALID_ARGUMENT);
        !           199: 
        !           200: 
        !           201:        /*
        !           202:          *     Create entry in user task
        !           203:          */
        !           204: 
        !           205:        vm_map_lock(map);
        !           206:        kr = vm_map_find_entry(map, &user_addr, size, (vm_offset_t) 0,
        !           207:                               VM_OBJECT_NULL, &u_entry);
        !           208:        if (kr != KERN_SUCCESS) {
        !           209:          vm_map_unlock(map);
        !           210:          return kr;
        !           211:        }
        !           212: 
        !           213:        u_entry->object.vm_object = k_entry->object.vm_object;
        !           214:        vm_object_reference(k_entry->object.vm_object);
        !           215:        u_entry->offset = kernel_addr - k_entry->vme_start + k_entry->offset;
        !           216:        u_entry->projected_on = k_entry;
        !           217:              /*Creates coupling with kernel mapping of the buffer, and
        !           218:                also guarantees that user cannot directly manipulate
        !           219:                buffer VM entry*/
        !           220:        u_entry->protection = protection;
        !           221:        u_entry->max_protection = protection;
        !           222:        u_entry->inheritance = inheritance;
        !           223:        u_entry->wired_count = k_entry->wired_count;
        !           224:        vm_map_unlock(map);
        !           225:                *user_p = user_addr;
        !           226: 
        !           227:        /* Set up physical mappings for user pmap */
        !           228: 
        !           229:        pmap_pageable(map->pmap, user_addr, user_addr + size,
        !           230:                      !k_entry->wired_count);
        !           231:        for (r_size = 0; r_size < size; r_size += PAGE_SIZE) {
        !           232:          physical_addr = pmap_extract(kernel_pmap, kernel_addr + r_size);
        !           233:          pmap_enter(map->pmap, user_addr + r_size, physical_addr,
        !           234:                     protection, k_entry->wired_count);
        !           235:        }
        !           236: 
        !           237:        return(KERN_SUCCESS);
        !           238: }
        !           239: 
        !           240: 
        !           241: /*
        !           242:  *     projected_buffer_deallocate
        !           243:  *
        !           244:  *     Unmap projected buffer from task's address space.
        !           245:  *      May also unmap buffer from kernel map, if buffer is not
        !           246:  *      persistent and only the kernel reference remains.
        !           247:  */
        !           248: 
        !           249: kern_return_t
        !           250: projected_buffer_deallocate(map, start, end)
        !           251:      vm_map_t map;
        !           252:      vm_offset_t start, end;
        !           253: {
        !           254:        vm_map_entry_t entry, k_entry;
        !           255: 
        !           256:        vm_map_lock(map);
        !           257:        if (map == VM_MAP_NULL || map == kernel_map ||
        !           258:            !vm_map_lookup_entry(map, start, &entry) ||
        !           259:            end > entry->vme_end ||
        !           260:             /*Check corresponding kernel entry*/
        !           261:            (k_entry = entry->projected_on) == 0) {
        !           262:          vm_map_unlock(map);
        !           263:          return(KERN_INVALID_ARGUMENT);
        !           264:        }
        !           265: 
        !           266:        /*Prepare for deallocation*/
        !           267:        if (entry->vme_start < start)
        !           268:          _vm_map_clip_start(map, entry, start);
        !           269:        if (entry->vme_end > end)
        !           270:          _vm_map_clip_end(map, entry, end);
        !           271:        if (map->first_free == entry)   /*Adjust first_free hint*/
        !           272:          map->first_free = entry->vme_prev;
        !           273:        entry->projected_on = 0;        /*Needed to allow deletion*/
        !           274:        entry->wired_count = 0;         /*Avoid unwire fault*/
        !           275:        vm_map_entry_delete(map, entry);
        !           276:        vm_map_unlock(map);
        !           277: 
        !           278:        /*Check if the buffer is not persistent and only the 
        !           279:           kernel mapping remains, and if so delete it*/
        !           280:        vm_map_lock(kernel_map);
        !           281:        if (k_entry->projected_on == (vm_map_entry_t) -1 &&
        !           282:            k_entry->object.vm_object->ref_count == 1) {
        !           283:          if (kernel_map->first_free == k_entry)
        !           284:            kernel_map->first_free = k_entry->vme_prev;
        !           285:          k_entry->projected_on = 0;    /*Allow unwire fault*/
        !           286:          vm_map_entry_delete(kernel_map, k_entry);
        !           287:        }
        !           288:        vm_map_unlock(kernel_map);
        !           289:        return(KERN_SUCCESS);
        !           290: }
        !           291: 
        !           292: 
        !           293: /*
        !           294:  *     projected_buffer_collect
        !           295:  *
        !           296:  *     Unmap all projected buffers from task's address space.
        !           297:  */
        !           298: 
        !           299: kern_return_t
        !           300: projected_buffer_collect(map)
        !           301:         vm_map_t map;
        !           302: {
        !           303:         vm_map_entry_t entry, next;
        !           304: 
        !           305:         if (map == VM_MAP_NULL || map == kernel_map)
        !           306:          return(KERN_INVALID_ARGUMENT);
        !           307: 
        !           308:        for (entry = vm_map_first_entry(map);
        !           309:             entry != vm_map_to_entry(map);
        !           310:             entry = next) {
        !           311:          next = entry->vme_next;
        !           312:          if (entry->projected_on != 0)
        !           313:            projected_buffer_deallocate(map, entry->vme_start, entry->vme_end);
        !           314:        }
        !           315:        return(KERN_SUCCESS);
        !           316: }
        !           317: 
        !           318: 
        !           319: /*
        !           320:  *     projected_buffer_in_range
        !           321:  *
        !           322:  *     Verifies whether a projected buffer exists in the address range 
        !           323:  *      given.
        !           324:  */
        !           325: 
        !           326: boolean_t
        !           327: projected_buffer_in_range(map, start, end)
        !           328:         vm_map_t map;
        !           329:         vm_offset_t start, end;
        !           330: {
        !           331:         vm_map_entry_t entry;
        !           332: 
        !           333:         if (map == VM_MAP_NULL || map == kernel_map)
        !           334:          return(FALSE);
        !           335: 
        !           336:        /*Find first entry*/
        !           337:        if (!vm_map_lookup_entry(map, start, &entry))
        !           338:          entry = entry->vme_next;
        !           339: 
        !           340:        while (entry != vm_map_to_entry(map) && entry->projected_on == 0 &&
        !           341:               entry->vme_start <= end) {
        !           342:          entry = entry->vme_next;
        !           343:        }
        !           344:        return(entry != vm_map_to_entry(map) && entry->vme_start <= end);
        !           345: }
        !           346: 
        !           347: 
        !           348: /*
        !           349:  *     kmem_alloc:
        !           350:  *
        !           351:  *     Allocate wired-down memory in the kernel's address map
        !           352:  *     or a submap.  The memory is not zero-filled.
        !           353:  */
        !           354: 
        !           355: kern_return_t
        !           356: kmem_alloc(map, addrp, size)
        !           357:        vm_map_t map;
        !           358:        vm_offset_t *addrp;
        !           359:        vm_size_t size;
        !           360: {
        !           361:        vm_object_t object;
        !           362:        vm_map_entry_t entry;
        !           363:        vm_offset_t addr;
        !           364:        kern_return_t kr;
        !           365: 
        !           366:        /*
        !           367:         *      Allocate a new object.  We must do this before locking
        !           368:         *      the map, lest we risk deadlock with the default pager:
        !           369:         *              device_read_alloc uses kmem_alloc,
        !           370:         *              which tries to allocate an object,
        !           371:         *              which uses kmem_alloc_wired to get memory,
        !           372:         *              which blocks for pages.
        !           373:         *              then the default pager needs to read a block
        !           374:         *              to process a memory_object_data_write,
        !           375:         *              and device_read_alloc calls kmem_alloc
        !           376:         *              and deadlocks on the map lock.
        !           377:         */
        !           378: 
        !           379:        size = round_page(size);
        !           380:        object = vm_object_allocate(size);
        !           381: 
        !           382:        vm_map_lock(map);
        !           383:        kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0,
        !           384:                               VM_OBJECT_NULL, &entry);
        !           385:        if (kr != KERN_SUCCESS) {
        !           386:                vm_map_unlock(map);
        !           387:                vm_object_deallocate(object);
        !           388:                return kr;
        !           389:        }
        !           390: 
        !           391:        entry->object.vm_object = object;
        !           392:        entry->offset = 0;
        !           393: 
        !           394:        /*
        !           395:         *      Since we have not given out this address yet,
        !           396:         *      it is safe to unlock the map.
        !           397:         */
        !           398:        vm_map_unlock(map);
        !           399: 
        !           400:        /*
        !           401:         *      Allocate wired-down memory in the kernel_object,
        !           402:         *      for this entry, and enter it in the kernel pmap.
        !           403:         */
        !           404:        kmem_alloc_pages(object, 0,
        !           405:                         addr, addr + size,
        !           406:                         VM_PROT_DEFAULT);
        !           407: 
        !           408:        /*
        !           409:         *      Return the memory, not zeroed.
        !           410:         */
        !           411:        *addrp = addr;
        !           412:        return KERN_SUCCESS;
        !           413: }
        !           414: 
        !           415: /*
        !           416:  *     kmem_realloc:
        !           417:  *
        !           418:  *     Reallocate wired-down memory in the kernel's address map
        !           419:  *     or a submap.  Newly allocated pages are not zeroed.
        !           420:  *     This can only be used on regions allocated with kmem_alloc.
        !           421:  *
        !           422:  *     If successful, the pages in the old region are mapped twice.
        !           423:  *     The old region is unchanged.  Use kmem_free to get rid of it.
        !           424:  */
        !           425: kern_return_t kmem_realloc(map, oldaddr, oldsize, newaddrp, newsize)
        !           426:        vm_map_t map;
        !           427:        vm_offset_t oldaddr;
        !           428:        vm_size_t oldsize;
        !           429:        vm_offset_t *newaddrp;
        !           430:        vm_size_t newsize;
        !           431: {
        !           432:        vm_offset_t oldmin, oldmax;
        !           433:        vm_offset_t newaddr;
        !           434:        vm_object_t object;
        !           435:        vm_map_entry_t oldentry, newentry;
        !           436:        kern_return_t kr;
        !           437: 
        !           438:        oldmin = trunc_page(oldaddr);
        !           439:        oldmax = round_page(oldaddr + oldsize);
        !           440:        oldsize = oldmax - oldmin;
        !           441:        newsize = round_page(newsize);
        !           442: 
        !           443:        /*
        !           444:         *      Find space for the new region.
        !           445:         */
        !           446: 
        !           447:        vm_map_lock(map);
        !           448:        kr = vm_map_find_entry(map, &newaddr, newsize, (vm_offset_t) 0,
        !           449:                               VM_OBJECT_NULL, &newentry);
        !           450:        if (kr != KERN_SUCCESS) {
        !           451:                vm_map_unlock(map);
        !           452:                return kr;
        !           453:        }
        !           454: 
        !           455:        /*
        !           456:         *      Find the VM object backing the old region.
        !           457:         */
        !           458: 
        !           459:        if (!vm_map_lookup_entry(map, oldmin, &oldentry))
        !           460:                panic("kmem_realloc");
        !           461:        object = oldentry->object.vm_object;
        !           462: 
        !           463:        /*
        !           464:         *      Increase the size of the object and
        !           465:         *      fill in the new region.
        !           466:         */
        !           467: 
        !           468:        vm_object_reference(object);
        !           469:        vm_object_lock(object);
        !           470:        if (object->size != oldsize)
        !           471:                panic("kmem_realloc");
        !           472:        object->size = newsize;
        !           473:        vm_object_unlock(object);
        !           474: 
        !           475:        newentry->object.vm_object = object;
        !           476:        newentry->offset = 0;
        !           477: 
        !           478:        /*
        !           479:         *      Since we have not given out this address yet,
        !           480:         *      it is safe to unlock the map.  We are trusting
        !           481:         *      that nobody will play with either region.
        !           482:         */
        !           483: 
        !           484:        vm_map_unlock(map);
        !           485: 
        !           486:        /*
        !           487:         *      Remap the pages in the old region and
        !           488:         *      allocate more pages for the new region.
        !           489:         */
        !           490: 
        !           491:        kmem_remap_pages(object, 0,
        !           492:                         newaddr, newaddr + oldsize,
        !           493:                         VM_PROT_DEFAULT);
        !           494:        kmem_alloc_pages(object, oldsize,
        !           495:                         newaddr + oldsize, newaddr + newsize,
        !           496:                         VM_PROT_DEFAULT);
        !           497: 
        !           498:        *newaddrp = newaddr;
        !           499:        return KERN_SUCCESS;
        !           500: }
        !           501: 
        !           502: /*
        !           503:  *     kmem_alloc_wired:
        !           504:  *
        !           505:  *     Allocate wired-down memory in the kernel's address map
        !           506:  *     or a submap.  The memory is not zero-filled.
        !           507:  *
        !           508:  *     The memory is allocated in the kernel_object.
        !           509:  *     It may not be copied with vm_map_copy, and
        !           510:  *     it may not be reallocated with kmem_realloc.
        !           511:  */
        !           512: 
        !           513: kern_return_t
        !           514: kmem_alloc_wired(map, addrp, size)
        !           515:        vm_map_t map;
        !           516:        vm_offset_t *addrp;
        !           517:        vm_size_t size;
        !           518: {
        !           519:        vm_map_entry_t entry;
        !           520:        vm_offset_t offset;
        !           521:        vm_offset_t addr;
        !           522:        kern_return_t kr;
        !           523: 
        !           524:        /*
        !           525:         *      Use the kernel object for wired-down kernel pages.
        !           526:         *      Assume that no region of the kernel object is
        !           527:         *      referenced more than once.  We want vm_map_find_entry
        !           528:         *      to extend an existing entry if possible.
        !           529:         */
        !           530: 
        !           531:        size = round_page(size);
        !           532:        vm_map_lock(map);
        !           533:        kr = vm_map_find_entry(map, &addr, size, (vm_offset_t) 0,
        !           534:                               kernel_object, &entry);
        !           535:        if (kr != KERN_SUCCESS) {
        !           536:                vm_map_unlock(map);
        !           537:                return kr;
        !           538:        }
        !           539: 
        !           540:        /*
        !           541:         *      Since we didn't know where the new region would
        !           542:         *      start, we couldn't supply the correct offset into
        !           543:         *      the kernel object.  We only initialize the entry
        !           544:         *      if we aren't extending an existing entry.
        !           545:         */
        !           546: 
        !           547:        offset = addr - VM_MIN_KERNEL_ADDRESS;
        !           548: 
        !           549:        if (entry->object.vm_object == VM_OBJECT_NULL) {
        !           550:                vm_object_reference(kernel_object);
        !           551: 
        !           552:                entry->object.vm_object = kernel_object;
        !           553:                entry->offset = offset;
        !           554:        }
        !           555: 
        !           556:        /*
        !           557:         *      Since we have not given out this address yet,
        !           558:         *      it is safe to unlock the map.
        !           559:         */
        !           560:        vm_map_unlock(map);
        !           561: 
        !           562:        /*
        !           563:         *      Allocate wired-down memory in the kernel_object,
        !           564:         *      for this entry, and enter it in the kernel pmap.
        !           565:         */
        !           566:        kmem_alloc_pages(kernel_object, offset,
        !           567:                         addr, addr + size,
        !           568:                         VM_PROT_DEFAULT);
        !           569: 
        !           570:        /*
        !           571:         *      Return the memory, not zeroed.
        !           572:         */
        !           573:        *addrp = addr;
        !           574:        return KERN_SUCCESS;
        !           575: }
        !           576: 
        !           577: /*
        !           578:  *     kmem_alloc_aligned:
        !           579:  *
        !           580:  *     Like kmem_alloc_wired, except that the memory is aligned.
        !           581:  *     The size should be a power-of-2.
        !           582:  */
        !           583: 
        !           584: kern_return_t
        !           585: kmem_alloc_aligned(map, addrp, size)
        !           586:        vm_map_t map;
        !           587:        vm_offset_t *addrp;
        !           588:        vm_size_t size;
        !           589: {
        !           590:        vm_map_entry_t entry;
        !           591:        vm_offset_t offset;
        !           592:        vm_offset_t addr;
        !           593:        kern_return_t kr;
        !           594: 
        !           595:        if ((size & (size - 1)) != 0)
        !           596:                panic("kmem_alloc_aligned");
        !           597: 
        !           598:        /*
        !           599:         *      Use the kernel object for wired-down kernel pages.
        !           600:         *      Assume that no region of the kernel object is
        !           601:         *      referenced more than once.  We want vm_map_find_entry
        !           602:         *      to extend an existing entry if possible.
        !           603:         */
        !           604: 
        !           605:        size = round_page(size);
        !           606:        vm_map_lock(map);
        !           607:        kr = vm_map_find_entry(map, &addr, size, size - 1,
        !           608:                               kernel_object, &entry);
        !           609:        if (kr != KERN_SUCCESS) {
        !           610:                vm_map_unlock(map);
        !           611:                return kr;
        !           612:        }
        !           613: 
        !           614:        /*
        !           615:         *      Since we didn't know where the new region would
        !           616:         *      start, we couldn't supply the correct offset into
        !           617:         *      the kernel object.  We only initialize the entry
        !           618:         *      if we aren't extending an existing entry.
        !           619:         */
        !           620: 
        !           621:        offset = addr - VM_MIN_KERNEL_ADDRESS;
        !           622: 
        !           623:        if (entry->object.vm_object == VM_OBJECT_NULL) {
        !           624:                vm_object_reference(kernel_object);
        !           625: 
        !           626:                entry->object.vm_object = kernel_object;
        !           627:                entry->offset = offset;
        !           628:        }
        !           629: 
        !           630:        /*
        !           631:         *      Since we have not given out this address yet,
        !           632:         *      it is safe to unlock the map.
        !           633:         */
        !           634:        vm_map_unlock(map);
        !           635: 
        !           636:        /*
        !           637:         *      Allocate wired-down memory in the kernel_object,
        !           638:         *      for this entry, and enter it in the kernel pmap.
        !           639:         */
        !           640:        kmem_alloc_pages(kernel_object, offset,
        !           641:                         addr, addr + size,
        !           642:                         VM_PROT_DEFAULT);
        !           643: 
        !           644:        /*
        !           645:         *      Return the memory, not zeroed.
        !           646:         */
        !           647:        *addrp = addr;
        !           648:        return KERN_SUCCESS;
        !           649: }
        !           650: 
        !           651: /*
        !           652:  *     kmem_alloc_pageable:
        !           653:  *
        !           654:  *     Allocate pageable memory in the kernel's address map.
        !           655:  */
        !           656: 
        !           657: kern_return_t
        !           658: kmem_alloc_pageable(map, addrp, size)
        !           659:        vm_map_t map;
        !           660:        vm_offset_t *addrp;
        !           661:        vm_size_t size;
        !           662: {
        !           663:        vm_offset_t addr;
        !           664:        kern_return_t kr;
        !           665: 
        !           666:        addr = vm_map_min(map);
        !           667:        kr = vm_map_enter(map, &addr, round_page(size),
        !           668:                          (vm_offset_t) 0, TRUE,
        !           669:                          VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           670:                          VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
        !           671:        if (kr != KERN_SUCCESS)
        !           672:                return kr;
        !           673: 
        !           674:        *addrp = addr;
        !           675:        return KERN_SUCCESS;
        !           676: }
        !           677: 
        !           678: /*
        !           679:  *     kmem_free:
        !           680:  *
        !           681:  *     Release a region of kernel virtual memory allocated
        !           682:  *     with kmem_alloc, kmem_alloc_wired, or kmem_alloc_pageable,
        !           683:  *     and return the physical pages associated with that region.
        !           684:  */
        !           685: 
        !           686: void
        !           687: kmem_free(map, addr, size)
        !           688:        vm_map_t map;
        !           689:        vm_offset_t addr;
        !           690:        vm_size_t size;
        !           691: {
        !           692:        kern_return_t kr;
        !           693: 
        !           694:        kr = vm_map_remove(map, trunc_page(addr), round_page(addr + size));
        !           695:        if (kr != KERN_SUCCESS)
        !           696:                panic("kmem_free");
        !           697: }
        !           698: 
        !           699: /*
        !           700:  *     Allocate new wired pages in an object.
        !           701:  *     The object is assumed to be mapped into the kernel map or
        !           702:  *     a submap.
        !           703:  */
        !           704: void
        !           705: kmem_alloc_pages(object, offset, start, end, protection)
        !           706:        register vm_object_t    object;
        !           707:        register vm_offset_t    offset;
        !           708:        register vm_offset_t    start, end;
        !           709:        vm_prot_t               protection;
        !           710: {
        !           711:        /*
        !           712:         *      Mark the pmap region as not pageable.
        !           713:         */
        !           714:        pmap_pageable(kernel_pmap, start, end, FALSE);
        !           715: 
        !           716:        while (start < end) {
        !           717:            register vm_page_t  mem;
        !           718: 
        !           719:            vm_object_lock(object);
        !           720: 
        !           721:            /*
        !           722:             *  Allocate a page
        !           723:             */
        !           724:            while ((mem = vm_page_alloc(object, offset))
        !           725:                         == VM_PAGE_NULL) {
        !           726:                vm_object_unlock(object);
        !           727:                VM_PAGE_WAIT((void (*)()) 0);
        !           728:                vm_object_lock(object);
        !           729:            }
        !           730: 
        !           731:            /*
        !           732:             *  Wire it down
        !           733:             */
        !           734:            vm_page_lock_queues();
        !           735:            vm_page_wire(mem);
        !           736:            vm_page_unlock_queues();
        !           737:            vm_object_unlock(object);
        !           738: 
        !           739:            /*
        !           740:             *  Enter it in the kernel pmap
        !           741:             */
        !           742:            PMAP_ENTER(kernel_pmap, start, mem,
        !           743:                       protection, TRUE);
        !           744: 
        !           745:            vm_object_lock(object);
        !           746:            PAGE_WAKEUP_DONE(mem);
        !           747:            vm_object_unlock(object);
        !           748: 
        !           749:            start += PAGE_SIZE;
        !           750:            offset += PAGE_SIZE;
        !           751:        }
        !           752: }
        !           753: 
        !           754: /*
        !           755:  *     Remap wired pages in an object into a new region.
        !           756:  *     The object is assumed to be mapped into the kernel map or
        !           757:  *     a submap.
        !           758:  */
        !           759: void
        !           760: kmem_remap_pages(object, offset, start, end, protection)
        !           761:        register vm_object_t    object;
        !           762:        register vm_offset_t    offset;
        !           763:        register vm_offset_t    start, end;
        !           764:        vm_prot_t               protection;
        !           765: {
        !           766:        /*
        !           767:         *      Mark the pmap region as not pageable.
        !           768:         */
        !           769:        pmap_pageable(kernel_pmap, start, end, FALSE);
        !           770: 
        !           771:        while (start < end) {
        !           772:            register vm_page_t  mem;
        !           773: 
        !           774:            vm_object_lock(object);
        !           775: 
        !           776:            /*
        !           777:             *  Find a page
        !           778:             */
        !           779:            if ((mem = vm_page_lookup(object, offset)) == VM_PAGE_NULL)
        !           780:                panic("kmem_remap_pages");
        !           781: 
        !           782:            /*
        !           783:             *  Wire it down (again)
        !           784:             */
        !           785:            vm_page_lock_queues();
        !           786:            vm_page_wire(mem);
        !           787:            vm_page_unlock_queues();
        !           788:            vm_object_unlock(object);
        !           789: 
        !           790:            /*
        !           791:             *  Enter it in the kernel pmap.  The page isn't busy,
        !           792:             *  but this shouldn't be a problem because it is wired.
        !           793:             */
        !           794:            PMAP_ENTER(kernel_pmap, start, mem,
        !           795:                       protection, TRUE);
        !           796: 
        !           797:            start += PAGE_SIZE;
        !           798:            offset += PAGE_SIZE;
        !           799:        }
        !           800: }
        !           801: 
        !           802: /*
        !           803:  *     kmem_suballoc:
        !           804:  *
        !           805:  *     Allocates a map to manage a subrange
        !           806:  *     of the kernel virtual address space.
        !           807:  *
        !           808:  *     Arguments are as follows:
        !           809:  *
        !           810:  *     parent          Map to take range from
        !           811:  *     size            Size of range to find
        !           812:  *     min, max        Returned endpoints of map
        !           813:  *     pageable        Can the region be paged
        !           814:  */
        !           815: 
        !           816: vm_map_t
        !           817: kmem_suballoc(parent, min, max, size, pageable)
        !           818:        vm_map_t parent;
        !           819:        vm_offset_t *min, *max;
        !           820:        vm_size_t size;
        !           821:        boolean_t pageable;
        !           822: {
        !           823:        vm_map_t map;
        !           824:        vm_offset_t addr;
        !           825:        kern_return_t kr;
        !           826: 
        !           827:        size = round_page(size);
        !           828: 
        !           829:        /*
        !           830:         *      Need reference on submap object because it is internal
        !           831:         *      to the vm_system.  vm_object_enter will never be called
        !           832:         *      on it (usual source of reference for vm_map_enter).
        !           833:         */
        !           834:        vm_object_reference(vm_submap_object);
        !           835: 
        !           836:        addr = (vm_offset_t) vm_map_min(parent);
        !           837:        kr = vm_map_enter(parent, &addr, size,
        !           838:                          (vm_offset_t) 0, TRUE,
        !           839:                          vm_submap_object, (vm_offset_t) 0, FALSE,
        !           840:                          VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
        !           841:        if (kr != KERN_SUCCESS)
        !           842:                panic("kmem_suballoc");
        !           843: 
        !           844:        pmap_reference(vm_map_pmap(parent));
        !           845:        map = vm_map_create(vm_map_pmap(parent), addr, addr + size, pageable);
        !           846:        if (map == VM_MAP_NULL)
        !           847:                panic("kmem_suballoc");
        !           848: 
        !           849:        kr = vm_map_submap(parent, addr, addr + size, map);
        !           850:        if (kr != KERN_SUCCESS)
        !           851:                panic("kmem_suballoc");
        !           852: 
        !           853:        *min = addr;
        !           854:        *max = addr + size;
        !           855:        return map;
        !           856: }
        !           857: 
        !           858: /*
        !           859:  *     kmem_init:
        !           860:  *
        !           861:  *     Initialize the kernel's virtual memory map, taking
        !           862:  *     into account all memory allocated up to this time.
        !           863:  */
        !           864: void kmem_init(start, end)
        !           865:        vm_offset_t     start;
        !           866:        vm_offset_t     end;
        !           867: {
        !           868:        kernel_map = vm_map_create(pmap_kernel(),
        !           869:                                   VM_MIN_KERNEL_ADDRESS, end,
        !           870:                                   FALSE);
        !           871: 
        !           872:        /*
        !           873:         *      Reserve virtual memory allocated up to this time.
        !           874:         */
        !           875: 
        !           876:        if (start != VM_MIN_KERNEL_ADDRESS) {
        !           877:                kern_return_t rc;
        !           878:                vm_offset_t addr = VM_MIN_KERNEL_ADDRESS;
        !           879:                rc = vm_map_enter(kernel_map,
        !           880:                                  &addr, start - VM_MIN_KERNEL_ADDRESS,
        !           881:                                  (vm_offset_t) 0, TRUE,
        !           882:                                  VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           883:                                  VM_PROT_DEFAULT, VM_PROT_ALL,
        !           884:                                  VM_INHERIT_DEFAULT);
        !           885:                if (rc)
        !           886:                        panic("%s:%d: vm_map_enter failed (%d)\n", rc);
        !           887:        }
        !           888: }
        !           889: 
        !           890: /*
        !           891:  *     New and improved IO wiring support.
        !           892:  */
        !           893: 
        !           894: /*
        !           895:  *     kmem_io_map_copyout:
        !           896:  *
        !           897:  *     Establish temporary mapping in designated map for the memory
        !           898:  *     passed in.  Memory format must be a page_list vm_map_copy.
        !           899:  *     Mapping is READ-ONLY.
        !           900:  */
        !           901: 
        !           902: kern_return_t
        !           903: kmem_io_map_copyout(map, addr, alloc_addr, alloc_size, copy, min_size)
        !           904:      vm_map_t          map;
        !           905:      vm_offset_t       *addr;          /* actual addr of data */
        !           906:      vm_offset_t       *alloc_addr;    /* page aligned addr */
        !           907:      vm_size_t         *alloc_size;    /* size allocated */
        !           908:      vm_map_copy_t     copy;
        !           909:      vm_size_t         min_size;       /* Do at least this much */
        !           910: {
        !           911:        vm_offset_t     myaddr, offset;
        !           912:        vm_size_t       mysize, copy_size;
        !           913:        kern_return_t   ret;
        !           914:        register
        !           915:        vm_page_t       *page_list;
        !           916:        vm_map_copy_t   new_copy;
        !           917:        register
        !           918:        int             i;
        !           919: 
        !           920:        assert(copy->type == VM_MAP_COPY_PAGE_LIST);
        !           921:        assert(min_size != 0);
        !           922: 
        !           923:        /*
        !           924:         *      Figure out the size in vm pages.
        !           925:         */
        !           926:        min_size += copy->offset - trunc_page(copy->offset);
        !           927:        min_size = round_page(min_size);
        !           928:        mysize = round_page(copy->offset + copy->size) -
        !           929:                trunc_page(copy->offset);
        !           930: 
        !           931:        /*
        !           932:         *      If total size is larger than one page list and
        !           933:         *      we don't have to do more than one page list, then
        !           934:         *      only do one page list.  
        !           935:         *
        !           936:         * XXX  Could be much smarter about this ... like trimming length
        !           937:         * XXX  if we need more than one page list but not all of them.
        !           938:         */
        !           939: 
        !           940:        copy_size = ptoa(copy->cpy_npages);
        !           941:        if (mysize > copy_size && copy_size > min_size)
        !           942:                mysize = copy_size;
        !           943: 
        !           944:        /*
        !           945:         *      Allocate some address space in the map (must be kernel
        !           946:         *      space).
        !           947:         */
        !           948:        myaddr = vm_map_min(map);
        !           949:        ret = vm_map_enter(map, &myaddr, mysize,
        !           950:                          (vm_offset_t) 0, TRUE,
        !           951:                          VM_OBJECT_NULL, (vm_offset_t) 0, FALSE,
        !           952:                          VM_PROT_DEFAULT, VM_PROT_ALL, VM_INHERIT_DEFAULT);
        !           953: 
        !           954:        if (ret != KERN_SUCCESS)
        !           955:                return(ret);
        !           956: 
        !           957:        /*
        !           958:         *      Tell the pmap module that this will be wired, and
        !           959:         *      enter the mappings.
        !           960:         */
        !           961:        pmap_pageable(vm_map_pmap(map), myaddr, myaddr + mysize, TRUE);
        !           962: 
        !           963:        *addr = myaddr + (copy->offset - trunc_page(copy->offset));
        !           964:        *alloc_addr = myaddr;
        !           965:        *alloc_size = mysize;
        !           966: 
        !           967:        offset = myaddr;
        !           968:        page_list = &copy->cpy_page_list[0];
        !           969:        while (TRUE) {
        !           970:                for ( i = 0; i < copy->cpy_npages; i++, offset += PAGE_SIZE) {
        !           971:                        PMAP_ENTER(vm_map_pmap(map), offset, *page_list,
        !           972:                                   VM_PROT_READ, TRUE);
        !           973:                        page_list++;
        !           974:                }
        !           975: 
        !           976:                if (offset == (myaddr + mysize))
        !           977:                        break;
        !           978: 
        !           979:                /*
        !           980:                 *      Onward to the next page_list.  The extend_cont
        !           981:                 *      leaves the current page list's pages alone; 
        !           982:                 *      they'll be cleaned up at discard.  Reset this
        !           983:                 *      copy's continuation to discard the next one.
        !           984:                 */
        !           985:                vm_map_copy_invoke_extend_cont(copy, &new_copy, &ret);
        !           986: 
        !           987:                if (ret != KERN_SUCCESS) {
        !           988:                        kmem_io_map_deallocate(map, myaddr, mysize);
        !           989:                        return(ret);
        !           990:                }
        !           991:                copy->cpy_cont = vm_map_copy_discard_cont;
        !           992:                copy->cpy_cont_args = (char *) new_copy;
        !           993:                copy = new_copy;
        !           994:                page_list = &copy->cpy_page_list[0];
        !           995:        }
        !           996: 
        !           997:        return(ret);
        !           998: }
        !           999: 
        !          1000: /*
        !          1001:  *     kmem_io_map_deallocate:
        !          1002:  *
        !          1003:  *     Get rid of the mapping established by kmem_io_map_copyout.
        !          1004:  *     Assumes that addr and size have been rounded to page boundaries.
        !          1005:  *     (e.g., the alloc_addr and alloc_size returned by kmem_io_map_copyout)
        !          1006:  */
        !          1007: 
        !          1008: void
        !          1009: kmem_io_map_deallocate(map, addr, size)
        !          1010:        vm_map_t        map;
        !          1011:        vm_offset_t     addr;
        !          1012:        vm_size_t       size;
        !          1013: {
        !          1014:        /*
        !          1015:         *      Remove the mappings.  The pmap_remove is needed.
        !          1016:         */
        !          1017:        
        !          1018:        pmap_remove(vm_map_pmap(map), addr, addr + size);
        !          1019:        vm_map_remove(map, addr, addr + size);
        !          1020: }
        !          1021: 
        !          1022: /*
        !          1023:  *     Routine:        copyinmap
        !          1024:  *     Purpose:
        !          1025:  *             Like copyin, except that fromaddr is an address
        !          1026:  *             in the specified VM map.  This implementation
        !          1027:  *             is incomplete; it handles the current user map
        !          1028:  *             and the kernel map/submaps.
        !          1029:  */
        !          1030: 
        !          1031: int copyinmap(map, fromaddr, toaddr, length)
        !          1032:        vm_map_t map;
        !          1033:        char *fromaddr, *toaddr;
        !          1034:        int length;
        !          1035: {
        !          1036:        if (vm_map_pmap(map) == kernel_pmap) {
        !          1037:                /* assume a correct copy */
        !          1038:                bcopy(fromaddr, toaddr, length);
        !          1039:                return 0;
        !          1040:        }
        !          1041: 
        !          1042:        if (current_map() == map)
        !          1043:                return copyin( fromaddr, toaddr, length);
        !          1044: 
        !          1045:        return 1;
        !          1046: }
        !          1047: 
        !          1048: /*
        !          1049:  *     Routine:        copyoutmap
        !          1050:  *     Purpose:
        !          1051:  *             Like copyout, except that toaddr is an address
        !          1052:  *             in the specified VM map.  This implementation
        !          1053:  *             is incomplete; it handles the current user map
        !          1054:  *             and the kernel map/submaps.
        !          1055:  */
        !          1056: 
        !          1057: int copyoutmap(map, fromaddr, toaddr, length)
        !          1058:        vm_map_t map;
        !          1059:        char *fromaddr, *toaddr;
        !          1060:        int length;
        !          1061: {
        !          1062:        if (vm_map_pmap(map) == kernel_pmap) {
        !          1063:                /* assume a correct copy */
        !          1064:                bcopy(fromaddr, toaddr, length);
        !          1065:                return 0;
        !          1066:        }
        !          1067: 
        !          1068:        if (current_map() == map)
        !          1069:                return copyout(fromaddr, toaddr, length);
        !          1070: 
        !          1071:        return 1;
        !          1072: }

unix.superglobalmegacorp.com

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