Annotation of OSKit-Mach/ipc/ipc_kmsg.c, revision 1.1

1.1     ! root        1: /*
        !             2:  * Mach Operating System
        !             3:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
        !             4:  * Copyright (c) 1993,1994 The University of Utah and
        !             5:  * the Computer Systems Laboratory (CSL).
        !             6:  * All rights reserved.
        !             7:  *
        !             8:  * Permission to use, copy, modify and distribute this software and its
        !             9:  * documentation is hereby granted, provided that both the copyright
        !            10:  * notice and this permission notice appear in all copies of the
        !            11:  * software, derivative works or modified versions, and any portions
        !            12:  * thereof, and that both notices appear in supporting documentation.
        !            13:  *
        !            14:  * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
        !            15:  * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
        !            16:  * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
        !            17:  * THIS SOFTWARE.
        !            18:  *
        !            19:  * Carnegie Mellon requests users of this software to return to
        !            20:  *
        !            21:  *  Software Distribution Coordinator  or  [email protected]
        !            22:  *  School of Computer Science
        !            23:  *  Carnegie Mellon University
        !            24:  *  Pittsburgh PA 15213-3890
        !            25:  *
        !            26:  * any improvements or extensions that they make and grant Carnegie Mellon
        !            27:  * the rights to redistribute these changes.
        !            28:  */
        !            29: /*
        !            30:  *     File:   ipc/ipc_kmsg.c
        !            31:  *     Author: Rich Draves
        !            32:  *     Date:   1989
        !            33:  *
        !            34:  *     Operations on kernel messages.
        !            35:  */
        !            36: 
        !            37: #include <cpus.h>
        !            38: #include <mach_ipc_compat.h>
        !            39: #include <norma_ipc.h>
        !            40: #include <norma_vm.h>
        !            41: 
        !            42: #include <mach/boolean.h>
        !            43: #include <mach/kern_return.h>
        !            44: #include <mach/message.h>
        !            45: #include <mach/port.h>
        !            46: #include <kern/assert.h>
        !            47: #include <kern/kalloc.h>
        !            48: #include <vm/vm_map.h>
        !            49: #include <vm/vm_object.h>
        !            50: #include <vm/vm_kern.h>
        !            51: #include <ipc/port.h>
        !            52: #include <ipc/ipc_entry.h>
        !            53: #include <ipc/ipc_kmsg.h>
        !            54: #include <ipc/ipc_thread.h>
        !            55: #include <ipc/ipc_marequest.h>
        !            56: #include <ipc/ipc_notify.h>
        !            57: #include <ipc/ipc_object.h>
        !            58: #include <ipc/ipc_space.h>
        !            59: #include <ipc/ipc_port.h>
        !            60: #include <ipc/ipc_right.h>
        !            61: 
        !            62: #include <ipc/ipc_machdep.h>
        !            63: 
        !            64: extern int copyinmap();
        !            65: extern int copyoutmap();
        !            66: void ipc_msg_print(); /* forward */
        !            67: 
        !            68: #define is_misaligned(x)       ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
        !            69: #define ptr_align(x)   \
        !            70:        ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
        !            71: 
        !            72: ipc_kmsg_t ipc_kmsg_cache[NCPUS];
        !            73: 
        !            74: /*
        !            75:  *     Routine:        ipc_kmsg_enqueue
        !            76:  *     Purpose:
        !            77:  *             Enqueue a kmsg.
        !            78:  */
        !            79: 
        !            80: void
        !            81: ipc_kmsg_enqueue(
        !            82:        ipc_kmsg_queue_t        queue,
        !            83:        ipc_kmsg_t              kmsg)
        !            84: {
        !            85:        ipc_kmsg_enqueue_macro(queue, kmsg);
        !            86: }
        !            87: 
        !            88: /*
        !            89:  *     Routine:        ipc_kmsg_dequeue
        !            90:  *     Purpose:
        !            91:  *             Dequeue and return a kmsg.
        !            92:  */
        !            93: 
        !            94: ipc_kmsg_t
        !            95: ipc_kmsg_dequeue(
        !            96:        ipc_kmsg_queue_t        queue)
        !            97: {
        !            98:        ipc_kmsg_t first;
        !            99: 
        !           100:        first = ipc_kmsg_queue_first(queue);
        !           101: 
        !           102:        if (first != IKM_NULL)
        !           103:                ipc_kmsg_rmqueue_first_macro(queue, first);
        !           104: 
        !           105:        return first;
        !           106: }
        !           107: 
        !           108: /*
        !           109:  *     Routine:        ipc_kmsg_rmqueue
        !           110:  *     Purpose:
        !           111:  *             Pull a kmsg out of a queue.
        !           112:  */
        !           113: 
        !           114: void
        !           115: ipc_kmsg_rmqueue(
        !           116:        ipc_kmsg_queue_t        queue,
        !           117:        ipc_kmsg_t              kmsg)
        !           118: {
        !           119:        ipc_kmsg_t next, prev;
        !           120: 
        !           121:        assert(queue->ikmq_base != IKM_NULL);
        !           122: 
        !           123:        next = kmsg->ikm_next;
        !           124:        prev = kmsg->ikm_prev;
        !           125: 
        !           126:        if (next == kmsg) {
        !           127:                assert(prev == kmsg);
        !           128:                assert(queue->ikmq_base == kmsg);
        !           129: 
        !           130:                queue->ikmq_base = IKM_NULL;
        !           131:        } else {
        !           132:                if (queue->ikmq_base == kmsg)
        !           133:                        queue->ikmq_base = next;
        !           134: 
        !           135:                next->ikm_prev = prev;
        !           136:                prev->ikm_next = next;
        !           137:        }
        !           138:        /* XXX Temporary debug logic */
        !           139:        kmsg->ikm_next = IKM_BOGUS;
        !           140:        kmsg->ikm_prev = IKM_BOGUS;
        !           141: }
        !           142: 
        !           143: /*
        !           144:  *     Routine:        ipc_kmsg_queue_next
        !           145:  *     Purpose:
        !           146:  *             Return the kmsg following the given kmsg.
        !           147:  *             (Or IKM_NULL if it is the last one in the queue.)
        !           148:  */
        !           149: 
        !           150: ipc_kmsg_t
        !           151: ipc_kmsg_queue_next(
        !           152:        ipc_kmsg_queue_t        queue,
        !           153:        ipc_kmsg_t              kmsg)
        !           154: {
        !           155:        ipc_kmsg_t next;
        !           156: 
        !           157:        assert(queue->ikmq_base != IKM_NULL);
        !           158: 
        !           159:        next = kmsg->ikm_next;
        !           160:        if (queue->ikmq_base == next)
        !           161:                next = IKM_NULL;
        !           162: 
        !           163:        return next;
        !           164: }
        !           165: 
        !           166: /*
        !           167:  *     Routine:        ipc_kmsg_destroy
        !           168:  *     Purpose:
        !           169:  *             Destroys a kernel message.  Releases all rights,
        !           170:  *             references, and memory held by the message.
        !           171:  *             Frees the message.
        !           172:  *     Conditions:
        !           173:  *             No locks held.
        !           174:  */
        !           175: 
        !           176: void
        !           177: ipc_kmsg_destroy(
        !           178:        ipc_kmsg_t      kmsg)
        !           179: {
        !           180:        ipc_kmsg_queue_t queue;
        !           181:        boolean_t empty;
        !           182: 
        !           183:        /*
        !           184:         *      ipc_kmsg_clean can cause more messages to be destroyed.
        !           185:         *      Curtail recursion by queueing messages.  If a message
        !           186:         *      is already queued, then this is a recursive call.
        !           187:         */
        !           188: 
        !           189:        queue = &current_thread()->ith_messages;
        !           190:        empty = ipc_kmsg_queue_empty(queue);
        !           191:        ipc_kmsg_enqueue(queue, kmsg);
        !           192: 
        !           193:        if (empty) {
        !           194:                /* must leave kmsg in queue while cleaning it */
        !           195: 
        !           196:                while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
        !           197:                        ipc_kmsg_clean(kmsg);
        !           198:                        ipc_kmsg_rmqueue(queue, kmsg);
        !           199:                        ikm_free(kmsg);
        !           200:                }
        !           201:        }
        !           202: }
        !           203: 
        !           204: /*
        !           205:  *     Routine:        ipc_kmsg_clean_body
        !           206:  *     Purpose:
        !           207:  *             Cleans the body of a kernel message.
        !           208:  *             Releases all rights, references, and memory.
        !           209:  *
        !           210:  *             The last type/data pair might stretch past eaddr.
        !           211:  *             (See the usage in ipc_kmsg_copyout.)
        !           212:  *     Conditions:
        !           213:  *             No locks held.
        !           214:  */
        !           215: 
        !           216: void
        !           217: ipc_kmsg_clean_body(saddr, eaddr)
        !           218:        vm_offset_t saddr;
        !           219:        vm_offset_t eaddr;
        !           220: {
        !           221:        while (saddr < eaddr) {
        !           222:                mach_msg_type_long_t *type;
        !           223:                mach_msg_type_name_t name;
        !           224:                mach_msg_type_size_t size;
        !           225:                mach_msg_type_number_t number;
        !           226:                boolean_t is_inline, is_port;
        !           227:                vm_size_t length;
        !           228: 
        !           229:                type = (mach_msg_type_long_t *) saddr;
        !           230:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !           231:                if (((mach_msg_type_t*)type)->msgt_longform) {
        !           232:                        /* This must be aligned */
        !           233:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           234:                            (is_misaligned(type))) {
        !           235:                                saddr = ptr_align(saddr);
        !           236:                                continue;
        !           237:                        }
        !           238:                        name = type->msgtl_name;
        !           239:                        size = type->msgtl_size;
        !           240:                        number = type->msgtl_number;
        !           241:                        saddr += sizeof(mach_msg_type_long_t);
        !           242:                } else {
        !           243:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !           244:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !           245:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !           246:                        saddr += sizeof(mach_msg_type_t);
        !           247:                }
        !           248: 
        !           249:                /* padding (ptrs and ports) ? */
        !           250:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           251:                    ((size >> 3) == sizeof(natural_t)))
        !           252:                        saddr = ptr_align(saddr);
        !           253: 
        !           254:                /* calculate length of data in bytes, rounding up */
        !           255: 
        !           256:                length = ((number * size) + 7) >> 3;
        !           257: 
        !           258:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !           259: 
        !           260:                if (is_port) {
        !           261:                        ipc_object_t *objects;
        !           262:                        mach_msg_type_number_t i;
        !           263: 
        !           264:                        if (is_inline) {
        !           265:                                objects = (ipc_object_t *) saddr;
        !           266:                                /* sanity check */
        !           267:                                while (eaddr < (vm_offset_t)&objects[number]) number--;
        !           268:                        } else {
        !           269:                                objects = (ipc_object_t *)
        !           270:                                                * (vm_offset_t *) saddr;
        !           271:                        }
        !           272: 
        !           273:                        /* destroy port rights carried in the message */
        !           274: 
        !           275:                        for (i = 0; i < number; i++) {
        !           276:                                ipc_object_t object = objects[i];
        !           277: 
        !           278:                                if (!IO_VALID(object))
        !           279:                                        continue;
        !           280: 
        !           281:                                ipc_object_destroy(object, name);
        !           282:                        }
        !           283:                }
        !           284: 
        !           285:                if (is_inline) {
        !           286:                        /* inline data sizes round up to int boundaries */
        !           287: 
        !           288:                        saddr += (length + 3) &~ 3;
        !           289:                } else {
        !           290:                        vm_offset_t data = * (vm_offset_t *) saddr;
        !           291: 
        !           292:                        /* destroy memory carried in the message */
        !           293: 
        !           294:                        if (length == 0)
        !           295:                                assert(data == 0);
        !           296:                        else if (is_port)
        !           297:                                kfree(data, length);
        !           298:                        else
        !           299:                                vm_map_copy_discard((vm_map_copy_t) data);
        !           300: 
        !           301:                        saddr += sizeof(vm_offset_t);
        !           302:                }
        !           303:        }
        !           304: }
        !           305: 
        !           306: /*
        !           307:  *     Routine:        ipc_kmsg_clean
        !           308:  *     Purpose:
        !           309:  *             Cleans a kernel message.  Releases all rights,
        !           310:  *             references, and memory held by the message.
        !           311:  *     Conditions:
        !           312:  *             No locks held.
        !           313:  */
        !           314: 
        !           315: void
        !           316: ipc_kmsg_clean(kmsg)
        !           317:        ipc_kmsg_t kmsg;
        !           318: {
        !           319:        ipc_marequest_t marequest;
        !           320:        ipc_object_t object;
        !           321:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !           322: 
        !           323:        marequest = kmsg->ikm_marequest;
        !           324:        if (marequest != IMAR_NULL)
        !           325:                ipc_marequest_destroy(marequest);
        !           326: 
        !           327:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !           328:        if (IO_VALID(object))
        !           329:                ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
        !           330: 
        !           331:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !           332:        if (IO_VALID(object))
        !           333:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
        !           334: 
        !           335:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !           336:                vm_offset_t saddr, eaddr;
        !           337: 
        !           338:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !           339:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !           340:                                kmsg->ikm_header.msgh_size;
        !           341: 
        !           342:                ipc_kmsg_clean_body(saddr, eaddr);
        !           343:        }
        !           344: }
        !           345: 
        !           346: /*
        !           347:  *     Routine:        ipc_kmsg_clean_partial
        !           348:  *     Purpose:
        !           349:  *             Cleans a partially-acquired kernel message.
        !           350:  *             eaddr is the address of the type specification
        !           351:  *             in the body of the message that contained the error.
        !           352:  *             If dolast, the memory and port rights in this last
        !           353:  *             type spec are also cleaned.  In that case, number
        !           354:  *             specifies the number of port rights to clean.
        !           355:  *     Conditions:
        !           356:  *             Nothing locked.
        !           357:  */
        !           358: 
        !           359: void
        !           360: ipc_kmsg_clean_partial(kmsg, eaddr, dolast, number)
        !           361:        ipc_kmsg_t kmsg;
        !           362:        vm_offset_t eaddr;
        !           363:        boolean_t dolast;
        !           364:        mach_msg_type_number_t number;
        !           365: {
        !           366:        ipc_object_t object;
        !           367:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !           368:        vm_offset_t saddr;
        !           369: 
        !           370:        assert(kmsg->ikm_marequest == IMAR_NULL);
        !           371: 
        !           372:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !           373:        assert(IO_VALID(object));
        !           374:        ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
        !           375: 
        !           376:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !           377:        if (IO_VALID(object))
        !           378:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
        !           379: 
        !           380:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !           381:        ipc_kmsg_clean_body(saddr, eaddr);
        !           382: 
        !           383:        if (dolast) {
        !           384:                mach_msg_type_long_t *type;
        !           385:                mach_msg_type_name_t name;
        !           386:                mach_msg_type_size_t size;
        !           387:                mach_msg_type_number_t rnumber;
        !           388:                boolean_t is_inline, is_port;
        !           389:                vm_size_t length;
        !           390: 
        !           391: xxx:           type = (mach_msg_type_long_t *) eaddr;
        !           392:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !           393:                if (((mach_msg_type_t*)type)->msgt_longform) {
        !           394:                        /* This must be aligned */
        !           395:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           396:                            (is_misaligned(type))) {
        !           397:                                eaddr = ptr_align(eaddr);
        !           398:                                goto xxx;
        !           399:                        }
        !           400:                        name = type->msgtl_name;
        !           401:                        size = type->msgtl_size;
        !           402:                        rnumber = type->msgtl_number;
        !           403:                        eaddr += sizeof(mach_msg_type_long_t);
        !           404:                } else {
        !           405:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !           406:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !           407:                        rnumber = ((mach_msg_type_t*)type)->msgt_number;
        !           408:                        eaddr += sizeof(mach_msg_type_t);
        !           409:                }
        !           410: 
        !           411:                /* padding (ptrs and ports) ? */
        !           412:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !           413:                    ((size >> 3) == sizeof(natural_t)))
        !           414:                        eaddr = ptr_align(eaddr);
        !           415: 
        !           416:                /* calculate length of data in bytes, rounding up */
        !           417: 
        !           418:                length = ((rnumber * size) + 7) >> 3;
        !           419: 
        !           420:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !           421: 
        !           422:                if (is_port) {
        !           423:                        ipc_object_t *objects;
        !           424:                        mach_msg_type_number_t i;
        !           425: 
        !           426:                        objects = (ipc_object_t *)
        !           427:                                (is_inline ? eaddr : * (vm_offset_t *) eaddr);
        !           428: 
        !           429:                        /* destroy port rights carried in the message */
        !           430: 
        !           431:                        for (i = 0; i < number; i++) {
        !           432:                                ipc_object_t obj = objects[i];
        !           433: 
        !           434:                                if (!IO_VALID(obj))
        !           435:                                        continue;
        !           436: 
        !           437:                                ipc_object_destroy(obj, name);
        !           438:                        }
        !           439:                }
        !           440: 
        !           441:                if (!is_inline) {
        !           442:                        vm_offset_t data = * (vm_offset_t *) eaddr;
        !           443: 
        !           444:                        /* destroy memory carried in the message */
        !           445: 
        !           446:                        if (length == 0)
        !           447:                                assert(data == 0);
        !           448:                        else if (is_port)
        !           449:                                kfree(data, length);
        !           450:                        else
        !           451:                                vm_map_copy_discard((vm_map_copy_t) data);
        !           452:                }
        !           453:        }
        !           454: }
        !           455: 
        !           456: /*
        !           457:  *     Routine:        ipc_kmsg_free
        !           458:  *     Purpose:
        !           459:  *             Free a kernel message buffer.
        !           460:  *     Conditions:
        !           461:  *             Nothing locked.
        !           462:  */
        !           463: 
        !           464: void
        !           465: ipc_kmsg_free(kmsg)
        !           466:        ipc_kmsg_t kmsg;
        !           467: {
        !           468:        vm_size_t size = kmsg->ikm_size;
        !           469: 
        !           470:        switch (size) {
        !           471: #if    NORMA_IPC
        !           472:            case IKM_SIZE_NORMA:
        !           473:                /* return it to the norma ipc code */
        !           474:                norma_kmsg_put(kmsg);
        !           475:                break;
        !           476: #endif /* NORMA_IPC */
        !           477: 
        !           478:            case IKM_SIZE_NETWORK:
        !           479:                /* return it to the network code */
        !           480:                net_kmsg_put(kmsg);
        !           481:                break;
        !           482: 
        !           483:            default:
        !           484:                kfree((vm_offset_t) kmsg, size);
        !           485:                break;
        !           486:        }
        !           487: }
        !           488: 
        !           489: /*
        !           490:  *     Routine:        ipc_kmsg_get
        !           491:  *     Purpose:
        !           492:  *             Allocates a kernel message buffer.
        !           493:  *             Copies a user message to the message buffer.
        !           494:  *     Conditions:
        !           495:  *             Nothing locked.
        !           496:  *     Returns:
        !           497:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
        !           498:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
        !           499:  *             MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
        !           500:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
        !           501:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
        !           502:  */
        !           503: 
        !           504: mach_msg_return_t
        !           505: ipc_kmsg_get(msg, size, kmsgp)
        !           506:        mach_msg_header_t *msg;
        !           507:        mach_msg_size_t size;
        !           508:        ipc_kmsg_t *kmsgp;
        !           509: {
        !           510:        ipc_kmsg_t kmsg;
        !           511: 
        !           512:        if ((size < sizeof(mach_msg_header_t)) || (size & 3))
        !           513:                return MACH_SEND_MSG_TOO_SMALL;
        !           514: 
        !           515:        if (size <= IKM_SAVED_MSG_SIZE) {
        !           516:                kmsg = ikm_cache();
        !           517:                if (kmsg != IKM_NULL) {
        !           518:                        ikm_cache() = IKM_NULL;
        !           519:                        ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
        !           520:                } else {
        !           521:                        kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
        !           522:                        if (kmsg == IKM_NULL)
        !           523:                                return MACH_SEND_NO_BUFFER;
        !           524:                        ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
        !           525:                }
        !           526:        } else {
        !           527:                kmsg = ikm_alloc(size);
        !           528:                if (kmsg == IKM_NULL)
        !           529:                        return MACH_SEND_NO_BUFFER;
        !           530:                ikm_init(kmsg, size);
        !           531:        }
        !           532: 
        !           533:        if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) {
        !           534:                ikm_free(kmsg);
        !           535:                return MACH_SEND_INVALID_DATA;
        !           536:        }
        !           537: 
        !           538:        kmsg->ikm_header.msgh_size = size;
        !           539:        *kmsgp = kmsg;
        !           540:        return MACH_MSG_SUCCESS;
        !           541: }
        !           542: 
        !           543: /*
        !           544:  *     Routine:        ipc_kmsg_get_from_kernel
        !           545:  *     Purpose:
        !           546:  *             Allocates a kernel message buffer.
        !           547:  *             Copies a kernel message to the message buffer.
        !           548:  *             Only resource errors are allowed.
        !           549:  *     Conditions:
        !           550:  *             Nothing locked.
        !           551:  *     Returns:
        !           552:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
        !           553:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
        !           554:  */
        !           555: 
        !           556: extern mach_msg_return_t
        !           557: ipc_kmsg_get_from_kernel(msg, size, kmsgp)
        !           558:        mach_msg_header_t *msg;
        !           559:        mach_msg_size_t size;
        !           560:        ipc_kmsg_t *kmsgp;
        !           561: {
        !           562:        ipc_kmsg_t kmsg;
        !           563: 
        !           564:        assert(size >= sizeof(mach_msg_header_t));
        !           565:        assert((size & 3) == 0);
        !           566: 
        !           567:        kmsg = ikm_alloc(size);
        !           568:        if (kmsg == IKM_NULL)
        !           569:                return MACH_SEND_NO_BUFFER;
        !           570:        ikm_init(kmsg, size);
        !           571: 
        !           572:        bcopy((char *) msg, (char *) &kmsg->ikm_header, size);
        !           573: 
        !           574:        kmsg->ikm_header.msgh_size = size;
        !           575:        *kmsgp = kmsg;
        !           576:        return MACH_MSG_SUCCESS;
        !           577: }
        !           578: 
        !           579: /*
        !           580:  *     Routine:        ipc_kmsg_put
        !           581:  *     Purpose:
        !           582:  *             Copies a message buffer to a user message.
        !           583:  *             Copies only the specified number of bytes.
        !           584:  *             Frees the message buffer.
        !           585:  *     Conditions:
        !           586:  *             Nothing locked.  The message buffer must have clean
        !           587:  *             header (ikm_marequest) fields.
        !           588:  *     Returns:
        !           589:  *             MACH_MSG_SUCCESS        Copied data out of message buffer.
        !           590:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user message.
        !           591:  */
        !           592: 
        !           593: mach_msg_return_t
        !           594: ipc_kmsg_put(msg, kmsg, size)
        !           595:        mach_msg_header_t *msg;
        !           596:        ipc_kmsg_t kmsg;
        !           597:        mach_msg_size_t size;
        !           598: {
        !           599:        mach_msg_return_t mr;
        !           600: 
        !           601:        ikm_check_initialized(kmsg, kmsg->ikm_size);
        !           602: 
        !           603:        if (copyoutmsg((char *) &kmsg->ikm_header, (char *) msg, size))
        !           604:                mr = MACH_RCV_INVALID_DATA;
        !           605:        else
        !           606:                mr = MACH_MSG_SUCCESS;
        !           607: 
        !           608:        if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
        !           609:            (ikm_cache() == IKM_NULL))
        !           610:                ikm_cache() = kmsg;
        !           611:        else
        !           612:                ikm_free(kmsg);
        !           613: 
        !           614:        return mr;
        !           615: }
        !           616: 
        !           617: /*
        !           618:  *     Routine:        ipc_kmsg_put_to_kernel
        !           619:  *     Purpose:
        !           620:  *             Copies a message buffer to a kernel message.
        !           621:  *             Frees the message buffer.
        !           622:  *             No errors allowed.
        !           623:  *     Conditions:
        !           624:  *             Nothing locked.
        !           625:  */
        !           626: 
        !           627: void
        !           628: ipc_kmsg_put_to_kernel(
        !           629:        mach_msg_header_t       *msg,
        !           630:        ipc_kmsg_t              kmsg,
        !           631:        mach_msg_size_t         size)
        !           632: {
        !           633: #if    DIPC
        !           634:        assert(!KMSG_IN_DIPC(kmsg));
        !           635: #endif /* DIPC */
        !           636: 
        !           637:        (void) memcpy((void *) msg, (const void *) &kmsg->ikm_header, size);
        !           638: 
        !           639:        ikm_free(kmsg);
        !           640: }
        !           641: 
        !           642: /*
        !           643:  *     Routine:        ipc_kmsg_copyin_header
        !           644:  *     Purpose:
        !           645:  *             "Copy-in" port rights in the header of a message.
        !           646:  *             Operates atomically; if it doesn't succeed the
        !           647:  *             message header and the space are left untouched.
        !           648:  *             If it does succeed the remote/local port fields
        !           649:  *             contain object pointers instead of port names,
        !           650:  *             and the bits field is updated.  The destination port
        !           651:  *             will be a valid port pointer.
        !           652:  *
        !           653:  *             The notify argument implements the MACH_SEND_CANCEL option.
        !           654:  *             If it is not MACH_PORT_NULL, it should name a receive right.
        !           655:  *             If the processing of the destination port would generate
        !           656:  *             a port-deleted notification (because the right for the
        !           657:  *             destination port is destroyed and it had a request for
        !           658:  *             a dead-name notification registered), and the port-deleted
        !           659:  *             notification would be sent to the named receive right,
        !           660:  *             then it isn't sent and the send-once right for the notify
        !           661:  *             port is quietly destroyed.
        !           662:  *
        !           663:  *             [MACH_IPC_COMPAT] There is an atomicity problem if the
        !           664:  *             reply port is a compat entry and dies at an inopportune
        !           665:  *             time.  This doesn't have any serious consequences
        !           666:  *             (an observant user task might conceivably notice that
        !           667:  *             the destination and reply ports were handled inconsistently),
        !           668:  *             only happens in compat mode, and is extremely unlikely.
        !           669:  *     Conditions:
        !           670:  *             Nothing locked.
        !           671:  *     Returns:
        !           672:  *             MACH_MSG_SUCCESS        Successful copyin.
        !           673:  *             MACH_SEND_INVALID_HEADER
        !           674:  *                     Illegal value in the message header bits.
        !           675:  *             MACH_SEND_INVALID_DEST  The space is dead.
        !           676:  *             MACH_SEND_INVALID_NOTIFY
        !           677:  *                     Notify is non-null and doesn't name a receive right.
        !           678:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !           679:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !           680:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !           681:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !           682:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !           683:  */
        !           684: 
        !           685: mach_msg_return_t
        !           686: ipc_kmsg_copyin_header(msg, space, notify)
        !           687:        mach_msg_header_t *msg;
        !           688:        ipc_space_t space;
        !           689:        mach_port_t notify;
        !           690: {
        !           691:        mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
        !           692:        mach_port_t dest_name = msg->msgh_remote_port;
        !           693:        mach_port_t reply_name = msg->msgh_local_port;
        !           694:        kern_return_t kr;
        !           695: 
        !           696: #ifndef MIGRATING_THREADS
        !           697:        /* first check for common cases */
        !           698: 
        !           699:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
        !           700:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
        !           701:                ipc_entry_t entry;
        !           702:                ipc_entry_bits_t bits;
        !           703:                ipc_port_t dest_port;
        !           704: 
        !           705:                /* sending an asynchronous message */
        !           706: 
        !           707:                if (reply_name != MACH_PORT_NULL)
        !           708:                        break;
        !           709: 
        !           710:                is_read_lock(space);
        !           711:                if (!space->is_active)
        !           712:                        goto abort_async;
        !           713: 
        !           714:                /* optimized ipc_entry_lookup */
        !           715: 
        !           716:            {
        !           717:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
        !           718:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
        !           719: 
        !           720:                if (index >= space->is_table_size)
        !           721:                        goto abort_async;
        !           722: 
        !           723:                entry = &space->is_table[index];
        !           724:                bits = entry->ie_bits;
        !           725: 
        !           726:                /* check generation number and type bit */
        !           727: 
        !           728:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
        !           729:                    (gen | MACH_PORT_TYPE_SEND))
        !           730:                        goto abort_async;
        !           731:            }
        !           732: 
        !           733:                /* optimized ipc_right_copyin */
        !           734: 
        !           735:                assert(IE_BITS_UREFS(bits) > 0);
        !           736: 
        !           737:                dest_port = (ipc_port_t) entry->ie_object;
        !           738:                assert(dest_port != IP_NULL);
        !           739: 
        !           740:                ip_lock(dest_port);
        !           741:                /* can unlock space now without compromising atomicity */
        !           742:                is_read_unlock(space);
        !           743: 
        !           744:                if (!ip_active(dest_port)) {
        !           745:                        ip_unlock(dest_port);
        !           746:                        break;
        !           747:                }
        !           748: 
        !           749:                assert(dest_port->ip_srights > 0);
        !           750:                dest_port->ip_srights++;
        !           751:                ip_reference(dest_port);
        !           752:                ip_unlock(dest_port);
        !           753: 
        !           754:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !           755:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
        !           756:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !           757:                return MACH_MSG_SUCCESS;
        !           758: 
        !           759:            abort_async:
        !           760:                is_read_unlock(space);
        !           761:                break;
        !           762:            }
        !           763: 
        !           764:            case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
        !           765:                                MACH_MSG_TYPE_MAKE_SEND_ONCE): {
        !           766:                ipc_entry_num_t size;
        !           767:                ipc_entry_t table;
        !           768:                ipc_entry_t entry;
        !           769:                ipc_entry_bits_t bits;
        !           770:                ipc_port_t dest_port, reply_port;
        !           771: 
        !           772:                /* sending a request message */
        !           773: 
        !           774:                is_read_lock(space);
        !           775:                if (!space->is_active)
        !           776:                        goto abort_request;
        !           777: 
        !           778:                size = space->is_table_size;
        !           779:                table = space->is_table;
        !           780: 
        !           781:                /* optimized ipc_entry_lookup of dest_name */
        !           782: 
        !           783:            {
        !           784:                mach_port_index_t index = MACH_PORT_INDEX(dest_name);
        !           785:                mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
        !           786: 
        !           787:                if (index >= size)
        !           788:                        goto abort_request;
        !           789: 
        !           790:                entry = &table[index];
        !           791:                bits = entry->ie_bits;
        !           792: 
        !           793:                /* check generation number and type bit */
        !           794: 
        !           795:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
        !           796:                    (gen | MACH_PORT_TYPE_SEND))
        !           797:                        goto abort_request;
        !           798:            }
        !           799: 
        !           800:                assert(IE_BITS_UREFS(bits) > 0);
        !           801: 
        !           802:                dest_port = (ipc_port_t) entry->ie_object;
        !           803:                assert(dest_port != IP_NULL);
        !           804: 
        !           805:                /* optimized ipc_entry_lookup of reply_name */
        !           806: 
        !           807:            {
        !           808:                mach_port_index_t index = MACH_PORT_INDEX(reply_name);
        !           809:                mach_port_gen_t gen = MACH_PORT_GEN(reply_name);
        !           810: 
        !           811:                if (index >= size)
        !           812:                        goto abort_request;
        !           813: 
        !           814:                entry = &table[index];
        !           815:                bits = entry->ie_bits;
        !           816: 
        !           817:                /* check generation number and type bit */
        !           818: 
        !           819:                if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) !=
        !           820:                    (gen | MACH_PORT_TYPE_RECEIVE))
        !           821:                        goto abort_request;
        !           822:            }
        !           823: 
        !           824:                reply_port = (ipc_port_t) entry->ie_object;
        !           825:                assert(reply_port != IP_NULL);
        !           826: 
        !           827:                /*
        !           828:                 *      To do an atomic copyin, need simultaneous
        !           829:                 *      locks on both ports and the space.  If
        !           830:                 *      dest_port == reply_port, and simple locking is
        !           831:                 *      enabled, then we will abort.  Otherwise it's
        !           832:                 *      OK to unlock twice.
        !           833:                 */
        !           834: 
        !           835:                ip_lock(dest_port);
        !           836:                if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
        !           837:                        ip_unlock(dest_port);
        !           838:                        goto abort_request;
        !           839:                }
        !           840:                /* can unlock space now without compromising atomicity */
        !           841:                is_read_unlock(space);
        !           842: 
        !           843:                assert(dest_port->ip_srights > 0);
        !           844:                dest_port->ip_srights++;
        !           845:                ip_reference(dest_port);
        !           846:                ip_unlock(dest_port);
        !           847: 
        !           848:                assert(ip_active(reply_port));
        !           849:                assert(reply_port->ip_receiver_name == reply_name);
        !           850:                assert(reply_port->ip_receiver == space);
        !           851: 
        !           852:                reply_port->ip_sorights++;
        !           853:                ip_reference(reply_port);
        !           854:                ip_unlock(reply_port);
        !           855: 
        !           856:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !           857:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
        !           858:                                       MACH_MSG_TYPE_PORT_SEND_ONCE));
        !           859:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !           860:                msg->msgh_local_port = (mach_port_t) reply_port;
        !           861:                return MACH_MSG_SUCCESS;
        !           862: 
        !           863:            abort_request:
        !           864:                is_read_unlock(space);
        !           865:                break;
        !           866:            }
        !           867: 
        !           868:            case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
        !           869:                mach_port_index_t index;
        !           870:                mach_port_gen_t gen;
        !           871:                ipc_entry_t table;
        !           872:                ipc_entry_t entry;
        !           873:                ipc_entry_bits_t bits;
        !           874:                ipc_port_t dest_port;
        !           875: 
        !           876:                /* sending a reply message */
        !           877: 
        !           878:                if (reply_name != MACH_PORT_NULL)
        !           879:                        break;
        !           880: 
        !           881:                is_write_lock(space);
        !           882:                if (!space->is_active)
        !           883:                        goto abort_reply;
        !           884: 
        !           885:                /* optimized ipc_entry_lookup */
        !           886: 
        !           887:                table = space->is_table;
        !           888: 
        !           889:                index = MACH_PORT_INDEX(dest_name);
        !           890:                gen = MACH_PORT_GEN(dest_name);
        !           891: 
        !           892:                if (index >= space->is_table_size)
        !           893:                        goto abort_reply;
        !           894: 
        !           895:                entry = &table[index];
        !           896:                bits = entry->ie_bits;
        !           897: 
        !           898:                /* check generation number, collision bit, and type bit */
        !           899: 
        !           900:                if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION|
        !           901:                             MACH_PORT_TYPE_SEND_ONCE)) !=
        !           902:                    (gen | MACH_PORT_TYPE_SEND_ONCE))
        !           903:                        goto abort_reply;
        !           904: 
        !           905:                /* optimized ipc_right_copyin */
        !           906: 
        !           907:                assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
        !           908:                assert(IE_BITS_UREFS(bits) == 1);
        !           909:                assert((bits & IE_BITS_MAREQUEST) == 0);
        !           910: 
        !           911:                if (entry->ie_request != 0)
        !           912:                        goto abort_reply;
        !           913: 
        !           914:                dest_port = (ipc_port_t) entry->ie_object;
        !           915:                assert(dest_port != IP_NULL);
        !           916: 
        !           917:                ip_lock(dest_port);
        !           918:                if (!ip_active(dest_port)) {
        !           919:                        ip_unlock(dest_port);
        !           920:                        goto abort_reply;
        !           921:                }
        !           922: 
        !           923:                assert(dest_port->ip_sorights > 0);
        !           924:                ip_unlock(dest_port);
        !           925: 
        !           926:                /* optimized ipc_entry_dealloc */
        !           927: 
        !           928:                entry->ie_next = table->ie_next;
        !           929:                table->ie_next = index;
        !           930:                entry->ie_bits = gen;
        !           931:                entry->ie_object = IO_NULL;
        !           932:                is_write_unlock(space);
        !           933: 
        !           934:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !           935:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !           936:                                                 0));
        !           937:                msg->msgh_remote_port = (mach_port_t) dest_port;
        !           938:                return MACH_MSG_SUCCESS;
        !           939: 
        !           940:            abort_reply:
        !           941:                is_write_unlock(space);
        !           942:                break;
        !           943:            }
        !           944: 
        !           945:            default:
        !           946:                /* don't bother optimizing */
        !           947:                break;
        !           948:        }
        !           949: #endif /* MIGRATING_THREADS */
        !           950: 
        !           951:     {
        !           952:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !           953:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !           954:        ipc_object_t dest_port, reply_port;
        !           955:        ipc_port_t dest_soright, reply_soright;
        !           956:        ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
        !           957: 
        !           958:        if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
        !           959:                return MACH_SEND_INVALID_HEADER;
        !           960: 
        !           961:        if ((reply_type == 0) ?
        !           962:            (reply_name != MACH_PORT_NULL) :
        !           963:            !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
        !           964:                return MACH_SEND_INVALID_HEADER;
        !           965: 
        !           966:        is_write_lock(space);
        !           967:        if (!space->is_active)
        !           968:                goto invalid_dest;
        !           969: 
        !           970:        if (notify != MACH_PORT_NULL) {
        !           971:                ipc_entry_t entry;
        !           972: 
        !           973:                if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
        !           974:                    ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
        !           975:                        is_write_unlock(space);
        !           976:                        return MACH_SEND_INVALID_NOTIFY;
        !           977:                }
        !           978: 
        !           979:                notify_port = (ipc_port_t) entry->ie_object;
        !           980:        }
        !           981: 
        !           982:        if (dest_name == reply_name) {
        !           983:                ipc_entry_t entry;
        !           984:                mach_port_t name = dest_name;
        !           985: 
        !           986:                /*
        !           987:                 *      Destination and reply ports are the same!
        !           988:                 *      This is a little tedious to make atomic, because
        !           989:                 *      there are 25 combinations of dest_type/reply_type.
        !           990:                 *      However, most are easy.  If either is move-sonce,
        !           991:                 *      then there must be an error.  If either are
        !           992:                 *      make-send or make-sonce, then we must be looking
        !           993:                 *      at a receive right so the port can't die.
        !           994:                 *      The hard cases are the combinations of
        !           995:                 *      copy-send and make-send.
        !           996:                 */
        !           997: 
        !           998:                entry = ipc_entry_lookup(space, name);
        !           999:                if (entry == IE_NULL)
        !          1000:                        goto invalid_dest;
        !          1001: 
        !          1002:                assert(reply_type != 0); /* because name not null */
        !          1003: 
        !          1004:                if (!ipc_right_copyin_check(space, name, entry, reply_type))
        !          1005:                        goto invalid_reply;
        !          1006: 
        !          1007:                if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
        !          1008:                    (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
        !          1009:                        /*
        !          1010:                         *      Why must there be an error?  To get a valid
        !          1011:                         *      destination, this entry must name a live
        !          1012:                         *      port (not a dead name or dead port).  However
        !          1013:                         *      a successful move-sonce will destroy a
        !          1014:                         *      live entry.  Therefore the other copyin,
        !          1015:                         *      whatever it is, would fail.  We've already
        !          1016:                         *      checked for reply port errors above,
        !          1017:                         *      so report a destination error.
        !          1018:                         */
        !          1019: 
        !          1020:                        goto invalid_dest;
        !          1021:                } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
        !          1022:                           (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
        !          1023:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
        !          1024:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
        !          1025:                        kr = ipc_right_copyin(space, name, entry,
        !          1026:                                              dest_type, FALSE,
        !          1027:                                              &dest_port, &dest_soright);
        !          1028:                        if (kr != KERN_SUCCESS)
        !          1029:                                goto invalid_dest;
        !          1030: 
        !          1031:                        /*
        !          1032:                         *      Either dest or reply needs a receive right.
        !          1033:                         *      We know the receive right is there, because
        !          1034:                         *      of the copyin_check and copyin calls.  Hence
        !          1035:                         *      the port is not in danger of dying.  If dest
        !          1036:                         *      used the receive right, then the right needed
        !          1037:                         *      by reply (and verified by copyin_check) will
        !          1038:                         *      still be there.
        !          1039:                         */
        !          1040: 
        !          1041:                        assert(IO_VALID(dest_port));
        !          1042:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
        !          1043:                        assert(dest_soright == IP_NULL);
        !          1044: 
        !          1045:                        kr = ipc_right_copyin(space, name, entry,
        !          1046:                                              reply_type, TRUE,
        !          1047:                                              &reply_port, &reply_soright);
        !          1048: 
        !          1049:                        assert(kr == KERN_SUCCESS);
        !          1050:                        assert(reply_port == dest_port);
        !          1051:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
        !          1052:                        assert(reply_soright == IP_NULL);
        !          1053:                } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
        !          1054:                           (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
        !          1055:                        /*
        !          1056:                         *      To make this atomic, just do one copy-send,
        !          1057:                         *      and dup the send right we get out.
        !          1058:                         */
        !          1059: 
        !          1060:                        kr = ipc_right_copyin(space, name, entry,
        !          1061:                                              dest_type, FALSE,
        !          1062:                                              &dest_port, &dest_soright);
        !          1063:                        if (kr != KERN_SUCCESS)
        !          1064:                                goto invalid_dest;
        !          1065: 
        !          1066:                        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
        !          1067:                        assert(dest_soright == IP_NULL);
        !          1068: 
        !          1069:                        /*
        !          1070:                         *      It's OK if the port we got is dead now,
        !          1071:                         *      so reply_port is IP_DEAD, because the msg
        !          1072:                         *      won't go anywhere anyway.
        !          1073:                         */
        !          1074: 
        !          1075:                        reply_port = (ipc_object_t)
        !          1076:                                ipc_port_copy_send((ipc_port_t) dest_port);
        !          1077:                        reply_soright = IP_NULL;
        !          1078:                } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
        !          1079:                           (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
        !          1080:                        /*
        !          1081:                         *      This is an easy case.  Just use our
        !          1082:                         *      handy-dandy special-purpose copyin call
        !          1083:                         *      to get two send rights for the price of one.
        !          1084:                         */
        !          1085: 
        !          1086:                        kr = ipc_right_copyin_two(space, name, entry,
        !          1087:                                                  &dest_port, &dest_soright);
        !          1088:                        if (kr != KERN_SUCCESS)
        !          1089:                                goto invalid_dest;
        !          1090: 
        !          1091:                        /* the entry might need to be deallocated */
        !          1092: 
        !          1093:                        if (IE_BITS_TYPE(entry->ie_bits)
        !          1094:                                                == MACH_PORT_TYPE_NONE)
        !          1095:                                ipc_entry_dealloc(space, name, entry);
        !          1096: 
        !          1097:                        reply_port = dest_port;
        !          1098:                        reply_soright = IP_NULL;
        !          1099:                } else {
        !          1100:                        ipc_port_t soright;
        !          1101: 
        !          1102:                        assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
        !          1103:                                (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
        !          1104:                               ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
        !          1105:                                (reply_type == MACH_MSG_TYPE_COPY_SEND)));
        !          1106: 
        !          1107:                        /*
        !          1108:                         *      To make this atomic, just do a move-send,
        !          1109:                         *      and dup the send right we get out.
        !          1110:                         */
        !          1111: 
        !          1112:                        kr = ipc_right_copyin(space, name, entry,
        !          1113:                                              MACH_MSG_TYPE_MOVE_SEND, FALSE,
        !          1114:                                              &dest_port, &soright);
        !          1115:                        if (kr != KERN_SUCCESS)
        !          1116:                                goto invalid_dest;
        !          1117: 
        !          1118:                        /* the entry might need to be deallocated */
        !          1119: 
        !          1120:                        if (IE_BITS_TYPE(entry->ie_bits)
        !          1121:                                                == MACH_PORT_TYPE_NONE)
        !          1122:                                ipc_entry_dealloc(space, name, entry);
        !          1123: 
        !          1124:                        /*
        !          1125:                         *      It's OK if the port we got is dead now,
        !          1126:                         *      so reply_port is IP_DEAD, because the msg
        !          1127:                         *      won't go anywhere anyway.
        !          1128:                         */
        !          1129: 
        !          1130:                        reply_port = (ipc_object_t)
        !          1131:                                ipc_port_copy_send((ipc_port_t) dest_port);
        !          1132: 
        !          1133:                        if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
        !          1134:                                dest_soright = soright;
        !          1135:                                reply_soright = IP_NULL;
        !          1136:                        } else {
        !          1137:                                dest_soright = IP_NULL;
        !          1138:                                reply_soright = soright;
        !          1139:                        }
        !          1140:                }
        !          1141:        } else if (!MACH_PORT_VALID(reply_name)) {
        !          1142:                ipc_entry_t entry;
        !          1143: 
        !          1144:                /*
        !          1145:                 *      No reply port!  This is an easy case
        !          1146:                 *      to make atomic.  Just copyin the destination.
        !          1147:                 */
        !          1148: 
        !          1149:                entry = ipc_entry_lookup(space, dest_name);
        !          1150:                if (entry == IE_NULL)
        !          1151:                        goto invalid_dest;
        !          1152: 
        !          1153:                kr = ipc_right_copyin(space, dest_name, entry,
        !          1154:                                      dest_type, FALSE,
        !          1155:                                      &dest_port, &dest_soright);
        !          1156:                if (kr != KERN_SUCCESS)
        !          1157:                        goto invalid_dest;
        !          1158: 
        !          1159:                /* the entry might need to be deallocated */
        !          1160: 
        !          1161:                if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1162:                        ipc_entry_dealloc(space, dest_name, entry);
        !          1163: 
        !          1164:                reply_port = (ipc_object_t) reply_name;
        !          1165:                reply_soright = IP_NULL;
        !          1166:        } else {
        !          1167:                ipc_entry_t dest_entry, reply_entry;
        !          1168:                ipc_port_t saved_reply;
        !          1169: 
        !          1170:                /*
        !          1171:                 *      This is the tough case to make atomic.
        !          1172:                 *      The difficult problem is serializing with port death.
        !          1173:                 *      At the time we copyin dest_port, it must be alive.
        !          1174:                 *      If reply_port is alive when we copyin it, then
        !          1175:                 *      we are OK, because we serialize before the death
        !          1176:                 *      of both ports.  Assume reply_port is dead at copyin.
        !          1177:                 *      Then if dest_port dies/died after reply_port died,
        !          1178:                 *      we are OK, because we serialize between the death
        !          1179:                 *      of the two ports.  So the bad case is when dest_port
        !          1180:                 *      dies after its copyin, reply_port dies before its
        !          1181:                 *      copyin, and dest_port dies before reply_port.  Then
        !          1182:                 *      the copyins operated as if dest_port was alive
        !          1183:                 *      and reply_port was dead, which shouldn't have happened
        !          1184:                 *      because they died in the other order.
        !          1185:                 *
        !          1186:                 *      We handle the bad case by undoing the copyins
        !          1187:                 *      (which is only possible because the ports are dead)
        !          1188:                 *      and failing with MACH_SEND_INVALID_DEST, serializing
        !          1189:                 *      after the death of the ports.
        !          1190:                 *
        !          1191:                 *      Note that it is easy for a user task to tell if
        !          1192:                 *      a copyin happened before or after a port died.
        !          1193:                 *      For example, suppose both dest and reply are
        !          1194:                 *      send-once rights (types are both move-sonce) and
        !          1195:                 *      both rights have dead-name requests registered.
        !          1196:                 *      If a port dies before copyin, a dead-name notification
        !          1197:                 *      is generated and the dead name's urefs are incremented,
        !          1198:                 *      and if the copyin happens first, a port-deleted
        !          1199:                 *      notification is generated.
        !          1200:                 *
        !          1201:                 *      Note that although the entries are different,
        !          1202:                 *      dest_port and reply_port might still be the same.
        !          1203:                 */
        !          1204: 
        !          1205:                dest_entry = ipc_entry_lookup(space, dest_name);
        !          1206:                if (dest_entry == IE_NULL)
        !          1207:                        goto invalid_dest;
        !          1208: 
        !          1209:                reply_entry = ipc_entry_lookup(space, reply_name);
        !          1210:                if (reply_entry == IE_NULL)
        !          1211:                        goto invalid_reply;
        !          1212: 
        !          1213:                assert(dest_entry != reply_entry); /* names are not equal */
        !          1214:                assert(reply_type != 0); /* because reply_name not null */
        !          1215: 
        !          1216:                if (!ipc_right_copyin_check(space, reply_name, reply_entry,
        !          1217:                                            reply_type))
        !          1218:                        goto invalid_reply;
        !          1219: 
        !          1220:                kr = ipc_right_copyin(space, dest_name, dest_entry,
        !          1221:                                      dest_type, FALSE,
        !          1222:                                      &dest_port, &dest_soright);
        !          1223:                if (kr != KERN_SUCCESS)
        !          1224:                        goto invalid_dest;
        !          1225: 
        !          1226:                assert(IO_VALID(dest_port));
        !          1227: 
        !          1228:                saved_reply = (ipc_port_t) reply_entry->ie_object;
        !          1229:                /* might be IP_NULL, if this is a dead name */
        !          1230:                if (saved_reply != IP_NULL)
        !          1231:                        ipc_port_reference(saved_reply);
        !          1232: 
        !          1233:                kr = ipc_right_copyin(space, reply_name, reply_entry,
        !          1234:                                      reply_type, TRUE,
        !          1235:                                      &reply_port, &reply_soright);
        !          1236: #if    MACH_IPC_COMPAT
        !          1237:                if (kr != KERN_SUCCESS) {
        !          1238:                        assert(kr == KERN_INVALID_NAME);
        !          1239: 
        !          1240:                        /*
        !          1241:                         *      Oops.  This must have been a compat entry
        !          1242:                         *      and the port died after the check above.
        !          1243:                         *      We should back out the copyin of dest_port,
        !          1244:                         *      and report MACH_SEND_INVALID_REPLY, but
        !          1245:                         *      if dest_port is alive we can't always do that.
        !          1246:                         *      Punt and pretend we got IO_DEAD, skipping
        !          1247:                         *      further hairy atomicity problems.
        !          1248:                         */
        !          1249: 
        !          1250:                        reply_port = IO_DEAD;
        !          1251:                        reply_soright = IP_NULL;
        !          1252:                        goto skip_reply_checks;
        !          1253:                }
        !          1254: #else  /* MACH_IPC_COMPAT */
        !          1255:                assert(kr == KERN_SUCCESS);
        !          1256: #endif /* MACH_IPC_COMPAT */
        !          1257: 
        !          1258:                if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
        !          1259:                        ipc_port_t dest = (ipc_port_t) dest_port;
        !          1260:                        ipc_port_timestamp_t timestamp;
        !          1261:                        boolean_t must_undo;
        !          1262: 
        !          1263:                        /*
        !          1264:                         *      The reply port died before copyin.
        !          1265:                         *      Check if dest port died before reply.
        !          1266:                         */
        !          1267: 
        !          1268:                        ip_lock(saved_reply);
        !          1269:                        assert(!ip_active(saved_reply));
        !          1270:                        timestamp = saved_reply->ip_timestamp;
        !          1271:                        ip_unlock(saved_reply);
        !          1272: 
        !          1273:                        ip_lock(dest);
        !          1274:                        must_undo = (!ip_active(dest) &&
        !          1275:                                     IP_TIMESTAMP_ORDER(dest->ip_timestamp,
        !          1276:                                                        timestamp));
        !          1277:                        ip_unlock(dest);
        !          1278: 
        !          1279:                        if (must_undo) {
        !          1280:                                /*
        !          1281:                                 *      Our worst nightmares are realized.
        !          1282:                                 *      Both destination and reply ports
        !          1283:                                 *      are dead, but in the wrong order,
        !          1284:                                 *      so we must undo the copyins and
        !          1285:                                 *      possibly generate a dead-name notif.
        !          1286:                                 */
        !          1287: 
        !          1288:                                ipc_right_copyin_undo(
        !          1289:                                                space, dest_name, dest_entry,
        !          1290:                                                dest_type, dest_port,
        !          1291:                                                dest_soright);
        !          1292:                                /* dest_entry may be deallocated now */
        !          1293: 
        !          1294:                                ipc_right_copyin_undo(
        !          1295:                                                space, reply_name, reply_entry,
        !          1296:                                                reply_type, reply_port,
        !          1297:                                                reply_soright);
        !          1298:                                /* reply_entry may be deallocated now */
        !          1299: 
        !          1300:                                is_write_unlock(space);
        !          1301: 
        !          1302:                                if (dest_soright != IP_NULL)
        !          1303:                                        ipc_notify_dead_name(dest_soright,
        !          1304:                                                             dest_name);
        !          1305:                                assert(reply_soright == IP_NULL);
        !          1306: 
        !          1307:                                ipc_port_release(saved_reply);
        !          1308:                                return MACH_SEND_INVALID_DEST;
        !          1309:                        }
        !          1310:                }
        !          1311: 
        !          1312:                /* the entries might need to be deallocated */
        !          1313: 
        !          1314:                if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1315:                        ipc_entry_dealloc(space, reply_name, reply_entry);
        !          1316: 
        !          1317: #if    MACH_IPC_COMPAT
        !          1318:            skip_reply_checks:
        !          1319:                /*
        !          1320:                 *      We jump here if the reply entry was a compat entry
        !          1321:                 *      and the port died on us.  In this case, the copyin
        !          1322:                 *      code already deallocated reply_entry.
        !          1323:                 */
        !          1324: #endif /* MACH_IPC_COMPAT */
        !          1325: 
        !          1326:                if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
        !          1327:                        ipc_entry_dealloc(space, dest_name, dest_entry);
        !          1328: 
        !          1329:                if (saved_reply != IP_NULL)
        !          1330:                        ipc_port_release(saved_reply);
        !          1331:        }
        !          1332: 
        !          1333:        /*
        !          1334:         *      At this point, dest_port, reply_port,
        !          1335:         *      dest_soright, reply_soright are all initialized.
        !          1336:         *      Any defunct entries have been deallocated.
        !          1337:         *      The space is still write-locked, and we need to
        !          1338:         *      make the MACH_SEND_CANCEL check.  The notify_port pointer
        !          1339:         *      is still usable, because the copyin code above won't ever
        !          1340:         *      deallocate a receive right, so its entry still exists
        !          1341:         *      and holds a ref.  Note notify_port might even equal
        !          1342:         *      dest_port or reply_port.
        !          1343:         */
        !          1344: 
        !          1345:        if ((notify != MACH_PORT_NULL) &&
        !          1346:            (dest_soright == notify_port)) {
        !          1347:                ipc_port_release_sonce(dest_soright);
        !          1348:                dest_soright = IP_NULL;
        !          1349:        }
        !          1350: 
        !          1351:        is_write_unlock(space);
        !          1352: 
        !          1353:        if (dest_soright != IP_NULL)
        !          1354:                ipc_notify_port_deleted(dest_soright, dest_name);
        !          1355: 
        !          1356:        if (reply_soright != IP_NULL)
        !          1357:                ipc_notify_port_deleted(reply_soright, reply_name);
        !          1358: 
        !          1359:        dest_type = ipc_object_copyin_type(dest_type);
        !          1360:        reply_type = ipc_object_copyin_type(reply_type);
        !          1361: 
        !          1362:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1363:                          MACH_MSGH_BITS(dest_type, reply_type));
        !          1364:        msg->msgh_remote_port = (mach_port_t) dest_port;
        !          1365:        msg->msgh_local_port = (mach_port_t) reply_port;
        !          1366:     }
        !          1367: 
        !          1368:        return MACH_MSG_SUCCESS;
        !          1369: 
        !          1370:     invalid_dest:
        !          1371:        is_write_unlock(space);
        !          1372:        return MACH_SEND_INVALID_DEST;
        !          1373: 
        !          1374:     invalid_reply:
        !          1375:        is_write_unlock(space);
        !          1376:        return MACH_SEND_INVALID_REPLY;
        !          1377: }
        !          1378: 
        !          1379: mach_msg_return_t
        !          1380: ipc_kmsg_copyin_body(kmsg, space, map)
        !          1381:        ipc_kmsg_t kmsg;
        !          1382:        ipc_space_t space;
        !          1383:        vm_map_t map;
        !          1384: {
        !          1385:        ipc_object_t dest;
        !          1386:        vm_offset_t saddr, eaddr;
        !          1387:        boolean_t complex;
        !          1388:        mach_msg_return_t mr;
        !          1389:        boolean_t use_page_lists, steal_pages;
        !          1390: 
        !          1391:        dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          1392:        complex = FALSE;
        !          1393:        use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
        !          1394:        steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
        !          1395: 
        !          1396: #if    NORMA_IPC
        !          1397:        if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
        !          1398:                use_page_lists = TRUE;
        !          1399:                steal_pages = TRUE;
        !          1400:        }
        !          1401: #endif /* NORMA_IPC */
        !          1402: 
        !          1403:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          1404:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          1405: 
        !          1406:        while (saddr < eaddr) {
        !          1407:                vm_offset_t taddr = saddr;
        !          1408:                mach_msg_type_long_t *type;
        !          1409:                mach_msg_type_name_t name;
        !          1410:                mach_msg_type_size_t size;
        !          1411:                mach_msg_type_number_t number;
        !          1412:                boolean_t is_inline, longform, dealloc, is_port;
        !          1413:                vm_offset_t data;
        !          1414:                vm_size_t length;
        !          1415:                kern_return_t kr;
        !          1416: 
        !          1417:                type = (mach_msg_type_long_t *) saddr;
        !          1418: 
        !          1419:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
        !          1420:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
        !          1421:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
        !          1422:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          1423:                        return MACH_SEND_MSG_TOO_SMALL;
        !          1424:                }
        !          1425: 
        !          1426:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          1427:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
        !          1428:                if (longform) {
        !          1429:                        /* This must be aligned */
        !          1430:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          1431:                            (is_misaligned(type))) {
        !          1432:                                saddr = ptr_align(saddr);
        !          1433:                                continue;
        !          1434:                        }
        !          1435:                        name = type->msgtl_name;
        !          1436:                        size = type->msgtl_size;
        !          1437:                        number = type->msgtl_number;
        !          1438:                        saddr += sizeof(mach_msg_type_long_t);
        !          1439:                } else {
        !          1440:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          1441:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          1442:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          1443:                        saddr += sizeof(mach_msg_type_t);
        !          1444:                }
        !          1445: 
        !          1446:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          1447: 
        !          1448:                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
        !          1449:                    (longform && ((type->msgtl_header.msgt_name != 0) ||
        !          1450:                                  (type->msgtl_header.msgt_size != 0) ||
        !          1451:                                  (type->msgtl_header.msgt_number != 0))) ||
        !          1452:                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
        !          1453:                    (dealloc && is_inline)) {
        !          1454:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          1455:                        return MACH_SEND_INVALID_TYPE;
        !          1456:                }
        !          1457: 
        !          1458:                /* padding (ptrs and ports) ? */
        !          1459:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          1460:                    ((size >> 3) == sizeof(natural_t)))
        !          1461:                        saddr = ptr_align(saddr);
        !          1462: 
        !          1463:                /* calculate length of data in bytes, rounding up */
        !          1464: 
        !          1465:                length = ((number * size) + 7) >> 3;
        !          1466: 
        !          1467:                if (is_inline) {
        !          1468:                        vm_size_t amount;
        !          1469: 
        !          1470:                        /* inline data sizes round up to int boundaries */
        !          1471: 
        !          1472:                        amount = (length + 3) &~ 3;
        !          1473:                        if ((eaddr - saddr) < amount) {
        !          1474:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          1475:                                return MACH_SEND_MSG_TOO_SMALL;
        !          1476:                        }
        !          1477: 
        !          1478:                        data = saddr;
        !          1479:                        saddr += amount;
        !          1480:                } else {
        !          1481:                        vm_offset_t addr;
        !          1482: 
        !          1483:                        if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
        !          1484:                                saddr = ptr_align(saddr);
        !          1485: 
        !          1486:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
        !          1487:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          1488:                                return MACH_SEND_MSG_TOO_SMALL;
        !          1489:                        }
        !          1490: 
        !          1491:                        /* grab the out-of-line data */
        !          1492: 
        !          1493:                        addr = * (vm_offset_t *) saddr;
        !          1494: 
        !          1495:                        if (length == 0)
        !          1496:                                data = 0;
        !          1497:                        else if (is_port) {
        !          1498:                                data = kalloc(length);
        !          1499:                                if (data == 0)
        !          1500:                                        goto invalid_memory;
        !          1501: 
        !          1502:                                if (copyinmap(map, (char *) addr,
        !          1503:                                              (char *) data, length) ||
        !          1504:                                    (dealloc &&
        !          1505:                                     (vm_deallocate(map, addr, length) !=
        !          1506:                                                        KERN_SUCCESS))) {
        !          1507:                                        kfree(data, length);
        !          1508:                                        goto invalid_memory;
        !          1509:                                }
        !          1510:                        } else {
        !          1511:                                vm_map_copy_t copy;
        !          1512: 
        !          1513:                                if (use_page_lists) {
        !          1514:                                        kr = vm_map_copyin_page_list(map,
        !          1515:                                                addr, length, dealloc,
        !          1516:                                                steal_pages, &copy, FALSE);
        !          1517:                                } else {
        !          1518:                                        kr = vm_map_copyin(map, addr, length,
        !          1519:                                                           dealloc, &copy);
        !          1520:                                }
        !          1521:                                if (kr != KERN_SUCCESS) {
        !          1522:                                    invalid_memory:
        !          1523:                                        ipc_kmsg_clean_partial(kmsg, taddr,
        !          1524:                                                               FALSE, 0);
        !          1525:                                        return MACH_SEND_INVALID_MEMORY;
        !          1526:                                }
        !          1527: 
        !          1528:                                data = (vm_offset_t) copy;
        !          1529:                        }
        !          1530: 
        !          1531:                        * (vm_offset_t *) saddr = data;
        !          1532:                        saddr += sizeof(vm_offset_t);
        !          1533:                        complex = TRUE;
        !          1534:                }
        !          1535: 
        !          1536:                if (is_port) {
        !          1537:                        mach_msg_type_name_t newname =
        !          1538:                                        ipc_object_copyin_type(name);
        !          1539:                        ipc_object_t *objects = (ipc_object_t *) data;
        !          1540:                        mach_msg_type_number_t i;
        !          1541: 
        !          1542:                        if (longform)
        !          1543:                                type->msgtl_name = newname;
        !          1544:                        else
        !          1545:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          1546: 
        !          1547:                        for (i = 0; i < number; i++) {
        !          1548:                                mach_port_t port = (mach_port_t) objects[i];
        !          1549:                                ipc_object_t object;
        !          1550: 
        !          1551:                                if (!MACH_PORT_VALID(port))
        !          1552:                                        continue;
        !          1553: 
        !          1554:                                kr = ipc_object_copyin(space, port,
        !          1555:                                                       name, &object);
        !          1556:                                if (kr != KERN_SUCCESS) {
        !          1557:                                        ipc_kmsg_clean_partial(kmsg, taddr,
        !          1558:                                                               TRUE, i);
        !          1559:                                        return MACH_SEND_INVALID_RIGHT;
        !          1560:                                }
        !          1561: 
        !          1562:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          1563:                                    ipc_port_check_circularity(
        !          1564:                                                        (ipc_port_t) object,
        !          1565:                                                        (ipc_port_t) dest))
        !          1566:                                        kmsg->ikm_header.msgh_bits |=
        !          1567:                                                MACH_MSGH_BITS_CIRCULAR;
        !          1568: 
        !          1569:                                objects[i] = object;
        !          1570:                        }
        !          1571: 
        !          1572:                        complex = TRUE;
        !          1573:                }
        !          1574:        }
        !          1575: 
        !          1576:        if (!complex)
        !          1577:                kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
        !          1578: 
        !          1579:        return MACH_MSG_SUCCESS;
        !          1580: }
        !          1581: 
        !          1582: /*
        !          1583:  *     Routine:        ipc_kmsg_copyin
        !          1584:  *     Purpose:
        !          1585:  *             "Copy-in" port rights and out-of-line memory
        !          1586:  *             in the message.
        !          1587:  *
        !          1588:  *             In all failure cases, the message is left holding
        !          1589:  *             no rights or memory.  However, the message buffer
        !          1590:  *             is not deallocated.  If successful, the message
        !          1591:  *             contains a valid destination port.
        !          1592:  *     Conditions:
        !          1593:  *             Nothing locked.
        !          1594:  *     Returns:
        !          1595:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          1596:  *             MACH_SEND_INVALID_HEADER
        !          1597:  *                     Illegal value in the message header bits.
        !          1598:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
        !          1599:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !          1600:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !          1601:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
        !          1602:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
        !          1603:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
        !          1604:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
        !          1605:  */
        !          1606: 
        !          1607: mach_msg_return_t
        !          1608: ipc_kmsg_copyin(kmsg, space, map, notify)
        !          1609:        ipc_kmsg_t kmsg;
        !          1610:        ipc_space_t space;
        !          1611:        vm_map_t map;
        !          1612:        mach_port_t notify;
        !          1613: {
        !          1614:        mach_msg_return_t mr;
        !          1615: 
        !          1616:        mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
        !          1617:        if (mr != MACH_MSG_SUCCESS)
        !          1618:                return mr;
        !          1619: 
        !          1620:        if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
        !          1621:                return MACH_MSG_SUCCESS;
        !          1622: 
        !          1623:        return ipc_kmsg_copyin_body(kmsg, space, map);
        !          1624: }
        !          1625: 
        !          1626: /*
        !          1627:  *     Routine:        ipc_kmsg_copyin_from_kernel
        !          1628:  *     Purpose:
        !          1629:  *             "Copy-in" port rights and out-of-line memory
        !          1630:  *             in a message sent from the kernel.
        !          1631:  *
        !          1632:  *             Because the message comes from the kernel,
        !          1633:  *             the implementation assumes there are no errors
        !          1634:  *             or peculiarities in the message.
        !          1635:  *
        !          1636:  *             Returns TRUE if queueing the message
        !          1637:  *             would result in a circularity.
        !          1638:  *     Conditions:
        !          1639:  *             Nothing locked.
        !          1640:  */
        !          1641: 
        !          1642: void
        !          1643: ipc_kmsg_copyin_from_kernel(
        !          1644:        ipc_kmsg_t      kmsg)
        !          1645: {
        !          1646:        mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
        !          1647:        mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
        !          1648:        mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
        !          1649:        ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          1650:        ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          1651:        vm_offset_t saddr, eaddr;
        !          1652: 
        !          1653:        /* translate the destination and reply ports */
        !          1654: 
        !          1655:        ipc_object_copyin_from_kernel(remote, rname);
        !          1656:        if (IO_VALID(local))
        !          1657:                ipc_object_copyin_from_kernel(local, lname);
        !          1658: 
        !          1659:        /*
        !          1660:         *      The common case is a complex message with no reply port,
        !          1661:         *      because that is what the memory_object interface uses.
        !          1662:         */
        !          1663: 
        !          1664:        if (bits == (MACH_MSGH_BITS_COMPLEX |
        !          1665:                     MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
        !          1666:                bits = (MACH_MSGH_BITS_COMPLEX |
        !          1667:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
        !          1668: 
        !          1669:                kmsg->ikm_header.msgh_bits = bits;
        !          1670:        } else {
        !          1671:                bits = (MACH_MSGH_BITS_OTHER(bits) |
        !          1672:                        MACH_MSGH_BITS(ipc_object_copyin_type(rname),
        !          1673:                                       ipc_object_copyin_type(lname)));
        !          1674: 
        !          1675:                kmsg->ikm_header.msgh_bits = bits;
        !          1676:                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
        !          1677:                        return;
        !          1678:        }
        !          1679: 
        !          1680:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          1681:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          1682: 
        !          1683:        while (saddr < eaddr) {
        !          1684:                mach_msg_type_long_t *type;
        !          1685:                mach_msg_type_name_t name;
        !          1686:                mach_msg_type_size_t size;
        !          1687:                mach_msg_type_number_t number;
        !          1688:                boolean_t is_inline, longform, is_port;
        !          1689:                vm_offset_t data;
        !          1690:                vm_size_t length;
        !          1691: 
        !          1692:                type = (mach_msg_type_long_t *) saddr;
        !          1693:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          1694:                longform = ((mach_msg_type_t*)type)->msgt_longform;
        !          1695:                /* type->msgtl_header.msgt_deallocate not used */
        !          1696:                if (longform) {
        !          1697:                        /* This must be aligned */
        !          1698:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          1699:                            (is_misaligned(type))) {
        !          1700:                                saddr = ptr_align(saddr);
        !          1701:                                continue;
        !          1702:                        }
        !          1703:                        name = type->msgtl_name;
        !          1704:                        size = type->msgtl_size;
        !          1705:                        number = type->msgtl_number;
        !          1706:                        saddr += sizeof(mach_msg_type_long_t);
        !          1707:                } else {
        !          1708:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          1709:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          1710:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          1711:                        saddr += sizeof(mach_msg_type_t);
        !          1712:                }
        !          1713: 
        !          1714:                /* padding (ptrs and ports) ? */
        !          1715:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          1716:                    ((size >> 3) == sizeof(natural_t)))
        !          1717:                        saddr = ptr_align(saddr);
        !          1718: 
        !          1719:                /* calculate length of data in bytes, rounding up */
        !          1720: 
        !          1721:                length = ((number * size) + 7) >> 3;
        !          1722: 
        !          1723:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          1724: 
        !          1725:                if (is_inline) {
        !          1726:                        /* inline data sizes round up to int boundaries */
        !          1727: 
        !          1728:                        data = saddr;
        !          1729:                        saddr += (length + 3) &~ 3;
        !          1730:                } else {
        !          1731:                        /*
        !          1732:                         *      The sender should supply ready-made memory
        !          1733:                         *      for us, so we don't need to do anything.
        !          1734:                         */
        !          1735: 
        !          1736:                        data = * (vm_offset_t *) saddr;
        !          1737:                        saddr += sizeof(vm_offset_t);
        !          1738:                }
        !          1739: 
        !          1740:                if (is_port) {
        !          1741:                        mach_msg_type_name_t newname =
        !          1742:                                        ipc_object_copyin_type(name);
        !          1743:                        ipc_object_t *objects = (ipc_object_t *) data;
        !          1744:                        mach_msg_type_number_t i;
        !          1745: 
        !          1746:                        if (longform)
        !          1747:                                type->msgtl_name = newname;
        !          1748:                        else
        !          1749:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          1750:                        for (i = 0; i < number; i++) {
        !          1751:                                ipc_object_t object = objects[i];
        !          1752: 
        !          1753:                                if (!IO_VALID(object))
        !          1754:                                        continue;
        !          1755: 
        !          1756:                                ipc_object_copyin_from_kernel(object, name);
        !          1757: 
        !          1758:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          1759:                                    ipc_port_check_circularity(
        !          1760:                                                        (ipc_port_t) object,
        !          1761:                                                        (ipc_port_t) remote))
        !          1762:                                        kmsg->ikm_header.msgh_bits |=
        !          1763:                                                MACH_MSGH_BITS_CIRCULAR;
        !          1764:                        }
        !          1765:                }
        !          1766:        }
        !          1767: }
        !          1768: 
        !          1769: /*
        !          1770:  *     Routine:        ipc_kmsg_copyout_header
        !          1771:  *     Purpose:
        !          1772:  *             "Copy-out" port rights in the header of a message.
        !          1773:  *             Operates atomically; if it doesn't succeed the
        !          1774:  *             message header and the space are left untouched.
        !          1775:  *             If it does succeed the remote/local port fields
        !          1776:  *             contain port names instead of object pointers,
        !          1777:  *             and the bits field is updated.
        !          1778:  *
        !          1779:  *             The notify argument implements the MACH_RCV_NOTIFY option.
        !          1780:  *             If it is not MACH_PORT_NULL, it should name a receive right.
        !          1781:  *             If the process of receiving the reply port creates a
        !          1782:  *             new right in the receiving task, then the new right is
        !          1783:  *             automatically registered for a dead-name notification,
        !          1784:  *             with the notify port supplying the send-once right.
        !          1785:  *     Conditions:
        !          1786:  *             Nothing locked.
        !          1787:  *     Returns:
        !          1788:  *             MACH_MSG_SUCCESS        Copied out port rights.
        !          1789:  *             MACH_RCV_INVALID_NOTIFY
        !          1790:  *                     Notify is non-null and doesn't name a receive right.
        !          1791:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
        !          1792:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
        !          1793:  *                     The space is dead.
        !          1794:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
        !          1795:  *                     No room in space for another name.
        !          1796:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
        !          1797:  *                     Couldn't allocate memory for the reply port.
        !          1798:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
        !          1799:  *                     Couldn't allocate memory for the dead-name request.
        !          1800:  */
        !          1801: 
        !          1802: mach_msg_return_t
        !          1803: ipc_kmsg_copyout_header(msg, space, notify)
        !          1804:        mach_msg_header_t *msg;
        !          1805:        ipc_space_t space;
        !          1806:        mach_port_t notify;
        !          1807: {
        !          1808:        mach_msg_bits_t mbits = msg->msgh_bits;
        !          1809:        ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
        !          1810: 
        !          1811:        assert(IP_VALID(dest));
        !          1812: 
        !          1813: #ifndef MIGRATING_THREADS
        !          1814:        /* first check for common cases */
        !          1815: 
        !          1816:        if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
        !          1817:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
        !          1818:                mach_port_t dest_name;
        !          1819:                ipc_port_t nsrequest;
        !          1820: 
        !          1821:                /* receiving an asynchronous message */
        !          1822: 
        !          1823:                ip_lock(dest);
        !          1824:                if (!ip_active(dest)) {
        !          1825:                        ip_unlock(dest);
        !          1826:                        break;
        !          1827:                }
        !          1828: 
        !          1829:                /* optimized ipc_object_copyout_dest */
        !          1830: 
        !          1831:                assert(dest->ip_srights > 0);
        !          1832:                ip_release(dest);
        !          1833: 
        !          1834:                if (dest->ip_receiver == space)
        !          1835:                        dest_name = dest->ip_receiver_name;
        !          1836:                else
        !          1837:                        dest_name = MACH_PORT_NULL;
        !          1838: 
        !          1839:                if ((--dest->ip_srights == 0) &&
        !          1840:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
        !          1841:                        mach_port_mscount_t mscount;
        !          1842: 
        !          1843:                        dest->ip_nsrequest = IP_NULL;
        !          1844:                        mscount = dest->ip_mscount;
        !          1845:                        ip_unlock(dest);
        !          1846: 
        !          1847:                        ipc_notify_no_senders(nsrequest, mscount);
        !          1848:                } else
        !          1849:                        ip_unlock(dest);
        !          1850: 
        !          1851:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1852:                                  MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
        !          1853:                msg->msgh_local_port = dest_name;
        !          1854:                msg->msgh_remote_port = MACH_PORT_NULL;
        !          1855:                return MACH_MSG_SUCCESS;
        !          1856:            }
        !          1857: 
        !          1858:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
        !          1859:                                MACH_MSG_TYPE_PORT_SEND_ONCE): {
        !          1860:                ipc_entry_t table;
        !          1861:                mach_port_index_t index;
        !          1862:                ipc_entry_t entry;
        !          1863:                ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
        !          1864:                mach_port_t dest_name, reply_name;
        !          1865:                ipc_port_t nsrequest;
        !          1866: 
        !          1867:                /* receiving a request message */
        !          1868: 
        !          1869:                if (!IP_VALID(reply))
        !          1870:                        break;
        !          1871: 
        !          1872:                is_write_lock(space);
        !          1873:                if (!space->is_active ||
        !          1874:                    ((index = (table = space->is_table)->ie_next) == 0)) {
        !          1875:                        is_write_unlock(space);
        !          1876:                        break;
        !          1877:                }
        !          1878: 
        !          1879:                /*
        !          1880:                 *      To do an atomic copyout, need simultaneous
        !          1881:                 *      locks on both ports and the space.  If
        !          1882:                 *      dest == reply, and simple locking is
        !          1883:                 *      enabled, then we will abort.  Otherwise it's
        !          1884:                 *      OK to unlock twice.
        !          1885:                 */
        !          1886: 
        !          1887:                ip_lock(dest);
        !          1888:                if (!ip_active(dest) || !ip_lock_try(reply)) {
        !          1889:                        ip_unlock(dest);
        !          1890:                        is_write_unlock(space);
        !          1891:                        break;
        !          1892:                }
        !          1893: 
        !          1894:                if (!ip_active(reply)) {
        !          1895:                        ip_unlock(reply);
        !          1896:                        ip_unlock(dest);
        !          1897:                        is_write_unlock(space);
        !          1898:                        break;
        !          1899:                }
        !          1900: 
        !          1901:                assert(reply->ip_sorights > 0);
        !          1902:                ip_unlock(reply);
        !          1903: 
        !          1904:                /* optimized ipc_entry_get */
        !          1905: 
        !          1906:                entry = &table[index];
        !          1907:                table->ie_next = entry->ie_next;
        !          1908:                entry->ie_request = 0;
        !          1909: 
        !          1910:            {
        !          1911:                mach_port_gen_t gen;
        !          1912: 
        !          1913:                assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
        !          1914:                gen = entry->ie_bits + IE_BITS_GEN_ONE;
        !          1915: 
        !          1916:                reply_name = MACH_PORT_MAKE(index, gen);
        !          1917: 
        !          1918:                /* optimized ipc_right_copyout */
        !          1919: 
        !          1920:                entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
        !          1921:            }
        !          1922: 
        !          1923:                assert(MACH_PORT_VALID(reply_name));
        !          1924:                entry->ie_object = (ipc_object_t) reply;
        !          1925:                is_write_unlock(space);
        !          1926: 
        !          1927:                /* optimized ipc_object_copyout_dest */
        !          1928: 
        !          1929:                assert(dest->ip_srights > 0);
        !          1930:                ip_release(dest);
        !          1931: 
        !          1932:                if (dest->ip_receiver == space)
        !          1933:                        dest_name = dest->ip_receiver_name;
        !          1934:                else
        !          1935:                        dest_name = MACH_PORT_NULL;
        !          1936: 
        !          1937:                if ((--dest->ip_srights == 0) &&
        !          1938:                    ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
        !          1939:                        mach_port_mscount_t mscount;
        !          1940: 
        !          1941:                        dest->ip_nsrequest = IP_NULL;
        !          1942:                        mscount = dest->ip_mscount;
        !          1943:                        ip_unlock(dest);
        !          1944: 
        !          1945:                        ipc_notify_no_senders(nsrequest, mscount);
        !          1946:                } else
        !          1947:                        ip_unlock(dest);
        !          1948: 
        !          1949:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1950:                                  MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
        !          1951:                                                 MACH_MSG_TYPE_PORT_SEND));
        !          1952:                msg->msgh_local_port = dest_name;
        !          1953:                msg->msgh_remote_port = reply_name;
        !          1954:                return MACH_MSG_SUCCESS;
        !          1955:            }
        !          1956: 
        !          1957:            case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
        !          1958:                mach_port_t dest_name;
        !          1959: 
        !          1960:                /* receiving a reply message */
        !          1961: 
        !          1962:                ip_lock(dest);
        !          1963:                if (!ip_active(dest)) {
        !          1964:                        ip_unlock(dest);
        !          1965:                        break;
        !          1966:                }
        !          1967: 
        !          1968:                /* optimized ipc_object_copyout_dest */
        !          1969: 
        !          1970:                assert(dest->ip_sorights > 0);
        !          1971: 
        !          1972:                if (dest->ip_receiver == space) {
        !          1973:                        ip_release(dest);
        !          1974:                        dest->ip_sorights--;
        !          1975:                        dest_name = dest->ip_receiver_name;
        !          1976:                        ip_unlock(dest);
        !          1977:                } else {
        !          1978:                        ip_unlock(dest);
        !          1979: 
        !          1980:                        ipc_notify_send_once(dest);
        !          1981:                        dest_name = MACH_PORT_NULL;
        !          1982:                }
        !          1983: 
        !          1984:                msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          1985:                        MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE));
        !          1986:                msg->msgh_local_port = dest_name;
        !          1987:                msg->msgh_remote_port = MACH_PORT_NULL;
        !          1988:                return MACH_MSG_SUCCESS;
        !          1989:            }
        !          1990: 
        !          1991:            default:
        !          1992:                /* don't bother optimizing */
        !          1993:                break;
        !          1994:        }
        !          1995: #endif /* MIGRATING_THREADS */
        !          1996: 
        !          1997:     {
        !          1998:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          1999:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          2000:        ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
        !          2001:        mach_port_t dest_name, reply_name;
        !          2002: 
        !          2003:        if (IP_VALID(reply)) {
        !          2004:                ipc_port_t notify_port;
        !          2005:                ipc_entry_t entry;
        !          2006:                kern_return_t kr;
        !          2007: 
        !          2008:                /*
        !          2009:                 *      Handling notify (for MACH_RCV_NOTIFY) is tricky.
        !          2010:                 *      The problem is atomically making a send-once right
        !          2011:                 *      from the notify port and installing it for a
        !          2012:                 *      dead-name request in the new entry, because this
        !          2013:                 *      requires two port locks (on the notify port and
        !          2014:                 *      the reply port).  However, we can safely make
        !          2015:                 *      and consume send-once rights for the notify port
        !          2016:                 *      as long as we hold the space locked.  This isn't
        !          2017:                 *      an atomicity problem, because the only way
        !          2018:                 *      to detect that a send-once right has been created
        !          2019:                 *      and then consumed if it wasn't needed is by getting
        !          2020:                 *      at the receive right to look at ip_sorights, and
        !          2021:                 *      because the space is write-locked status calls can't
        !          2022:                 *      lookup the notify port receive right.  When we make
        !          2023:                 *      the send-once right, we lock the notify port,
        !          2024:                 *      so any status calls in progress will be done.
        !          2025:                 */
        !          2026: 
        !          2027:                is_write_lock(space);
        !          2028: 
        !          2029:                for (;;) {
        !          2030:                        ipc_port_request_index_t request;
        !          2031: 
        !          2032:                        if (!space->is_active) {
        !          2033:                                is_write_unlock(space);
        !          2034:                                return (MACH_RCV_HEADER_ERROR|
        !          2035:                                        MACH_MSG_IPC_SPACE);
        !          2036:                        }
        !          2037: 
        !          2038:                        if (notify != MACH_PORT_NULL) {
        !          2039:                                notify_port = ipc_port_lookup_notify(space,
        !          2040:                                                                     notify);
        !          2041:                                if (notify_port == IP_NULL) {
        !          2042:                                        is_write_unlock(space);
        !          2043:                                        return MACH_RCV_INVALID_NOTIFY;
        !          2044:                                }
        !          2045:                        } else
        !          2046:                                notify_port = IP_NULL;
        !          2047: 
        !          2048:                        if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
        !          2049:                            ipc_right_reverse(space, (ipc_object_t) reply,
        !          2050:                                              &reply_name, &entry)) {
        !          2051:                                /* reply port is locked and active */
        !          2052: 
        !          2053:                                /*
        !          2054:                                 *      We don't need the notify_port
        !          2055:                                 *      send-once right, but we can't release
        !          2056:                                 *      it here because reply port is locked.
        !          2057:                                 *      Wait until after the copyout to
        !          2058:                                 *      release the notify port right.
        !          2059:                                 */
        !          2060: 
        !          2061:                                assert(entry->ie_bits &
        !          2062:                                                MACH_PORT_TYPE_SEND_RECEIVE);
        !          2063:                                break;
        !          2064:                        }
        !          2065: 
        !          2066:                        ip_lock(reply);
        !          2067:                        if (!ip_active(reply)) {
        !          2068:                                ip_release(reply);
        !          2069:                                ip_check_unlock(reply);
        !          2070: 
        !          2071:                                if (notify_port != IP_NULL)
        !          2072:                                        ipc_port_release_sonce(notify_port);
        !          2073: 
        !          2074:                                ip_lock(dest);
        !          2075:                                is_write_unlock(space);
        !          2076: 
        !          2077:                                reply = IP_DEAD;
        !          2078:                                reply_name = MACH_PORT_DEAD;
        !          2079:                                goto copyout_dest;
        !          2080:                        }
        !          2081: 
        !          2082:                        kr = ipc_entry_get(space, &reply_name, &entry);
        !          2083:                        if (kr != KERN_SUCCESS) {
        !          2084:                                ip_unlock(reply);
        !          2085: 
        !          2086:                                if (notify_port != IP_NULL)
        !          2087:                                        ipc_port_release_sonce(notify_port);
        !          2088: 
        !          2089:                                /* space is locked */
        !          2090:                                kr = ipc_entry_grow_table(space);
        !          2091:                                if (kr != KERN_SUCCESS) {
        !          2092:                                        /* space is unlocked */
        !          2093: 
        !          2094:                                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          2095:                                                return (MACH_RCV_HEADER_ERROR|
        !          2096:                                                        MACH_MSG_IPC_KERNEL);
        !          2097:                                        else
        !          2098:                                                return (MACH_RCV_HEADER_ERROR|
        !          2099:                                                        MACH_MSG_IPC_SPACE);
        !          2100:                                }
        !          2101:                                /* space is locked again; start over */
        !          2102: 
        !          2103:                                continue;
        !          2104:                        }
        !          2105: 
        !          2106:                        assert(IE_BITS_TYPE(entry->ie_bits)
        !          2107:                                                == MACH_PORT_TYPE_NONE);
        !          2108:                        assert(entry->ie_object == IO_NULL);
        !          2109: 
        !          2110:                        if (notify_port == IP_NULL) {
        !          2111:                                /* not making a dead-name request */
        !          2112: 
        !          2113:                                entry->ie_object = (ipc_object_t) reply;
        !          2114:                                break;
        !          2115:                        }
        !          2116: 
        !          2117:                        kr = ipc_port_dnrequest(reply, reply_name,
        !          2118:                                                notify_port, &request);
        !          2119:                        if (kr != KERN_SUCCESS) {
        !          2120:                                ip_unlock(reply);
        !          2121: 
        !          2122:                                ipc_port_release_sonce(notify_port);
        !          2123: 
        !          2124:                                ipc_entry_dealloc(space, reply_name, entry);
        !          2125:                                is_write_unlock(space);
        !          2126: 
        !          2127:                                ip_lock(reply);
        !          2128:                                if (!ip_active(reply)) {
        !          2129:                                        /* will fail next time around loop */
        !          2130: 
        !          2131:                                        ip_unlock(reply);
        !          2132:                                        is_write_lock(space);
        !          2133:                                        continue;
        !          2134:                                }
        !          2135: 
        !          2136:                                kr = ipc_port_dngrow(reply);
        !          2137:                                /* port is unlocked */
        !          2138:                                if (kr != KERN_SUCCESS)
        !          2139:                                        return (MACH_RCV_HEADER_ERROR|
        !          2140:                                                MACH_MSG_IPC_KERNEL);
        !          2141: 
        !          2142:                                is_write_lock(space);
        !          2143:                                continue;
        !          2144:                        }
        !          2145: 
        !          2146:                        notify_port = IP_NULL; /* don't release right below */
        !          2147: 
        !          2148:                        entry->ie_object = (ipc_object_t) reply;
        !          2149:                        entry->ie_request = request;
        !          2150:                        break;
        !          2151:                }
        !          2152: 
        !          2153:                /* space and reply port are locked and active */
        !          2154: 
        !          2155:                ip_reference(reply);    /* hold onto the reply port */
        !          2156: 
        !          2157:                kr = ipc_right_copyout(space, reply_name, entry,
        !          2158:                                       reply_type, TRUE, (ipc_object_t) reply);
        !          2159:                /* reply port is unlocked */
        !          2160:                assert(kr == KERN_SUCCESS);
        !          2161: 
        !          2162:                if (notify_port != IP_NULL)
        !          2163:                        ipc_port_release_sonce(notify_port);
        !          2164: 
        !          2165:                ip_lock(dest);
        !          2166:                is_write_unlock(space);
        !          2167:        } else {
        !          2168:                /*
        !          2169:                 *      No reply port!  This is an easy case.
        !          2170:                 *      We only need to have the space locked
        !          2171:                 *      when checking notify and when locking
        !          2172:                 *      the destination (to ensure atomicity).
        !          2173:                 */
        !          2174: 
        !          2175:                is_read_lock(space);
        !          2176:                if (!space->is_active) {
        !          2177:                        is_read_unlock(space);
        !          2178:                        return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
        !          2179:                }
        !          2180: 
        !          2181:                if (notify != MACH_PORT_NULL) {
        !          2182:                        ipc_entry_t entry;
        !          2183: 
        !          2184:                        /* must check notify even though it won't be used */
        !          2185: 
        !          2186:                        if (((entry = ipc_entry_lookup(space, notify))
        !          2187:                                                                == IE_NULL) ||
        !          2188:                            ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
        !          2189:                                is_read_unlock(space);
        !          2190:                                return MACH_RCV_INVALID_NOTIFY;
        !          2191:                        }
        !          2192:                }
        !          2193: 
        !          2194:                ip_lock(dest);
        !          2195:                is_read_unlock(space);
        !          2196: 
        !          2197:                reply_name = (mach_port_t) reply;
        !          2198:        }
        !          2199: 
        !          2200:        /*
        !          2201:         *      At this point, the space is unlocked and the destination
        !          2202:         *      port is locked.  (Lock taken while space was locked.)
        !          2203:         *      reply_name is taken care of; we still need dest_name.
        !          2204:         *      We still hold a ref for reply (if it is valid).
        !          2205:         *
        !          2206:         *      If the space holds receive rights for the destination,
        !          2207:         *      we return its name for the right.  Otherwise the task
        !          2208:         *      managed to destroy or give away the receive right between
        !          2209:         *      receiving the message and this copyout.  If the destination
        !          2210:         *      is dead, return MACH_PORT_DEAD, and if the receive right
        !          2211:         *      exists somewhere else (another space, in transit)
        !          2212:         *      return MACH_PORT_NULL.
        !          2213:         *
        !          2214:         *      Making this copyout operation atomic with the previous
        !          2215:         *      copyout of the reply port is a bit tricky.  If there was
        !          2216:         *      no real reply port (it wasn't IP_VALID) then this isn't
        !          2217:         *      an issue.  If the reply port was dead at copyout time,
        !          2218:         *      then we are OK, because if dest is dead we serialize
        !          2219:         *      after the death of both ports and if dest is alive
        !          2220:         *      we serialize after reply died but before dest's (later) death.
        !          2221:         *      So assume reply was alive when we copied it out.  If dest
        !          2222:         *      is alive, then we are OK because we serialize before
        !          2223:         *      the ports' deaths.  So assume dest is dead when we look at it.
        !          2224:         *      If reply dies/died after dest, then we are OK because
        !          2225:         *      we serialize after dest died but before reply dies.
        !          2226:         *      So the hard case is when reply is alive at copyout,
        !          2227:         *      dest is dead at copyout, and reply died before dest died.
        !          2228:         *      In this case pretend that dest is still alive, so
        !          2229:         *      we serialize while both ports are alive.
        !          2230:         *
        !          2231:         *      Because the space lock is held across the copyout of reply
        !          2232:         *      and locking dest, the receive right for dest can't move
        !          2233:         *      in or out of the space while the copyouts happen, so
        !          2234:         *      that isn't an atomicity problem.  In the last hard case
        !          2235:         *      above, this implies that when dest is dead that the
        !          2236:         *      space couldn't have had receive rights for dest at
        !          2237:         *      the time reply was copied-out, so when we pretend
        !          2238:         *      that dest is still alive, we can return MACH_PORT_NULL.
        !          2239:         *
        !          2240:         *      If dest == reply, then we have to make it look like
        !          2241:         *      either both copyouts happened before the port died,
        !          2242:         *      or both happened after the port died.  This special
        !          2243:         *      case works naturally if the timestamp comparison
        !          2244:         *      is done correctly.
        !          2245:         */
        !          2246: 
        !          2247:     copyout_dest:
        !          2248: 
        !          2249:        if (ip_active(dest)) {
        !          2250:                ipc_object_copyout_dest(space, (ipc_object_t) dest,
        !          2251:                                        dest_type, &dest_name);
        !          2252:                /* dest is unlocked */
        !          2253:        } else {
        !          2254:                ipc_port_timestamp_t timestamp;
        !          2255: 
        !          2256:                timestamp = dest->ip_timestamp;
        !          2257:                ip_release(dest);
        !          2258:                ip_check_unlock(dest);
        !          2259: 
        !          2260:                if (IP_VALID(reply)) {
        !          2261:                        ip_lock(reply);
        !          2262:                        if (ip_active(reply) ||
        !          2263:                            IP_TIMESTAMP_ORDER(timestamp,
        !          2264:                                               reply->ip_timestamp))
        !          2265:                                dest_name = MACH_PORT_DEAD;
        !          2266:                        else
        !          2267:                                dest_name = MACH_PORT_NULL;
        !          2268:                        ip_unlock(reply);
        !          2269:                } else
        !          2270:                        dest_name = MACH_PORT_DEAD;
        !          2271:        }
        !          2272: 
        !          2273:        if (IP_VALID(reply))
        !          2274:                ipc_port_release(reply);
        !          2275: 
        !          2276:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2277:                          MACH_MSGH_BITS(reply_type, dest_type));
        !          2278:        msg->msgh_local_port = dest_name;
        !          2279:        msg->msgh_remote_port = reply_name;
        !          2280:     }
        !          2281: 
        !          2282:        return MACH_MSG_SUCCESS;
        !          2283: }
        !          2284: 
        !          2285: /*
        !          2286:  *     Routine:        ipc_kmsg_copyout_object
        !          2287:  *     Purpose:
        !          2288:  *             Copy-out a port right.  Always returns a name,
        !          2289:  *             even for unsuccessful return codes.  Always
        !          2290:  *             consumes the supplied object.
        !          2291:  *     Conditions:
        !          2292:  *             Nothing locked.
        !          2293:  *     Returns:
        !          2294:  *             MACH_MSG_SUCCESS        The space acquired the right
        !          2295:  *                     (name is valid) or the object is dead (MACH_PORT_DEAD).
        !          2296:  *             MACH_MSG_IPC_SPACE      No room in space for the right,
        !          2297:  *                     or the space is dead.  (Name is MACH_PORT_NULL.)
        !          2298:  *             MACH_MSG_IPC_KERNEL     Kernel resource shortage.
        !          2299:  *                     (Name is MACH_PORT_NULL.)
        !          2300:  */
        !          2301: 
        !          2302: mach_msg_return_t
        !          2303: ipc_kmsg_copyout_object(space, object, msgt_name, namep)
        !          2304:        ipc_space_t space;
        !          2305:        ipc_object_t object;
        !          2306:        mach_msg_type_name_t msgt_name;
        !          2307:        mach_port_t *namep;
        !          2308: {
        !          2309:        if (!IO_VALID(object)) {
        !          2310:                *namep = (mach_port_t) object;
        !          2311:                return MACH_MSG_SUCCESS;
        !          2312:        }
        !          2313: 
        !          2314: #ifndef MIGRATING_THREADS
        !          2315:        /*
        !          2316:         *      Attempt quick copyout of send rights.  We optimize for a
        !          2317:         *      live port for which the receiver holds send (and not
        !          2318:         *      receive) rights in his local table.
        !          2319:         */
        !          2320: 
        !          2321:        if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
        !          2322:                goto slow_copyout;
        !          2323: 
        !          2324:     {
        !          2325:        register ipc_port_t port = (ipc_port_t) object;
        !          2326:        ipc_entry_t entry;
        !          2327: 
        !          2328:        is_write_lock(space);
        !          2329:        if (!space->is_active) {
        !          2330:                is_write_unlock(space);
        !          2331:                goto slow_copyout;
        !          2332:        }
        !          2333: 
        !          2334:        ip_lock(port);
        !          2335:        if (!ip_active(port) ||
        !          2336:            !ipc_hash_local_lookup(space, (ipc_object_t) port,
        !          2337:                                   namep, &entry)) {
        !          2338:                ip_unlock(port);
        !          2339:                is_write_unlock(space);
        !          2340:                goto slow_copyout;
        !          2341:        }
        !          2342: 
        !          2343:        /*
        !          2344:         *      Copyout the send right, incrementing urefs
        !          2345:         *      unless it would overflow, and consume the right.
        !          2346:         */
        !          2347: 
        !          2348:        assert(port->ip_srights > 1);
        !          2349:        port->ip_srights--;
        !          2350:        ip_release(port);
        !          2351:        ip_unlock(port);
        !          2352: 
        !          2353:        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
        !          2354:        assert(IE_BITS_UREFS(entry->ie_bits) > 0);
        !          2355:        assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
        !          2356: 
        !          2357:     {
        !          2358:        register ipc_entry_bits_t bits = entry->ie_bits + 1;
        !          2359: 
        !          2360:        if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
        !          2361:                entry->ie_bits = bits;
        !          2362:     }
        !          2363: 
        !          2364:        is_write_unlock(space);
        !          2365:        return MACH_MSG_SUCCESS;
        !          2366:     }
        !          2367: 
        !          2368:     slow_copyout:
        !          2369: #endif /* MIGRATING_THREADS */
        !          2370: 
        !          2371:    {
        !          2372:        kern_return_t kr;
        !          2373: 
        !          2374:        kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
        !          2375:        if (kr != KERN_SUCCESS) {
        !          2376:                ipc_object_destroy(object, msgt_name);
        !          2377: 
        !          2378:                if (kr == KERN_INVALID_CAPABILITY)
        !          2379:                        *namep = MACH_PORT_DEAD;
        !          2380:                else {
        !          2381:                        *namep = MACH_PORT_NULL;
        !          2382: 
        !          2383:                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          2384:                                return MACH_MSG_IPC_KERNEL;
        !          2385:                        else
        !          2386:                                return MACH_MSG_IPC_SPACE;
        !          2387:                }
        !          2388:        }
        !          2389: 
        !          2390:        return MACH_MSG_SUCCESS;
        !          2391:     }
        !          2392: }
        !          2393: 
        !          2394: /*
        !          2395:  *     Routine:        ipc_kmsg_copyout_body
        !          2396:  *     Purpose:
        !          2397:  *             "Copy-out" port rights and out-of-line memory
        !          2398:  *             in the body of a message.
        !          2399:  *
        !          2400:  *             The error codes are a combination of special bits.
        !          2401:  *             The copyout proceeds despite errors.
        !          2402:  *     Conditions:
        !          2403:  *             Nothing locked.
        !          2404:  *     Returns:
        !          2405:  *             MACH_MSG_SUCCESS        Successful copyout.
        !          2406:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
        !          2407:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
        !          2408:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
        !          2409:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
        !          2410:  */
        !          2411: 
        !          2412: mach_msg_return_t
        !          2413: ipc_kmsg_copyout_body(saddr, eaddr, space, map)
        !          2414:        vm_offset_t saddr, eaddr;
        !          2415:        ipc_space_t space;
        !          2416:        vm_map_t map;
        !          2417: {
        !          2418:        mach_msg_return_t mr = MACH_MSG_SUCCESS;
        !          2419:        kern_return_t kr;
        !          2420: 
        !          2421:        while (saddr < eaddr) {
        !          2422:                vm_offset_t taddr = saddr;
        !          2423:                mach_msg_type_long_t *type;
        !          2424:                mach_msg_type_name_t name;
        !          2425:                mach_msg_type_size_t size;
        !          2426:                mach_msg_type_number_t number;
        !          2427:                boolean_t is_inline, longform, is_port;
        !          2428:                vm_size_t length;
        !          2429:                vm_offset_t addr;
        !          2430: 
        !          2431:                type = (mach_msg_type_long_t *) saddr;
        !          2432:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          2433:                longform = ((mach_msg_type_t*)type)->msgt_longform;
        !          2434:                if (longform) {
        !          2435:                        /* This must be aligned */
        !          2436:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          2437:                            (is_misaligned(type))) {
        !          2438:                                saddr = ptr_align(saddr);
        !          2439:                                continue;
        !          2440:                        }
        !          2441:                        name = type->msgtl_name;
        !          2442:                        size = type->msgtl_size;
        !          2443:                        number = type->msgtl_number;
        !          2444:                        saddr += sizeof(mach_msg_type_long_t);
        !          2445:                } else {
        !          2446:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          2447:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          2448:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          2449:                        saddr += sizeof(mach_msg_type_t);
        !          2450:                }
        !          2451: 
        !          2452:                /* padding (ptrs and ports) ? */
        !          2453:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          2454:                    ((size >> 3) == sizeof(natural_t)))
        !          2455:                        saddr = ptr_align(saddr);
        !          2456: 
        !          2457:                /* calculate length of data in bytes, rounding up */
        !          2458: 
        !          2459:                length = ((number * size) + 7) >> 3;
        !          2460: 
        !          2461:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          2462: 
        !          2463:                if (is_port) {
        !          2464:                        mach_port_t *objects;
        !          2465:                        mach_msg_type_number_t i;
        !          2466: 
        !          2467:                        if (!is_inline && (length != 0)) {
        !          2468:                                /* first allocate memory in the map */
        !          2469: 
        !          2470:                                kr = vm_allocate(map, &addr, length, TRUE);
        !          2471:                                if (kr != KERN_SUCCESS) {
        !          2472:                                        ipc_kmsg_clean_body(taddr, saddr);
        !          2473:                                        goto vm_copyout_failure;
        !          2474:                                }
        !          2475:                        }
        !          2476: 
        !          2477:                        objects = (mach_port_t *)
        !          2478:                                (is_inline ? saddr : * (vm_offset_t *) saddr);
        !          2479: 
        !          2480:                        /* copyout port rights carried in the message */
        !          2481: 
        !          2482:                        for (i = 0; i < number; i++) {
        !          2483:                                ipc_object_t object =
        !          2484:                                        (ipc_object_t) objects[i];
        !          2485: 
        !          2486:                                mr |= ipc_kmsg_copyout_object(space, object,
        !          2487:                                                        name, &objects[i]);
        !          2488:                        }
        !          2489:                }
        !          2490: 
        !          2491:                if (is_inline) {
        !          2492:                        /* inline data sizes round up to int boundaries */
        !          2493: 
        !          2494:                        ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
        !          2495:                        saddr += (length + 3) &~ 3;
        !          2496:                } else {
        !          2497:                        vm_offset_t data;
        !          2498: 
        !          2499:                        if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
        !          2500:                                saddr = ptr_align(saddr);
        !          2501: 
        !          2502:                        data = * (vm_offset_t *) saddr;
        !          2503: 
        !          2504:                        /* copyout memory carried in the message */
        !          2505: 
        !          2506:                        if (length == 0) {
        !          2507:                                assert(data == 0);
        !          2508:                                addr = 0;
        !          2509:                        } else if (is_port) {
        !          2510:                                /* copyout to memory allocated above */
        !          2511: 
        !          2512:                                (void) copyoutmap(map, (char *) data,
        !          2513:                                                  (char *) addr, length);
        !          2514:                                kfree(data, length);
        !          2515:                        } else {
        !          2516:                                vm_map_copy_t copy = (vm_map_copy_t) data;
        !          2517: 
        !          2518:                                kr = vm_map_copyout(map, &addr, copy);
        !          2519:                                if (kr != KERN_SUCCESS) {
        !          2520:                                        vm_map_copy_discard(copy);
        !          2521: 
        !          2522:                                    vm_copyout_failure:
        !          2523: 
        !          2524:                                        addr = 0;
        !          2525:                                        if (longform)
        !          2526:                                                type->msgtl_size = 0;
        !          2527:                                        else
        !          2528:                                                ((mach_msg_type_t*)type)->msgt_size = 0;
        !          2529: 
        !          2530:                                        if (kr == KERN_RESOURCE_SHORTAGE)
        !          2531:                                                mr |= MACH_MSG_VM_KERNEL;
        !          2532:                                        else
        !          2533:                                                mr |= MACH_MSG_VM_SPACE;
        !          2534:                                }
        !          2535:                        }
        !          2536: 
        !          2537:                        ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
        !          2538:                        * (vm_offset_t *) saddr = addr;
        !          2539:                        saddr += sizeof(vm_offset_t);
        !          2540:                }
        !          2541:        }
        !          2542: 
        !          2543:        return mr;
        !          2544: }
        !          2545: 
        !          2546: /*
        !          2547:  *     Routine:        ipc_kmsg_copyout
        !          2548:  *     Purpose:
        !          2549:  *             "Copy-out" port rights and out-of-line memory
        !          2550:  *             in the message.
        !          2551:  *     Conditions:
        !          2552:  *             Nothing locked.
        !          2553:  *     Returns:
        !          2554:  *             MACH_MSG_SUCCESS        Copied out all rights and memory.
        !          2555:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
        !          2556:  *                     Rights and memory in the message are intact.
        !          2557:  *             MACH_RCV_HEADER_ERROR + special bits
        !          2558:  *                     Rights and memory in the message are intact.
        !          2559:  *             MACH_RCV_BODY_ERROR + special bits
        !          2560:  *                     The message header was successfully copied out.
        !          2561:  *                     As much of the body was handled as possible.
        !          2562:  */
        !          2563: 
        !          2564: mach_msg_return_t
        !          2565: ipc_kmsg_copyout(kmsg, space, map, notify)
        !          2566:        ipc_kmsg_t kmsg;
        !          2567:        ipc_space_t space;
        !          2568:        vm_map_t map;
        !          2569:        mach_port_t notify;
        !          2570: {
        !          2571:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          2572:        mach_msg_return_t mr;
        !          2573: 
        !          2574:        mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
        !          2575:        if (mr != MACH_MSG_SUCCESS)
        !          2576:                return mr;
        !          2577: 
        !          2578:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          2579:                vm_offset_t saddr, eaddr;
        !          2580: 
        !          2581:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          2582:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !          2583:                                kmsg->ikm_header.msgh_size;
        !          2584: 
        !          2585:                mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
        !          2586:                if (mr != MACH_MSG_SUCCESS)
        !          2587:                        mr |= MACH_RCV_BODY_ERROR;
        !          2588:        }
        !          2589: 
        !          2590:        return mr;
        !          2591: }
        !          2592: 
        !          2593: /*
        !          2594:  *     Routine:        ipc_kmsg_copyout_pseudo
        !          2595:  *     Purpose:
        !          2596:  *             Does a pseudo-copyout of the message.
        !          2597:  *             This is like a regular copyout, except
        !          2598:  *             that the ports in the header are handled
        !          2599:  *             as if they are in the body.  They aren't reversed.
        !          2600:  *
        !          2601:  *             The error codes are a combination of special bits.
        !          2602:  *             The copyout proceeds despite errors.
        !          2603:  *     Conditions:
        !          2604:  *             Nothing locked.
        !          2605:  *     Returns:
        !          2606:  *             MACH_MSG_SUCCESS        Successful copyout.
        !          2607:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
        !          2608:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
        !          2609:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
        !          2610:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
        !          2611:  */
        !          2612: 
        !          2613: mach_msg_return_t
        !          2614: ipc_kmsg_copyout_pseudo(
        !          2615:        ipc_kmsg_t              kmsg,
        !          2616:        ipc_space_t             space,
        !          2617:        vm_map_t                map)
        !          2618: {
        !          2619:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          2620:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          2621:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          2622:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          2623:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          2624:        mach_port_t dest_name, reply_name;
        !          2625:        mach_msg_return_t mr;
        !          2626: 
        !          2627:        assert(IO_VALID(dest));
        !          2628: 
        !          2629:        mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
        !          2630:              ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
        !          2631: 
        !          2632:        kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
        !          2633:        kmsg->ikm_header.msgh_remote_port = dest_name;
        !          2634:        kmsg->ikm_header.msgh_local_port = reply_name;
        !          2635: 
        !          2636:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          2637:                vm_offset_t saddr, eaddr;
        !          2638: 
        !          2639:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          2640:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !          2641:                                kmsg->ikm_header.msgh_size;
        !          2642: 
        !          2643:                mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
        !          2644:        }
        !          2645: 
        !          2646:        return mr;
        !          2647: }
        !          2648: 
        !          2649: /*
        !          2650:  *     Routine:        ipc_kmsg_copyout_dest
        !          2651:  *     Purpose:
        !          2652:  *             Copies out the destination port in the message.
        !          2653:  *             Destroys all other rights and memory in the message.
        !          2654:  *     Conditions:
        !          2655:  *             Nothing locked.
        !          2656:  */
        !          2657: 
        !          2658: void
        !          2659: ipc_kmsg_copyout_dest(kmsg, space)
        !          2660:        ipc_kmsg_t kmsg;
        !          2661:        ipc_space_t space;
        !          2662: {
        !          2663:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          2664:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          2665:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          2666:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          2667:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          2668:        mach_port_t dest_name, reply_name;
        !          2669: 
        !          2670:        assert(IO_VALID(dest));
        !          2671: 
        !          2672:        io_lock(dest);
        !          2673:        if (io_active(dest)) {
        !          2674:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          2675:                /* dest is unlocked */
        !          2676:        } else {
        !          2677:                io_release(dest);
        !          2678:                io_check_unlock(dest);
        !          2679:                dest_name = MACH_PORT_DEAD;
        !          2680:        }
        !          2681: 
        !          2682:        if (IO_VALID(reply)) {
        !          2683:                ipc_object_destroy(reply, reply_type);
        !          2684:                reply_name = MACH_PORT_NULL;
        !          2685:        } else
        !          2686:                reply_name = (mach_port_t) reply;
        !          2687: 
        !          2688:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2689:                                      MACH_MSGH_BITS(reply_type, dest_type));
        !          2690:        kmsg->ikm_header.msgh_local_port = dest_name;
        !          2691:        kmsg->ikm_header.msgh_remote_port = reply_name;
        !          2692: 
        !          2693:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
        !          2694:                vm_offset_t saddr, eaddr;
        !          2695: 
        !          2696:                saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          2697:                eaddr = (vm_offset_t) &kmsg->ikm_header +
        !          2698:                                kmsg->ikm_header.msgh_size;
        !          2699: 
        !          2700:                ipc_kmsg_clean_body(saddr, eaddr);
        !          2701:        }
        !          2702: }
        !          2703: 
        !          2704: #if    NORMA_IPC || NORMA_VM
        !          2705: /*
        !          2706:  *     Routine:        ipc_kmsg_copyout_to_kernel
        !          2707:  *     Purpose:
        !          2708:  *             Copies out the destination and reply ports in the message.
        !          2709:  *             Leaves all other rights and memory in the message alone.
        !          2710:  *     Conditions:
        !          2711:  *             Nothing locked.
        !          2712:  *
        !          2713:  *     Derived from ipc_kmsg_copyout_dest.
        !          2714:  *     Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
        !          2715:  *     We really do want to save rights and memory.
        !          2716:  */
        !          2717: 
        !          2718: void
        !          2719: ipc_kmsg_copyout_to_kernel(kmsg, space)
        !          2720:        ipc_kmsg_t kmsg;
        !          2721:        ipc_space_t space;
        !          2722: {
        !          2723:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          2724:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          2725:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          2726:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          2727:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          2728:        mach_port_t dest_name, reply_name;
        !          2729: 
        !          2730:        assert(IO_VALID(dest));
        !          2731: 
        !          2732:        io_lock(dest);
        !          2733:        if (io_active(dest)) {
        !          2734:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          2735:                /* dest is unlocked */
        !          2736:        } else {
        !          2737:                io_release(dest);
        !          2738:                io_check_unlock(dest);
        !          2739:                dest_name = MACH_PORT_DEAD;
        !          2740:        }
        !          2741: 
        !          2742:        reply_name = (mach_port_t) reply;
        !          2743: 
        !          2744:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
        !          2745:                                      MACH_MSGH_BITS(reply_type, dest_type));
        !          2746:        kmsg->ikm_header.msgh_local_port = dest_name;
        !          2747:        kmsg->ikm_header.msgh_remote_port = reply_name;
        !          2748: }
        !          2749: #endif /* NORMA_IPC || NORMA_VM */
        !          2750: 
        !          2751: #if    MACH_IPC_COMPAT
        !          2752: 
        !          2753: /*
        !          2754:  *     Routine:        ipc_kmsg_copyin_compat
        !          2755:  *     Purpose:
        !          2756:  *             "Copy-in" port rights and out-of-line memory
        !          2757:  *             in the message.
        !          2758:  *
        !          2759:  *             In all failure cases, the message is left holding
        !          2760:  *             no rights or memory.  However, the message buffer
        !          2761:  *             is not deallocated.  If successful, the message
        !          2762:  *             contains a valid destination port.
        !          2763:  *     Conditions:
        !          2764:  *             Nothing locked.
        !          2765:  *     Returns:
        !          2766:  *             MACH_MSG_SUCCESS        Successful copyin.
        !          2767:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
        !          2768:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
        !          2769:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
        !          2770:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
        !          2771:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
        !          2772:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
        !          2773:  */
        !          2774: 
        !          2775: mach_msg_return_t
        !          2776: ipc_kmsg_copyin_compat(kmsg, space, map)
        !          2777:        ipc_kmsg_t kmsg;
        !          2778:        ipc_space_t space;
        !          2779:        vm_map_t map;
        !          2780: {
        !          2781:        msg_header_t msg;
        !          2782:        mach_port_t dest_name;
        !          2783:        mach_port_t reply_name;
        !          2784:        ipc_object_t dest, reply;
        !          2785:        mach_msg_type_name_t dest_type, reply_type;
        !          2786:        vm_offset_t saddr, eaddr;
        !          2787:        boolean_t complex;
        !          2788:        kern_return_t kr;
        !          2789:        boolean_t use_page_lists, steal_pages;
        !          2790: 
        !          2791:        msg = * (msg_header_t *) &kmsg->ikm_header;
        !          2792:        dest_name = (mach_port_t) msg.msg_remote_port;
        !          2793:        reply_name = (mach_port_t) msg.msg_local_port;
        !          2794: 
        !          2795:        /* translate the destination and reply ports */
        !          2796: 
        !          2797:        kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type);
        !          2798:        if (kr != KERN_SUCCESS)
        !          2799:                return MACH_SEND_INVALID_DEST;
        !          2800: 
        !          2801:        if (reply_name == MACH_PORT_NULL) {
        !          2802:                reply = IO_NULL;
        !          2803:                reply_type = 0;
        !          2804:        } else {
        !          2805:                kr = ipc_object_copyin_header(space, reply_name,
        !          2806:                                              &reply, &reply_type);
        !          2807:                if (kr != KERN_SUCCESS) {
        !          2808:                        ipc_object_destroy(dest, dest_type);
        !          2809:                        return MACH_SEND_INVALID_REPLY;
        !          2810:                }
        !          2811:        }
        !          2812: 
        !          2813:        kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type);
        !          2814:        kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size;
        !          2815:        kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest;
        !          2816:        kmsg->ikm_header.msgh_local_port = (mach_port_t) reply;
        !          2817:        kmsg->ikm_header.msgh_seqno = (mach_msg_kind_t) msg.msg_type;
        !          2818:        kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id;
        !          2819: 
        !          2820:        if (msg.msg_simple)
        !          2821:                return MACH_MSG_SUCCESS;
        !          2822: 
        !          2823:        complex = FALSE;
        !          2824:        use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
        !          2825:        steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
        !          2826: 
        !          2827: #if    NORMA_IPC
        !          2828:        if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
        !          2829:                use_page_lists = TRUE;
        !          2830:                steal_pages = TRUE;
        !          2831:        }
        !          2832: #endif /* NORMA_IPC */
        !          2833: 
        !          2834:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          2835:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          2836: 
        !          2837:        while (saddr < eaddr) {
        !          2838:                vm_offset_t taddr = saddr;
        !          2839:                mach_msg_type_long_t *type;
        !          2840:                mach_msg_type_name_t name;
        !          2841:                mach_msg_type_size_t size;
        !          2842:                mach_msg_type_number_t number;
        !          2843:                boolean_t is_inline, longform, dealloc, is_port;
        !          2844:                vm_offset_t data;
        !          2845:                vm_size_t length;
        !          2846: 
        !          2847:                type = (mach_msg_type_long_t *) saddr;
        !          2848: 
        !          2849:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
        !          2850:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
        !          2851:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
        !          2852:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          2853:                        return MACH_SEND_MSG_TOO_SMALL;
        !          2854:                }
        !          2855: 
        !          2856:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          2857:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
        !          2858:                if (longform) {
        !          2859:                        /* This must be aligned */
        !          2860:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          2861:                            (is_misaligned(type))) {
        !          2862:                                saddr = ptr_align(saddr);
        !          2863:                                continue;
        !          2864:                        }
        !          2865:                        name = type->msgtl_name;
        !          2866:                        size = type->msgtl_size;
        !          2867:                        number = type->msgtl_number;
        !          2868:                        saddr += sizeof(mach_msg_type_long_t);
        !          2869:                } else {
        !          2870:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          2871:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          2872:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          2873:                        saddr += sizeof(mach_msg_type_t);
        !          2874:                }
        !          2875: 
        !          2876:                is_port = MSG_TYPE_PORT_ANY(name);
        !          2877: 
        !          2878:                if (is_port && (size != PORT_T_SIZE_IN_BITS)) {
        !          2879:                        ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          2880:                        return MACH_SEND_INVALID_TYPE;
        !          2881:                }
        !          2882: 
        !          2883:                /*
        !          2884:                 *      New IPC says these should be zero, but old IPC
        !          2885:                 *      tasks often leave them with random values.  So
        !          2886:                 *      we have to clear them.
        !          2887:                 */
        !          2888: 
        !          2889:                ((mach_msg_type_t*)type)->msgt_unused = 0;
        !          2890:                if (longform) {
        !          2891:                        type->msgtl_header.msgt_name = 0;
        !          2892:                        type->msgtl_header.msgt_size = 0;
        !          2893:                        type->msgtl_header.msgt_number = 0;
        !          2894:                }
        !          2895: 
        !          2896:                /* padding (ptrs and ports) ? */
        !          2897:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          2898:                    ((size >> 3) == sizeof(natural_t)))
        !          2899:                        saddr = ptr_align(saddr);
        !          2900: 
        !          2901:                /* calculate length of data in bytes, rounding up */
        !          2902: 
        !          2903:                length = ((number * size) + 7) >> 3;
        !          2904: 
        !          2905:                if (is_inline) {
        !          2906:                        vm_size_t amount;
        !          2907: 
        !          2908:                        /* inline data sizes round up to int boundaries */
        !          2909: 
        !          2910:                        amount = (length + 3) &~ 3;
        !          2911:                        if ((eaddr - saddr) < amount) {
        !          2912:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          2913:                                return MACH_SEND_MSG_TOO_SMALL;
        !          2914:                        }
        !          2915: 
        !          2916:                        data = saddr;
        !          2917:                        saddr += amount;
        !          2918:                } else {
        !          2919:                        vm_offset_t addr;
        !          2920: 
        !          2921:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
        !          2922:                                ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
        !          2923:                                return MACH_SEND_MSG_TOO_SMALL;
        !          2924:                        }
        !          2925: 
        !          2926:                        /* grab the out-of-line data */
        !          2927: 
        !          2928:                        addr = * (vm_offset_t *) saddr;
        !          2929: 
        !          2930:                        if (length == 0)
        !          2931:                                data = 0;
        !          2932:                        else if (is_port) {
        !          2933:                                data = kalloc(length);
        !          2934:                                if (data == 0)
        !          2935:                                        goto invalid_memory;
        !          2936: 
        !          2937:                                if (copyinmap(map, (char *) addr,
        !          2938:                                              (char *) data, length) ||
        !          2939:                                    (dealloc &&
        !          2940:                                     (vm_deallocate(map, addr, length) !=
        !          2941:                                                        KERN_SUCCESS))) {
        !          2942:                                        kfree(data, length);
        !          2943:                                        goto invalid_memory;
        !          2944:                                }
        !          2945:                        } else {
        !          2946:                                vm_map_copy_t copy;
        !          2947: 
        !          2948:                                if (use_page_lists) {
        !          2949:                                        kr = vm_map_copyin_page_list(map,
        !          2950:                                                addr, length, dealloc,
        !          2951:                                                steal_pages, &copy, FALSE);
        !          2952:                                } else {
        !          2953:                                        kr = vm_map_copyin(map, addr, length,
        !          2954:                                                           dealloc,
        !          2955:                                                           &copy);
        !          2956:                                }
        !          2957:                                if (kr != KERN_SUCCESS) {
        !          2958:                                    invalid_memory:
        !          2959:                                        ipc_kmsg_clean_partial(kmsg, taddr,
        !          2960:                                                               FALSE, 0);
        !          2961:                                        return MACH_SEND_INVALID_MEMORY;
        !          2962:                                }
        !          2963: 
        !          2964:                                data = (vm_offset_t) copy;
        !          2965:                        }
        !          2966: 
        !          2967:                        * (vm_offset_t *) saddr = data;
        !          2968:                        saddr += sizeof(vm_offset_t);
        !          2969:                        complex = TRUE;
        !          2970:                }
        !          2971: 
        !          2972:                if (is_port) {
        !          2973:                        mach_msg_type_name_t newname =
        !          2974:                                        ipc_object_copyin_type(name);
        !          2975:                        ipc_object_t *objects = (ipc_object_t *) data;
        !          2976:                        mach_msg_type_number_t i;
        !          2977: 
        !          2978:                        if (longform)
        !          2979:                                type->msgtl_name = newname;
        !          2980:                        else
        !          2981:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          2982: 
        !          2983:                        for (i = 0; i < number; i++) {
        !          2984:                                mach_port_t port = (mach_port_t) objects[i];
        !          2985:                                ipc_object_t object;
        !          2986: 
        !          2987:                                if (!MACH_PORT_VALID(port))
        !          2988:                                        continue;
        !          2989: 
        !          2990:                                kr = ipc_object_copyin_compat(space, port,
        !          2991:                                                name, dealloc, &object);
        !          2992:                                if (kr != KERN_SUCCESS) {
        !          2993:                                        ipc_kmsg_clean_partial(kmsg, taddr,
        !          2994:                                                               TRUE, i);
        !          2995:                                        return MACH_SEND_INVALID_RIGHT;
        !          2996:                                }
        !          2997: 
        !          2998:                                if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
        !          2999:                                    ipc_port_check_circularity(
        !          3000:                                                        (ipc_port_t) object,
        !          3001:                                                        (ipc_port_t) dest))
        !          3002:                                        kmsg->ikm_header.msgh_bits |=
        !          3003:                                                MACH_MSGH_BITS_CIRCULAR;
        !          3004: 
        !          3005:                                objects[i] = object;
        !          3006:                        }
        !          3007: 
        !          3008:                        complex = TRUE;
        !          3009:                }
        !          3010:        }
        !          3011: 
        !          3012:        if (complex)
        !          3013:                kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
        !          3014: 
        !          3015:        return MACH_MSG_SUCCESS;
        !          3016: }
        !          3017: 
        !          3018: /*
        !          3019:  *     Routine:        ipc_kmsg_copyout_compat
        !          3020:  *     Purpose:
        !          3021:  *             "Copy-out" port rights and out-of-line memory
        !          3022:  *             in the message, producing an old IPC message.
        !          3023:  *
        !          3024:  *             Doesn't bother to handle the header atomically.
        !          3025:  *             Skips over errors.  Problem ports produce MACH_PORT_NULL
        !          3026:  *             (MACH_PORT_DEAD is never produced), and problem memory
        !          3027:  *             produces a zero address.
        !          3028:  *     Conditions:
        !          3029:  *             Nothing locked.
        !          3030:  *     Returns:
        !          3031:  *             MACH_MSG_SUCCESS        Copied out rights and memory.
        !          3032:  */
        !          3033: 
        !          3034: mach_msg_return_t
        !          3035: ipc_kmsg_copyout_compat(kmsg, space, map)
        !          3036:        ipc_kmsg_t kmsg;
        !          3037:        ipc_space_t space;
        !          3038:        vm_map_t map;
        !          3039: {
        !          3040:        msg_header_t msg;
        !          3041:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
        !          3042:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
        !          3043:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
        !          3044:        mach_port_t dest_name, reply_name;
        !          3045:        vm_offset_t saddr, eaddr;
        !          3046:        kern_return_t kr;
        !          3047: 
        !          3048:        assert(IO_VALID(dest));
        !          3049: 
        !          3050:        io_lock(dest);
        !          3051:        if (io_active(dest)) {
        !          3052:                mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
        !          3053: 
        !          3054:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
        !          3055:                /* dest is unlocked */
        !          3056:        } else {
        !          3057:                io_release(dest);
        !          3058:                io_check_unlock(dest);
        !          3059:                dest_name = MACH_PORT_NULL;
        !          3060:        }
        !          3061: 
        !          3062:        if (IO_VALID(reply)) {
        !          3063:                mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
        !          3064: 
        !          3065:                kr = ipc_object_copyout_compat(space, reply, reply_type,
        !          3066:                                               &reply_name);
        !          3067:                if (kr != KERN_SUCCESS) {
        !          3068:                        ipc_object_destroy(reply, reply_type);
        !          3069:                        reply_name = MACH_PORT_NULL;
        !          3070:                }
        !          3071:        } else
        !          3072:                reply_name = MACH_PORT_NULL;
        !          3073: 
        !          3074:        msg.msg_unused = 0;
        !          3075:        msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE;
        !          3076:        msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size;
        !          3077:        msg.msg_type = (integer_t) kmsg->ikm_header.msgh_seqno;
        !          3078:        msg.msg_local_port = (port_name_t) dest_name;
        !          3079:        msg.msg_remote_port = (port_name_t) reply_name;
        !          3080:        msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id;
        !          3081:        * (msg_header_t *) &kmsg->ikm_header = msg;
        !          3082: 
        !          3083:        if (msg.msg_simple)
        !          3084:                return MACH_MSG_SUCCESS;
        !          3085: 
        !          3086:        saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
        !          3087:        eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
        !          3088: 
        !          3089:        while (saddr < eaddr) {
        !          3090:                vm_offset_t taddr = saddr;
        !          3091:                mach_msg_type_long_t *type;
        !          3092:                mach_msg_type_name_t name;
        !          3093:                mach_msg_type_size_t size;
        !          3094:                mach_msg_type_number_t number;
        !          3095:                boolean_t is_inline, longform, is_port;
        !          3096:                vm_size_t length;
        !          3097:                vm_offset_t addr;
        !          3098: 
        !          3099:                type = (mach_msg_type_long_t *) saddr;
        !          3100:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          3101:                longform = ((mach_msg_type_t*)type)->msgt_longform;
        !          3102:                if (longform) {
        !          3103:                        /* This must be aligned */
        !          3104:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3105:                            (is_misaligned(type))) {
        !          3106:                                saddr = ptr_align(saddr);
        !          3107:                                continue;
        !          3108:                        }
        !          3109:                        name = type->msgtl_name;
        !          3110:                        size = type->msgtl_size;
        !          3111:                        number = type->msgtl_number;
        !          3112:                        saddr += sizeof(mach_msg_type_long_t);
        !          3113:                } else {
        !          3114:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          3115:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          3116:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          3117:                        saddr += sizeof(mach_msg_type_t);
        !          3118:                }
        !          3119: 
        !          3120:                /* padding (ptrs and ports) ? */
        !          3121:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3122:                    ((size >> 3) == sizeof(natural_t)))
        !          3123:                        saddr = ptr_align(saddr);
        !          3124: 
        !          3125:                /* calculate length of data in bytes, rounding up */
        !          3126: 
        !          3127:                length = ((number * size) + 7) >> 3;
        !          3128: 
        !          3129:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          3130: 
        !          3131:                if (is_port) {
        !          3132:                        mach_port_t *objects;
        !          3133:                        mach_msg_type_number_t i;
        !          3134:                        mach_msg_type_name_t newname;
        !          3135: 
        !          3136:                        if (!is_inline && (length != 0)) {
        !          3137:                                /* first allocate memory in the map */
        !          3138: 
        !          3139:                                kr = vm_allocate(map, &addr, length, TRUE);
        !          3140:                                if (kr != KERN_SUCCESS) {
        !          3141:                                        ipc_kmsg_clean_body(taddr, saddr);
        !          3142:                                        goto vm_copyout_failure;
        !          3143:                                }
        !          3144:                        }
        !          3145: 
        !          3146:                        newname = ipc_object_copyout_type_compat(name);
        !          3147:                        if (longform)
        !          3148:                                type->msgtl_name = newname;
        !          3149:                        else
        !          3150:                                ((mach_msg_type_t*)type)->msgt_name = newname;
        !          3151: 
        !          3152:                        objects = (mach_port_t *)
        !          3153:                                (is_inline ? saddr : * (vm_offset_t *) saddr);
        !          3154: 
        !          3155:                        /* copyout port rights carried in the message */
        !          3156: 
        !          3157:                        for (i = 0; i < number; i++) {
        !          3158:                                ipc_object_t object =
        !          3159:                                        (ipc_object_t) objects[i];
        !          3160: 
        !          3161:                                if (!IO_VALID(object)) {
        !          3162:                                        objects[i] = MACH_PORT_NULL;
        !          3163:                                        continue;
        !          3164:                                }
        !          3165: 
        !          3166:                                kr = ipc_object_copyout_compat(space, object,
        !          3167:                                                        name, &objects[i]);
        !          3168:                                if (kr != KERN_SUCCESS) {
        !          3169:                                        ipc_object_destroy(object, name);
        !          3170:                                        objects[i] = MACH_PORT_NULL;
        !          3171:                                }
        !          3172:                        }
        !          3173:                }
        !          3174: 
        !          3175:                if (is_inline) {
        !          3176:                        /* inline data sizes round up to int boundaries */
        !          3177: 
        !          3178:                        saddr += (length + 3) &~ 3;
        !          3179:                } else {
        !          3180:                        vm_offset_t data = * (vm_offset_t *) saddr;
        !          3181: 
        !          3182:                        /* copyout memory carried in the message */
        !          3183: 
        !          3184:                        if (length == 0) {
        !          3185:                                assert(data == 0);
        !          3186:                                addr = 0;
        !          3187:                        } else if (is_port) {
        !          3188:                                /* copyout to memory allocated above */
        !          3189: 
        !          3190:                                (void) copyoutmap(map, (char *) data,
        !          3191:                                                  (char *) addr, length);
        !          3192:                                kfree(data, length);
        !          3193:                        } else {
        !          3194:                                vm_map_copy_t copy = (vm_map_copy_t) data;
        !          3195: 
        !          3196:                                kr = vm_map_copyout(map, &addr, copy);
        !          3197:                                if (kr != KERN_SUCCESS) {
        !          3198:                                        vm_map_copy_discard(copy);
        !          3199: 
        !          3200:                                    vm_copyout_failure:
        !          3201: 
        !          3202:                                        addr = 0;
        !          3203:                                }
        !          3204:                        }
        !          3205: 
        !          3206:                        * (vm_offset_t *) saddr = addr;
        !          3207:                        saddr += sizeof(vm_offset_t);
        !          3208:                }
        !          3209:        }
        !          3210: 
        !          3211:        return MACH_MSG_SUCCESS;
        !          3212: }
        !          3213: 
        !          3214: #endif /* MACH_IPC_COMPAT */
        !          3215: 
        !          3216: #include <mach_kdb.h>
        !          3217: #if    MACH_KDB
        !          3218: 
        !          3219: char *
        !          3220: ipc_type_name(type_name, received)
        !          3221:        int type_name;
        !          3222:        boolean_t received;
        !          3223: {
        !          3224:        switch (type_name) {
        !          3225:                case MACH_MSG_TYPE_BOOLEAN:
        !          3226:                return "boolean";
        !          3227: 
        !          3228:                case MACH_MSG_TYPE_INTEGER_16:
        !          3229:                return "short";
        !          3230: 
        !          3231:                case MACH_MSG_TYPE_INTEGER_32:
        !          3232:                return "int32";
        !          3233: 
        !          3234:                case MACH_MSG_TYPE_INTEGER_64:
        !          3235:                return "int64";
        !          3236: 
        !          3237:                case MACH_MSG_TYPE_CHAR:
        !          3238:                return "char";
        !          3239: 
        !          3240:                case MACH_MSG_TYPE_BYTE:
        !          3241:                return "byte";
        !          3242: 
        !          3243:                case MACH_MSG_TYPE_REAL:
        !          3244:                return "real";
        !          3245: 
        !          3246:                case MACH_MSG_TYPE_STRING:
        !          3247:                return "string";
        !          3248: 
        !          3249:                case MACH_MSG_TYPE_PORT_NAME:
        !          3250:                return "port_name";
        !          3251: 
        !          3252:                case MACH_MSG_TYPE_MOVE_RECEIVE:
        !          3253:                if (received) {
        !          3254:                        return "port_receive";
        !          3255:                } else {
        !          3256:                        return "move_receive";
        !          3257:                }
        !          3258: 
        !          3259:                case MACH_MSG_TYPE_MOVE_SEND:
        !          3260:                if (received) {
        !          3261:                        return "port_send";
        !          3262:                } else {
        !          3263:                        return "move_send";
        !          3264:                }
        !          3265: 
        !          3266:                case MACH_MSG_TYPE_MOVE_SEND_ONCE:
        !          3267:                if (received) {
        !          3268:                        return "port_send_once";
        !          3269:                } else {
        !          3270:                        return "move_send_once";
        !          3271:                }
        !          3272: 
        !          3273:                case MACH_MSG_TYPE_COPY_SEND:
        !          3274:                return "copy_send";
        !          3275: 
        !          3276:                case MACH_MSG_TYPE_MAKE_SEND:
        !          3277:                return "make_send";
        !          3278: 
        !          3279:                case MACH_MSG_TYPE_MAKE_SEND_ONCE:
        !          3280:                return "make_send_once";
        !          3281: 
        !          3282:                default:
        !          3283:                return (char *) 0;
        !          3284:        }
        !          3285: }
        !          3286: 
        !          3287: void
        !          3288: ipc_print_type_name(
        !          3289:        int     type_name)
        !          3290: {
        !          3291:        char *name = ipc_type_name(type_name, TRUE);
        !          3292:        if (name) {
        !          3293:                printf("%s", name);
        !          3294:        } else {
        !          3295:                printf("type%d", type_name);
        !          3296:        }
        !          3297: }
        !          3298: 
        !          3299: /*
        !          3300:  * ipc_kmsg_print      [ debug ]
        !          3301:  */
        !          3302: void
        !          3303: ipc_kmsg_print(kmsg)
        !          3304:        ipc_kmsg_t kmsg;
        !          3305: {
        !          3306:        db_printf("kmsg=0x%x\n", kmsg);
        !          3307:        db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
        !          3308:                  kmsg->ikm_next,
        !          3309:                  kmsg->ikm_prev,
        !          3310:                  kmsg->ikm_size,
        !          3311:                  kmsg->ikm_marequest);
        !          3312: #if    NORMA_IPC
        !          3313:        db_printf(",page=0x%x,copy=0x%x\n",
        !          3314:                  kmsg->ikm_page,
        !          3315:                  kmsg->ikm_copy);
        !          3316: #else  /* NORMA_IPC */
        !          3317:        db_printf("\n");
        !          3318: #endif /* NORMA_IPC */
        !          3319:        ipc_msg_print(&kmsg->ikm_header);
        !          3320: }
        !          3321: 
        !          3322: /*
        !          3323:  * ipc_msg_print       [ debug ]
        !          3324:  */
        !          3325: void
        !          3326: ipc_msg_print(msgh)
        !          3327:        mach_msg_header_t *msgh;
        !          3328: {
        !          3329:        vm_offset_t saddr, eaddr;
        !          3330: 
        !          3331:        db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
        !          3332:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
        !          3333:                db_printf("complex,");
        !          3334:        }
        !          3335:        if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
        !          3336:                db_printf("circular,");
        !          3337:        }
        !          3338:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
        !          3339:                db_printf("complex_ports,");
        !          3340:        }
        !          3341:        if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
        !          3342:                db_printf("complex_data,");
        !          3343:        }
        !          3344:        if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
        !          3345:                db_printf("migrated,");
        !          3346:        }
        !          3347:        if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
        !          3348:                db_printf("unused=0x%x,",
        !          3349:                          msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
        !          3350:        }
        !          3351:        db_printf("l=0x%x,r=0x%x\n",
        !          3352:                  MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
        !          3353:                  MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
        !          3354: 
        !          3355:        db_printf("msgh_id=%d,size=%d,seqno=%d,",
        !          3356:                  msgh->msgh_id,
        !          3357:                  msgh->msgh_size,
        !          3358:                  msgh->msgh_seqno);
        !          3359: 
        !          3360:        if (msgh->msgh_remote_port) {
        !          3361:                db_printf("remote=0x%x(", msgh->msgh_remote_port);
        !          3362:                ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
        !          3363:                db_printf("),");
        !          3364:        } else {
        !          3365:                db_printf("remote=null,\n");
        !          3366:        }
        !          3367: 
        !          3368:        if (msgh->msgh_local_port) {
        !          3369:                db_printf("local=0x%x(", msgh->msgh_local_port);
        !          3370:                ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
        !          3371:                db_printf(")\n");
        !          3372:        } else {
        !          3373:                db_printf("local=null\n");
        !          3374:        }
        !          3375: 
        !          3376:        saddr = (vm_offset_t) (msgh + 1);
        !          3377:        eaddr = (vm_offset_t) msgh + msgh->msgh_size;
        !          3378: 
        !          3379:        while (saddr < eaddr) {
        !          3380:                mach_msg_type_long_t *type;
        !          3381:                mach_msg_type_name_t name;
        !          3382:                mach_msg_type_size_t size;
        !          3383:                mach_msg_type_number_t number;
        !          3384:                boolean_t is_inline, longform, dealloc, is_port;
        !          3385:                vm_size_t length;
        !          3386: 
        !          3387:                type = (mach_msg_type_long_t *) saddr;
        !          3388: 
        !          3389:                if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
        !          3390:                    ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
        !          3391:                     ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
        !          3392:                        db_printf("*** msg too small\n");
        !          3393:                        return;
        !          3394:                }
        !          3395: 
        !          3396:                is_inline = ((mach_msg_type_t*)type)->msgt_inline;
        !          3397:                dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
        !          3398:                if (longform) {
        !          3399:                        /* This must be aligned */
        !          3400:                        if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3401:                            (is_misaligned(type))) {
        !          3402:                                saddr = ptr_align(saddr);
        !          3403:                                continue;
        !          3404:                        }
        !          3405:                        name = type->msgtl_name;
        !          3406:                        size = type->msgtl_size;
        !          3407:                        number = type->msgtl_number;
        !          3408:                        saddr += sizeof(mach_msg_type_long_t);
        !          3409:                } else {
        !          3410:                        name = ((mach_msg_type_t*)type)->msgt_name;
        !          3411:                        size = ((mach_msg_type_t*)type)->msgt_size;
        !          3412:                        number = ((mach_msg_type_t*)type)->msgt_number;
        !          3413:                        saddr += sizeof(mach_msg_type_t);
        !          3414:                }
        !          3415: 
        !          3416:                db_printf("-- type=");
        !          3417:                ipc_print_type_name(name);
        !          3418:                if (! is_inline) {
        !          3419:                        db_printf(",ool");
        !          3420:                }
        !          3421:                if (dealloc) {
        !          3422:                        db_printf(",dealloc");
        !          3423:                }
        !          3424:                if (longform) {
        !          3425:                        db_printf(",longform");
        !          3426:                }
        !          3427:                db_printf(",size=%d,number=%d,addr=0x%x\n",
        !          3428:                       size,
        !          3429:                       number,
        !          3430:                       saddr);
        !          3431: 
        !          3432:                is_port = MACH_MSG_TYPE_PORT_ANY(name);
        !          3433: 
        !          3434:                if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
        !          3435:                    (longform && ((type->msgtl_header.msgt_name != 0) ||
        !          3436:                                  (type->msgtl_header.msgt_size != 0) ||
        !          3437:                                  (type->msgtl_header.msgt_number != 0))) ||
        !          3438:                    (((mach_msg_type_t*)type)->msgt_unused != 0) ||
        !          3439:                    (dealloc && is_inline)) {
        !          3440:                        db_printf("*** invalid type\n");
        !          3441:                        return;
        !          3442:                }
        !          3443: 
        !          3444:                /* padding (ptrs and ports) ? */
        !          3445:                if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
        !          3446:                    ((size >> 3) == sizeof(natural_t)))
        !          3447:                        saddr = ptr_align(saddr);
        !          3448: 
        !          3449:                /* calculate length of data in bytes, rounding up */
        !          3450: 
        !          3451:                length = ((number * size) + 7) >> 3;
        !          3452: 
        !          3453:                if (is_inline) {
        !          3454:                        vm_size_t amount;
        !          3455:                        int i, numwords;
        !          3456: 
        !          3457:                        /* inline data sizes round up to int boundaries */
        !          3458:                        amount = (length + 3) &~ 3;
        !          3459:                        if ((eaddr - saddr) < amount) {
        !          3460:                                db_printf("*** too small\n");
        !          3461:                                return;
        !          3462:                        }
        !          3463:                        numwords = amount / sizeof(int);
        !          3464:                        if (numwords > 8) {
        !          3465:                                numwords = 8;
        !          3466:                        }
        !          3467:                        for (i = 0; i < numwords; i++) {
        !          3468:                                db_printf("0x%x\n", ((int *) saddr)[i]);
        !          3469:                        }
        !          3470:                        if (numwords < amount / sizeof(int)) {
        !          3471:                                db_printf("...\n");
        !          3472:                        }
        !          3473:                        saddr += amount;
        !          3474:                } else {
        !          3475:                        if ((eaddr - saddr) < sizeof(vm_offset_t)) {
        !          3476:                                db_printf("*** too small\n");
        !          3477:                                return;
        !          3478:                        }
        !          3479:                        db_printf("0x%x\n", * (vm_offset_t *) saddr);
        !          3480:                        saddr += sizeof(vm_offset_t);
        !          3481:                }
        !          3482:        }
        !          3483: }
        !          3484: #endif /* MACH_KDB */

unix.superglobalmegacorp.com

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