Annotation of XNU/osfmk/ipc/ipc_kmsg.c, revision 1.1.1.1

1.1       root        1: /*
                      2:  * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
                      3:  *
                      4:  * @APPLE_LICENSE_HEADER_START@
                      5:  * 
                      6:  * The contents of this file constitute Original Code as defined in and
                      7:  * are subject to the Apple Public Source License Version 1.1 (the
                      8:  * "License").  You may not use this file except in compliance with the
                      9:  * License.  Please obtain a copy of the License at
                     10:  * http://www.apple.com/publicsource and read it before using this file.
                     11:  * 
                     12:  * This Original Code and all software distributed under the License are
                     13:  * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
                     14:  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
                     15:  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
                     16:  * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT.  Please see the
                     17:  * License for the specific language governing rights and limitations
                     18:  * under the License.
                     19:  * 
                     20:  * @APPLE_LICENSE_HEADER_END@
                     21:  */
                     22: /*
                     23:  * @OSF_COPYRIGHT@
                     24:  */
                     25: /* 
                     26:  * Mach Operating System
                     27:  * Copyright (c) 1991,1990,1989 Carnegie Mellon University
                     28:  * All Rights Reserved.
                     29:  * 
                     30:  * Permission to use, copy, modify and distribute this software and its
                     31:  * documentation is hereby granted, provided that both the copyright
                     32:  * notice and this permission notice appear in all copies of the
                     33:  * software, derivative works or modified versions, and any portions
                     34:  * thereof, and that both notices appear in supporting documentation.
                     35:  * 
                     36:  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
                     37:  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
                     38:  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
                     39:  * 
                     40:  * Carnegie Mellon requests users of this software to return to
                     41:  * 
                     42:  *  Software Distribution Coordinator  or  [email protected]
                     43:  *  School of Computer Science
                     44:  *  Carnegie Mellon University
                     45:  *  Pittsburgh PA 15213-3890
                     46:  * 
                     47:  * any improvements or extensions that they make and grant Carnegie Mellon
                     48:  * the rights to redistribute these changes.
                     49:  */
                     50: /*
                     51:  */
                     52: /*
                     53:  *     File:   ipc/ipc_kmsg.c
                     54:  *     Author: Rich Draves
                     55:  *     Date:   1989
                     56:  *
                     57:  *     Operations on kernel messages.
                     58:  */
                     59: 
                     60: #include <cpus.h>
                     61: #include <dipc.h>
                     62: #include <mach_rt.h>
                     63: #include <norma_vm.h>
                     64: 
                     65: #include <mach/boolean.h>
                     66: #include <mach/kern_return.h>
                     67: #include <mach/message.h>
                     68: #include <mach/port.h>
                     69: #include <kern/assert.h>
                     70: #include <kern/kalloc.h>
                     71: #include <kern/thread.h>
                     72: #include <kern/sched_prim.h>
                     73: #if    MACH_RT
                     74: #include <kern/rtmalloc.h>
                     75: #endif /* MACH_RT */
                     76: #include <kern/spl.h>
                     77: #include <kern/misc_protos.h>
                     78: #include <kern/counters.h>
                     79: #include <vm/vm_map.h>
                     80: #include <vm/vm_object.h>
                     81: #include <vm/vm_kern.h>
                     82: #include <ipc/port.h>
                     83: #include <ipc/ipc_entry.h>
                     84: #include <ipc/ipc_kmsg.h>
                     85: #include <ipc/ipc_notify.h>
                     86: #include <ipc/ipc_object.h>
                     87: #include <ipc/ipc_space.h>
                     88: #include <ipc/ipc_port.h>
                     89: #include <ipc/ipc_right.h>
                     90: #include <ipc/ipc_hash.h>
                     91: #include <ipc/ipc_table.h>
                     92: 
                     93: #include <string.h>
                     94: 
                     95: extern vm_map_t                ipc_kernel_copy_map;
                     96: extern vm_size_t       ipc_kmsg_max_vm_space;
                     97: extern vm_size_t       msg_ool_size_small;
                     98: 
                     99: #if    MACH_RT
                    100: extern vm_size_t       msg_ool_size_small_rt;
                    101: #define MSG_OOL_SIZE_SMALL(rt) ((rt) ? msg_ool_size_small_rt : \
                    102:                                        msg_ool_size_small)
                    103: #else  /* MACH_RT */
                    104: #define MSG_OOL_SIZE_SMALL(rt) msg_ool_size_small
                    105: #endif /* MACH_RT */
                    106: 
                    107: 
                    108: /*
                    109:  * Forward declarations
                    110:  */
                    111: 
                    112: void ipc_kmsg_clean(
                    113:        ipc_kmsg_t      kmsg);
                    114: 
                    115: void ipc_kmsg_clean_body(
                    116:        ipc_kmsg_t      kmsg,
                    117:        mach_msg_type_number_t  number);
                    118: 
                    119: void ipc_kmsg_clean_partial(
                    120:        ipc_kmsg_t              kmsg,
                    121:        mach_msg_type_number_t  number,
                    122:        vm_offset_t             paddr,
                    123:        vm_size_t               length);
                    124: 
                    125: mach_msg_return_t ipc_kmsg_copyout_body(
                    126:        ipc_kmsg_t              kmsg,
                    127:        ipc_space_t             space,
                    128:        vm_map_t                map,
                    129:        mach_msg_body_t         *slist);
                    130: 
                    131: mach_msg_return_t ipc_kmsg_copyin_body(
                    132:        ipc_kmsg_t              kmsg,
                    133:        ipc_space_t             space,
                    134:        vm_map_t                map);
                    135: 
                    136: void ikm_cache_init(void);
                    137: 
                    138: 
                    139: /*
                    140:  *     Routine:        ipc_kmsg_enqueue
                    141:  *     Purpose:
                    142:  *             Enqueue a kmsg.
                    143:  */
                    144: 
                    145: void
                    146: ipc_kmsg_enqueue(
                    147:        ipc_kmsg_queue_t        queue,
                    148:        ipc_kmsg_t              kmsg)
                    149: {
                    150:        ipc_kmsg_enqueue_macro(queue, kmsg);
                    151: }
                    152: 
                    153: /*
                    154:  *     Routine:        ipc_kmsg_dequeue
                    155:  *     Purpose:
                    156:  *             Dequeue and return a kmsg.
                    157:  */
                    158: 
                    159: ipc_kmsg_t
                    160: ipc_kmsg_dequeue(
                    161:        ipc_kmsg_queue_t        queue)
                    162: {
                    163:        ipc_kmsg_t first;
                    164: 
                    165:        first = ipc_kmsg_queue_first(queue);
                    166: 
                    167:        if (first != IKM_NULL)
                    168:                ipc_kmsg_rmqueue_first_macro(queue, first);
                    169: 
                    170:        return first;
                    171: }
                    172: 
                    173: /*
                    174:  *     Routine:        ipc_kmsg_rmqueue
                    175:  *     Purpose:
                    176:  *             Pull a kmsg out of a queue.
                    177:  */
                    178: 
                    179: void
                    180: ipc_kmsg_rmqueue(
                    181:        ipc_kmsg_queue_t        queue,
                    182:        ipc_kmsg_t              kmsg)
                    183: {
                    184:        ipc_kmsg_t next, prev;
                    185: 
                    186:        assert(queue->ikmq_base != IKM_NULL);
                    187: 
                    188:        next = kmsg->ikm_next;
                    189:        prev = kmsg->ikm_prev;
                    190: 
                    191:        if (next == kmsg) {
                    192:                assert(prev == kmsg);
                    193:                assert(queue->ikmq_base == kmsg);
                    194: 
                    195:                queue->ikmq_base = IKM_NULL;
                    196:        } else {
                    197:                if (queue->ikmq_base == kmsg)
                    198:                        queue->ikmq_base = next;
                    199: 
                    200:                next->ikm_prev = prev;
                    201:                prev->ikm_next = next;
                    202:        }
                    203:        /* XXX Temporary debug logic */
                    204:        kmsg->ikm_next = IKM_BOGUS;
                    205:        kmsg->ikm_prev = IKM_BOGUS;
                    206: }
                    207: 
                    208: /*
                    209:  *     Routine:        ipc_kmsg_queue_next
                    210:  *     Purpose:
                    211:  *             Return the kmsg following the given kmsg.
                    212:  *             (Or IKM_NULL if it is the last one in the queue.)
                    213:  */
                    214: 
                    215: ipc_kmsg_t
                    216: ipc_kmsg_queue_next(
                    217:        ipc_kmsg_queue_t        queue,
                    218:        ipc_kmsg_t              kmsg)
                    219: {
                    220:        ipc_kmsg_t next;
                    221: 
                    222:        assert(queue->ikmq_base != IKM_NULL);
                    223: 
                    224:        next = kmsg->ikm_next;
                    225:        if (queue->ikmq_base == next)
                    226:                next = IKM_NULL;
                    227: 
                    228:        return next;
                    229: }
                    230: 
                    231: /*
                    232:  *     Routine:        ipc_kmsg_destroy
                    233:  *     Purpose:
                    234:  *             Destroys a kernel message.  Releases all rights,
                    235:  *             references, and memory held by the message.
                    236:  *             Frees the message.
                    237:  *     Conditions:
                    238:  *             No locks held.
                    239:  */
                    240: 
                    241: void
                    242: ipc_kmsg_destroy(
                    243:        ipc_kmsg_t      kmsg)
                    244: {
                    245:        ipc_kmsg_queue_t queue;
                    246:        boolean_t empty;
                    247: 
                    248:        /*
                    249:         *      ipc_kmsg_clean can cause more messages to be destroyed.
                    250:         *      Curtail recursion by queueing messages.  If a message
                    251:         *      is already queued, then this is a recursive call.
                    252:         */
                    253: 
                    254:        queue = &(current_thread()->ith_messages);
                    255:        empty = ipc_kmsg_queue_empty(queue);
                    256:        ipc_kmsg_enqueue(queue, kmsg);
                    257: 
                    258:        if (empty) {
                    259:                /* must leave kmsg in queue while cleaning it */
                    260: 
                    261:                while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
                    262:                        ipc_kmsg_clean(kmsg);
                    263:                        ipc_kmsg_rmqueue(queue, kmsg);
                    264:                        ikm_free(kmsg);
                    265:                }
                    266:        }
                    267: }
                    268: 
                    269: /*
                    270:  *     Routine:        ipc_kmsg_destroy_dest
                    271:  *     Purpose:
                    272:  *             Destroys a kernel message.  Releases all rights,
                    273:  *             references, and memory held by the message (including
                    274:  *             the destination port reference.
                    275:  *             Frees the message.
                    276:  *     Conditions:
                    277:  *             No locks held.
                    278:  */
                    279: 
                    280: ipc_kmsg_destroy_dest(
                    281:        ipc_kmsg_t kmsg)
                    282: {
                    283:     ipc_port_t port;
                    284:        
                    285:     port = kmsg->ikm_header.msgh_remote_port;
                    286: 
                    287:     ipc_port_release(port);
                    288:     kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    289:     ipc_kmsg_destroy(kmsg);
                    290: }
                    291: 
                    292: /*
                    293:  *     Routine:        ipc_kmsg_clean_body
                    294:  *     Purpose:
                    295:  *             Cleans the body of a kernel message.
                    296:  *             Releases all rights, references, and memory.
                    297:  *
                    298:  *     Conditions:
                    299:  *             No locks held.
                    300:  */
                    301: 
                    302: void
                    303: ipc_kmsg_clean_body(
                    304:        ipc_kmsg_t      kmsg,
                    305:        mach_msg_type_number_t  number)
                    306: {
                    307:     mach_msg_descriptor_t      *saddr, *eaddr;
                    308:     boolean_t                  rt;
                    309: 
                    310:     if ( number == 0 )
                    311:        return;
                    312: 
                    313:     rt = KMSG_IS_RT(kmsg);
                    314:     saddr = (mach_msg_descriptor_t *) 
                    315:                        ((mach_msg_base_t *) &kmsg->ikm_header + 1);
                    316:     eaddr = saddr + number;
                    317: 
                    318:     for ( ; saddr < eaddr; saddr++ ) {
                    319:        
                    320:        switch (saddr->type.type) {
                    321:            
                    322:            case MACH_MSG_PORT_DESCRIPTOR: {
                    323:                mach_msg_port_descriptor_t *dsc;
                    324: 
                    325:                dsc = &saddr->port;
                    326: 
                    327:                /* 
                    328:                 * Destroy port rights carried in the message 
                    329:                 */
                    330:                if (!IO_VALID((ipc_object_t) dsc->name))
                    331:                    continue;
                    332:                ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
                    333:                break;
                    334:            }
                    335:            case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
                    336:            case MACH_MSG_OOL_DESCRIPTOR : {
                    337:                mach_msg_ool_descriptor_t *dsc;
                    338: 
                    339:                dsc = &saddr->out_of_line;
                    340:                
                    341:                /* 
                    342:                 * Destroy memory carried in the message 
                    343:                 */
                    344:                if (dsc->size == 0) {
                    345:                    assert(dsc->address == (void *) 0);
                    346:                } else {
                    347:                    if (dsc->copy == MACH_MSG_PHYSICAL_COPY &&
                    348:                            dsc->size < MSG_OOL_SIZE_SMALL(rt)) {
                    349:                            KFREE((vm_offset_t)dsc->address,
                    350:                                  (vm_size_t)dsc->size,
                    351:                                  rt);
                    352:                    } else {
                    353:                        vm_map_copy_discard((vm_map_copy_t) dsc->address);
                    354:                    }
                    355:                }
                    356:                break;
                    357:            }
                    358:            case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
                    359:                ipc_object_t                    *objects;
                    360:                mach_msg_type_number_t          j;
                    361:                mach_msg_ool_ports_descriptor_t *dsc;
                    362: 
                    363:                dsc = &saddr->ool_ports;
                    364:                objects = (ipc_object_t *) dsc->address;
                    365: 
                    366:                if (dsc->count == 0) {
                    367:                        break;
                    368:                }
                    369: 
                    370:                assert(objects != (ipc_object_t *) 0);
                    371:                
                    372:                /* destroy port rights carried in the message */
                    373:                
                    374:                for (j = 0; j < dsc->count; j++) {
                    375:                    ipc_object_t object = objects[j];
                    376:                    
                    377:                    if (!IO_VALID(object))
                    378:                        continue;
                    379:                    
                    380:                    ipc_object_destroy(object, dsc->disposition);
                    381:                }
                    382: 
                    383:                /* destroy memory carried in the message */
                    384: 
                    385:                assert(dsc->count != 0);
                    386: 
                    387:                KFREE((vm_offset_t) dsc->address, 
                    388:                     (vm_size_t) dsc->count * sizeof(mach_port_name_t),
                    389:                     rt);
                    390:                break;
                    391:            }
                    392:            default : {
                    393:                printf("cleanup: don't understand this type of descriptor\n");
                    394:            }
                    395:        }
                    396:     }
                    397: }
                    398: 
                    399: /*
                    400:  *     Routine:        ipc_kmsg_clean_partial
                    401:  *     Purpose:
                    402:  *             Cleans a partially-acquired kernel message.
                    403:  *             number is the index of the type descriptor
                    404:  *             in the body of the message that contained the error.
                    405:  *             If dolast, the memory and port rights in this last
                    406:  *             type spec are also cleaned.  In that case, number
                    407:  *             specifies the number of port rights to clean.
                    408:  *     Conditions:
                    409:  *             Nothing locked.
                    410:  */
                    411: 
                    412: void
                    413: ipc_kmsg_clean_partial(
                    414:        ipc_kmsg_t              kmsg,
                    415:        mach_msg_type_number_t  number,
                    416:        vm_offset_t             paddr,
                    417:        vm_size_t               length)
                    418: {
                    419:        ipc_object_t object;
                    420:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                    421: 
                    422:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                    423:        assert(IO_VALID(object));
                    424:        ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
                    425: 
                    426:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                    427:        if (IO_VALID(object))
                    428:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
                    429: 
                    430:        if (paddr) {
                    431:                (void) vm_deallocate(ipc_kernel_copy_map, paddr, length);
                    432:        }
                    433: 
                    434:        ipc_kmsg_clean_body(kmsg, number);
                    435: }
                    436: 
                    437: /*
                    438:  *     Routine:        ipc_kmsg_clean
                    439:  *     Purpose:
                    440:  *             Cleans a kernel message.  Releases all rights,
                    441:  *             references, and memory held by the message.
                    442:  *     Conditions:
                    443:  *             No locks held.
                    444:  */
                    445: 
                    446: void
                    447: ipc_kmsg_clean(
                    448:        ipc_kmsg_t      kmsg)
                    449: {
                    450:        ipc_object_t object;
                    451:        mach_msg_bits_t mbits;
                    452: 
                    453:        mbits = kmsg->ikm_header.msgh_bits;
                    454:        object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                    455:        if (IO_VALID(object))
                    456:                ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
                    457: 
                    458:        object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                    459:        if (IO_VALID(object))
                    460:                ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
                    461: 
                    462:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                    463:                mach_msg_body_t *body;
                    464: 
                    465:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                    466:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
                    467:        }
                    468: }
                    469: 
                    470: /*
                    471:  *     Routine:        ipc_kmsg_free
                    472:  *     Purpose:
                    473:  *             Free a kernel message buffer.
                    474:  *     Conditions:
                    475:  *             Nothing locked.
                    476:  */
                    477: 
                    478: void
                    479: ipc_kmsg_free(
                    480:        ipc_kmsg_t      kmsg)
                    481: {
                    482:        vm_size_t size = kmsg->ikm_size;
                    483: 
                    484:        if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE ||
                    485:            KMSG_IS_RT(kmsg) ||
                    486:            !ikm_cache_put(kmsg))
                    487:            KFREE((vm_offset_t) kmsg, size, KMSG_IS_RT(kmsg));
                    488: }
                    489: 
                    490: /*
                    491:  *     Routine:        ipc_kmsg_get
                    492:  *     Purpose:
                    493:  *             Allocates a kernel message buffer.
                    494:  *             Copies a user message to the message buffer.
                    495:  *     Conditions:
                    496:  *             Nothing locked.
                    497:  *     Returns:
                    498:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
                    499:  *             MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
                    500:  *             MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
                    501:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
                    502:  *             MACH_SEND_INVALID_DATA  Couldn't copy message data.
                    503:  */
                    504: 
                    505: mach_msg_return_t
                    506: ipc_kmsg_get(
                    507:        mach_msg_header_t       *msg,
                    508:        mach_msg_size_t         size,
                    509:        ipc_kmsg_t              *kmsgp,
                    510:        ipc_space_t             space)
                    511: {
                    512:        mach_msg_size_t                 msg_and_trailer_size;
                    513:        ipc_kmsg_t                      kmsg;
                    514:        mach_msg_format_0_trailer_t     *trailer;
                    515:        mach_port_name_t                dest_name;
                    516:        ipc_entry_t                     dest_entry;
                    517:        ipc_port_t                      dest_port;
                    518: #if    MACH_RT
                    519:        boolean_t                       rt = FALSE;
                    520: #endif /* MACH_RT */
                    521: 
                    522:        if ((size < sizeof(mach_msg_header_t)) || (size & 3))
                    523:                return MACH_SEND_MSG_TOO_SMALL;
                    524: 
                    525: #if 0 /* used to be MACH_RT */
                    526:        /*
                    527:         * JMM - We don't do this now, let's not pay the price
                    528:         */
                    529:        /*
                    530:         * Copyin just the destination mach_port_name_t
                    531:         */
                    532:        if (copyinmsg((char *) &msg->msgh_remote_port,
                    533:                      (char *) &dest_name,
                    534:                      sizeof(mach_port_name_t))) {
                    535:                return MACH_SEND_INVALID_DATA;
                    536:        }
                    537:        
                    538:        /*
                    539:         * Validate the space
                    540:         */
                    541:        is_write_lock(space);
                    542:        if (!space->is_active) {
                    543:          is_write_unlock(space);
                    544:          return MACH_SEND_INVALID_DEST;
                    545:        }
                    546:        
                    547:        /*
                    548:         * Lookup and validate the entry
                    549:         */
                    550:        dest_entry = ipc_entry_lookup(space, dest_name);
                    551:        if (dest_entry == IE_NULL) {
                    552:          is_write_unlock(space);
                    553:          return MACH_SEND_INVALID_DEST;
                    554:         }
                    555: 
                    556:        /*
                    557:         * Extract the port and check whether it is an RT port
                    558:         */
                    559:        dest_port = (ipc_port_t) dest_entry->ie_object;
                    560:        if (dest_port == IP_NULL) {
                    561:          is_write_unlock(space);
                    562:          return MACH_SEND_INVALID_DEST;
                    563:         }
                    564:          
                    565:        rt = IP_RT(dest_port);
                    566:        is_write_unlock(space);
                    567: #endif /* 0 used to be MACH_RT */
                    568: 
                    569:        msg_and_trailer_size = size + MAX_TRAILER_SIZE;
                    570: 
                    571:        if (msg_and_trailer_size <= IKM_SAVED_MSG_SIZE) {
                    572:                if (
                    573: #if    MACH_RT
                    574:                    (!rt) &&
                    575: #endif /* MACH_RT */
                    576:                    ikm_cache_get(&kmsg)) {
                    577:                        ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
                    578:                } else {
                    579: #if    MACH_RT
                    580:                        if (rt)
                    581:                                kmsg = ikm_rtalloc(IKM_SAVED_MSG_SIZE);
                    582:                        else
                    583: #endif /* MACH_RT */
                    584:                                kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
                    585:                        if (kmsg == IKM_NULL)
                    586:                                return MACH_SEND_NO_BUFFER;
                    587:                        ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
                    588:                }
                    589:        } else {
                    590: #if    MACH_RT
                    591:                if (rt)
                    592:                        kmsg = ikm_rtalloc(msg_and_trailer_size);
                    593:                else
                    594: #endif /* MACH_RT */
                    595:                        kmsg = ikm_alloc(msg_and_trailer_size);
                    596: 
                    597:                if (kmsg == IKM_NULL)
                    598:                        return MACH_SEND_NO_BUFFER;
                    599:                ikm_init(kmsg, msg_and_trailer_size);
                    600:        }
                    601: 
                    602:        if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) {
                    603: #if    MACH_RT
                    604:                if (rt)
                    605:                        KMSG_MARK_RT(kmsg);
                    606: #endif /* MACH_RT */
                    607:                ikm_free(kmsg);
                    608:                return MACH_SEND_INVALID_DATA;
                    609:        }
                    610: 
                    611:        kmsg->ikm_header.msgh_size = size;
                    612: #if    MACH_RT
                    613:        if (rt)
                    614:                KMSG_MARK_RT(kmsg);
                    615: #endif /* MACH_RT */
                    616: 
                    617:        /* 
                    618:         * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
                    619:         * However, the internal size field of the trailer (msgh_trailer_size)
                    620:         * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
                    621:         * the cases where no implicit data is requested.
                    622:         */
                    623:        trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)&kmsg->ikm_header + size);
                    624:        trailer->msgh_sender = current_thread()->top_act->task->sec_token;
                    625:        trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                    626:        trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
                    627: 
                    628:        *kmsgp = kmsg;
                    629:        return MACH_MSG_SUCCESS;
                    630: }
                    631: 
                    632: /*
                    633:  *     Routine:        ipc_kmsg_get_from_kernel
                    634:  *     Purpose:
                    635:  *             Allocates a kernel message buffer.
                    636:  *             Copies a kernel message to the message buffer.
                    637:  *             Only resource errors are allowed.
                    638:  *     Conditions:
                    639:  *             Nothing locked.
                    640:  *             Ports in header are ipc_port_t.
                    641:  *     Returns:
                    642:  *             MACH_MSG_SUCCESS        Acquired a message buffer.
                    643:  *             MACH_SEND_NO_BUFFER     Couldn't allocate a message buffer.
                    644:  */
                    645: 
                    646: mach_msg_return_t
                    647: ipc_kmsg_get_from_kernel(
                    648:        mach_msg_header_t       *msg,
                    649:        mach_msg_size_t         size,
                    650:        ipc_kmsg_t              *kmsgp)
                    651: {
                    652:        ipc_kmsg_t      kmsg;
                    653:        mach_msg_size_t msg_and_trailer_size;
                    654:        mach_msg_format_0_trailer_t *trailer;
                    655:        ipc_port_t      dest_port;
                    656: #if    MACH_RT
                    657:        boolean_t       rt;
                    658: #endif /* MACH_RT */
                    659: 
                    660:        assert(size >= sizeof(mach_msg_header_t));
                    661:        assert((size & 3) == 0);
                    662: 
                    663:        /* round up for ikm_cache */
                    664:        msg_and_trailer_size = size + MAX_TRAILER_SIZE;
                    665:        if (msg_and_trailer_size < IKM_SAVED_MSG_SIZE)
                    666:            msg_and_trailer_size = IKM_SAVED_MSG_SIZE;
                    667: 
                    668:        assert(IP_VALID((ipc_port_t) msg->msgh_remote_port));
                    669: 
                    670: #if    MACH_RT
                    671:        rt = IP_RT((ipc_port_t) msg->msgh_remote_port);
                    672: 
                    673:        if (rt)
                    674:                kmsg = ikm_rtalloc(msg_and_trailer_size);
                    675:        else
                    676: #endif /* MACH_RT */
                    677:                kmsg = ikm_alloc(msg_and_trailer_size);
                    678: 
                    679:        if (kmsg == IKM_NULL)
                    680:                return MACH_SEND_NO_BUFFER;
                    681:        ikm_init(kmsg, msg_and_trailer_size);
                    682: 
                    683:        (void) memcpy((void *) &kmsg->ikm_header, (const void *) msg, size);
                    684: 
                    685:        kmsg->ikm_header.msgh_size = size;
                    686: #if    MACH_RT
                    687:        if (rt)
                    688:                KMSG_MARK_RT(kmsg);
                    689: #endif /* MACH_RT */
                    690: 
                    691:        /* 
                    692:         * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
                    693:         * However, the internal size field of the trailer (msgh_trailer_size)
                    694:         * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
                    695:         * the cases where no implicit data is requested.
                    696:         */
                    697:        trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)&kmsg->ikm_header + size);
                    698:        trailer->msgh_sender = KERNEL_SECURITY_TOKEN;
                    699:        trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
                    700:        trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
                    701: 
                    702:        *kmsgp = kmsg;
                    703:        return MACH_MSG_SUCCESS;
                    704: }
                    705: 
                    706: /*
                    707:  *     Routine:        ipc_kmsg_send
                    708:  *     Purpose:
                    709:  *             Send a message.  The message holds a reference
                    710:  *             for the destination port in the msgh_remote_port field.
                    711:  *
                    712:  *             If unsuccessful, the caller still has possession of
                    713:  *             the message and must do something with it.  If successful,
                    714:  *             the message is queued, given to a receiver, destroyed,
                    715:  *             or handled directly by the kernel via mach_msg.
                    716:  *     Conditions:
                    717:  *             Nothing locked.
                    718:  *     Returns:
                    719:  *             MACH_MSG_SUCCESS        The message was accepted.
                    720:  *             MACH_SEND_TIMED_OUT     Caller still has message.
                    721:  *             MACH_SEND_INTERRUPTED   Caller still has message.
                    722:  */
                    723: mach_msg_return_t
                    724: ipc_kmsg_send(
                    725:        ipc_kmsg_t              kmsg,
                    726:        mach_msg_option_t       option,
                    727:        mach_msg_timeout_t      timeout)
                    728: {
                    729:        kern_return_t           save_wait_result;
                    730: 
                    731:        ipc_port_t port;
                    732:        port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
                    733:        assert(IP_VALID(port));
                    734: 
                    735:        ip_lock(port);
                    736: 
                    737:        if (port->ip_receiver == ipc_space_kernel) {
                    738: 
                    739:                /*
                    740:                 *      We can check ip_receiver == ipc_space_kernel
                    741:                 *      before checking that the port is active because
                    742:                 *      ipc_port_dealloc_kernel clears ip_receiver
                    743:                 *      before destroying a kernel port.
                    744:                 */
                    745:                assert(ip_active(port));
                    746:                port->ip_messages.imq_seqno++;
                    747:                ip_unlock(port);
                    748: 
                    749:                current_task()->messages_sent++;
                    750: 
                    751:                /*
                    752:                 * Call the server routine, and get the reply message to send.
                    753:                 */
                    754:                kmsg = ipc_kobject_server(kmsg);
                    755:                if (kmsg == IKM_NULL)
                    756:                        return MACH_MSG_SUCCESS;
                    757: 
                    758:                port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port;
                    759:                assert(IP_VALID(port));
                    760:                ip_lock(port);
                    761:                /* fall thru with reply - same options */
                    762:        }
                    763: 
                    764:        /*
                    765:         *      Can't deliver to a dead port.
                    766:         *      However, we can pretend it got sent
                    767:         *      and was then immediately destroyed.
                    768:         */
                    769:        if (!ip_active(port)) {
                    770:                /*
                    771:                 *      We can't let ipc_kmsg_destroy deallocate
                    772:                 *      the port right, because we might end up
                    773:                 *      in an infinite loop trying to deliver
                    774:                 *      a send-once notification.
                    775:                 */
                    776: 
                    777:                ip_release(port);
                    778:                ip_check_unlock(port);
                    779:                kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL;
                    780:                ipc_kmsg_destroy(kmsg);
                    781:                return MACH_MSG_SUCCESS;
                    782:        }
                    783: 
                    784:        if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
                    785:                ip_unlock(port);
                    786: 
                    787:                /* don't allow the creation of a circular loop */
                    788: 
                    789:                ipc_kmsg_destroy(kmsg);
                    790:                return MACH_MSG_SUCCESS;
                    791:        }
                    792: 
                    793:        /*
                    794:         * We have a valid message and a valid reference on the port.
                    795:         * we can unlock the port and call mqueue_send() on it's message
                    796:         * queue.
                    797:         */
                    798:        ip_unlock(port);
                    799:        return (ipc_mqueue_send(&port->ip_messages, kmsg, option, timeout));
                    800: }
                    801: 
                    802: /*
                    803:  *     Routine:        ipc_kmsg_put
                    804:  *     Purpose:
                    805:  *             Copies a message buffer to a user message.
                    806:  *             Copies only the specified number of bytes.
                    807:  *             Frees the message buffer.
                    808:  *     Conditions:
                    809:  *             Nothing locked.  The message buffer must have clean
                    810:  *             header fields.
                    811:  *     Returns:
                    812:  *             MACH_MSG_SUCCESS        Copied data out of message buffer.
                    813:  *             MACH_RCV_INVALID_DATA   Couldn't copy to user message.
                    814:  */
                    815: 
                    816: mach_msg_return_t
                    817: ipc_kmsg_put(
                    818:        mach_msg_header_t       *msg,
                    819:        ipc_kmsg_t              kmsg,
                    820:        mach_msg_size_t         size)
                    821: {
                    822:        mach_msg_return_t mr;
                    823: 
                    824:        ikm_check_initialized(kmsg, kmsg->ikm_size);
                    825: 
                    826:        if (copyoutmsg((const char *) &kmsg->ikm_header, (char *) msg, size))
                    827:                mr = MACH_RCV_INVALID_DATA;
                    828:        else
                    829:                mr = MACH_MSG_SUCCESS;
                    830: 
                    831:        if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE ||
                    832:            KMSG_IS_RT(kmsg) ||
                    833:            !ikm_cache_put(kmsg))
                    834:                ikm_free(kmsg);
                    835: 
                    836:        return mr;
                    837: }
                    838: 
                    839: /*
                    840:  *     Routine:        ipc_kmsg_put_to_kernel
                    841:  *     Purpose:
                    842:  *             Copies a message buffer to a kernel message.
                    843:  *             Frees the message buffer.
                    844:  *             No errors allowed.
                    845:  *     Conditions:
                    846:  *             Nothing locked.
                    847:  */
                    848: 
                    849: void
                    850: ipc_kmsg_put_to_kernel(
                    851:        mach_msg_header_t       *msg,
                    852:        ipc_kmsg_t              kmsg,
                    853:        mach_msg_size_t         size)
                    854: {
                    855:        (void) memcpy((void *) msg, (const void *) &kmsg->ikm_header, size);
                    856: 
                    857:        ikm_free(kmsg);
                    858: }
                    859: 
                    860: /*
                    861:  *     Routine:        ipc_kmsg_copyin_header
                    862:  *     Purpose:
                    863:  *             "Copy-in" port rights in the header of a message.
                    864:  *             Operates atomically; if it doesn't succeed the
                    865:  *             message header and the space are left untouched.
                    866:  *             If it does succeed the remote/local port fields
                    867:  *             contain object pointers instead of port names,
                    868:  *             and the bits field is updated.  The destination port
                    869:  *             will be a valid port pointer.
                    870:  *
                    871:  *             The notify argument implements the MACH_SEND_CANCEL option.
                    872:  *             If it is not MACH_PORT_NULL, it should name a receive right.
                    873:  *             If the processing of the destination port would generate
                    874:  *             a port-deleted notification (because the right for the
                    875:  *             destination port is destroyed and it had a request for
                    876:  *             a dead-name notification registered), and the port-deleted
                    877:  *             notification would be sent to the named receive right,
                    878:  *             then it isn't sent and the send-once right for the notify
                    879:  *             port is quietly destroyed.
                    880:  *
                    881:  *     Conditions:
                    882:  *             Nothing locked.
                    883:  *     Returns:
                    884:  *             MACH_MSG_SUCCESS        Successful copyin.
                    885:  *             MACH_SEND_INVALID_HEADER
                    886:  *                     Illegal value in the message header bits.
                    887:  *             MACH_SEND_INVALID_DEST  The space is dead.
                    888:  *             MACH_SEND_INVALID_NOTIFY
                    889:  *                     Notify is non-null and doesn't name a receive right.
                    890:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    891:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
                    892:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    893:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
                    894:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                    895:  */
                    896: 
                    897: mach_msg_return_t
                    898: ipc_kmsg_copyin_header(
                    899:        mach_msg_header_t       *msg,
                    900:        ipc_space_t             space,
                    901:        mach_port_name_t        notify)
                    902: {
                    903:        mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
                    904:        mach_port_name_t dest_name = (mach_port_name_t)msg->msgh_remote_port;
                    905:        mach_port_name_t reply_name = (mach_port_name_t)msg->msgh_local_port;
                    906:        kern_return_t kr;
                    907: 
                    908:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                    909:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                    910:        ipc_object_t dest_port, reply_port;
                    911:        ipc_port_t dest_soright, reply_soright;
                    912:        ipc_port_t notify_port;
                    913: 
                    914:        if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
                    915:                return MACH_SEND_INVALID_HEADER;
                    916: 
                    917:        if ((reply_type == 0) ?
                    918:            (reply_name != MACH_PORT_NULL) :
                    919:            !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
                    920:                return MACH_SEND_INVALID_HEADER;
                    921: 
                    922:        reply_soright = IP_NULL; /* in case we go to invalid dest early */
                    923: 
                    924:        is_write_lock(space);
                    925:        if (!space->is_active)
                    926:                goto invalid_dest;
                    927: 
                    928:        if (notify != MACH_PORT_NULL) {
                    929:                ipc_entry_t entry;
                    930: 
                    931:                if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
                    932:                        is_write_unlock(space);
                    933:                        return MACH_SEND_INVALID_NOTIFY;
                    934:                }
                    935:                if((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) {
                    936:                        is_write_unlock(space);
                    937:                        return MACH_SEND_INVALID_NOTIFY;
                    938:                }
                    939: 
                    940:                notify_port = (ipc_port_t) entry->ie_object;
                    941:        }
                    942: 
                    943:        if (dest_name == reply_name) {
                    944:                ipc_entry_t entry;
                    945:                mach_port_name_t name = dest_name;
                    946: 
                    947:                /*
                    948:                 *      Destination and reply ports are the same!
                    949:                 *      This is a little tedious to make atomic, because
                    950:                 *      there are 25 combinations of dest_type/reply_type.
                    951:                 *      However, most are easy.  If either is move-sonce,
                    952:                 *      then there must be an error.  If either are
                    953:                 *      make-send or make-sonce, then we must be looking
                    954:                 *      at a receive right so the port can't die.
                    955:                 *      The hard cases are the combinations of
                    956:                 *      copy-send and make-send.
                    957:                 */
                    958: 
                    959:                entry = ipc_entry_lookup(space, name);
                    960:                if (entry == IE_NULL)
                    961:                        goto invalid_dest;
                    962: 
                    963:                assert(reply_type != 0); /* because name not null */
                    964: 
                    965:                if (!ipc_right_copyin_check(space, name, entry, reply_type))
                    966:                        goto invalid_reply;
                    967: 
                    968:                if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
                    969:                    (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
                    970:                        /*
                    971:                         *      Why must there be an error?  To get a valid
                    972:                         *      destination, this entry must name a live
                    973:                         *      port (not a dead name or dead port).  However
                    974:                         *      a successful move-sonce will destroy a
                    975:                         *      live entry.  Therefore the other copyin,
                    976:                         *      whatever it is, would fail.  We've already
                    977:                         *      checked for reply port errors above,
                    978:                         *      so report a destination error.
                    979:                         */
                    980: 
                    981:                        goto invalid_dest;
                    982:                } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
                    983:                           (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
                    984:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
                    985:                           (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
                    986:                        kr = ipc_right_copyin(space, name, entry,
                    987:                                              dest_type, FALSE,
                    988:                                              &dest_port, &dest_soright);
                    989:                        if (kr != KERN_SUCCESS)
                    990:                                goto invalid_dest;
                    991: 
                    992:                        /*
                    993:                         *      Either dest or reply needs a receive right.
                    994:                         *      We know the receive right is there, because
                    995:                         *      of the copyin_check and copyin calls.  Hence
                    996:                         *      the port is not in danger of dying.  If dest
                    997:                         *      used the receive right, then the right needed
                    998:                         *      by reply (and verified by copyin_check) will
                    999:                         *      still be there.
                   1000:                         */
                   1001: 
                   1002:                        assert(IO_VALID(dest_port));
                   1003:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                   1004:                        assert(dest_soright == IP_NULL);
                   1005: 
                   1006:                        kr = ipc_right_copyin(space, name, entry,
                   1007:                                              reply_type, TRUE,
                   1008:                                              &reply_port, &reply_soright);
                   1009: 
                   1010:                        assert(kr == KERN_SUCCESS);
                   1011:                        assert(reply_port == dest_port);
                   1012:                        assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
                   1013:                        assert(reply_soright == IP_NULL);
                   1014:                } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
                   1015:                           (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
                   1016:                        /*
                   1017:                         *      To make this atomic, just do one copy-send,
                   1018:                         *      and dup the send right we get out.
                   1019:                         */
                   1020: 
                   1021:                        kr = ipc_right_copyin(space, name, entry,
                   1022:                                              dest_type, FALSE,
                   1023:                                              &dest_port, &dest_soright);
                   1024:                        if (kr != KERN_SUCCESS)
                   1025:                                goto invalid_dest;
                   1026: 
                   1027:                        assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
                   1028:                        assert(dest_soright == IP_NULL);
                   1029: 
                   1030:                        /*
                   1031:                         *      It's OK if the port we got is dead now,
                   1032:                         *      so reply_port is IP_DEAD, because the msg
                   1033:                         *      won't go anywhere anyway.
                   1034:                         */
                   1035: 
                   1036:                        reply_port = (ipc_object_t)
                   1037:                                ipc_port_copy_send((ipc_port_t) dest_port);
                   1038:                        reply_soright = IP_NULL;
                   1039:                } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
                   1040:                           (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
                   1041:                        /*
                   1042:                         *      This is an easy case.  Just use our
                   1043:                         *      handy-dandy special-purpose copyin call
                   1044:                         *      to get two send rights for the price of one.
                   1045:                         */
                   1046: 
                   1047:                        kr = ipc_right_copyin_two(space, name, entry,
                   1048:                                                  &dest_port, &dest_soright);
                   1049:                        if (kr != KERN_SUCCESS)
                   1050:                                goto invalid_dest;
                   1051: 
                   1052:                        /* the entry might need to be deallocated */
                   1053:                        if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1054:                                ipc_entry_dealloc(space, name, entry);
                   1055: 
                   1056:                        reply_port = dest_port;
                   1057:                        reply_soright = IP_NULL;
                   1058:                } else {
                   1059:                        ipc_port_t soright;
                   1060: 
                   1061:                        assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
                   1062:                                (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
                   1063:                               ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
                   1064:                                (reply_type == MACH_MSG_TYPE_COPY_SEND)));
                   1065: 
                   1066:                        /*
                   1067:                         *      To make this atomic, just do a move-send,
                   1068:                         *      and dup the send right we get out.
                   1069:                         */
                   1070: 
                   1071:                        kr = ipc_right_copyin(space, name, entry,
                   1072:                                              MACH_MSG_TYPE_MOVE_SEND, FALSE,
                   1073:                                              &dest_port, &soright);
                   1074:                        if (kr != KERN_SUCCESS)
                   1075:                                goto invalid_dest;
                   1076: 
                   1077:                        /* the entry might need to be deallocated */
                   1078: 
                   1079:                        if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1080:                                ipc_entry_dealloc(space, name, entry);
                   1081: 
                   1082:                        /*
                   1083:                         *      It's OK if the port we got is dead now,
                   1084:                         *      so reply_port is IP_DEAD, because the msg
                   1085:                         *      won't go anywhere anyway.
                   1086:                         */
                   1087: 
                   1088:                        reply_port = (ipc_object_t)
                   1089:                                ipc_port_copy_send((ipc_port_t) dest_port);
                   1090: 
                   1091:                        if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
                   1092:                                dest_soright = soright;
                   1093:                                reply_soright = IP_NULL;
                   1094:                        } else {
                   1095:                                dest_soright = IP_NULL;
                   1096:                                reply_soright = soright;
                   1097:                        }
                   1098:                }
                   1099:        } else if (!MACH_PORT_VALID(reply_name)) {
                   1100:                ipc_entry_t entry;
                   1101: 
                   1102:                /*
                   1103:                 *      No reply port!  This is an easy case
                   1104:                 *      to make atomic.  Just copyin the destination.
                   1105:                 */
                   1106: 
                   1107:                entry = ipc_entry_lookup(space, dest_name);
                   1108:                if (entry == IE_NULL)
                   1109:                        goto invalid_dest;
                   1110: 
                   1111:                kr = ipc_right_copyin(space, dest_name, entry,
                   1112:                                      dest_type, FALSE,
                   1113:                                      &dest_port, &dest_soright);
                   1114:                if (kr != KERN_SUCCESS)
                   1115:                        goto invalid_dest;
                   1116: 
                   1117:                /* the entry might need to be deallocated */
                   1118: 
                   1119:                if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1120:                        ipc_entry_dealloc(space, dest_name, entry);
                   1121: 
                   1122:                reply_port = (ipc_object_t) reply_name;
                   1123:                reply_soright = IP_NULL;
                   1124:        } else {
                   1125:                ipc_entry_t dest_entry, reply_entry;
                   1126:                ipc_port_t saved_reply;
                   1127: 
                   1128:                /*
                   1129:                 *      This is the tough case to make atomic.
                   1130:                 *      The difficult problem is serializing with port death.
                   1131:                 *      At the time we copyin dest_port, it must be alive.
                   1132:                 *      If reply_port is alive when we copyin it, then
                   1133:                 *      we are OK, because we serialize before the death
                   1134:                 *      of both ports.  Assume reply_port is dead at copyin.
                   1135:                 *      Then if dest_port dies/died after reply_port died,
                   1136:                 *      we are OK, because we serialize between the death
                   1137:                 *      of the two ports.  So the bad case is when dest_port
                   1138:                 *      dies after its copyin, reply_port dies before its
                   1139:                 *      copyin, and dest_port dies before reply_port.  Then
                   1140:                 *      the copyins operated as if dest_port was alive
                   1141:                 *      and reply_port was dead, which shouldn't have happened
                   1142:                 *      because they died in the other order.
                   1143:                 *
                   1144:                 *      Note that it is easy for a user task to tell if
                   1145:                 *      a copyin happened before or after a port died.
                   1146:                 *      For example, suppose both dest and reply are
                   1147:                 *      send-once rights (types are both move-sonce) and
                   1148:                 *      both rights have dead-name requests registered.
                   1149:                 *      If a port dies before copyin, a dead-name notification
                   1150:                 *      is generated and the dead name's urefs are incremented,
                   1151:                 *      and if the copyin happens first, a port-deleted
                   1152:                 *      notification is generated.
                   1153:                 *
                   1154:                 *      Note that although the entries are different,
                   1155:                 *      dest_port and reply_port might still be the same.
                   1156:                 *
                   1157:                 * JMM - The code to handle this was too expensive and, anyway,
                   1158:                 * we intend to separate the dest lookup from the reply copyin
                   1159:                 * by a wide margin, so the user will have to learn to deal!
                   1160:                 * I will be making the change soon!
                   1161:                 */
                   1162: 
                   1163:                dest_entry = ipc_entry_lookup(space, dest_name);
                   1164:                if (dest_entry == IE_NULL)
                   1165:                        goto invalid_dest;
                   1166: 
                   1167:                reply_entry = ipc_entry_lookup(space, reply_name);
                   1168:                if (reply_entry == IE_NULL)
                   1169:                        goto invalid_reply;
                   1170: 
                   1171:                assert(dest_entry != reply_entry); /* names are not equal */
                   1172:                assert(reply_type != 0); /* because reply_name not null */
                   1173: 
                   1174:                if (!ipc_right_copyin_check(space, reply_name, reply_entry,
                   1175:                                            reply_type))
                   1176:                        goto invalid_reply;
                   1177: 
                   1178:                kr = ipc_right_copyin(space, dest_name, dest_entry,
                   1179:                                      dest_type, FALSE,
                   1180:                                      &dest_port, &dest_soright);
                   1181:                if (kr != KERN_SUCCESS)
                   1182:                        goto invalid_dest;
                   1183: 
                   1184:                assert(IO_VALID(dest_port));
                   1185: 
                   1186:                kr = ipc_right_copyin(space, reply_name, reply_entry,
                   1187:                                      reply_type, TRUE,
                   1188:                                      &reply_port, &reply_soright);
                   1189: 
                   1190:                assert(kr == KERN_SUCCESS);
                   1191: 
                   1192:                /* the entries might need to be deallocated */
                   1193: 
                   1194:                if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1195:                        ipc_entry_dealloc(space, reply_name, reply_entry);
                   1196: 
                   1197:                if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
                   1198:                        ipc_entry_dealloc(space, dest_name, dest_entry);
                   1199:        }
                   1200: 
                   1201:        /*
                   1202:         *      At this point, dest_port, reply_port,
                   1203:         *      dest_soright, reply_soright are all initialized.
                   1204:         *      Any defunct entries have been deallocated.
                   1205:         *      The space is still write-locked, and we need to
                   1206:         *      make the MACH_SEND_CANCEL check.  The notify_port pointer
                   1207:         *      is still usable, because the copyin code above won't ever
                   1208:         *      deallocate a receive right, so its entry still exists
                   1209:         *      and holds a ref.  Note notify_port might even equal
                   1210:         *      dest_port or reply_port.
                   1211:         */
                   1212: 
                   1213:        if ((notify != MACH_PORT_NULL) &&
                   1214:            (dest_soright == notify_port)) {
                   1215:                ipc_port_release_sonce(dest_soright);
                   1216:                dest_soright = IP_NULL;
                   1217:        }
                   1218: 
                   1219:        is_write_unlock(space);
                   1220: 
                   1221:        if (dest_soright != IP_NULL)
                   1222:                ipc_notify_port_deleted(dest_soright, dest_name);
                   1223: 
                   1224:        if (reply_soright != IP_NULL)
                   1225:                ipc_notify_port_deleted(reply_soright, reply_name);
                   1226: 
                   1227:        dest_type = ipc_object_copyin_type(dest_type);
                   1228:        reply_type = ipc_object_copyin_type(reply_type);
                   1229: 
                   1230:        msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                   1231:                          MACH_MSGH_BITS(dest_type, reply_type));
                   1232:        msg->msgh_remote_port = (ipc_port_t)dest_port;
                   1233:        msg->msgh_local_port = (ipc_port_t)reply_port;
                   1234: 
                   1235:        return MACH_MSG_SUCCESS;
                   1236: 
                   1237: invalid_reply:
                   1238:        is_write_unlock(space);
                   1239:        return MACH_SEND_INVALID_REPLY;
                   1240: 
                   1241: invalid_dest:
                   1242:        is_write_unlock(space);
                   1243:        if (reply_soright != IP_NULL)
                   1244:                ipc_notify_port_deleted(reply_soright, reply_name);
                   1245:        return MACH_SEND_INVALID_DEST;
                   1246: }
                   1247: 
                   1248: /*
                   1249:  *     Routine:        ipc_kmsg_copyin_body
                   1250:  *     Purpose:
                   1251:  *             "Copy-in" port rights and out-of-line memory
                   1252:  *             in the message body.
                   1253:  *
                   1254:  *             In all failure cases, the message is left holding
                   1255:  *             no rights or memory.  However, the message buffer
                   1256:  *             is not deallocated.  If successful, the message
                   1257:  *             contains a valid destination port.
                   1258:  *     Conditions:
                   1259:  *             Nothing locked.
                   1260:  *     Returns:
                   1261:  *             MACH_MSG_SUCCESS        Successful copyin.
                   1262:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
                   1263:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
                   1264:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
                   1265:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
                   1266:  *             MACH_SEND_INVALID_RT_OOL_SIZE OOL Buffer too large for RT
                   1267:  *             MACH_MSG_INVALID_RT_DESCRIPTOR Dealloc and RT are incompatible
                   1268:  */
                   1269: 
                   1270: mach_msg_return_t
                   1271: ipc_kmsg_copyin_body(
                   1272:        ipc_kmsg_t      kmsg,
                   1273:        ipc_space_t     space,
                   1274:        vm_map_t        map)
                   1275: {
                   1276:     ipc_object_t                       dest;
                   1277:     mach_msg_body_t            *body;
                   1278:     mach_msg_descriptor_t      *saddr, *eaddr;
                   1279:     boolean_t                  complex;
                   1280:     mach_msg_return_t          mr;
                   1281:     boolean_t                  use_page_lists, steal_pages;
                   1282:     int                                i;
                   1283:     kern_return_t              kr;
                   1284:     vm_size_t                  space_needed = 0;
                   1285:     vm_offset_t                        paddr = 0;
                   1286:     mach_msg_descriptor_t      *sstart;
                   1287:     vm_map_copy_t              copy = VM_MAP_COPY_NULL;
                   1288: #if    MACH_RT
                   1289:     boolean_t                  rt;
                   1290: #endif /* MACH_RT */
                   1291:     
                   1292:     /*
                   1293:      * Determine if the target is a kernel port.
                   1294:      */
                   1295:     dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   1296:     complex = FALSE;
                   1297:     use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
                   1298:     steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
                   1299: #if    MACH_RT
                   1300:     rt = KMSG_IS_RT(kmsg);
                   1301: #endif /* MACH_RT */
                   1302: 
                   1303:     body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   1304:     saddr = (mach_msg_descriptor_t *) (body + 1);
                   1305:     eaddr = saddr + body->msgh_descriptor_count;
                   1306:     
                   1307:     /* make sure the message does not ask for more msg descriptors
                   1308:      * than the message can hold.
                   1309:      */
                   1310:     
                   1311:     if (eaddr <= saddr ||
                   1312:        eaddr > (mach_msg_descriptor_t *) (&kmsg->ikm_header + 
                   1313:                            kmsg->ikm_header.msgh_size)) {
                   1314:        ipc_kmsg_clean_partial(kmsg,0,0,0);
                   1315:        return MACH_SEND_MSG_TOO_SMALL;
                   1316:     }
                   1317:     
                   1318:     /*
                   1319:      * Make an initial pass to determine kernal VM space requirements for
                   1320:      * physical copies.
                   1321:      */
                   1322:     for (sstart = saddr; sstart <  eaddr; sstart++) {
                   1323: 
                   1324:        if (sstart->type.type == MACH_MSG_OOL_DESCRIPTOR ||
                   1325:            sstart->type.type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
                   1326: 
                   1327:                assert(!(sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY &&
                   1328:                       (use_page_lists || steal_pages)));
                   1329: 
                   1330:                if (sstart->out_of_line.copy != MACH_MSG_PHYSICAL_COPY &&
                   1331:                    sstart->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) {
                   1332:                    /*
                   1333:                     * Invalid copy option
                   1334:                     */
                   1335:                    ipc_kmsg_clean_partial(kmsg,0,0,0);
                   1336:                    return MACH_SEND_INVALID_TYPE;
                   1337:                }
                   1338:                
                   1339:                if (sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && 
                   1340:                    sstart->out_of_line.size >= MSG_OOL_SIZE_SMALL(rt) &&
                   1341:                    !sstart->out_of_line.deallocate) {
                   1342: 
                   1343:                        /*
                   1344:                         * Out-of-line memory descriptor, accumulate kernel
                   1345:                         * memory requirements
                   1346:                         */
                   1347:                        space_needed += round_page(sstart->out_of_line.size);
                   1348:                        if (space_needed > ipc_kmsg_max_vm_space) {
                   1349: 
                   1350:                                /*
                   1351:                                 * Per message kernel memory limit exceeded
                   1352:                                 */
                   1353:                                ipc_kmsg_clean_partial(kmsg,0,0,0);
                   1354:                                return MACH_MSG_VM_KERNEL;
                   1355:                        }
                   1356:                }
                   1357:        }
                   1358:     }
                   1359: 
                   1360:     /*
                   1361:      * Allocate space in the pageable kernel ipc copy map for all the
                   1362:      * ool data that is to be physically copied.  Map is marked wait for
                   1363:      * space.
                   1364:      */
                   1365:     if (space_needed) {
                   1366: #if    MACH_RT
                   1367:        if (rt) {
                   1368:                ipc_kmsg_clean_partial(kmsg,0,0,0);
                   1369:                return MACH_SEND_INVALID_RT_OOL_SIZE;
                   1370:        }
                   1371: #endif /* MACH_RT */
                   1372:        if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, 
                   1373:                                TRUE) != KERN_SUCCESS) {
                   1374:                ipc_kmsg_clean_partial(kmsg,0,0,0);
                   1375:                return MACH_MSG_VM_KERNEL;
                   1376:        }
                   1377:     }
                   1378: 
                   1379:     /* 
                   1380:      * handle the OOL regions and port descriptors.
                   1381:      * the check for complex messages was done earlier.
                   1382:      */
                   1383:     
                   1384:     for (i = 0, sstart = saddr; sstart <  eaddr; sstart++) {
                   1385:        
                   1386:        switch (sstart->type.type) {
                   1387:            
                   1388:            case MACH_MSG_PORT_DESCRIPTOR: {
                   1389:                mach_msg_type_name_t            name;
                   1390:                ipc_object_t                    object;
                   1391:                mach_msg_port_descriptor_t      *dsc;
                   1392:                
                   1393:                dsc = &sstart->port;
                   1394:                
                   1395:                /* this is really the type SEND, SEND_ONCE, etc. */
                   1396:                name = dsc->disposition;
                   1397:                dsc->disposition = ipc_object_copyin_type(name);
                   1398:                
                   1399:                if (!MACH_PORT_VALID((mach_port_name_t)dsc->name)) {
                   1400:                    complex = TRUE;
                   1401:                    break;
                   1402:                }
                   1403:                kr = ipc_object_copyin(space, (mach_port_name_t)dsc->name, name, &object);
                   1404:                if (kr != KERN_SUCCESS) {
                   1405:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1406:                    return MACH_SEND_INVALID_RIGHT;
                   1407:                }
                   1408:                if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1409:                    ipc_port_check_circularity((ipc_port_t) object,
                   1410:                                               (ipc_port_t) dest)) {
                   1411:                    kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
                   1412:                }
                   1413:                dsc->name = (ipc_port_t) object;
                   1414:                complex = TRUE;
                   1415:                break;
                   1416:            }
                   1417:            case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
                   1418:            case MACH_MSG_OOL_DESCRIPTOR: {
                   1419:                vm_size_t                       length;
                   1420:                boolean_t                       dealloc;
                   1421:                vm_offset_t                     addr;
                   1422:                vm_offset_t                     kaddr;
                   1423:                mach_msg_ool_descriptor_t       *dsc;
                   1424:                
                   1425:                dsc = &sstart->out_of_line;
                   1426: #if    MACH_RT                     
                   1427:                if ((dealloc = dsc->deallocate) && rt) {
                   1428:                    /* If RT, we cannot have paddr */
                   1429:                    ipc_kmsg_clean_partial(kmsg, i, 0, 0);
                   1430:                    return MACH_MSG_INVALID_RT_DESCRIPTOR;
                   1431:                }
                   1432: #else  /* MACH_RT */           
                   1433:                dealloc = dsc->deallocate;
                   1434: #endif /* MACH_RT */
                   1435:                addr = (vm_offset_t) dsc->address;
                   1436:                
                   1437:                length = dsc->size;
                   1438:                
                   1439:                if (length == 0) {
                   1440:                    dsc->address = 0;
                   1441:                } else if (use_page_lists) {
                   1442:                    int options;
                   1443: 
                   1444: #if    MACH_RT
                   1445:                    assert(!rt);
                   1446: #endif /* MACH_RT */
                   1447:                    /*
                   1448:                     * Use page list copy mechanism if specified. Since the
                   1449:                     * destination is a kernel port, no RT handling is
                   1450:                     * necessary. 
                   1451:                     */
                   1452:                    if (steal_pages == FALSE) {
                   1453:                        /*
                   1454:                         * XXX Temporary Hackaround.
                   1455:                         * XXX Because the same page
                   1456:                         * XXX might be in more than one
                   1457:                         * XXX out of line region, steal
                   1458:                         * XXX (busy) pages from previous
                   1459:                         * XXX region so that this copyin
                   1460:                         * XXX won't block (permanently).
                   1461:                         */
                   1462:                        if (copy != VM_MAP_COPY_NULL)
                   1463:                            vm_map_copy_steal_pages(copy);
                   1464:                    }
                   1465: 
                   1466:                    /*
                   1467:                     *  Set up options for copying in page list.
                   1468:                     *  If deallocating, steal pages to prevent
                   1469:                     *  vm code from lazy evaluating deallocation.
                   1470:                     */
                   1471:                    options = VM_PROT_READ;
                   1472:                    if (dealloc) {
                   1473:                        options |= VM_MAP_COPYIN_OPT_SRC_DESTROY |
                   1474:                                        VM_MAP_COPYIN_OPT_STEAL_PAGES;
                   1475:                    }
                   1476:                    else if (steal_pages) {
                   1477:                        options |= VM_MAP_COPYIN_OPT_STEAL_PAGES;
                   1478:                    }
                   1479: 
                   1480:                    if (vm_map_copyin_page_list(map, addr, length, options,
                   1481:                                                &copy, FALSE)
                   1482:                        != KERN_SUCCESS) {
                   1483: 
                   1484:                        ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1485:                        return MACH_SEND_INVALID_MEMORY;
                   1486:                    }
                   1487: 
                   1488:                    dsc->address = (void *) copy;
                   1489:                    dsc->copy = MACH_MSG_PAGE_LIST_COPY_T;
                   1490:                } else if (length < MSG_OOL_SIZE_SMALL(rt) &&
                   1491:                           dsc->copy == MACH_MSG_PHYSICAL_COPY) {
                   1492: 
                   1493:                    /*
                   1494:                     * If the data is 'small' enough, always kalloc space for
                   1495:                     * it and copy it in.  The data will be copied out
                   1496:                     * on the  message receive.  This is a performance
                   1497:                     * optimization that assumes the cost of VM operations
                   1498:                     * dominates the copyin/copyout overhead for 'small'
                   1499:                     * regions.
                   1500:                     * If the kernel is the message target, a consistent data
                   1501:                     * repesentation is needed for ool data since kernel 
                   1502:                     * functions may deallocate the ool data.  In this case
                   1503:                     * a vm_map_copy_t is allocated along with the space for
                   1504:                     * the data as an optimization.  No RT handling is needed.
                   1505:                     */ 
                   1506:                    if (is_ipc_kobject(ip_kotype((ipc_port_t)dest))) {
                   1507:                        vm_map_copy_t copy;
                   1508:                        vm_size_t kalloc_size = sizeof(struct vm_map_copy) +
                   1509:                            length;
                   1510: 
                   1511: #if    MACH_RT
                   1512:                        assert(!rt);
                   1513: #endif /* MACH_RT */
                   1514:                        copy = (vm_map_copy_t) kalloc(kalloc_size);
                   1515:                        if (copy == VM_MAP_COPY_NULL) {
                   1516:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1517:                                                        space_needed);
                   1518:                            return MACH_MSG_VM_KERNEL;
                   1519:                        }
                   1520:                        copy->type = VM_MAP_COPY_KERNEL_BUFFER;
                   1521:                        if (copyin((const char *) addr, (char *) (copy + 1), 
                   1522:                                                                length)) {
                   1523:                            kfree((vm_offset_t) copy, kalloc_size);
                   1524:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1525:                                                        space_needed);
                   1526:                            return MACH_SEND_INVALID_MEMORY;
                   1527:                        }       
                   1528:                        dsc->address = (void *) copy;
                   1529:                        dsc->copy = MACH_MSG_KALLOC_COPY_T;
                   1530:                        copy->size = length;
                   1531:                        copy->offset = 0;
                   1532:                        copy->cpy_kdata = (vm_offset_t) (copy + 1);
                   1533:                        copy->cpy_kalloc_size = kalloc_size;
                   1534:                    } else {
                   1535:                        if ((kaddr = KALLOC(length, rt)) == (vm_offset_t) 0) {
                   1536:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1537:                                                        space_needed);
                   1538:                            return MACH_MSG_VM_KERNEL;
                   1539:                        }
                   1540: 
                   1541:                        if (copyin((const char *) addr, (char *) kaddr, 
                   1542:                                                                length)) {
                   1543:                            KFREE(kaddr, length, rt);
                   1544:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1545:                                                        space_needed);
                   1546:                            return MACH_SEND_INVALID_MEMORY;
                   1547:                        }       
                   1548:                        dsc->address = (void *) kaddr;
                   1549:                    }
                   1550:                    if (dealloc) {
                   1551:                        (void) vm_map_remove(map, trunc_page(addr), 
                   1552:                                             round_page(addr + length),
                   1553:                                             VM_MAP_REMOVE_WAIT_FOR_KWIRE|
                   1554:                                             VM_MAP_REMOVE_INTERRUPTIBLE);
                   1555:                    }
                   1556:                } else {
                   1557:                    if ((dsc->copy == MACH_MSG_PHYSICAL_COPY) && !dealloc) {
                   1558: 
                   1559:                        /*
                   1560:                         * If the request is a physical copy and the source
                   1561:                         * is not being deallocated, then allocate space
                   1562:                         * in the kernel's pageable ipc copy map and copy
                   1563:                         * the data in.  The semantics guarantee that the
                   1564:                         * data will have been physically copied before
                   1565:                         * the send operation terminates.  Thus if the data
                   1566:                         * is not being deallocated, we must be prepared
                   1567:                         * to page if the region is sufficiently large.
                   1568:                         */
                   1569:                        if (copyin((const char *) addr, (char *) paddr, 
                   1570:                                                                length)) {
                   1571:                                ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1572:                                                           space_needed);
                   1573:                                return MACH_SEND_INVALID_MEMORY;
                   1574:                        }       
                   1575: 
                   1576:                        /*
                   1577:                         * The kernel ipc copy map is marked no_zero_fill.
                   1578:                         * If the transfer is not a page multiple, we need
                   1579:                         * to zero fill the balance.
                   1580:                         */
                   1581:                        if (!page_aligned(length)) {
                   1582:                                (void) memset((void *) (paddr + length), 0,
                   1583:                                        round_page(length) - length);
                   1584:                        }
                   1585:                        if (vm_map_copyin(ipc_kernel_copy_map, paddr, length,
                   1586:                                           TRUE, &copy) != KERN_SUCCESS) {
                   1587:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1588:                                                       space_needed);
                   1589:                            return MACH_MSG_VM_KERNEL;
                   1590:                        }
                   1591:                        paddr += round_page(length);
                   1592:                        space_needed -= round_page(length);
                   1593:                    } else {
                   1594: 
                   1595:                        /*
                   1596:                         * Make a virtual copy of the of the data if requested
                   1597:                         * or if a physical copy was requested but the source
                   1598:                         * is being deallocated.  This is an invalid
                   1599:                         * path if RT.
                   1600:                         */
                   1601: #if    MACH_RT                     
                   1602:                        if (rt) {
                   1603:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1604:                                                       space_needed);
                   1605:                            return MACH_SEND_INVALID_TYPE;
                   1606:                        }
                   1607: #endif /* MACH_RT */
                   1608:                        if (vm_map_copyin(map, addr, length,
                   1609:                                           dealloc, &copy) != KERN_SUCCESS) {
                   1610:                            ipc_kmsg_clean_partial(kmsg, i, paddr, 
                   1611:                                                       space_needed);
                   1612:                            return MACH_SEND_INVALID_MEMORY;
                   1613:                        }
                   1614:                    }
                   1615:                    dsc->address = (void *) copy;
                   1616:                }
                   1617:                complex = TRUE;
                   1618:                break;
                   1619:            }
                   1620:            case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
                   1621:                vm_size_t                               length;
                   1622:                vm_offset_t                             data;
                   1623:                vm_offset_t                             addr;
                   1624:                ipc_object_t                            *objects;
                   1625:                int                                     j;
                   1626:                mach_msg_type_name_t                    name;
                   1627:                mach_msg_ool_ports_descriptor_t         *dsc;
                   1628:                
                   1629:                dsc = &sstart->ool_ports;
                   1630:                addr = (vm_offset_t) dsc->address;
                   1631: 
                   1632:                /* calculate length of data in bytes, rounding up */
                   1633:                length = dsc->count * sizeof(mach_port_name_t);
                   1634:                
                   1635:                if (length == 0) {
                   1636:                    complex = TRUE;
                   1637:                    dsc->address = (void *) 0;
                   1638:                    break;
                   1639:                }
                   1640: 
                   1641:                data = KALLOC(length, rt);
                   1642: 
                   1643:                if (data == 0) {
                   1644:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1645:                    return MACH_SEND_NO_BUFFER;
                   1646:                }
                   1647:                
                   1648:                if (copyinmap(map, addr, data, length)) {
                   1649:                    KFREE(data, length, rt);
                   1650:                    ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1651:                    return MACH_SEND_INVALID_MEMORY;
                   1652:                }
                   1653: 
                   1654:                if (dsc->deallocate) {
                   1655:                        (void) vm_deallocate(map, addr, length);
                   1656:                }
                   1657:                
                   1658:                dsc->address = (void *) data;
                   1659:                
                   1660:                /* this is really the type SEND, SEND_ONCE, etc. */
                   1661:                name = dsc->disposition;
                   1662:                dsc->disposition = ipc_object_copyin_type(name);
                   1663:                
                   1664:                objects = (ipc_object_t *) data;
                   1665:                
                   1666:                for ( j = 0; j < dsc->count; j++) {
                   1667:                    mach_port_name_t port = (mach_port_name_t) objects[j];
                   1668:                    ipc_object_t object;
                   1669:                    
                   1670:                    if (!MACH_PORT_VALID(port))
                   1671:                        continue;
                   1672:                    
                   1673:                    kr = ipc_object_copyin(space, port, name, &object);
                   1674: 
                   1675:                    if (kr != KERN_SUCCESS) {
                   1676:                        int k;
                   1677: 
                   1678:                        for(k = 0; k < j; k++) {
                   1679:                            object = objects[k];
                   1680:                            if (!MACH_PORT_VALID(port))
                   1681:                                continue;
                   1682:                            ipc_object_destroy(object, dsc->disposition);
                   1683:                        }
                   1684:                        KFREE(data, length, rt);
                   1685:                        ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1686:                        return MACH_SEND_INVALID_RIGHT;
                   1687:                    }
                   1688:                    
                   1689:                    if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1690:                        ipc_port_check_circularity(
                   1691:                                                   (ipc_port_t) object,
                   1692:                                                   (ipc_port_t) dest))
                   1693:                        kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
                   1694:                    
                   1695:                    objects[j] = object;
                   1696:                }
                   1697:                
                   1698:                complex = TRUE;
                   1699:                break;
                   1700:            }
                   1701:            default: {
                   1702:                /*
                   1703:                 * Invalid descriptor
                   1704:                 */
                   1705:                ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed);
                   1706:                return MACH_SEND_INVALID_TYPE;
                   1707:            }
                   1708:        }
                   1709:        i++ ;
                   1710:     }
                   1711:     
                   1712:     if (!complex)
                   1713:        kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
                   1714:     return MACH_MSG_SUCCESS;
                   1715: }
                   1716: 
                   1717: 
                   1718: /*
                   1719:  *     Routine:        ipc_kmsg_copyin
                   1720:  *     Purpose:
                   1721:  *             "Copy-in" port rights and out-of-line memory
                   1722:  *             in the message.
                   1723:  *
                   1724:  *             In all failure cases, the message is left holding
                   1725:  *             no rights or memory.  However, the message buffer
                   1726:  *             is not deallocated.  If successful, the message
                   1727:  *             contains a valid destination port.
                   1728:  *     Conditions:
                   1729:  *             Nothing locked.
                   1730:  *     Returns:
                   1731:  *             MACH_MSG_SUCCESS        Successful copyin.
                   1732:  *             MACH_SEND_INVALID_HEADER
                   1733:  *                     Illegal value in the message header bits.
                   1734:  *             MACH_SEND_INVALID_NOTIFY        Bad notify port.
                   1735:  *             MACH_SEND_INVALID_DEST  Can't copyin destination port.
                   1736:  *             MACH_SEND_INVALID_REPLY Can't copyin reply port.
                   1737:  *             MACH_SEND_INVALID_MEMORY        Can't grab out-of-line memory.
                   1738:  *             MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
                   1739:  *             MACH_SEND_INVALID_TYPE  Bad type specification.
                   1740:  *             MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
                   1741:  */
                   1742: 
                   1743: mach_msg_return_t
                   1744: ipc_kmsg_copyin(
                   1745:        ipc_kmsg_t              kmsg,
                   1746:        ipc_space_t             space,
                   1747:        vm_map_t                map,
                   1748:        mach_port_name_t        notify)
                   1749: {
                   1750:     mach_msg_return_t          mr;
                   1751:     
                   1752:     mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
                   1753:     if (mr != MACH_MSG_SUCCESS)
                   1754:        return mr;
                   1755:     
                   1756:     if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
                   1757:        return MACH_MSG_SUCCESS;
                   1758:     
                   1759:     return( ipc_kmsg_copyin_body( kmsg, space, map) );
                   1760: }
                   1761: 
                   1762: /*
                   1763:  *     Routine:        ipc_kmsg_copyin_from_kernel
                   1764:  *     Purpose:
                   1765:  *             "Copy-in" port rights and out-of-line memory
                   1766:  *             in a message sent from the kernel.
                   1767:  *
                   1768:  *             Because the message comes from the kernel,
                   1769:  *             the implementation assumes there are no errors
                   1770:  *             or peculiarities in the message.
                   1771:  *
                   1772:  *             Returns TRUE if queueing the message
                   1773:  *             would result in a circularity.
                   1774:  *     Conditions:
                   1775:  *             Nothing locked.
                   1776:  */
                   1777: 
                   1778: void
                   1779: ipc_kmsg_copyin_from_kernel(
                   1780:        ipc_kmsg_t      kmsg)
                   1781: {
                   1782:        mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
                   1783:        mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
                   1784:        mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
                   1785:        ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   1786:        ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   1787: 
                   1788:        /* translate the destination and reply ports */
                   1789: 
                   1790:        ipc_object_copyin_from_kernel(remote, rname);
                   1791:        if (IO_VALID(local))
                   1792:                ipc_object_copyin_from_kernel(local, lname);
                   1793: 
                   1794:        /*
                   1795:         *      The common case is a complex message with no reply port,
                   1796:         *      because that is what the memory_object interface uses.
                   1797:         */
                   1798: 
                   1799:        if (bits == (MACH_MSGH_BITS_COMPLEX |
                   1800:                     MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
                   1801:                bits = (MACH_MSGH_BITS_COMPLEX |
                   1802:                        MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
                   1803: 
                   1804:                kmsg->ikm_header.msgh_bits = bits;
                   1805:        } else {
                   1806:                bits = (MACH_MSGH_BITS_OTHER(bits) |
                   1807:                        MACH_MSGH_BITS(ipc_object_copyin_type(rname),
                   1808:                                       ipc_object_copyin_type(lname)));
                   1809: 
                   1810:                kmsg->ikm_header.msgh_bits = bits;
                   1811:                if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
                   1812:                        return;
                   1813:        }
                   1814:     {
                   1815:        mach_msg_descriptor_t   *saddr, *eaddr;
                   1816:        mach_msg_body_t         *body;
                   1817: 
                   1818:        body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   1819:        saddr = (mach_msg_descriptor_t *) (body + 1);
                   1820:        eaddr = (mach_msg_descriptor_t *) saddr + body->msgh_descriptor_count;
                   1821: 
                   1822:        for ( ; saddr <  eaddr; saddr++) {
                   1823: 
                   1824:            switch (saddr->type.type) {
                   1825:            
                   1826:                case MACH_MSG_PORT_DESCRIPTOR: {
                   1827:                    mach_msg_type_name_t        name;
                   1828:                    ipc_object_t                object;
                   1829:                    mach_msg_port_descriptor_t  *dsc;
                   1830:                
                   1831:                    dsc = &saddr->port;
                   1832:                
                   1833:                    /* this is really the type SEND, SEND_ONCE, etc. */
                   1834:                    name = dsc->disposition;
                   1835:                    object = (ipc_object_t) dsc->name;
                   1836:                    dsc->disposition = ipc_object_copyin_type(name);
                   1837:                
                   1838:                    if (!IO_VALID(object)) {
                   1839:                        break;
                   1840:                    }
                   1841: 
                   1842:                    ipc_object_copyin_from_kernel(object, name);
                   1843:                    
                   1844:                    /* CDY avoid circularity when the destination is also */
                   1845:                    /* the kernel.  This check should be changed into an  */
                   1846:                    /* assert when the new kobject model is in place since*/
                   1847:                    /* ports will not be used in kernel to kernel chats   */
                   1848:                        
                   1849:                    if (((ipc_port_t)remote)->ip_receiver != ipc_space_kernel) {
                   1850:                       if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1851:                           ipc_port_check_circularity((ipc_port_t) object, 
                   1852:                                                (ipc_port_t) remote)) {
                   1853:                           kmsg->ikm_header.msgh_bits |= 
                   1854:                                        MACH_MSGH_BITS_CIRCULAR;
                   1855:                       }
                   1856:                    }
                   1857:                    break;
                   1858:                }
                   1859:                case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
                   1860:                case MACH_MSG_OOL_DESCRIPTOR: {
                   1861:                    /*
                   1862:                     * The sender should supply ready-made memory, i.e.
                   1863:                     * a vm_map_copy_t, so we don't need to do anything.
                   1864:                     */
                   1865:                    break;
                   1866:                }
                   1867:                case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
                   1868:                    ipc_object_t                        *objects;
                   1869:                    int                                 j;
                   1870:                    mach_msg_type_name_t                name;
                   1871:                    mach_msg_ool_ports_descriptor_t     *dsc;
                   1872:                
                   1873:                    dsc = &saddr->ool_ports;
                   1874: 
                   1875:                    /* this is really the type SEND, SEND_ONCE, etc. */
                   1876:                    name = dsc->disposition;
                   1877:                    dsc->disposition = ipc_object_copyin_type(name);
                   1878:                
                   1879:                    objects = (ipc_object_t *) dsc->address;
                   1880:                
                   1881:                    for ( j = 0; j < dsc->count; j++) {
                   1882:                        ipc_object_t object = objects[j];
                   1883:                        
                   1884:                        if (!IO_VALID(object))
                   1885:                            continue;
                   1886:                        
                   1887:                        ipc_object_copyin_from_kernel(object, name);
                   1888:     
                   1889:                        if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
                   1890:                            ipc_port_check_circularity(
                   1891:                                                       (ipc_port_t) object,
                   1892:                                                       (ipc_port_t) remote))
                   1893:                            kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
                   1894:                    }
                   1895:                    break;
                   1896:                }
                   1897:                default: {
                   1898: #if    MACH_ASSERT
                   1899:                    panic("ipc_kmsg_copyin_from_kernel:  bad descriptor");
                   1900: #endif /* MACH_ASSERT */
                   1901:                }
                   1902:            }
                   1903:        }
                   1904:     }
                   1905: }
                   1906: 
                   1907: /*
                   1908:  *     Routine:        ipc_kmsg_copyout_header
                   1909:  *     Purpose:
                   1910:  *             "Copy-out" port rights in the header of a message.
                   1911:  *             Operates atomically; if it doesn't succeed the
                   1912:  *             message header and the space are left untouched.
                   1913:  *             If it does succeed the remote/local port fields
                   1914:  *             contain port names instead of object pointers,
                   1915:  *             and the bits field is updated.
                   1916:  *
                   1917:  *             The notify argument implements the MACH_RCV_NOTIFY option.
                   1918:  *             If it is not MACH_PORT_NULL, it should name a receive right.
                   1919:  *             If the process of receiving the reply port creates a
                   1920:  *             new right in the receiving task, then the new right is
                   1921:  *             automatically registered for a dead-name notification,
                   1922:  *             with the notify port supplying the send-once right.
                   1923:  *     Conditions:
                   1924:  *             Nothing locked.
                   1925:  *     Returns:
                   1926:  *             MACH_MSG_SUCCESS        Copied out port rights.
                   1927:  *             MACH_RCV_INVALID_NOTIFY 
                   1928:  *                     Notify is non-null and doesn't name a receive right.
                   1929:  *                     (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
                   1930:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
                   1931:  *                     The space is dead.
                   1932:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
                   1933:  *                     No room in space for another name.
                   1934:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
                   1935:  *                     Couldn't allocate memory for the reply port.
                   1936:  *             MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
                   1937:  *                     Couldn't allocate memory for the dead-name request.
                   1938:  */
                   1939: 
                   1940: mach_msg_return_t
                   1941: ipc_kmsg_copyout_header(
                   1942:        mach_msg_header_t       *msg,
                   1943:        ipc_space_t             space,
                   1944:        mach_port_name_t        notify)
                   1945: {
                   1946:        mach_msg_bits_t mbits = msg->msgh_bits;
                   1947:        ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
                   1948: 
                   1949:        assert(IP_VALID(dest));
                   1950: 
                   1951:     {
                   1952:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   1953:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   1954:        ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
                   1955:        mach_port_name_t dest_name, reply_name;
                   1956: 
                   1957:        if (IP_VALID(reply)) {
                   1958:                ipc_port_t notify_port;
                   1959:                ipc_entry_t entry;
                   1960:                kern_return_t kr;
                   1961: 
                   1962:                /*
                   1963:                 *      Handling notify (for MACH_RCV_NOTIFY) is tricky.
                   1964:                 *      The problem is atomically making a send-once right
                   1965:                 *      from the notify port and installing it for a
                   1966:                 *      dead-name request in the new entry, because this
                   1967:                 *      requires two port locks (on the notify port and
                   1968:                 *      the reply port).  However, we can safely make
                   1969:                 *      and consume send-once rights for the notify port
                   1970:                 *      as long as we hold the space locked.  This isn't
                   1971:                 *      an atomicity problem, because the only way
                   1972:                 *      to detect that a send-once right has been created
                   1973:                 *      and then consumed if it wasn't needed is by getting
                   1974:                 *      at the receive right to look at ip_sorights, and
                   1975:                 *      because the space is write-locked status calls can't
                   1976:                 *      lookup the notify port receive right.  When we make
                   1977:                 *      the send-once right, we lock the notify port,
                   1978:                 *      so any status calls in progress will be done.
                   1979:                 */
                   1980: 
                   1981:                is_write_lock(space);
                   1982: 
                   1983:                for (;;) {
                   1984:                        ipc_port_request_index_t request;
                   1985: 
                   1986:                        if (!space->is_active) {
                   1987:                                is_write_unlock(space);
                   1988:                                return (MACH_RCV_HEADER_ERROR|
                   1989:                                        MACH_MSG_IPC_SPACE);
                   1990:                        }
                   1991: 
                   1992:                        if (notify != MACH_PORT_NULL) {
                   1993:                                notify_port = ipc_port_lookup_notify(space,
                   1994:                                                                     notify);
                   1995:                                if (notify_port == IP_NULL) {
                   1996:                                        is_write_unlock(space);
                   1997:                                        return MACH_RCV_INVALID_NOTIFY;
                   1998:                                }
                   1999:                        } else
                   2000:                                notify_port = IP_NULL;
                   2001: 
                   2002:                        if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
                   2003:                            ipc_right_reverse(space, (ipc_object_t) reply,
                   2004:                                              &reply_name, &entry)) {
                   2005:                                /* reply port is locked and active */
                   2006: 
                   2007:                                /*
                   2008:                                 *      We don't need the notify_port
                   2009:                                 *      send-once right, but we can't release
                   2010:                                 *      it here because reply port is locked.
                   2011:                                 *      Wait until after the copyout to
                   2012:                                 *      release the notify port right.
                   2013:                                 */
                   2014: 
                   2015:                                assert(entry->ie_bits &
                   2016:                                       MACH_PORT_TYPE_SEND_RECEIVE);
                   2017:                                break;
                   2018:                        }
                   2019: 
                   2020:                        ip_lock(reply);
                   2021:                        if (!ip_active(reply)) {
                   2022:                                ip_release(reply);
                   2023:                                ip_check_unlock(reply);
                   2024: 
                   2025:                                if (notify_port != IP_NULL)
                   2026:                                        ipc_port_release_sonce(notify_port);
                   2027: 
                   2028:                                ip_lock(dest);
                   2029:                                is_write_unlock(space);
                   2030: 
                   2031:                                reply = IP_DEAD;
                   2032:                                reply_name = MACH_PORT_DEAD;
                   2033:                                goto copyout_dest;
                   2034:                        }
                   2035: 
                   2036:                        reply_name = (mach_port_name_t)reply;
                   2037:                        kr = ipc_entry_get(space, &reply_name, &entry);
                   2038:                        if (kr != KERN_SUCCESS) {
                   2039:                                ip_unlock(reply);
                   2040: 
                   2041:                                if (notify_port != IP_NULL)
                   2042:                                        ipc_port_release_sonce(notify_port);
                   2043: 
                   2044:                                /* space is locked */
                   2045:                                kr = ipc_entry_grow_table(space,
                   2046:                                                          ITS_SIZE_NONE);
                   2047:                                if (kr != KERN_SUCCESS) {
                   2048:                                        /* space is unlocked */
                   2049: 
                   2050:                                        if (kr == KERN_RESOURCE_SHORTAGE)
                   2051:                                                return (MACH_RCV_HEADER_ERROR|
                   2052:                                                        MACH_MSG_IPC_KERNEL);
                   2053:                                        else
                   2054:                                                return (MACH_RCV_HEADER_ERROR|
                   2055:                                                        MACH_MSG_IPC_SPACE);
                   2056:                                }
                   2057:                                /* space is locked again; start over */
                   2058: 
                   2059:                                continue;
                   2060:                        }
                   2061:                        assert(IE_BITS_TYPE(entry->ie_bits) ==
                   2062:                               MACH_PORT_TYPE_NONE);
                   2063:                        assert(entry->ie_object == IO_NULL); 
                   2064: 
                   2065:                        if (notify_port == IP_NULL) {
                   2066:                                /* not making a dead-name request */
                   2067: 
                   2068:                                entry->ie_object = (ipc_object_t) reply;
                   2069:                                break;
                   2070:                        }
                   2071: 
                   2072:                        kr = ipc_port_dnrequest(reply, reply_name,
                   2073:                                                notify_port, &request);
                   2074:                        if (kr != KERN_SUCCESS) {
                   2075:                                ip_unlock(reply);
                   2076: 
                   2077:                                ipc_port_release_sonce(notify_port);
                   2078: 
                   2079:                                ipc_entry_dealloc(space, reply_name, entry);
                   2080:                                is_write_unlock(space);
                   2081: 
                   2082:                                ip_lock(reply);
                   2083:                                if (!ip_active(reply)) {
                   2084:                                        /* will fail next time around loop */
                   2085: 
                   2086:                                        ip_unlock(reply);
                   2087:                                        is_write_lock(space);
                   2088:                                        continue;
                   2089:                                }
                   2090: 
                   2091:                                kr = ipc_port_dngrow(reply, ITS_SIZE_NONE);
                   2092:                                /* port is unlocked */
                   2093:                                if (kr != KERN_SUCCESS)
                   2094:                                        return (MACH_RCV_HEADER_ERROR|
                   2095:                                                MACH_MSG_IPC_KERNEL);
                   2096: 
                   2097:                                is_write_lock(space);
                   2098:                                continue;
                   2099:                        }
                   2100: 
                   2101:                        notify_port = IP_NULL; /* don't release right below */
                   2102: 
                   2103:                        entry->ie_object = (ipc_object_t) reply;
                   2104:                        entry->ie_request = request;
                   2105:                        break;
                   2106:                }
                   2107: 
                   2108:                /* space and reply port are locked and active */
                   2109: 
                   2110:                ip_reference(reply);    /* hold onto the reply port */
                   2111: 
                   2112:                kr = ipc_right_copyout(space, reply_name, entry,
                   2113:                                       reply_type, TRUE, (ipc_object_t) reply);
                   2114:                /* reply port is unlocked */
                   2115:                assert(kr == KERN_SUCCESS);
                   2116: 
                   2117:                if (notify_port != IP_NULL)
                   2118:                        ipc_port_release_sonce(notify_port);
                   2119: 
                   2120:                ip_lock(dest);
                   2121:                is_write_unlock(space);
                   2122:        } else {
                   2123:                /*
                   2124:                 *      No reply port!  This is an easy case.
                   2125:                 *      We only need to have the space locked
                   2126:                 *      when checking notify and when locking
                   2127:                 *      the destination (to ensure atomicity).
                   2128:                 */
                   2129: 
                   2130:                is_read_lock(space);
                   2131:                if (!space->is_active) {
                   2132:                        is_read_unlock(space);
                   2133:                        return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
                   2134:                }
                   2135: 
                   2136:                if (notify != MACH_PORT_NULL) {
                   2137:                        ipc_entry_t entry;
                   2138: 
                   2139:                        /* must check notify even though it won't be used */
                   2140: 
                   2141:                        if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) {
                   2142:                                is_read_unlock(space);
                   2143:                                return MACH_RCV_INVALID_NOTIFY;
                   2144:                        }
                   2145:        
                   2146:                        if ((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_name_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 = (ipc_port_t)dest_name;
                   2237:        msg->msgh_remote_port = (ipc_port_t)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(
                   2262:        ipc_space_t             space,
                   2263:        ipc_object_t            object,
                   2264:        mach_msg_type_name_t    msgt_name,
                   2265:        mach_port_name_t        *namep)
                   2266: {
                   2267:        kern_return_t kr;
                   2268: 
                   2269:        if (!IO_VALID(object)) {
                   2270:                *namep = (mach_port_name_t) object;
                   2271:                return MACH_MSG_SUCCESS;
                   2272:        }
                   2273: 
                   2274:        kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
                   2275:        if (kr != KERN_SUCCESS) {
                   2276:                ipc_object_destroy(object, msgt_name);
                   2277: 
                   2278:                if (kr == KERN_INVALID_CAPABILITY)
                   2279:                        *namep = MACH_PORT_DEAD;
                   2280:                else {
                   2281:                        *namep = MACH_PORT_NULL;
                   2282: 
                   2283:                        if (kr == KERN_RESOURCE_SHORTAGE)
                   2284:                                return MACH_MSG_IPC_KERNEL;
                   2285:                        else
                   2286:                                return MACH_MSG_IPC_SPACE;
                   2287:                }
                   2288:        }
                   2289: 
                   2290:        return MACH_MSG_SUCCESS;
                   2291: }
                   2292: 
                   2293: /*
                   2294:  *     Routine:        ipc_kmsg_copyout_body
                   2295:  *     Purpose:
                   2296:  *             "Copy-out" port rights and out-of-line memory
                   2297:  *             in the body of a message.
                   2298:  *
                   2299:  *             The error codes are a combination of special bits.
                   2300:  *             The copyout proceeds despite errors.
                   2301:  *     Conditions:
                   2302:  *             Nothing locked.
                   2303:  *     Returns:
                   2304:  *             MACH_MSG_SUCCESS        Successful copyout.
                   2305:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
                   2306:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
                   2307:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
                   2308:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
                   2309:  *             MACH_MSG_INVALID_RT_DESCRIPTOR Descriptor incompatible with RT
                   2310:  */
                   2311: 
                   2312: mach_msg_return_t
                   2313: ipc_kmsg_copyout_body(
                   2314:        ipc_kmsg_t              kmsg,
                   2315:        ipc_space_t             space,
                   2316:        vm_map_t                map,
                   2317:        mach_msg_body_t         *slist)
                   2318: {
                   2319:     mach_msg_body_t            *body;
                   2320:     mach_msg_descriptor_t      *saddr, *eaddr;
                   2321:     mach_msg_return_t          mr = MACH_MSG_SUCCESS;
                   2322:     kern_return_t              kr;
                   2323:     vm_offset_t                data;
                   2324:     mach_msg_descriptor_t      *sstart, *send;
                   2325: #if    MACH_RT
                   2326:     boolean_t                  rt;
                   2327: #endif /* MACH_RT */
                   2328: 
                   2329:     body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   2330:     saddr = (mach_msg_descriptor_t *) (body + 1);
                   2331:     eaddr = saddr + body->msgh_descriptor_count;
                   2332: #if    MACH_RT
                   2333:     rt = KMSG_IS_RT(kmsg);
                   2334: #endif /* MACH_RT */
                   2335: 
                   2336:     /*
                   2337:      * Do scatter list setup
                   2338:      */
                   2339:     if (slist != MACH_MSG_BODY_NULL) {
                   2340:        sstart = (mach_msg_descriptor_t *) (slist + 1);
                   2341:        send = sstart + slist->msgh_descriptor_count;
                   2342:     }
                   2343:     else {
                   2344:        sstart = MACH_MSG_DESCRIPTOR_NULL;
                   2345:     }
                   2346: 
                   2347:     for ( ; saddr < eaddr; saddr++ ) {
                   2348:        
                   2349:        switch (saddr->type.type) {
                   2350:            
                   2351:            case MACH_MSG_PORT_DESCRIPTOR: {
                   2352:                mach_msg_port_descriptor_t *dsc;
                   2353:                
                   2354:                /* 
                   2355:                 * Copyout port right carried in the message 
                   2356:                 */
                   2357:                dsc = &saddr->port;
                   2358:                mr |= ipc_kmsg_copyout_object(space, 
                   2359:                                              (ipc_object_t) dsc->name, 
                   2360:                                              dsc->disposition, 
                   2361:                                              (mach_port_name_t *) &dsc->name);
                   2362: 
                   2363:                break;
                   2364:            }
                   2365:            case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
                   2366:            case MACH_MSG_OOL_DESCRIPTOR : {
                   2367:                vm_offset_t                     rcv_addr;
                   2368:                vm_offset_t                     snd_addr;
                   2369:                mach_msg_ool_descriptor_t       *dsc;
                   2370:                mach_msg_copy_options_t         copy_option;
                   2371: 
                   2372:                SKIP_PORT_DESCRIPTORS(sstart, send);
                   2373: 
                   2374:                dsc = &saddr->out_of_line;
                   2375: 
                   2376:                assert(dsc->copy != MACH_MSG_KALLOC_COPY_T);
                   2377:                assert(dsc->copy != MACH_MSG_PAGE_LIST_COPY_T);
                   2378: 
                   2379:                copy_option = dsc->copy;
                   2380: 
                   2381:                if ((snd_addr = (vm_offset_t) dsc->address) != 0) {
                   2382:                    if (sstart != MACH_MSG_DESCRIPTOR_NULL &&
                   2383:                        sstart->out_of_line.copy == MACH_MSG_OVERWRITE) {
                   2384: 
                   2385:                        /*
                   2386:                         * There is an overwrite descriptor specified in the
                   2387:                         * scatter list for this ool data.  The descriptor
                   2388:                         * has already been verified
                   2389:                         */
                   2390:                        rcv_addr = (vm_offset_t) sstart->out_of_line.address;
                   2391:                        dsc->copy = MACH_MSG_OVERWRITE;
                   2392:                    } else {
                   2393:                        dsc->copy = MACH_MSG_ALLOCATE;
                   2394:                    }
                   2395:                        
                   2396:                    if (copy_option == MACH_MSG_PHYSICAL_COPY &&
                   2397:                            dsc->size < MSG_OOL_SIZE_SMALL(rt)) {
                   2398: 
                   2399:                        /* 
                   2400:                         * Sufficiently 'small' data was copied into a kalloc'ed
                   2401:                         * buffer copy was requested.  Just copy it out and 
                   2402:                         * free the buffer.
                   2403:                         */
                   2404:                        if (dsc->copy == MACH_MSG_ALLOCATE) {
                   2405: #if    MACH_RT                     
                   2406:                            /*
                   2407:                             * The MACH_MSG_ALLOCATE option is not
                   2408:                             * compatible with RT behavior.
                   2409:                             */
                   2410:                            if (rt) {
                   2411:                                mr |= MACH_MSG_INVALID_RT_DESCRIPTOR;
                   2412:                                KFREE(snd_addr, dsc->size, rt);
                   2413:                                dsc->address = (void *) 0;
                   2414:                                INCREMENT_SCATTER(sstart);
                   2415:                                break;
                   2416:                            }
                   2417: #endif /* MACH_RT */
                   2418: 
                   2419:                            /*
                   2420:                             * If there is no overwrite region, allocate
                   2421:                             * space in receiver's address space for the
                   2422:                             * data
                   2423:                             */
                   2424:                            if ((kr = vm_allocate(map, &rcv_addr, dsc->size, 
                   2425:                                        TRUE)) != KERN_SUCCESS) {
                   2426:                                if (kr == KERN_RESOURCE_SHORTAGE)
                   2427:                                        mr |= MACH_MSG_VM_KERNEL;
                   2428:                                else
                   2429:                                        mr |= MACH_MSG_VM_SPACE;
                   2430:                                KFREE(snd_addr, dsc->size, rt);
                   2431:                                dsc->address = (void *) 0;
                   2432:                                INCREMENT_SCATTER(sstart);
                   2433:                                break;
                   2434:                            }
                   2435:                        }
                   2436:                        (void) copyoutmap(map, snd_addr, rcv_addr, dsc->size);
                   2437:                        KFREE(snd_addr, dsc->size, rt);
                   2438:                    } else {
                   2439: 
                   2440:                        /*
                   2441:                         * Whether the data was virtually or physically
                   2442:                         * copied we have a vm_map_copy_t for it.
                   2443:                         * If there's an overwrite region specified
                   2444:                         * overwrite it, otherwise do a virtual copy out.
                   2445:                         */
                   2446:                        if (dsc->copy == MACH_MSG_OVERWRITE) {
                   2447:                            kr = vm_map_copy_overwrite(map, rcv_addr,
                   2448:                                        (vm_map_copy_t) dsc->address, TRUE);
                   2449:                        } else {
                   2450:                            kr = vm_map_copyout(map, &rcv_addr, 
                   2451:                                                (vm_map_copy_t) dsc->address);
                   2452:                        }       
                   2453:                        if (kr != KERN_SUCCESS) {
                   2454:                            if (kr == KERN_RESOURCE_SHORTAGE)
                   2455:                                mr |= MACH_MSG_VM_KERNEL;
                   2456:                            else
                   2457:                                mr |= MACH_MSG_VM_SPACE;
                   2458:                            vm_map_copy_discard((vm_map_copy_t) dsc->address);
                   2459:                            dsc->address = 0;
                   2460:                            INCREMENT_SCATTER(sstart);
                   2461:                            break;
                   2462:                        }
                   2463:                    }
                   2464:                    dsc->address = (void *) rcv_addr;
                   2465:                }
                   2466:                INCREMENT_SCATTER(sstart);
                   2467:                break;
                   2468:            }
                   2469:            case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
                   2470:                vm_offset_t                     addr;
                   2471:                mach_port_name_t                *objects;
                   2472:                mach_msg_type_number_t          j;
                   2473:                vm_size_t                       length;
                   2474:                mach_msg_ool_ports_descriptor_t *dsc;
                   2475: 
                   2476:                SKIP_PORT_DESCRIPTORS(sstart, send);
                   2477: 
                   2478:                dsc = &saddr->ool_ports;
                   2479: 
                   2480:                length = dsc->count * sizeof(mach_port_name_t);
                   2481: 
                   2482:                if (length != 0) {
                   2483:                    if (sstart != MACH_MSG_DESCRIPTOR_NULL &&
                   2484:                        sstart->ool_ports.copy == MACH_MSG_OVERWRITE) {
                   2485: 
                   2486:                        /*
                   2487:                         * There is an overwrite descriptor specified in the
                   2488:                         * scatter list for this ool data.  The descriptor
                   2489:                         * has already been verified
                   2490:                         */
                   2491:                        addr = (vm_offset_t) sstart->out_of_line.address;
                   2492:                        dsc->copy = MACH_MSG_OVERWRITE;
                   2493:                    } 
                   2494:                    else {
                   2495: #if    MACH_RT                     
                   2496:                        /*
                   2497:                         * The MACH_MSG_ALLOCATE option is not
                   2498:                         * compatible with RT behavior.
                   2499:                         */
                   2500:                        if (rt) {
                   2501:                            mr |= MACH_MSG_INVALID_RT_DESCRIPTOR;
                   2502:                            ipc_kmsg_clean_body(kmsg,
                   2503:                                                body->msgh_descriptor_count);
                   2504:                            dsc->address = 0;
                   2505:                            INCREMENT_SCATTER(sstart);
                   2506:                            break;
                   2507:                        }
                   2508: #endif /* MACH_RT */
                   2509: 
                   2510:                        /*
                   2511:                         * Dynamically allocate the region
                   2512:                         */
                   2513:                        dsc->copy = MACH_MSG_ALLOCATE;
                   2514:                        if ((kr = vm_allocate(map, &addr, length, TRUE)) !=
                   2515:                                                                KERN_SUCCESS) {
                   2516:                            ipc_kmsg_clean_body(kmsg,
                   2517:                                                body->msgh_descriptor_count);
                   2518:                            dsc->address = 0;
                   2519: 
                   2520:                            if (kr == KERN_RESOURCE_SHORTAGE){
                   2521:                                mr |= MACH_MSG_VM_KERNEL;
                   2522:                            } else {
                   2523:                                mr |= MACH_MSG_VM_SPACE;
                   2524:                            }
                   2525:                            INCREMENT_SCATTER(sstart);
                   2526:                            break;
                   2527:                        }
                   2528:                    }
                   2529:                } else {
                   2530:                    INCREMENT_SCATTER(sstart);
                   2531:                    break;
                   2532:                }
                   2533: 
                   2534:                
                   2535:                objects = (mach_port_name_t *) dsc->address ;
                   2536:                
                   2537:                /* copyout port rights carried in the message */
                   2538:                
                   2539:                for ( j = 0; j < dsc->count ; j++) {
                   2540:                    ipc_object_t object =
                   2541:                        (ipc_object_t) objects[j];
                   2542:                    
                   2543:                    mr |= ipc_kmsg_copyout_object(space, object,
                   2544:                                        dsc->disposition, &objects[j]);
                   2545:                }
                   2546: 
                   2547:                /* copyout to memory allocated above */
                   2548:                
                   2549:                data = (vm_offset_t) dsc->address;
                   2550:                (void) copyoutmap(map, data, addr, length);
                   2551:                KFREE(data, length, rt);
                   2552:                
                   2553:                dsc->address = (void *) addr;
                   2554:                INCREMENT_SCATTER(sstart);
                   2555:                break;
                   2556:            }
                   2557:            default : {
                   2558:                panic("untyped IPC copyout body: invalid message descriptor");
                   2559:            }
                   2560:        }
                   2561:     }
                   2562:     return mr;
                   2563: }
                   2564: 
                   2565: /*
                   2566:  *     Routine:        ipc_kmsg_copyout
                   2567:  *     Purpose:
                   2568:  *             "Copy-out" port rights and out-of-line memory
                   2569:  *             in the message.
                   2570:  *     Conditions:
                   2571:  *             Nothing locked.
                   2572:  *     Returns:
                   2573:  *             MACH_MSG_SUCCESS        Copied out all rights and memory.
                   2574:  *             MACH_RCV_INVALID_NOTIFY Bad notify port.
                   2575:  *                     Rights and memory in the message are intact.
                   2576:  *             MACH_RCV_HEADER_ERROR + special bits
                   2577:  *                     Rights and memory in the message are intact.
                   2578:  *             MACH_RCV_BODY_ERROR + special bits
                   2579:  *                     The message header was successfully copied out.
                   2580:  *                     As much of the body was handled as possible.
                   2581:  */
                   2582: 
                   2583: mach_msg_return_t
                   2584: ipc_kmsg_copyout(
                   2585:        ipc_kmsg_t              kmsg,
                   2586:        ipc_space_t             space,
                   2587:        vm_map_t                map,
                   2588:        mach_port_name_t        notify,
                   2589:        mach_msg_body_t         *slist)
                   2590: {
                   2591:        mach_msg_return_t mr;
                   2592: 
                   2593:        mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
                   2594:        if (mr != MACH_MSG_SUCCESS)
                   2595:                return mr;
                   2596: 
                   2597:        if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
                   2598:                mr = ipc_kmsg_copyout_body(kmsg, space, map, slist);
                   2599: 
                   2600:                if (mr != MACH_MSG_SUCCESS)
                   2601:                        mr |= MACH_RCV_BODY_ERROR;
                   2602:        }
                   2603: 
                   2604:        return mr;
                   2605: }
                   2606: 
                   2607: /*
                   2608:  *     Routine:        ipc_kmsg_copyout_pseudo
                   2609:  *     Purpose:
                   2610:  *             Does a pseudo-copyout of the message.
                   2611:  *             This is like a regular copyout, except
                   2612:  *             that the ports in the header are handled
                   2613:  *             as if they are in the body.  They aren't reversed.
                   2614:  *
                   2615:  *             The error codes are a combination of special bits.
                   2616:  *             The copyout proceeds despite errors.
                   2617:  *     Conditions:
                   2618:  *             Nothing locked.
                   2619:  *     Returns:
                   2620:  *             MACH_MSG_SUCCESS        Successful copyout.
                   2621:  *             MACH_MSG_IPC_SPACE      No room for port right in name space.
                   2622:  *             MACH_MSG_VM_SPACE       No room for memory in address space.
                   2623:  *             MACH_MSG_IPC_KERNEL     Resource shortage handling port right.
                   2624:  *             MACH_MSG_VM_KERNEL      Resource shortage handling memory.
                   2625:  */
                   2626: 
                   2627: mach_msg_return_t
                   2628: ipc_kmsg_copyout_pseudo(
                   2629:        ipc_kmsg_t              kmsg,
                   2630:        ipc_space_t             space,
                   2631:        vm_map_t                map,
                   2632:        mach_msg_body_t         *slist)
                   2633: {
                   2634:        mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
                   2635:        ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   2636:        ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   2637:        mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   2638:        mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   2639:        mach_port_name_t dest_name, reply_name;
                   2640:        mach_msg_return_t mr;
                   2641: 
                   2642:        assert(IO_VALID(dest));
                   2643: 
                   2644:        mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
                   2645:              ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
                   2646: 
                   2647:        kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
                   2648:        kmsg->ikm_header.msgh_remote_port = (ipc_port_t)dest_name;
                   2649:        kmsg->ikm_header.msgh_local_port = (ipc_port_t)reply_name;
                   2650: 
                   2651:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   2652:                mr |= ipc_kmsg_copyout_body(kmsg, space, map, slist);
                   2653:        }
                   2654: 
                   2655:        return mr;
                   2656: }
                   2657: 
                   2658: /*
                   2659:  *     Routine:        ipc_kmsg_copyout_dest
                   2660:  *     Purpose:
                   2661:  *             Copies out the destination port in the message.
                   2662:  *             Destroys all other rights and memory in the message.
                   2663:  *     Conditions:
                   2664:  *             Nothing locked.
                   2665:  */
                   2666: 
                   2667: void
                   2668: ipc_kmsg_copyout_dest(
                   2669:        ipc_kmsg_t      kmsg,
                   2670:        ipc_space_t     space)
                   2671: {
                   2672:        mach_msg_bits_t mbits;
                   2673:        ipc_object_t dest;
                   2674:        ipc_object_t reply;
                   2675:        mach_msg_type_name_t dest_type;
                   2676:        mach_msg_type_name_t reply_type;
                   2677:        mach_port_name_t dest_name, reply_name;
                   2678: 
                   2679:        mbits = kmsg->ikm_header.msgh_bits;
                   2680:        dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   2681:        reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   2682:        dest_type = MACH_MSGH_BITS_REMOTE(mbits);
                   2683:        reply_type = MACH_MSGH_BITS_LOCAL(mbits);
                   2684: 
                   2685:        assert(IO_VALID(dest));
                   2686: 
                   2687:        io_lock(dest);
                   2688:        if (io_active(dest)) {
                   2689:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                   2690:                /* dest is unlocked */
                   2691:        } else {
                   2692:                io_release(dest);
                   2693:                io_check_unlock(dest);
                   2694:                dest_name = MACH_PORT_DEAD;
                   2695:        }
                   2696: 
                   2697:        if (IO_VALID(reply)) {
                   2698:                ipc_object_destroy(reply, reply_type);
                   2699:                reply_name = MACH_PORT_NULL;
                   2700:        } else
                   2701:                reply_name = (mach_port_name_t) reply;
                   2702: 
                   2703:        kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
                   2704:                                      MACH_MSGH_BITS(reply_type, dest_type));
                   2705:        kmsg->ikm_header.msgh_local_port = (ipc_port_t)dest_name;
                   2706:        kmsg->ikm_header.msgh_remote_port = (ipc_port_t)reply_name;
                   2707: 
                   2708:        if (mbits & MACH_MSGH_BITS_COMPLEX) {
                   2709:                mach_msg_body_t *body;
                   2710: 
                   2711:                body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   2712:                ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count);
                   2713:        }
                   2714: }
                   2715: 
                   2716: /*
                   2717:  *     Routine:        ipc_kmsg_check_scatter
                   2718:  *     Purpose:
                   2719:  *             Checks scatter and gather lists for consistency.
                   2720:  *             
                   2721:  *     Algorithm:
                   2722:  *             The gather is assumed valid since it has been copied in.
                   2723:  *             The scatter list has only been range checked.
                   2724:  *             Gather list descriptors are sequentially paired with scatter 
                   2725:  *             list descriptors, with port descriptors in either list ignored.
                   2726:  *             Descriptors are consistent if the type fileds match and size
                   2727:  *             of the scatter descriptor is less than or equal to the
                   2728:  *             size of the gather descriptor.  A MACH_MSG_ALLOCATE copy 
                   2729:  *             strategy in a scatter descriptor matches any size in the 
                   2730:  *             corresponding gather descriptor assuming they are the same type.
                   2731:  *             Either list may be larger than the other.  During the
                   2732:  *             subsequent copy out, excess scatter descriptors are ignored
                   2733:  *             and excess gather descriptors default to dynamic allocation.
                   2734:  *             
                   2735:  *             In the case of a size error, a new scatter list is formed
                   2736:  *             from the gather list copying only the size and type fields.
                   2737:  *             
                   2738:  *     Conditions:
                   2739:  *             Nothing locked.
                   2740:  *     Returns:
                   2741:  *             MACH_MSG_SUCCESS                Lists are consistent
                   2742:  *             MACH_RCV_INVALID_TYPE           Scatter type does not match
                   2743:  *                                             gather type
                   2744:  *             MACH_RCV_SCATTER_SMALL          Scatter size less than gather
                   2745:  *                                             size
                   2746:  */
                   2747: 
                   2748: mach_msg_return_t
                   2749: ipc_kmsg_check_scatter(
                   2750:        ipc_kmsg_t              kmsg,
                   2751:        mach_msg_option_t       option,
                   2752:        mach_msg_body_t         **slistp,
                   2753:        mach_msg_size_t         *sizep)
                   2754: {
                   2755:        mach_msg_body_t         *body;
                   2756:        mach_msg_descriptor_t   *gstart, *gend;
                   2757:        mach_msg_descriptor_t   *sstart, *send;
                   2758:        mach_msg_return_t       mr = MACH_MSG_SUCCESS;
                   2759: 
                   2760:        assert(*slistp != MACH_MSG_BODY_NULL);
                   2761:        assert(*sizep != 0);
                   2762: 
                   2763:        body = (mach_msg_body_t *) (&kmsg->ikm_header + 1);
                   2764:        gstart = (mach_msg_descriptor_t *) (body + 1);
                   2765:        gend = gstart + body->msgh_descriptor_count;
                   2766: 
                   2767:        sstart = (mach_msg_descriptor_t *) (*slistp + 1);
                   2768:        send = sstart + (*slistp)->msgh_descriptor_count;
                   2769: 
                   2770:        while (gstart < gend) {
                   2771:            mach_msg_descriptor_type_t  g_type;
                   2772: 
                   2773:            /*
                   2774:             * Skip port descriptors in gather list. 
                   2775:             */
                   2776:            g_type = gstart->type.type;
                   2777: 
                   2778:            if (g_type != MACH_MSG_PORT_DESCRIPTOR) {
                   2779: 
                   2780:                /*
                   2781:                 * A scatter list with a 0 descriptor count is treated as an
                   2782:                 * automatic size mismatch.
                   2783:                 */
                   2784:                 if ((*slistp)->msgh_descriptor_count == 0) {
                   2785:                        return(MACH_RCV_SCATTER_SMALL);
                   2786:                 }
                   2787: 
                   2788:                /*
                   2789:                 * Skip port descriptors in  scatter list.
                   2790:                 */
                   2791:                while (sstart < send) {
                   2792:                    if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR)
                   2793:                        break;
                   2794:                    sstart++;
                   2795:                }
                   2796: 
                   2797:                /*
                   2798:                 * No more scatter descriptors, we're done
                   2799:                 */
                   2800:                if (sstart >= send) {
                   2801:                    break;
                   2802:                }
                   2803: 
                   2804:                /*
                   2805:                 * Check type, copy and size fields
                   2806:                 */
                   2807:                if (g_type == MACH_MSG_OOL_DESCRIPTOR ||
                   2808:                    g_type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
                   2809:                    if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR &&
                   2810:                        sstart->type.type != MACH_MSG_OOL_VOLATILE_DESCRIPTOR) {
                   2811:                        return(MACH_RCV_INVALID_TYPE);
                   2812:                    }
                   2813:                    if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE && 
                   2814:                        gstart->out_of_line.size > sstart->out_of_line.size) {
                   2815:                            return(MACH_RCV_SCATTER_SMALL);
                   2816:                    }
                   2817:                }
                   2818:                else {
                   2819:                    if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR) {
                   2820:                        return(MACH_RCV_INVALID_TYPE);
                   2821:                    }
                   2822:                    if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE &&
                   2823:                        gstart->ool_ports.count > sstart->ool_ports.count) {
                   2824:                            return(MACH_RCV_SCATTER_SMALL);
                   2825:                    }
                   2826:                }
                   2827:                sstart++;
                   2828:            }
                   2829:            gstart++;
                   2830:        }
                   2831: 
                   2832:        return(mr);
                   2833: }
                   2834: 
                   2835: 
                   2836: /*
                   2837:  *     We keep a per-processor cache of kernel message buffers.
                   2838:  *     The cache saves the overhead/locking of using kalloc/kfree.
                   2839:  *     The per-processor cache seems to miss less than a per-thread cache,
                   2840:  *     and it also uses less memory.  Access to the cache doesn't
                   2841:  *     require locking.
                   2842:  */
                   2843: #define IKM_STASH 16   /* # of cache entries per cpu */
                   2844: ipc_kmsg_t     ipc_kmsg_cache[ NCPUS ][ IKM_STASH ];
                   2845: unsigned int   ipc_kmsg_cache_avail[NCPUS];
                   2846: counter(unsigned int   c_ipc_kmsg_cache_tries = 0;)
                   2847: counter(unsigned int   c_ipc_kmsg_cache_misses = 0;)
                   2848: 
                   2849: /*
                   2850:  *     Routine:        ikm_cache_get
                   2851:  *     Purpose:        Attempt to allocate from the per-cpu IKM cache.
                   2852:  *     Conditions:     Nothing locked.
                   2853:  *
                   2854:  *     If the IKM cache for the current cpu is not empty, this routine
                   2855:  *     will return the address of the block, nulling out the cache.
                   2856:  *     TRUE is returned for success, FALSE for failure.
                   2857:  *     Preemption must be disabled while in here.
                   2858:  */
                   2859: 
                   2860: boolean_t
                   2861: ikm_cache_get(
                   2862:        ipc_kmsg_t      * kmsg)
                   2863: {
                   2864:        register unsigned int   cpu, i;
                   2865: 
                   2866:        counter(++c_ipc_kmsg_cache_tries);
                   2867:        disable_preemption();
                   2868:        cpu = cpu_number();
                   2869: 
                   2870:        if (ipc_kmsg_cache_avail[cpu]) {
                   2871:                for (i = 0; i < IKM_STASH; i++) {
                   2872:                        if ( *kmsg = ipc_kmsg_cache[cpu][i] ) {
                   2873:                                ipc_kmsg_cache[cpu][i] = IKM_NULL;
                   2874:                                ipc_kmsg_cache_avail[cpu]--;
                   2875:                                enable_preemption();
                   2876:                                return(TRUE);
                   2877:                        }
                   2878:                }
                   2879:        }
                   2880: 
                   2881:        enable_preemption();
                   2882:        counter(++c_ipc_kmsg_cache_misses);
                   2883:        return(FALSE);
                   2884: }
                   2885: 
                   2886: /*
                   2887:  *     Routine:        ikm_cache_put
                   2888:  *     Purpose:        Attempt to free a block to the per-cpu IKM cache.
                   2889:  *     Conditions:     Nothing locked.
                   2890:  *
                   2891:  *     If the IKM cache for the current cpu is empty, this routine
                   2892:  *     will store its argument into the cache.
                   2893:  *     TRUE is returned for success, FALSE for failure.
                   2894:  *     Preemption must be disabled while in here.
                   2895:  */
                   2896: 
                   2897: boolean_t
                   2898: ikm_cache_put(
                   2899:        ipc_kmsg_t      kmsg)
                   2900: {
                   2901:        unsigned int    cpu, i;
                   2902: 
                   2903:        disable_preemption();
                   2904:        cpu = cpu_number();
                   2905: 
                   2906:        if (ipc_kmsg_cache_avail[cpu] < IKM_STASH) {
                   2907:                for (i = 0; i < IKM_STASH; i++) {
                   2908:                        if (ipc_kmsg_cache[cpu][i] == IKM_NULL) {
                   2909:                                ipc_kmsg_cache[cpu][i] = kmsg;
                   2910:                                ipc_kmsg_cache_avail[cpu]++;
                   2911:                                enable_preemption();
                   2912:                                return(TRUE);
                   2913:                        }
                   2914:                }
                   2915:        }
                   2916: 
                   2917:        enable_preemption();
                   2918:        return(FALSE);
                   2919: }
                   2920: 
                   2921: 
                   2922: void
                   2923: ikm_cache_init()
                   2924: {
                   2925:        unsigned int    cpu, i;
                   2926: 
                   2927:        for (cpu = 0; cpu < NCPUS; ++cpu) {
                   2928:                ipc_kmsg_cache_avail[cpu] = 0;
                   2929:                for (i = 0; i < IKM_STASH; ++i)
                   2930:                        ipc_kmsg_cache[cpu][i] = IKM_NULL;
                   2931:        }
                   2932: }
                   2933: 
                   2934: 
                   2935: /*
                   2936:  *     Routine:        ipc_kmsg_copyout_to_kernel
                   2937:  *     Purpose:
                   2938:  *             Copies out the destination and reply ports in the message.
                   2939:  *             Leaves all other rights and memory in the message alone.
                   2940:  *     Conditions:
                   2941:  *             Nothing locked.
                   2942:  *
                   2943:  *     Derived from ipc_kmsg_copyout_dest.
                   2944:  *     Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
                   2945:  *     We really do want to save rights and memory.
                   2946:  */
                   2947: 
                   2948: void
                   2949: ipc_kmsg_copyout_to_kernel(
                   2950:        ipc_kmsg_t      kmsg,
                   2951:        ipc_space_t     space)
                   2952: {
                   2953:        ipc_object_t dest;
                   2954:        ipc_object_t reply;
                   2955:        mach_msg_type_name_t dest_type;
                   2956:        mach_msg_type_name_t reply_type;
                   2957:        mach_port_name_t dest_name, reply_name;
                   2958: 
                   2959:        dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
                   2960:        reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
                   2961:        dest_type = MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits);
                   2962:        reply_type = MACH_MSGH_BITS_LOCAL(kmsg->ikm_header.msgh_bits);
                   2963: 
                   2964:        assert(IO_VALID(dest));
                   2965: 
                   2966:        io_lock(dest);
                   2967:        if (io_active(dest)) {
                   2968:                ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
                   2969:                /* dest is unlocked */
                   2970:        } else {
                   2971:                io_release(dest);
                   2972:                io_check_unlock(dest);
                   2973:                dest_name = MACH_PORT_DEAD;
                   2974:        }
                   2975: 
                   2976:        reply_name = (mach_port_name_t) reply;
                   2977: 
                   2978:        kmsg->ikm_header.msgh_bits =
                   2979:                (MACH_MSGH_BITS_OTHER(kmsg->ikm_header.msgh_bits) |
                   2980:                                        MACH_MSGH_BITS(reply_type, dest_type));
                   2981:        kmsg->ikm_header.msgh_local_port = (ipc_port_t)dest_name;
                   2982:        kmsg->ikm_header.msgh_remote_port = (ipc_port_t)reply_name;
                   2983: }
                   2984: 
                   2985: #include <mach_kdb.h>
                   2986: #if    MACH_KDB
                   2987: 
                   2988: #include <ddb/db_output.h>
                   2989: #include <ipc/ipc_print.h>
                   2990: /*
                   2991:  * Forward declarations
                   2992:  */
                   2993: void ipc_msg_print_untyped(
                   2994:        mach_msg_body_t         *body);
                   2995: 
                   2996: char * ipc_type_name(
                   2997:        int             type_name,
                   2998:        boolean_t       received);
                   2999: 
                   3000: void ipc_print_type_name(
                   3001:        int     type_name);
                   3002: 
                   3003: char *
                   3004: msgh_bit_decode(
                   3005:        mach_msg_bits_t bit);
                   3006: 
                   3007: char *
                   3008: mm_copy_options_string(
                   3009:        mach_msg_copy_options_t option);
                   3010: 
                   3011: void db_print_msg_uid(mach_msg_header_t *);
                   3012: 
                   3013: 
                   3014: char *
                   3015: ipc_type_name(
                   3016:        int             type_name,
                   3017:        boolean_t       received)
                   3018: {
                   3019:        switch (type_name) {
                   3020:                case MACH_MSG_TYPE_PORT_NAME:
                   3021:                return "port_name";
                   3022:                
                   3023:                case MACH_MSG_TYPE_MOVE_RECEIVE:
                   3024:                if (received) {
                   3025:                        return "port_receive";
                   3026:                } else {
                   3027:                        return "move_receive";
                   3028:                }
                   3029:                
                   3030:                case MACH_MSG_TYPE_MOVE_SEND:
                   3031:                if (received) {
                   3032:                        return "port_send";
                   3033:                } else {
                   3034:                        return "move_send";
                   3035:                }
                   3036:                
                   3037:                case MACH_MSG_TYPE_MOVE_SEND_ONCE:
                   3038:                if (received) {
                   3039:                        return "port_send_once";
                   3040:                } else {
                   3041:                        return "move_send_once";
                   3042:                }
                   3043:                
                   3044:                case MACH_MSG_TYPE_COPY_SEND:
                   3045:                return "copy_send";
                   3046:                
                   3047:                case MACH_MSG_TYPE_MAKE_SEND:
                   3048:                return "make_send";
                   3049:                
                   3050:                case MACH_MSG_TYPE_MAKE_SEND_ONCE:
                   3051:                return "make_send_once";
                   3052:                
                   3053:                default:
                   3054:                return (char *) 0;
                   3055:        }
                   3056: }
                   3057:                
                   3058: void
                   3059: ipc_print_type_name(
                   3060:        int     type_name)
                   3061: {
                   3062:        char *name = ipc_type_name(type_name, TRUE);
                   3063:        if (name) {
                   3064:                printf("%s", name);
                   3065:        } else {
                   3066:                printf("type%d", type_name);
                   3067:        }
                   3068: }
                   3069: 
                   3070: /*
                   3071:  * ipc_kmsg_print      [ debug ]
                   3072:  */
                   3073: void
                   3074: ipc_kmsg_print(
                   3075:        ipc_kmsg_t      kmsg)
                   3076: {
                   3077:        iprintf("kmsg=0x%x\n", kmsg);
                   3078:        iprintf("ikm_next=0x%x, prev=0x%x, size=%d",
                   3079:                kmsg->ikm_next,
                   3080:                kmsg->ikm_prev,
                   3081:                kmsg->ikm_size);
                   3082:        printf("\n");
                   3083:        ipc_msg_print(&kmsg->ikm_header);
                   3084: }
                   3085: 
                   3086: char *
                   3087: msgh_bit_decode(
                   3088:        mach_msg_bits_t bit)
                   3089: {
                   3090:        switch (bit) {
                   3091:            case MACH_MSGH_BITS_COMPLEX:        return "complex";
                   3092:            case MACH_MSGH_BITS_CIRCULAR:       return "circular";
                   3093:            case MACH_MSGH_BITS_RTALLOC:        return "rtmalloc";
                   3094:            default:                            return (char *) 0;
                   3095:        }
                   3096: }
                   3097: 
                   3098: /*
                   3099:  * ipc_msg_print       [ debug ]
                   3100:  */
                   3101: void
                   3102: ipc_msg_print(
                   3103:        mach_msg_header_t       *msgh)
                   3104: {
                   3105:        mach_msg_bits_t mbits;
                   3106:        unsigned int    bit, i;
                   3107:        char            *bit_name;
                   3108:        int             needs_comma;
                   3109: 
                   3110:        mbits = msgh->msgh_bits;
                   3111:        iprintf("msgh_bits=0x%x:  l=0x%x,r=0x%x\n",
                   3112:                mbits,
                   3113:                MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
                   3114:                MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
                   3115: 
                   3116:        mbits = MACH_MSGH_BITS_OTHER(mbits) & ~MACH_MSGH_BITS_UNUSED;
                   3117:        db_indent += 2;
                   3118:        if (mbits)
                   3119:                iprintf("decoded bits:  ");
                   3120:        needs_comma = 0;
                   3121:        for (i = 0, bit = 1; i < sizeof(mbits) * 8; ++i, bit <<= 1) {
                   3122:                if ((mbits & bit) == 0)
                   3123:                        continue;
                   3124:                bit_name = msgh_bit_decode((mach_msg_bits_t)bit);
                   3125:                if (bit_name)
                   3126:                        printf("%s%s", needs_comma ? "," : "", bit_name);
                   3127:                else
                   3128:                        printf("%sunknown(0x%x),", needs_comma ? "," : "", bit);
                   3129:                ++needs_comma;
                   3130:        }
                   3131:        if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
                   3132:                printf("%sunused=0x%x,", needs_comma ? "," : "",
                   3133:                       msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
                   3134:        }
                   3135:        printf("\n");
                   3136:        db_indent -= 2;
                   3137: 
                   3138:        needs_comma = 1;
                   3139:        if (msgh->msgh_remote_port) {
                   3140:                iprintf("remote=0x%x(", msgh->msgh_remote_port);
                   3141:                ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
                   3142:                printf(")");
                   3143:        } else {
                   3144:                iprintf("remote=null");
                   3145:        }
                   3146: 
                   3147:        if (msgh->msgh_local_port) {
                   3148:                printf("%slocal=0x%x(", needs_comma ? "," : "",
                   3149:                       msgh->msgh_local_port);
                   3150:                ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
                   3151:                printf(")\n");
                   3152:        } else {
                   3153:                printf("local=null\n");
                   3154:        }
                   3155: 
                   3156:        iprintf("msgh_id=%d, size=%d\n",
                   3157:                msgh->msgh_id,
                   3158:                msgh->msgh_size);
                   3159: 
                   3160:        if (mbits & MACH_MSGH_BITS_COMPLEX) {   
                   3161:                ipc_msg_print_untyped((mach_msg_body_t *) (msgh + 1));
                   3162:        }
                   3163: }
                   3164: 
                   3165: 
                   3166: char *
                   3167: mm_copy_options_string(
                   3168:        mach_msg_copy_options_t option)
                   3169: {
                   3170:        char    *name;
                   3171: 
                   3172:        switch (option) {
                   3173:            case MACH_MSG_PHYSICAL_COPY:
                   3174:                name = "PHYSICAL";
                   3175:                break;
                   3176:            case MACH_MSG_VIRTUAL_COPY:
                   3177:                name = "VIRTUAL";
                   3178:                break;
                   3179:            case MACH_MSG_OVERWRITE:
                   3180:                name = "OVERWRITE";
                   3181:                break;
                   3182:            case MACH_MSG_ALLOCATE:
                   3183:                name = "ALLOCATE";
                   3184:                break;
                   3185:            case MACH_MSG_KALLOC_COPY_T:
                   3186:                name = "KALLOC_COPY_T";
                   3187:                break;
                   3188:            case MACH_MSG_PAGE_LIST_COPY_T:
                   3189:                name = "PAGE_LIST_COPY_T";
                   3190:                break;
                   3191:            default:
                   3192:                name = "unknown";
                   3193:                break;
                   3194:        }
                   3195:        return name;
                   3196: }
                   3197: 
                   3198: void
                   3199: ipc_msg_print_untyped(
                   3200:        mach_msg_body_t         *body)
                   3201: {
                   3202:     mach_msg_descriptor_t      *saddr, *send;
                   3203:     mach_msg_descriptor_type_t type;
                   3204: 
                   3205:     iprintf("%d descriptors %d: \n", body->msgh_descriptor_count);
                   3206: 
                   3207:     saddr = (mach_msg_descriptor_t *) (body + 1);
                   3208:     send = saddr + body->msgh_descriptor_count;
                   3209: 
                   3210:     for ( ; saddr < send; saddr++ ) {
                   3211:        
                   3212:        type = saddr->type.type;
                   3213: 
                   3214:        switch (type) {
                   3215:            
                   3216:            case MACH_MSG_PORT_DESCRIPTOR: {
                   3217:                mach_msg_port_descriptor_t *dsc;
                   3218: 
                   3219:                dsc = &saddr->port;
                   3220:                iprintf("-- PORT name = 0x%x disp = ", dsc->name);
                   3221:                ipc_print_type_name(dsc->disposition);
                   3222:                printf("\n");
                   3223:                break;
                   3224:            }
                   3225:            case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
                   3226:            case MACH_MSG_OOL_DESCRIPTOR: {
                   3227:                mach_msg_ool_descriptor_t *dsc;
                   3228:                
                   3229:                dsc = &saddr->out_of_line;
                   3230:                iprintf("-- OOL%s addr = 0x%x size = 0x%x copy = %s %s\n",
                   3231:                        type == MACH_MSG_OOL_DESCRIPTOR ? "" : " VOLATILE",
                   3232:                        dsc->address, dsc->size,
                   3233:                        mm_copy_options_string(dsc->copy),
                   3234:                        dsc->deallocate ? "DEALLOC" : "");
                   3235:                break;
                   3236:            } 
                   3237:            case MACH_MSG_OOL_PORTS_DESCRIPTOR : {
                   3238:                mach_msg_ool_ports_descriptor_t *dsc;
                   3239: 
                   3240:                dsc = &saddr->ool_ports;
                   3241: 
                   3242:                iprintf("-- OOL_PORTS addr = 0x%x count = 0x%x ",
                   3243:                          dsc->address, dsc->count);
                   3244:                printf("disp = ");
                   3245:                ipc_print_type_name(dsc->disposition);
                   3246:                printf(" copy = %s %s\n",
                   3247:                       mm_copy_options_string(dsc->copy),
                   3248:                       dsc->deallocate ? "DEALLOC" : "");
                   3249:                break;
                   3250:            }
                   3251: 
                   3252:            default: {
                   3253:                iprintf("-- UNKNOWN DESCRIPTOR 0x%x\n", type);
                   3254:                break;
                   3255:            }
                   3256:        }
                   3257:     }
                   3258: }
                   3259: #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.