2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_LICENSE_OSREFERENCE_HEADER_START@
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the
10 * License may not be used to create, or enable the creation or
11 * redistribution of, unlawful or unlicensed copies of an Apple operating
12 * system, or to circumvent, violate, or enable the circumvention or
13 * violation of, any terms of an Apple operating system software license
16 * Please obtain a copy of the License at
17 * http://www.opensource.apple.com/apsl/ and read it before using this
20 * The Original Code and all software distributed under the License are
21 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
22 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
23 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
24 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
25 * Please see the License for the specific language governing rights and
26 * limitations under the License.
28 * @APPLE_LICENSE_OSREFERENCE_HEADER_END@
34 * Mach Operating System
35 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
36 * All Rights Reserved.
38 * Permission to use, copy, modify and distribute this software and its
39 * documentation is hereby granted, provided that both the copyright
40 * notice and this permission notice appear in all copies of the
41 * software, derivative works or modified versions, and any portions
42 * thereof, and that both notices appear in supporting documentation.
44 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
45 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
46 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
48 * Carnegie Mellon requests users of this software to return to
50 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
51 * School of Computer Science
52 * Carnegie Mellon University
53 * Pittsburgh PA 15213-3890
55 * any improvements or extensions that they make and grant Carnegie Mellon
56 * the rights to redistribute these changes.
64 * Task and thread related IPC functions.
67 #include <mach/mach_types.h>
68 #include <mach/boolean.h>
69 #include <mach/kern_return.h>
70 #include <mach/mach_param.h>
71 #include <mach/task_special_ports.h>
72 #include <mach/thread_special_ports.h>
73 #include <mach/thread_status.h>
74 #include <mach/exception_types.h>
75 #include <mach/memory_object_types.h>
76 #include <mach/mach_traps.h>
77 #include <mach/task_server.h>
78 #include <mach/thread_act_server.h>
79 #include <mach/mach_host_server.h>
80 #include <mach/host_priv_server.h>
81 #include <mach/vm_map_server.h>
83 #include <kern/kern_types.h>
84 #include <kern/host.h>
85 #include <kern/ipc_kobject.h>
86 #include <kern/ipc_tt.h>
87 #include <kern/kalloc.h>
88 #include <kern/thread.h>
89 #include <kern/misc_protos.h>
91 #include <vm/vm_map.h>
92 #include <vm/vm_pageout.h>
93 #include <vm/vm_shared_memory_server.h>
94 #include <vm/vm_protos.h>
96 /* forward declarations */
97 task_t
convert_port_to_locked_task(ipc_port_t port
);
101 * Routine: ipc_task_init
103 * Initialize a task's IPC state.
105 * If non-null, some state will be inherited from the parent.
106 * The parent must be appropriately initialized.
122 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
123 if (kr
!= KERN_SUCCESS
)
124 panic("ipc_task_init");
127 kport
= ipc_port_alloc_kernel();
128 if (kport
== IP_NULL
)
129 panic("ipc_task_init");
132 task
->itk_self
= kport
;
133 task
->itk_sself
= ipc_port_make_send(kport
);
134 task
->itk_space
= space
;
135 space
->is_fast
= FALSE
;
137 if (parent
== TASK_NULL
) {
140 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
141 task
->exc_actions
[i
].port
= IP_NULL
;
144 kr
= host_get_host_port(host_priv_self(), &port
);
145 assert(kr
== KERN_SUCCESS
);
146 task
->itk_host
= port
;
148 task
->itk_bootstrap
= IP_NULL
;
150 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
151 task
->itk_registered
[i
] = IP_NULL
;
154 assert(parent
->itk_self
!= IP_NULL
);
156 /* inherit registered ports */
158 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
159 task
->itk_registered
[i
] =
160 ipc_port_copy_send(parent
->itk_registered
[i
]);
162 /* inherit exception and bootstrap ports */
164 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
165 task
->exc_actions
[i
].port
=
166 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
167 task
->exc_actions
[i
].flavor
=
168 parent
->exc_actions
[i
].flavor
;
169 task
->exc_actions
[i
].behavior
=
170 parent
->exc_actions
[i
].behavior
;
171 task
->exc_actions
[i
].privileged
=
172 parent
->exc_actions
[i
].privileged
;
175 ipc_port_copy_send(parent
->itk_host
);
177 task
->itk_bootstrap
=
178 ipc_port_copy_send(parent
->itk_bootstrap
);
185 * Routine: ipc_task_enable
187 * Enable a task for IPC access.
199 kport
= task
->itk_self
;
200 if (kport
!= IP_NULL
)
201 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
206 * Routine: ipc_task_disable
208 * Disable IPC access to a task.
220 kport
= task
->itk_self
;
221 if (kport
!= IP_NULL
)
222 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
227 * Routine: ipc_task_terminate
229 * Clean up and destroy a task's IPC state.
231 * Nothing locked. The task must be suspended.
232 * (Or the current thread must be in the task.)
243 kport
= task
->itk_self
;
245 if (kport
== IP_NULL
) {
246 /* the task is already terminated (can this happen?) */
251 task
->itk_self
= IP_NULL
;
254 /* release the naked send rights */
256 if (IP_VALID(task
->itk_sself
))
257 ipc_port_release_send(task
->itk_sself
);
259 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
260 if (IP_VALID(task
->exc_actions
[i
].port
)) {
261 ipc_port_release_send(task
->exc_actions
[i
].port
);
265 if (IP_VALID(task
->itk_host
))
266 ipc_port_release_send(task
->itk_host
);
268 if (IP_VALID(task
->itk_bootstrap
))
269 ipc_port_release_send(task
->itk_bootstrap
);
271 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
272 if (IP_VALID(task
->itk_registered
[i
]))
273 ipc_port_release_send(task
->itk_registered
[i
]);
275 ipc_port_release_send(task
->wired_ledger_port
);
276 ipc_port_release_send(task
->paged_ledger_port
);
278 /* destroy the kernel port */
279 ipc_port_dealloc_kernel(kport
);
283 * Routine: ipc_task_reset
285 * Reset a task's IPC state to protect it when
286 * it enters an elevated security context.
288 * Nothing locked. The task must be suspended.
289 * (Or the current thread must be in the task.)
296 ipc_port_t old_kport
, new_kport
;
297 ipc_port_t old_sself
;
298 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
301 new_kport
= ipc_port_alloc_kernel();
302 if (new_kport
== IP_NULL
)
303 panic("ipc_task_reset");
307 old_kport
= task
->itk_self
;
309 if (old_kport
== IP_NULL
) {
310 /* the task is already terminated (can this happen?) */
312 ipc_port_dealloc_kernel(new_kport
);
316 task
->itk_self
= new_kport
;
317 old_sself
= task
->itk_sself
;
318 task
->itk_sself
= ipc_port_make_send(new_kport
);
319 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
320 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
322 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
323 if (!task
->exc_actions
[i
].privileged
) {
324 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
325 task
->exc_actions
[i
].port
= IP_NULL
;
327 old_exc_actions
[i
] = IP_NULL
;
333 /* release the naked send rights */
335 if (IP_VALID(old_sself
))
336 ipc_port_release_send(old_sself
);
338 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
339 if (IP_VALID(old_exc_actions
[i
])) {
340 ipc_port_release_send(old_exc_actions
[i
]);
344 /* destroy the kernel port */
345 ipc_port_dealloc_kernel(old_kport
);
349 * Routine: ipc_thread_init
351 * Initialize a thread's IPC state.
363 kport
= ipc_port_alloc_kernel();
364 if (kport
== IP_NULL
)
365 panic("ipc_thread_init");
367 thread
->ith_self
= kport
;
368 thread
->ith_sself
= ipc_port_make_send(kport
);
370 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
371 thread
->exc_actions
[i
].port
= IP_NULL
;
373 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
375 ipc_kmsg_queue_init(&thread
->ith_messages
);
377 thread
->ith_rpc_reply
= IP_NULL
;
384 ipc_port_t kport
= thread
->ith_self
;
386 if (kport
!= IP_NULL
)
387 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
391 * Routine: ipc_thread_terminate
393 * Clean up and destroy a thread's IPC state.
399 ipc_thread_terminate(
402 ipc_port_t kport
= thread
->ith_self
;
404 if (kport
!= IP_NULL
) {
407 if (IP_VALID(thread
->ith_sself
))
408 ipc_port_release_send(thread
->ith_sself
);
410 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
412 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
413 if (IP_VALID(thread
->exc_actions
[i
].port
))
414 ipc_port_release_send(thread
->exc_actions
[i
].port
);
417 ipc_port_dealloc_kernel(kport
);
420 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
422 if (thread
->ith_rpc_reply
!= IP_NULL
)
423 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
425 thread
->ith_rpc_reply
= IP_NULL
;
429 * Routine: retrieve_task_self_fast
431 * Optimized version of retrieve_task_self,
432 * that only works for the current task.
434 * Return a send right (possibly null/dead)
435 * for the task's user-visible self port.
441 retrieve_task_self_fast(
442 register task_t task
)
444 register ipc_port_t port
;
446 assert(task
== current_task());
449 assert(task
->itk_self
!= IP_NULL
);
451 if ((port
= task
->itk_sself
) == task
->itk_self
) {
455 assert(ip_active(port
));
460 port
= ipc_port_copy_send(port
);
467 * Routine: retrieve_thread_self_fast
469 * Return a send right (possibly null/dead)
470 * for the thread's user-visible self port.
472 * Only works for the current thread.
479 retrieve_thread_self_fast(
482 register ipc_port_t port
;
484 assert(thread
== current_thread());
486 thread_mtx_lock(thread
);
488 assert(thread
->ith_self
!= IP_NULL
);
490 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
494 assert(ip_active(port
));
500 port
= ipc_port_copy_send(port
);
502 thread_mtx_unlock(thread
);
508 * Routine: task_self_trap [mach trap]
510 * Give the caller send rights for his own task port.
514 * MACH_PORT_NULL if there are any resource failures
520 __unused
struct task_self_trap_args
*args
)
522 task_t task
= current_task();
524 mach_port_name_t name
;
526 sright
= retrieve_task_self_fast(task
);
527 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
532 * Routine: thread_self_trap [mach trap]
534 * Give the caller send rights for his own thread port.
538 * MACH_PORT_NULL if there are any resource failures
544 __unused
struct thread_self_trap_args
*args
)
546 thread_t thread
= current_thread();
547 task_t task
= thread
->task
;
549 mach_port_name_t name
;
551 sright
= retrieve_thread_self_fast(thread
);
552 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
558 * Routine: mach_reply_port [mach trap]
560 * Allocate a port for the caller.
564 * MACH_PORT_NULL if there are any resource failures
570 __unused
struct mach_reply_port_args
*args
)
573 mach_port_name_t name
;
576 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
577 if (kr
== KERN_SUCCESS
)
580 name
= MACH_PORT_NULL
;
585 * Routine: thread_get_special_port [kernel call]
587 * Clones a send right for one of the thread's
592 * KERN_SUCCESS Extracted a send right.
593 * KERN_INVALID_ARGUMENT The thread is null.
594 * KERN_FAILURE The thread is dead.
595 * KERN_INVALID_ARGUMENT Invalid special port.
599 thread_get_special_port(
604 kern_return_t result
= KERN_SUCCESS
;
607 if (thread
== THREAD_NULL
)
608 return (KERN_INVALID_ARGUMENT
);
612 case THREAD_KERNEL_PORT
:
613 whichp
= &thread
->ith_sself
;
617 return (KERN_INVALID_ARGUMENT
);
620 thread_mtx_lock(thread
);
623 *portp
= ipc_port_copy_send(*whichp
);
625 result
= KERN_FAILURE
;
627 thread_mtx_unlock(thread
);
633 * Routine: thread_set_special_port [kernel call]
635 * Changes one of the thread's special ports,
636 * setting it to the supplied send right.
638 * Nothing locked. If successful, consumes
639 * the supplied send right.
641 * KERN_SUCCESS Changed the special port.
642 * KERN_INVALID_ARGUMENT The thread is null.
643 * KERN_FAILURE The thread is dead.
644 * KERN_INVALID_ARGUMENT Invalid special port.
648 thread_set_special_port(
653 kern_return_t result
= KERN_SUCCESS
;
654 ipc_port_t
*whichp
, old
= IP_NULL
;
656 if (thread
== THREAD_NULL
)
657 return (KERN_INVALID_ARGUMENT
);
661 case THREAD_KERNEL_PORT
:
662 whichp
= &thread
->ith_sself
;
666 return (KERN_INVALID_ARGUMENT
);
669 thread_mtx_lock(thread
);
671 if (thread
->active
) {
676 result
= KERN_FAILURE
;
678 thread_mtx_unlock(thread
);
681 ipc_port_release_send(old
);
687 * Routine: task_get_special_port [kernel call]
689 * Clones a send right for one of the task's
694 * KERN_SUCCESS Extracted a send right.
695 * KERN_INVALID_ARGUMENT The task is null.
696 * KERN_FAILURE The task/space is dead.
697 * KERN_INVALID_ARGUMENT Invalid special port.
701 task_get_special_port(
709 if (task
== TASK_NULL
)
710 return KERN_INVALID_ARGUMENT
;
713 case TASK_KERNEL_PORT
:
714 whichp
= &task
->itk_sself
;
718 whichp
= &task
->itk_host
;
721 case TASK_BOOTSTRAP_PORT
:
722 whichp
= &task
->itk_bootstrap
;
725 case TASK_WIRED_LEDGER_PORT
:
726 whichp
= &task
->wired_ledger_port
;
729 case TASK_PAGED_LEDGER_PORT
:
730 whichp
= &task
->paged_ledger_port
;
734 return KERN_INVALID_ARGUMENT
;
738 if (task
->itk_self
== IP_NULL
) {
743 port
= ipc_port_copy_send(*whichp
);
751 * Routine: task_set_special_port [kernel call]
753 * Changes one of the task's special ports,
754 * setting it to the supplied send right.
756 * Nothing locked. If successful, consumes
757 * the supplied send right.
759 * KERN_SUCCESS Changed the special port.
760 * KERN_INVALID_ARGUMENT The task is null.
761 * KERN_FAILURE The task/space is dead.
762 * KERN_INVALID_ARGUMENT Invalid special port.
766 task_set_special_port(
774 if (task
== TASK_NULL
)
775 return KERN_INVALID_ARGUMENT
;
778 case TASK_KERNEL_PORT
:
779 whichp
= &task
->itk_sself
;
783 whichp
= &task
->itk_host
;
786 case TASK_BOOTSTRAP_PORT
:
787 whichp
= &task
->itk_bootstrap
;
790 case TASK_WIRED_LEDGER_PORT
:
791 whichp
= &task
->wired_ledger_port
;
794 case TASK_PAGED_LEDGER_PORT
:
795 whichp
= &task
->paged_ledger_port
;
799 return KERN_INVALID_ARGUMENT
;
803 if (task
->itk_self
== IP_NULL
) {
813 ipc_port_release_send(old
);
819 * Routine: mach_ports_register [kernel call]
821 * Stash a handful of port send rights in the task.
822 * Child tasks will inherit these rights, but they
823 * must use mach_ports_lookup to acquire them.
825 * The rights are supplied in a (wired) kalloc'd segment.
826 * Rights which aren't supplied are assumed to be null.
828 * Nothing locked. If successful, consumes
829 * the supplied rights and memory.
831 * KERN_SUCCESS Stashed the port rights.
832 * KERN_INVALID_ARGUMENT The task is null.
833 * KERN_INVALID_ARGUMENT The task is dead.
834 * KERN_INVALID_ARGUMENT Too many port rights supplied.
840 mach_port_array_t memory
,
841 mach_msg_type_number_t portsCnt
)
843 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
846 if ((task
== TASK_NULL
) ||
847 (portsCnt
> TASK_PORT_REGISTER_MAX
))
848 return KERN_INVALID_ARGUMENT
;
851 * Pad the port rights with nulls.
854 for (i
= 0; i
< portsCnt
; i
++)
855 ports
[i
] = memory
[i
];
856 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
860 if (task
->itk_self
== IP_NULL
) {
862 return KERN_INVALID_ARGUMENT
;
866 * Replace the old send rights with the new.
867 * Release the old rights after unlocking.
870 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
873 old
= task
->itk_registered
[i
];
874 task
->itk_registered
[i
] = ports
[i
];
880 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
881 if (IP_VALID(ports
[i
]))
882 ipc_port_release_send(ports
[i
]);
885 * Now that the operation is known to be successful,
886 * we can free the memory.
891 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
897 * Routine: mach_ports_lookup [kernel call]
899 * Retrieves (clones) the stashed port send rights.
901 * Nothing locked. If successful, the caller gets
904 * KERN_SUCCESS Retrieved the send rights.
905 * KERN_INVALID_ARGUMENT The task is null.
906 * KERN_INVALID_ARGUMENT The task is dead.
907 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
913 mach_port_array_t
*portsp
,
914 mach_msg_type_number_t
*portsCnt
)
921 if (task
== TASK_NULL
)
922 return KERN_INVALID_ARGUMENT
;
924 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
926 memory
= kalloc(size
);
928 return KERN_RESOURCE_SHORTAGE
;
931 if (task
->itk_self
== IP_NULL
) {
935 return KERN_INVALID_ARGUMENT
;
938 ports
= (ipc_port_t
*) memory
;
941 * Clone port rights. Because kalloc'd memory
942 * is wired, we won't fault while holding the task lock.
945 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
946 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
950 *portsp
= (mach_port_array_t
) ports
;
951 *portsCnt
= TASK_PORT_REGISTER_MAX
;
956 * Routine: convert_port_to_locked_task
958 * Internal helper routine to convert from a port to a locked
959 * task. Used by several routines that try to convert from a
960 * task port to a reference on some task related object.
962 * Nothing locked, blocking OK.
965 convert_port_to_locked_task(ipc_port_t port
)
967 while (IP_VALID(port
)) {
971 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
975 task
= (task_t
) port
->ip_kobject
;
976 assert(task
!= TASK_NULL
);
979 * Normal lock ordering puts task_lock() before ip_lock().
980 * Attempt out-of-order locking here.
982 if (task_lock_try(task
)) {
994 * Routine: convert_port_to_task
996 * Convert from a port to a task.
997 * Doesn't consume the port ref; produces a task ref,
1003 convert_port_to_task(
1006 task_t task
= TASK_NULL
;
1008 if (IP_VALID(port
)) {
1011 if ( ip_active(port
) &&
1012 ip_kotype(port
) == IKOT_TASK
) {
1013 task
= (task_t
)port
->ip_kobject
;
1014 assert(task
!= TASK_NULL
);
1016 task_reference_internal(task
);
1026 * Routine: convert_port_to_space
1028 * Convert from a port to a space.
1029 * Doesn't consume the port ref; produces a space ref,
1030 * which may be null.
1035 convert_port_to_space(
1041 task
= convert_port_to_locked_task(port
);
1043 if (task
== TASK_NULL
)
1044 return IPC_SPACE_NULL
;
1046 if (!task
->active
) {
1048 return IPC_SPACE_NULL
;
1051 space
= task
->itk_space
;
1052 is_reference(space
);
1058 * Routine: convert_port_to_map
1060 * Convert from a port to a map.
1061 * Doesn't consume the port ref; produces a map ref,
1062 * which may be null.
1068 convert_port_to_map(
1074 task
= convert_port_to_locked_task(port
);
1076 if (task
== TASK_NULL
)
1079 if (!task
->active
) {
1085 vm_map_reference_swap(map
);
1092 * Routine: convert_port_to_thread
1094 * Convert from a port to a thread.
1095 * Doesn't consume the port ref; produces an thread ref,
1096 * which may be null.
1102 convert_port_to_thread(
1105 thread_t thread
= THREAD_NULL
;
1107 if (IP_VALID(port
)) {
1110 if ( ip_active(port
) &&
1111 ip_kotype(port
) == IKOT_THREAD
) {
1112 thread
= (thread_t
)port
->ip_kobject
;
1113 assert(thread
!= THREAD_NULL
);
1115 thread_reference_internal(thread
);
1125 * Routine: port_name_to_thread
1127 * Convert from a port name to an thread reference
1128 * A name of MACH_PORT_NULL is valid for the null thread.
1133 port_name_to_thread(
1134 mach_port_name_t name
)
1136 thread_t thread
= THREAD_NULL
;
1139 if (MACH_PORT_VALID(name
)) {
1140 if (ipc_object_copyin(current_space(), name
,
1141 MACH_MSG_TYPE_COPY_SEND
,
1142 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1143 return (THREAD_NULL
);
1145 thread
= convert_port_to_thread(kport
);
1147 if (IP_VALID(kport
))
1148 ipc_port_release_send(kport
);
1156 mach_port_name_t name
)
1158 ipc_port_t kern_port
;
1160 task_t task
= TASK_NULL
;
1162 if (MACH_PORT_VALID(name
)) {
1163 kr
= ipc_object_copyin(current_space(), name
,
1164 MACH_MSG_TYPE_COPY_SEND
,
1165 (ipc_object_t
*) &kern_port
);
1166 if (kr
!= KERN_SUCCESS
)
1169 task
= convert_port_to_task(kern_port
);
1171 if (IP_VALID(kern_port
))
1172 ipc_port_release_send(kern_port
);
1178 * Routine: convert_task_to_port
1180 * Convert from a task to a port.
1181 * Consumes a task ref; produces a naked send right
1182 * which may be invalid.
1188 convert_task_to_port(
1194 if (task
->itk_self
!= IP_NULL
)
1195 port
= ipc_port_make_send(task
->itk_self
);
1200 task_deallocate(task
);
1205 * Routine: convert_thread_to_port
1207 * Convert from a thread to a port.
1208 * Consumes an thread ref; produces a naked send right
1209 * which may be invalid.
1215 convert_thread_to_port(
1220 thread_mtx_lock(thread
);
1222 if (thread
->ith_self
!= IP_NULL
)
1223 port
= ipc_port_make_send(thread
->ith_self
);
1227 thread_mtx_unlock(thread
);
1229 thread_deallocate(thread
);
1235 * Routine: space_deallocate
1237 * Deallocate a space ref produced by convert_port_to_space.
1246 if (space
!= IS_NULL
)
1251 * Routine: thread/task_set_exception_ports [kernel call]
1253 * Sets the thread/task exception port, flavor and
1254 * behavior for the exception types specified by the mask.
1255 * There will be one send right per exception per valid
1258 * Nothing locked. If successful, consumes
1259 * the supplied send right.
1261 * KERN_SUCCESS Changed the special port.
1262 * KERN_INVALID_ARGUMENT The thread is null,
1263 * Illegal mask bit set.
1264 * Illegal exception behavior
1265 * KERN_FAILURE The thread is dead.
1269 thread_set_exception_ports(
1271 exception_mask_t exception_mask
,
1272 ipc_port_t new_port
,
1273 exception_behavior_t new_behavior
,
1274 thread_state_flavor_t new_flavor
)
1276 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1279 if (thread
== THREAD_NULL
)
1280 return (KERN_INVALID_ARGUMENT
);
1282 if (exception_mask
& ~EXC_MASK_ALL
)
1283 return (KERN_INVALID_ARGUMENT
);
1285 if (IP_VALID(new_port
)) {
1286 switch (new_behavior
) {
1288 case EXCEPTION_DEFAULT
:
1289 case EXCEPTION_STATE
:
1290 case EXCEPTION_STATE_IDENTITY
:
1294 return (KERN_INVALID_ARGUMENT
);
1299 * Check the validity of the thread_state_flavor by calling the
1300 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1301 * osfmk/mach/ARCHITECTURE/thread_status.h
1303 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1304 return (KERN_INVALID_ARGUMENT
);
1306 thread_mtx_lock(thread
);
1308 if (!thread
->active
) {
1309 thread_mtx_unlock(thread
);
1311 return (KERN_FAILURE
);
1314 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1315 if (exception_mask
& (1 << i
)) {
1316 old_port
[i
] = thread
->exc_actions
[i
].port
;
1317 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1318 thread
->exc_actions
[i
].behavior
= new_behavior
;
1319 thread
->exc_actions
[i
].flavor
= new_flavor
;
1322 old_port
[i
] = IP_NULL
;
1325 thread_mtx_unlock(thread
);
1327 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1328 if (IP_VALID(old_port
[i
]))
1329 ipc_port_release_send(old_port
[i
]);
1331 if (IP_VALID(new_port
)) /* consume send right */
1332 ipc_port_release_send(new_port
);
1334 return (KERN_SUCCESS
);
1338 task_set_exception_ports(
1340 exception_mask_t exception_mask
,
1341 ipc_port_t new_port
,
1342 exception_behavior_t new_behavior
,
1343 thread_state_flavor_t new_flavor
)
1345 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1346 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1349 if (task
== TASK_NULL
)
1350 return (KERN_INVALID_ARGUMENT
);
1352 if (exception_mask
& ~EXC_MASK_ALL
)
1353 return (KERN_INVALID_ARGUMENT
);
1355 if (IP_VALID(new_port
)) {
1356 switch (new_behavior
) {
1358 case EXCEPTION_DEFAULT
:
1359 case EXCEPTION_STATE
:
1360 case EXCEPTION_STATE_IDENTITY
:
1364 return (KERN_INVALID_ARGUMENT
);
1370 if (task
->itk_self
== IP_NULL
) {
1373 return (KERN_FAILURE
);
1376 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1377 if (exception_mask
& (1 << i
)) {
1378 old_port
[i
] = task
->exc_actions
[i
].port
;
1379 task
->exc_actions
[i
].port
=
1380 ipc_port_copy_send(new_port
);
1381 task
->exc_actions
[i
].behavior
= new_behavior
;
1382 task
->exc_actions
[i
].flavor
= new_flavor
;
1383 task
->exc_actions
[i
].privileged
= privileged
;
1386 old_port
[i
] = IP_NULL
;
1391 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1392 if (IP_VALID(old_port
[i
]))
1393 ipc_port_release_send(old_port
[i
]);
1395 if (IP_VALID(new_port
)) /* consume send right */
1396 ipc_port_release_send(new_port
);
1398 return (KERN_SUCCESS
);
1402 * Routine: thread/task_swap_exception_ports [kernel call]
1404 * Sets the thread/task exception port, flavor and
1405 * behavior for the exception types specified by the
1408 * The old ports, behavior and flavors are returned
1409 * Count specifies the array sizes on input and
1410 * the number of returned ports etc. on output. The
1411 * arrays must be large enough to hold all the returned
1412 * data, MIG returnes an error otherwise. The masks
1413 * array specifies the corresponding exception type(s).
1416 * Nothing locked. If successful, consumes
1417 * the supplied send right.
1419 * Returns upto [in} CountCnt elements.
1421 * KERN_SUCCESS Changed the special port.
1422 * KERN_INVALID_ARGUMENT The thread is null,
1423 * Illegal mask bit set.
1424 * Illegal exception behavior
1425 * KERN_FAILURE The thread is dead.
1429 thread_swap_exception_ports(
1431 exception_mask_t exception_mask
,
1432 ipc_port_t new_port
,
1433 exception_behavior_t new_behavior
,
1434 thread_state_flavor_t new_flavor
,
1435 exception_mask_array_t masks
,
1436 mach_msg_type_number_t
*CountCnt
,
1437 exception_port_array_t ports
,
1438 exception_behavior_array_t behaviors
,
1439 thread_state_flavor_array_t flavors
)
1441 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1442 unsigned int i
, j
, count
;
1444 if (thread
== THREAD_NULL
)
1445 return (KERN_INVALID_ARGUMENT
);
1447 if (exception_mask
& ~EXC_MASK_ALL
)
1448 return (KERN_INVALID_ARGUMENT
);
1450 if (IP_VALID(new_port
)) {
1451 switch (new_behavior
) {
1453 case EXCEPTION_DEFAULT
:
1454 case EXCEPTION_STATE
:
1455 case EXCEPTION_STATE_IDENTITY
:
1459 return (KERN_INVALID_ARGUMENT
);
1463 thread_mtx_lock(thread
);
1465 if (!thread
->active
) {
1466 thread_mtx_unlock(thread
);
1468 return (KERN_FAILURE
);
1473 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1474 if (exception_mask
& (1 << i
)) {
1475 for (j
= 0; j
< count
; ++j
) {
1477 * search for an identical entry, if found
1478 * set corresponding mask for this exception.
1480 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1481 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1482 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1483 masks
[j
] |= (1 << i
);
1489 masks
[j
] = (1 << i
);
1490 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1492 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1493 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1497 old_port
[i
] = thread
->exc_actions
[i
].port
;
1498 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1499 thread
->exc_actions
[i
].behavior
= new_behavior
;
1500 thread
->exc_actions
[i
].flavor
= new_flavor
;
1501 if (count
> *CountCnt
)
1505 old_port
[i
] = IP_NULL
;
1508 thread_mtx_unlock(thread
);
1510 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1511 if (IP_VALID(old_port
[i
]))
1512 ipc_port_release_send(old_port
[i
]);
1514 if (IP_VALID(new_port
)) /* consume send right */
1515 ipc_port_release_send(new_port
);
1519 return (KERN_SUCCESS
);
1523 task_swap_exception_ports(
1525 exception_mask_t exception_mask
,
1526 ipc_port_t new_port
,
1527 exception_behavior_t new_behavior
,
1528 thread_state_flavor_t new_flavor
,
1529 exception_mask_array_t masks
,
1530 mach_msg_type_number_t
*CountCnt
,
1531 exception_port_array_t ports
,
1532 exception_behavior_array_t behaviors
,
1533 thread_state_flavor_array_t flavors
)
1535 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1536 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1537 unsigned int i
, j
, count
;
1539 if (task
== TASK_NULL
)
1540 return (KERN_INVALID_ARGUMENT
);
1542 if (exception_mask
& ~EXC_MASK_ALL
)
1543 return (KERN_INVALID_ARGUMENT
);
1545 if (IP_VALID(new_port
)) {
1546 switch (new_behavior
) {
1548 case EXCEPTION_DEFAULT
:
1549 case EXCEPTION_STATE
:
1550 case EXCEPTION_STATE_IDENTITY
:
1554 return (KERN_INVALID_ARGUMENT
);
1560 if (task
->itk_self
== IP_NULL
) {
1563 return (KERN_FAILURE
);
1568 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1569 if (exception_mask
& (1 << i
)) {
1570 for (j
= 0; j
< count
; j
++) {
1572 * search for an identical entry, if found
1573 * set corresponding mask for this exception.
1575 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1576 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1577 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1578 masks
[j
] |= (1 << i
);
1584 masks
[j
] = (1 << i
);
1585 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1586 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1587 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1591 old_port
[i
] = task
->exc_actions
[i
].port
;
1592 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1593 task
->exc_actions
[i
].behavior
= new_behavior
;
1594 task
->exc_actions
[i
].flavor
= new_flavor
;
1595 task
->exc_actions
[i
].privileged
= privileged
;
1596 if (count
> *CountCnt
)
1600 old_port
[i
] = IP_NULL
;
1605 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1606 if (IP_VALID(old_port
[i
]))
1607 ipc_port_release_send(old_port
[i
]);
1609 if (IP_VALID(new_port
)) /* consume send right */
1610 ipc_port_release_send(new_port
);
1614 return (KERN_SUCCESS
);
1618 * Routine: thread/task_get_exception_ports [kernel call]
1620 * Clones a send right for each of the thread/task's exception
1621 * ports specified in the mask and returns the behaviour
1622 * and flavor of said port.
1624 * Returns upto [in} CountCnt elements.
1629 * KERN_SUCCESS Extracted a send right.
1630 * KERN_INVALID_ARGUMENT The thread is null,
1631 * Invalid special port,
1632 * Illegal mask bit set.
1633 * KERN_FAILURE The thread is dead.
1637 thread_get_exception_ports(
1639 exception_mask_t exception_mask
,
1640 exception_mask_array_t masks
,
1641 mach_msg_type_number_t
*CountCnt
,
1642 exception_port_array_t ports
,
1643 exception_behavior_array_t behaviors
,
1644 thread_state_flavor_array_t flavors
)
1646 unsigned int i
, j
, count
;
1648 if (thread
== THREAD_NULL
)
1649 return (KERN_INVALID_ARGUMENT
);
1651 if (exception_mask
& ~EXC_MASK_ALL
)
1652 return (KERN_INVALID_ARGUMENT
);
1654 thread_mtx_lock(thread
);
1656 if (!thread
->active
) {
1657 thread_mtx_unlock(thread
);
1659 return (KERN_FAILURE
);
1664 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1665 if (exception_mask
& (1 << i
)) {
1666 for (j
= 0; j
< count
; ++j
) {
1668 * search for an identical entry, if found
1669 * set corresponding mask for this exception.
1671 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1672 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1673 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1674 masks
[j
] |= (1 << i
);
1680 masks
[j
] = (1 << i
);
1681 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1682 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1683 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1685 if (count
>= *CountCnt
)
1691 thread_mtx_unlock(thread
);
1695 return (KERN_SUCCESS
);
1699 task_get_exception_ports(
1701 exception_mask_t exception_mask
,
1702 exception_mask_array_t masks
,
1703 mach_msg_type_number_t
*CountCnt
,
1704 exception_port_array_t ports
,
1705 exception_behavior_array_t behaviors
,
1706 thread_state_flavor_array_t flavors
)
1708 unsigned int i
, j
, count
;
1710 if (task
== TASK_NULL
)
1711 return (KERN_INVALID_ARGUMENT
);
1713 if (exception_mask
& ~EXC_MASK_ALL
)
1714 return (KERN_INVALID_ARGUMENT
);
1718 if (task
->itk_self
== IP_NULL
) {
1721 return (KERN_FAILURE
);
1726 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1727 if (exception_mask
& (1 << i
)) {
1728 for (j
= 0; j
< count
; ++j
) {
1730 * search for an identical entry, if found
1731 * set corresponding mask for this exception.
1733 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1734 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1735 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1736 masks
[j
] |= (1 << i
);
1742 masks
[j
] = (1 << i
);
1743 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1744 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1745 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1747 if (count
> *CountCnt
)
1757 return (KERN_SUCCESS
);