Annotation of OSKit-Mach/ipc/ipc_kmsg.c, revision 1.1.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.