Annotation of XNU/osfmk/vm/vm_shared_memory_server.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  *
                     24:  *     File: vm/vm_shared_memory_server.c
                     25:  *     Author: Chris Youngworth
                     26:  *
                     27:  *      Support routines for an in-kernel shared memory allocator
                     28:  */
                     29: 
                     30: #include <ipc/ipc_port.h>
                     31: #include <kern/thread.h>
                     32: #include <mach/shared_memory_server.h>
                     33: #include <kern/zalloc.h>
                     34: #include <mach/kern_return.h>
                     35: #include <mach/vm_inherit.h>
                     36: #include <vm/vm_kern.h>
                     37: #include <vm/vm_map.h>
                     38: #include <vm/vm_page.h>
                     39: 
                     40: 
                     41: zone_t          lsf_zone;
                     42: vm_offset_t     alternate_load_base;
                     43: vm_offset_t     alternate_load_next;
                     44: 
                     45: /* called at boot time, allocates two regions, each 256 megs in size */
                     46: /* these regions are later mapped into task spaces, allowing them to */
                     47: /* share the contents of the regions.  shared_file_init is part of   */
                     48: /* a shared_memory_server which not only allocates the backing maps  */
                     49: /* but also coordinates requests for space.  */
                     50: 
                     51: 
                     52: kern_return_t
                     53: shared_file_init(
                     54:        ipc_port_t      *shared_text_region_handle,
                     55:        vm_size_t       text_region_size, 
                     56:        ipc_port_t      *shared_data_region_handle,
                     57:        vm_size_t       data_region_size,
                     58:        vm_offset_t     *shared_file_mapping_array)
                     59: {
                     60:        vm_offset_t             aligned_address;
                     61:        shared_file_info_t      *sf_head;
                     62:        vm_offset_t             table_mapping_address;
                     63:        ipc_port_t              sfma_handle;
                     64:        int                     data_table_size;
                     65:        int                     hash_size;
                     66:        int                     i;
                     67:        kern_return_t           kret;
                     68: 
                     69:        vm_object_t             buf_object;
                     70:        vm_map_entry_t          entry;
                     71:        vm_size_t               alloced;
                     72:        vm_offset_t             b;
                     73:        vm_page_t               p;
                     74: 
                     75:        *shared_file_mapping_array = 0;
                     76: 
                     77:        /* create text and data maps/regions */
                     78:        if(kret = vm_region_object_create(kernel_map, 
                     79:                                text_region_size, 
                     80:                                shared_text_region_handle)) {
                     81:                
                     82:                return kret;
                     83:        }
                     84:        if(kret = vm_region_object_create(kernel_map, 
                     85:                                data_region_size, 
                     86:                                shared_data_region_handle)) {
                     87:                ipc_port_release_send(*shared_text_region_handle);
                     88:                return kret;
                     89:        }
                     90: 
                     91:        data_table_size = data_region_size >> 9;
                     92:        hash_size = data_region_size >> 14;
                     93: 
                     94:        buf_object = vm_object_allocate(data_table_size);
                     95: 
                     96:        if(vm_map_find_space(kernel_map, shared_file_mapping_array, 
                     97:                        data_table_size, 0, &entry) != KERN_SUCCESS) {
                     98: 
                     99:                panic("shared_file_init: no space");
                    100:        }
                    101:        vm_map_unlock(kernel_map);
                    102:        entry->object.vm_object = buf_object;
                    103:        entry->offset = 0;
                    104: 
                    105:        for (b = *shared_file_mapping_array, alloced = 0; 
                    106:                        alloced < round_page(sizeof(struct sf_mapping)); 
                    107:                        alloced += PAGE_SIZE,  b += PAGE_SIZE) {
                    108:                vm_object_lock(buf_object);
                    109:                p = vm_page_alloc(buf_object, alloced);
                    110:                if (p == VM_PAGE_NULL) {
                    111:                        panic("shared_file_init: no space");
                    112:                }       
                    113:                p->busy = FALSE;
                    114:                vm_object_unlock(buf_object);
                    115:                pmap_enter(kernel_pmap, b, p->phys_addr,
                    116:                        VM_PROT_READ | VM_PROT_WRITE, TRUE);
                    117:        }
                    118: 
                    119: 
                    120:        /* initialize loaded file array */
                    121:        sf_head = (shared_file_info_t *)*shared_file_mapping_array;
                    122:        sf_head->hash = (queue_head_t *) 
                    123:                        (((int)*shared_file_mapping_array) + 
                    124:                                sizeof(struct shared_file_info));
                    125:        sf_head->hash_size = hash_size/sizeof(queue_head_t);
                    126:        mutex_init(&(sf_head->lock), (ETAP_VM_MAP));
                    127:        sf_head->hash_init = FALSE;
                    128: 
                    129:        table_mapping_address = data_region_size - data_table_size;
                    130: 
                    131:        mach_make_memory_entry(kernel_map, &data_table_size, 
                    132:                        *shared_file_mapping_array, VM_PROT_READ, &sfma_handle,
                    133:                        NULL);
                    134: 
                    135:        vm_map(((vm_named_entry_t)
                    136:                        (*shared_data_region_handle)->ip_kobject)->backing.map,
                    137:                        &table_mapping_address,
                    138:                        data_table_size, 0, SHARED_LIB_ALIAS, 
                    139:                        sfma_handle, 0, FALSE, 
                    140:                        VM_PROT_READ, VM_PROT_READ, VM_INHERIT_NONE);
                    141: 
                    142:        ipc_port_release_send(sfma_handle);
                    143: 
                    144:        lsf_zone = zinit(sizeof(struct load_file_ele), 
                    145:                data_table_size - hash_size,
                    146:                0, "load_file_server"); 
                    147: 
                    148:        zone_change(lsf_zone, Z_EXHAUST, TRUE);
                    149:        zone_change(lsf_zone, Z_COLLECT, FALSE);
                    150:        zone_change(lsf_zone, Z_EXPAND, FALSE);
                    151:        zone_change(lsf_zone, Z_FOREIGN, TRUE);
                    152:        
                    153:        alternate_load_base = text_region_size>>2;
                    154:        alternate_load_next = text_region_size>>2;
                    155: }
                    156: 
                    157: /* A call made from user space, copyin_shared_file requires the user to */
                    158: /* provide the address and size of a mapped file, the full path name of */
                    159: /* that file and a list of offsets to be mapped into shared memory.     */
                    160: /* By requiring that the file be pre-mapped, copyin_shared_file can     */
                    161: /* guarantee that the file is neither deleted nor changed after the user */
                    162: /* begins the call.  */
                    163: 
                    164: kern_return_t
                    165: copyin_shared_file(
                    166:        vm_offset_t     mapped_file,
                    167:        vm_size_t       mapped_file_size,
                    168:        vm_offset_t     *base_address, 
                    169:        int             map_cnt,
                    170:        sf_mapping_t    *mappings,
                    171:        vm_object_t     file_object,
                    172:        int             *flags)
                    173: {
                    174:        vm_map_entry_t          entry;
                    175:        shared_file_info_t      *shared_file_header;
                    176:        load_struct_t           *file_entry;
                    177:        sf_mapping_t            *file_mapping;
                    178:        boolean_t               alternate;
                    179:        int                     i;
                    180:        kern_return_t           ret;
                    181:        
                    182: 
                    183:        shared_file_header = (shared_file_info_t *)shared_file_mapping_array;
                    184: 
                    185:        mutex_lock(&shared_file_header->lock);
                    186: 
                    187:        if(shared_file_header->hash_init == FALSE) {
                    188:                vm_size_t       hash_table_size;
                    189:                vm_size_t       hash_table_offset;
                    190:                
                    191:                hash_table_size = (shared_file_header->hash_size) 
                    192:                                                * sizeof(struct queue_entry);
                    193:                hash_table_offset = hash_table_size + 
                    194:                                        round_page(sizeof(struct sf_mapping));
                    195:                for (i = 0; i < shared_file_header->hash_size; i++)
                    196:                        queue_init(&shared_file_header->hash[i]);
                    197: 
                    198:                zcram(lsf_zone,  shared_file_mapping_array + 
                    199:                                hash_table_offset,
                    200:                                (hash_table_size<<5) - hash_table_offset);
                    201:                shared_file_header->hash_init = TRUE;
                    202:        }
                    203: 
                    204:        
                    205:        if(vm_map_lookup_entry(current_map(), mapped_file, &entry)) {
                    206:                vm_object_t     mapped_object;
                    207:                if(entry->is_sub_map) {
                    208:                        mutex_unlock(&shared_file_header->lock);
                    209:                        return KERN_FAILURE;
                    210:                }
                    211:                mapped_object = entry->object.vm_object;
                    212:                while(mapped_object->shadow != NULL) {
                    213:                        mapped_object = mapped_object->shadow;
                    214:                }
                    215:                if(file_object != mapped_object) {
                    216:                        mutex_unlock(&shared_file_header->lock);
                    217:                        return KERN_FAILURE;
                    218:                }
                    219:        } else {
                    220:                mutex_unlock(&shared_file_header->lock);
                    221:                return KERN_FAILURE;
                    222:        }
                    223: 
                    224:        alternate = (*flags & ALTERNATE_LOAD_SITE) ? TRUE : FALSE;
                    225: 
                    226:        if (file_entry = lsf_hash_lookup(shared_file_header->hash, 
                    227:                        (void *) file_object, 
                    228:                        shared_file_header->hash_size, alternate)) {
                    229:                /* File is loaded, check the load manifest for exact match */
                    230:                /* we simplify by requiring that the elements be the same  */
                    231:                /* size and in the same order rather than checking for     */
                    232:                /* semantic equivalence. */
                    233: 
                    234:                /* If the file is being loaded in the alternate        */
                    235:                /* area, one load to alternate is allowed per mapped   */
                    236:                /* object the base address is passed back to the       */
                    237:                /* caller and the mappings field is filled in.  If the */
                    238:                /* caller does not pass the precise mappings_cnt       */
                    239:                /* and the Alternate is already loaded, an error       */
                    240:                /* is returned.  */
                    241:                i = 0;
                    242:                file_mapping = file_entry->mappings;
                    243:                while(file_mapping != NULL) {
                    244:                        if(i>=map_cnt) {
                    245:                                mutex_unlock(&shared_file_header->lock);
                    246:                                return KERN_FAILURE;
                    247:                        }
                    248:                        if (mappings[i].mapping_offset != 
                    249:                                        file_mapping->mapping_offset ||
                    250:                                        mappings[i].size != 
                    251:                                                file_mapping->size ||   
                    252:                                        mappings[i].file_offset != 
                    253:                                                file_mapping->file_offset ||    
                    254:                                        mappings[i].protection != 
                    255:                                                file_mapping->protection) {
                    256:                                break;
                    257:                        }
                    258:                        file_mapping = file_mapping->next;
                    259:                        i++;
                    260:                }
                    261:                if(i!=map_cnt) {
                    262:                        mutex_unlock(&shared_file_header->lock);
                    263:                        return KERN_FAILURE;
                    264:                }
                    265:                *base_address = file_entry->base_address;
                    266:                *flags = SF_PREV_LOADED;
                    267:                mutex_unlock(&shared_file_header->lock);
                    268:                return KERN_SUCCESS;
                    269:        } else {
                    270:                /* File is not loaded, lets attempt to load it */
                    271:                ret = lsf_load(mapped_file, mapped_file_size, base_address,
                    272:                                             mappings, map_cnt, 
                    273:                                             (void *)file_object, *flags);
                    274:                *flags = 0;
                    275:                mutex_unlock(&shared_file_header->lock);
                    276:                return ret;
                    277:        }
                    278: }
                    279: 
                    280: /* A hash lookup function for the list of loaded files in      */
                    281: /* shared_memory_server space.  */
                    282: 
                    283: load_struct_t  *
                    284: lsf_hash_lookup(
                    285:        queue_head_t    *hash_table,
                    286:        void            *file_object,
                    287:        int             size,
                    288:        boolean_t       alternate)
                    289: {
                    290:        register queue_t        bucket;
                    291:        load_struct_t           *entry;
                    292:        
                    293:        bucket = &(hash_table[load_file_hash((int)file_object, size)]);
                    294:        for (entry = (load_struct_t *)queue_first(bucket);
                    295:                !queue_end(bucket, &entry->links);
                    296:                entry = (load_struct_t *)queue_next(&entry->links)) {
                    297:                if (entry->file_object == (int)file_object) {
                    298:                        if(alternate) {
                    299:                                if (entry->base_address >= alternate_load_base) 
                    300:                                        return entry;
                    301:                        } else {
                    302:                                if (entry->base_address < alternate_load_base) 
                    303:                                        return entry;
                    304:                        }
                    305:                }
                    306:        }
                    307: 
                    308:        return (load_struct_t *)0;
                    309: }
                    310: 
                    311: /* Removes a map_list, (list of loaded extents) for a file from     */
                    312: /* the loaded file hash table.  */
                    313: 
                    314: load_struct_t *
                    315: lsf_hash_delete(
                    316:        void            *file_object)
                    317: {
                    318:        register queue_t        bucket;
                    319:        shared_file_info_t *shared_file_header;
                    320:        load_struct_t           *entry;
                    321:        load_struct_t           *prev_entry;
                    322: 
                    323:        shared_file_header = (shared_file_info_t *)shared_file_mapping_array;
                    324: 
                    325:        bucket = &shared_file_header->hash
                    326:             [load_file_hash((int)file_object, shared_file_header->hash_size)];
                    327: 
                    328:        for (entry = (load_struct_t *)queue_first(bucket);
                    329:                !queue_end(bucket, &entry->links);
                    330:                entry = (load_struct_t *)queue_next(&entry->links)) {
                    331:                if (entry->file_object == (int) file_object) {
                    332:                        queue_remove(bucket, entry, load_struct_ptr_t, links);
                    333:                        return entry;
                    334:                }
                    335: 
                    336:        }
                    337: 
                    338:        return (load_struct_t *)0;
                    339: }
                    340: 
                    341: /* Inserts a new map_list, (list of loaded file extents), into the */
                    342: /* server loaded file hash table. */
                    343: 
                    344: void
                    345: lsf_hash_insert(
                    346:        load_struct_t   *entry)
                    347: {
                    348:        shared_file_info_t *shared_file_header;
                    349: 
                    350:        shared_file_header = (shared_file_info_t *)shared_file_mapping_array;
                    351:        queue_enter(&shared_file_header->hash
                    352:                        [load_file_hash(entry->file_object, 
                    353:                                        shared_file_header->hash_size)],
                    354:                        entry, load_struct_ptr_t, links);
                    355: }
                    356:        
                    357: /* Looks up the file type requested.  If already loaded and the */
                    358: /* file extents are an exact match, returns Success.  If not    */
                    359: /* loaded attempts to load the file extents at the given offsets */
                    360: /* if any extent fails to load or if the file was already loaded */
                    361: /* in a different configuration, lsf_load fails.                 */
                    362: 
                    363: kern_return_t
                    364: lsf_load(
                    365:        vm_offset_t     mapped_file,
                    366:        vm_size_t       mapped_file_size,
                    367:        vm_offset_t     *base_address, 
                    368:        sf_mapping_t    *mappings,
                    369:        int             map_cnt,
                    370:        void            *file_object,
                    371:        int             flags)
                    372: {
                    373: 
                    374:        load_struct_t   *entry;
                    375:        vm_map_copy_t   copy_object;
                    376:        sf_mapping_t    *file_mapping;
                    377:        sf_mapping_t    **tptr;
                    378:        int             i;
                    379:        ipc_port_t      local_map;
                    380: 
                    381:        entry = (load_struct_t *)zalloc(lsf_zone);
                    382:        entry->file_object = (int)file_object;
                    383:        entry->base_address = *base_address;
                    384:        entry->mapping_cnt = map_cnt;
                    385:        entry->mappings = NULL;
                    386:        entry->links.prev = (queue_entry_t) 0;
                    387:        entry->links.next = (queue_entry_t) 0;
                    388: 
                    389:        lsf_hash_insert(entry);
                    390:        tptr = &(entry->mappings);
                    391: 
                    392: 
                    393:        if (flags & ALTERNATE_LOAD_SITE) {
                    394:                int     max_loadfile_offset;
                    395: 
                    396:                *base_address = alternate_load_next;
                    397:                max_loadfile_offset = 0;
                    398:                for(i = 0; i<map_cnt; i++) {
                    399:                        if((mappings[i].mapping_offset + mappings[i].size) >
                    400:                                max_loadfile_offset) {
                    401:                                max_loadfile_offset = 
                    402:                                        mappings[i].mapping_offset 
                    403:                                                        + mappings[i].size;
                    404:                        }
                    405:                }
                    406:                alternate_load_next += round_page(max_loadfile_offset);
                    407:        }
                    408:        /* copyin mapped file data */
                    409:        for(i = 0; i<map_cnt; i++) {
                    410:                vm_offset_t     target_address;
                    411: 
                    412:                if(mappings[i].protection & VM_PROT_COW) {
                    413:                        local_map = shared_data_region_handle;
                    414:                } else {
                    415:                        local_map = shared_text_region_handle;
                    416:                }
                    417:                if((mapped_file + mappings[i].file_offset + 
                    418:                                mappings[i].size) > 
                    419:                                (mapped_file + mapped_file_size)) {
                    420:                        lsf_unload(file_object);
                    421:                        return KERN_FAILURE;
                    422:                }
                    423:                target_address = *base_address + mappings[i].mapping_offset;
                    424:                if(vm_allocate(((vm_named_entry_t)local_map->ip_kobject)
                    425:                                ->backing.map, &target_address,
                    426:                                mappings[i].size, FALSE)) {
                    427:                        lsf_unload(file_object);
                    428:                        return KERN_FAILURE;
                    429:                }
                    430:                if(vm_map_copyin(current_map(), 
                    431:                        mapped_file + mappings[i].file_offset, 
                    432:                        mappings[i].size, TRUE, &copy_object)) {
                    433:                        lsf_unload(file_object);
                    434:                        return KERN_FAILURE;
                    435:                }
                    436:                target_address = *base_address + mappings[i].mapping_offset;
                    437:                vm_map_copy_overwrite(((vm_named_entry_t)local_map->ip_kobject)
                    438:                        ->backing.map, target_address,
                    439:                        copy_object, FALSE);
                    440:                vm_map_protect(((vm_named_entry_t)local_map->ip_kobject)
                    441:                                ->backing.map, target_address,
                    442:                                target_address + mappings[i].size,
                    443:                                mappings[i].protection & ~VM_PROT_COW, FALSE);
                    444:                file_mapping = (sf_mapping_t *)zalloc(lsf_zone);
                    445:                file_mapping->mapping_offset = mappings[i].mapping_offset;
                    446:                file_mapping->size = mappings[i].size;
                    447:                file_mapping->file_offset = mappings[i].file_offset;
                    448:                file_mapping->protection = mappings[i].protection;
                    449:                file_mapping->next == NULL;
                    450:                *tptr = file_mapping;
                    451:                tptr = &(file_mapping->next);
                    452:        }
                    453:        return KERN_SUCCESS;
                    454:                        
                    455: }
                    456: 
                    457: 
                    458: /* finds the file_object extent list in the shared memory hash table       */
                    459: /* If one is found the associated extents in shared memory are deallocated */
                    460: /* and the extent list is freed */
                    461: 
                    462: void
                    463: lsf_unload(
                    464:        void    *file_object)
                    465: {
                    466:        load_struct_t   *entry;
                    467:        ipc_port_t      local_map;
                    468:        sf_mapping_t    *map_ele;
                    469:        sf_mapping_t    *back_ptr;
                    470: 
                    471:        entry = lsf_hash_delete(file_object);
                    472:        if(entry) {
                    473:                map_ele = entry->mappings;
                    474:                while(map_ele != NULL) {
                    475:                        if(map_ele->protection & VM_PROT_COW) {
                    476:                                local_map = shared_data_region_handle;
                    477:                        } else {
                    478:                                local_map = shared_text_region_handle;
                    479:                        }
                    480:                        vm_deallocate(((vm_named_entry_t)local_map->ip_kobject)
                    481:                                        ->backing.map, entry->base_address + 
                    482:                                        map_ele->mapping_offset,
                    483:                                        map_ele->size);
                    484:                        back_ptr = map_ele;
                    485:                        map_ele = map_ele->next;
                    486:                        zfree(lsf_zone, (vm_offset_t)back_ptr);
                    487:                }
                    488:                zfree(lsf_zone, (vm_offset_t)entry);
                    489:        }
                    490: }

unix.superglobalmegacorp.com

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