Annotation of XNU/osfmk/ipc/ipc_kmsg.c, revision 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.