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_kobject.c

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

    1 /* 
    2  * Mach Operating System
    3  * Copyright (c) 1993,1992,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_kobject.c,v $
   29  * Revision 2.16  93/11/17  17:10:30  dbg
   30  *      Added kern_reply_kmsg_zone, for quick allocation of kernel reply
   31  *      messages.
   32  *      [93/03/30            dbg]
   33  * 
   34  *      Added ANSI function prototypes.
   35  *      [93/02/04            dbg]
   36  * 
   37  * Revision 2.15  93/01/24  13:19:00  danner
   38  *      Introduce Mach4 interface.  Initially for pc sampling.
   39  *      [93/01/11            rvb]
   40  * 
   41  * Revision 2.14  92/08/03  17:37:23  jfriedl
   42  *      removed silly prototypes
   43  *      [92/08/02            jfriedl]
   44  * 
   45  * Revision 2.13  92/05/21  17:13:47  jfriedl
   46  *      Made correct for when assert is off.
   47  *      [92/05/16            jfriedl]
   48  * 
   49  * Revision 2.12  92/03/10  16:26:28  jsb
   50  *      Add IKOT_PAGER_TERMINATING case to ipc_kobject_destroy.
   51  *      [92/02/25            dlb]
   52  *      Added ipc_kobject_notify for kernel-requested notifications.
   53  *      Added code to correctly release send-once kobject destinations.
   54  *      [92/01/21  18:20:19  jsb]
   55  * 
   56  * Revision 2.11  92/01/03  20:14:32  dbg
   57  *      Call <subsystem>_routine_name to find IPC stub to execute.
   58  *      Build reply message header by hand. (XXX)
   59  *      Simplify cleanup of request message when reply is success.
   60  *      [91/12/18            dbg]
   61  * 
   62  * Revision 2.10  91/12/13  13:42:24  jsb
   63  *      Added support for norma/norma_internal.defs.
   64  * 
   65  * Revision 2.9  91/08/01  14:36:18  dbg
   66  *      Call machine-dependent interface routine, under
   67  *      MACH_MACHINE_ROUTINES.
   68  *      [91/08/01            dbg]
   69  * 
   70  * Revision 2.8  91/06/17  15:47:02  jsb
   71  *      Renamed NORMA conditionals. Added NORMA_VM support.
   72  *      [91/06/17  13:46:55  jsb]
   73  * 
   74  * Revision 2.7  91/06/06  17:07:05  jsb
   75  *      Added NORMA_TASK support.
   76  *      [91/05/14  09:05:48  jsb]
   77  * 
   78  * Revision 2.6  91/05/18  14:31:42  rpd
   79  *      Added check_simple_locks.
   80  *      [91/04/01            rpd]
   81  * 
   82  * Revision 2.5  91/05/14  16:42:00  mrt
   83  *      Correcting copyright
   84  * 
   85  * Revision 2.4  91/03/16  14:50:02  rpd
   86  *      Replaced ith_saved with ikm_cache.
   87  *      [91/02/16            rpd]
   88  * 
   89  * Revision 2.3  91/02/05  17:26:37  mrt
   90  *      Changed to new Mach copyright
   91  *      [91/02/01  16:12:51  mrt]
   92  * 
   93  * Revision 2.2  90/06/02  14:54:08  rpd
   94  *      Created for new IPC.
   95  *      [90/03/26  23:46:53  rpd]
   96  * 
   97  */
   98 /*
   99  *      File:   kern/ipc_kobject.c
  100  *      Author: Rich Draves
  101  *      Date:   1989
  102  *
  103  *      Functions for letting a port represent a kernel object.
  104  */
  105 
  106 #include <mach_debug.h>
  107 #include <mach_ipc_test.h>
  108 #include <mach_machine_routines.h>
  109 #include <mach_rt.h>
  110 #include <norma_task.h>
  111 #include <norma_vm.h>
  112 
  113 #include <mach/port.h>
  114 #include <mach/kern_return.h>
  115 #include <mach/message.h>
  116 #include <mach/mig_errors.h>
  117 #include <mach/notify.h>
  118 #include <kern/ipc_kobject.h>
  119 #include <ipc/ipc_object.h>
  120 #include <ipc/ipc_kmsg.h>
  121 #include <ipc/ipc_port.h>
  122 #include <ipc/ipc_thread.h>
  123 #include <kern/kern_kmsg.h>
  124 #include <kern/kern_io.h>
  125 #include <kern/mach_timer.h>
  126 #include <device/ds_routines.h>
  127 
  128 #if     MACH_MACHINE_ROUTINES
  129 #include <machine/machine_routines.h>
  130 #endif
  131 
  132 /*
  133  *      Size of kernel reply messages.
  134  *      Value is historical.
  135  */
  136 #define KERNEL_REPLY_KMSG_SIZE          (8192)
  137 
  138 int     kern_reply_kmsg_size = KERNEL_REPLY_KMSG_SIZE;
  139 int     kern_reply_kmsg_max  = 4096;
  140 /*
  141  *      Zone for kernel reply messages.
  142  */
  143 zone_t  kernel_reply_kmsg_zone;
  144 
  145 boolean_t
  146 ipc_kobject_notify(
  147         mach_msg_header_t *request_header,
  148         mach_msg_header_t *reply_header);       /* forward */
  149 
  150 /*
  151  *      Initialize zone.
  152  */
  153 void kernel_reply_kmsg_init(void)
  154 {
  155         kernel_reply_kmsg_zone = zinit(
  156                         kern_reply_kmsg_size,
  157                         kern_reply_kmsg_size * kern_reply_kmsg_max,
  158                         kern_reply_kmsg_size,
  159                         FALSE,
  160                         "kernel reply messages");
  161 }
  162 
  163 /*
  164  *      Routine:        ipc_kobject_server
  165  *      Purpose:
  166  *              Handle a message sent to the kernel.
  167  *              Generates a reply message.
  168  *      Conditions:
  169  *              Nothing locked.
  170  */
  171 
  172 ipc_kmsg_t
  173 ipc_kobject_server(
  174         ipc_kmsg_t request)
  175 {
  176         ipc_kmsg_t reply;
  177         kern_return_t kr;
  178         mig_routine_t routine;
  179         ipc_port_t dest;
  180 
  181         kernel_reply_kmsg_get(reply);
  182         if (reply == IKM_NULL) {
  183                 printf("ipc_kobject_server: dropping request\n");
  184                 ipc_kmsg_destroy(request);
  185                 return IKM_NULL;
  186         }
  187 
  188         /*
  189          * Initialize reply message.
  190          */
  191         {
  192 #define InP     ((mach_msg_header_t *) &request->ikm_header)
  193 #define OutP    ((mig_reply_header_t *) &reply->ikm_header)
  194 
  195             static mach_msg_type_t RetCodeType = {
  196                 /* msgt_name = */               MACH_MSG_TYPE_INTEGER_32,
  197                 /* msgt_size = */               32,
  198                 /* msgt_number = */             1,
  199                 /* msgt_inline = */             TRUE,
  200                 /* msgt_longform = */           FALSE,
  201                 /* msgt_unused = */             0
  202             };
  203             OutP->Head.msgh_bits =
  204                 MACH_MSGH_BITS(MACH_MSGH_BITS_LOCAL(InP->msgh_bits), 0);
  205             OutP->Head.msgh_size = sizeof(mig_reply_header_t);
  206             OutP->Head.msgh_remote_port = InP->msgh_local_port;
  207             OutP->Head.msgh_local_port  = MACH_PORT_NULL;
  208             OutP->Head.msgh_seqno = 0;
  209             OutP->Head.msgh_id = InP->msgh_id + 100;
  210 
  211             OutP->RetCodeType = RetCodeType;
  212 
  213 #undef  InP
  214 #undef  OutP
  215         }
  216 
  217         /*
  218          * Find the server routine to call, and call it
  219          * to perform the kernel function
  220          */
  221     {
  222         extern mig_routine_t
  223                 mach_server_routine(mach_msg_header_t *),
  224                 mach_port_server_routine(mach_msg_header_t *),
  225                 mach_host_server_routine(mach_msg_header_t *),
  226                 device_server_routine(mach_msg_header_t *),
  227                 device_pager_server_routine(mach_msg_header_t *),
  228                 mach4_server_routine(mach_msg_header_t *);
  229 #if     MACH_DEBUG
  230         extern mig_routine_t
  231                 mach_debug_server_routine(mach_msg_header_t *);
  232 #endif
  233 #if     NORMA_TASK
  234         extern mig_routine_t
  235                 mach_norma_server_routine(mach_msg_header_t *),
  236                 norma_internal_server_routine(mach_msg_header_t *);
  237 #endif
  238 #if     NORMA_VM
  239         extern mig_routine_t
  240                 proxy_server_routine(mach_msg_header_t *);
  241 #endif
  242 
  243 #if     MACH_MACHINE_ROUTINES
  244         extern mig_routine_t
  245                 MACHINE_SERVER_ROUTINE(mach_msg_header_t *);
  246 #endif
  247 
  248         check_simple_locks();
  249         if ((routine = mach_server_routine(&request->ikm_header)) != 0
  250          || (routine = mach_port_server_routine(&request->ikm_header)) != 0
  251          || (routine = mach_host_server_routine(&request->ikm_header)) != 0
  252          || (routine = device_server_routine(&request->ikm_header)) != 0
  253          || (routine = device_pager_server_routine(&request->ikm_header)) != 0
  254 #if     MACH_DEBUG
  255          || (routine = mach_debug_server_routine(&request->ikm_header)) != 0
  256 #endif
  257 #if     NORMA_TASK
  258          || (routine = mach_norma_server_routine(&request->ikm_header)) != 0
  259          || (routine = norma_internal_server_routine(&request->ikm_header)) != 0
  260 #endif
  261 #if     NORMA_VM
  262          || (routine = proxy_server_routine(&request->ikm_header)) != 0
  263 #endif
  264          || (routine = mach4_server_routine(&request->ikm_header)) != 0
  265 #if     MACH_MACHINE_ROUTINES
  266          || (routine = MACHINE_SERVER_ROUTINE(&request->ikm_header)) != 0
  267 #endif
  268         ) {
  269             (*routine)(&request->ikm_header, &reply->ikm_header);
  270         }
  271         else if (!ipc_kobject_notify(&request->ikm_header,&reply->ikm_header)){
  272                 ((mig_reply_header_t *) &reply->ikm_header)->RetCode
  273                     = MIG_BAD_ID;
  274 #if     MACH_IPC_TEST
  275                 printf("ipc_kobject_server: bogus kernel message, id=%d\n",
  276                        request->ikm_header.msgh_id);
  277 #endif  /* MACH_IPC_TEST */
  278         }
  279     }
  280         check_simple_locks();
  281 
  282         /*
  283          *      Destroy destination. The following code differs from
  284          *      ipc_object_destroy in that we release the send-once
  285          *      right instead of generating a send-once notification
  286          *      (which would bring us here again, creating a loop).
  287          *      It also differs in that we only expect send or
  288          *      send-once rights, never receive rights.
  289          *
  290          *      We set msgh_remote_port to IP_NULL so that the kmsg
  291          *      destroy routines don't try to destroy the port twice.
  292          */
  293         dest = (ipc_port_t) request->ikm_header.msgh_remote_port;
  294         switch (MACH_MSGH_BITS_REMOTE(request->ikm_header.msgh_bits)) {
  295             case MACH_MSG_TYPE_PORT_SEND:
  296                 ipc_port_release_send(dest);
  297                 break;
  298                 
  299             case MACH_MSG_TYPE_PORT_SEND_ONCE:
  300                 ipc_port_release_sonce(dest);
  301                 break;
  302                 
  303             default:
  304 #if MACH_ASSERT
  305                 assert(!"ipc_object_destroy: strange destination rights");
  306 #else
  307                 panic("ipc_object_destroy: strange destination rights");
  308 #endif
  309         }
  310 
  311         kr = ((mig_reply_header_t *) &reply->ikm_header)->RetCode;
  312         if ((kr == KERN_SUCCESS) || (kr == MIG_NO_REPLY)) {
  313                 /*
  314                  *      The server function is responsible for the contents
  315                  *      of the message.  The reply port right is moved
  316                  *      to the reply message, and we have deallocated
  317                  *      the destination port right, so we just need
  318                  *      to free the kmsg.
  319                  */
  320 
  321                 /* like ipc_kmsg_put, but without the copyout */
  322 
  323                 ikm_check_initialized(request, request->ikm_size);
  324                 if ((request->ikm_size == IKM_SAVED_KMSG_SIZE) &&
  325                     (ikm_cache() == IKM_NULL))
  326                         ikm_cache() = request;
  327                 else
  328                         ikm_free(request);
  329         } else {
  330                 /*
  331                  *      The message contents of the request are intact.
  332                  *      Destroy everything except the reply port right,
  333                  *      which is needed in the reply message.  The
  334                  *      destination port right has already been destroyed.
  335                  */
  336 
  337                 request->ikm_header.msgh_remote_port = MACH_PORT_NULL;
  338                 request->ikm_header.msgh_local_port = MACH_PORT_NULL;
  339                 ipc_kmsg_destroy(request);
  340         }
  341 
  342         if (kr == MIG_NO_REPLY) {
  343                 /*
  344                  *      The server function will send a reply message
  345                  *      using the reply port right, which it has saved.
  346                  */
  347 
  348                 ikm_free(reply);
  349                 return IKM_NULL;
  350         } else if (!IP_VALID((ipc_port_t)reply->ikm_header.msgh_remote_port)) {
  351                 /*
  352                  *      Can't queue the reply message if the destination
  353                  *      (the reply port) isn't valid.
  354                  */
  355 
  356                 ipc_kmsg_destroy(reply);
  357                 return IKM_NULL;
  358         }
  359 
  360         return reply;
  361 }
  362 
  363 /*
  364  *      Routine:        ipc_kobject_set
  365  *      Purpose:
  366  *              Make a port represent a kernel object of the given type.
  367  *              The caller is responsible for handling refs for the
  368  *              kernel object, if necessary.
  369  *      Conditions:
  370  *              Nothing locked.  The port must be active.
  371  */
  372 
  373 void
  374 ipc_kobject_set(
  375         ipc_port_t port,
  376         ipc_kobject_t kobject,
  377         ipc_kobject_type_t type)
  378 {
  379         ip_lock(port);
  380         assert(ip_active(port));
  381         port->ip_bits = (port->ip_bits &~ IO_BITS_KOTYPE) | type;
  382         port->ip_kobject = kobject;
  383         ip_unlock(port);
  384 }
  385 
  386 /*
  387  *      Routine:        ipc_kobject_destroy
  388  *      Purpose:
  389  *              Release any kernel object resources associated
  390  *              with the port, which is being destroyed.
  391  *
  392  *              This should only be needed when resources are
  393  *              associated with a user's port.  In the normal case,
  394  *              when the kernel is the receiver, the code calling
  395  *              ipc_port_dealloc_kernel should clean up the resources.
  396  *      Conditions:
  397  *              The port is not locked, but it is dead.
  398  */
  399 
  400 void
  401 ipc_kobject_destroy(
  402         ipc_port_t port)
  403 {
  404         switch (ip_kotype(port)) {
  405             case IKOT_PAGER:
  406                 vm_object_destroy(port);
  407                 break;
  408 
  409             case IKOT_PAGER_TERMINATING:
  410                 vm_object_pager_wakeup(port);
  411                 break;
  412 
  413             default:
  414 #if     MACH_ASSERT
  415                 printf("ipc_kobject_destroy: port 0x%x, kobj 0x%x, type %d\n",
  416                        port, port->ip_kobject, ip_kotype(port));
  417 #endif  /* MACH_ASSERT */
  418                 break;
  419         }
  420 }
  421 
  422 /*
  423  *      Routine:        ipc_kobject_notify
  424  *      Purpose:
  425  *              Deliver notifications to kobjects that care about them.
  426  */
  427 
  428 boolean_t
  429 ipc_kobject_notify(
  430         mach_msg_header_t *request_header,
  431         mach_msg_header_t *reply_header)
  432 {
  433         ipc_port_t port = (ipc_port_t) request_header->msgh_remote_port;
  434 
  435         ((mig_reply_header_t *) reply_header)->RetCode = MIG_NO_REPLY;
  436         switch (request_header->msgh_id) {
  437                 case MACH_NOTIFY_PORT_DELETED:
  438                 case MACH_NOTIFY_MSG_ACCEPTED:
  439                 case MACH_NOTIFY_PORT_DESTROYED:
  440                 case MACH_NOTIFY_NO_SENDERS:
  441                 case MACH_NOTIFY_SEND_ONCE:
  442                 case MACH_NOTIFY_DEAD_NAME:
  443                 break;
  444 
  445                 default:
  446                 return FALSE;
  447         }
  448         switch (ip_kotype(port)) {
  449 #if     NORMA_VM
  450                 case IKOT_XMM_OBJECT:
  451                 return xmm_object_notify(request_header);
  452 
  453                 case IKOT_XMM_PAGER:
  454                 return xmm_pager_notify(request_header);
  455 
  456                 case IKOT_XMM_KERNEL:
  457                 return xmm_kernel_notify(request_header);
  458 
  459                 case IKOT_XMM_REPLY:
  460                 return xmm_reply_notify(request_header);
  461 #endif  /* NORMA_VM */
  462 
  463                 case IKOT_DEVICE:
  464                 return ds_notify(request_header);
  465 
  466                 case IKOT_TIMER:
  467                 return timer_notify(request_header);
  468 
  469                 default:
  470                 return FALSE;
  471         }
  472 }

Cache object: d308f98e135a7af963e83832f6b0a615


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