The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_kmsg.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

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

Cache object: 40b9017f034dda541b545d0b58715b72


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.