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/compat/mach/mach_port.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 /*      $NetBSD: mach_port.c,v 1.65 2008/04/28 20:23:44 martin Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 2002-2003 The NetBSD Foundation, Inc.
    5  * All rights reserved.
    6  *
    7  * This code is derived from software contributed to The NetBSD Foundation
    8  * by Emmanuel Dreyfus
    9  *
   10  * Redistribution and use in source and binary forms, with or without
   11  * modification, are permitted provided that the following conditions
   12  * are met:
   13  * 1. Redistributions of source code must retain the above copyright
   14  *    notice, this list of conditions and the following disclaimer.
   15  * 2. Redistributions in binary form must reproduce the above copyright
   16  *    notice, this list of conditions and the following disclaimer in the
   17  *    documentation and/or other materials provided with the distribution.
   18  *
   19  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   20  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   21  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   22  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   23  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   24  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   25  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   26  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   27  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   28  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   29  * POSSIBILITY OF SUCH DAMAGE.
   30  */
   31 
   32 #include "opt_compat_darwin.h"
   33 
   34 #include <sys/cdefs.h>
   35 __KERNEL_RCSID(0, "$NetBSD: mach_port.c,v 1.65 2008/04/28 20:23:44 martin Exp $");
   36 
   37 #include <sys/types.h>
   38 #include <sys/param.h>
   39 #include <sys/systm.h>
   40 #include <sys/signal.h>
   41 #include <sys/pool.h>
   42 #include <sys/queue.h>
   43 #include <sys/malloc.h>
   44 #include <sys/proc.h>
   45 
   46 #include <compat/mach/mach_types.h>
   47 #include <compat/mach/mach_message.h>
   48 #include <compat/mach/mach_port.h>
   49 #include <compat/mach/mach_iokit.h>
   50 #include <compat/mach/mach_clock.h>
   51 #include <compat/mach/mach_exec.h>
   52 #include <compat/mach/mach_errno.h>
   53 #include <compat/mach/mach_notify.h>
   54 #include <compat/mach/mach_services.h>
   55 #include <compat/mach/mach_syscallargs.h>
   56 
   57 #ifdef COMPAT_DARWIN
   58 #include <compat/darwin/darwin_exec.h>
   59 #endif
   60 
   61 /* Right and port pools, list of all rights and its lock */
   62 static struct pool mach_port_pool;
   63 static struct pool mach_right_pool;
   64 
   65 struct mach_port *mach_bootstrap_port;
   66 struct mach_port *mach_clock_port;
   67 struct mach_port *mach_io_master_port;
   68 struct mach_port *mach_saved_bootstrap_port;
   69 
   70 int
   71 mach_sys_reply_port(struct lwp *l, const void *v, register_t *retval)
   72 {
   73         struct mach_right *mr;
   74 
   75         mr = mach_right_get(mach_port_get(), l, MACH_PORT_TYPE_RECEIVE, 0);
   76         *retval = (register_t)mr->mr_name;
   77 
   78         return 0;
   79 }
   80 
   81 int
   82 mach_sys_thread_self_trap(struct lwp *l, const void *v, register_t *retval)
   83 {
   84         struct mach_lwp_emuldata *mle;
   85         struct mach_right *mr;
   86 
   87         mle = l->l_emuldata;
   88         mr = mach_right_get(mle->mle_kernel, l, MACH_PORT_TYPE_SEND, 0);
   89         *retval = (register_t)mr->mr_name;
   90 
   91         return 0;
   92 }
   93 
   94 
   95 int
   96 mach_sys_task_self_trap(struct lwp *l, const void *v, register_t *retval)
   97 {
   98         struct mach_emuldata *med;
   99         struct mach_right *mr;
  100 
  101         med = (struct mach_emuldata *)l->l_proc->p_emuldata;
  102         mr = mach_right_get(med->med_kernel, l, MACH_PORT_TYPE_SEND, 0);
  103         *retval = (register_t)mr->mr_name;
  104 
  105         return 0;
  106 }
  107 
  108 
  109 int
  110 mach_sys_host_self_trap(struct lwp *l, const void *v, register_t *retval)
  111 {
  112         struct mach_emuldata *med;
  113         struct mach_right *mr;
  114 
  115         med = (struct mach_emuldata *)l->l_proc->p_emuldata;
  116         mr = mach_right_get(med->med_host, l, MACH_PORT_TYPE_SEND, 0);
  117         *retval = (register_t)mr->mr_name;
  118 
  119         return 0;
  120 }
  121 
  122 int
  123 mach_port_deallocate(struct mach_trap_args *args)
  124 {
  125         mach_port_deallocate_request_t *req = args->smsg;
  126         mach_port_deallocate_reply_t *rep = args->rmsg;
  127         size_t *msglen = args->rsize;
  128         struct lwp *l = args->l;
  129         mach_port_t mn;
  130         struct mach_right *mr;
  131 
  132         mn = req->req_name;
  133         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_REF_RIGHTS)) != NULL)
  134                 mach_right_put(mr, MACH_PORT_TYPE_REF_RIGHTS);
  135 
  136         *msglen = sizeof(*rep);
  137         mach_set_header(rep, req, *msglen);
  138 
  139         rep->rep_retval = 0;
  140 
  141         mach_set_trailer(rep, *msglen);
  142 
  143         return 0;
  144 }
  145 
  146 int
  147 mach_port_destroy(struct mach_trap_args *args)
  148 {
  149         mach_port_destroy_request_t *req = args->smsg;
  150         mach_port_destroy_reply_t *rep = args->rmsg;
  151         size_t *msglen = args->rsize;
  152         struct lwp *l = args->l;
  153         mach_port_t mn;
  154         struct mach_right *mr;
  155 
  156 #ifdef DEBUG_MACH
  157         printf("mach_port_destroy mn = %x\n", req->req_name);
  158 #endif
  159         mn = req->req_name;
  160         if ((mr = mach_right_check(mn,
  161             l, MACH_PORT_TYPE_ALL_RIGHTS)) != NULL) {
  162                 MACH_PORT_UNREF(mr->mr_port);
  163                 mr->mr_port = NULL;
  164                 mach_right_put(mr, MACH_PORT_TYPE_ALL_RIGHTS);
  165         }
  166 
  167         *msglen = sizeof(*rep);
  168         mach_set_header(rep, req, *msglen);
  169 
  170         rep->rep_retval = 0;
  171 
  172         mach_set_trailer(rep, *msglen);
  173 
  174         return 0;
  175 }
  176 
  177 int
  178 mach_port_allocate(struct mach_trap_args *args)
  179 {
  180         mach_port_allocate_request_t *req = args->smsg;
  181         mach_port_allocate_reply_t *rep = args->rmsg;
  182         size_t *msglen = args->rsize;
  183         struct lwp *l = args->l;
  184         struct mach_right *mr;
  185         struct mach_port *mp;
  186 
  187         switch (req->req_right) {
  188         case MACH_PORT_RIGHT_RECEIVE:
  189                 mp = mach_port_get();
  190                 mr = mach_right_get(mp, l, MACH_PORT_TYPE_RECEIVE, 0);
  191                 break;
  192 
  193         case MACH_PORT_RIGHT_DEAD_NAME:
  194                 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_DEAD_NAME, 0);
  195                 break;
  196 
  197         case MACH_PORT_RIGHT_PORT_SET:
  198                 mr = mach_right_get(NULL, l, MACH_PORT_TYPE_PORT_SET, 0);
  199                 break;
  200 
  201         default:
  202                 uprintf("mach_port_allocate: unknown right %x\n",
  203                     req->req_right);
  204                 return mach_msg_error(args, EINVAL);
  205                 break;
  206         }
  207 
  208         *msglen = sizeof(*rep);
  209         mach_set_header(rep, req, *msglen);
  210 
  211         rep->rep_retval = 0;
  212         rep->rep_name = (mach_port_name_t)mr->mr_name;
  213 
  214         mach_set_trailer(rep, *msglen);
  215 
  216         return 0;
  217 }
  218 
  219 int
  220 mach_port_insert_right(struct mach_trap_args *args)
  221 {
  222         mach_port_insert_right_request_t *req = args->smsg;
  223         mach_port_insert_right_reply_t *rep = args->rmsg;
  224         size_t *msglen = args->rsize;
  225         struct lwp *l = args->l;
  226         mach_port_t name;
  227         mach_port_t right;
  228         struct mach_right *mr;
  229         struct mach_right *nmr;
  230 
  231         name = req->req_name;
  232         right = req->req_poly.name;
  233         nmr = NULL;
  234 
  235         mr = mach_right_check(right, l, MACH_PORT_TYPE_ALL_RIGHTS);
  236         if (mr == NULL)
  237                 return mach_msg_error(args, EPERM);
  238 
  239         switch (req->req_poly.disposition) {
  240         case MACH_MSG_TYPE_MAKE_SEND:
  241         case MACH_MSG_TYPE_MOVE_SEND:
  242         case MACH_MSG_TYPE_COPY_SEND:
  243                 nmr = mach_right_get(mr->mr_port,
  244                     l, MACH_PORT_TYPE_SEND, name);
  245                 break;
  246 
  247         case MACH_MSG_TYPE_MAKE_SEND_ONCE:
  248         case MACH_MSG_TYPE_MOVE_SEND_ONCE:
  249                 nmr = mach_right_get(mr->mr_port,
  250                     l, MACH_PORT_TYPE_SEND_ONCE, name);
  251                 break;
  252 
  253         case MACH_MSG_TYPE_MOVE_RECEIVE:
  254                 nmr = mach_right_get(mr->mr_port,
  255                     l, MACH_PORT_TYPE_RECEIVE, name);
  256                 break;
  257 
  258         default:
  259                 uprintf("mach_port_insert_right: unknown right %x\n",
  260                     req->req_poly.disposition);
  261                 break;
  262         }
  263 
  264         *msglen = sizeof(*rep);
  265         mach_set_header(rep, req, *msglen);
  266 
  267         rep->rep_retval = 0;
  268 
  269         mach_set_trailer(rep, *msglen);
  270 
  271         return 0;
  272 }
  273 
  274 int
  275 mach_port_type(struct mach_trap_args *args)
  276 {
  277         mach_port_type_request_t *req = args->smsg;
  278         mach_port_type_reply_t *rep = args->rmsg;
  279         size_t *msglen = args->rsize;
  280         struct lwp *l = args->l;
  281         mach_port_t mn;
  282         struct mach_right *mr;
  283 
  284         mn = req->req_name;
  285         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  286                 return mach_msg_error(args, EPERM);
  287 
  288         *msglen = sizeof(*rep);
  289         mach_set_header(rep, req, *msglen);
  290 
  291         rep->rep_retval = 0;
  292         rep->rep_ptype = mr->mr_type;
  293 
  294         mach_set_trailer(rep, *msglen);
  295 
  296         return 0;
  297 }
  298 
  299 int
  300 mach_port_set_attributes(struct mach_trap_args *args)
  301 {
  302         mach_port_set_attributes_request_t *req = args->smsg;
  303         mach_port_set_attributes_reply_t *rep = args->rmsg;
  304         size_t *msglen = args->rsize;
  305         int end_offset;
  306 
  307         /* Sanity check req->req_count */
  308         end_offset = req->req_count;
  309         if (MACH_REQMSG_OVERFLOW(args, req->req_port_info[end_offset]))
  310                  return mach_msg_error(args, EINVAL);
  311 
  312         switch(req->req_flavor) {
  313         case MACH_PORT_LIMITS_INFO:
  314         case MACH_PORT_RECEIVE_STATUS:
  315         case MACH_PORT_DNREQUESTS_SIZE:
  316                 break;
  317         default:
  318                 uprintf("mach_port_set_attributes: unknown flavor %d\n",
  319                     req->req_flavor);
  320                 break;
  321         }
  322 
  323         *msglen = sizeof(*rep);
  324         mach_set_header(rep, req, *msglen);
  325 
  326         rep->rep_retval = 0;
  327 
  328         mach_set_trailer(rep, *msglen);
  329 
  330         return 0;
  331 }
  332 
  333 int
  334 mach_port_get_attributes(struct mach_trap_args *args)
  335 {
  336         mach_port_get_attributes_request_t *req = args->smsg;
  337         mach_port_get_attributes_reply_t *rep = args->rmsg;
  338         size_t *msglen = args->rsize;
  339         struct lwp *l = args->l;
  340         mach_port_t mn;
  341         struct mach_right *mr;
  342 
  343         /* Sanity check req_count */
  344         if (req->req_count > 10)
  345                 return mach_msg_error(args, EINVAL);
  346 
  347         mn = req->req_msgh.msgh_remote_port;
  348         if ((mr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  349                 return mach_msg_error(args, EPERM);
  350 
  351         switch (req->req_flavor) {
  352         case MACH_PORT_LIMITS_INFO: {
  353                 struct mach_port_limits *mpl;
  354 
  355                 if (req->req_count < (sizeof(*mpl) / sizeof(rep->rep_info[0])))
  356                         return mach_msg_error(args, EINVAL);
  357 
  358                 mpl = (struct mach_port_limits *)&rep->rep_info[0];
  359                 mpl->mpl_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
  360 
  361                 rep->rep_count = sizeof(*mpl);
  362 
  363                 break;
  364         }
  365 
  366         case MACH_PORT_RECEIVE_STATUS: {
  367                 struct mach_port_status *mps;
  368                 struct mach_port *mp;
  369 
  370                 if (req->req_count < (sizeof(*mps) / sizeof(rep->rep_info[0])))
  371                         return mach_msg_error(args, EINVAL);
  372 
  373                 mps = (struct mach_port_status *)&rep->rep_info[0];
  374                 memset(mps, 0, sizeof(*mps));
  375 
  376                 if (mr->mr_sethead != NULL)
  377                         mps->mps_pset = mr->mr_sethead->mr_name;
  378                 mps->mps_seqno = 0; /* XXX */
  379                 mps->mps_qlimit = MACH_PORT_QLIMIT_DEFAULT; /* XXX fake limit */
  380                 if ((mp = mr->mr_port) != NULL) {
  381                         mps->mps_mscount = mp->mp_refcount; /* XXX */
  382                         mps->mps_msgcount = mp->mp_count;
  383                 } else {
  384                         mps->mps_mscount = 0;
  385                         mps->mps_msgcount = 0;
  386                 }
  387                 mps->mps_sorights = 0; /* XXX */
  388                 mps->mps_srights =  0; /* XXX */
  389                 if (mr->mr_notify_destroyed != NULL)
  390                         mps->mps_pdrequest = 1;
  391                 if (mr->mr_notify_no_senders != NULL)
  392                         mps->mps_nsrequest = 1;
  393                 mps->mps_flags = 0; /* XXX */
  394 
  395                 rep->rep_count = sizeof(*mps);
  396                 break;
  397         }
  398 
  399         default:
  400                 printf("mach_port_get_attributes: unknown flavor %d\n",
  401                     req->req_flavor);
  402                 return mach_msg_error(args, EINVAL);
  403 
  404                 break;
  405         };
  406 
  407         *msglen = sizeof(*rep) - 10 + rep->rep_count;
  408         mach_set_header(rep, req, *msglen);
  409 
  410         rep->rep_retval = 0;
  411 
  412         mach_set_trailer(rep, *msglen);
  413 
  414         return 0;
  415 }
  416 
  417 /* XXX insert a recv right into a port set without removing it from another */
  418 int
  419 mach_port_insert_member(struct mach_trap_args *args)
  420 {
  421         mach_port_insert_member_request_t *req = args->smsg;
  422         mach_port_insert_member_reply_t *rep = args->rmsg;
  423         size_t *msglen = args->rsize;
  424 
  425         uprintf("Unimplemented mach_port_insert_member\n");
  426 
  427         *msglen = sizeof(*rep);
  428         mach_set_header(rep, req, *msglen);
  429 
  430         rep->rep_retval = 0;
  431 
  432         mach_set_trailer(rep, *msglen);
  433 
  434         return 0;
  435 }
  436 
  437 int
  438 mach_port_move_member(struct mach_trap_args *args)
  439 {
  440         mach_port_move_member_request_t *req = args->smsg;
  441         mach_port_move_member_reply_t *rep = args->rmsg;
  442         size_t *msglen = args->rsize;
  443         struct lwp *l = args->l;
  444         struct mach_emuldata *med = l->l_proc->p_emuldata;
  445         mach_port_t member = req->req_member;
  446         mach_port_t after = req->req_after;
  447         struct mach_right *mrr;
  448         struct mach_right *mrs;
  449 
  450         mrr = mach_right_check(member, l, MACH_PORT_TYPE_RECEIVE);
  451         if (mrr == NULL)
  452                 return mach_msg_error(args, EPERM);
  453 
  454         mrs = mach_right_check(after, l, MACH_PORT_TYPE_PORT_SET);
  455         if (mrs == NULL)
  456                 return mach_msg_error(args, EPERM);
  457 
  458         rw_enter(&med->med_rightlock, RW_WRITER);
  459 
  460         /* Remove it from an existing port set */
  461         if (mrr->mr_sethead != mrr)
  462                 LIST_REMOVE(mrr, mr_setlist);
  463 
  464         /* Insert it into the new port set */
  465         LIST_INSERT_HEAD(&mrs->mr_set, mrr, mr_setlist);
  466         mrr->mr_sethead = mrs;
  467 
  468         rw_exit(&med->med_rightlock);
  469 
  470         *msglen = sizeof(*rep);
  471         mach_set_header(rep, req, *msglen);
  472 
  473         rep->rep_retval = 0;
  474 
  475         mach_set_trailer(rep, *msglen);
  476 
  477         return 0;
  478 }
  479 
  480 int
  481 mach_port_request_notification(struct mach_trap_args *args)
  482 {
  483         mach_port_request_notification_request_t *req = args->smsg;
  484         mach_port_request_notification_reply_t *rep = args->rmsg;
  485         struct lwp *l = args->l;
  486         size_t *msglen = args->rsize;
  487         mach_port_t mn;
  488         struct mach_right *nmr;
  489         struct mach_right *tmr;
  490         struct mach_right *oldnmr;
  491         mach_port_t oldmn;
  492 
  493 #ifdef DEBUG_MACH
  494         printf("mach_port_request_notification, notify = %08x, target = %08x\n",
  495             req->req_notify.name, mn = req->req_name);
  496 #endif
  497         mn = req->req_notify.name;
  498         if ((nmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  499                 return mach_msg_error(args, EINVAL);
  500 
  501         mn = req->req_name;
  502         if ((tmr = mach_right_check(mn, l, MACH_PORT_TYPE_ALL_RIGHTS)) == NULL)
  503                 return mach_msg_error(args, EINVAL);
  504 
  505 #ifdef DEBUG_MACH
  506         if (nmr->mr_port == NULL) {
  507                 printf("Notification right without a port\n");
  508                 printf("mr->mr_port = %p, mr = %08x\n", nmr->mr_port, nmr->mr_name);
  509                 return mach_msg_error(args, EINVAL);
  510         }
  511 #endif
  512 
  513 
  514         oldnmr = NULL;
  515         switch(req->req_msgid) {
  516         case MACH_NOTIFY_DESTROYED_MSGID:
  517                 oldnmr = tmr->mr_notify_destroyed;
  518                 tmr->mr_notify_destroyed = mach_right_get(nmr->mr_port,
  519                     l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
  520                 break;
  521 
  522         case MACH_NOTIFY_NO_SENDERS_MSGID:
  523                 oldnmr = tmr->mr_notify_no_senders;
  524                 tmr->mr_notify_no_senders = mach_right_get(nmr->mr_port,
  525                     l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
  526                 tmr->mr_notify_no_senders->mr_port->mp_datatype =
  527                     MACH_MP_NOTIFY_SYNC;
  528                 tmr->mr_notify_no_senders->mr_port->mp_data = (void *)
  529                     req->req_count;
  530                 break;
  531 
  532         case MACH_NOTIFY_DEAD_NAME_MSGID:
  533                 oldnmr = tmr->mr_notify_dead_name;
  534                 tmr->mr_notify_dead_name = mach_right_get(nmr->mr_port,
  535                     l, MACH_PORT_TYPE_SEND_ONCE, req->req_notify.name);
  536                 break;
  537 
  538         case MACH_NOTIFY_SEND_ONCE_MSGID:
  539         case MACH_NOTIFY_DELETED_MSGID:
  540         default:
  541 #ifdef DEBUG_MACH
  542                 printf("unsupported notify request %d\n", req->req_msgid);
  543                 return mach_msg_error(args, EINVAL);
  544 #endif
  545                 break;
  546         }
  547 
  548         if (oldnmr != NULL) {
  549                 oldnmr->mr_refcount++;
  550                 oldmn = oldnmr->mr_name;
  551         } else {
  552                 oldmn = (mach_port_t)MACH_PORT_NULL;
  553         }
  554 
  555         *msglen = sizeof(*rep);
  556         mach_set_header(rep, req, *msglen);
  557         mach_add_port_desc(rep, oldmn);
  558         mach_set_trailer(rep, *msglen);
  559 
  560         return 0;
  561 }
  562 
  563 int
  564 mach_port_get_refs(struct mach_trap_args *args)
  565 {
  566         mach_port_get_refs_request_t *req = args->smsg;
  567         mach_port_get_refs_reply_t *rep = args->rmsg;
  568         size_t *msglen = args->rsize;
  569         struct lwp *l = args->l;
  570         mach_port_t mn;
  571         struct mach_right *mr;
  572         mach_port_right_t right = req->req_right;
  573 
  574         mn = req->req_name;
  575         if ((mr = mach_right_check(mn, l, right)) == NULL)
  576                 return mach_msg_error(args, EINVAL);
  577 
  578         *msglen = sizeof(*rep);
  579         mach_set_header(rep, req, *msglen);
  580 
  581         rep->rep_retval = 0;
  582         rep->rep_refs = mr->mr_refcount;
  583 
  584         mach_set_trailer(rep, *msglen);
  585 
  586         return 0;
  587 }
  588 
  589 int
  590 mach_port_mod_refs(struct mach_trap_args *args)
  591 {
  592         mach_port_mod_refs_request_t *req = args->smsg;
  593         mach_port_mod_refs_reply_t *rep = args->rmsg;
  594         size_t *msglen = args->rsize;
  595 #if 0
  596         struct lwp *l = args->l;
  597         mach_port_t mn;
  598         struct mach_right *mr;
  599         mach_port_right_t right = req->req_right;
  600 
  601         mn = req->req_name;
  602         if ((mr = mach_right_check(mn, l, right)) == NULL)
  603                 return mach_msg_error(args, EINVAL);
  604 
  605         /*
  606          * Changing the refcount is likely to cause crashes,
  607          * as we will free a right which might still be referenced
  608          * within the kernel. Add a user refcount field?
  609          */
  610         mr->mr_refcount += req->req_delta;
  611         if (mr->mr_refcount <= 0)
  612                 mach_right_put(mr, right);
  613 #endif
  614 
  615         *msglen = sizeof(*rep);
  616         mach_set_header(rep, req, *msglen);
  617 
  618         rep->rep_retval = 0;
  619 
  620         mach_set_trailer(rep, *msglen);
  621 
  622         return 0;
  623 }
  624 
  625 void
  626 mach_port_init(void)
  627 {
  628         pool_init(&mach_port_pool, sizeof (struct mach_port),
  629             0, 0, 0, "mach_port_pool", NULL, IPL_NONE);
  630         pool_init(&mach_right_pool, sizeof (struct mach_right),
  631             0, 0, 0, "mach_right_pool", NULL, IPL_NONE);
  632 
  633         mach_bootstrap_port = mach_port_get();
  634         mach_clock_port = mach_port_get();
  635         mach_io_master_port = mach_port_get();
  636 
  637         mach_bootstrap_port->mp_flags |= MACH_MP_INKERNEL;
  638         mach_clock_port->mp_flags |= MACH_MP_INKERNEL;
  639         mach_io_master_port->mp_flags |= MACH_MP_INKERNEL;
  640 
  641         mach_saved_bootstrap_port = mach_bootstrap_port;
  642 
  643         return;
  644 }
  645 
  646 struct mach_port *
  647 mach_port_get(void)
  648 {
  649         struct mach_port *mp;
  650 
  651         mp = (struct mach_port *)pool_get(&mach_port_pool, PR_WAITOK);
  652         bzero(mp, sizeof(*mp));
  653         mp->mp_recv = NULL;
  654         mp->mp_count = 0;
  655         mp->mp_flags = 0;
  656         mp->mp_datatype = MACH_MP_NONE;
  657         mp->mp_data = NULL;
  658         TAILQ_INIT(&mp->mp_msglist);
  659         rw_init(&mp->mp_msglock);
  660 
  661         return mp;
  662 }
  663 
  664 void
  665 mach_port_put(struct mach_port *mp)
  666 {
  667         struct mach_message *mm;
  668 
  669 #ifdef DIAGNOSTIC
  670         if (mp->mp_refcount > 0) {
  671                 uprintf("mach_port_put: trying to free a referenced port\n");
  672                 return;
  673         }
  674 #endif
  675 
  676         rw_enter(&mp->mp_msglock, RW_WRITER);
  677         while ((mm = TAILQ_FIRST(&mp->mp_msglist)) != NULL)
  678                 mach_message_put_exclocked(mm);
  679         rw_exit(&mp->mp_msglock);
  680         rw_destroy(&mp->mp_msglock);
  681 
  682         if (mp->mp_flags & MACH_MP_DATA_ALLOCATED)
  683                 free(mp->mp_data, M_EMULDATA);
  684 
  685         pool_put(&mach_port_pool, mp);
  686 
  687         return;
  688 }
  689 
  690 struct mach_right *
  691 mach_right_get(struct mach_port *mp, struct lwp *l, int type, mach_port_t hint)
  692 {
  693         struct mach_right *mr;
  694         struct mach_emuldata *med;
  695         int rights;
  696 
  697 #ifdef DEBUG_MACH
  698         if (type == 0)
  699                 uprintf("mach_right_get: right = 0\n");
  700 #endif
  701         med = (struct mach_emuldata *)l->l_proc->p_emuldata;
  702 
  703         if (mp != NULL)
  704                 MACH_PORT_REF(mp);
  705 
  706         /* Send and receive right must return an existing right */
  707         rights = (MACH_PORT_TYPE_SEND | MACH_PORT_TYPE_RECEIVE);
  708         if (type & rights) {
  709                 rw_enter(&med->med_rightlock, RW_READER);
  710                 LIST_FOREACH(mr, &med->med_right, mr_list) {
  711                         if ((mr->mr_port == mp) && (mr->mr_type & rights))
  712                                 break;
  713                 }
  714                 rw_exit(&med->med_rightlock);
  715 
  716                 if (mr != NULL) {
  717                         mr->mr_type |= type;
  718                         if (type & MACH_PORT_TYPE_SEND)
  719                                 mr->mr_refcount++;
  720                         goto rcvck;
  721                 }
  722         }
  723 
  724         mr = pool_get(&mach_right_pool, PR_WAITOK);
  725 
  726         mr->mr_port = mp;
  727         mr->mr_lwp = l;
  728         mr->mr_type = type;
  729         mr->mr_sethead = mr;
  730         mr->mr_refcount = 1;
  731         mr->mr_notify_destroyed = NULL;
  732         mr->mr_notify_dead_name = NULL;
  733         mr->mr_notify_no_senders = NULL;
  734 
  735         LIST_INIT(&mr->mr_set);
  736 
  737         /* Insert the right in the right lists */
  738         if (type & MACH_PORT_TYPE_ALL_RIGHTS) {
  739                 rw_enter(&med->med_rightlock, RW_WRITER);
  740                 mr->mr_name = mach_right_newname(l, hint);
  741 #ifdef DEBUG_MACH_RIGHT
  742                 printf("mach_right_get: insert right %x(%x)\n",
  743                     mr->mr_name, mr->mr_type);
  744 #endif
  745                 LIST_INSERT_HEAD(&med->med_right, mr, mr_list);
  746                 rw_exit(&med->med_rightlock);
  747         }
  748 
  749 rcvck:
  750         if (type & MACH_PORT_TYPE_RECEIVE) {
  751                 /*
  752                  * Destroy the former receive right on this port, and
  753                  * register the new right.
  754                  */
  755                 if (mr->mr_port->mp_recv != NULL)
  756                         mach_right_put(mr->mr_port->mp_recv,
  757                             MACH_PORT_TYPE_RECEIVE);
  758                 mr->mr_port->mp_recv = mr;
  759         }
  760         return mr;
  761 }
  762 
  763 void
  764 mach_right_put(struct mach_right *mr, int right)
  765 {
  766         struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
  767 
  768         rw_enter(&med->med_rightlock, RW_WRITER);
  769         mach_right_put_exclocked(mr, right);
  770         rw_exit(&med->med_rightlock);
  771 
  772         return;
  773 }
  774 
  775 void
  776 mach_right_put_shlocked(struct mach_right *mr, int right)
  777 {
  778         struct mach_emuldata *med = mr->mr_lwp->l_proc->p_emuldata;
  779 
  780         if (!rw_tryupgrade(&med->med_rightlock)) {
  781                 /* XXX */
  782                 rw_exit(&med->med_rightlock);
  783                 rw_enter(&med->med_rightlock, RW_WRITER);
  784         }
  785         mach_right_put_exclocked(mr, right);
  786         rw_downgrade(&med->med_rightlock);
  787 
  788         return;
  789 }
  790 
  791 void
  792 mach_right_put_exclocked(struct mach_right *mr, int right)
  793 {
  794         struct mach_right *cmr;
  795         struct mach_emuldata *med;
  796         int lright;
  797         int kill_right;
  798 
  799         med = mr->mr_lwp->l_proc->p_emuldata;
  800 
  801 #ifdef DEBUG_MACH_RIGHT
  802         printf("mach_right_put: mr = %p\n", mr);
  803         printf("right %x(%x) refcount %d, deallocate %x\n",
  804             mr->mr_name, mr->mr_type, mr->mr_refcount, right);
  805         if ((mr->mr_type & right) == 0)
  806                 printf("mach_right_put: dropping nonexistant right %x on %x\n",
  807                     right, mr->mr_name);
  808         LIST_FOREACH(cmr, &med->med_right, mr_list)
  809                 if (cmr == mr)
  810                         break;
  811         if (cmr == NULL) {
  812                 printf("mach_right_put: dropping already dropped right %x\n",
  813                     mr->mr_name);
  814                 return;
  815         }
  816 #endif
  817         kill_right = 0;
  818 
  819         /* When receive right is deallocated, the port should die */
  820         lright = (right & MACH_PORT_TYPE_RECEIVE);
  821 #ifdef DEBUG_MACH_RIGHT
  822         printf("mr->mr_type = %x, lright = %x, right = %x, refcount = %d\n",
  823             mr->mr_type, lright, right, mr->mr_refcount);
  824 #endif
  825         if (mr->mr_type & lright) {
  826                 if (mr->mr_refcount <= 0) {
  827                         mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
  828                         kill_right = 1;
  829                 } else {
  830                         mr->mr_type &= ~MACH_PORT_TYPE_RECEIVE;
  831                         mr->mr_type |= MACH_PORT_TYPE_DEAD_NAME;
  832                         mach_notify_port_dead_name(mr->mr_lwp, mr);
  833                 }
  834                 if (mr->mr_port != NULL) {
  835                         /* There is no more receiver */
  836 #ifdef DIAGNOSTIC
  837                         if (mr->mr_port->mp_recv != mr)
  838                                 printf("several receiver on a single port\n");
  839 #endif
  840                         mr->mr_port->mp_recv = NULL;
  841 
  842                         MACH_PORT_UNREF(mr->mr_port);
  843                         mr->mr_port = NULL;
  844                 }
  845         }
  846 
  847         /* send, send_once and dead_name */
  848         lright = (right & MACH_PORT_TYPE_REF_RIGHTS);
  849         if (mr->mr_type & lright) {
  850                 mr->mr_refcount--;
  851 
  852                 mach_notify_port_no_senders(mr->mr_lwp, mr);
  853 
  854                 if (mr->mr_refcount <= 0) {
  855                         mr->mr_type &= ~MACH_PORT_TYPE_REF_RIGHTS;
  856                         if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
  857                                 kill_right = 1;
  858                 }
  859         }
  860 
  861         lright = (right & MACH_PORT_TYPE_PORT_SET);
  862         if ((mr->mr_type & lright) || (kill_right == 1)) {
  863                 while ((cmr = LIST_FIRST(&mr->mr_set)) != NULL) {
  864                         LIST_REMOVE(cmr, mr_setlist);
  865                         cmr->mr_sethead = cmr;
  866                 }
  867                 mr->mr_type &= ~MACH_PORT_TYPE_PORT_SET;
  868                 if ((mr->mr_type & MACH_PORT_TYPE_RECEIVE) == 0)
  869                         kill_right = 1;
  870         }
  871 
  872         /* Should we kill it? */
  873         if (kill_right == 1) {
  874 #ifdef DEBUG_MACH_RIGHT
  875                 printf("mach_right_put: kill name %x\n", mr->mr_name);
  876 #endif
  877                 /* If the right is used for an IO notification, remove it */
  878                 mach_iokit_cleanup_notify(mr);
  879 
  880                 mach_notify_port_destroyed(mr->mr_lwp, mr);
  881                 LIST_REMOVE(mr, mr_list);
  882                 pool_put(&mach_right_pool, mr);
  883         }
  884         return;
  885 }
  886 
  887 /*
  888  * Check that a process has a given right.
  889  */
  890 struct mach_right *
  891 mach_right_check(mach_port_t mn, struct lwp *l, int type)
  892 {
  893         struct mach_right *cmr;
  894         struct mach_emuldata *med;
  895 
  896         if ((mn == 0) || (mn == -1) || (l == NULL))
  897                 return NULL;
  898 
  899         med = (struct mach_emuldata *)l->l_proc->p_emuldata;
  900 
  901         rw_enter(&med->med_rightlock, RW_READER);
  902 
  903 #ifdef DEBUG_MACH_RIGHT
  904         printf("mach_right_check: type = %x, mn = %x\n", type, mn);
  905 #endif
  906         LIST_FOREACH(cmr, &med->med_right, mr_list) {
  907 #ifdef DEBUG_MACH_RIGHT
  908                 printf("cmr = %p, cmr->mr_name = %x, cmr->mr_type = %x\n",
  909                     cmr, cmr->mr_name, cmr->mr_type);
  910 #endif
  911                 if (cmr->mr_name != mn)
  912                         continue;
  913                 if (type & cmr->mr_type)
  914                         break;
  915         }
  916 
  917         rw_exit(&med->med_rightlock);
  918 
  919         return cmr;
  920 }
  921 
  922 
  923 /*
  924  * Find an usnused port name in a given lwp.
  925  * Right lists should be locked.
  926  */
  927 mach_port_t
  928 mach_right_newname(struct lwp *l, mach_port_t hint)
  929 {
  930         struct mach_emuldata *med;
  931         struct mach_right *mr;
  932         mach_port_t newname = -1;
  933 
  934         med = l->l_proc->p_emuldata;
  935 
  936         if (hint == 0)
  937                 hint = med->med_nextright;
  938 
  939         while (newname == -1) {
  940                 LIST_FOREACH(mr, &med->med_right, mr_list)
  941                         if (mr->mr_name == hint)
  942                                 break;
  943                 if (mr == NULL)
  944                         newname = hint;
  945                 hint++;
  946         }
  947 
  948         med->med_nextright = hint;
  949 
  950         return newname;
  951 }
  952 
  953 #ifdef DEBUG_MACH
  954 void
  955 mach_debug_port(void)
  956 {
  957         struct mach_emuldata *med;
  958         struct mach_right *mr;
  959         struct mach_right *mrs;
  960         struct proc *p;
  961 
  962         PROCLIST_FOREACH(p, &allproc) {
  963                 if ((p->p_emul != &emul_mach) &&
  964 #ifdef COMPAT_DARWIN
  965                     (p->p_emul != &emul_darwin) &&
  966 #endif
  967                     1)
  968                         continue;
  969 
  970                 med = p->p_emuldata;
  971                 LIST_FOREACH(mr, &med->med_right, mr_list) {
  972                         if ((mr->mr_type & MACH_PORT_TYPE_PORT_SET) == 0) {
  973                                 printf("pid %d: %p(%x)=>%p",
  974                                     p->p_pid, mr, mr->mr_type, mr->mr_port);
  975                                 if (mr->mr_port && mr->mr_port->mp_recv)
  976                                         printf("[%p]\n",
  977                                             mr->mr_port->mp_recv->mr_sethead);
  978                                 else
  979                                         printf("[NULL]\n");
  980 
  981                                 continue;
  982                         }
  983 
  984                         /* Port set... */
  985                         printf("pid %d: set %p(%x) ",
  986                             p->p_pid, mr, mr->mr_type);
  987                         LIST_FOREACH(mrs, &mr->mr_set, mr_setlist) {
  988                                 printf("%p(%x)=>%p",
  989                                     mrs, mrs->mr_type, mrs->mr_port);
  990                                 if (mrs->mr_port && mrs->mr_port->mp_recv)
  991                                         printf("[%p]",
  992                                             mrs->mr_port->mp_recv->mr_sethead);
  993                                 else
  994                                         printf("[NULL]");
  995 
  996                                 printf(" ");
  997                         }
  998                         printf("\n");
  999                 }
 1000         }
 1001         return;
 1002 }
 1003 
 1004 #endif /* DEBUG_MACH */

Cache object: 2e63ddc570ec29bf7d68cc9f25cc5c2a


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