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

Cache object: ebd6f3b3b510e9b19386938d3029cd5d


[ 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.