Annotation of Gnu-Mach/kern/ipc_mig.c, revision 1.1.1.5

1.1.1.2   root        1: /*
1.1       root        2:  * Mach Operating System
                      3:  * Copyright (c) 1991,1990 Carnegie Mellon University
                      4:  * All Rights Reserved.
1.1.1.2   root        5:  *
1.1       root        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.
1.1.1.2   root       11:  *
1.1       root       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.
1.1.1.2   root       15:  *
1.1       root       16:  * Carnegie Mellon requests users of this software to return to
1.1.1.2   root       17:  *
1.1       root       18:  *  Software Distribution Coordinator  or  [email protected]
                     19:  *  School of Computer Science
                     20:  *  Carnegie Mellon University
                     21:  *  Pittsburgh PA 15213-3890
1.1.1.2   root       22:  *
1.1       root       23:  * any improvements or extensions that they make and grant Carnegie Mellon
                     24:  * the rights to redistribute these changes.
                     25:  */
                     26: 
                     27: #include <mach/boolean.h>
                     28: #include <mach/port.h>
                     29: #include <mach/message.h>
                     30: #include <mach/thread_status.h>
1.1.1.3   root       31: #include <machine/locore.h>
1.1       root       32: #include <kern/ast.h>
1.1.1.3   root       33: #include <kern/debug.h>
1.1       root       34: #include <kern/ipc_tt.h>
1.1.1.3   root       35: #include <kern/syscall_subr.h>
1.1       root       36: #include <kern/thread.h>
                     37: #include <kern/task.h>
                     38: #include <kern/ipc_kobject.h>
1.1.1.3   root       39: #include <kern/ipc_tt.h>
1.1.1.4   root       40: #include <kern/ipc_mig.h>
1.1       root       41: #include <vm/vm_map.h>
                     42: #include <vm/vm_user.h>
                     43: #include <ipc/port.h>
                     44: #include <ipc/ipc_kmsg.h>
                     45: #include <ipc/ipc_entry.h>
                     46: #include <ipc/ipc_object.h>
                     47: #include <ipc/ipc_mqueue.h>
                     48: #include <ipc/ipc_space.h>
                     49: #include <ipc/ipc_port.h>
                     50: #include <ipc/ipc_pset.h>
                     51: #include <ipc/ipc_thread.h>
1.1.1.3   root       52: #include <ipc/mach_port.h>
                     53: #include <device/dev_hdr.h>
1.1       root       54: #include <device/device_types.h>
1.1.1.3   root       55: #include <device/ds_routines.h>
1.1       root       56: 
                     57: /*
                     58:  *     Routine:        mach_msg_send_from_kernel
                     59:  *     Purpose:
                     60:  *             Send a message from the kernel.
                     61:  *
                     62:  *             This is used by the client side of KernelUser interfaces
                     63:  *             to implement SimpleRoutines.  Currently, this includes
                     64:  *             device_reply and memory_object messages.
                     65:  *     Conditions:
                     66:  *             Nothing locked.
                     67:  *     Returns:
                     68:  *             MACH_MSG_SUCCESS        Sent the message.
                     69:  *             MACH_SEND_INVALID_DATA  Bad destination port.
                     70:  */
                     71: 
                     72: mach_msg_return_t
                     73: mach_msg_send_from_kernel(
                     74:        mach_msg_header_t       *msg,
                     75:        mach_msg_size_t         send_size)
                     76: {
                     77:        ipc_kmsg_t kmsg;
                     78:        mach_msg_return_t mr;
                     79: 
                     80:        if (!MACH_PORT_VALID(msg->msgh_remote_port))
                     81:                return MACH_SEND_INVALID_DEST;
                     82: 
                     83:        mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
                     84:        if (mr != MACH_MSG_SUCCESS)
                     85:                panic("mach_msg_send_from_kernel");
                     86: 
                     87:        ipc_kmsg_copyin_from_kernel(kmsg);
                     88:        ipc_mqueue_send_always(kmsg);
                     89: 
                     90:        return MACH_MSG_SUCCESS;
                     91: }
                     92: 
                     93: mach_msg_return_t
                     94: mach_msg_rpc_from_kernel(msg, send_size, reply_size)
1.1.1.4   root       95:        const mach_msg_header_t *msg;
1.1       root       96:        mach_msg_size_t send_size;
                     97:        mach_msg_size_t reply_size;
                     98: {
                     99:        panic("mach_msg_rpc_from_kernel"); /*XXX*/
                    100: }
                    101: 
                    102: /*
                    103:  *     Routine:        mach_msg_abort_rpc
                    104:  *     Purpose:
                    105:  *             Destroy the thread's ith_rpc_reply port.
                    106:  *             This will interrupt a mach_msg_rpc_from_kernel
                    107:  *             with a MACH_RCV_PORT_DIED return code.
                    108:  *     Conditions:
                    109:  *             Nothing locked.
                    110:  */
                    111: 
                    112: void
1.1.1.4   root      113: mach_msg_abort_rpc(ipc_thread_t thread)
1.1       root      114: {
                    115:        ipc_port_t reply = IP_NULL;
                    116: 
                    117:        ith_lock(thread);
                    118:        if (thread->ith_self != IP_NULL) {
                    119:                reply = thread->ith_rpc_reply;
                    120:                thread->ith_rpc_reply = IP_NULL;
                    121:        }
                    122:        ith_unlock(thread);
                    123: 
                    124:        if (reply != IP_NULL)
                    125:                ipc_port_dealloc_reply(reply);
                    126: }
                    127: 
                    128: /*
                    129:  *     Routine:        mach_msg
                    130:  *     Purpose:
                    131:  *             Like mach_msg_trap except that message buffers
                    132:  *             live in kernel space.  Doesn't handle any options.
                    133:  *
                    134:  *             This is used by in-kernel server threads to make
                    135:  *             kernel calls, to receive request messages, and
                    136:  *             to send reply messages.
                    137:  *     Conditions:
                    138:  *             Nothing locked.
                    139:  *     Returns:
                    140:  */
                    141: 
                    142: mach_msg_return_t
1.1.1.4   root      143: mach_msg(
                    144:        mach_msg_header_t       *msg,
                    145:        mach_msg_option_t       option,
                    146:        mach_msg_size_t         send_size,
                    147:        mach_msg_size_t         rcv_size,
                    148:        mach_port_t             rcv_name,
                    149:        mach_msg_timeout_t      time_out,
                    150:        mach_port_t             notify)
1.1       root      151: {
                    152:        ipc_space_t space = current_space();
                    153:        vm_map_t map = current_map();
                    154:        ipc_kmsg_t kmsg;
                    155:        mach_port_seqno_t seqno;
                    156:        mach_msg_return_t mr;
                    157: 
                    158:        if (option & MACH_SEND_MSG) {
                    159:                mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
                    160:                if (mr != MACH_MSG_SUCCESS)
                    161:                        panic("mach_msg");
                    162: 
                    163:                mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
                    164:                if (mr != MACH_MSG_SUCCESS) {
                    165:                        ikm_free(kmsg);
                    166:                        return mr;
                    167:                }
                    168: 
                    169:                do
                    170:                        mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
                    171:                                             MACH_MSG_TIMEOUT_NONE);
                    172:                while (mr == MACH_SEND_INTERRUPTED);
                    173:                assert(mr == MACH_MSG_SUCCESS);
                    174:        }
                    175: 
                    176:        if (option & MACH_RCV_MSG) {
                    177:                do {
                    178:                        ipc_object_t object;
                    179:                        ipc_mqueue_t mqueue;
                    180: 
                    181:                        mr = ipc_mqueue_copyin(space, rcv_name,
                    182:                                               &mqueue, &object);
                    183:                        if (mr != MACH_MSG_SUCCESS)
                    184:                                return mr;
                    185:                        /* hold ref for object; mqueue is locked */
                    186: 
                    187:                        mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
                    188:                                                MACH_MSG_SIZE_MAX,
                    189:                                                MACH_MSG_TIMEOUT_NONE,
                    190:                                                FALSE, IMQ_NULL_CONTINUE,
                    191:                                                &kmsg, &seqno);
                    192:                        /* mqueue is unlocked */
                    193:                        ipc_object_release(object);
                    194:                } while (mr == MACH_RCV_INTERRUPTED);
                    195:                if (mr != MACH_MSG_SUCCESS)
                    196:                        return mr;
                    197: 
                    198:                kmsg->ikm_header.msgh_seqno = seqno;
                    199: 
                    200:                if (rcv_size < kmsg->ikm_header.msgh_size) {
                    201:                        ipc_kmsg_copyout_dest(kmsg, space);
                    202:                        ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
                    203:                        return MACH_RCV_TOO_LARGE;
                    204:                }
                    205: 
                    206:                mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
                    207:                if (mr != MACH_MSG_SUCCESS) {
                    208:                        if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
                    209:                                ipc_kmsg_put_to_kernel(msg, kmsg,
                    210:                                                kmsg->ikm_header.msgh_size);
                    211:                        } else {
                    212:                                ipc_kmsg_copyout_dest(kmsg, space);
                    213:                                ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
                    214:                        }
                    215: 
                    216:                        return mr;
                    217:                }
                    218: 
                    219:                ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
                    220:        }
                    221: 
                    222:        return MACH_MSG_SUCCESS;
                    223: }
                    224: 
                    225: /*
                    226:  *     Routine:        mig_get_reply_port
                    227:  *     Purpose:
                    228:  *             Called by client side interfaces living in the kernel
                    229:  *             to get a reply port.  This port is used for
                    230:  *             mach_msg() calls which are kernel calls.
                    231:  */
                    232: 
                    233: mach_port_t
                    234: mig_get_reply_port(void)
                    235: {
                    236:        ipc_thread_t self = current_thread();
                    237: 
                    238:        if (self->ith_mig_reply == MACH_PORT_NULL)
                    239:                self->ith_mig_reply = mach_reply_port();
                    240: 
                    241:        return self->ith_mig_reply;
                    242: }
                    243: 
                    244: /*
                    245:  *     Routine:        mig_dealloc_reply_port
                    246:  *     Purpose:
                    247:  *             Called by client side interfaces to get rid of a reply port.
                    248:  *             Shouldn't ever be called inside the kernel, because
                    249:  *             kernel calls shouldn't prompt Mig to call it.
                    250:  */
                    251: 
                    252: void
                    253: mig_dealloc_reply_port(
                    254:        mach_port_t     reply_port)
                    255: {
                    256:        panic("mig_dealloc_reply_port");
                    257: }
                    258: 
                    259: /*
                    260:  *     Routine:        mig_put_reply_port
                    261:  *     Purpose:
1.1.1.2   root      262:  *             Called by client side interfaces after each RPC to
1.1       root      263:  *             let the client recycle the reply port if it wishes.
                    264:  */
                    265: void
                    266: mig_put_reply_port(
                    267:        mach_port_t     reply_port)
                    268: {
                    269: }
                    270: 
                    271: /*
                    272:  * mig_strncpy.c - by Joshua Block
                    273:  *
1.1.1.4   root      274:  * mig_strncpy -- Bounded string copy.  Does what the library routine
                    275:  * strncpy does: Copies the (null terminated) string in src into dest,
                    276:  * a buffer of length len.  Returns the length of the destination
                    277:  * string excluding the terminating null.
1.1       root      278:  *
                    279:  * Parameters:
1.1.1.2   root      280:  *
1.1       root      281:  *     dest - Pointer to destination buffer.
1.1.1.2   root      282:  *
1.1       root      283:  *     src - Pointer to source string.
1.1.1.2   root      284:  *
1.1       root      285:  *     len - Length of destination buffer.
                    286:  */
1.1.1.4   root      287: vm_size_t
                    288: mig_strncpy(dest, src, len)
                    289:        char *dest;
                    290:        const char *src;
                    291:        int len;
                    292: {
                    293:        char *dest_ = dest;
                    294:        int i;
                    295: 
                    296:        if (len <= 0)
                    297:                return 0;
                    298: 
                    299:        for (i = 0; i < len; i++) {
                    300:                if (! (*dest = *src))
                    301:                        break;
                    302:                dest++;
                    303:                src++;
                    304:        }
1.1       root      305: 
1.1.1.4   root      306:        return dest - dest_;
1.1       root      307: }
                    308: 
                    309: #define        fast_send_right_lookup(name, port, abort)                       \
                    310: MACRO_BEGIN                                                            \
1.1.1.4   root      311:        ipc_space_t space = current_space();                            \
                    312:        ipc_entry_t entry;                                              \
1.1       root      313:                                                                        \
                    314:        is_read_lock(space);                                            \
                    315:        assert(space->is_active);                                       \
                    316:                                                                        \
1.1.1.5 ! root      317:        entry = ipc_entry_lookup (space, name);                         \
        !           318:        if (entry == IE_NULL) {                                         \
        !           319:                is_read_unlock (space);                                 \
        !           320:                abort;                                                  \
        !           321:        }                                                               \
        !           322:                                                                        \
        !           323:        if (IE_BITS_TYPE (entry->ie_bits) != MACH_PORT_TYPE_SEND) {     \
        !           324:                is_read_unlock (space);                                 \
1.1       root      325:                abort;                                                  \
                    326:        }                                                               \
                    327:                                                                        \
                    328:        port = (ipc_port_t) entry->ie_object;                           \
                    329:        assert(port != IP_NULL);                                        \
                    330:                                                                        \
                    331:        ip_lock(port);                                                  \
                    332:        /* can safely unlock space now that port is locked */           \
                    333:        is_read_unlock(space);                                          \
                    334: MACRO_END
                    335: 
                    336: device_t
1.1.1.4   root      337: port_name_to_device(mach_port_t name)
1.1       root      338: {
1.1.1.4   root      339:        ipc_port_t port;
                    340:        device_t device;
1.1.1.2   root      341: 
1.1       root      342:        fast_send_right_lookup(name, port, goto abort);
                    343:        /* port is locked */
1.1.1.2   root      344: 
1.1       root      345:        /*
                    346:         * Now map the port object to a device object.
                    347:         * This is an inline version of dev_port_lookup().
                    348:         */
                    349:        if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
                    350:                device = (device_t) port->ip_kobject;
                    351:                device_reference(device);
                    352:                ip_unlock(port);
1.1.1.2   root      353:                return device;
1.1       root      354:        }
1.1.1.2   root      355: 
1.1       root      356:        ip_unlock(port);
                    357:        return DEVICE_NULL;
1.1.1.2   root      358: 
1.1       root      359:        /*
                    360:         * The slow case.  The port wasn't easily accessible.
                    361:         */
                    362:     abort: {
                    363:            ipc_port_t kern_port;
                    364:            kern_return_t kr;
1.1.1.2   root      365: 
1.1       root      366:            kr = ipc_object_copyin(current_space(), name,
                    367:                                   MACH_MSG_TYPE_COPY_SEND,
                    368:                                   (ipc_object_t *) &kern_port);
                    369:            if (kr != KERN_SUCCESS)
                    370:                    return DEVICE_NULL;
1.1.1.2   root      371: 
1.1       root      372:            device = dev_port_lookup(kern_port);
                    373:            if (IP_VALID(kern_port))
                    374:                    ipc_port_release_send(kern_port);
                    375:            return device;
                    376:     }
                    377: }
                    378: 
                    379: thread_t
1.1.1.4   root      380: port_name_to_thread(mach_port_t name)
1.1       root      381: {
1.1.1.4   root      382:        ipc_port_t port;
1.1       root      383: 
                    384:        fast_send_right_lookup(name, port, goto abort);
                    385:        /* port is locked */
                    386: 
                    387:        if (ip_active(port) &&
                    388:            (ip_kotype(port) == IKOT_THREAD)) {
1.1.1.4   root      389:                thread_t thread;
1.1       root      390: 
                    391:                thread = (thread_t) port->ip_kobject;
                    392:                assert(thread != THREAD_NULL);
                    393: 
                    394:                /* thread referencing is a bit complicated,
                    395:                   so don't bother to expand inline */
                    396:                thread_reference(thread);
                    397:                ip_unlock(port);
                    398: 
                    399:                return thread;
                    400:        }
                    401: 
                    402:        ip_unlock(port);
                    403:        return THREAD_NULL;
                    404: 
                    405:     abort: {
                    406:        thread_t thread;
                    407:        ipc_port_t kern_port;
                    408:        kern_return_t kr;
                    409: 
                    410:        kr = ipc_object_copyin(current_space(), name,
                    411:                               MACH_MSG_TYPE_COPY_SEND,
                    412:                               (ipc_object_t *) &kern_port);
                    413:        if (kr != KERN_SUCCESS)
                    414:                return THREAD_NULL;
                    415: 
                    416:        thread = convert_port_to_thread(kern_port);
                    417:        if (IP_VALID(kern_port))
                    418:                ipc_port_release_send(kern_port);
                    419: 
                    420:        return thread;
                    421:     }
                    422: }
                    423: 
                    424: task_t
1.1.1.4   root      425: port_name_to_task(mach_port_t name)
1.1       root      426: {
1.1.1.4   root      427:        ipc_port_t port;
1.1       root      428: 
                    429:        fast_send_right_lookup(name, port, goto abort);
                    430:        /* port is locked */
                    431: 
                    432:        if (ip_active(port) &&
                    433:            (ip_kotype(port) == IKOT_TASK)) {
1.1.1.4   root      434:                task_t task;
1.1       root      435: 
                    436:                task = (task_t) port->ip_kobject;
                    437:                assert(task != TASK_NULL);
                    438: 
                    439:                task_lock(task);
                    440:                /* can safely unlock port now that task is locked */
                    441:                ip_unlock(port);
                    442: 
                    443:                task->ref_count++;
                    444:                task_unlock(task);
                    445: 
                    446:                return task;
                    447:        }
                    448: 
                    449:        ip_unlock(port);
                    450:        return TASK_NULL;
                    451: 
                    452:     abort: {
                    453:        task_t task;
                    454:        ipc_port_t kern_port;
                    455:        kern_return_t kr;
                    456: 
                    457:        kr = ipc_object_copyin(current_space(), name,
                    458:                               MACH_MSG_TYPE_COPY_SEND,
                    459:                               (ipc_object_t *) &kern_port);
                    460:        if (kr != KERN_SUCCESS)
                    461:                return TASK_NULL;
                    462: 
                    463:        task = convert_port_to_task(kern_port);
                    464:        if (IP_VALID(kern_port))
                    465:                ipc_port_release_send(kern_port);
                    466: 
                    467:        return task;
                    468:     }
                    469: }
                    470: 
                    471: vm_map_t
                    472: port_name_to_map(
                    473:        mach_port_t     name)
                    474: {
1.1.1.4   root      475:        ipc_port_t port;
1.1       root      476: 
                    477:        fast_send_right_lookup(name, port, goto abort);
                    478:        /* port is locked */
                    479: 
                    480:        if (ip_active(port) &&
                    481:            (ip_kotype(port) == IKOT_TASK)) {
1.1.1.4   root      482:                vm_map_t map;
1.1       root      483: 
                    484:                map = ((task_t) port->ip_kobject)->map;
                    485:                assert(map != VM_MAP_NULL);
                    486: 
                    487:                simple_lock(&map->ref_lock);
                    488:                /* can safely unlock port now that map is locked */
                    489:                ip_unlock(port);
                    490: 
                    491:                map->ref_count++;
                    492:                simple_unlock(&map->ref_lock);
                    493: 
                    494:                return map;
                    495:        }
                    496: 
                    497:        ip_unlock(port);
                    498:        return VM_MAP_NULL;
                    499: 
                    500:     abort: {
                    501:        vm_map_t map;
                    502:        ipc_port_t kern_port;
                    503:        kern_return_t kr;
                    504: 
                    505:        kr = ipc_object_copyin(current_space(), name,
                    506:                               MACH_MSG_TYPE_COPY_SEND,
                    507:                               (ipc_object_t *) &kern_port);
                    508:        if (kr != KERN_SUCCESS)
                    509:                return VM_MAP_NULL;
                    510: 
                    511:        map = convert_port_to_map(kern_port);
                    512:        if (IP_VALID(kern_port))
                    513:                ipc_port_release_send(kern_port);
                    514: 
                    515:        return map;
                    516:     }
                    517: }
                    518: 
                    519: ipc_space_t
1.1.1.4   root      520: port_name_to_space(mach_port_t name)
1.1       root      521: {
1.1.1.4   root      522:        ipc_port_t port;
1.1       root      523: 
                    524:        fast_send_right_lookup(name, port, goto abort);
                    525:        /* port is locked */
                    526: 
                    527:        if (ip_active(port) &&
                    528:            (ip_kotype(port) == IKOT_TASK)) {
1.1.1.4   root      529:                ipc_space_t space;
1.1       root      530: 
                    531:                space = ((task_t) port->ip_kobject)->itk_space;
                    532:                assert(space != IS_NULL);
                    533: 
                    534:                simple_lock(&space->is_ref_lock_data);
                    535:                /* can safely unlock port now that space is locked */
                    536:                ip_unlock(port);
                    537: 
                    538:                space->is_references++;
                    539:                simple_unlock(&space->is_ref_lock_data);
                    540: 
                    541:                return space;
                    542:        }
                    543: 
                    544:        ip_unlock(port);
                    545:        return IS_NULL;
                    546: 
                    547:     abort: {
                    548:        ipc_space_t space;
                    549:        ipc_port_t kern_port;
                    550:        kern_return_t kr;
                    551: 
                    552:        kr = ipc_object_copyin(current_space(), name,
                    553:                               MACH_MSG_TYPE_COPY_SEND,
                    554:                               (ipc_object_t *) &kern_port);
                    555:        if (kr != KERN_SUCCESS)
                    556:                return IS_NULL;
                    557: 
                    558:        space = convert_port_to_space(kern_port);
                    559:        if (IP_VALID(kern_port))
                    560:                ipc_port_release_send(kern_port);
                    561: 
                    562:        return space;
                    563:     }
                    564: }
                    565: 
                    566: /*
                    567:  * Hack to translate a thread port to a thread pointer for calling
                    568:  * thread_get_state and thread_set_state.  This is only necessary
                    569:  * because the IPC message for these two operations overflows the
                    570:  * kernel stack.
                    571:  *
                    572:  * AARGH!
                    573:  */
                    574: 
1.1.1.4   root      575: kern_return_t thread_get_state_KERNEL(
                    576:        mach_port_t     thread_port,    /* port right for thread */
                    577:        int             flavor,
                    578:        thread_state_t  old_state,      /* pointer to OUT array */
                    579:        natural_t       *old_state_count)       /* IN/OUT */
1.1       root      580: {
                    581:        thread_t        thread;
                    582:        kern_return_t   result;
                    583: 
                    584:        thread = port_name_to_thread(thread_port);
                    585:        result = thread_get_state(thread, flavor, old_state, old_state_count);
                    586:        thread_deallocate(thread);
                    587: 
                    588:        return result;
                    589: }
                    590: 
1.1.1.4   root      591: kern_return_t thread_set_state_KERNEL(
                    592:        mach_port_t     thread_port,    /* port right for thread */
                    593:        int             flavor,
                    594:        thread_state_t  new_state,
                    595:        natural_t       new_state_count)
1.1       root      596: {
                    597:        thread_t        thread;
                    598:        kern_return_t   result;
                    599: 
                    600:        thread = port_name_to_thread(thread_port);
                    601:        result = thread_set_state(thread, flavor, new_state, new_state_count);
                    602:        thread_deallocate(thread);
                    603: 
                    604:        return result;
                    605: }
                    606: 
                    607: /*
                    608:  *     Things to keep in mind:
                    609:  *
                    610:  *     The idea here is to duplicate the semantics of the true kernel RPC.
                    611:  *     The destination port/object should be checked first, before anything
                    612:  *     that the user might notice (like ipc_object_copyin).  Return
                    613:  *     MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
                    614:  *     knows to fall back on an RPC.  For other return values, it won't
                    615:  *     retry with an RPC.  The retry might get a different (incorrect) rc.
                    616:  *     Return values are only set (and should only be set, with copyout)
1.1.1.4   root      617:  *     on successful calls.
1.1       root      618:  */
                    619: 
                    620: kern_return_t
                    621: syscall_vm_map(
                    622:        mach_port_t     target_map,
                    623:        vm_offset_t     *address,
                    624:        vm_size_t       size,
                    625:        vm_offset_t     mask,
                    626:        boolean_t       anywhere,
                    627:        mach_port_t     memory_object,
                    628:        vm_offset_t     offset,
                    629:        boolean_t       copy,
                    630:        vm_prot_t       cur_protection,
                    631:        vm_prot_t       max_protection,
                    632:        vm_inherit_t    inheritance)
                    633: {
                    634:        vm_map_t                map;
                    635:        ipc_port_t              port;
                    636:        vm_offset_t             addr;
                    637:        kern_return_t           result;
                    638: 
                    639:        map = port_name_to_map(target_map);
                    640:        if (map == VM_MAP_NULL)
                    641:                return MACH_SEND_INTERRUPTED;
                    642: 
                    643:        if (MACH_PORT_VALID(memory_object)) {
                    644:                result = ipc_object_copyin(current_space(), memory_object,
                    645:                                           MACH_MSG_TYPE_COPY_SEND,
                    646:                                           (ipc_object_t *) &port);
                    647:                if (result != KERN_SUCCESS) {
                    648:                        vm_map_deallocate(map);
                    649:                        return result;
                    650:                }
                    651:        } else
                    652:                port = (ipc_port_t) memory_object;
                    653: 
1.1.1.4   root      654:        copyin(address, &addr, sizeof(vm_offset_t));
1.1       root      655:        result = vm_map(map, &addr, size, mask, anywhere,
                    656:                        port, offset, copy,
                    657:                        cur_protection, max_protection, inheritance);
                    658:        if (result == KERN_SUCCESS)
1.1.1.4   root      659:                copyout(&addr, address, sizeof(vm_offset_t));
1.1       root      660:        if (IP_VALID(port))
                    661:                ipc_port_release_send(port);
                    662:        vm_map_deallocate(map);
                    663: 
                    664:        return result;
                    665: }
                    666: 
1.1.1.4   root      667: kern_return_t syscall_vm_allocate(
                    668:        mach_port_t             target_map,
                    669:        vm_offset_t             *address,
                    670:        vm_size_t               size,
                    671:        boolean_t               anywhere)
1.1       root      672: {
                    673:        vm_map_t                map;
                    674:        vm_offset_t             addr;
                    675:        kern_return_t           result;
                    676: 
                    677:        map = port_name_to_map(target_map);
                    678:        if (map == VM_MAP_NULL)
                    679:                return MACH_SEND_INTERRUPTED;
                    680: 
1.1.1.4   root      681:        copyin(address, &addr, sizeof(vm_offset_t));
1.1       root      682:        result = vm_allocate(map, &addr, size, anywhere);
                    683:        if (result == KERN_SUCCESS)
1.1.1.4   root      684:                copyout(&addr, address, sizeof(vm_offset_t));
1.1       root      685:        vm_map_deallocate(map);
                    686: 
                    687:        return result;
                    688: }
                    689: 
1.1.1.4   root      690: kern_return_t syscall_vm_deallocate(
                    691:        mach_port_t             target_map,
                    692:        vm_offset_t             start,
                    693:        vm_size_t               size)
1.1       root      694: {
                    695:        vm_map_t                map;
                    696:        kern_return_t           result;
                    697: 
                    698:        map = port_name_to_map(target_map);
                    699:        if (map == VM_MAP_NULL)
                    700:                return MACH_SEND_INTERRUPTED;
                    701: 
                    702:        result = vm_deallocate(map, start, size);
                    703:        vm_map_deallocate(map);
                    704: 
                    705:        return result;
                    706: }
                    707: 
1.1.1.4   root      708: kern_return_t syscall_task_create(
                    709:        mach_port_t     parent_task,
                    710:        boolean_t       inherit_memory,
                    711:        mach_port_t     *child_task)            /* OUT */
1.1       root      712: {
                    713:        task_t          t, c;
                    714:        ipc_port_t      port;
                    715:        mach_port_t     name;
                    716:        kern_return_t   result;
                    717: 
                    718:        t = port_name_to_task(parent_task);
                    719:        if (t == TASK_NULL)
                    720:                return MACH_SEND_INTERRUPTED;
                    721: 
                    722:        result = task_create(t, inherit_memory, &c);
                    723:        if (result == KERN_SUCCESS) {
                    724:                port = (ipc_port_t) convert_task_to_port(c);
                    725:                /* always returns a name, even for non-success return codes */
                    726:                (void) ipc_kmsg_copyout_object(current_space(),
                    727:                                               (ipc_object_t) port,
                    728:                                               MACH_MSG_TYPE_PORT_SEND, &name);
1.1.1.4   root      729:                copyout(&name, child_task,
1.1       root      730:                        sizeof(mach_port_t));
                    731:        }
                    732:        task_deallocate(t);
                    733: 
                    734:        return result;
                    735: }
                    736: 
1.1.1.4   root      737: kern_return_t syscall_task_terminate(mach_port_t task)
1.1       root      738: {
                    739:        task_t          t;
                    740:        kern_return_t   result;
                    741: 
                    742:        t = port_name_to_task(task);
                    743:        if (t == TASK_NULL)
                    744:                return MACH_SEND_INTERRUPTED;
                    745: 
                    746:        result = task_terminate(t);
                    747:        task_deallocate(t);
                    748: 
                    749:        return result;
                    750: }
                    751: 
1.1.1.4   root      752: kern_return_t syscall_task_suspend(mach_port_t task)
1.1       root      753: {
                    754:        task_t          t;
                    755:        kern_return_t   result;
                    756: 
                    757:        t = port_name_to_task(task);
                    758:        if (t == TASK_NULL)
                    759:                return MACH_SEND_INTERRUPTED;
                    760: 
                    761:        result = task_suspend(t);
                    762:        task_deallocate(t);
                    763: 
                    764:        return result;
                    765: }
                    766: 
1.1.1.4   root      767: kern_return_t syscall_task_set_special_port(
                    768:        mach_port_t     task,
                    769:        int             which_port,
                    770:        mach_port_t     port_name)
1.1       root      771: {
                    772:        task_t          t;
                    773:        ipc_port_t      port;
                    774:        kern_return_t   result;
                    775: 
                    776:        t = port_name_to_task(task);
                    777:        if (t == TASK_NULL)
                    778:                return MACH_SEND_INTERRUPTED;
                    779: 
                    780:        if (MACH_PORT_VALID(port_name)) {
                    781:                result = ipc_object_copyin(current_space(), port_name,
                    782:                                           MACH_MSG_TYPE_COPY_SEND,
                    783:                                           (ipc_object_t *) &port);
                    784:                if (result != KERN_SUCCESS) {
                    785:                        task_deallocate(t);
                    786:                        return result;
                    787:                }
                    788:        } else
                    789:                port = (ipc_port_t) port_name;
                    790: 
                    791:        result = task_set_special_port(t, which_port, port);
                    792:        if ((result != KERN_SUCCESS) && IP_VALID(port))
                    793:                ipc_port_release_send(port);
                    794:        task_deallocate(t);
                    795: 
                    796:        return result;
                    797: }
                    798: 
                    799: kern_return_t
1.1.1.4   root      800: syscall_mach_port_allocate(
                    801:        mach_port_t             task,
                    802:        mach_port_right_t       right,
                    803:        mach_port_t             *namep)
1.1       root      804: {
                    805:        ipc_space_t space;
                    806:        mach_port_t name;
                    807:        kern_return_t kr;
                    808: 
                    809:        space = port_name_to_space(task);
                    810:        if (space == IS_NULL)
                    811:                return MACH_SEND_INTERRUPTED;
                    812: 
                    813:        kr = mach_port_allocate(space, right, &name);
                    814:        if (kr == KERN_SUCCESS)
1.1.1.4   root      815:                copyout(&name, namep, sizeof(mach_port_t));
1.1       root      816:        is_release(space);
                    817: 
                    818:        return kr;
                    819: }
                    820: 
                    821: kern_return_t
1.1.1.4   root      822: syscall_mach_port_allocate_name(
                    823:        mach_port_t             task,
                    824:        mach_port_right_t       right,
                    825:        mach_port_t             name)
1.1       root      826: {
                    827:        ipc_space_t space;
                    828:        kern_return_t kr;
                    829: 
                    830:        space = port_name_to_space(task);
                    831:        if (space == IS_NULL)
                    832:                return MACH_SEND_INTERRUPTED;
                    833: 
                    834:        kr = mach_port_allocate_name(space, right, name);
                    835:        is_release(space);
                    836: 
                    837:        return kr;
                    838: }
                    839: 
                    840: kern_return_t
1.1.1.4   root      841: syscall_mach_port_deallocate(
                    842:        mach_port_t task,
                    843:        mach_port_t name)
1.1       root      844: {
                    845:        ipc_space_t space;
                    846:        kern_return_t kr;
                    847: 
                    848:        space = port_name_to_space(task);
                    849:        if (space == IS_NULL)
                    850:                return MACH_SEND_INTERRUPTED;
                    851: 
                    852:        kr = mach_port_deallocate(space, name);
                    853:        is_release(space);
                    854: 
                    855:        return kr;
                    856: }
                    857: 
                    858: kern_return_t
1.1.1.4   root      859: syscall_mach_port_insert_right(
                    860:        mach_port_t             task,
                    861:        mach_port_t             name,
                    862:        mach_port_t             right,
                    863:        mach_msg_type_name_t    rightType)
1.1       root      864: {
                    865:        ipc_space_t space;
                    866:        ipc_object_t object;
                    867:        mach_msg_type_name_t newtype;
                    868:        kern_return_t kr;
                    869: 
                    870:        space = port_name_to_space(task);
                    871:        if (space == IS_NULL)
                    872:                return MACH_SEND_INTERRUPTED;
                    873: 
                    874:        if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
                    875:                is_release(space);
                    876:                return KERN_INVALID_VALUE;
                    877:        }
                    878: 
                    879:        if (MACH_PORT_VALID(right)) {
                    880:                kr = ipc_object_copyin(current_space(), right, rightType,
                    881:                                       &object);
                    882:                if (kr != KERN_SUCCESS) {
                    883:                        is_release(space);
                    884:                        return kr;
                    885:                }
                    886:        } else
                    887:                object = (ipc_object_t) right;
                    888:        newtype = ipc_object_copyin_type(rightType);
                    889: 
                    890:        kr = mach_port_insert_right(space, name, (ipc_port_t) object, newtype);
                    891:        if ((kr != KERN_SUCCESS) && IO_VALID(object))
                    892:                ipc_object_destroy(object, newtype);
                    893:        is_release(space);
                    894: 
                    895:        return kr;
                    896: }
                    897: 
1.1.1.4   root      898: kern_return_t syscall_thread_depress_abort(mach_port_t thread)
1.1       root      899: {
                    900:        thread_t        t;
                    901:        kern_return_t   result;
                    902: 
                    903:        t = port_name_to_thread(thread);
                    904:        if (t == THREAD_NULL)
                    905:                return MACH_SEND_INTERRUPTED;
                    906: 
                    907:        result = thread_depress_abort(t);
                    908:        thread_deallocate(t);
                    909: 
                    910:        return result;
                    911: }
                    912: 
                    913: /*
                    914:  * Device traps -- these are way experimental.
                    915:  */
                    916: io_return_t
                    917: syscall_device_write_request(mach_port_t       device_name,
                    918:                             mach_port_t        reply_name,
                    919:                             dev_mode_t         mode,
                    920:                             recnum_t           recnum,
                    921:                             vm_offset_t        data,
                    922:                             vm_size_t          data_count)
                    923: {
                    924:        device_t        dev;
1.1.1.3   root      925:        /*ipc_port_t    reply_port;*/
1.1       root      926:        io_return_t     res;
                    927: 
                    928:        /*
                    929:         * First try to translate the device name.
                    930:         *
                    931:         * If this fails, return KERN_INVALID_CAPABILITY.
                    932:         * Caller knows that this most likely means that
                    933:         * device is not local to node and IPC should be used.
                    934:         *
                    935:         * If kernel doesn't do device traps, kern_invalid()
                    936:         * will be called instead of this function which will
                    937:         * return KERN_INVALID_ARGUMENT.
                    938:         */
                    939:        dev = port_name_to_device(device_name);
                    940:        if (dev == DEVICE_NULL)
                    941:                return KERN_INVALID_CAPABILITY;
                    942: 
                    943:        /*
                    944:         * Translate reply port.
                    945:         */
1.1.1.3   root      946:        /*if (reply_name == MACH_PORT_NULL)
1.1       root      947:                reply_port = IP_NULL;
1.1.1.3   root      948:        */
                    949:        if (reply_name != MACH_PORT_NULL) {
1.1       root      950:                /* Homey don't play that. */
                    951:                device_deallocate(dev);
                    952:                return KERN_INVALID_RIGHT;
                    953:        }
                    954: 
                    955:        /* note: doesn't take reply_port arg yet. */
                    956:        res = ds_device_write_trap(dev, /*reply_port,*/
                    957:                                   mode, recnum,
                    958:                                   data, data_count);
                    959: 
                    960:        /*
                    961:         * Give up reference from port_name_to_device.
                    962:         */
                    963:        device_deallocate(dev);
                    964:        return res;
                    965: }
                    966: 
                    967: io_return_t
                    968: syscall_device_writev_request(mach_port_t      device_name,
                    969:                              mach_port_t       reply_name,
                    970:                              dev_mode_t        mode,
                    971:                              recnum_t          recnum,
                    972:                              io_buf_vec_t      *iovec,
                    973:                              vm_size_t         iocount)
                    974: {
                    975:        device_t        dev;
1.1.1.4   root      976:        /*ipc_port_t    reply_port;*/
1.1       root      977:        io_return_t     res;
                    978: 
                    979:        /*
                    980:         * First try to translate the device name.
                    981:         *
                    982:         * If this fails, return KERN_INVALID_CAPABILITY.
                    983:         * Caller knows that this most likely means that
                    984:         * device is not local to node and IPC should be used.
                    985:         *
                    986:         * If kernel doesn't do device traps, kern_invalid()
                    987:         * will be called instead of this function which will
                    988:         * return KERN_INVALID_ARGUMENT.
                    989:         */
                    990:        dev = port_name_to_device(device_name);
                    991:        if (dev == DEVICE_NULL)
                    992:                return KERN_INVALID_CAPABILITY;
                    993: 
                    994:        /*
                    995:         * Translate reply port.
                    996:         */
1.1.1.4   root      997:        /*if (reply_name == MACH_PORT_NULL)
1.1       root      998:                reply_port = IP_NULL;
1.1.1.4   root      999:        */
                   1000:        if (reply_name != MACH_PORT_NULL) {
1.1       root     1001:                /* Homey don't play that. */
                   1002:                device_deallocate(dev);
                   1003:                return KERN_INVALID_RIGHT;
                   1004:        }
                   1005: 
                   1006:        /* note: doesn't take reply_port arg yet. */
                   1007:        res = ds_device_writev_trap(dev, /*reply_port,*/
                   1008:                                    mode, recnum,
                   1009:                                    iovec, iocount);
                   1010: 
                   1011:        /*
                   1012:         * Give up reference from port_name_to_device.
                   1013:         */
                   1014:        device_deallocate(dev);
                   1015:        return res;
                   1016: }

unix.superglobalmegacorp.com

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