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