Annotation of XNU/osfmk/kern/kmod.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:  * Copyright (c) 1999 Apple Computer, Inc.  All rights reserved. 
                     24:  *
                     25:  * HISTORY
                     26:  *
                     27:  * 1999 Mar 29 rsulack created.
                     28:  */
                     29: 
                     30: #include <mach/mach_types.h>
                     31: #include <mach/vm_types.h>
                     32: #include <mach/kern_return.h>
                     33: #include <kern/kern_types.h>
                     34: #include <vm/vm_kern.h>
                     35: #include <kern/thread.h>
                     36: 
                     37: #include <mach_host.h>
                     38: 
                     39: static kmod_info_t *kmod = 0;
                     40: static int kmod_index = 1;
                     41: 
                     42: decl_simple_lock_data(,kmod_lock)
                     43: decl_simple_lock_data(,kmod_queue_lock)
                     44: 
                     45: typedef struct cmd_queue_entry {
                     46:        queue_chain_t   links;
                     47:        vm_address_t    data;
                     48:        vm_size_t       size;
                     49: } cmd_queue_entry_t;
                     50: 
                     51: queue_head_t   kmod_cmd_queue;
                     52: 
                     53: void
                     54: kmod_init()
                     55: {
                     56:        simple_lock_init(&kmod_lock, ETAP_MISC_Q);
                     57:        simple_lock_init(&kmod_queue_lock, ETAP_MISC_Q);
                     58:        queue_init(&kmod_cmd_queue);
                     59: 
                     60:        // XXX grab list drivers already loaded by bootloader
                     61:        // XXX when we get such support (include the kernel itself?)
                     62: }
                     63: 
                     64: kmod_info_t *
                     65: kmod_lookupbyid(kmod_t id)
                     66: {
                     67:        kmod_info_t *k = 0;
                     68: 
                     69:        k = kmod;
                     70:        while (k) {
                     71:                if (k->id == id) break;
                     72:                k = k->next;
                     73:        }
                     74: 
                     75:        return k;
                     76: }
                     77: 
                     78: kmod_info_t *
                     79: kmod_lookupbyname(char * name)
                     80: {
                     81:        kmod_info_t *k = 0;
                     82: 
                     83:        k = kmod;
                     84:        while (k) {
                     85:                if (!strcmp(k->name, name)) break;
                     86:                k = k->next;
                     87:        }
                     88: 
                     89:        return k;
                     90: }
                     91: 
                     92: // XXX add a nocopy flag??
                     93: 
                     94: kern_return_t
                     95: kmod_queue_cmd(vm_address_t data, vm_size_t size)
                     96: {
                     97:        kern_return_t rc;
                     98:        cmd_queue_entry_t *e = (cmd_queue_entry_t *)kalloc(sizeof(struct cmd_queue_entry));
                     99:        if (!e) return KERN_RESOURCE_SHORTAGE;
                    100: 
                    101:        rc = kmem_alloc(kernel_map, &e->data, size);
                    102:        if (rc != KERN_SUCCESS) {
                    103:                kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry));
                    104:                return rc;
                    105:        }
                    106:        e->size = size;
                    107:        bcopy((void *)data, (void *)e->data, size);
                    108: 
                    109:        simple_lock(&kmod_queue_lock);
                    110:        enqueue_tail(&kmod_cmd_queue, (queue_entry_t)e);
                    111:        simple_unlock(&kmod_queue_lock);
                    112: 
                    113:        thread_wakeup_one((event_t)&kmod_cmd_queue);
                    114:        
                    115:        return KERN_SUCCESS;
                    116: }
                    117: 
                    118: kern_return_t
                    119: kmod_load_extension(char *name)
                    120: {
                    121:        kmod_load_extension_cmd_t       *data;
                    122:        vm_size_t                       size;
                    123: 
                    124:        size = sizeof(kmod_load_extension_cmd_t);
                    125:        data = (kmod_load_extension_cmd_t *)kalloc(size);
                    126:        if (!data) return KERN_RESOURCE_SHORTAGE;
                    127: 
                    128:        data->type = KMOD_LOAD_EXTENSION_PACKET;
                    129:        strncpy(data->name, name, KMOD_MAX_NAME);
                    130: 
                    131:        return kmod_queue_cmd((vm_address_t)data, size);
                    132: }
                    133: 
                    134: kern_return_t
                    135: kmod_load_extension_with_dependencies(char *name, char **dependencies)
                    136: {
                    137:        kmod_load_with_dependencies_cmd_t *data;
                    138:        vm_size_t       size;
                    139:        char            **c;
                    140:        int             i, count = 0;
                    141: 
                    142:        c = dependencies;
                    143:        if (c) {
                    144:                while (*c) {
                    145:                        count++; c++;
                    146:                }
                    147:        }
                    148:        size = sizeof(int) + KMOD_MAX_NAME * (count + 1) + 1; 
                    149:        data = (kmod_load_with_dependencies_cmd_t *)kalloc(size);
                    150:        if (!data) return KERN_RESOURCE_SHORTAGE;
                    151: 
                    152:        data->type = KMOD_LOAD_WITH_DEPENDENCIES_PACKET;
                    153:        strncpy(data->name, name, KMOD_MAX_NAME);
                    154: 
                    155:        c = dependencies;
                    156:        for (i=0; i < count; i++) {
                    157:                strncpy(data->dependencies[i], *c, KMOD_MAX_NAME);
                    158:                c++;
                    159:        }
                    160:        data->dependencies[count][0] = 0;
                    161: 
                    162:        return kmod_queue_cmd((vm_address_t)data, size);
                    163: }
                    164: kern_return_t
                    165: kmod_send_generic(int type, void *generic_data, int size)
                    166: {
                    167:        kmod_generic_cmd_t      *data;
                    168: 
                    169:        data = (kmod_generic_cmd_t *)kalloc(size + sizeof(int));
                    170:        if (!data) return KERN_RESOURCE_SHORTAGE;
                    171: 
                    172:        data->type = type;
                    173:        bcopy(data->data, generic_data, size);
                    174: 
                    175:        return kmod_queue_cmd((vm_address_t)data, size + sizeof(int));
                    176: }
                    177: 
                    178: kern_return_t
                    179: kmod_create(host_t host,
                    180:            kmod_info_t *info,
                    181:            kmod_t *id)
                    182: {
                    183:        kern_return_t rc;
                    184: 
                    185:        if (host == HOST_NULL) return KERN_INVALID_HOST;
                    186:        if (!info) return KERN_INVALID_ADDRESS;
                    187: 
                    188:        // double check for page alignment
                    189:        if ((info->address | info->hdr_size) & (PAGE_SIZE - 1)) {
                    190:                return KERN_INVALID_ADDRESS;
                    191:        }
                    192: 
                    193:        rc = vm_map_wire(kernel_map, info->address + info->hdr_size, 
                    194:                         info->address + info->size, VM_PROT_DEFAULT, FALSE);
                    195:        if (rc != KERN_SUCCESS) {
                    196:                return rc;
                    197:        }
                    198: 
                    199:        simple_lock(&kmod_lock);
                    200: 
                    201:        // check to see if already loaded
                    202:        if (kmod_lookupbyname(info->name)) {
                    203:                simple_unlock(&kmod_lock);
                    204:                vm_map_unwire(kernel_map, info->address + info->hdr_size, 
                    205:                              info->address + info->size - info->hdr_size, FALSE);
                    206:                return KERN_INVALID_ARGUMENT;
                    207:        }
                    208: 
                    209:        info->id = kmod_index++;
                    210:        info->reference_count = 0;
                    211: 
                    212:        info->next = kmod;
                    213:        kmod = info;
                    214: 
                    215:        *id = info->id;
                    216: 
                    217:        simple_unlock(&kmod_lock);
                    218: 
                    219:        printf("kmod_create: %s (id %d), %d pages loaded at 0x%x, header size 0x%x\n", 
                    220:               info->name, info->id, info->size / PAGE_SIZE, info->address, info->hdr_size);
                    221: 
                    222:        return KERN_SUCCESS;
                    223: }
                    224: 
                    225: 
                    226: kern_return_t
                    227: kmod_destroy(host_t host,
                    228:             kmod_t id)
                    229: {
                    230:        kmod_info_t *k = kmod;
                    231:        kmod_info_t *p = kmod;
                    232: 
                    233:        if (host == HOST_NULL) return KERN_INVALID_HOST;
                    234: 
                    235:        simple_lock(&kmod_lock);
                    236:        while (k) {
                    237:                if (k->id == id) {
                    238:                        kmod_reference_t *r, *t;
                    239: 
                    240:                        if (k->reference_count != 0) {
                    241:                                simple_unlock(&kmod_lock);
                    242:                                return KERN_INVALID_ARGUMENT;
                    243:                        }
                    244:                                
                    245:                        if (k == p) {   // first element
                    246:                                kmod = k->next;
                    247:                        } else {
                    248:                                p->next = k->next;
                    249:                        }
                    250:                        simple_unlock(&kmod_lock);
                    251: 
                    252:                        r = k->reference_list;
                    253:                        while (r) {
                    254:                                r->info->reference_count--;
                    255:                                t = r;
                    256:                                r = r->next;
                    257:                                kfree((vm_offset_t)t, sizeof(struct kmod_reference));
                    258:                        }
                    259: 
                    260:                        printf("kmod_destroy: %s (id %d), deallocating %d pages starting at 0x%x\n", 
                    261:                               k->name, k->id, k->size / PAGE_SIZE, k->address);
                    262: 
                    263:                        vm_map_unwire(kernel_map, k->address + k->hdr_size, 
                    264:                                      k->address + k->size - k->hdr_size, FALSE);
                    265:                        vm_deallocate(kernel_map, k->address, k->size);
                    266:                        return KERN_SUCCESS;
                    267:                }
                    268:                p = k;
                    269:                k = k->next;
                    270:        }
                    271:        simple_unlock(&kmod_lock);
                    272: 
                    273:        return KERN_INVALID_ARGUMENT;
                    274: }
                    275: 
                    276: 
                    277: kern_return_t
                    278: kmod_control(host_t host,
                    279:             kmod_t id,
                    280:             kmod_control_flavor_t flavor,
                    281:             kmod_args_t *data,
                    282:             mach_msg_type_number_t *dataCount)
                    283: {
                    284:        kern_return_t rc = KERN_SUCCESS;
                    285: 
                    286:        if (host == HOST_NULL) return KERN_INVALID_HOST;
                    287: 
                    288:        switch (flavor) {
                    289: 
                    290:        case KMOD_CNTL_START:
                    291:        case KMOD_CNTL_STOP: 
                    292:        {
                    293:                void * user_data = 0;
                    294:                kern_return_t (*func)();
                    295:                kmod_info_t *k;
                    296: 
                    297:                simple_lock(&kmod_lock);
                    298: 
                    299:                k = kmod_lookupbyid(id);
                    300:                if (!k || k->reference_count) {
                    301:                        simple_unlock(&kmod_lock);
                    302:                        rc = KERN_INVALID_ARGUMENT;
                    303:                        break;
                    304:                }
                    305: 
                    306:                if (flavor == KMOD_CNTL_START) {
                    307:                        func = (void *)k->start;
                    308:                } else {
                    309:                        func = (void *)k->stop;
                    310:                }
                    311: 
                    312:                simple_unlock(&kmod_lock);
                    313: 
                    314:                //
                    315:                // call kmod entry point
                    316:                //
                    317:                if (*data && *dataCount) {
                    318:                        vm_map_copyout(kernel_map, (vm_offset_t *)&user_data, (vm_map_copy_t)*data);
                    319:                }
                    320: 
                    321:                rc = (*func)(k, user_data);
                    322: 
                    323:                if (user_data) {
                    324:                        (void) vm_deallocate(kernel_map, (vm_offset_t)user_data, *dataCount);
                    325:                }
                    326: 
                    327:                break;
                    328:        }
                    329: 
                    330:        case KMOD_CNTL_RETAIN:
                    331:        case KMOD_CNTL_RELEASE:
                    332:        {
                    333:                kmod_info_t *t;         // reference to
                    334:                kmod_info_t *f;         // reference from
                    335:                kmod_reference_t *r = 0;
                    336: 
                    337:                if (flavor == KMOD_CNTL_RETAIN) {
                    338:                        r = (kmod_reference_t *)kalloc(sizeof(struct kmod_reference));
                    339:                        if (!r) return KERN_RESOURCE_SHORTAGE;
                    340:                }
                    341: 
                    342:                simple_lock(&kmod_lock);
                    343: 
                    344:                t = kmod_lookupbyid(KMOD_UNPACK_TO_ID(id));
                    345:                f = kmod_lookupbyid(KMOD_UNPACK_FROM_ID(id));
                    346:                if (!t || !f) {
                    347:                        simple_unlock(&kmod_lock);
                    348:                        if (r) kfree((vm_offset_t)r, sizeof(struct kmod_reference));
                    349:                        rc = KERN_INVALID_ARGUMENT;
                    350:                        break;
                    351:                }
                    352:                if (flavor == KMOD_CNTL_RETAIN) {
                    353:                        r->next = f->reference_list;
                    354:                        r->info = t;
                    355:                        f->reference_list = r;
                    356:                        t->reference_count++;
                    357:                } else {
                    358:                        kmod_reference_t *p;
                    359: 
                    360:                        p = r = f->reference_list;
                    361:                        while (r) {
                    362:                                if (r->info == t) {
                    363:                                        if (p == r) {   // first element
                    364:                                                f->reference_list = r->next;
                    365:                                        } else {
                    366:                                                p->next = r->next;
                    367:                                        }
                    368:                                        r->info->reference_count--;
                    369:                                        simple_unlock(&kmod_lock);
                    370:                                        kfree((vm_offset_t)r, sizeof(struct kmod_reference));
                    371:                                        return rc;
                    372:                                }
                    373:                                p = r;
                    374:                                r = r->next;
                    375:                        }
                    376:                        rc = KERN_INVALID_ARGUMENT;
                    377:                }
                    378:                simple_unlock(&kmod_lock);
                    379: 
                    380:                break;
                    381:        }
                    382: 
                    383:        case KMOD_CNTL_GET_CMD: {
                    384: 
                    385:                cmd_queue_entry_t *e;
                    386: 
                    387:                simple_lock(&kmod_queue_lock);
                    388: 
                    389:                if (queue_empty(&kmod_cmd_queue)) {
                    390:                        assert_wait((event_t)&kmod_cmd_queue, THREAD_ABORTSAFE);
                    391:                        simple_unlock(&kmod_queue_lock);
                    392:                        thread_block((void(*)(void))0);
                    393:                        simple_lock(&kmod_queue_lock);
                    394:                        if (queue_empty(&kmod_cmd_queue)) {
                    395:                                // we must have been interrupted!
                    396:                                simple_unlock(&kmod_queue_lock);
                    397:                                return KERN_ABORTED;
                    398:                        }
                    399:                }
                    400:                e = (cmd_queue_entry_t *)dequeue_head(&kmod_cmd_queue);
                    401:                simple_unlock(&kmod_queue_lock);
                    402: 
                    403:                rc = vm_map_copyin(kernel_map, e->data, e->size, TRUE, (vm_map_copy_t *)data);
                    404:                if (rc) {
                    405:                        simple_lock(&kmod_queue_lock);
                    406:                        enqueue_head(&kmod_cmd_queue, (queue_entry_t)e);
                    407:                        simple_unlock(&kmod_queue_lock);
                    408:                        *data = 0;
                    409:                        *dataCount = 0;
                    410:                        return rc;
                    411:                }
                    412:                *dataCount = e->size;
                    413: 
                    414:                kfree((vm_offset_t)e, sizeof(struct cmd_queue_entry));
                    415:                
                    416:                break;
                    417:        }
                    418: 
                    419:        default:
                    420:                rc = KERN_INVALID_ARGUMENT;
                    421:        }
                    422: 
                    423:        return rc;
                    424: };
                    425: 
                    426: 
                    427: kern_return_t
                    428: kmod_get_info(host_t host,
                    429:              kmod_info_array_t *kmods,
                    430:              mach_msg_type_number_t *kmodCount)
                    431: {
                    432:        vm_offset_t data;
                    433:        kmod_info_t *k, *p1;
                    434:        kmod_reference_t *r, *p2;
                    435:        int ref_count;
                    436:        unsigned size = 0;
                    437:        kern_return_t rc = KERN_SUCCESS;
                    438: 
                    439:        *kmods = (void *)0;
                    440:        *kmodCount = 0;
                    441: 
                    442: retry:
                    443:        simple_lock(&kmod_lock);
                    444:        k = kmod;
                    445:        while (k) {
                    446:                size += sizeof(kmod_info_t);
                    447:                r = k->reference_list;
                    448:                while (r) {
                    449:                        size +=sizeof(kmod_reference_t);
                    450:                        r = r->next;
                    451:                }
                    452:                k = k->next;
                    453:        }
                    454:        simple_unlock(&kmod_lock);
                    455:        if (!size) return KERN_SUCCESS;
                    456: 
                    457:        rc = kmem_alloc(kernel_map, &data, size);
                    458:        if (rc) return rc;
                    459: 
                    460:        // copy kmod into data, retry if kmod's size has changed (grown)
                    461:        // the copied out data is tweeked to figure what's what at user level
                    462:        // change the copied out k->next pointers to point to themselves
                    463:        // change the k->reference into a count, tack the references on
                    464:        // the end of the data packet in the order they are found
                    465: 
                    466:        simple_lock(&kmod_lock);
                    467:        k = kmod; p1 = (kmod_info_t *)data;
                    468:        while (k) {
                    469:                if ((p1 + 1) > (kmod_info_t *)(data + size)) {
                    470:                        simple_unlock(&kmod_lock);
                    471:                        kmem_free(kernel_map, data, size);
                    472:                        goto retry;
                    473:                }
                    474: 
                    475:                *p1 = *k;
                    476:                if (k->next) p1->next = k;
                    477:                p1++; k = k->next;
                    478:        }
                    479: 
                    480:        p2 = (kmod_reference_t *)p1;
                    481:        k = kmod; p1 = (kmod_info_t *)data;
                    482:        while (k) {
                    483:                r = k->reference_list; ref_count = 0;
                    484:                while (r) {
                    485:                        if ((p2 + 1) > (kmod_reference_t *)(data + size)) {
                    486:                                simple_unlock(&kmod_lock);
                    487:                                kmem_free(kernel_map, data, size);
                    488:                                goto retry;
                    489:                        }
                    490:                        // note the last 'k' in the chain has its next == 0
                    491:                        // since there can only be one like that, 
                    492:                        // this case is handled by the caller
                    493:                        *p2 = *r;
                    494:                        p2++; r = r->next; ref_count++;
                    495:                }
                    496:                p1->reference_list = (kmod_reference_t *)ref_count;
                    497:                p1++; k = k->next;
                    498:        }
                    499:        simple_unlock(&kmod_lock);
                    500:        
                    501:        rc = vm_map_copyin(kernel_map, data, size, TRUE, (vm_map_copy_t *)kmods);
                    502:        if (rc) {
                    503:                kmem_free(kernel_map, data, size);
                    504:                *kmods = 0;
                    505:                *kmodCount = 0;
                    506:                return rc;
                    507:        }
                    508:        *kmodCount = size;
                    509: 
                    510:        return KERN_SUCCESS;
                    511: }
                    512: 
                    513: #include <mach-o/loader.h>
                    514: 
                    515: extern void *getsectdatafromheader(struct mach_header *mhp,
                    516:                                    const char *segname,
                    517:                                    const char *sectname,
                    518:                                    int *size);
                    519: 
                    520: static kern_return_t
                    521: kmod_call_funcs_in_section(struct mach_header *header, const char *sectName)
                    522: {
                    523:        typedef void    (*Routine)(void);
                    524:        Routine *       routines;
                    525:        int             size, i;
                    526: 
                    527:        if (header->magic != MH_MAGIC) {
                    528:                return KERN_INVALID_ARGUMENT;
                    529:        }
                    530: 
                    531:        routines = (Routine *) getsectdatafromheader(header, SEG_TEXT, sectName, &size);
                    532:        if (!routines) return KERN_SUCCESS;
                    533: 
                    534:        size /= sizeof(Routine);
                    535:        for (i = 0; i < size; i++) {
                    536:                (*routines[i])();
                    537:        }
                    538: 
                    539:        return KERN_SUCCESS;
                    540: }
                    541: 
                    542: kern_return_t
                    543: kmod_initialize_cpp(kmod_info_t *info)
                    544: {
                    545:        return kmod_call_funcs_in_section((struct mach_header *)info->address, "__constructor");
                    546: }
                    547: 
                    548: kern_return_t
                    549: kmod_finalize_cpp(kmod_info_t *info)
                    550: {
                    551:        return kmod_call_funcs_in_section((struct mach_header *)info->address, "__destructor");
                    552: }
                    553: 
                    554: kern_return_t
                    555: kmod_default_start(struct kmod_info *ki, void *data)
                    556: {
                    557:        return KMOD_RETURN_SUCCESS;
                    558: }
                    559: 
                    560: kern_return_t
                    561: kmod_default_stop(struct kmod_info *ki, void *data)
                    562: {
                    563:        return KMOD_RETURN_SUCCESS;
                    564: }

unix.superglobalmegacorp.com

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