Annotation of OSKit-Mach/kern/syscall_emulation.c, revision 1.1.1.1

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: 
                     27: #include <mach/error.h>
                     28: #include <mach/vm_param.h>
                     29: #include <kern/syscall_emulation.h>
                     30: #include <kern/task.h>
                     31: #include <kern/kalloc.h>
                     32: #include <vm/vm_kern.h>
                     33: 
                     34: /* XXX */
                     35: #define syscall_emulation_sync(task)
                     36: 
                     37: 
                     38: 
                     39: /*
                     40:  * WARNING:
                     41:  * This code knows that kalloc() allocates memory most efficiently
                     42:  * in sizes that are powers of 2, and asks for those sizes.
                     43:  */
                     44: 
                     45: /*
                     46:  * Go from number of entries to size of struct eml_dispatch and back.
                     47:  */
                     48: #define        base_size       (sizeof(struct eml_dispatch) - sizeof(eml_routine_t))
                     49: #define        count_to_size(count) \
                     50:        (base_size + sizeof(vm_offset_t) * (count))
                     51: 
                     52: #define        size_to_count(size) \
                     53:        ( ((size) - base_size) / sizeof(vm_offset_t) )
                     54: 
                     55: /*
                     56:  *  eml_init:  initialize user space emulation code
                     57:  */
                     58: void eml_init()
                     59: {
                     60: }
                     61: 
                     62: /*
                     63:  * eml_task_reference() [Exported]
                     64:  *
                     65:  *     Bumps the reference count on the common emulation
                     66:  *     vector.
                     67:  */
                     68: 
                     69: void eml_task_reference(task, parent)
                     70:        task_t  task, parent;
                     71: {
                     72:        register eml_dispatch_t eml;
                     73: 
                     74:        if (parent == TASK_NULL)
                     75:            eml = EML_DISPATCH_NULL;
                     76:        else
                     77:            eml = parent->eml_dispatch;
                     78: 
                     79:        if (eml != EML_DISPATCH_NULL) {
                     80:            simple_lock(&eml->lock);
                     81:            eml->ref_count++;
                     82:            simple_unlock(&eml->lock);
                     83:        }
                     84:        task->eml_dispatch = eml;
                     85: }
                     86: 
                     87: 
                     88: /*
                     89:  * eml_task_deallocate() [Exported]
                     90:  *
                     91:  *     Cleans up after the emulation code when a process exits.
                     92:  */
                     93:  
                     94: void eml_task_deallocate(task)
                     95:        task_t task;
                     96: {
                     97:        register eml_dispatch_t eml;
                     98: 
                     99:        eml = task->eml_dispatch;
                    100:        if (eml != EML_DISPATCH_NULL) {
                    101:            int count;
                    102: 
                    103:            simple_lock(&eml->lock);
                    104:            count = --eml->ref_count;
                    105:            simple_unlock(&eml->lock);
                    106: 
                    107:            if (count == 0)
                    108:                kfree((vm_offset_t)eml, count_to_size(eml->disp_count));
                    109:        }
                    110: }
                    111: 
                    112: /*
                    113:  *   task_set_emulation_vector:  [Server Entry]
                    114:  *   set a list of emulated system calls for this task.
                    115:  */
                    116: kern_return_t
                    117: task_set_emulation_vector_internal(task, vector_start, emulation_vector,
                    118:                          emulation_vector_count)
                    119:        task_t                  task;
                    120:        int                     vector_start;
                    121:        emulation_vector_t      emulation_vector;
                    122:        unsigned int            emulation_vector_count;
                    123: {
                    124:        eml_dispatch_t  cur_eml, new_eml, old_eml;
                    125:        vm_size_t       new_size;
                    126:        int             cur_start, cur_end;
                    127:        int             new_start = 0, new_end = 0;
                    128:        int             vector_end;
                    129: 
                    130:        if (task == TASK_NULL)
                    131:                return EML_BAD_TASK;
                    132: 
                    133:        vector_end = vector_start + emulation_vector_count;
                    134: 
                    135:        /*
                    136:         * We try to re-use the existing emulation vector
                    137:         * if possible.  We can reuse the vector if it
                    138:         * is not shared with another task and if it is
                    139:         * large enough to contain the entries we are
                    140:         * supplying.
                    141:         *
                    142:         * We must grab the lock on the task to check whether
                    143:         * there is an emulation vector.
                    144:         * If the vector is shared or not large enough, we
                    145:         * need to drop the lock and allocate a new emulation
                    146:         * vector.
                    147:         *
                    148:         * While the lock is dropped, the emulation vector
                    149:         * may be released by all other tasks (giving us
                    150:         * exclusive use), or may be enlarged by another
                    151:         * task_set_emulation_vector call.  Therefore,
                    152:         * after allocating the new emulation vector, we
                    153:         * must grab the lock again to check whether we
                    154:         * really need the new vector we just allocated.
                    155:         *
                    156:         * Since an emulation vector cannot be altered
                    157:         * if it is in use by more than one task, the
                    158:         * task lock is sufficient to protect the vector`s
                    159:         * start, count, and contents.  The lock in the
                    160:         * vector protects only the reference count.
                    161:         */
                    162: 
                    163:        old_eml = EML_DISPATCH_NULL;    /* vector to discard */
                    164:        new_eml = EML_DISPATCH_NULL;    /* new vector */
                    165: 
                    166:        for (;;) {
                    167:            /*
                    168:             * Find the current emulation vector.
                    169:             * See whether we can overwrite it.
                    170:             */
                    171:            task_lock(task);
                    172:            cur_eml = task->eml_dispatch;
                    173:            if (cur_eml != EML_DISPATCH_NULL) {
                    174:                cur_start = cur_eml->disp_min;
                    175:                cur_end   = cur_eml->disp_count + cur_start;
                    176: 
                    177:                simple_lock(&cur_eml->lock);
                    178:                if (cur_eml->ref_count == 1 &&
                    179:                    cur_start <= vector_start &&
                    180:                    cur_end >= vector_end)
                    181:                {
                    182:                    /*
                    183:                     * Can use the existing emulation vector.
                    184:                     * Discard any new one we allocated.
                    185:                     */
                    186:                    simple_unlock(&cur_eml->lock);
                    187:                    old_eml = new_eml;
                    188:                    break;
                    189:                }
                    190: 
                    191:                if (new_eml != EML_DISPATCH_NULL &&
                    192:                    new_start <= cur_start &&
                    193:                    new_end >= cur_end)
                    194:                {
                    195:                    /*
                    196:                     * A new vector was allocated, and it is large enough
                    197:                     * to hold all the entries from the current vector.
                    198:                     * Copy the entries to the new emulation vector,
                    199:                     * deallocate the current one, and use the new one.
                    200:                     */
                    201:                    bcopy((char *)&cur_eml->disp_vector[0],
                    202:                          (char *)&new_eml->disp_vector[cur_start-new_start],
                    203:                          cur_eml->disp_count * sizeof(vm_offset_t));
                    204: 
                    205:                    if (--cur_eml->ref_count == 0)
                    206:                        old_eml = cur_eml;      /* discard old vector */
                    207:                    simple_unlock(&cur_eml->lock);
                    208: 
                    209:                    task->eml_dispatch = new_eml;
                    210:                    syscall_emulation_sync(task);
                    211:                    cur_eml = new_eml;
                    212:                    break;
                    213:                }
                    214:                simple_unlock(&cur_eml->lock);
                    215: 
                    216:                /*
                    217:                 * Need a new emulation vector.
                    218:                 * Ensure it will hold all the entries from
                    219:                 * both the old and new emulation vectors.
                    220:                 */
                    221:                new_start = vector_start;
                    222:                if (new_start > cur_start)
                    223:                    new_start = cur_start;
                    224:                new_end = vector_end;
                    225:                if (new_end < cur_end)
                    226:                    new_end = cur_end;
                    227:            }
                    228:            else {
                    229:                /*
                    230:                 * There is no current emulation vector.
                    231:                 * If a new one was allocated, use it.
                    232:                 */
                    233:                if (new_eml != EML_DISPATCH_NULL) {
                    234:                    task->eml_dispatch = new_eml;
                    235:                    cur_eml = new_eml;
                    236:                    break;
                    237:                }
                    238: 
                    239:                /*
                    240:                 * Compute the size needed for the new vector.
                    241:                 */
                    242:                new_start = vector_start;
                    243:                new_end = vector_end;
                    244:            }
                    245: 
                    246:            /*
                    247:             * Have no vector (or one that is no longer large enough).
                    248:             * Drop all the locks and allocate a new vector.
                    249:             * Repeat the loop to check whether the old vector was
                    250:             * changed while we didn`t hold the locks.
                    251:             */
                    252: 
                    253:            task_unlock(task);
                    254: 
                    255:            if (new_eml != EML_DISPATCH_NULL)
                    256:                kfree((vm_offset_t)new_eml, count_to_size(new_eml->disp_count));
                    257: 
                    258:            new_size = count_to_size(new_end - new_start);
                    259:            new_eml = (eml_dispatch_t) kalloc(new_size);
                    260: 
                    261:            bzero((char *)new_eml, new_size);
                    262:            simple_lock_init(&new_eml->lock);
                    263:            new_eml->ref_count = 1;
                    264:            new_eml->disp_min   = new_start;
                    265:            new_eml->disp_count = new_end - new_start;
                    266: 
                    267:            continue;
                    268:        }
                    269: 
                    270:        /*
                    271:         * We have the emulation vector.
                    272:         * Install the new emulation entries.
                    273:         */
                    274:        bcopy((char *)&emulation_vector[0],
                    275:              (char *)&cur_eml->disp_vector[vector_start - cur_eml->disp_min],
                    276:              emulation_vector_count * sizeof(vm_offset_t));
                    277: 
                    278:        task_unlock(task);
                    279: 
                    280:        /*
                    281:         * Discard any old emulation vector we don`t need.
                    282:         */
                    283:        if (old_eml)
                    284:            kfree((vm_offset_t) old_eml, count_to_size(old_eml->disp_count));
                    285: 
                    286:        return KERN_SUCCESS;
                    287: }
                    288: 
                    289: /*
                    290:  *     task_set_emulation_vector:  [Server Entry]
                    291:  *
                    292:  *     Set the list of emulated system calls for this task.
                    293:  *     The list is out-of-line.
                    294:  */
                    295: kern_return_t
                    296: task_set_emulation_vector(task, vector_start, emulation_vector,
                    297:                          emulation_vector_count)
                    298:        task_t                  task;
                    299:        int                     vector_start;
                    300:        emulation_vector_t      emulation_vector;
                    301:        unsigned int            emulation_vector_count;
                    302: {
                    303:        kern_return_t           kr;
                    304:        vm_offset_t             emul_vector_addr;
                    305: 
                    306:        if (task == TASK_NULL)
                    307:            return EML_BAD_TASK;        /* XXX sb KERN_INVALID_ARGUMENT */
                    308: 
                    309:        /*
                    310:         *      The emulation vector is really a vm_map_copy_t.
                    311:         */
                    312:        kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
                    313:                        (vm_map_copy_t) emulation_vector);
                    314:        if (kr != KERN_SUCCESS)
                    315:            return kr;
                    316: 
                    317:        /*
                    318:         *      Do the work.
                    319:         */
                    320:        kr = task_set_emulation_vector_internal(
                    321:                        task,
                    322:                        vector_start,
                    323:                        (emulation_vector_t) emul_vector_addr,
                    324:                        emulation_vector_count);
                    325: 
                    326:        /*
                    327:         *      Discard the memory
                    328:         */
                    329:        (void) kmem_free(ipc_kernel_map,
                    330:                         emul_vector_addr,
                    331:                         emulation_vector_count * sizeof(eml_dispatch_t));
                    332: 
                    333:        return kr;
                    334: }
                    335: 
                    336: /*
                    337:  *     Compatibility entry.  Vector is passed inline.
                    338:  */
                    339: kern_return_t
                    340: xxx_task_set_emulation_vector(task, vector_start, emulation_vector,
                    341:                          emulation_vector_count)
                    342:        task_t                  task;
                    343:        int                     vector_start;
                    344:        emulation_vector_t      emulation_vector;
                    345:        unsigned int            emulation_vector_count;
                    346: {
                    347:        return task_set_emulation_vector_internal(
                    348:                        task,
                    349:                        vector_start,
                    350:                        emulation_vector,
                    351:                        emulation_vector_count);
                    352: }
                    353: 
                    354: /*
                    355:  *     task_get_emulation_vector: [Server Entry]
                    356:  *
                    357:  *     Get the list of emulated system calls for this task.
                    358:  *     List is returned out-of-line.
                    359:  */
                    360: kern_return_t
                    361: task_get_emulation_vector(task, vector_start, emulation_vector,
                    362:                        emulation_vector_count)
                    363:        task_t                  task;
                    364:        int                     *vector_start;                  /* out */
                    365:        emulation_vector_t      *emulation_vector;              /* out */
                    366:        unsigned int            *emulation_vector_count;        /* out */
                    367: {
                    368:        eml_dispatch_t          eml;
                    369:        vm_size_t               vector_size, size;
                    370:        vm_offset_t             addr;
                    371: 
                    372:        if (task == TASK_NULL)
                    373:            return EML_BAD_TASK;
                    374: 
                    375:        addr = 0;
                    376:        size = 0;
                    377: 
                    378:        for(;;) {
                    379:            vm_size_t   size_needed;
                    380: 
                    381:            task_lock(task);
                    382:            eml = task->eml_dispatch;
                    383:            if (eml == EML_DISPATCH_NULL) {
                    384:                task_unlock(task);
                    385:                if (addr)
                    386:                    (void) kmem_free(ipc_kernel_map, addr, size);
                    387:                *vector_start = 0;
                    388:                *emulation_vector = 0;
                    389:                *emulation_vector_count = 0;
                    390:                return KERN_SUCCESS;
                    391:            }
                    392: 
                    393:            /*
                    394:             * Do we have the memory we need?
                    395:             */
                    396:            vector_size = eml->disp_count * sizeof(vm_offset_t);
                    397: 
                    398:            size_needed = round_page(vector_size);
                    399:            if (size_needed <= size)
                    400:                break;
                    401: 
                    402:            /*
                    403:             * If not, unlock the task and allocate more memory.
                    404:             */
                    405:            task_unlock(task);
                    406: 
                    407:            if (size != 0)
                    408:                kmem_free(ipc_kernel_map, addr, size);
                    409: 
                    410:            size = size_needed;
                    411:            if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS)
                    412:                return KERN_RESOURCE_SHORTAGE;
                    413:        }
                    414: 
                    415:        /*
                    416:         * Copy out the dispatch addresses
                    417:         */
                    418:        *vector_start = eml->disp_min;
                    419:        *emulation_vector_count = eml->disp_count;
                    420:        bcopy((char *)eml->disp_vector,
                    421:              (char *)addr,
                    422:              vector_size);
                    423: 
                    424:        /*
                    425:         * Unlock the task and free any memory we did not need
                    426:         */
                    427:        task_unlock(task);
                    428: 
                    429:     {
                    430:        vm_size_t       size_used, size_left;
                    431:        vm_map_copy_t   memory;
                    432: 
                    433:        /*
                    434:         * Free any unused memory beyond the end of the last page used
                    435:         */
                    436:        size_used = round_page(vector_size);
                    437:        if (size_used != size)
                    438:            (void) kmem_free(ipc_kernel_map,
                    439:                             addr + size_used,
                    440:                             size - size_used);
                    441: 
                    442:        /*
                    443:         * Zero the remainder of the page being returned.
                    444:         */
                    445:        size_left = size_used - vector_size;
                    446:        if (size_left > 0)
                    447:            bzero((char *)addr + vector_size, size_left);
                    448: 
                    449:        /*
                    450:         * Make memory into copyin form - this unwires it.
                    451:         */
                    452:        (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory);
                    453: 
                    454:        *emulation_vector = (emulation_vector_t) memory;
                    455:     }
                    456: 
                    457:        return KERN_SUCCESS;
                    458: }
                    459: 
                    460: /*
                    461:  *     xxx_task_get_emulation:  [Server Entry]
                    462:  *     get the list of emulated system calls for this task.
                    463:  *     Compatibility code: return list in-line.
                    464:  */
                    465: kern_return_t
                    466: xxx_task_get_emulation_vector(task, vector_start, emulation_vector,
                    467:                          emulation_vector_count)
                    468:        task_t                  task;
                    469:        int                     *vector_start;
                    470:        emulation_vector_t      emulation_vector; /* pointer to OUT array */
                    471:        unsigned int            *emulation_vector_count;        /*IN/OUT*/
                    472: {
                    473:        register eml_dispatch_t eml;
                    474: 
                    475:        if (task == TASK_NULL)
                    476:                return( EML_BAD_TASK );
                    477: 
                    478:        task_lock(task);
                    479: 
                    480:        eml = task->eml_dispatch;
                    481:        if (eml == EML_DISPATCH_NULL) {
                    482:                task_unlock(task);
                    483:                *vector_start = 0;
                    484:                *emulation_vector_count = 0;
                    485:                return( KERN_SUCCESS );
                    486:        }
                    487: 
                    488:        simple_lock(&eml->lock);
                    489: 
                    490:        if (*emulation_vector_count < eml->disp_count) {
                    491:                simple_unlock(&eml->lock);
                    492:                task_unlock(task);
                    493:                return( EML_BAD_CNT );
                    494:        }
                    495: 
                    496:        *vector_start = eml->disp_min;
                    497:        *emulation_vector_count = eml->disp_count;
                    498:        bcopy((char *)eml->disp_vector, (char *)emulation_vector,
                    499:              *emulation_vector_count * sizeof(vm_offset_t));
                    500:        simple_unlock(&eml->lock);
                    501: 
                    502:        task_unlock(task);
                    503: 
                    504:        return( KERN_SUCCESS );
                    505: }
                    506: 
                    507: /*
                    508:  *   task_set_emulation:  [Server Entry]
                    509:  *   set up for user space emulation of syscalls within this task.
                    510:  */
                    511: kern_return_t task_set_emulation(task, routine_entry_pt, routine_number)
                    512:        task_t          task;
                    513:        vm_offset_t     routine_entry_pt;
                    514:        int             routine_number;
                    515: {
                    516:        return task_set_emulation_vector_internal(task, routine_number,
                    517:                                         &routine_entry_pt, 1);
                    518: }

unix.superglobalmegacorp.com

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