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

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

unix.superglobalmegacorp.com

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