Annotation of Gnu-Mach/vm/vm_kern.c, revision 1.1.1.4

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

unix.superglobalmegacorp.com

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