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

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:  */
                     60: void eml_init()
                     61: {
                     62: }
                     63: 
                     64: /*
                     65:  * eml_task_reference() [Exported]
                     66:  *
                     67:  *     Bumps the reference count on the common emulation
                     68:  *     vector.
                     69:  */
                     70: 
                     71: void eml_task_reference(task, parent)
                     72:        task_t  task, parent;
                     73: {
                     74:        register eml_dispatch_t eml;
                     75: 
                     76:        if (parent == TASK_NULL)
                     77:            eml = EML_DISPATCH_NULL;
                     78:        else
                     79:            eml = parent->eml_dispatch;
                     80: 
                     81:        if (eml != EML_DISPATCH_NULL) {
                     82:            simple_lock(&eml->lock);
                     83:            eml->ref_count++;
                     84:            simple_unlock(&eml->lock);
                     85:        }
                     86:        task->eml_dispatch = eml;
                     87: }
                     88: 
                     89: 
                     90: /*
                     91:  * eml_task_deallocate() [Exported]
                     92:  *
                     93:  *     Cleans up after the emulation code when a process exits.
                     94:  */
                     95:  
                     96: void eml_task_deallocate(task)
                     97:        task_t task;
                     98: {
                     99:        register eml_dispatch_t eml;
                    100: 
                    101:        eml = task->eml_dispatch;
                    102:        if (eml != EML_DISPATCH_NULL) {
                    103:            int count;
                    104: 
                    105:            simple_lock(&eml->lock);
                    106:            count = --eml->ref_count;
                    107:            simple_unlock(&eml->lock);
                    108: 
                    109:            if (count == 0)
                    110:                kfree((vm_offset_t)eml, count_to_size(eml->disp_count));
                    111:        }
                    112: }
                    113: 
                    114: /*
                    115:  *   task_set_emulation_vector:  [Server Entry]
                    116:  *   set a list of emulated system calls for this task.
                    117:  */
                    118: kern_return_t
                    119: task_set_emulation_vector_internal(task, vector_start, emulation_vector,
                    120:                          emulation_vector_count)
                    121:        task_t                  task;
                    122:        int                     vector_start;
                    123:        emulation_vector_t      emulation_vector;
                    124:        unsigned int            emulation_vector_count;
                    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
                    298: task_set_emulation_vector(task, vector_start, emulation_vector,
                    299:                          emulation_vector_count)
                    300:        task_t                  task;
                    301:        int                     vector_start;
                    302:        emulation_vector_t      emulation_vector;
                    303:        unsigned int            emulation_vector_count;
                    304: {
                    305:        kern_return_t           kr;
                    306:        vm_offset_t             emul_vector_addr;
                    307: 
                    308:        if (task == TASK_NULL)
                    309:            return EML_BAD_TASK;        /* XXX sb KERN_INVALID_ARGUMENT */
                    310: 
                    311:        /*
                    312:         *      The emulation vector is really a vm_map_copy_t.
                    313:         */
                    314:        kr = vm_map_copyout(ipc_kernel_map, &emul_vector_addr,
                    315:                        (vm_map_copy_t) emulation_vector);
                    316:        if (kr != KERN_SUCCESS)
                    317:            return kr;
                    318: 
                    319:        /*
                    320:         *      Do the work.
                    321:         */
                    322:        kr = task_set_emulation_vector_internal(
                    323:                        task,
                    324:                        vector_start,
                    325:                        (emulation_vector_t) emul_vector_addr,
                    326:                        emulation_vector_count);
                    327: 
                    328:        /*
                    329:         *      Discard the memory
                    330:         */
                    331:        (void) kmem_free(ipc_kernel_map,
                    332:                         emul_vector_addr,
                    333:                         emulation_vector_count * sizeof(eml_dispatch_t));
                    334: 
                    335:        return kr;
                    336: }
                    337: 
                    338: /*
                    339:  *     task_get_emulation_vector: [Server Entry]
                    340:  *
                    341:  *     Get the list of emulated system calls for this task.
                    342:  *     List is returned out-of-line.
                    343:  */
                    344: kern_return_t
                    345: task_get_emulation_vector(task, vector_start, emulation_vector,
                    346:                        emulation_vector_count)
                    347:        task_t                  task;
                    348:        int                     *vector_start;                  /* out */
                    349:        emulation_vector_t      *emulation_vector;              /* out */
                    350:        unsigned int            *emulation_vector_count;        /* out */
                    351: {
                    352:        eml_dispatch_t          eml;
                    353:        vm_size_t               vector_size, size;
                    354:        vm_offset_t             addr;
                    355: 
                    356:        if (task == TASK_NULL)
                    357:            return EML_BAD_TASK;
                    358: 
                    359:        addr = 0;
                    360:        size = 0;
                    361: 
                    362:        for(;;) {
                    363:            vm_size_t   size_needed;
                    364: 
                    365:            task_lock(task);
                    366:            eml = task->eml_dispatch;
                    367:            if (eml == EML_DISPATCH_NULL) {
                    368:                task_unlock(task);
                    369:                if (addr)
                    370:                    (void) kmem_free(ipc_kernel_map, addr, size);
                    371:                *vector_start = 0;
                    372:                *emulation_vector = 0;
                    373:                *emulation_vector_count = 0;
                    374:                return KERN_SUCCESS;
                    375:            }
                    376: 
                    377:            /*
                    378:             * Do we have the memory we need?
                    379:             */
                    380:            vector_size = eml->disp_count * sizeof(vm_offset_t);
                    381: 
                    382:            size_needed = round_page(vector_size);
                    383:            if (size_needed <= size)
                    384:                break;
                    385: 
                    386:            /*
                    387:             * If not, unlock the task and allocate more memory.
                    388:             */
                    389:            task_unlock(task);
                    390: 
                    391:            if (size != 0)
                    392:                kmem_free(ipc_kernel_map, addr, size);
                    393: 
                    394:            size = size_needed;
                    395:            if (kmem_alloc(ipc_kernel_map, &addr, size) != KERN_SUCCESS)
                    396:                return KERN_RESOURCE_SHORTAGE;
                    397:        }
                    398: 
                    399:        /*
                    400:         * Copy out the dispatch addresses
                    401:         */
                    402:        *vector_start = eml->disp_min;
                    403:        *emulation_vector_count = eml->disp_count;
1.1.1.2 ! root      404:        memcpy((void *)addr,
        !           405:               eml->disp_vector,
        !           406:               vector_size);
1.1       root      407: 
                    408:        /*
                    409:         * Unlock the task and free any memory we did not need
                    410:         */
                    411:        task_unlock(task);
                    412: 
                    413:     {
                    414:        vm_size_t       size_used, size_left;
                    415:        vm_map_copy_t   memory;
                    416: 
                    417:        /*
                    418:         * Free any unused memory beyond the end of the last page used
                    419:         */
                    420:        size_used = round_page(vector_size);
                    421:        if (size_used != size)
                    422:            (void) kmem_free(ipc_kernel_map,
                    423:                             addr + size_used,
                    424:                             size - size_used);
                    425: 
                    426:        /*
                    427:         * Zero the remainder of the page being returned.
                    428:         */
                    429:        size_left = size_used - vector_size;
                    430:        if (size_left > 0)
1.1.1.2 ! root      431:            memset((char *)addr + vector_size, 0, size_left);
1.1       root      432: 
                    433:        /*
                    434:         * Make memory into copyin form - this unwires it.
                    435:         */
                    436:        (void) vm_map_copyin(ipc_kernel_map, addr, vector_size, TRUE, &memory);
                    437: 
                    438:        *emulation_vector = (emulation_vector_t) memory;
                    439:     }
                    440: 
                    441:        return KERN_SUCCESS;
                    442: }
                    443: 
                    444: /*
                    445:  *   task_set_emulation:  [Server Entry]
                    446:  *   set up for user space emulation of syscalls within this task.
                    447:  */
                    448: kern_return_t task_set_emulation(task, routine_entry_pt, routine_number)
                    449:        task_t          task;
                    450:        vm_offset_t     routine_entry_pt;
                    451:        int             routine_number;
                    452: {
                    453:        return task_set_emulation_vector_internal(task, routine_number,
                    454:                                         &routine_entry_pt, 1);
                    455: }

unix.superglobalmegacorp.com

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