Annotation of OSKit-Mach/kern/syscall_emulation.c, revision 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.