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/kern/ipc_mig.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 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_mig.c,v $
   29  * Revision 2.22  93/08/10  15:11:34  mrt
   30  *      Fixed the case where device write traps are called with reply ports.
   31  *      [93/07/29            cmaeda]
   32  * 
   33  *      Device traps and scatter/gather IO (actually just gather IO) --
   34  *      Added port_name_to_device, syscall_device_write_request,
   35  *      and syscall_device_writev_request.
   36  *      (Original version of this code from rfr, many moons ago.)
   37  *      [93/04/14            cmaeda]
   38  * 
   39  * Revision 2.21  93/03/26  17:54:47  mrt
   40  *      Merge botch got rid of the above.
   41  *      [93/03/23            af]
   42  * 
   43  * Revision 2.20  93/01/14  17:34:34  danner
   44  *      64bit cleanup.
   45  *      [92/12/01            af]
   46  * 
   47  * Revision 2.19  92/08/03  17:37:30  jfriedl
   48  *      removed silly prototypes
   49  *      [92/08/02            jfriedl]
   50  * 
   51  * Revision 2.18  92/05/21  17:13:55  jfriedl
   52  *      Removed unsed var 'addr' from syscall_vm_deallocate.
   53  *      [92/05/16            jfriedl]
   54  * 
   55  * Revision 2.17  92/03/10  16:26:34  jsb
   56  *      Corrected log.
   57  *      [91/12/24  14:42:53  jsb]
   58  * 
   59  * Revision 2.16  92/02/19  16:06:28  elf
   60  *      Added syscall_thread_depress_abort.
   61  *      [92/01/20            rwd]
   62  * 
   63  * Revision 2.15  91/11/14  16:56:39  rpd
   64  *      Replaced call to ipc_kmsg_copyout_dest with ipc_kmsg_copyout_to_kernel
   65  *      in mach_msg_rpc_from_kernel, to preserve rights and memory.
   66  *      [91/11/00            jsb]
   67  * 
   68  * Revision 2.14  91/08/28  11:14:34  jsb
   69  *      Fixed syscall_mach_port_insert_right and syscall_task_set_special_port
   70  *      to handle non-valid port names correctly.
   71  *      [91/08/15            rpd]
   72  * 
   73  *      Changed MACH_RCV_TOO_LARGE and MACH_RCV_INVALID_NOTIFY to work
   74  *      like MACH_RCV_HEADER_ERROR, using ipc_kmsg_copyout_dest.
   75  *      [91/08/12            rpd]
   76  * 
   77  *      Added seqno argument to ipc_mqueue_receive.
   78  *      [91/08/10            rpd]
   79  *      Conditionalize mach_msg_rpc_from_kernel on NORMA_VM, not NORMA_TASK.
   80  *      [91/08/14  18:34:30  jsb]
   81  * 
   82  * Revision 2.13  91/08/03  18:18:53  jsb
   83  *      Corrected comment for mach_msg_send_from_kernel.
   84  *      [91/07/04  10:08:23  jsb]
   85  * 
   86  * Revision 2.12  91/07/30  15:45:43  rvb
   87  *      Fixed syscall_vm_map to handle non-valid memory objects correctly.
   88  *      [91/07/12            rpd]
   89  * 
   90  * Revision 2.11  91/06/17  15:47:05  jsb
   91  *      Renamed NORMA conditionals.
   92  *      [91/06/17  10:50:07  jsb]
   93  * 
   94  * Revision 2.10  91/06/06  17:07:09  jsb
   95  *      NORMA_TASK: We still need mach_msg_rpc_from_kernel.
   96  *      [91/05/14  09:13:45  jsb]
   97  * 
   98  * Revision 2.9  91/05/20  22:22:16  rpd
   99  *      Cleaned up the semantics of the syscall forms of kernel RPCs.
  100  *      [91/05/20            rpd]
  101  * 
  102  * Revision 2.8  91/05/14  16:42:22  mrt
  103  *      Correcting copyright
  104  * 
  105  * Revision 2.7  91/02/05  17:26:46  mrt
  106  *      Changed to new Mach copyright
  107  *      [91/02/01  16:13:09  mrt]
  108  * 
  109  * Revision 2.6  91/01/08  15:15:44  rpd
  110  *      Don't need mach_msg_rpc_from_kernel.
  111  *      [90/12/26            rpd]
  112  *      Updated ipc_mqueue_receive calls.
  113  *      [90/11/21            rpd]
  114  *      Removed MACH_IPC_GENNOS.
  115  *      [90/11/09            rpd]
  116  * 
  117  * Revision 2.5  90/11/05  14:30:59  rpd
  118  *      Changed ip_reference to ipc_port_reference.
  119  *      Changed ip_release to ipc_port_release.
  120  *      Removed ipc_object_release_macro.
  121  *      Use new ip_reference and ip_release.
  122  *      [90/10/29            rpd]
  123  * 
  124  * Revision 2.4  90/09/09  14:32:13  rpd
  125  *      Added mach_port_allocate_name.
  126  *      [90/09/03            rwd]
  127  * 
  128  * Revision 2.3  90/06/19  22:58:57  rpd
  129  *      Optimized port_name_to_task, port_name_to_thread, etc.
  130  *      [90/06/03            rpd]
  131  * 
  132  *      Added mach_port_allocate, mach_port_deallocate, mach_port_insert_right.
  133  *      [90/06/02            rpd]
  134  * 
  135  * Revision 2.2  90/06/02  14:54:16  rpd
  136  *      Moved trap versions of kernel calls here
  137  *      from vm/vm_user.c, kern/task.c.
  138  *      Converted them to new IPC.
  139  *      [90/05/31            rpd]
  140  * 
  141  *      Created for new IPC.
  142  *      [90/03/26  23:47:15  rpd]
  143  * 
  144  */
  145 
  146 #include <norma_vm.h>
  147 
  148 #include <mach/boolean.h>
  149 #include <mach/port.h>
  150 #include <mach/message.h>
  151 #include <mach/thread_status.h>
  152 #include <kern/ast.h>
  153 #include <kern/ipc_tt.h>
  154 #include <kern/thread.h>
  155 #include <kern/task.h>
  156 #include <kern/ipc_kobject.h>
  157 #include <vm/vm_map.h>
  158 #include <vm/vm_user.h>
  159 #include <ipc/port.h>
  160 #include <ipc/ipc_kmsg.h>
  161 #include <ipc/ipc_entry.h>
  162 #include <ipc/ipc_object.h>
  163 #include <ipc/ipc_mqueue.h>
  164 #include <ipc/ipc_space.h>
  165 #include <ipc/ipc_port.h>
  166 #include <ipc/ipc_pset.h>
  167 #include <ipc/ipc_thread.h>
  168 #include <device/device_types.h>
  169 
  170 
  171 /*
  172  *      Routine:        mach_msg_send_from_kernel
  173  *      Purpose:
  174  *              Send a message from the kernel.
  175  *
  176  *              This is used by the client side of KernelUser interfaces
  177  *              to implement SimpleRoutines.  Currently, this includes
  178  *              device_reply and memory_object messages.
  179  *      Conditions:
  180  *              Nothing locked.
  181  *      Returns:
  182  *              MACH_MSG_SUCCESS        Sent the message.
  183  *              MACH_SEND_INVALID_DATA  Bad destination port.
  184  */
  185 
  186 mach_msg_return_t
  187 mach_msg_send_from_kernel(msg, send_size)
  188         mach_msg_header_t *msg;
  189         mach_msg_size_t send_size;
  190 {
  191         ipc_kmsg_t kmsg;
  192         mach_msg_return_t mr;
  193 
  194         if (!MACH_PORT_VALID(msg->msgh_remote_port))
  195                 return MACH_SEND_INVALID_DEST;
  196 
  197         mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
  198         if (mr != MACH_MSG_SUCCESS)
  199                 panic("mach_msg_send_from_kernel");
  200 
  201         ipc_kmsg_copyin_from_kernel(kmsg);
  202         ipc_mqueue_send_always(kmsg);
  203 
  204         return MACH_MSG_SUCCESS;
  205 }
  206 
  207 #if     NORMA_VM
  208 /*
  209  *      Routine:        mach_msg_rpc_from_kernel
  210  *      Purpose:
  211  *              Send a message from the kernel and receive a reply.
  212  *              Uses ith_rpc_reply for the reply port.
  213  *
  214  *              This is used by the client side of KernelUser interfaces
  215  *              to implement Routines.  Currently, this is only
  216  *              used by norma code.
  217  *      Conditions:
  218  *              Nothing locked.
  219  *      Returns:
  220  *              MACH_MSG_SUCCESS        Sent the message.
  221  *              MACH_RCV_PORT_DIED      The reply port was deallocated.
  222  */
  223 
  224 mach_msg_return_t
  225 mach_msg_rpc_from_kernel(msg, send_size, rcv_size)
  226         mach_msg_header_t *msg;
  227         mach_msg_size_t send_size;
  228         mach_msg_size_t rcv_size;
  229 {
  230         ipc_thread_t self = current_thread();
  231         ipc_port_t reply;
  232         ipc_kmsg_t kmsg;
  233         mach_port_seqno_t seqno;
  234         mach_msg_return_t mr;
  235 
  236         assert(MACH_PORT_VALID(msg->msgh_remote_port));
  237         assert(msg->msgh_local_port == MACH_PORT_NULL);
  238 
  239         mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
  240         if (mr != MACH_MSG_SUCCESS)
  241                 panic("mach_msg_rpc_from_kernel");
  242 
  243         ipc_kmsg_copyin_from_kernel(kmsg);
  244 
  245         ith_lock(self);
  246         assert(self->ith_self != IP_NULL);
  247 
  248         reply = self->ith_rpc_reply;
  249         if (reply == IP_NULL) {
  250                 ith_unlock(self);
  251                 reply = ipc_port_alloc_reply();
  252                 ith_lock(self);
  253                 if ((reply == IP_NULL) ||
  254                     (self->ith_rpc_reply != IP_NULL))
  255                         panic("mach_msg_rpc_from_kernel");
  256                 self->ith_rpc_reply = reply;
  257         }
  258 
  259         /* insert send-once right for the reply port */
  260         kmsg->ikm_header.msgh_local_port =
  261                 (mach_port_t) ipc_port_make_sonce(reply);
  262 
  263         ipc_port_reference(reply);
  264         ith_unlock(self);
  265 
  266         ipc_mqueue_send_always(kmsg);
  267 
  268         for (;;) {
  269                 ipc_mqueue_t mqueue;
  270 
  271                 ip_lock(reply);
  272                 if (!ip_active(reply)) {
  273                         ip_unlock(reply);
  274                         ipc_port_release(reply);
  275                         return MACH_RCV_PORT_DIED;
  276                 }
  277 
  278                 assert(reply->ip_pset == IPS_NULL);
  279                 mqueue = &reply->ip_messages;
  280                 imq_lock(mqueue);
  281                 ip_unlock(reply);
  282 
  283                 mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
  284                                         MACH_MSG_SIZE_MAX,
  285                                         MACH_MSG_TIMEOUT_NONE,
  286                                         FALSE, IMQ_NULL_CONTINUE,
  287                                         &kmsg, &seqno);
  288                 /* mqueue is unlocked */
  289                 if (mr == MACH_MSG_SUCCESS)
  290                         break;
  291 
  292                 assert((mr == MACH_RCV_INTERRUPTED) ||
  293                        (mr == MACH_RCV_PORT_DIED));
  294 
  295                 while (thread_should_halt(self)) {
  296                         /* don't terminate while holding a reference */
  297                         if (self->ast & AST_TERMINATE)
  298                                 ipc_port_release(reply);
  299                         thread_halt_self();
  300                 }
  301         }
  302         ipc_port_release(reply);
  303 
  304         kmsg->ikm_header.msgh_seqno = seqno;
  305 
  306         if (rcv_size < kmsg->ikm_header.msgh_size) {
  307                 ipc_kmsg_copyout_dest(kmsg, ipc_space_reply);
  308                 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
  309                 return MACH_RCV_TOO_LARGE;
  310         }
  311 
  312         /*
  313          *      We want to preserve rights and memory in reply!
  314          *      We don't have to put them anywhere; just leave them
  315          *      as they are.
  316          */
  317 
  318         ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply);
  319         ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
  320         return MACH_MSG_SUCCESS;
  321 }
  322 #endif  NORMA_VM
  323 
  324 /*
  325  *      Routine:        mach_msg_abort_rpc
  326  *      Purpose:
  327  *              Destroy the thread's ith_rpc_reply port.
  328  *              This will interrupt a mach_msg_rpc_from_kernel
  329  *              with a MACH_RCV_PORT_DIED return code.
  330  *      Conditions:
  331  *              Nothing locked.
  332  */
  333 
  334 void
  335 mach_msg_abort_rpc(thread)
  336         ipc_thread_t thread;
  337 {
  338         ipc_port_t reply = IP_NULL;
  339 
  340         ith_lock(thread);
  341         if (thread->ith_self != IP_NULL) {
  342                 reply = thread->ith_rpc_reply;
  343                 thread->ith_rpc_reply = IP_NULL;
  344         }
  345         ith_unlock(thread);
  346 
  347         if (reply != IP_NULL)
  348                 ipc_port_dealloc_reply(reply);
  349 }
  350 
  351 /*
  352  *      Routine:        mach_msg
  353  *      Purpose:
  354  *              Like mach_msg_trap except that message buffers
  355  *              live in kernel space.  Doesn't handle any options.
  356  *
  357  *              This is used by in-kernel server threads to make
  358  *              kernel calls, to receive request messages, and
  359  *              to send reply messages.
  360  *      Conditions:
  361  *              Nothing locked.
  362  *      Returns:
  363  */
  364 
  365 mach_msg_return_t
  366 mach_msg(msg, option, send_size, rcv_size, rcv_name, time_out, notify)
  367         mach_msg_header_t *msg;
  368         mach_msg_option_t option;
  369         mach_msg_size_t send_size;
  370         mach_msg_size_t rcv_size;
  371         mach_port_t rcv_name;
  372         mach_msg_timeout_t time_out;
  373         mach_port_t notify;
  374 {
  375         ipc_space_t space = current_space();
  376         vm_map_t map = current_map();
  377         ipc_kmsg_t kmsg;
  378         mach_port_seqno_t seqno;
  379         mach_msg_return_t mr;
  380 
  381         if (option & MACH_SEND_MSG) {
  382                 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
  383                 if (mr != MACH_MSG_SUCCESS)
  384                         panic("mach_msg");
  385 
  386                 mr = ipc_kmsg_copyin(kmsg, space, map, MACH_PORT_NULL);
  387                 if (mr != MACH_MSG_SUCCESS) {
  388                         ikm_free(kmsg);
  389                         return mr;
  390                 }
  391 
  392                 do
  393                         mr = ipc_mqueue_send(kmsg, MACH_MSG_OPTION_NONE,
  394                                              MACH_MSG_TIMEOUT_NONE);
  395                 while (mr == MACH_SEND_INTERRUPTED);
  396                 assert(mr == MACH_MSG_SUCCESS);
  397         }
  398 
  399         if (option & MACH_RCV_MSG) {
  400                 do {
  401                         ipc_object_t object;
  402                         ipc_mqueue_t mqueue;
  403 
  404                         mr = ipc_mqueue_copyin(space, rcv_name,
  405                                                &mqueue, &object);
  406                         if (mr != MACH_MSG_SUCCESS)
  407                                 return mr;
  408                         /* hold ref for object; mqueue is locked */
  409 
  410                         mr = ipc_mqueue_receive(mqueue, MACH_MSG_OPTION_NONE,
  411                                                 MACH_MSG_SIZE_MAX,
  412                                                 MACH_MSG_TIMEOUT_NONE,
  413                                                 FALSE, IMQ_NULL_CONTINUE,
  414                                                 &kmsg, &seqno);
  415                         /* mqueue is unlocked */
  416                         ipc_object_release(object);
  417                 } while (mr == MACH_RCV_INTERRUPTED);
  418                 if (mr != MACH_MSG_SUCCESS)
  419                         return mr;
  420 
  421                 kmsg->ikm_header.msgh_seqno = seqno;
  422 
  423                 if (rcv_size < kmsg->ikm_header.msgh_size) {
  424                         ipc_kmsg_copyout_dest(kmsg, space);
  425                         ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
  426                         return MACH_RCV_TOO_LARGE;
  427                 }
  428 
  429                 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_PORT_NULL);
  430                 if (mr != MACH_MSG_SUCCESS) {
  431                         if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
  432                                 ipc_kmsg_put_to_kernel(msg, kmsg,
  433                                                 kmsg->ikm_header.msgh_size);
  434                         } else {
  435                                 ipc_kmsg_copyout_dest(kmsg, space);
  436                                 ipc_kmsg_put_to_kernel(msg, kmsg, sizeof *msg);
  437                         }
  438 
  439                         return mr;
  440                 }
  441 
  442                 ipc_kmsg_put_to_kernel(msg, kmsg, kmsg->ikm_header.msgh_size);
  443         }
  444 
  445         return MACH_MSG_SUCCESS;
  446 }
  447 
  448 /*
  449  *      Routine:        mig_get_reply_port
  450  *      Purpose:
  451  *              Called by client side interfaces living in the kernel
  452  *              to get a reply port.  This port is used for
  453  *              mach_msg() calls which are kernel calls.
  454  */
  455 
  456 mach_port_t
  457 mig_get_reply_port()
  458 {
  459         ipc_thread_t self = current_thread();
  460 
  461         if (self->ith_mig_reply == MACH_PORT_NULL)
  462                 self->ith_mig_reply = mach_reply_port();
  463 
  464         return self->ith_mig_reply;
  465 }
  466 
  467 /*
  468  *      Routine:        mig_dealloc_reply_port
  469  *      Purpose:
  470  *              Called by client side interfaces to get rid of a reply port.
  471  *              Shouldn't ever be called inside the kernel, because
  472  *              kernel calls shouldn't prompt Mig to call it.
  473  */
  474 
  475 void
  476 mig_dealloc_reply_port()
  477 {
  478         panic("mig_dealloc_reply_port");
  479 }
  480 
  481 /*
  482  * mig_strncpy.c - by Joshua Block
  483  *
  484  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
  485  * OUGHT to do:  Copies the (null terminated) string in src into dest, a 
  486  * buffer of length len.  Assures that the copy is still null terminated
  487  * and doesn't overflow the buffer, truncating the copy if necessary.
  488  *
  489  * Parameters:
  490  * 
  491  *     dest - Pointer to destination buffer.
  492  * 
  493  *     src - Pointer to source string.
  494  * 
  495  *     len - Length of destination buffer.
  496  */
  497 void mig_strncpy(dest, src, len)
  498 char *dest, *src;
  499 int len;
  500 {
  501     int i;
  502 
  503     if (len <= 0)
  504         return;
  505 
  506     for (i=1; i<len; i++)
  507         if (! (*dest++ = *src++))
  508             return;
  509 
  510     *dest = '\0';
  511     return;
  512 }
  513 
  514 #define fast_send_right_lookup(name, port, abort)                       \
  515 MACRO_BEGIN                                                             \
  516         register ipc_space_t space = current_space();                   \
  517         register ipc_entry_t entry;                                     \
  518         register mach_port_index_t index = MACH_PORT_INDEX(name);       \
  519                                                                         \
  520         is_read_lock(space);                                            \
  521         assert(space->is_active);                                       \
  522                                                                         \
  523         if ((index >= space->is_table_size) ||                          \
  524             (((entry = &space->is_table[index])->ie_bits &              \
  525               (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=                \
  526              (MACH_PORT_GEN(name) | MACH_PORT_TYPE_SEND))) {            \
  527                 is_read_unlock(space);                                  \
  528                 abort;                                                  \
  529         }                                                               \
  530                                                                         \
  531         port = (ipc_port_t) entry->ie_object;                           \
  532         assert(port != IP_NULL);                                        \
  533                                                                         \
  534         ip_lock(port);                                                  \
  535         /* can safely unlock space now that port is locked */           \
  536         is_read_unlock(space);                                          \
  537 MACRO_END
  538 
  539 device_t
  540 port_name_to_device(name)
  541         mach_port_t name;
  542 {
  543         register ipc_port_t port;
  544         register device_t device;
  545  
  546         fast_send_right_lookup(name, port, goto abort);
  547         /* port is locked */
  548  
  549         /*
  550          * Now map the port object to a device object.
  551          * This is an inline version of dev_port_lookup().
  552          */
  553         if (ip_active(port) && (ip_kotype(port) == IKOT_DEVICE)) {
  554                 device = (device_t) port->ip_kobject;
  555                 device_reference(device);
  556                 ip_unlock(port);
  557                 return device;                  
  558         }
  559  
  560         ip_unlock(port);
  561         return DEVICE_NULL;
  562  
  563        /*
  564         * The slow case.  The port wasn't easily accessible.
  565         */
  566     abort: {
  567             ipc_port_t kern_port;
  568             kern_return_t kr;
  569            
  570             kr = ipc_object_copyin(current_space(), name,
  571                                    MACH_MSG_TYPE_COPY_SEND,
  572                                    (ipc_object_t *) &kern_port);
  573             if (kr != KERN_SUCCESS)
  574                     return DEVICE_NULL;
  575  
  576             device = dev_port_lookup(kern_port);
  577             if (IP_VALID(kern_port))
  578                     ipc_port_release_send(kern_port);
  579             return device;
  580     }
  581 }
  582 
  583 thread_t
  584 port_name_to_thread(name)
  585         mach_port_t name;
  586 {
  587         register ipc_port_t port;
  588 
  589         fast_send_right_lookup(name, port, goto abort);
  590         /* port is locked */
  591 
  592         if (ip_active(port) &&
  593             (ip_kotype(port) == IKOT_THREAD)) {
  594                 register thread_t thread;
  595 
  596                 thread = (thread_t) port->ip_kobject;
  597                 assert(thread != THREAD_NULL);
  598 
  599                 /* thread referencing is a bit complicated,
  600                    so don't bother to expand inline */
  601                 thread_reference(thread);
  602                 ip_unlock(port);
  603 
  604                 return thread;
  605         }
  606 
  607         ip_unlock(port);
  608         return THREAD_NULL;
  609 
  610     abort: {
  611         thread_t thread;
  612         ipc_port_t kern_port;
  613         kern_return_t kr;
  614 
  615         kr = ipc_object_copyin(current_space(), name,
  616                                MACH_MSG_TYPE_COPY_SEND,
  617                                (ipc_object_t *) &kern_port);
  618         if (kr != KERN_SUCCESS)
  619                 return THREAD_NULL;
  620 
  621         thread = convert_port_to_thread(kern_port);
  622         if (IP_VALID(kern_port))
  623                 ipc_port_release_send(kern_port);
  624 
  625         return thread;
  626     }
  627 }
  628 
  629 task_t
  630 port_name_to_task(name)
  631         mach_port_t name;
  632 {
  633         register ipc_port_t port;
  634 
  635         fast_send_right_lookup(name, port, goto abort);
  636         /* port is locked */
  637 
  638         if (ip_active(port) &&
  639             (ip_kotype(port) == IKOT_TASK)) {
  640                 register task_t task;
  641 
  642                 task = (task_t) port->ip_kobject;
  643                 assert(task != TASK_NULL);
  644 
  645                 task_lock(task);
  646                 /* can safely unlock port now that task is locked */
  647                 ip_unlock(port);
  648 
  649                 task->ref_count++;
  650                 task_unlock(task);
  651 
  652                 return task;
  653         }
  654 
  655         ip_unlock(port);
  656         return TASK_NULL;
  657 
  658     abort: {
  659         task_t task;
  660         ipc_port_t kern_port;
  661         kern_return_t kr;
  662 
  663         kr = ipc_object_copyin(current_space(), name,
  664                                MACH_MSG_TYPE_COPY_SEND,
  665                                (ipc_object_t *) &kern_port);
  666         if (kr != KERN_SUCCESS)
  667                 return TASK_NULL;
  668 
  669         task = convert_port_to_task(kern_port);
  670         if (IP_VALID(kern_port))
  671                 ipc_port_release_send(kern_port);
  672 
  673         return task;
  674     }
  675 }
  676 
  677 vm_map_t
  678 port_name_to_map(name)
  679         mach_port_t name;
  680 {
  681         register ipc_port_t port;
  682 
  683         fast_send_right_lookup(name, port, goto abort);
  684         /* port is locked */
  685 
  686         if (ip_active(port) &&
  687             (ip_kotype(port) == IKOT_TASK)) {
  688                 register vm_map_t map;
  689 
  690                 map = ((task_t) port->ip_kobject)->map;
  691                 assert(map != VM_MAP_NULL);
  692 
  693                 simple_lock(&map->ref_lock);
  694                 /* can safely unlock port now that map is locked */
  695                 ip_unlock(port);
  696 
  697                 map->ref_count++;
  698                 simple_unlock(&map->ref_lock);
  699 
  700                 return map;
  701         }
  702 
  703         ip_unlock(port);
  704         return VM_MAP_NULL;
  705 
  706     abort: {
  707         vm_map_t map;
  708         ipc_port_t kern_port;
  709         kern_return_t kr;
  710 
  711         kr = ipc_object_copyin(current_space(), name,
  712                                MACH_MSG_TYPE_COPY_SEND,
  713                                (ipc_object_t *) &kern_port);
  714         if (kr != KERN_SUCCESS)
  715                 return VM_MAP_NULL;
  716 
  717         map = convert_port_to_map(kern_port);
  718         if (IP_VALID(kern_port))
  719                 ipc_port_release_send(kern_port);
  720 
  721         return map;
  722     }
  723 }
  724 
  725 ipc_space_t
  726 port_name_to_space(name)
  727         mach_port_t name;
  728 {
  729         register ipc_port_t port;
  730 
  731         fast_send_right_lookup(name, port, goto abort);
  732         /* port is locked */
  733 
  734         if (ip_active(port) &&
  735             (ip_kotype(port) == IKOT_TASK)) {
  736                 register ipc_space_t space;
  737 
  738                 space = ((task_t) port->ip_kobject)->itk_space;
  739                 assert(space != IS_NULL);
  740 
  741                 simple_lock(&space->is_ref_lock_data);
  742                 /* can safely unlock port now that space is locked */
  743                 ip_unlock(port);
  744 
  745                 space->is_references++;
  746                 simple_unlock(&space->is_ref_lock_data);
  747 
  748                 return space;
  749         }
  750 
  751         ip_unlock(port);
  752         return IS_NULL;
  753 
  754     abort: {
  755         ipc_space_t space;
  756         ipc_port_t kern_port;
  757         kern_return_t kr;
  758 
  759         kr = ipc_object_copyin(current_space(), name,
  760                                MACH_MSG_TYPE_COPY_SEND,
  761                                (ipc_object_t *) &kern_port);
  762         if (kr != KERN_SUCCESS)
  763                 return IS_NULL;
  764 
  765         space = convert_port_to_space(kern_port);
  766         if (IP_VALID(kern_port))
  767                 ipc_port_release_send(kern_port);
  768 
  769         return space;
  770     }
  771 }
  772 
  773 /*
  774  * Hack to translate a thread port to a thread pointer for calling
  775  * thread_get_state and thread_set_state.  This is only necessary
  776  * because the IPC message for these two operations overflows the
  777  * kernel stack.
  778  *
  779  * AARGH!
  780  */
  781 
  782 kern_return_t thread_get_state_KERNEL(thread_port, flavor,
  783                         old_state, old_state_count)
  784         mach_port_t     thread_port;    /* port right for thread */
  785         int             flavor;
  786         thread_state_t  old_state;      /* pointer to OUT array */
  787         natural_t       *old_state_count;       /* IN/OUT */
  788 {
  789         thread_t        thread;
  790         kern_return_t   result;
  791 
  792         thread = port_name_to_thread(thread_port);
  793         result = thread_get_state(thread, flavor, old_state, old_state_count);
  794         thread_deallocate(thread);
  795 
  796         return result;
  797 }
  798 
  799 kern_return_t thread_set_state_KERNEL(thread_port, flavor,
  800                         new_state, new_state_count)
  801         mach_port_t     thread_port;    /* port right for thread */
  802         int             flavor;
  803         thread_state_t  new_state;
  804         natural_t       new_state_count;
  805 {
  806         thread_t        thread;
  807         kern_return_t   result;
  808 
  809         thread = port_name_to_thread(thread_port);
  810         result = thread_set_state(thread, flavor, new_state, new_state_count);
  811         thread_deallocate(thread);
  812 
  813         return result;
  814 }
  815 
  816 /*
  817  *      Things to keep in mind:
  818  *
  819  *      The idea here is to duplicate the semantics of the true kernel RPC.
  820  *      The destination port/object should be checked first, before anything
  821  *      that the user might notice (like ipc_object_copyin).  Return
  822  *      MACH_SEND_INTERRUPTED if it isn't correct, so that the user stub
  823  *      knows to fall back on an RPC.  For other return values, it won't
  824  *      retry with an RPC.  The retry might get a different (incorrect) rc.
  825  *      Return values are only set (and should only be set, with copyout)
  826  *      on successfull calls.
  827  */
  828 
  829 kern_return_t syscall_vm_map(
  830                 target_map,
  831                 address, size, mask, anywhere,
  832                 memory_object, offset,
  833                 copy,
  834                 cur_protection, max_protection, inheritance)
  835         mach_port_t     target_map;
  836         vm_offset_t     *address;
  837         vm_size_t       size;
  838         vm_offset_t     mask;
  839         boolean_t       anywhere;
  840         mach_port_t     memory_object;
  841         vm_offset_t     offset;
  842         boolean_t       copy;
  843         vm_prot_t       cur_protection;
  844         vm_prot_t       max_protection;
  845         vm_inherit_t    inheritance;
  846 {
  847         vm_map_t                map;
  848         ipc_port_t              port;
  849         vm_offset_t             addr;
  850         kern_return_t           result;
  851 
  852         map = port_name_to_map(target_map);
  853         if (map == VM_MAP_NULL)
  854                 return MACH_SEND_INTERRUPTED;
  855 
  856         if (MACH_PORT_VALID(memory_object)) {
  857                 result = ipc_object_copyin(current_space(), memory_object,
  858                                            MACH_MSG_TYPE_COPY_SEND,
  859                                            (ipc_object_t *) &port);
  860                 if (result != KERN_SUCCESS) {
  861                         vm_map_deallocate(map);
  862                         return result;
  863                 }
  864         } else
  865                 port = (ipc_port_t) memory_object;
  866 
  867         copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
  868         result = vm_map(map, &addr, size, mask, anywhere,
  869                         port, offset, copy,
  870                         cur_protection, max_protection, inheritance);
  871         if (result == KERN_SUCCESS)
  872                 copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
  873         if (IP_VALID(port))
  874                 ipc_port_release_send(port);
  875         vm_map_deallocate(map);
  876 
  877         return result;
  878 }
  879 
  880 kern_return_t syscall_vm_allocate(target_map, address, size, anywhere)
  881         mach_port_t             target_map;
  882         vm_offset_t             *address;
  883         vm_size_t               size;
  884         boolean_t               anywhere;
  885 {
  886         vm_map_t                map;
  887         vm_offset_t             addr;
  888         kern_return_t           result;
  889 
  890         map = port_name_to_map(target_map);
  891         if (map == VM_MAP_NULL)
  892                 return MACH_SEND_INTERRUPTED;
  893 
  894         copyin((char *)address, (char *)&addr, sizeof(vm_offset_t));
  895         result = vm_allocate(map, &addr, size, anywhere);
  896         if (result == KERN_SUCCESS)
  897                 copyout((char *)&addr, (char *)address, sizeof(vm_offset_t));
  898         vm_map_deallocate(map);
  899 
  900         return result;
  901 }
  902 
  903 kern_return_t syscall_vm_deallocate(target_map, start, size)
  904         mach_port_t             target_map;
  905         vm_offset_t             start;
  906         vm_size_t               size;
  907 {
  908         vm_map_t                map;
  909         kern_return_t           result;
  910 
  911         map = port_name_to_map(target_map);
  912         if (map == VM_MAP_NULL)
  913                 return MACH_SEND_INTERRUPTED;
  914 
  915         result = vm_deallocate(map, start, size);
  916         vm_map_deallocate(map);
  917 
  918         return result;
  919 }
  920 
  921 kern_return_t syscall_task_create(parent_task, inherit_memory, child_task)
  922         mach_port_t     parent_task;
  923         boolean_t       inherit_memory;
  924         mach_port_t     *child_task;            /* OUT */
  925 {
  926         task_t          t, c;
  927         ipc_port_t      port;
  928         mach_port_t     name;
  929         kern_return_t   result;
  930 
  931         t = port_name_to_task(parent_task);
  932         if (t == TASK_NULL)
  933                 return MACH_SEND_INTERRUPTED;
  934 
  935         result = task_create(t, inherit_memory, &c);
  936         if (result == KERN_SUCCESS) {
  937                 port = (ipc_port_t) convert_task_to_port(c);
  938                 /* always returns a name, even for non-success return codes */
  939                 (void) ipc_kmsg_copyout_object(current_space(),
  940                                                (ipc_object_t) port,
  941                                                MACH_MSG_TYPE_PORT_SEND, &name);
  942                 copyout((char *)&name, (char *)child_task,
  943                         sizeof(mach_port_t));
  944         }
  945         task_deallocate(t);
  946 
  947         return result;
  948 }
  949 
  950 kern_return_t syscall_task_terminate(task)
  951         mach_port_t     task;
  952 {
  953         task_t          t;
  954         kern_return_t   result;
  955 
  956         t = port_name_to_task(task);
  957         if (t == TASK_NULL)
  958                 return MACH_SEND_INTERRUPTED;
  959 
  960         result = task_terminate(t);
  961         task_deallocate(t);
  962 
  963         return result;
  964 }
  965 
  966 kern_return_t syscall_task_suspend(task)
  967         mach_port_t     task;
  968 {
  969         task_t          t;
  970         kern_return_t   result;
  971 
  972         t = port_name_to_task(task);
  973         if (t == TASK_NULL)
  974                 return MACH_SEND_INTERRUPTED;
  975 
  976         result = task_suspend(t);
  977         task_deallocate(t);
  978 
  979         return result;
  980 }
  981 
  982 kern_return_t syscall_task_set_special_port(task, which_port, port_name)
  983         mach_port_t     task;
  984         int             which_port;
  985         mach_port_t     port_name;
  986 {
  987         task_t          t;
  988         ipc_port_t      port;
  989         kern_return_t   result;
  990 
  991         t = port_name_to_task(task);
  992         if (t == TASK_NULL)
  993                 return MACH_SEND_INTERRUPTED;
  994 
  995         if (MACH_PORT_VALID(port_name)) {
  996                 result = ipc_object_copyin(current_space(), port_name,
  997                                            MACH_MSG_TYPE_COPY_SEND,
  998                                            (ipc_object_t *) &port);
  999                 if (result != KERN_SUCCESS) {
 1000                         task_deallocate(t);
 1001                         return result;
 1002                 }
 1003         } else
 1004                 port = (ipc_port_t) port_name;
 1005 
 1006         result = task_set_special_port(t, which_port, port);
 1007         if ((result != KERN_SUCCESS) && IP_VALID(port))
 1008                 ipc_port_release_send(port);
 1009         task_deallocate(t);
 1010 
 1011         return result;
 1012 }
 1013 
 1014 kern_return_t
 1015 syscall_mach_port_allocate(task, right, namep)
 1016         mach_port_t task;
 1017         mach_port_right_t right;
 1018         mach_port_t *namep;
 1019 {
 1020         ipc_space_t space;
 1021         mach_port_t name;
 1022         kern_return_t kr;
 1023 
 1024         space = port_name_to_space(task);
 1025         if (space == IS_NULL)
 1026                 return MACH_SEND_INTERRUPTED;
 1027 
 1028         kr = mach_port_allocate(space, right, &name);
 1029         if (kr == KERN_SUCCESS)
 1030                 copyout((char *)&name, (char *)namep, sizeof(mach_port_t));
 1031         is_release(space);
 1032 
 1033         return kr;
 1034 }
 1035 
 1036 kern_return_t
 1037 syscall_mach_port_allocate_name(task, right, name)
 1038         mach_port_t task;
 1039         mach_port_right_t right;
 1040         mach_port_t name;
 1041 {
 1042         ipc_space_t space;
 1043         kern_return_t kr;
 1044 
 1045         space = port_name_to_space(task);
 1046         if (space == IS_NULL)
 1047                 return MACH_SEND_INTERRUPTED;
 1048 
 1049         kr = mach_port_allocate_name(space, right, name);
 1050         is_release(space);
 1051 
 1052         return kr;
 1053 }
 1054 
 1055 kern_return_t
 1056 syscall_mach_port_deallocate(task, name)
 1057         mach_port_t task;
 1058         mach_port_t name;
 1059 {
 1060         ipc_space_t space;
 1061         kern_return_t kr;
 1062 
 1063         space = port_name_to_space(task);
 1064         if (space == IS_NULL)
 1065                 return MACH_SEND_INTERRUPTED;
 1066 
 1067         kr = mach_port_deallocate(space, name);
 1068         is_release(space);
 1069 
 1070         return kr;
 1071 }
 1072 
 1073 kern_return_t
 1074 syscall_mach_port_insert_right(task, name, right, rightType)
 1075         mach_port_t task;
 1076         mach_port_t name;
 1077         mach_port_t right;
 1078         mach_msg_type_name_t rightType;
 1079 {
 1080         ipc_space_t space;
 1081         ipc_object_t object;
 1082         mach_msg_type_name_t newtype;
 1083         kern_return_t kr;
 1084 
 1085         space = port_name_to_space(task);
 1086         if (space == IS_NULL)
 1087                 return MACH_SEND_INTERRUPTED;
 1088 
 1089         if (!MACH_MSG_TYPE_PORT_ANY(rightType)) {
 1090                 is_release(space);
 1091                 return KERN_INVALID_VALUE;
 1092         }
 1093 
 1094         if (MACH_PORT_VALID(right)) {
 1095                 kr = ipc_object_copyin(current_space(), right, rightType,
 1096                                        &object);
 1097                 if (kr != KERN_SUCCESS) {
 1098                         is_release(space);
 1099                         return kr;
 1100                 }
 1101         } else
 1102                 object = (ipc_object_t) right;
 1103         newtype = ipc_object_copyin_type(rightType);
 1104 
 1105         kr = mach_port_insert_right(space, name, object, newtype);
 1106         if ((kr != KERN_SUCCESS) && IO_VALID(object))
 1107                 ipc_object_destroy(object, newtype);
 1108         is_release(space);
 1109 
 1110         return kr;
 1111 }
 1112 
 1113 kern_return_t syscall_thread_depress_abort(thread)
 1114         mach_port_t     thread;
 1115 {
 1116         thread_t        t;
 1117         kern_return_t   result;
 1118 
 1119         t = port_name_to_thread(thread);
 1120         if (t == THREAD_NULL)
 1121                 return MACH_SEND_INTERRUPTED;
 1122 
 1123         result = thread_depress_abort(t);
 1124         thread_deallocate(t);
 1125 
 1126         return result;
 1127 }
 1128 
 1129 /*
 1130  * Device traps -- these are way experimental.
 1131  */
 1132 
 1133 extern io_return_t ds_device_write_trap();
 1134 extern io_return_t ds_device_writev_trap();
 1135 
 1136 io_return_t
 1137 syscall_device_write_request(mach_port_t        device_name,
 1138                              mach_port_t        reply_name,
 1139                              dev_mode_t         mode,
 1140                              recnum_t           recnum,
 1141                              vm_offset_t        data,
 1142                              vm_size_t          data_count)
 1143 {
 1144         device_t        dev;
 1145         ipc_port_t      reply_port;
 1146         io_return_t     res;
 1147 
 1148         /*
 1149          * First try to translate the device name.
 1150          *
 1151          * If this fails, return KERN_INVALID_CAPABILITY.
 1152          * Caller knows that this most likely means that
 1153          * device is not local to node and IPC should be used.
 1154          *
 1155          * If kernel doesn't do device traps, kern_invalid()
 1156          * will be called instead of this function which will
 1157          * return KERN_INVALID_ARGUMENT.
 1158          */
 1159         dev = port_name_to_device(device_name);
 1160         if (dev == DEVICE_NULL)
 1161                 return KERN_INVALID_CAPABILITY;
 1162 
 1163         /*
 1164          * Translate reply port.
 1165          */
 1166         if (reply_name == MACH_PORT_NULL)
 1167                 reply_port = IP_NULL;
 1168         else {
 1169                 /* Homey don't play that. */
 1170                 device_deallocate(dev);
 1171                 return KERN_INVALID_RIGHT;
 1172         }
 1173 
 1174         /* note: doesn't take reply_port arg yet. */
 1175         res = ds_device_write_trap(dev, /*reply_port,*/
 1176                                    mode, recnum,
 1177                                    data, data_count);
 1178 
 1179         /*
 1180          * Give up reference from port_name_to_device.
 1181          */
 1182         device_deallocate(dev);
 1183         return res;
 1184 }
 1185 
 1186 io_return_t
 1187 syscall_device_writev_request(mach_port_t       device_name,
 1188                               mach_port_t       reply_name,
 1189                               dev_mode_t        mode,
 1190                               recnum_t          recnum,
 1191                               io_buf_vec_t      *iovec,
 1192                               vm_size_t         iocount)
 1193 {
 1194         device_t        dev;
 1195         ipc_port_t      reply_port;
 1196         io_return_t     res;
 1197 
 1198         /*
 1199          * First try to translate the device name.
 1200          *
 1201          * If this fails, return KERN_INVALID_CAPABILITY.
 1202          * Caller knows that this most likely means that
 1203          * device is not local to node and IPC should be used.
 1204          *
 1205          * If kernel doesn't do device traps, kern_invalid()
 1206          * will be called instead of this function which will
 1207          * return KERN_INVALID_ARGUMENT.
 1208          */
 1209         dev = port_name_to_device(device_name);
 1210         if (dev == DEVICE_NULL)
 1211                 return KERN_INVALID_CAPABILITY;
 1212 
 1213         /*
 1214          * Translate reply port.
 1215          */
 1216         if (reply_name == MACH_PORT_NULL)
 1217                 reply_port = IP_NULL;
 1218         else {
 1219                 /* Homey don't play that. */
 1220                 device_deallocate(dev);
 1221                 return KERN_INVALID_RIGHT;
 1222         }
 1223 
 1224         /* note: doesn't take reply_port arg yet. */
 1225         res = ds_device_writev_trap(dev, /*reply_port,*/
 1226                                     mode, recnum,
 1227                                     iovec, iocount);
 1228 
 1229         /*
 1230          * Give up reference from port_name_to_device.
 1231          */
 1232         device_deallocate(dev);
 1233         return res;
 1234 }
 1235 
 1236 

Cache object: 6e18cc0fea97ce382b0ee038c83e23ba


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