Annotation of Gnu-Mach/ipc/ipc_kmsg.c, revision 1.1.1.3

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