2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_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 License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
46 * Carnegie Mellon requests users of this software to return to
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
62 * Task and thread related IPC functions.
65 #include <mach/mach_types.h>
66 #include <mach/boolean.h>
67 #include <mach/kern_return.h>
68 #include <mach/mach_param.h>
69 #include <mach/task_special_ports.h>
70 #include <mach/thread_special_ports.h>
71 #include <mach/thread_status.h>
72 #include <mach/exception_types.h>
73 #include <mach/memory_object_types.h>
74 #include <mach/mach_traps.h>
75 #include <mach/task_server.h>
76 #include <mach/thread_act_server.h>
77 #include <mach/mach_host_server.h>
78 #include <mach/host_priv_server.h>
79 #include <mach/vm_map_server.h>
81 #include <kern/kern_types.h>
82 #include <kern/host.h>
83 #include <kern/ipc_kobject.h>
84 #include <kern/ipc_tt.h>
85 #include <kern/kalloc.h>
86 #include <kern/thread.h>
87 #include <kern/misc_protos.h>
89 #include <vm/vm_map.h>
90 #include <vm/vm_pageout.h>
91 #include <vm/vm_shared_memory_server.h>
92 #include <vm/vm_protos.h>
94 /* forward declarations */
95 task_t
convert_port_to_locked_task(ipc_port_t port
);
99 * Routine: ipc_task_init
101 * Initialize a task's IPC state.
103 * If non-null, some state will be inherited from the parent.
104 * The parent must be appropriately initialized.
120 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
121 if (kr
!= KERN_SUCCESS
)
122 panic("ipc_task_init");
125 kport
= ipc_port_alloc_kernel();
126 if (kport
== IP_NULL
)
127 panic("ipc_task_init");
130 task
->itk_self
= kport
;
131 task
->itk_sself
= ipc_port_make_send(kport
);
132 task
->itk_space
= space
;
133 space
->is_fast
= FALSE
;
135 if (parent
== TASK_NULL
) {
138 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
139 task
->exc_actions
[i
].port
= IP_NULL
;
142 kr
= host_get_host_port(host_priv_self(), &port
);
143 assert(kr
== KERN_SUCCESS
);
144 task
->itk_host
= port
;
146 task
->itk_bootstrap
= IP_NULL
;
148 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
149 task
->itk_registered
[i
] = IP_NULL
;
152 assert(parent
->itk_self
!= IP_NULL
);
154 /* inherit registered ports */
156 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
157 task
->itk_registered
[i
] =
158 ipc_port_copy_send(parent
->itk_registered
[i
]);
160 /* inherit exception and bootstrap ports */
162 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
163 task
->exc_actions
[i
].port
=
164 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
165 task
->exc_actions
[i
].flavor
=
166 parent
->exc_actions
[i
].flavor
;
167 task
->exc_actions
[i
].behavior
=
168 parent
->exc_actions
[i
].behavior
;
169 task
->exc_actions
[i
].privileged
=
170 parent
->exc_actions
[i
].privileged
;
173 ipc_port_copy_send(parent
->itk_host
);
175 task
->itk_bootstrap
=
176 ipc_port_copy_send(parent
->itk_bootstrap
);
183 * Routine: ipc_task_enable
185 * Enable a task for IPC access.
197 kport
= task
->itk_self
;
198 if (kport
!= IP_NULL
)
199 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
204 * Routine: ipc_task_disable
206 * Disable IPC access to a task.
218 kport
= task
->itk_self
;
219 if (kport
!= IP_NULL
)
220 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
225 * Routine: ipc_task_terminate
227 * Clean up and destroy a task's IPC state.
229 * Nothing locked. The task must be suspended.
230 * (Or the current thread must be in the task.)
241 kport
= task
->itk_self
;
243 if (kport
== IP_NULL
) {
244 /* the task is already terminated (can this happen?) */
249 task
->itk_self
= IP_NULL
;
252 /* release the naked send rights */
254 if (IP_VALID(task
->itk_sself
))
255 ipc_port_release_send(task
->itk_sself
);
257 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
258 if (IP_VALID(task
->exc_actions
[i
].port
)) {
259 ipc_port_release_send(task
->exc_actions
[i
].port
);
263 if (IP_VALID(task
->itk_host
))
264 ipc_port_release_send(task
->itk_host
);
266 if (IP_VALID(task
->itk_bootstrap
))
267 ipc_port_release_send(task
->itk_bootstrap
);
269 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
270 if (IP_VALID(task
->itk_registered
[i
]))
271 ipc_port_release_send(task
->itk_registered
[i
]);
273 ipc_port_release_send(task
->wired_ledger_port
);
274 ipc_port_release_send(task
->paged_ledger_port
);
276 /* destroy the kernel port */
277 ipc_port_dealloc_kernel(kport
);
281 * Routine: ipc_task_reset
283 * Reset a task's IPC state to protect it when
284 * it enters an elevated security context.
286 * Nothing locked. The task must be suspended.
287 * (Or the current thread must be in the task.)
294 ipc_port_t old_kport
, new_kport
;
295 ipc_port_t old_sself
;
296 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
299 new_kport
= ipc_port_alloc_kernel();
300 if (new_kport
== IP_NULL
)
301 panic("ipc_task_reset");
305 old_kport
= task
->itk_self
;
307 if (old_kport
== IP_NULL
) {
308 /* the task is already terminated (can this happen?) */
310 ipc_port_dealloc_kernel(new_kport
);
314 task
->itk_self
= new_kport
;
315 old_sself
= task
->itk_sself
;
316 task
->itk_sself
= ipc_port_make_send(new_kport
);
317 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
318 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
320 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
321 if (!task
->exc_actions
[i
].privileged
) {
322 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
323 task
->exc_actions
[i
].port
= IP_NULL
;
325 old_exc_actions
[i
] = IP_NULL
;
331 /* release the naked send rights */
333 if (IP_VALID(old_sself
))
334 ipc_port_release_send(old_sself
);
336 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
337 if (IP_VALID(old_exc_actions
[i
])) {
338 ipc_port_release_send(old_exc_actions
[i
]);
342 /* destroy the kernel port */
343 ipc_port_dealloc_kernel(old_kport
);
347 * Routine: ipc_thread_init
349 * Initialize a thread's IPC state.
361 kport
= ipc_port_alloc_kernel();
362 if (kport
== IP_NULL
)
363 panic("ipc_thread_init");
365 thread
->ith_self
= kport
;
366 thread
->ith_sself
= ipc_port_make_send(kport
);
368 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
369 thread
->exc_actions
[i
].port
= IP_NULL
;
371 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
373 ipc_kmsg_queue_init(&thread
->ith_messages
);
375 thread
->ith_rpc_reply
= IP_NULL
;
382 ipc_port_t kport
= thread
->ith_self
;
384 if (kport
!= IP_NULL
)
385 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
389 * Routine: ipc_thread_terminate
391 * Clean up and destroy a thread's IPC state.
397 ipc_thread_terminate(
400 ipc_port_t kport
= thread
->ith_self
;
402 if (kport
!= IP_NULL
) {
405 if (IP_VALID(thread
->ith_sself
))
406 ipc_port_release_send(thread
->ith_sself
);
408 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
410 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
411 if (IP_VALID(thread
->exc_actions
[i
].port
))
412 ipc_port_release_send(thread
->exc_actions
[i
].port
);
415 ipc_port_dealloc_kernel(kport
);
418 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
420 if (thread
->ith_rpc_reply
!= IP_NULL
)
421 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
423 thread
->ith_rpc_reply
= IP_NULL
;
427 * Routine: retrieve_task_self_fast
429 * Optimized version of retrieve_task_self,
430 * that only works for the current task.
432 * Return a send right (possibly null/dead)
433 * for the task's user-visible self port.
439 retrieve_task_self_fast(
440 register task_t task
)
442 register ipc_port_t port
;
444 assert(task
== current_task());
447 assert(task
->itk_self
!= IP_NULL
);
449 if ((port
= task
->itk_sself
) == task
->itk_self
) {
453 assert(ip_active(port
));
458 port
= ipc_port_copy_send(port
);
465 * Routine: retrieve_thread_self_fast
467 * Return a send right (possibly null/dead)
468 * for the thread's user-visible self port.
470 * Only works for the current thread.
477 retrieve_thread_self_fast(
480 register ipc_port_t port
;
482 assert(thread
== current_thread());
484 thread_mtx_lock(thread
);
486 assert(thread
->ith_self
!= IP_NULL
);
488 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
492 assert(ip_active(port
));
498 port
= ipc_port_copy_send(port
);
500 thread_mtx_unlock(thread
);
506 * Routine: task_self_trap [mach trap]
508 * Give the caller send rights for his own task port.
512 * MACH_PORT_NULL if there are any resource failures
518 __unused
struct task_self_trap_args
*args
)
520 task_t task
= current_task();
522 mach_port_name_t name
;
524 sright
= retrieve_task_self_fast(task
);
525 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
530 * Routine: thread_self_trap [mach trap]
532 * Give the caller send rights for his own thread port.
536 * MACH_PORT_NULL if there are any resource failures
542 __unused
struct thread_self_trap_args
*args
)
544 thread_t thread
= current_thread();
545 task_t task
= thread
->task
;
547 mach_port_name_t name
;
549 sright
= retrieve_thread_self_fast(thread
);
550 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
556 * Routine: mach_reply_port [mach trap]
558 * Allocate a port for the caller.
562 * MACH_PORT_NULL if there are any resource failures
568 __unused
struct mach_reply_port_args
*args
)
571 mach_port_name_t name
;
574 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
575 if (kr
== KERN_SUCCESS
)
578 name
= MACH_PORT_NULL
;
583 * Routine: thread_get_special_port [kernel call]
585 * Clones a send right for one of the thread's
590 * KERN_SUCCESS Extracted a send right.
591 * KERN_INVALID_ARGUMENT The thread is null.
592 * KERN_FAILURE The thread is dead.
593 * KERN_INVALID_ARGUMENT Invalid special port.
597 thread_get_special_port(
602 kern_return_t result
= KERN_SUCCESS
;
605 if (thread
== THREAD_NULL
)
606 return (KERN_INVALID_ARGUMENT
);
610 case THREAD_KERNEL_PORT
:
611 whichp
= &thread
->ith_sself
;
615 return (KERN_INVALID_ARGUMENT
);
618 thread_mtx_lock(thread
);
621 *portp
= ipc_port_copy_send(*whichp
);
623 result
= KERN_FAILURE
;
625 thread_mtx_unlock(thread
);
631 * Routine: thread_set_special_port [kernel call]
633 * Changes one of the thread's special ports,
634 * setting it to the supplied send right.
636 * Nothing locked. If successful, consumes
637 * the supplied send right.
639 * KERN_SUCCESS Changed the special port.
640 * KERN_INVALID_ARGUMENT The thread is null.
641 * KERN_FAILURE The thread is dead.
642 * KERN_INVALID_ARGUMENT Invalid special port.
646 thread_set_special_port(
651 kern_return_t result
= KERN_SUCCESS
;
652 ipc_port_t
*whichp
, old
= IP_NULL
;
654 if (thread
== THREAD_NULL
)
655 return (KERN_INVALID_ARGUMENT
);
659 case THREAD_KERNEL_PORT
:
660 whichp
= &thread
->ith_sself
;
664 return (KERN_INVALID_ARGUMENT
);
667 thread_mtx_lock(thread
);
669 if (thread
->active
) {
674 result
= KERN_FAILURE
;
676 thread_mtx_unlock(thread
);
679 ipc_port_release_send(old
);
685 * Routine: task_get_special_port [kernel call]
687 * Clones a send right for one of the task's
692 * KERN_SUCCESS Extracted a send right.
693 * KERN_INVALID_ARGUMENT The task is null.
694 * KERN_FAILURE The task/space is dead.
695 * KERN_INVALID_ARGUMENT Invalid special port.
699 task_get_special_port(
707 if (task
== TASK_NULL
)
708 return KERN_INVALID_ARGUMENT
;
711 case TASK_KERNEL_PORT
:
712 whichp
= &task
->itk_sself
;
716 whichp
= &task
->itk_host
;
719 case TASK_BOOTSTRAP_PORT
:
720 whichp
= &task
->itk_bootstrap
;
723 case TASK_WIRED_LEDGER_PORT
:
724 whichp
= &task
->wired_ledger_port
;
727 case TASK_PAGED_LEDGER_PORT
:
728 whichp
= &task
->paged_ledger_port
;
732 return KERN_INVALID_ARGUMENT
;
736 if (task
->itk_self
== IP_NULL
) {
741 port
= ipc_port_copy_send(*whichp
);
749 * Routine: task_set_special_port [kernel call]
751 * Changes one of the task's special ports,
752 * setting it to the supplied send right.
754 * Nothing locked. If successful, consumes
755 * the supplied send right.
757 * KERN_SUCCESS Changed the special port.
758 * KERN_INVALID_ARGUMENT The task is null.
759 * KERN_FAILURE The task/space is dead.
760 * KERN_INVALID_ARGUMENT Invalid special port.
764 task_set_special_port(
772 if (task
== TASK_NULL
)
773 return KERN_INVALID_ARGUMENT
;
776 case TASK_KERNEL_PORT
:
777 whichp
= &task
->itk_sself
;
781 whichp
= &task
->itk_host
;
784 case TASK_BOOTSTRAP_PORT
:
785 whichp
= &task
->itk_bootstrap
;
788 case TASK_WIRED_LEDGER_PORT
:
789 whichp
= &task
->wired_ledger_port
;
792 case TASK_PAGED_LEDGER_PORT
:
793 whichp
= &task
->paged_ledger_port
;
797 return KERN_INVALID_ARGUMENT
;
801 if (task
->itk_self
== IP_NULL
) {
811 ipc_port_release_send(old
);
817 * Routine: mach_ports_register [kernel call]
819 * Stash a handful of port send rights in the task.
820 * Child tasks will inherit these rights, but they
821 * must use mach_ports_lookup to acquire them.
823 * The rights are supplied in a (wired) kalloc'd segment.
824 * Rights which aren't supplied are assumed to be null.
826 * Nothing locked. If successful, consumes
827 * the supplied rights and memory.
829 * KERN_SUCCESS Stashed the port rights.
830 * KERN_INVALID_ARGUMENT The task is null.
831 * KERN_INVALID_ARGUMENT The task is dead.
832 * KERN_INVALID_ARGUMENT Too many port rights supplied.
838 mach_port_array_t memory
,
839 mach_msg_type_number_t portsCnt
)
841 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
844 if ((task
== TASK_NULL
) ||
845 (portsCnt
> TASK_PORT_REGISTER_MAX
))
846 return KERN_INVALID_ARGUMENT
;
849 * Pad the port rights with nulls.
852 for (i
= 0; i
< portsCnt
; i
++)
853 ports
[i
] = memory
[i
];
854 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
858 if (task
->itk_self
== IP_NULL
) {
860 return KERN_INVALID_ARGUMENT
;
864 * Replace the old send rights with the new.
865 * Release the old rights after unlocking.
868 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
871 old
= task
->itk_registered
[i
];
872 task
->itk_registered
[i
] = ports
[i
];
878 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
879 if (IP_VALID(ports
[i
]))
880 ipc_port_release_send(ports
[i
]);
883 * Now that the operation is known to be successful,
884 * we can free the memory.
889 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
895 * Routine: mach_ports_lookup [kernel call]
897 * Retrieves (clones) the stashed port send rights.
899 * Nothing locked. If successful, the caller gets
902 * KERN_SUCCESS Retrieved the send rights.
903 * KERN_INVALID_ARGUMENT The task is null.
904 * KERN_INVALID_ARGUMENT The task is dead.
905 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
911 mach_port_array_t
*portsp
,
912 mach_msg_type_number_t
*portsCnt
)
919 if (task
== TASK_NULL
)
920 return KERN_INVALID_ARGUMENT
;
922 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
924 memory
= kalloc(size
);
926 return KERN_RESOURCE_SHORTAGE
;
929 if (task
->itk_self
== IP_NULL
) {
933 return KERN_INVALID_ARGUMENT
;
936 ports
= (ipc_port_t
*) memory
;
939 * Clone port rights. Because kalloc'd memory
940 * is wired, we won't fault while holding the task lock.
943 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
944 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
948 *portsp
= (mach_port_array_t
) ports
;
949 *portsCnt
= TASK_PORT_REGISTER_MAX
;
954 * Routine: convert_port_to_locked_task
956 * Internal helper routine to convert from a port to a locked
957 * task. Used by several routines that try to convert from a
958 * task port to a reference on some task related object.
960 * Nothing locked, blocking OK.
963 convert_port_to_locked_task(ipc_port_t port
)
965 while (IP_VALID(port
)) {
969 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
973 task
= (task_t
) port
->ip_kobject
;
974 assert(task
!= TASK_NULL
);
977 * Normal lock ordering puts task_lock() before ip_lock().
978 * Attempt out-of-order locking here.
980 if (task_lock_try(task
)) {
992 * Routine: convert_port_to_task
994 * Convert from a port to a task.
995 * Doesn't consume the port ref; produces a task ref,
1001 convert_port_to_task(
1004 task_t task
= TASK_NULL
;
1006 if (IP_VALID(port
)) {
1009 if ( ip_active(port
) &&
1010 ip_kotype(port
) == IKOT_TASK
) {
1011 task
= (task_t
)port
->ip_kobject
;
1012 assert(task
!= TASK_NULL
);
1014 task_reference_internal(task
);
1024 * Routine: convert_port_to_space
1026 * Convert from a port to a space.
1027 * Doesn't consume the port ref; produces a space ref,
1028 * which may be null.
1033 convert_port_to_space(
1039 task
= convert_port_to_locked_task(port
);
1041 if (task
== TASK_NULL
)
1042 return IPC_SPACE_NULL
;
1044 if (!task
->active
) {
1046 return IPC_SPACE_NULL
;
1049 space
= task
->itk_space
;
1050 is_reference(space
);
1056 * Routine: convert_port_to_map
1058 * Convert from a port to a map.
1059 * Doesn't consume the port ref; produces a map ref,
1060 * which may be null.
1066 convert_port_to_map(
1072 task
= convert_port_to_locked_task(port
);
1074 if (task
== TASK_NULL
)
1077 if (!task
->active
) {
1083 vm_map_reference_swap(map
);
1090 * Routine: convert_port_to_thread
1092 * Convert from a port to a thread.
1093 * Doesn't consume the port ref; produces an thread ref,
1094 * which may be null.
1100 convert_port_to_thread(
1103 thread_t thread
= THREAD_NULL
;
1105 if (IP_VALID(port
)) {
1108 if ( ip_active(port
) &&
1109 ip_kotype(port
) == IKOT_THREAD
) {
1110 thread
= (thread_t
)port
->ip_kobject
;
1111 assert(thread
!= THREAD_NULL
);
1113 thread_reference_internal(thread
);
1123 * Routine: port_name_to_thread
1125 * Convert from a port name to an thread reference
1126 * A name of MACH_PORT_NULL is valid for the null thread.
1131 port_name_to_thread(
1132 mach_port_name_t name
)
1134 thread_t thread
= THREAD_NULL
;
1137 if (MACH_PORT_VALID(name
)) {
1138 if (ipc_object_copyin(current_space(), name
,
1139 MACH_MSG_TYPE_COPY_SEND
,
1140 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1141 return (THREAD_NULL
);
1143 thread
= convert_port_to_thread(kport
);
1145 if (IP_VALID(kport
))
1146 ipc_port_release_send(kport
);
1154 mach_port_name_t name
)
1156 ipc_port_t kern_port
;
1158 task_t task
= TASK_NULL
;
1160 if (MACH_PORT_VALID(name
)) {
1161 kr
= ipc_object_copyin(current_space(), name
,
1162 MACH_MSG_TYPE_COPY_SEND
,
1163 (ipc_object_t
*) &kern_port
);
1164 if (kr
!= KERN_SUCCESS
)
1167 task
= convert_port_to_task(kern_port
);
1169 if (IP_VALID(kern_port
))
1170 ipc_port_release_send(kern_port
);
1176 * Routine: convert_task_to_port
1178 * Convert from a task to a port.
1179 * Consumes a task ref; produces a naked send right
1180 * which may be invalid.
1186 convert_task_to_port(
1192 if (task
->itk_self
!= IP_NULL
)
1193 port
= ipc_port_make_send(task
->itk_self
);
1198 task_deallocate(task
);
1203 * Routine: convert_thread_to_port
1205 * Convert from a thread to a port.
1206 * Consumes an thread ref; produces a naked send right
1207 * which may be invalid.
1213 convert_thread_to_port(
1218 thread_mtx_lock(thread
);
1220 if (thread
->ith_self
!= IP_NULL
)
1221 port
= ipc_port_make_send(thread
->ith_self
);
1225 thread_mtx_unlock(thread
);
1227 thread_deallocate(thread
);
1233 * Routine: space_deallocate
1235 * Deallocate a space ref produced by convert_port_to_space.
1244 if (space
!= IS_NULL
)
1249 * Routine: thread/task_set_exception_ports [kernel call]
1251 * Sets the thread/task exception port, flavor and
1252 * behavior for the exception types specified by the mask.
1253 * There will be one send right per exception per valid
1256 * Nothing locked. If successful, consumes
1257 * the supplied send right.
1259 * KERN_SUCCESS Changed the special port.
1260 * KERN_INVALID_ARGUMENT The thread is null,
1261 * Illegal mask bit set.
1262 * Illegal exception behavior
1263 * KERN_FAILURE The thread is dead.
1267 thread_set_exception_ports(
1269 exception_mask_t exception_mask
,
1270 ipc_port_t new_port
,
1271 exception_behavior_t new_behavior
,
1272 thread_state_flavor_t new_flavor
)
1274 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1277 if (thread
== THREAD_NULL
)
1278 return (KERN_INVALID_ARGUMENT
);
1280 if (exception_mask
& ~EXC_MASK_ALL
)
1281 return (KERN_INVALID_ARGUMENT
);
1283 if (IP_VALID(new_port
)) {
1284 switch (new_behavior
) {
1286 case EXCEPTION_DEFAULT
:
1287 case EXCEPTION_STATE
:
1288 case EXCEPTION_STATE_IDENTITY
:
1292 return (KERN_INVALID_ARGUMENT
);
1297 * Check the validity of the thread_state_flavor by calling the
1298 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1299 * osfmk/mach/ARCHITECTURE/thread_status.h
1301 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1302 return (KERN_INVALID_ARGUMENT
);
1304 thread_mtx_lock(thread
);
1306 if (!thread
->active
) {
1307 thread_mtx_unlock(thread
);
1309 return (KERN_FAILURE
);
1312 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1313 if (exception_mask
& (1 << i
)) {
1314 old_port
[i
] = thread
->exc_actions
[i
].port
;
1315 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1316 thread
->exc_actions
[i
].behavior
= new_behavior
;
1317 thread
->exc_actions
[i
].flavor
= new_flavor
;
1320 old_port
[i
] = IP_NULL
;
1323 thread_mtx_unlock(thread
);
1325 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1326 if (IP_VALID(old_port
[i
]))
1327 ipc_port_release_send(old_port
[i
]);
1329 if (IP_VALID(new_port
)) /* consume send right */
1330 ipc_port_release_send(new_port
);
1332 return (KERN_SUCCESS
);
1336 task_set_exception_ports(
1338 exception_mask_t exception_mask
,
1339 ipc_port_t new_port
,
1340 exception_behavior_t new_behavior
,
1341 thread_state_flavor_t new_flavor
)
1343 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1344 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1347 if (task
== TASK_NULL
)
1348 return (KERN_INVALID_ARGUMENT
);
1350 if (exception_mask
& ~EXC_MASK_ALL
)
1351 return (KERN_INVALID_ARGUMENT
);
1353 if (IP_VALID(new_port
)) {
1354 switch (new_behavior
) {
1356 case EXCEPTION_DEFAULT
:
1357 case EXCEPTION_STATE
:
1358 case EXCEPTION_STATE_IDENTITY
:
1362 return (KERN_INVALID_ARGUMENT
);
1368 if (task
->itk_self
== IP_NULL
) {
1371 return (KERN_FAILURE
);
1374 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1375 if (exception_mask
& (1 << i
)) {
1376 old_port
[i
] = task
->exc_actions
[i
].port
;
1377 task
->exc_actions
[i
].port
=
1378 ipc_port_copy_send(new_port
);
1379 task
->exc_actions
[i
].behavior
= new_behavior
;
1380 task
->exc_actions
[i
].flavor
= new_flavor
;
1381 task
->exc_actions
[i
].privileged
= privileged
;
1384 old_port
[i
] = IP_NULL
;
1389 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1390 if (IP_VALID(old_port
[i
]))
1391 ipc_port_release_send(old_port
[i
]);
1393 if (IP_VALID(new_port
)) /* consume send right */
1394 ipc_port_release_send(new_port
);
1396 return (KERN_SUCCESS
);
1400 * Routine: thread/task_swap_exception_ports [kernel call]
1402 * Sets the thread/task exception port, flavor and
1403 * behavior for the exception types specified by the
1406 * The old ports, behavior and flavors are returned
1407 * Count specifies the array sizes on input and
1408 * the number of returned ports etc. on output. The
1409 * arrays must be large enough to hold all the returned
1410 * data, MIG returnes an error otherwise. The masks
1411 * array specifies the corresponding exception type(s).
1414 * Nothing locked. If successful, consumes
1415 * the supplied send right.
1417 * Returns upto [in} CountCnt elements.
1419 * KERN_SUCCESS Changed the special port.
1420 * KERN_INVALID_ARGUMENT The thread is null,
1421 * Illegal mask bit set.
1422 * Illegal exception behavior
1423 * KERN_FAILURE The thread is dead.
1427 thread_swap_exception_ports(
1429 exception_mask_t exception_mask
,
1430 ipc_port_t new_port
,
1431 exception_behavior_t new_behavior
,
1432 thread_state_flavor_t new_flavor
,
1433 exception_mask_array_t masks
,
1434 mach_msg_type_number_t
*CountCnt
,
1435 exception_port_array_t ports
,
1436 exception_behavior_array_t behaviors
,
1437 thread_state_flavor_array_t flavors
)
1439 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1440 unsigned int i
, j
, count
;
1442 if (thread
== THREAD_NULL
)
1443 return (KERN_INVALID_ARGUMENT
);
1445 if (exception_mask
& ~EXC_MASK_ALL
)
1446 return (KERN_INVALID_ARGUMENT
);
1448 if (IP_VALID(new_port
)) {
1449 switch (new_behavior
) {
1451 case EXCEPTION_DEFAULT
:
1452 case EXCEPTION_STATE
:
1453 case EXCEPTION_STATE_IDENTITY
:
1457 return (KERN_INVALID_ARGUMENT
);
1461 thread_mtx_lock(thread
);
1463 if (!thread
->active
) {
1464 thread_mtx_unlock(thread
);
1466 return (KERN_FAILURE
);
1471 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1472 if (exception_mask
& (1 << i
)) {
1473 for (j
= 0; j
< count
; ++j
) {
1475 * search for an identical entry, if found
1476 * set corresponding mask for this exception.
1478 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1479 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1480 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1481 masks
[j
] |= (1 << i
);
1487 masks
[j
] = (1 << i
);
1488 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1490 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1491 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1495 old_port
[i
] = thread
->exc_actions
[i
].port
;
1496 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1497 thread
->exc_actions
[i
].behavior
= new_behavior
;
1498 thread
->exc_actions
[i
].flavor
= new_flavor
;
1499 if (count
> *CountCnt
)
1503 old_port
[i
] = IP_NULL
;
1506 thread_mtx_unlock(thread
);
1508 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1509 if (IP_VALID(old_port
[i
]))
1510 ipc_port_release_send(old_port
[i
]);
1512 if (IP_VALID(new_port
)) /* consume send right */
1513 ipc_port_release_send(new_port
);
1517 return (KERN_SUCCESS
);
1521 task_swap_exception_ports(
1523 exception_mask_t exception_mask
,
1524 ipc_port_t new_port
,
1525 exception_behavior_t new_behavior
,
1526 thread_state_flavor_t new_flavor
,
1527 exception_mask_array_t masks
,
1528 mach_msg_type_number_t
*CountCnt
,
1529 exception_port_array_t ports
,
1530 exception_behavior_array_t behaviors
,
1531 thread_state_flavor_array_t flavors
)
1533 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1534 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1535 unsigned int i
, j
, count
;
1537 if (task
== TASK_NULL
)
1538 return (KERN_INVALID_ARGUMENT
);
1540 if (exception_mask
& ~EXC_MASK_ALL
)
1541 return (KERN_INVALID_ARGUMENT
);
1543 if (IP_VALID(new_port
)) {
1544 switch (new_behavior
) {
1546 case EXCEPTION_DEFAULT
:
1547 case EXCEPTION_STATE
:
1548 case EXCEPTION_STATE_IDENTITY
:
1552 return (KERN_INVALID_ARGUMENT
);
1558 if (task
->itk_self
== IP_NULL
) {
1561 return (KERN_FAILURE
);
1566 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1567 if (exception_mask
& (1 << i
)) {
1568 for (j
= 0; j
< count
; j
++) {
1570 * search for an identical entry, if found
1571 * set corresponding mask for this exception.
1573 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1574 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1575 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1576 masks
[j
] |= (1 << i
);
1582 masks
[j
] = (1 << i
);
1583 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1584 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1585 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1589 old_port
[i
] = task
->exc_actions
[i
].port
;
1590 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1591 task
->exc_actions
[i
].behavior
= new_behavior
;
1592 task
->exc_actions
[i
].flavor
= new_flavor
;
1593 task
->exc_actions
[i
].privileged
= privileged
;
1594 if (count
> *CountCnt
)
1598 old_port
[i
] = IP_NULL
;
1603 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1604 if (IP_VALID(old_port
[i
]))
1605 ipc_port_release_send(old_port
[i
]);
1607 if (IP_VALID(new_port
)) /* consume send right */
1608 ipc_port_release_send(new_port
);
1612 return (KERN_SUCCESS
);
1616 * Routine: thread/task_get_exception_ports [kernel call]
1618 * Clones a send right for each of the thread/task's exception
1619 * ports specified in the mask and returns the behaviour
1620 * and flavor of said port.
1622 * Returns upto [in} CountCnt elements.
1627 * KERN_SUCCESS Extracted a send right.
1628 * KERN_INVALID_ARGUMENT The thread is null,
1629 * Invalid special port,
1630 * Illegal mask bit set.
1631 * KERN_FAILURE The thread is dead.
1635 thread_get_exception_ports(
1637 exception_mask_t exception_mask
,
1638 exception_mask_array_t masks
,
1639 mach_msg_type_number_t
*CountCnt
,
1640 exception_port_array_t ports
,
1641 exception_behavior_array_t behaviors
,
1642 thread_state_flavor_array_t flavors
)
1644 unsigned int i
, j
, count
;
1646 if (thread
== THREAD_NULL
)
1647 return (KERN_INVALID_ARGUMENT
);
1649 if (exception_mask
& ~EXC_MASK_ALL
)
1650 return (KERN_INVALID_ARGUMENT
);
1652 thread_mtx_lock(thread
);
1654 if (!thread
->active
) {
1655 thread_mtx_unlock(thread
);
1657 return (KERN_FAILURE
);
1662 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1663 if (exception_mask
& (1 << i
)) {
1664 for (j
= 0; j
< count
; ++j
) {
1666 * search for an identical entry, if found
1667 * set corresponding mask for this exception.
1669 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1670 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1671 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1672 masks
[j
] |= (1 << i
);
1678 masks
[j
] = (1 << i
);
1679 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1680 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1681 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1683 if (count
>= *CountCnt
)
1689 thread_mtx_unlock(thread
);
1693 return (KERN_SUCCESS
);
1697 task_get_exception_ports(
1699 exception_mask_t exception_mask
,
1700 exception_mask_array_t masks
,
1701 mach_msg_type_number_t
*CountCnt
,
1702 exception_port_array_t ports
,
1703 exception_behavior_array_t behaviors
,
1704 thread_state_flavor_array_t flavors
)
1706 unsigned int i
, j
, count
;
1708 if (task
== TASK_NULL
)
1709 return (KERN_INVALID_ARGUMENT
);
1711 if (exception_mask
& ~EXC_MASK_ALL
)
1712 return (KERN_INVALID_ARGUMENT
);
1716 if (task
->itk_self
== IP_NULL
) {
1719 return (KERN_FAILURE
);
1724 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1725 if (exception_mask
& (1 << i
)) {
1726 for (j
= 0; j
< count
; ++j
) {
1728 * search for an identical entry, if found
1729 * set corresponding mask for this exception.
1731 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1732 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1733 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1734 masks
[j
] |= (1 << i
);
1740 masks
[j
] = (1 << i
);
1741 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1742 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1743 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1745 if (count
> *CountCnt
)
1755 return (KERN_SUCCESS
);