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) 1991,1990,1989,1988,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.14  92/08/03  17:37:42  jfriedl
   30  *      removed silly prototypes
   31  *      [92/08/02            jfriedl]
   32  * 
   33  * Revision 2.13  92/05/21  17:14:13  jfriedl
   34  *      Removed unsed var 'kr' from mach_ports_lookup().
   35  *      [92/05/16            jfriedl]
   36  * 
   37  * Revision 2.12  91/06/25  10:28:49  rpd
   38  *      Changed the convert_foo_to_bar functions
   39  *      to use ipc_port_t instead of mach_port_t.
   40  *      [91/05/27            rpd]
   41  * 
   42  * Revision 2.11  91/06/17  15:47:09  jsb
   43  *      Renamed NORMA conditionals. Moved norma code to norma/kern_task.c.
   44  *      [91/06/17  10:50:57  jsb]
   45  * 
   46  * Revision 2.10  91/06/06  17:07:15  jsb
   47  *      NORMA_TASK support.
   48  *      [91/05/14  09:17:09  jsb]
   49  * 
   50  * Revision 2.9  91/05/14  16:42:54  mrt
   51  *      Correcting copyright
   52  * 
   53  * Revision 2.8  91/03/16  14:50:24  rpd
   54  *      Removed ith_saved.
   55  *      [91/02/16            rpd]
   56  * 
   57  * Revision 2.7  91/02/05  17:27:08  mrt
   58  *      Changed to new Mach copyright
   59  *      [91/02/01  16:13:42  mrt]
   60  * 
   61  * Revision 2.6  91/01/08  15:16:05  rpd
   62  *      Added retrieve_task_self_fast, retrieve_thread_self_fast.
   63  *      [90/12/27            rpd]
   64  * 
   65  * Revision 2.5  90/11/05  14:31:08  rpd
   66  *      Changed ip_reference to ipc_port_reference.
   67  *      Use new ip_reference and ip_release.
   68  *      [90/10/29            rpd]
   69  * 
   70  * Revision 2.4  90/06/02  14:54:33  rpd
   71  *      Converted to new IPC.
   72  *      [90/03/26  22:05:07  rpd]
   73  * 
   74  *
   75  * Condensed history:
   76  *      Modified for pure kernel (dbg).
   77  *      Support thread_exception_abort (dlb).
   78  *      Added kernel monitor support (tfl).
   79  *      Added task/thread kernel port interposing (rpd).
   80  *      Improvements/fixes for task_secure (rpd).
   81  *      New translation cache (rpd).
   82  *      Move old stuff under MACH_IPC_XXXHACK (rpd).
   83  *      Created from mach_ipc.c (rpd).
   84  */
   85 
   86 /*
   87  * File:        ipc_tt.c
   88  * Purpose:
   89  *      Task and thread related IPC functions.
   90  */
   91 
   92 #include <mach_ipc_compat.h>
   93 
   94 #include <mach/boolean.h>
   95 #include <mach/kern_return.h>
   96 #include <mach/mach_param.h>
   97 #include <mach/task_special_ports.h>
   98 #include <mach/thread_special_ports.h>
   99 #include <vm/vm_kern.h>
  100 #include <kern/task.h>
  101 #include <kern/thread.h>
  102 #include <kern/ipc_kobject.h>
  103 #include <kern/ipc_tt.h>
  104 #include <ipc/ipc_space.h>
  105 #include <ipc/ipc_table.h>
  106 #include <ipc/ipc_port.h>
  107 #include <ipc/ipc_right.h>
  108 #include <ipc/ipc_entry.h>
  109 #include <ipc/ipc_object.h>
  110 
  111 
  112 
  113 /*
  114  *      Routine:        ipc_task_init
  115  *      Purpose:
  116  *              Initialize a task's IPC state.
  117  *
  118  *              If non-null, some state will be inherited from the parent.
  119  *              The parent must be appropriately initialized.
  120  *      Conditions:
  121  *              Nothing locked.
  122  */
  123 
  124 void
  125 ipc_task_init(task, parent)
  126         task_t task;
  127         task_t parent;
  128 {
  129         ipc_space_t space;
  130         ipc_port_t kport;
  131         kern_return_t kr;
  132         int i;
  133 
  134         kr = ipc_space_create(&ipc_table_entries[0], &space);
  135         if (kr != KERN_SUCCESS)
  136                 panic("ipc_task_init");
  137 
  138         kport = ipc_port_alloc_kernel();
  139         if (kport == IP_NULL)
  140                 panic("ipc_task_init");
  141 
  142         itk_lock_init(task);
  143         task->itk_self = kport;
  144         task->itk_sself = ipc_port_make_send(kport);
  145         task->itk_space = space;
  146 
  147         if (parent == TASK_NULL) {
  148                 task->itk_exception = IP_NULL;
  149                 task->itk_bootstrap = IP_NULL;
  150                 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  151                         task->itk_registered[i] = IP_NULL;
  152         } else {
  153                 itk_lock(parent);
  154                 assert(parent->itk_self != IP_NULL);
  155 
  156                 /* inherit registered ports */
  157 
  158                 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  159                         task->itk_registered[i] =
  160                                 ipc_port_copy_send(parent->itk_registered[i]);
  161 
  162                 /* inherit exception and bootstrap ports */
  163 
  164                 task->itk_exception =
  165                         ipc_port_copy_send(parent->itk_exception);
  166                 task->itk_bootstrap =
  167                         ipc_port_copy_send(parent->itk_bootstrap);
  168 
  169                 itk_unlock(parent);
  170         }
  171 }
  172 
  173 /*
  174  *      Routine:        ipc_task_enable
  175  *      Purpose:
  176  *              Enable a task for IPC access.
  177  *      Conditions:
  178  *              Nothing locked.
  179  */
  180 
  181 void
  182 ipc_task_enable(task)
  183         task_t task;
  184 {
  185         ipc_port_t kport;
  186 
  187         itk_lock(task);
  188         kport = task->itk_self;
  189         if (kport != IP_NULL)
  190                 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK);
  191         itk_unlock(task);
  192 }
  193 
  194 /*
  195  *      Routine:        ipc_task_disable
  196  *      Purpose:
  197  *              Disable IPC access to a task.
  198  *      Conditions:
  199  *              Nothing locked.
  200  */
  201 
  202 void
  203 ipc_task_disable(task)
  204         task_t task;
  205 {
  206         ipc_port_t kport;
  207 
  208         itk_lock(task);
  209         kport = task->itk_self;
  210         if (kport != IP_NULL)
  211                 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
  212         itk_unlock(task);
  213 }
  214 
  215 /*
  216  *      Routine:        ipc_task_terminate
  217  *      Purpose:
  218  *              Clean up and destroy a task's IPC state.
  219  *      Conditions:
  220  *              Nothing locked.  The task must be suspended.
  221  *              (Or the current thread must be in the task.)
  222  */
  223 
  224 void
  225 ipc_task_terminate(task)
  226         task_t task;
  227 {
  228         ipc_port_t kport;
  229         int i;
  230 
  231         itk_lock(task);
  232         kport = task->itk_self;
  233 
  234         if (kport == IP_NULL) {
  235                 /* the task is already terminated (can this happen?) */
  236                 itk_unlock(task);
  237                 return;
  238         }
  239 
  240         task->itk_self = IP_NULL;
  241         itk_unlock(task);
  242 
  243         /* release the naked send rights */
  244 
  245         if (IP_VALID(task->itk_sself))
  246                 ipc_port_release_send(task->itk_sself);
  247         if (IP_VALID(task->itk_exception))
  248                 ipc_port_release_send(task->itk_exception);
  249         if (IP_VALID(task->itk_bootstrap))
  250                 ipc_port_release_send(task->itk_bootstrap);
  251 
  252         for (i = 0; i < TASK_PORT_REGISTER_MAX; i++)
  253                 if (IP_VALID(task->itk_registered[i]))
  254                         ipc_port_release_send(task->itk_registered[i]);
  255 
  256         /* destroy the space, leaving just a reference for it */
  257 
  258         ipc_space_destroy(task->itk_space);
  259 
  260         /* destroy the kernel port */
  261 
  262         ipc_port_dealloc_kernel(kport);
  263 }
  264 
  265 /*
  266  *      Routine:        ipc_thread_init
  267  *      Purpose:
  268  *              Initialize a thread's IPC state.
  269  *      Conditions:
  270  *              Nothing locked.
  271  */
  272 
  273 void
  274 ipc_thread_init(thread)
  275         thread_t thread;
  276 {
  277         ipc_port_t kport;
  278 
  279         kport = ipc_port_alloc_kernel();
  280         if (kport == IP_NULL)
  281                 panic("ipc_thread_init");
  282 
  283         ipc_thread_links_init(thread);
  284         ipc_kmsg_queue_init(&thread->ith_messages);
  285 
  286         ith_lock_init(thread);
  287         thread->ith_self = kport;
  288         thread->ith_sself = ipc_port_make_send(kport);
  289         thread->ith_exception = IP_NULL;
  290 
  291         thread->ith_mig_reply = MACH_PORT_NULL;
  292         thread->ith_rpc_reply = IP_NULL;
  293 
  294 #if     MACH_IPC_COMPAT
  295     {
  296         ipc_space_t space = thread->task->itk_space;
  297         ipc_port_t port;
  298         mach_port_t name;
  299         kern_return_t kr;
  300 
  301         kr = ipc_port_alloc_compat(space, &name, &port);
  302         if (kr != KERN_SUCCESS)
  303                 panic("ipc_thread_init");
  304         /* port is locked and active */
  305 
  306         /*
  307          *      Now we have a reply port.  We need to make a naked
  308          *      send right to stash in ith_reply.  We can't use
  309          *      ipc_port_make_send, because we can't unlock the port
  310          *      before making the right.  Also we don't want to
  311          *      increment ip_mscount.  The net effect of all this
  312          *      is the same as doing
  313          *              ipc_port_alloc_kernel           get the port
  314          *              ipc_port_make_send              make the send right
  315          *              ipc_object_copyin_from_kernel   grab receive right
  316          *              ipc_object_copyout_compat       and give to user
  317          */
  318 
  319         port->ip_srights++;
  320         ip_reference(port);
  321         ip_unlock(port);
  322 
  323         thread->ith_reply = port;
  324     }
  325 #endif  MACH_IPC_COMPAT
  326 }
  327 
  328 /*
  329  *      Routine:        ipc_thread_enable
  330  *      Purpose:
  331  *              Enable a thread for IPC access.
  332  *      Conditions:
  333  *              Nothing locked.
  334  */
  335 
  336 void
  337 ipc_thread_enable(thread)
  338         thread_t thread;
  339 {
  340         ipc_port_t kport;
  341 
  342         ith_lock(thread);
  343         kport = thread->ith_self;
  344         if (kport != IP_NULL)
  345                 ipc_kobject_set(kport, (ipc_kobject_t) thread, IKOT_THREAD);
  346         ith_unlock(thread);
  347 }
  348 
  349 /*
  350  *      Routine:        ipc_thread_disable
  351  *      Purpose:
  352  *              Disable IPC access to a thread.
  353  *      Conditions:
  354  *              Nothing locked.
  355  */
  356 
  357 void
  358 ipc_thread_disable(thread)
  359         thread_t thread;
  360 {
  361         ipc_port_t kport;
  362 
  363         ith_lock(thread);
  364         kport = thread->ith_self;
  365         if (kport != IP_NULL)
  366                 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE);
  367         ith_unlock(thread);
  368 }
  369 
  370 /*
  371  *      Routine:        ipc_thread_terminate
  372  *      Purpose:
  373  *              Clean up and destroy a thread's IPC state.
  374  *      Conditions:
  375  *              Nothing locked.  The thread must be suspended.
  376  *              (Or be the current thread.)
  377  */
  378 
  379 void
  380 ipc_thread_terminate(thread)
  381         thread_t thread;
  382 {
  383         ipc_port_t kport;
  384 
  385         ith_lock(thread);
  386         kport = thread->ith_self;
  387 
  388         if (kport == IP_NULL) {
  389                 /* the thread is already terminated (can this happen?) */
  390                 ith_unlock(thread);
  391                 return;
  392         }
  393 
  394         thread->ith_self = IP_NULL;
  395         ith_unlock(thread);
  396 
  397         assert(ipc_kmsg_queue_empty(&thread->ith_messages));
  398 
  399         /* release the naked send rights */
  400 
  401         if (IP_VALID(thread->ith_sself))
  402                 ipc_port_release_send(thread->ith_sself);
  403         if (IP_VALID(thread->ith_exception))
  404                 ipc_port_release_send(thread->ith_exception);
  405 
  406 #if     MACH_IPC_COMPAT
  407         if (IP_VALID(thread->ith_reply)) {
  408                 ipc_space_t space = thread->task->itk_space;
  409                 ipc_port_t port = thread->ith_reply;
  410                 ipc_entry_t entry;
  411                 mach_port_t name;
  412 
  413                 /* destroy any rights the task may have for the port */
  414 
  415                 is_write_lock(space);
  416                 if (space->is_active &&
  417                     ipc_right_reverse(space, (ipc_object_t) port,
  418                                       &name, &entry)) {
  419                         /* reply port is locked and active */
  420                         ip_unlock(port);
  421 
  422                         (void) ipc_right_destroy(space, name, entry);
  423                         /* space is unlocked */
  424                 } else
  425                         is_write_unlock(space);
  426 
  427                 ipc_port_release_send(port);
  428         }
  429 
  430         /*
  431          *      Note we do *not* destroy any rights the space may have
  432          *      for the thread's kernel port.  The old IPC code did this,
  433          *      to avoid generating a notification when the port is
  434          *      destroyed.  However, this isn't a good idea when
  435          *      the kernel port is interposed, because then it doesn't
  436          *      happen, exposing the interposition to the task.
  437          *      Because we don't need the efficiency hack, I flushed
  438          *      this behaviour, introducing a small incompatibility
  439          *      with the old IPC code.
  440          */
  441 #endif  MACH_IPC_COMPAT
  442 
  443         /* destroy the kernel port */
  444 
  445         ipc_port_dealloc_kernel(kport);
  446 }
  447 
  448 #if     0
  449 /*
  450  *      Routine:        retrieve_task_self
  451  *      Purpose:
  452  *              Return a send right (possibly null/dead)
  453  *              for the task's user-visible self port.
  454  *      Conditions:
  455  *              Nothing locked.
  456  */
  457 
  458 ipc_port_t
  459 retrieve_task_self(task)
  460         task_t task;
  461 {
  462         ipc_port_t port;
  463 
  464         assert(task != TASK_NULL);
  465 
  466         itk_lock(task);
  467         if (task->itk_self != IP_NULL)
  468                 port = ipc_port_copy_send(task->itk_sself);
  469         else
  470                 port = IP_NULL;
  471         itk_unlock(task);
  472 
  473         return port;
  474 }
  475 
  476 /*
  477  *      Routine:        retrieve_thread_self
  478  *      Purpose:
  479  *              Return a send right (possibly null/dead)
  480  *              for the thread's user-visible self port.
  481  *      Conditions:
  482  *              Nothing locked.
  483  */
  484 
  485 ipc_port_t
  486 retrieve_thread_self(thread)
  487         thread_t thread;
  488 {
  489         ipc_port_t port;
  490 
  491         assert(thread != ITH_NULL);
  492 
  493         ith_lock(thread);
  494         if (thread->ith_self != IP_NULL)
  495                 port = ipc_port_copy_send(thread->ith_sself);
  496         else
  497                 port = IP_NULL;
  498         ith_unlock(thread);
  499 
  500         return port;
  501 }
  502 #endif  0
  503 
  504 /*
  505  *      Routine:        retrieve_task_self_fast
  506  *      Purpose:
  507  *              Optimized version of retrieve_task_self,
  508  *              that only works for the current task.
  509  *
  510  *              Return a send right (possibly null/dead)
  511  *              for the task's user-visible self port.
  512  *      Conditions:
  513  *              Nothing locked.
  514  */
  515 
  516 ipc_port_t
  517 retrieve_task_self_fast(task)
  518         register task_t task;
  519 {
  520         register ipc_port_t port;
  521 
  522         assert(task == current_task());
  523 
  524         itk_lock(task);
  525         assert(task->itk_self != IP_NULL);
  526 
  527         if ((port = task->itk_sself) == task->itk_self) {
  528                 /* no interposing */
  529 
  530                 ip_lock(port);
  531                 assert(ip_active(port));
  532                 ip_reference(port);
  533                 port->ip_srights++;
  534                 ip_unlock(port);
  535         } else
  536                 port = ipc_port_copy_send(port);
  537         itk_unlock(task);
  538 
  539         return port;
  540 }
  541 
  542 /*
  543  *      Routine:        retrieve_thread_self_fast
  544  *      Purpose:
  545  *              Optimized version of retrieve_thread_self,
  546  *              that only works for the current thread.
  547  *
  548  *              Return a send right (possibly null/dead)
  549  *              for the thread's user-visible self port.
  550  *      Conditions:
  551  *              Nothing locked.
  552  */
  553 
  554 ipc_port_t
  555 retrieve_thread_self_fast(thread)
  556         register thread_t thread;
  557 {
  558         register ipc_port_t port;
  559 
  560         assert(thread == current_thread());
  561 
  562         ith_lock(thread);
  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         ith_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(task)
  592         task_t task;
  593 {
  594         ipc_port_t port;
  595 
  596         assert(task != TASK_NULL);
  597 
  598         itk_lock(task);
  599         if (task->itk_self != IP_NULL)
  600                 port = ipc_port_copy_send(task->itk_exception);
  601         else
  602                 port = IP_NULL;
  603         itk_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(thread)
  619         thread_t thread;
  620 {
  621         ipc_port_t port;
  622 
  623         assert(thread != ITH_NULL);
  624 
  625         ith_lock(thread);
  626         if (thread->ith_self != IP_NULL)
  627                 port = ipc_port_copy_send(thread->ith_exception);
  628         else
  629                 port = IP_NULL;
  630         ith_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()
  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()
  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()
  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(task)
  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(thread)
  747         thread_t thread;
  748 {
  749         ipc_port_t port;
  750 
  751         ith_lock(thread);
  752         if (thread->ith_self != IP_NULL) {
  753                 port = thread->ith_reply;
  754                 if (IP_VALID(port))
  755                         ipc_port_reference(port);
  756         } else
  757                 port = IP_NULL;
  758         ith_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()
  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()
  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()
  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()
  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(task, which, portp)
  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         itk_lock(task);
  925         if (task->itk_self == IP_NULL) {
  926                 itk_unlock(task);
  927                 return KERN_FAILURE;
  928         }
  929 
  930         port = ipc_port_copy_send(*whichp);
  931         itk_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(task, which, 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         itk_lock(task);
 1002         if (task->itk_self == IP_NULL) {
 1003                 itk_unlock(task);
 1004                 return KERN_FAILURE;
 1005         }
 1006 
 1007         old = *whichp;
 1008         *whichp = port;
 1009         itk_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(thread, which, portp)
 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         ith_lock(thread);
 1062         if (thread->ith_self == IP_NULL) {
 1063                 ith_unlock(thread);
 1064                 return KERN_FAILURE;
 1065         }
 1066 
 1067         port = ipc_port_copy_send(*whichp);
 1068         ith_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(thread, which, 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         ith_lock(thread);
 1121         if (thread->ith_self == IP_NULL) {
 1122                 ith_unlock(thread);
 1123                 return KERN_FAILURE;
 1124         }
 1125 
 1126         old = *whichp;
 1127         *whichp = port;
 1128         ith_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(task, memory, portsCnt)
 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         itk_lock(task);
 1177         if (task->itk_self == IP_NULL) {
 1178                 itk_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         itk_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(task, portsp, portsCnt)
 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         itk_lock(task);
 1248         if (task->itk_self == IP_NULL) {
 1249                 itk_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         itk_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(port)
 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(port)
 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(port)
 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(port)
 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(task)
 1400         task_t task;
 1401 {
 1402         ipc_port_t port;
 1403 
 1404         itk_lock(task);
 1405         if (task->itk_self != IP_NULL)
 1406                 port = ipc_port_make_send(task->itk_self);
 1407         else
 1408                 port = IP_NULL;
 1409         itk_unlock(task);
 1410 
 1411         task_deallocate(task);
 1412         return port;
 1413 }
 1414 
 1415 /*
 1416  *      Routine:        convert_thread_to_port
 1417  *      Purpose:
 1418  *              Convert from a thread to a port.
 1419  *              Consumes a thread ref; produces a naked send right
 1420  *              which may be invalid.
 1421  *      Conditions:
 1422  *              Nothing locked.
 1423  */
 1424 
 1425 ipc_port_t
 1426 convert_thread_to_port(thread)
 1427         thread_t thread;
 1428 {
 1429         ipc_port_t port;
 1430 
 1431         ith_lock(thread);
 1432         if (thread->ith_self != IP_NULL)
 1433                 port = ipc_port_make_send(thread->ith_self);
 1434         else
 1435                 port = IP_NULL;
 1436         ith_unlock(thread);
 1437 
 1438         thread_deallocate(thread);
 1439         return port;
 1440 }
 1441 
 1442 /*
 1443  *      Routine:        space_deallocate
 1444  *      Purpose:
 1445  *              Deallocate a space ref produced by convert_port_to_space.
 1446  *      Conditions:
 1447  *              Nothing locked.
 1448  */
 1449 
 1450 void
 1451 space_deallocate(space)
 1452         ipc_space_t space;
 1453 {
 1454         if (space != IS_NULL)
 1455                 is_release(space);
 1456 }

Cache object: 3890c2892acb5410cd8a2bf6c2a2435c


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