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

1.1     ! root        1: /*
        !             2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
        !             3:  *
        !             4:  * @APPLE_LICENSE_HEADER_START@
        !             5:  * 
        !             6:  * The contents of this file constitute Original Code as defined in and
        !             7:  * are subject to the Apple Public Source License Version 1.1 (the
        !             8:  * "License").  You may not use this file except in compliance with the
        !             9:  * License.  Please obtain a copy of the License at
        !            10:  * http://www.apple.com/publicsource and read it before using this file.
        !            11:  * 
        !            12:  * This Original Code and all software distributed under the License are
        !            13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
        !            14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
        !            15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
        !            16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
        !            17:  * License for the specific language governing rights and limitations
        !            18:  * under the License.
        !            19:  * 
        !            20:  * @APPLE_LICENSE_HEADER_END@
        !            21:  */
        !            22: /*
        !            23:  *
        !            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.