Annotation of Gnu-Mach/kern/syscall_emulation.c, revision 1.1.1.3

1.1       root        1: /* 
                      2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
                      4:  * All Rights Reserved.
                      5:  * 
                      6:  * Permission to use, copy, modify and distribute this software and its
                      7:  * documentation is hereby granted, provided that both the copyright
                      8:  * notice and this permission notice appear in all copies of the
                      9:  * software, derivative works or modified versions, and any portions
                     10:  * thereof, and that both notices appear in supporting documentation.
                     11:  * 
                     12:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     13:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     14:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     15:  * 
                     16:  * Carnegie Mellon requests users of this software to return to
                     17:  * 
                     18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
                     22:  * 
                     23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: 
1.1.1.2   root       27: #include <string.h>
                     28: 
1.1       root       29: #include <mach/error.h>
                     30: #include <mach/vm_param.h>
                     31: #include <kern/syscall_emulation.h>
                     32: #include <kern/task.h>
                     33: #include <kern/kalloc.h>
                     34: #include <vm/vm_kern.h>
                     35: 
                     36: /* XXX */
                     37: #define syscall_emulation_sync(task)
                     38: 
                     39: 
                     40: 
                     41: /*
                     42:  * WARNING:
                     43:  * This code knows that kalloc() allocates memory most efficiently
                     44:  * in sizes that are powers of 2, and asks for those sizes.
                     45:  */
                     46: 
                     47: /*
                     48:  * Go from number of entries to size of struct eml_dispatch and back.
                     49:  */
                     50: #define        base_size       (sizeof(struct eml_dispatch) - sizeof(eml_routine_t))
                     51: #define        count_to_size(count) \
                     52:        (base_size + sizeof(vm_offset_t) * (count))
                     53: 
                     54: #define        size_to_count(size) \
                     55:        ( ((size) - base_size) / sizeof(vm_offset_t) )
                     56: 
                     57: /*
                     58:  *  eml_init:  initialize user space emulation code
                     59:  */
1.1.1.3 ! root       60: void eml_init(void)
1.1       root       61: {
                     62: }
                     63: 
                     64: /*
                     65:  * eml_task_reference() [Exported]
                     66:  *
                     67:  *     Bumps the reference count on the common emulation
                     68:  *     vector.
                     69:  */
                     70: 
1.1.1.3 ! root       71: void eml_task_reference(
        !            72:        task_t  task, 
        !            73:        task_t  parent)
1.1       root       74: {
1.1.1.3 ! root       75:        eml_dispatch_t  eml;
1.1       root       76: 
                     77:        if (parent == TASK_NULL)
                     78:            eml = EML_DISPATCH_NULL;
                     79:        else
                     80:            eml = parent->eml_dispatch;
                     81: 
                     82:        if (eml != EML_DISPATCH_NULL) {
                     83:            simple_lock(&eml->lock);
                     84:            eml->ref_count++;
                     85:            simple_unlock(&eml->lock);
                     86:        }
                     87:        task->eml_dispatch = eml;
                     88: }
                     89: 
                     90: 
                     91: /*
                     92:  * eml_task_deallocate() [Exported]
                     93:  *
                     94:  *     Cleans up after the emulation code when a process exits.
                     95:  */
                     96:  
                     97: void eml_task_deallocate(task)
1.1.1.3 ! root       98:        const task_t task;
1.1       root       99: {
1.1.1.3 ! root      100:        eml_dispatch_t  eml;
1.1       root      101: 
                    102:        eml = task->eml_dispatch;
                    103:        if (eml != EML_DISPATCH_NULL) {
                    104:            int count;
                    105: 
                    106:            simple_lock(&eml->lock);
                    107:            count = --eml->ref_count;
                    108:            simple_unlock(&eml->lock);
                    109: 
                    110:            if (count == 0)
                    111:                kfree((vm_offset_t)eml, count_to_size(eml->disp_count));
                    112:        }
                    113: }
                    114: 
                    115: /*
                    116:  *   task_set_emulation_vector:  [Server Entry]
                    117:  *   set a list of emulated system calls for this task.
                    118:  */
                    119: kern_return_t
1.1.1.3 ! root      120: task_set_emulation_vector_internal(
        !           121:        task_t                  task,
        !           122:        int                     vector_start,
        !           123:        emulation_vector_t      emulation_vector,
        !           124:        unsigned int            emulation_vector_count)
1.1       root      125: {
                    126:        eml_dispatch_t  cur_eml, new_eml, old_eml;
                    127:        vm_size_t       new_size;
                    128:        int             cur_start, cur_end;
                    129:        int             new_start = 0, new_end = 0;
                    130:        int             vector_end;
                    131: 
                    132:        if (task == TASK_NULL)
                    133:                return EML_BAD_TASK;
                    134: 
                    135:        vector_end = vector_start + emulation_vector_count;
                    136: 
                    137:        /*
                    138:         * We try to re-use the existing emulation vector
                    139:         * if possible.  We can reuse the vector if it
                    140:         * is not shared with another task and if it is
                    141:         * large enough to contain the entries we are
                    142:         * supplying.
                    143:         *
                    144:         * We must grab the lock on the task to check whether
                    145:         * there is an emulation vector.
                    146:         * If the vector is shared or not large enough, we
                    147:         * need to drop the lock and allocate a new emulation
                    148:         * vector.
                    149:         *
                    150:         * While the lock is dropped, the emulation vector
                    151:         * may be released by all other tasks (giving us
                    152:         * exclusive use), or may be enlarged by another
                    153:         * task_set_emulation_vector call.  Therefore,
                    154:         * after allocating the new emulation vector, we
                    155:         * must grab the lock again to check whether we
                    156:         * really need the new vector we just allocated.
                    157:         *
                    158:         * Since an emulation vector cannot be altered
                    159:         * if it is in use by more than one task, the
                    160:         * task lock is sufficient to protect the vector`s
                    161:         * start, count, and contents.  The lock in the
                    162:         * vector protects only the reference count.
                    163:         */
                    164: 
                    165:        old_eml = EML_DISPATCH_NULL;    /* vector to discard */
                    166:        new_eml = EML_DISPATCH_NULL;    /* new vector */
                    167: 
                    168:        for (;;) {
                    169:            /*
                    170:             * Find the current emulation vector.
                    171:             * See whether we can overwrite it.
                    172:             */
                    173:            task_lock(task);
                    174:            cur_eml = task->eml_dispatch;
                    175:            if (cur_eml != EML_DISPATCH_NULL) {
                    176:                cur_start = cur_eml->disp_min;
                    177:                cur_end   = cur_eml->disp_count + cur_start;
                    178: 
                    179:                simple_lock(&cur_eml->lock);
                    180:                if (cur_eml->ref_count == 1 &&
                    181:                    cur_start <= vector_start &&
                    182:                    cur_end >= vector_end)
                    183:                {
                    184:                    /*
                    185:                     * Can use the existing emulation vector.
                    186:                     * Discard any new one we allocated.
                    187:                     */
                    188:                    simple_unlock(&cur_eml->lock);
                    189:                    old_eml = new_eml;
                    190:                    break;
                    191:                }
                    192: 
                    193:                if (new_eml != EML_DISPATCH_NULL &&
                    194:                    new_start <= cur_start &&
                    195:                    new_end >= cur_end)
                    196:                {
                    197:                    /*
                    198:                     * A new vector was allocated, and it is large enough
                    199:                     * to hold all the entries from the current vector.
                    200:                     * Copy the entries to the new emulation vector,
                    201:                     * deallocate the current one, and use the new one.
                    202:                     */
1.1.1.2   root      203:                    memcpy(&new_eml->disp_vector[cur_start-new_start],
                    204:                           &cur_eml->disp_vector[0],
                    205:                           cur_eml->disp_count * sizeof(vm_offset_t));
1.1       root      206: 
                    207:                    if (--cur_eml->ref_count == 0)
                    208:                        old_eml = cur_eml;      /* discard old vector */
                    209:                    simple_unlock(&cur_eml->lock);
                    210: 
                    211:                    task->eml_dispatch = new_eml;
                    212:                    syscall_emulation_sync(task);
                    213:                    cur_eml = new_eml;
                    214:                    break;
                    215:                }
                    216:                simple_unlock(&cur_eml->lock);
                    217: 
                    218:                /*
                    219:                 * Need a new emulation vector.
                    220:                 * Ensure it will hold all the entries from
                    221:                 * both the old and new emulation vectors.
                    222:                 */
                    223:                new_start = vector_start;
                    224:                if (new_start > cur_start)
                    225:                    new_start = cur_start;
                    226:                new_end = vector_end;
                    227:                if (new_end < cur_end)
                    228:                    new_end = cur_end;
                    229:            }
                    230:            else {
                    231:                /*
                    232:                 * There is no current emulation vector.
                    233:                 * If a new one was allocated, use it.
                    234:                 */
                    235:                if (new_eml != EML_DISPATCH_NULL) {
                    236:                    task->eml_dispatch = new_eml;
                    237:                    cur_eml = new_eml;
                    238:                    break;
                    239:                }
                    240: 
                    241:                /*
                    242:                 * Compute the size needed for the new vector.
                    243:                 */
                    244:                new_start = vector_start;
                    245:                new_end = vector_end;
                    246:            }
                    247: 
                    248:            /*
                    249:             * Have no vector (or one that is no longer large enough).
                    250:             * Drop all the locks and allocate a new vector.
                    251:             * Repeat the loop to check whether the old vector was
                    252:             * changed while we didn`t hold the locks.
                    253:             */
                    254: 
                    255:            task_unlock(task);
                    256: 
                    257:            if (new_eml != EML_DISPATCH_NULL)
                    258:                kfree((vm_offset_t)new_eml, count_to_size(new_eml->disp_count));
                    259: 
                    260:            new_size = count_to_size(new_end - new_start);
                    261:            new_eml = (eml_dispatch_t) kalloc(new_size);
                    262: 
1.1.1.2   root      263:            memset(new_eml, 0, new_size);
1.1       root      264:            simple_lock_init(&new_eml->lock);
                    265:            new_eml->ref_count = 1;
                    266:            new_eml->disp_min   = new_start;
                    267:            new_eml->disp_count = new_end - new_start;
                    268: 
                    269:            continue;
                    270:        }
                    271: 
                    272:        /*
                    273:         * We have the emulation vector.
                    274:         * Install the new emulation entries.
                    275:         */
1.1.1.2   root      276:        memcpy(&cur_eml->disp_vector[vector_start - cur_eml->disp_min],
                    277:               &emulation_vector[0],
                    278:               emulation_vector_count * sizeof(vm_offset_t));
1.1       root      279: 
                    280:        task_unlock(task);
                    281: 
                    282:        /*
                    283:         * Discard any old emulation vector we don`t need.
                    284:         */
                    285:        if (old_eml)
                    286:            kfree((vm_offset_t) old_eml, count_to_size(old_eml->disp_count));
                    287: 
                    288:        return KERN_SUCCESS;
                    289: }
                    290: 
                    291: /*
                    292:  *     task_set_emulation_vector:  [Server Entry]
                    293:  *
                    294:  *     Set the list of emulated system calls for this task.
                    295:  *     The list is out-of-line.
                    296:  */
                    297: kern_return_t
1.1.1.3 ! root      298: task_set_emulation_vector(
        !           299:        task_t                  task,
        !           300:        int                     vector_start,
        !           301:        emulation_vector_t      emulation_vector,
        !           302:        unsigned int            emulation_vector_count)
1.1       root      303: {
                    304:        kern_return_t           kr;
                    305:        vm_offset_t             emul_vector_addr;
                    306: 
                    307:        if (task == TASK_NULL)
                    308:            return EML_BAD_TASK;        /* XXX sb KERN_INVALID_ARGUMENT */
                    309: 
                    310:        /*
                    311:         *      The emulation vector is really a vm_map_copy_t.
                    312:         */
                    313:        kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
                    314:                        (vm_map_copy_t) emulation_vector);
                    315:        if (kr != KERN_SUCCESS)
                    316:            return kr;
                    317: 
                    318:        /*
                    319:         *      Do the work.
                    320:         */
                    321:        kr = task_set_emulation_vector_internal(
                    322:                        task,
                    323:                        vector_start,
                    324:                        (emulation_vector_t) emul_vector_addr,
                    325:                        emulation_vector_count);
                    326: 
                    327:        /*
                    328:         *      Discard the memory
                    329:         */
                    330:        (void) kmem_free(ipc_kernel_map,
                    331:                         emul_vector_addr,
                    332:                         emulation_vector_count * sizeof(eml_dispatch_t));
                    333: 
                    334:        return kr;
                    335: }
                    336: 
                    337: /*
                    338:  *     task_get_emulation_vector: [Server Entry]
                    339:  *
                    340:  *     Get the list of emulated system calls for this task.
                    341:  *     List is returned out-of-line.
                    342:  */
                    343: kern_return_t
1.1.1.3 ! root      344: task_get_emulation_vector(
        !           345:        task_t                  task,
        !           346:        int                     *vector_start,                  /* out */
        !           347:        emulation_vector_t      *emulation_vector,              /* out */
        !           348:        unsigned int            *emulation_vector_count)        /* out */
1.1       root      349: {
                    350:        eml_dispatch_t          eml;
                    351:        vm_size_t               vector_size, size;
                    352:        vm_offset_t             addr;
                    353: 
                    354:        if (task == TASK_NULL)
                    355:            return EML_BAD_TASK;
                    356: 
                    357:        addr = 0;
                    358:        size = 0;
                    359: 
                    360:        for(;;) {
                    361:            vm_size_t   size_needed;
                    362: 
                    363:            task_lock(task);
                    364:            eml = task->eml_dispatch;
                    365:            if (eml == EML_DISPATCH_NULL) {
                    366:                task_unlock(task);
                    367:                if (addr)
                    368:                    (void) kmem_free(ipc_kernel_map, addr, size);
                    369:                *vector_start = 0;
                    370:                *emulation_vector = 0;
                    371:                *emulation_vector_count = 0;
                    372:                return KERN_SUCCESS;
                    373:            }
                    374: 
                    375:            /*
                    376:             * Do we have the memory we need?
                    377:             */
                    378:            vector_size = eml->disp_count * sizeof(vm_offset_t);
                    379: 
                    380:            size_needed = round_page(vector_size);
                    381:            if (size_needed <= size)
                    382:                break;
                    383: 
                    384:            /*
                    385:             * If not, unlock the task and allocate more memory.
                    386:             */
                    387:            task_unlock(task);
                    388: 
                    389:            if (size != 0)
                    390:                kmem_free(ipc_kernel_map, addr, size);
                    391: 
                    392:            size = size_needed;
                    393:            if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS)
                    394:                return KERN_RESOURCE_SHORTAGE;
                    395:        }
                    396: 
                    397:        /*
                    398:         * Copy out the dispatch addresses
                    399:         */
                    400:        *vector_start = eml->disp_min;
                    401:        *emulation_vector_count = eml->disp_count;
1.1.1.2   root      402:        memcpy((void *)addr,
                    403:               eml->disp_vector,
                    404:               vector_size);
1.1       root      405: 
                    406:        /*
                    407:         * Unlock the task and free any memory we did not need
                    408:         */
                    409:        task_unlock(task);
                    410: 
                    411:     {
                    412:        vm_size_t       size_used, size_left;
                    413:        vm_map_copy_t   memory;
                    414: 
                    415:        /*
                    416:         * Free any unused memory beyond the end of the last page used
                    417:         */
                    418:        size_used = round_page(vector_size);
                    419:        if (size_used != size)
                    420:            (void) kmem_free(ipc_kernel_map,
                    421:                             addr + size_used,
                    422:                             size - size_used);
                    423: 
                    424:        /*
                    425:         * Zero the remainder of the page being returned.
                    426:         */
                    427:        size_left = size_used - vector_size;
                    428:        if (size_left > 0)
1.1.1.2   root      429:            memset((char *)addr + vector_size, 0, size_left);
1.1       root      430: 
                    431:        /*
                    432:         * Make memory into copyin form - this unwires it.
                    433:         */
                    434:        (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory);
                    435: 
                    436:        *emulation_vector = (emulation_vector_t) memory;
                    437:     }
                    438: 
                    439:        return KERN_SUCCESS;
                    440: }
                    441: 
                    442: /*
                    443:  *   task_set_emulation:  [Server Entry]
                    444:  *   set up for user space emulation of syscalls within this task.
                    445:  */
1.1.1.3 ! root      446: kern_return_t task_set_emulation(
        !           447:        task_t          task,
        !           448:        vm_offset_t     routine_entry_pt,
        !           449:        int             routine_number)
1.1       root      450: {
                    451:        return task_set_emulation_vector_internal(task, routine_number,
                    452:                                         &routine_entry_pt, 1);
                    453: }

unix.superglobalmegacorp.com

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