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_tt.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-1987 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_tt.c,v $
   29  * Revision 2.15  93/11/17  17:12:01  dbg
   30  *      Use task_lock instead of ith_task_lock, thread_lock instead of
   31  *      ith_thread_lock.  Remove checks in ipc_task_terminate,
   32  *      ipc_thread_terminate for being called twice: caller prevents
   33  *      that.
   34  *      [93/07/12            dbg]
   35  * 
   36  *      ANSI-fied.
   37  *      [93/06/16            dbg]
   38  * 
   39  * Revision 2.14  92/08/03  17:37:42  jfriedl
   40  *      removed silly prototypes
   41  *      [92/08/02            jfriedl]
   42  * 
   43  * Revision 2.13  92/05/21  17:14:13  jfriedl
   44  *      Removed unsed var 'kr' from mach_ports_lookup().
   45  *      [92/05/16            jfriedl]
   46  * 
   47  * Revision 2.12  91/06/25  10:28:49  rpd
   48  *      Changed the convert_foo_to_bar functions
   49  *      to use ipc_port_t instead of mach_port_t.
   50  *      [91/05/27            rpd]
   51  * 
   52  * Revision 2.11  91/06/17  15:47:09  jsb
   53  *      Renamed NORMA conditionals. Moved norma code to norma/kern_task.c.
   54  *      [91/06/17  10:50:57  jsb]
   55  * 
   56  * Revision 2.10  91/06/06  17:07:15  jsb
   57  *      NORMA_TASK support.
   58  *      [91/05/14  09:17:09  jsb]
   59  * 
   60  * Revision 2.9  91/05/14  16:42:54  mrt
   61  *      Correcting copyright
   62  * 
   63  * Revision 2.8  91/03/16  14:50:24  rpd
   64  *      Removed ith_saved.
   65  *      [91/02/16            rpd]
   66  * 
   67  * Revision 2.7  91/02/05  17:27:08  mrt
   68  *      Changed to new Mach copyright
   69  *      [91/02/01  16:13:42  mrt]
   70  * 
   71  * Revision 2.6  91/01/08  15:16:05  rpd
   72  *      Added retrieve_task_self_fast, retrieve_thread_self_fast.
   73  *      [90/12/27            rpd]
   74  * 
   75  * Revision 2.5  90/11/05  14:31:08  rpd
   76  *      Changed ip_reference to ipc_port_reference.
   77  *      Use new ip_reference and ip_release.
   78  *      [90/10/29            rpd]
   79  * 
   80  * Revision 2.4  90/06/02  14:54:33  rpd
   81  *      Converted to new IPC.
   82  *      [90/03/26  22:05:07  rpd]
   83  * 
   84  *
   85  * Condensed history:
   86  *      Modified for pure kernel (dbg).
   87  *      Support thread_exception_abort (dlb).
   88  *      Added kernel monitor support (tfl).
   89  *      Added task/thread kernel port interposing (rpd).
   90  *      Improvements/fixes for task_secure (rpd).
   91  *      New translation cache (rpd).
   92  *      Move old stuff under MACH_IPC_XXXHACK (rpd).
   93  *      Created from mach_ipc.c (rpd).
   94  */
   95 
   96 /*
   97  * File:        ipc_tt.c
   98  * Purpose:
   99  *      Task and thread related IPC functions.
  100  */
  101 
  102 #include <mach_ipc_compat.h>
  103 
  104 #include <mach/boolean.h>
  105 #include <mach/kern_return.h>
  106 #include <mach/mach_param.h>
  107 #include <mach/task_special_ports.h>
  108 #include <mach/thread_special_ports.h>
  109 #include <vm/vm_kern.h>
  110 #include <kern/task.h>
  111 #include <kern/thread.h>
  112 #include <kern/ipc_kobject.h>
  113 #include <kern/ipc_tt.h>
  114 #include <ipc/ipc_space.h>
  115 #include <ipc/ipc_table.h>
  116 #include <ipc/ipc_port.h>
  117 #include <ipc/ipc_right.h>
  118 #include <ipc/ipc_entry.h>
  119 #include <ipc/ipc_object.h>
  120 
  121 
  122 
  123 /*
  124  *      Routine:        ipc_task_init
  125  *      Purpose:
  126  *              Initialize a task's IPC state.
  127  *
  128  *              If non-null, some state will be inherited from the parent.
  129  *              The parent must be appropriately initialized.
  130  *      Conditions:
  131  *              Nothing locked.
  132  */
  133 
  134 void
  135 ipc_task_init(
  136         task_t task,
  137         task_t parent)
  138 {
  139         ipc_space_t space;
  140         ipc_port_t kport;
  141         kern_return_t kr;
  142         int i;
  143 
  144         kr = ipc_space_create(&ipc_table_entries[0], &space);
  145         if (kr != KERN_SUCCESS)
  146                 panic("ipc_task_init");
  147 
  148         kport = ipc_port_alloc_kernel();
  149         if (kport == IP_NULL)
  150                 panic("ipc_task_init");
  151 
  152         task->itk_self = kport;
  153         task->itk_sself = ipc_port_make_send(kport);
  154         task->itk_space = space;
  155 
  156         if (parent == TASK_NULL) {
  157                 task->itk_exception = IP_NULL;
  158                 task->itk_bootstrap = IP_NULL;
  159                 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  160                         task->itk_registered[i] = IP_NULL;
  161         } else {
  162                 task_lock(parent);
  163                 assert(parent->active);
  164 
  165                 /* inherit registered ports */
  166 
  167                 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  168                         task->itk_registered[i] =
  169                                 ipc_port_copy_send(parent->itk_registered[i]);
  170 
  171                 /* inherit exception and bootstrap ports */
  172 
  173                 task->itk_exception =
  174                         ipc_port_copy_send(parent->itk_exception);
  175                 task->itk_bootstrap =
  176                         ipc_port_copy_send(parent->itk_bootstrap);
  177 
  178                 task_unlock(parent);
  179         }
  180 }
  181 
  182 /*
  183  *      Routine:        ipc_task_enable
  184  *      Purpose:
  185  *              Enable a task for IPC access.
  186  *      Conditions:
  187  *              Nothing locked.
  188  */
  189 
  190 void
  191 ipc_task_enable(
  192         task_t task)
  193 {
  194         ipc_port_t kport;
  195 
  196         task_lock(task);
  197         kport = task->itk_self;
  198         if (kport != IP_NULL)
  199                 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
  200         task_unlock(task);
  201 }
  202 
  203 /*
  204  *      Routine:        ipc_task_disable
  205  *      Purpose:
  206  *              Disable IPC access to a task.
  207  *      Conditions:
  208  *              The task is locked.
  209  */
  210 
  211 void
  212 ipc_task_disable(
  213         task_t task)
  214 {
  215         ipc_port_t kport;
  216 
  217         kport = task->itk_self;
  218         if (kport != IP_NULL)
  219                 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
  220 }
  221 
  222 /*
  223  *      Routine:        ipc_task_terminate
  224  *      Purpose:
  225  *              Clean up and destroy a task's IPC state.
  226  *      Conditions:
  227  *              Nothing locked.  The task must be suspended.
  228  *              (Or the current thread must be in the task.)
  229  */
  230 
  231 void
  232 ipc_task_terminate(
  233         task_t task)
  234 {
  235         ipc_port_t kport;
  236         int i;
  237 
  238         task_lock(task);
  239         kport = task->itk_self;
  240         assert(kport != IP_NULL);
  241 
  242         task->itk_self = IP_NULL;
  243         task_unlock(task);
  244 
  245         /* release the naked send rights */
  246 
  247         if (IP_VALID(task->itk_sself))
  248                 ipc_port_release_send(task->itk_sself);
  249         if (IP_VALID(task->itk_exception))
  250                 ipc_port_release_send(task->itk_exception);
  251         if (IP_VALID(task->itk_bootstrap))
  252                 ipc_port_release_send(task->itk_bootstrap);
  253 
  254         for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  255                 if (IP_VALID(task->itk_registered[i]))
  256                         ipc_port_release_send(task->itk_registered[i]);
  257 
  258         /* destroy the space, leaving just a reference for it */
  259 
  260         ipc_space_destroy(task->itk_space);
  261 
  262         /* destroy the kernel port */
  263 
  264         ipc_port_dealloc_kernel(kport);
  265 }
  266 
  267 /*
  268  *      Routine:        ipc_thread_init
  269  *      Purpose:
  270  *              Initialize a thread's IPC state.
  271  *      Conditions:
  272  *              Nothing locked.
  273  */
  274 
  275 void
  276 ipc_thread_init(
  277         thread_t thread)
  278 {
  279         ipc_port_t kport;
  280 
  281         kport = ipc_port_alloc_kernel();
  282         if (kport == IP_NULL)
  283                 panic("ipc_thread_init");
  284 
  285         ipc_thread_links_init(thread);
  286         ipc_kmsg_queue_init(&thread->ith_messages);
  287 
  288         thread->ith_self = kport;
  289         thread->ith_sself = ipc_port_make_send(kport);
  290         thread->ith_exception = IP_NULL;
  291 
  292         thread->ith_mig_reply = MACH_PORT_NULL;
  293         thread->ith_rpc_reply = IP_NULL;
  294 
  295 #if     MACH_IPC_COMPAT
  296     {
  297         ipc_space_t space = thread->task->itk_space;
  298         ipc_port_t port;
  299         mach_port_t name;
  300         kern_return_t kr;
  301 
  302         kr = ipc_port_alloc_compat(space, &name, &port);
  303         if (kr != KERN_SUCCESS)
  304                 panic("ipc_thread_init");
  305         /* port is locked and active */
  306 
  307         /*
  308          *      Now we have a reply port.  We need to make a naked
  309          *      send right to stash in ith_reply.  We can't use
  310          *      ipc_port_make_send, because we can't unlock the port
  311          *      before making the right.  Also we don't want to
  312          *      increment ip_mscount.  The net effect of all this
  313          *      is the same as doing
  314          *              ipc_port_alloc_kernel           get the port
  315          *              ipc_port_make_send              make the send right
  316          *              ipc_object_copyin_from_kernel   grab receive right
  317          *              ipc_object_copyout_compat       and give to user
  318          */
  319 
  320         port->ip_srights++;
  321         ip_reference(port);
  322         ip_unlock(port);
  323 
  324         thread->ith_reply = port;
  325     }
  326 #endif  /* MACH_IPC_COMPAT */
  327 }
  328 
  329 /*
  330  *      Routine:        ipc_thread_enable
  331  *      Purpose:
  332  *              Enable a thread for IPC access.
  333  *      Conditions:
  334  *              Nothing locked.
  335  */
  336 
  337 void
  338 ipc_thread_enable(
  339         thread_t thread)
  340 {
  341         ipc_port_t kport;
  342 
  343         thread_lock(thread);
  344         kport = thread->ith_self;
  345         if (kport != IP_NULL)
  346                 ipc_kobject_set(kport, (ipc_kobject_t) thread, IKOT_THREAD);
  347         thread_unlock(thread);
  348 }
  349 
  350 /*
  351  *      Routine:        ipc_thread_disable
  352  *      Purpose:
  353  *              Disable IPC access to a thread.
  354  *      Conditions:
  355  *              The thread is locked.
  356  */
  357 
  358 void
  359 ipc_thread_disable(
  360         thread_t thread)
  361 {
  362         ipc_port_t kport;
  363 
  364         kport = thread->ith_self;
  365         if (kport != IP_NULL)
  366                 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
  367 }
  368 
  369 /*
  370  *      Routine:        ipc_thread_terminate
  371  *      Purpose:
  372  *              Clean up and destroy a thread's IPC state.
  373  *      Conditions:
  374  *              Nothing locked.  The thread must be suspended.
  375  *              (Or be the current thread.)
  376  */
  377 
  378 void
  379 ipc_thread_terminate(
  380         thread_t thread)
  381 {
  382         ipc_port_t kport;
  383 
  384         thread_lock(thread);
  385         kport = thread->ith_self;
  386         if (kport == IP_NULL) {
  387             /* already done */
  388             thread_unlock(thread);
  389             return;
  390         }
  391 
  392         thread->ith_self = IP_NULL;
  393         thread_unlock(thread);
  394 
  395         assert(ipc_kmsg_queue_empty(&thread->ith_messages));
  396 
  397         /* release the naked send rights */
  398 
  399         if (IP_VALID(thread->ith_sself))
  400                 ipc_port_release_send(thread->ith_sself);
  401         if (IP_VALID(thread->ith_exception))
  402                 ipc_port_release_send(thread->ith_exception);
  403 
  404 #if     MACH_IPC_COMPAT
  405         if (IP_VALID(thread->ith_reply)) {
  406                 ipc_space_t space = thread->task->itk_space;
  407                 ipc_port_t port = thread->ith_reply;
  408                 ipc_entry_t entry;
  409                 mach_port_t name;
  410 
  411                 /* destroy any rights the task may have for the port */
  412 
  413                 is_write_lock(space);
  414                 if (space->is_active &&
  415                     ipc_right_reverse(space, (ipc_object_t) port,
  416                                       &name, &entry)) {
  417                         /* reply port is locked and active */
  418                         ip_unlock(port);
  419 
  420                         (void) ipc_right_destroy(space, name, entry);
  421                         /* space is unlocked */
  422                 } else
  423                         is_write_unlock(space);
  424 
  425                 ipc_port_release_send(port);
  426         }
  427 
  428         /*
  429          *      Note we do *not* destroy any rights the space may have
  430          *      for the thread's kernel port.  The old IPC code did this,
  431          *      to avoid generating a notification when the port is
  432          *      destroyed.  However, this isn't a good idea when
  433          *      the kernel port is interposed, because then it doesn't
  434          *      happen, exposing the interposition to the task.
  435          *      Because we don't need the efficiency hack, I flushed
  436          *      this behaviour, introducing a small incompatibility
  437          *      with the old IPC code.
  438          */
  439 #endif  /* MACH_IPC_COMPAT */
  440 
  441         /* destroy the kernel port */
  442 
  443         ipc_port_dealloc_kernel(kport);
  444 }
  445 
  446 #if     0
  447 /*
  448  *      Routine:        retrieve_task_self
  449  *      Purpose:
  450  *              Return a send right (possibly null/dead)
  451  *              for the task's user-visible self port.
  452  *      Conditions:
  453  *              Nothing locked.
  454  */
  455 
  456 ipc_port_t
  457 retrieve_task_self(
  458         task_t task)
  459 {
  460         ipc_port_t port;
  461 
  462         assert(task != TASK_NULL);
  463 
  464         task_lock(task);
  465         if (task->active)
  466                 port = ipc_port_copy_send(task->itk_sself);
  467         else
  468                 port = IP_NULL;
  469         task_unlock(task);
  470 
  471         return port;
  472 }
  473 
  474 /*
  475  *      Routine:        retrieve_thread_self
  476  *      Purpose:
  477  *              Return a send right (possibly null/dead)
  478  *              for the thread's user-visible self port.
  479  *      Conditions:
  480  *              Nothing locked.
  481  */
  482 
  483 ipc_port_t
  484 retrieve_thread_self(
  485         thread_t thread)
  486 {
  487         ipc_port_t port;
  488 
  489         assert(thread != ITH_NULL);
  490 
  491         thread_lock(thread);
  492         if (thread->active)
  493                 port = ipc_port_copy_send(thread->ith_sself);
  494         else
  495                 port = IP_NULL;
  496         thread_unlock(thread);
  497 
  498         return port;
  499 }
  500 #endif  /* 0 */
  501 
  502 /*
  503  *      Routine:        retrieve_task_self_fast
  504  *      Purpose:
  505  *              Optimized version of retrieve_task_self,
  506  *              that only works for the current task.
  507  *
  508  *              Return a send right (possibly null/dead)
  509  *              for the task's user-visible self port.
  510  *      Conditions:
  511  *              Nothing locked.
  512  */
  513 
  514 ipc_port_t
  515 retrieve_task_self_fast(
  516         register task_t task)
  517 {
  518         register ipc_port_t port;
  519 
  520         assert(task == current_task());
  521 
  522         task_lock(task);
  523         assert(task->active);
  524         assert(task->itk_self != IP_NULL);
  525 
  526         if ((port = task->itk_sself) == task->itk_self) {
  527                 /* no interposing */
  528 
  529                 ip_lock(port);
  530                 assert(ip_active(port));
  531                 ip_reference(port);
  532                 port->ip_srights++;
  533                 ip_unlock(port);
  534         } else
  535                 port = ipc_port_copy_send(port);
  536         task_unlock(task);
  537 
  538         return port;
  539 }
  540 
  541 /*
  542  *      Routine:        retrieve_thread_self_fast
  543  *      Purpose:
  544  *              Optimized version of retrieve_thread_self,
  545  *              that only works for the current thread.
  546  *
  547  *              Return a send right (possibly null/dead)
  548  *              for the thread's user-visible self port.
  549  *      Conditions:
  550  *              Nothing locked.
  551  */
  552 
  553 ipc_port_t
  554 retrieve_thread_self_fast(
  555         register thread_t thread)
  556 {
  557         register ipc_port_t port;
  558 
  559         assert(thread == current_thread());
  560 
  561         thread_lock(thread);
  562         assert(thread->active);
  563         assert(thread->ith_self != IP_NULL);
  564 
  565         if ((port = thread->ith_sself) == thread->ith_self) {
  566                 /* no interposing */
  567 
  568                 ip_lock(port);
  569                 assert(ip_active(port));
  570                 ip_reference(port);
  571                 port->ip_srights++;
  572                 ip_unlock(port);
  573         } else
  574                 port = ipc_port_copy_send(port);
  575         thread_unlock(thread);
  576 
  577         return port;
  578 }
  579 
  580 #if     0
  581 /*
  582  *      Routine:        retrieve_task_exception
  583  *      Purpose:
  584  *              Return a send right (possibly null/dead)
  585  *              for the task's exception port.
  586  *      Conditions:
  587  *              Nothing locked.
  588  */
  589 
  590 ipc_port_t
  591 retrieve_task_exception(
  592         task_t task)
  593 {
  594         ipc_port_t port;
  595 
  596         assert(task != TASK_NULL);
  597 
  598         task_lock(task);
  599         if (task->active)
  600                 port = ipc_port_copy_send(task->itk_exception);
  601         else
  602                 port = IP_NULL;
  603         task_unlock(task);
  604 
  605         return port;
  606 }
  607 
  608 /*
  609  *      Routine:        retrieve_thread_exception
  610  *      Purpose:
  611  *              Return a send right (possibly null/dead)
  612  *              for the thread's exception port.
  613  *      Conditions:
  614  *              Nothing locked.
  615  */
  616 
  617 ipc_port_t
  618 retrieve_thread_exception(
  619         thread_t thread)
  620 {
  621         ipc_port_t port;
  622 
  623         assert(thread != ITH_NULL);
  624 
  625         thread_lock(thread);
  626         if (thread->active)
  627                 port = ipc_port_copy_send(thread->ith_exception);
  628         else
  629                 port = IP_NULL;
  630         thread_unlock(thread);
  631 
  632         return port;
  633 }
  634 #endif  /* 0 */
  635 
  636 /*
  637  *      Routine:        mach_task_self [mach trap]
  638  *      Purpose:
  639  *              Give the caller send rights for his own task port.
  640  *      Conditions:
  641  *              Nothing locked.
  642  *      Returns:
  643  *              MACH_PORT_NULL if there are any resource failures
  644  *              or other errors.
  645  */
  646 
  647 mach_port_t
  648 mach_task_self(void)
  649 {
  650         task_t task = current_task();
  651         ipc_port_t sright;
  652 
  653         sright = retrieve_task_self_fast(task);
  654         return ipc_port_copyout_send(sright, task->itk_space);
  655 }
  656 
  657 /*
  658  *      Routine:        mach_thread_self [mach trap]
  659  *      Purpose:
  660  *              Give the caller send rights for his own thread port.
  661  *      Conditions:
  662  *              Nothing locked.
  663  *      Returns:
  664  *              MACH_PORT_NULL if there are any resource failures
  665  *              or other errors.
  666  */
  667 
  668 mach_port_t
  669 mach_thread_self(void)
  670 {
  671         thread_t thread = current_thread();
  672         task_t task = thread->task;
  673         ipc_port_t sright;
  674 
  675         sright = retrieve_thread_self_fast(thread);
  676         return ipc_port_copyout_send(sright, task->itk_space);
  677 }
  678 
  679 /*
  680  *      Routine:        mach_reply_port [mach trap]
  681  *      Purpose:
  682  *              Allocate a port for the caller.
  683  *      Conditions:
  684  *              Nothing locked.
  685  *      Returns:
  686  *              MACH_PORT_NULL if there are any resource failures
  687  *              or other errors.
  688  */
  689 
  690 mach_port_t
  691 mach_reply_port(void)
  692 {
  693         ipc_port_t port;
  694         mach_port_t name;
  695         kern_return_t kr;
  696 
  697         kr = ipc_port_alloc(current_task()->itk_space, &name, &port);
  698         if (kr == KERN_SUCCESS)
  699                 ip_unlock(port);
  700         else
  701                 name = MACH_PORT_NULL;
  702 
  703         return name;
  704 }
  705 
  706 #if     MACH_IPC_COMPAT
  707 
  708 /*
  709  *      Routine:        retrieve_task_notify
  710  *      Purpose:
  711  *              Return a reference (or null) for
  712  *              the task's notify port.
  713  *      Conditions:
  714  *              Nothing locked.
  715  */
  716 
  717 ipc_port_t
  718 retrieve_task_notify(
  719         task_t task)
  720 {
  721         ipc_space_t space = task->itk_space;
  722         ipc_port_t port;
  723 
  724         is_read_lock(space);
  725         if (space->is_active) {
  726                 port = space->is_notify;
  727                 if (IP_VALID(port))
  728                         ipc_port_reference(port);
  729         } else
  730                 port = IP_NULL;
  731         is_read_unlock(space);
  732 
  733         return port;
  734 }
  735 
  736 /*
  737  *      Routine:        retrieve_thread_reply
  738  *      Purpose:
  739  *              Return a reference (or null) for
  740  *              the thread's reply port.
  741  *      Conditions:
  742  *              Nothing locked.
  743  */
  744 
  745 ipc_port_t
  746 retrieve_thread_reply(
  747         thread_t thread)
  748 {
  749         ipc_port_t port;
  750 
  751         thread_lock(thread);
  752         if (thread->active) {
  753                 port = thread->ith_reply;
  754                 if (IP_VALID(port))
  755                         ipc_port_reference(port);
  756         } else
  757                 port = IP_NULL;
  758         thread_unlock(thread);
  759 
  760         return port;
  761 }
  762 
  763 /*
  764  *      Routine:        task_self [mach trap]
  765  *      Purpose:
  766  *              Give the caller send rights for his task port.
  767  *              If new, the send right is marked with IE_BITS_COMPAT.
  768  *      Conditions:
  769  *              Nothing locked.
  770  *      Returns:
  771  *              MACH_PORT_NULL if there are any resource failures
  772  *              or other errors.
  773  */
  774 
  775 port_name_t
  776 task_self(void)
  777 {
  778         task_t task = current_task();
  779         ipc_port_t sright;
  780         mach_port_t name;
  781 
  782         sright = retrieve_task_self_fast(task);
  783         name = ipc_port_copyout_send_compat(sright, task->itk_space);
  784         return (port_name_t) name;
  785 }
  786 
  787 /*
  788  *      Routine:        task_notify [mach trap]
  789  *      Purpose:
  790  *              Give the caller the name of his own notify port.
  791  *      Conditions:
  792  *              Nothing locked.
  793  *      Returns:
  794  *              MACH_PORT_NULL if there isn't a notify port,
  795  *              if it is dead, or if the caller doesn't hold
  796  *              receive rights for it.
  797  */
  798 
  799 port_name_t
  800 task_notify(void)
  801 {
  802         task_t task = current_task();
  803         ipc_port_t notify;
  804         mach_port_t name;
  805 
  806         notify = retrieve_task_notify(task);
  807         name = ipc_port_copyout_receiver(notify, task->itk_space);
  808         return (port_name_t) name;
  809 }
  810 
  811 /*
  812  *      Routine:        thread_self [mach trap]
  813  *      Purpose:
  814  *              Give the caller send rights for his own thread port.
  815  *              If new, the send right is marked with IE_BITS_COMPAT.
  816  *      Conditions:
  817  *              Nothing locked.
  818  *      Returns:
  819  *              MACH_PORT_NULL if there are any resource failures
  820  *              or other errors.
  821  */
  822 
  823 port_name_t
  824 thread_self(void)
  825 {
  826         thread_t thread = current_thread();
  827         task_t task = thread->task;
  828         ipc_port_t sright;
  829         mach_port_t name;
  830 
  831         sright = retrieve_thread_self_fast(thread);
  832         name = ipc_port_copyout_send_compat(sright, task->itk_space);
  833         return (port_name_t) name;
  834 }
  835 
  836 /*
  837  *      Routine:        thread_reply [mach trap]
  838  *      Purpose:
  839  *              Give the caller the name of his own reply port.
  840  *      Conditions:
  841  *              Nothing locked.
  842  *      Returns:
  843  *              MACH_PORT_NULL if there isn't a reply port,
  844  *              if it is dead, or if the caller doesn't hold
  845  *              receive rights for it.
  846  */
  847 
  848 port_name_t
  849 thread_reply(void)
  850 {
  851         task_t task = current_task();
  852         thread_t thread = current_thread();
  853         ipc_port_t reply;
  854         mach_port_t name;
  855 
  856         reply = retrieve_thread_reply(thread);
  857         name = ipc_port_copyout_receiver(reply, task->itk_space);
  858         return (port_name_t) name;
  859 }
  860 
  861 #endif  /* MACH_IPC_COMPAT */
  862 
  863 /*
  864  *      Routine:        task_get_special_port [kernel call]
  865  *      Purpose:
  866  *              Clones a send right for one of the task's
  867  *              special ports.
  868  *      Conditions:
  869  *              Nothing locked.
  870  *      Returns:
  871  *              KERN_SUCCESS            Extracted a send right.
  872  *              KERN_INVALID_ARGUMENT   The task is null.
  873  *              KERN_FAILURE            The task/space is dead.
  874  *              KERN_INVALID_ARGUMENT   Invalid special port.
  875  */
  876 
  877 kern_return_t
  878 task_get_special_port(
  879         task_t  task,
  880         int     which,
  881         ipc_port_t *portp)
  882 {
  883         ipc_port_t *whichp;
  884         ipc_port_t port;
  885 
  886         if (task == TASK_NULL)
  887                 return KERN_INVALID_ARGUMENT;
  888 
  889         switch (which) {
  890 #if     MACH_IPC_COMPAT
  891             case TASK_NOTIFY_PORT: {
  892                 ipc_space_t space = task->itk_space;
  893 
  894                 is_read_lock(space);
  895                 if (!space->is_active) {
  896                         is_read_unlock(space);
  897                         return KERN_FAILURE;
  898                 }
  899 
  900                 port = ipc_port_copy_send(space->is_notify);
  901                 is_read_unlock(space);
  902 
  903                 *portp = port;
  904                 return KERN_SUCCESS;
  905             }
  906 #endif  /* MACH_IPC_COMPAT */
  907 
  908             case TASK_KERNEL_PORT:
  909                 whichp = &task->itk_sself;
  910                 break;
  911 
  912             case TASK_EXCEPTION_PORT:
  913                 whichp = &task->itk_exception;
  914                 break;
  915 
  916             case TASK_BOOTSTRAP_PORT:
  917                 whichp = &task->itk_bootstrap;
  918                 break;
  919 
  920             default:
  921                 return KERN_INVALID_ARGUMENT;
  922         }
  923 
  924         task_lock(task);
  925         if (!task->active) {
  926                 task_unlock(task);
  927                 return KERN_FAILURE;
  928         }
  929 
  930         port = ipc_port_copy_send(*whichp);
  931         task_unlock(task);
  932 
  933         *portp = port;
  934         return KERN_SUCCESS;
  935 }
  936 
  937 /*
  938  *      Routine:        task_set_special_port [kernel call]
  939  *      Purpose:
  940  *              Changes one of the task's special ports,
  941  *              setting it to the supplied send right.
  942  *      Conditions:
  943  *              Nothing locked.  If successful, consumes
  944  *              the supplied send right.
  945  *      Returns:
  946  *              KERN_SUCCESS            Changed the special port.
  947  *              KERN_INVALID_ARGUMENT   The task is null.
  948  *              KERN_FAILURE            The task/space is dead.
  949  *              KERN_INVALID_ARGUMENT   Invalid special port.
  950  */
  951 
  952 kern_return_t
  953 task_set_special_port(
  954         task_t  task,
  955         int     which,
  956         ipc_port_t port)
  957 {
  958         ipc_port_t *whichp;
  959         ipc_port_t old;
  960 
  961         if (task == TASK_NULL)
  962                 return KERN_INVALID_ARGUMENT;
  963 
  964         switch (which) {
  965 #if     MACH_IPC_COMPAT
  966             case TASK_NOTIFY_PORT: {
  967                 ipc_space_t space = task->itk_space;
  968 
  969                 is_write_lock(space);
  970                 if (!space->is_active) {
  971                         is_write_unlock(space);
  972                         return KERN_FAILURE;
  973                 }
  974 
  975                 old = space->is_notify;
  976                 space->is_notify = port;
  977                 is_write_unlock(space);
  978 
  979                 if (IP_VALID(old))
  980                         ipc_port_release_send(old);
  981                 return KERN_SUCCESS;
  982             }
  983 #endif  /* MACH_IPC_COMPAT */
  984 
  985             case TASK_KERNEL_PORT:
  986                 whichp = &task->itk_sself;
  987                 break;
  988 
  989             case TASK_EXCEPTION_PORT:
  990                 whichp = &task->itk_exception;
  991                 break;
  992 
  993             case TASK_BOOTSTRAP_PORT:
  994                 whichp = &task->itk_bootstrap;
  995                 break;
  996 
  997             default:
  998                 return KERN_INVALID_ARGUMENT;
  999         }
 1000 
 1001         task_lock(task);
 1002         if (!task->active) {
 1003                 task_unlock(task);
 1004                 return KERN_FAILURE;
 1005         }
 1006 
 1007         old = *whichp;
 1008         *whichp = port;
 1009         task_unlock(task);
 1010 
 1011         if (IP_VALID(old))
 1012                 ipc_port_release_send(old);
 1013         return KERN_SUCCESS;
 1014 }
 1015 
 1016 /*
 1017  *      Routine:        thread_get_special_port [kernel call]
 1018  *      Purpose:
 1019  *              Clones a send right for one of the thread's
 1020  *              special ports.
 1021  *      Conditions:
 1022  *              Nothing locked.
 1023  *      Returns:
 1024  *              KERN_SUCCESS            Extracted a send right.
 1025  *              KERN_INVALID_ARGUMENT   The thread is null.
 1026  *              KERN_FAILURE            The thread is dead.
 1027  *              KERN_INVALID_ARGUMENT   Invalid special port.
 1028  */
 1029 
 1030 kern_return_t
 1031 thread_get_special_port(
 1032         thread_t thread,
 1033         int      which,
 1034         ipc_port_t *portp)
 1035 {
 1036         ipc_port_t *whichp;
 1037         ipc_port_t port;
 1038 
 1039         if (thread == ITH_NULL)
 1040                 return KERN_INVALID_ARGUMENT;
 1041 
 1042         switch (which) {
 1043 #if     MACH_IPC_COMPAT
 1044             case THREAD_REPLY_PORT:
 1045                 whichp = &thread->ith_reply;
 1046                 break;
 1047 #endif  /* MACH_IPC_COMPAT */
 1048 
 1049             case THREAD_KERNEL_PORT:
 1050                 whichp = &thread->ith_sself;
 1051                 break;
 1052 
 1053             case THREAD_EXCEPTION_PORT:
 1054                 whichp = &thread->ith_exception;
 1055                 break;
 1056 
 1057             default:
 1058                 return KERN_INVALID_ARGUMENT;
 1059         }
 1060 
 1061         thread_lock(thread);
 1062         if (!thread->active) {
 1063                 thread_unlock(thread);
 1064                 return KERN_FAILURE;
 1065         }
 1066 
 1067         port = ipc_port_copy_send(*whichp);
 1068         thread_unlock(thread);
 1069 
 1070         *portp = port;
 1071         return KERN_SUCCESS;
 1072 }
 1073 
 1074 /*
 1075  *      Routine:        thread_set_special_port [kernel call]
 1076  *      Purpose:
 1077  *              Changes one of the thread's special ports,
 1078  *              setting it to the supplied send right.
 1079  *      Conditions:
 1080  *              Nothing locked.  If successful, consumes
 1081  *              the supplied send right.
 1082  *      Returns:
 1083  *              KERN_SUCCESS            Changed the special port.
 1084  *              KERN_INVALID_ARGUMENT   The thread is null.
 1085  *              KERN_FAILURE            The thread is dead.
 1086  *              KERN_INVALID_ARGUMENT   Invalid special port.
 1087  */
 1088 
 1089 kern_return_t
 1090 thread_set_special_port(
 1091         thread_t thread,
 1092         int      which,
 1093         ipc_port_t port)
 1094 {
 1095         ipc_port_t *whichp;
 1096         ipc_port_t old;
 1097 
 1098         if (thread == ITH_NULL)
 1099                 return KERN_INVALID_ARGUMENT;
 1100 
 1101         switch (which) {
 1102 #if     MACH_IPC_COMPAT
 1103             case THREAD_REPLY_PORT:
 1104                 whichp = &thread->ith_reply;
 1105                 break;
 1106 #endif  /* MACH_IPC_COMPAT */
 1107 
 1108             case THREAD_KERNEL_PORT:
 1109                 whichp = &thread->ith_sself;
 1110                 break;
 1111 
 1112             case THREAD_EXCEPTION_PORT:
 1113                 whichp = &thread->ith_exception;
 1114                 break;
 1115 
 1116             default:
 1117                 return KERN_INVALID_ARGUMENT;
 1118         }
 1119 
 1120         thread_lock(thread);
 1121         if (!thread->active) {
 1122                 thread_unlock(thread);
 1123                 return KERN_FAILURE;
 1124         }
 1125 
 1126         old = *whichp;
 1127         *whichp = port;
 1128         thread_unlock(thread);
 1129 
 1130         if (IP_VALID(old))
 1131                 ipc_port_release_send(old);
 1132         return KERN_SUCCESS;
 1133 }
 1134 
 1135 /*
 1136  *      Routine:        mach_ports_register [kernel call]
 1137  *      Purpose:
 1138  *              Stash a handful of port send rights in the task.
 1139  *              Child tasks will inherit these rights, but they
 1140  *              must use mach_ports_lookup to acquire them.
 1141  *
 1142  *              The rights are supplied in a (wired) kalloc'd segment.
 1143  *              Rights which aren't supplied are assumed to be null.
 1144  *      Conditions:
 1145  *              Nothing locked.  If successful, consumes
 1146  *              the supplied rights and memory.
 1147  *      Returns:
 1148  *              KERN_SUCCESS            Stashed the port rights.
 1149  *              KERN_INVALID_ARGUMENT   The task is null.
 1150  *              KERN_INVALID_ARGUMENT   The task is dead.
 1151  *              KERN_INVALID_ARGUMENT   Too many port rights supplied.
 1152  */
 1153 
 1154 kern_return_t
 1155 mach_ports_register(
 1156         task_t task,
 1157         ipc_port_t *memory,
 1158         mach_msg_type_number_t portsCnt)
 1159 {
 1160         ipc_port_t ports[TASK_PORT_REGISTER_MAX];
 1161         int i;
 1162 
 1163         if ((task == TASK_NULL) ||
 1164             (portsCnt > TASK_PORT_REGISTER_MAX))
 1165                 return KERN_INVALID_ARGUMENT;
 1166 
 1167         /*
 1168          *      Pad the port rights with nulls.
 1169          */
 1170 
 1171         for (i = 0; i < portsCnt; i++)
 1172                 ports[i] = memory[i];
 1173         for (; i < TASK_PORT_REGISTER_MAX; i++)
 1174                 ports[i] = IP_NULL;
 1175 
 1176         task_lock(task);
 1177         if (!task->active) {
 1178                 task_unlock(task);
 1179                 return KERN_INVALID_ARGUMENT;
 1180         }
 1181 
 1182         /*
 1183          *      Replace the old send rights with the new.
 1184          *      Release the old rights after unlocking.
 1185          */
 1186 
 1187         for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) {
 1188                 ipc_port_t old;
 1189 
 1190                 old = task->itk_registered[i];
 1191                 task->itk_registered[i] = ports[i];
 1192                 ports[i] = old;
 1193         }
 1194 
 1195         task_unlock(task);
 1196 
 1197         for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
 1198                 if (IP_VALID(ports[i]))
 1199                         ipc_port_release_send(ports[i]);
 1200 
 1201         /*
 1202          *      Now that the operation is known to be successful,
 1203          *      we can free the memory.
 1204          */
 1205 
 1206         if (portsCnt != 0)
 1207                 kfree((vm_offset_t) memory,
 1208                       (vm_size_t) (portsCnt * sizeof(mach_port_t)));
 1209 
 1210         return KERN_SUCCESS;
 1211 }
 1212 
 1213 /*
 1214  *      Routine:        mach_ports_lookup [kernel call]
 1215  *      Purpose:
 1216  *              Retrieves (clones) the stashed port send rights.
 1217  *      Conditions:
 1218  *              Nothing locked.  If successful, the caller gets
 1219  *              rights and memory.
 1220  *      Returns:
 1221  *              KERN_SUCCESS            Retrieved the send rights.
 1222  *              KERN_INVALID_ARGUMENT   The task is null.
 1223  *              KERN_INVALID_ARGUMENT   The task is dead.
 1224  *              KERN_RESOURCE_SHORTAGE  Couldn't allocate memory.
 1225  */
 1226 
 1227 kern_return_t
 1228 mach_ports_lookup(
 1229         task_t task,
 1230         ipc_port_t **portsp,
 1231         mach_msg_type_number_t *portsCnt)
 1232 {
 1233         vm_offset_t memory;
 1234         vm_size_t size;
 1235         ipc_port_t *ports;
 1236         int i;
 1237 
 1238         if (task == TASK_NULL)
 1239                 return KERN_INVALID_ARGUMENT;
 1240 
 1241         size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t));
 1242 
 1243         memory = kalloc(size);
 1244         if (memory == 0)
 1245                 return KERN_RESOURCE_SHORTAGE;
 1246 
 1247         task_lock(task);
 1248         if (!task->active) {
 1249                 task_unlock(task);
 1250 
 1251                 kfree(memory, size);
 1252                 return KERN_INVALID_ARGUMENT;
 1253         }
 1254 
 1255         ports = (ipc_port_t *) memory;
 1256 
 1257         /*
 1258          *      Clone port rights.  Because kalloc'd memory
 1259          *      is wired, we won't fault while holding the task lock.
 1260          */
 1261 
 1262         for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
 1263                 ports[i] = ipc_port_copy_send(task->itk_registered[i]);
 1264 
 1265         task_unlock(task);
 1266 
 1267         *portsp = ports;
 1268         *portsCnt = TASK_PORT_REGISTER_MAX;
 1269         return KERN_SUCCESS;
 1270 }
 1271 
 1272 /*
 1273  *      Routine:        convert_port_to_task
 1274  *      Purpose:
 1275  *              Convert from a port to a task.
 1276  *              Doesn't consume the port ref; produces a task ref,
 1277  *              which may be null.
 1278  *      Conditions:
 1279  *              Nothing locked.
 1280  */
 1281 
 1282 task_t
 1283 convert_port_to_task(
 1284         ipc_port_t port)
 1285 {
 1286         task_t task = TASK_NULL;
 1287 
 1288         if (IP_VALID(port)) {
 1289                 ip_lock(port);
 1290                 if (ip_active(port) &&
 1291                     (ip_kotype(port) == IKOT_TASK)) {
 1292                         task = (task_t) port->ip_kobject;
 1293                         task_reference(task);
 1294                 }
 1295                 ip_unlock(port);
 1296         }
 1297 
 1298         return task;
 1299 }
 1300 
 1301 /*
 1302  *      Routine:        convert_port_to_space
 1303  *      Purpose:
 1304  *              Convert from a port to a space.
 1305  *              Doesn't consume the port ref; produces a space ref,
 1306  *              which may be null.
 1307  *      Conditions:
 1308  *              Nothing locked.
 1309  */
 1310 
 1311 ipc_space_t
 1312 convert_port_to_space(
 1313         ipc_port_t port)
 1314 {
 1315         ipc_space_t space = IS_NULL;
 1316 
 1317         if (IP_VALID(port)) {
 1318                 ip_lock(port);
 1319                 if (ip_active(port) &&
 1320                     (ip_kotype(port) == IKOT_TASK)) {
 1321                         space = ((task_t) port->ip_kobject)->itk_space;
 1322                         is_reference(space);
 1323                 }
 1324                 ip_unlock(port);
 1325         }
 1326 
 1327         return space;
 1328 }
 1329 
 1330 /*
 1331  *      Routine:        convert_port_to_map
 1332  *      Purpose:
 1333  *              Convert from a port to a map.
 1334  *              Doesn't consume the port ref; produces a map ref,
 1335  *              which may be null.
 1336  *      Conditions:
 1337  *              Nothing locked.
 1338  */
 1339 
 1340 vm_map_t
 1341 convert_port_to_map(
 1342         ipc_port_t port)
 1343 {
 1344         vm_map_t map = VM_MAP_NULL;
 1345 
 1346         if (IP_VALID(port)) {
 1347                 ip_lock(port);
 1348                 if (ip_active(port) &&
 1349                     (ip_kotype(port) == IKOT_TASK)) {
 1350                         map = ((task_t) port->ip_kobject)->map;
 1351                         vm_map_reference(map);
 1352                 }
 1353                 ip_unlock(port);
 1354         }
 1355 
 1356         return map;
 1357 }
 1358 
 1359 /*
 1360  *      Routine:        convert_port_to_thread
 1361  *      Purpose:
 1362  *              Convert from a port to a thread.
 1363  *              Doesn't consume the port ref; produces a thread ref,
 1364  *              which may be null.
 1365  *      Conditions:
 1366  *              Nothing locked.
 1367  */
 1368 
 1369 thread_t
 1370 convert_port_to_thread(
 1371         ipc_port_t port)
 1372 {
 1373         thread_t thread = THREAD_NULL;
 1374 
 1375         if (IP_VALID(port)) {
 1376                 ip_lock(port);
 1377                 if (ip_active(port) &&
 1378                     (ip_kotype(port) == IKOT_THREAD)) {
 1379                         thread = (thread_t) port->ip_kobject;
 1380                         thread_reference(thread);
 1381                 }
 1382                 ip_unlock(port);
 1383         }
 1384 
 1385         return thread;
 1386 }
 1387 
 1388 /*
 1389  *      Routine:        convert_task_to_port
 1390  *      Purpose:
 1391  *              Convert from a task to a port.
 1392  *              Consumes a task ref; produces a naked send right
 1393  *              which may be invalid.  
 1394  *      Conditions:
 1395  *              Nothing locked.
 1396  */
 1397 
 1398 ipc_port_t
 1399 convert_task_to_port(
 1400         task_t task)
 1401 {
 1402         ipc_port_t port;
 1403 
 1404         task_lock(task);
 1405         if (task->active) {
 1406                 assert(task->itk_self != IP_NULL);
 1407                 port = ipc_port_make_send(task->itk_self);
 1408         }
 1409         else
 1410                 port = IP_NULL;
 1411         task_unlock(task);
 1412 
 1413         task_deallocate(task);
 1414         return port;
 1415 }
 1416 
 1417 /*
 1418  *      Routine:        convert_thread_to_port
 1419  *      Purpose:
 1420  *              Convert from a thread to a port.
 1421  *              Consumes a thread ref; produces a naked send right
 1422  *              which may be invalid.
 1423  *      Conditions:
 1424  *              Nothing locked.
 1425  */
 1426 
 1427 ipc_port_t
 1428 convert_thread_to_port(
 1429         thread_t thread)
 1430 {
 1431         ipc_port_t port;
 1432 
 1433         thread_lock(thread);
 1434         if (thread->active) {
 1435                 assert(thread->ith_self != IP_NULL);
 1436                 port = ipc_port_make_send(thread->ith_self);
 1437         }
 1438         else
 1439                 port = IP_NULL;
 1440         thread_unlock(thread);
 1441 
 1442         thread_deallocate(thread);
 1443         return port;
 1444 }
 1445 
 1446 /*
 1447  *      Routine:        space_deallocate
 1448  *      Purpose:
 1449  *              Deallocate a space ref produced by convert_port_to_space.
 1450  *      Conditions:
 1451  *              Nothing locked.
 1452  */
 1453 
 1454 void
 1455 space_deallocate(
 1456         ipc_space_t space)
 1457 {
 1458         if (space != IS_NULL)
 1459                 is_release(space);
 1460 }

Cache object: e39b99df4654e2f2f99a2ad75d133c31


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