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.
123 kr
= ipc_space_create(&ipc_table_entries
[0], &space
);
124 if (kr
!= KERN_SUCCESS
)
125 panic("ipc_task_init");
128 kport
= ipc_port_alloc_kernel();
129 if (kport
== IP_NULL
)
130 panic("ipc_task_init");
132 nport
= ipc_port_alloc_kernel();
133 if (nport
== IP_NULL
)
134 panic("ipc_task_init");
137 task
->itk_self
= kport
;
138 task
->itk_nself
= nport
;
139 task
->itk_sself
= ipc_port_make_send(kport
);
140 task
->itk_space
= space
;
141 space
->is_fast
= FALSE
;
143 if (parent
== TASK_NULL
) {
146 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
147 task
->exc_actions
[i
].port
= IP_NULL
;
150 kr
= host_get_host_port(host_priv_self(), &port
);
151 assert(kr
== KERN_SUCCESS
);
152 task
->itk_host
= port
;
154 task
->itk_bootstrap
= IP_NULL
;
156 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
157 task
->itk_registered
[i
] = IP_NULL
;
160 assert(parent
->itk_self
!= IP_NULL
);
162 /* inherit registered ports */
164 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
165 task
->itk_registered
[i
] =
166 ipc_port_copy_send(parent
->itk_registered
[i
]);
168 /* inherit exception and bootstrap ports */
170 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
171 task
->exc_actions
[i
].port
=
172 ipc_port_copy_send(parent
->exc_actions
[i
].port
);
173 task
->exc_actions
[i
].flavor
=
174 parent
->exc_actions
[i
].flavor
;
175 task
->exc_actions
[i
].behavior
=
176 parent
->exc_actions
[i
].behavior
;
177 task
->exc_actions
[i
].privileged
=
178 parent
->exc_actions
[i
].privileged
;
181 ipc_port_copy_send(parent
->itk_host
);
183 task
->itk_bootstrap
=
184 ipc_port_copy_send(parent
->itk_bootstrap
);
191 * Routine: ipc_task_enable
193 * Enable a task for IPC access.
206 kport
= task
->itk_self
;
207 if (kport
!= IP_NULL
)
208 ipc_kobject_set(kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
209 nport
= task
->itk_nself
;
210 if (nport
!= IP_NULL
)
211 ipc_kobject_set(nport
, (ipc_kobject_t
) task
, IKOT_TASK_NAME
);
216 * Routine: ipc_task_disable
218 * Disable IPC access to a task.
231 kport
= task
->itk_self
;
232 if (kport
!= IP_NULL
)
233 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
234 nport
= task
->itk_nself
;
235 if (nport
!= IP_NULL
)
236 ipc_kobject_set(nport
, IKO_NULL
, IKOT_NONE
);
241 * Routine: ipc_task_terminate
243 * Clean up and destroy a task's IPC state.
245 * Nothing locked. The task must be suspended.
246 * (Or the current thread must be in the task.)
258 kport
= task
->itk_self
;
260 if (kport
== IP_NULL
) {
261 /* the task is already terminated (can this happen?) */
265 task
->itk_self
= IP_NULL
;
267 nport
= task
->itk_nself
;
268 assert(nport
!= IP_NULL
);
269 task
->itk_nself
= IP_NULL
;
273 /* release the naked send rights */
275 if (IP_VALID(task
->itk_sself
))
276 ipc_port_release_send(task
->itk_sself
);
278 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
279 if (IP_VALID(task
->exc_actions
[i
].port
)) {
280 ipc_port_release_send(task
->exc_actions
[i
].port
);
284 if (IP_VALID(task
->itk_host
))
285 ipc_port_release_send(task
->itk_host
);
287 if (IP_VALID(task
->itk_bootstrap
))
288 ipc_port_release_send(task
->itk_bootstrap
);
290 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
291 if (IP_VALID(task
->itk_registered
[i
]))
292 ipc_port_release_send(task
->itk_registered
[i
]);
294 ipc_port_release_send(task
->wired_ledger_port
);
295 ipc_port_release_send(task
->paged_ledger_port
);
297 /* destroy the kernel ports */
298 ipc_port_dealloc_kernel(kport
);
299 ipc_port_dealloc_kernel(nport
);
303 * Routine: ipc_task_reset
305 * Reset a task's IPC state to protect it when
306 * it enters an elevated security context. The
307 * task name port can remain the same - since
308 * it represents no specific privilege.
310 * Nothing locked. The task must be suspended.
311 * (Or the current thread must be in the task.)
318 ipc_port_t old_kport
, new_kport
;
319 ipc_port_t old_sself
;
320 ipc_port_t old_exc_actions
[EXC_TYPES_COUNT
];
323 new_kport
= ipc_port_alloc_kernel();
324 if (new_kport
== IP_NULL
)
325 panic("ipc_task_reset");
329 old_kport
= task
->itk_self
;
331 if (old_kport
== IP_NULL
) {
332 /* the task is already terminated (can this happen?) */
334 ipc_port_dealloc_kernel(new_kport
);
338 task
->itk_self
= new_kport
;
339 old_sself
= task
->itk_sself
;
340 task
->itk_sself
= ipc_port_make_send(new_kport
);
341 ipc_kobject_set(old_kport
, IKO_NULL
, IKOT_NONE
);
342 ipc_kobject_set(new_kport
, (ipc_kobject_t
) task
, IKOT_TASK
);
344 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
345 if (!task
->exc_actions
[i
].privileged
) {
346 old_exc_actions
[i
] = task
->exc_actions
[i
].port
;
347 task
->exc_actions
[i
].port
= IP_NULL
;
349 old_exc_actions
[i
] = IP_NULL
;
355 /* release the naked send rights */
357 if (IP_VALID(old_sself
))
358 ipc_port_release_send(old_sself
);
360 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++) {
361 if (IP_VALID(old_exc_actions
[i
])) {
362 ipc_port_release_send(old_exc_actions
[i
]);
366 /* destroy the kernel port */
367 ipc_port_dealloc_kernel(old_kport
);
371 * Routine: ipc_thread_init
373 * Initialize a thread's IPC state.
385 kport
= ipc_port_alloc_kernel();
386 if (kport
== IP_NULL
)
387 panic("ipc_thread_init");
389 thread
->ith_self
= kport
;
390 thread
->ith_sself
= ipc_port_make_send(kport
);
392 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
393 thread
->exc_actions
[i
].port
= IP_NULL
;
395 ipc_kobject_set(kport
, (ipc_kobject_t
)thread
, IKOT_THREAD
);
397 ipc_kmsg_queue_init(&thread
->ith_messages
);
399 thread
->ith_rpc_reply
= IP_NULL
;
406 ipc_port_t kport
= thread
->ith_self
;
408 if (kport
!= IP_NULL
)
409 ipc_kobject_set(kport
, IKO_NULL
, IKOT_NONE
);
413 * Routine: ipc_thread_terminate
415 * Clean up and destroy a thread's IPC state.
421 ipc_thread_terminate(
424 ipc_port_t kport
= thread
->ith_self
;
426 if (kport
!= IP_NULL
) {
429 if (IP_VALID(thread
->ith_sself
))
430 ipc_port_release_send(thread
->ith_sself
);
432 thread
->ith_sself
= thread
->ith_self
= IP_NULL
;
434 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
435 if (IP_VALID(thread
->exc_actions
[i
].port
))
436 ipc_port_release_send(thread
->exc_actions
[i
].port
);
439 ipc_port_dealloc_kernel(kport
);
442 assert(ipc_kmsg_queue_empty(&thread
->ith_messages
));
444 if (thread
->ith_rpc_reply
!= IP_NULL
)
445 ipc_port_dealloc_reply(thread
->ith_rpc_reply
);
447 thread
->ith_rpc_reply
= IP_NULL
;
451 * Routine: retrieve_task_self_fast
453 * Optimized version of retrieve_task_self,
454 * that only works for the current task.
456 * Return a send right (possibly null/dead)
457 * for the task's user-visible self port.
463 retrieve_task_self_fast(
464 register task_t task
)
466 register ipc_port_t port
;
468 assert(task
== current_task());
471 assert(task
->itk_self
!= IP_NULL
);
473 if ((port
= task
->itk_sself
) == task
->itk_self
) {
477 assert(ip_active(port
));
482 port
= ipc_port_copy_send(port
);
489 * Routine: retrieve_thread_self_fast
491 * Return a send right (possibly null/dead)
492 * for the thread's user-visible self port.
494 * Only works for the current thread.
501 retrieve_thread_self_fast(
504 register ipc_port_t port
;
506 assert(thread
== current_thread());
508 thread_mtx_lock(thread
);
510 assert(thread
->ith_self
!= IP_NULL
);
512 if ((port
= thread
->ith_sself
) == thread
->ith_self
) {
516 assert(ip_active(port
));
522 port
= ipc_port_copy_send(port
);
524 thread_mtx_unlock(thread
);
530 * Routine: task_self_trap [mach trap]
532 * Give the caller send rights for his own task port.
536 * MACH_PORT_NULL if there are any resource failures
542 __unused
struct task_self_trap_args
*args
)
544 task_t task
= current_task();
546 mach_port_name_t name
;
548 sright
= retrieve_task_self_fast(task
);
549 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
554 * Routine: thread_self_trap [mach trap]
556 * Give the caller send rights for his own thread port.
560 * MACH_PORT_NULL if there are any resource failures
566 __unused
struct thread_self_trap_args
*args
)
568 thread_t thread
= current_thread();
569 task_t task
= thread
->task
;
571 mach_port_name_t name
;
573 sright
= retrieve_thread_self_fast(thread
);
574 name
= ipc_port_copyout_send(sright
, task
->itk_space
);
580 * Routine: mach_reply_port [mach trap]
582 * Allocate a port for the caller.
586 * MACH_PORT_NULL if there are any resource failures
592 __unused
struct mach_reply_port_args
*args
)
595 mach_port_name_t name
;
598 kr
= ipc_port_alloc(current_task()->itk_space
, &name
, &port
);
599 if (kr
== KERN_SUCCESS
)
602 name
= MACH_PORT_NULL
;
607 * Routine: thread_get_special_port [kernel call]
609 * Clones a send right for one of the thread's
614 * KERN_SUCCESS Extracted a send right.
615 * KERN_INVALID_ARGUMENT The thread is null.
616 * KERN_FAILURE The thread is dead.
617 * KERN_INVALID_ARGUMENT Invalid special port.
621 thread_get_special_port(
626 kern_return_t result
= KERN_SUCCESS
;
629 if (thread
== THREAD_NULL
)
630 return (KERN_INVALID_ARGUMENT
);
634 case THREAD_KERNEL_PORT
:
635 whichp
= &thread
->ith_sself
;
639 return (KERN_INVALID_ARGUMENT
);
642 thread_mtx_lock(thread
);
645 *portp
= ipc_port_copy_send(*whichp
);
647 result
= KERN_FAILURE
;
649 thread_mtx_unlock(thread
);
655 * Routine: thread_set_special_port [kernel call]
657 * Changes one of the thread's special ports,
658 * setting it to the supplied send right.
660 * Nothing locked. If successful, consumes
661 * the supplied send right.
663 * KERN_SUCCESS Changed the special port.
664 * KERN_INVALID_ARGUMENT The thread is null.
665 * KERN_FAILURE The thread is dead.
666 * KERN_INVALID_ARGUMENT Invalid special port.
670 thread_set_special_port(
675 kern_return_t result
= KERN_SUCCESS
;
676 ipc_port_t
*whichp
, old
= IP_NULL
;
678 if (thread
== THREAD_NULL
)
679 return (KERN_INVALID_ARGUMENT
);
683 case THREAD_KERNEL_PORT
:
684 whichp
= &thread
->ith_sself
;
688 return (KERN_INVALID_ARGUMENT
);
691 thread_mtx_lock(thread
);
693 if (thread
->active
) {
698 result
= KERN_FAILURE
;
700 thread_mtx_unlock(thread
);
703 ipc_port_release_send(old
);
709 * Routine: task_get_special_port [kernel call]
711 * Clones a send right for one of the task's
716 * KERN_SUCCESS Extracted a send right.
717 * KERN_INVALID_ARGUMENT The task is null.
718 * KERN_FAILURE The task/space is dead.
719 * KERN_INVALID_ARGUMENT Invalid special port.
723 task_get_special_port(
730 if (task
== TASK_NULL
)
731 return KERN_INVALID_ARGUMENT
;
734 if (task
->itk_self
== IP_NULL
) {
740 case TASK_KERNEL_PORT
:
741 port
= ipc_port_copy_send(task
->itk_sself
);
745 port
= ipc_port_make_send(task
->itk_nself
);
749 port
= ipc_port_copy_send(task
->itk_host
);
752 case TASK_BOOTSTRAP_PORT
:
753 port
= ipc_port_copy_send(task
->itk_bootstrap
);
756 case TASK_WIRED_LEDGER_PORT
:
757 port
= ipc_port_copy_send(task
->wired_ledger_port
);
760 case TASK_PAGED_LEDGER_PORT
:
761 port
= ipc_port_copy_send(task
->paged_ledger_port
);
765 return KERN_INVALID_ARGUMENT
;
774 * Routine: task_set_special_port [kernel call]
776 * Changes one of the task's special ports,
777 * setting it to the supplied send right.
779 * Nothing locked. If successful, consumes
780 * the supplied send right.
782 * KERN_SUCCESS Changed the special port.
783 * KERN_INVALID_ARGUMENT The task is null.
784 * KERN_FAILURE The task/space is dead.
785 * KERN_INVALID_ARGUMENT Invalid special port.
789 task_set_special_port(
797 if (task
== TASK_NULL
)
798 return KERN_INVALID_ARGUMENT
;
801 case TASK_KERNEL_PORT
:
802 whichp
= &task
->itk_sself
;
806 whichp
= &task
->itk_host
;
809 case TASK_BOOTSTRAP_PORT
:
810 whichp
= &task
->itk_bootstrap
;
813 case TASK_WIRED_LEDGER_PORT
:
814 whichp
= &task
->wired_ledger_port
;
817 case TASK_PAGED_LEDGER_PORT
:
818 whichp
= &task
->paged_ledger_port
;
822 return KERN_INVALID_ARGUMENT
;
826 if (task
->itk_self
== IP_NULL
) {
836 ipc_port_release_send(old
);
842 * Routine: mach_ports_register [kernel call]
844 * Stash a handful of port send rights in the task.
845 * Child tasks will inherit these rights, but they
846 * must use mach_ports_lookup to acquire them.
848 * The rights are supplied in a (wired) kalloc'd segment.
849 * Rights which aren't supplied are assumed to be null.
851 * Nothing locked. If successful, consumes
852 * the supplied rights and memory.
854 * KERN_SUCCESS Stashed the port rights.
855 * KERN_INVALID_ARGUMENT The task is null.
856 * KERN_INVALID_ARGUMENT The task is dead.
857 * KERN_INVALID_ARGUMENT Too many port rights supplied.
863 mach_port_array_t memory
,
864 mach_msg_type_number_t portsCnt
)
866 ipc_port_t ports
[TASK_PORT_REGISTER_MAX
];
869 if ((task
== TASK_NULL
) ||
870 (portsCnt
> TASK_PORT_REGISTER_MAX
))
871 return KERN_INVALID_ARGUMENT
;
874 * Pad the port rights with nulls.
877 for (i
= 0; i
< portsCnt
; i
++)
878 ports
[i
] = memory
[i
];
879 for (; i
< TASK_PORT_REGISTER_MAX
; i
++)
883 if (task
->itk_self
== IP_NULL
) {
885 return KERN_INVALID_ARGUMENT
;
889 * Replace the old send rights with the new.
890 * Release the old rights after unlocking.
893 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++) {
896 old
= task
->itk_registered
[i
];
897 task
->itk_registered
[i
] = ports
[i
];
903 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
904 if (IP_VALID(ports
[i
]))
905 ipc_port_release_send(ports
[i
]);
908 * Now that the operation is known to be successful,
909 * we can free the memory.
914 (vm_size_t
) (portsCnt
* sizeof(mach_port_t
)));
920 * Routine: mach_ports_lookup [kernel call]
922 * Retrieves (clones) the stashed port send rights.
924 * Nothing locked. If successful, the caller gets
927 * KERN_SUCCESS Retrieved the send rights.
928 * KERN_INVALID_ARGUMENT The task is null.
929 * KERN_INVALID_ARGUMENT The task is dead.
930 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
936 mach_port_array_t
*portsp
,
937 mach_msg_type_number_t
*portsCnt
)
944 if (task
== TASK_NULL
)
945 return KERN_INVALID_ARGUMENT
;
947 size
= (vm_size_t
) (TASK_PORT_REGISTER_MAX
* sizeof(ipc_port_t
));
949 memory
= kalloc(size
);
951 return KERN_RESOURCE_SHORTAGE
;
954 if (task
->itk_self
== IP_NULL
) {
958 return KERN_INVALID_ARGUMENT
;
961 ports
= (ipc_port_t
*) memory
;
964 * Clone port rights. Because kalloc'd memory
965 * is wired, we won't fault while holding the task lock.
968 for (i
= 0; i
< TASK_PORT_REGISTER_MAX
; i
++)
969 ports
[i
] = ipc_port_copy_send(task
->itk_registered
[i
]);
973 *portsp
= (mach_port_array_t
) ports
;
974 *portsCnt
= TASK_PORT_REGISTER_MAX
;
979 * Routine: convert_port_to_locked_task
981 * Internal helper routine to convert from a port to a locked
982 * task. Used by several routines that try to convert from a
983 * task port to a reference on some task related object.
985 * Nothing locked, blocking OK.
988 convert_port_to_locked_task(ipc_port_t port
)
990 while (IP_VALID(port
)) {
994 if (!ip_active(port
) || (ip_kotype(port
) != IKOT_TASK
)) {
998 task
= (task_t
) port
->ip_kobject
;
999 assert(task
!= TASK_NULL
);
1002 * Normal lock ordering puts task_lock() before ip_lock().
1003 * Attempt out-of-order locking here.
1005 if (task_lock_try(task
)) {
1017 * Routine: convert_port_to_task
1019 * Convert from a port to a task.
1020 * Doesn't consume the port ref; produces a task ref,
1021 * which may be null.
1026 convert_port_to_task(
1029 task_t task
= TASK_NULL
;
1031 if (IP_VALID(port
)) {
1034 if ( ip_active(port
) &&
1035 ip_kotype(port
) == IKOT_TASK
) {
1036 task
= (task_t
)port
->ip_kobject
;
1037 assert(task
!= TASK_NULL
);
1039 task_reference_internal(task
);
1049 * Routine: convert_port_to_task_name
1051 * Convert from a port to a task name.
1052 * Doesn't consume the port ref; produces a task name ref,
1053 * which may be null.
1058 convert_port_to_task_name(
1061 task_name_t task
= TASK_NULL
;
1063 if (IP_VALID(port
)) {
1066 if ( ip_active(port
) &&
1067 (ip_kotype(port
) == IKOT_TASK
||
1068 ip_kotype(port
) == IKOT_TASK_NAME
)) {
1069 task
= (task_name_t
)port
->ip_kobject
;
1070 assert(task
!= TASK_NAME_NULL
);
1072 task_reference_internal(task
);
1082 * Routine: convert_port_to_space
1084 * Convert from a port to a space.
1085 * Doesn't consume the port ref; produces a space ref,
1086 * which may be null.
1091 convert_port_to_space(
1097 task
= convert_port_to_locked_task(port
);
1099 if (task
== TASK_NULL
)
1100 return IPC_SPACE_NULL
;
1102 if (!task
->active
) {
1104 return IPC_SPACE_NULL
;
1107 space
= task
->itk_space
;
1108 is_reference(space
);
1114 * Routine: convert_port_to_map
1116 * Convert from a port to a map.
1117 * Doesn't consume the port ref; produces a map ref,
1118 * which may be null.
1124 convert_port_to_map(
1130 task
= convert_port_to_locked_task(port
);
1132 if (task
== TASK_NULL
)
1135 if (!task
->active
) {
1141 vm_map_reference_swap(map
);
1148 * Routine: convert_port_to_thread
1150 * Convert from a port to a thread.
1151 * Doesn't consume the port ref; produces an thread ref,
1152 * which may be null.
1158 convert_port_to_thread(
1161 thread_t thread
= THREAD_NULL
;
1163 if (IP_VALID(port
)) {
1166 if ( ip_active(port
) &&
1167 ip_kotype(port
) == IKOT_THREAD
) {
1168 thread
= (thread_t
)port
->ip_kobject
;
1169 assert(thread
!= THREAD_NULL
);
1171 thread_reference_internal(thread
);
1181 * Routine: port_name_to_thread
1183 * Convert from a port name to an thread reference
1184 * A name of MACH_PORT_NULL is valid for the null thread.
1189 port_name_to_thread(
1190 mach_port_name_t name
)
1192 thread_t thread
= THREAD_NULL
;
1195 if (MACH_PORT_VALID(name
)) {
1196 if (ipc_object_copyin(current_space(), name
,
1197 MACH_MSG_TYPE_COPY_SEND
,
1198 (ipc_object_t
*)&kport
) != KERN_SUCCESS
)
1199 return (THREAD_NULL
);
1201 thread
= convert_port_to_thread(kport
);
1203 if (IP_VALID(kport
))
1204 ipc_port_release_send(kport
);
1212 mach_port_name_t name
)
1214 ipc_port_t kern_port
;
1216 task_t task
= TASK_NULL
;
1218 if (MACH_PORT_VALID(name
)) {
1219 kr
= ipc_object_copyin(current_space(), name
,
1220 MACH_MSG_TYPE_COPY_SEND
,
1221 (ipc_object_t
*) &kern_port
);
1222 if (kr
!= KERN_SUCCESS
)
1225 task
= convert_port_to_task(kern_port
);
1227 if (IP_VALID(kern_port
))
1228 ipc_port_release_send(kern_port
);
1234 * Routine: convert_task_to_port
1236 * Convert from a task to a port.
1237 * Consumes a task ref; produces a naked send right
1238 * which may be invalid.
1244 convert_task_to_port(
1250 if (task
->itk_self
!= IP_NULL
)
1251 port
= ipc_port_make_send(task
->itk_self
);
1256 task_deallocate(task
);
1261 * Routine: convert_task_name_to_port
1263 * Convert from a task name ref to a port.
1264 * Consumes a task name ref; produces a naked send right
1265 * which may be invalid.
1271 convert_task_name_to_port(
1272 task_name_t task_name
)
1276 itk_lock(task_name
);
1277 if (task_name
->itk_nself
!= IP_NULL
)
1278 port
= ipc_port_make_send(task_name
->itk_nself
);
1281 itk_unlock(task_name
);
1283 task_name_deallocate(task_name
);
1288 * Routine: convert_thread_to_port
1290 * Convert from a thread to a port.
1291 * Consumes an thread ref; produces a naked send right
1292 * which may be invalid.
1298 convert_thread_to_port(
1303 thread_mtx_lock(thread
);
1305 if (thread
->ith_self
!= IP_NULL
)
1306 port
= ipc_port_make_send(thread
->ith_self
);
1310 thread_mtx_unlock(thread
);
1312 thread_deallocate(thread
);
1318 * Routine: space_deallocate
1320 * Deallocate a space ref produced by convert_port_to_space.
1329 if (space
!= IS_NULL
)
1334 * Routine: thread/task_set_exception_ports [kernel call]
1336 * Sets the thread/task exception port, flavor and
1337 * behavior for the exception types specified by the mask.
1338 * There will be one send right per exception per valid
1341 * Nothing locked. If successful, consumes
1342 * the supplied send right.
1344 * KERN_SUCCESS Changed the special port.
1345 * KERN_INVALID_ARGUMENT The thread is null,
1346 * Illegal mask bit set.
1347 * Illegal exception behavior
1348 * KERN_FAILURE The thread is dead.
1352 thread_set_exception_ports(
1354 exception_mask_t exception_mask
,
1355 ipc_port_t new_port
,
1356 exception_behavior_t new_behavior
,
1357 thread_state_flavor_t new_flavor
)
1359 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1362 if (thread
== THREAD_NULL
)
1363 return (KERN_INVALID_ARGUMENT
);
1365 if (exception_mask
& ~EXC_MASK_ALL
)
1366 return (KERN_INVALID_ARGUMENT
);
1368 if (IP_VALID(new_port
)) {
1369 switch (new_behavior
) {
1371 case EXCEPTION_DEFAULT
:
1372 case EXCEPTION_STATE
:
1373 case EXCEPTION_STATE_IDENTITY
:
1377 return (KERN_INVALID_ARGUMENT
);
1382 * Check the validity of the thread_state_flavor by calling the
1383 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
1384 * osfmk/mach/ARCHITECTURE/thread_status.h
1386 if (!VALID_THREAD_STATE_FLAVOR(new_flavor
))
1387 return (KERN_INVALID_ARGUMENT
);
1389 thread_mtx_lock(thread
);
1391 if (!thread
->active
) {
1392 thread_mtx_unlock(thread
);
1394 return (KERN_FAILURE
);
1397 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1398 if (exception_mask
& (1 << i
)) {
1399 old_port
[i
] = thread
->exc_actions
[i
].port
;
1400 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1401 thread
->exc_actions
[i
].behavior
= new_behavior
;
1402 thread
->exc_actions
[i
].flavor
= new_flavor
;
1405 old_port
[i
] = IP_NULL
;
1408 thread_mtx_unlock(thread
);
1410 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1411 if (IP_VALID(old_port
[i
]))
1412 ipc_port_release_send(old_port
[i
]);
1414 if (IP_VALID(new_port
)) /* consume send right */
1415 ipc_port_release_send(new_port
);
1417 return (KERN_SUCCESS
);
1421 task_set_exception_ports(
1423 exception_mask_t exception_mask
,
1424 ipc_port_t new_port
,
1425 exception_behavior_t new_behavior
,
1426 thread_state_flavor_t new_flavor
)
1428 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1429 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1432 if (task
== TASK_NULL
)
1433 return (KERN_INVALID_ARGUMENT
);
1435 if (exception_mask
& ~EXC_MASK_ALL
)
1436 return (KERN_INVALID_ARGUMENT
);
1438 if (IP_VALID(new_port
)) {
1439 switch (new_behavior
) {
1441 case EXCEPTION_DEFAULT
:
1442 case EXCEPTION_STATE
:
1443 case EXCEPTION_STATE_IDENTITY
:
1447 return (KERN_INVALID_ARGUMENT
);
1453 if (task
->itk_self
== IP_NULL
) {
1456 return (KERN_FAILURE
);
1459 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1460 if (exception_mask
& (1 << i
)) {
1461 old_port
[i
] = task
->exc_actions
[i
].port
;
1462 task
->exc_actions
[i
].port
=
1463 ipc_port_copy_send(new_port
);
1464 task
->exc_actions
[i
].behavior
= new_behavior
;
1465 task
->exc_actions
[i
].flavor
= new_flavor
;
1466 task
->exc_actions
[i
].privileged
= privileged
;
1469 old_port
[i
] = IP_NULL
;
1474 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1475 if (IP_VALID(old_port
[i
]))
1476 ipc_port_release_send(old_port
[i
]);
1478 if (IP_VALID(new_port
)) /* consume send right */
1479 ipc_port_release_send(new_port
);
1481 return (KERN_SUCCESS
);
1485 * Routine: thread/task_swap_exception_ports [kernel call]
1487 * Sets the thread/task exception port, flavor and
1488 * behavior for the exception types specified by the
1491 * The old ports, behavior and flavors are returned
1492 * Count specifies the array sizes on input and
1493 * the number of returned ports etc. on output. The
1494 * arrays must be large enough to hold all the returned
1495 * data, MIG returnes an error otherwise. The masks
1496 * array specifies the corresponding exception type(s).
1499 * Nothing locked. If successful, consumes
1500 * the supplied send right.
1502 * Returns upto [in} CountCnt elements.
1504 * KERN_SUCCESS Changed the special port.
1505 * KERN_INVALID_ARGUMENT The thread is null,
1506 * Illegal mask bit set.
1507 * Illegal exception behavior
1508 * KERN_FAILURE The thread is dead.
1512 thread_swap_exception_ports(
1514 exception_mask_t exception_mask
,
1515 ipc_port_t new_port
,
1516 exception_behavior_t new_behavior
,
1517 thread_state_flavor_t new_flavor
,
1518 exception_mask_array_t masks
,
1519 mach_msg_type_number_t
*CountCnt
,
1520 exception_port_array_t ports
,
1521 exception_behavior_array_t behaviors
,
1522 thread_state_flavor_array_t flavors
)
1524 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1525 unsigned int i
, j
, count
;
1527 if (thread
== THREAD_NULL
)
1528 return (KERN_INVALID_ARGUMENT
);
1530 if (exception_mask
& ~EXC_MASK_ALL
)
1531 return (KERN_INVALID_ARGUMENT
);
1533 if (IP_VALID(new_port
)) {
1534 switch (new_behavior
) {
1536 case EXCEPTION_DEFAULT
:
1537 case EXCEPTION_STATE
:
1538 case EXCEPTION_STATE_IDENTITY
:
1542 return (KERN_INVALID_ARGUMENT
);
1546 thread_mtx_lock(thread
);
1548 if (!thread
->active
) {
1549 thread_mtx_unlock(thread
);
1551 return (KERN_FAILURE
);
1556 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1557 if (exception_mask
& (1 << i
)) {
1558 for (j
= 0; j
< count
; ++j
) {
1560 * search for an identical entry, if found
1561 * set corresponding mask for this exception.
1563 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1564 thread
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1565 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1566 masks
[j
] |= (1 << i
);
1572 masks
[j
] = (1 << i
);
1573 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1575 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1576 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1580 old_port
[i
] = thread
->exc_actions
[i
].port
;
1581 thread
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1582 thread
->exc_actions
[i
].behavior
= new_behavior
;
1583 thread
->exc_actions
[i
].flavor
= new_flavor
;
1584 if (count
> *CountCnt
)
1588 old_port
[i
] = IP_NULL
;
1591 thread_mtx_unlock(thread
);
1593 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
)
1594 if (IP_VALID(old_port
[i
]))
1595 ipc_port_release_send(old_port
[i
]);
1597 if (IP_VALID(new_port
)) /* consume send right */
1598 ipc_port_release_send(new_port
);
1602 return (KERN_SUCCESS
);
1606 task_swap_exception_ports(
1608 exception_mask_t exception_mask
,
1609 ipc_port_t new_port
,
1610 exception_behavior_t new_behavior
,
1611 thread_state_flavor_t new_flavor
,
1612 exception_mask_array_t masks
,
1613 mach_msg_type_number_t
*CountCnt
,
1614 exception_port_array_t ports
,
1615 exception_behavior_array_t behaviors
,
1616 thread_state_flavor_array_t flavors
)
1618 ipc_port_t old_port
[EXC_TYPES_COUNT
];
1619 boolean_t privileged
= current_task()->sec_token
.val
[0] == 0;
1620 unsigned int i
, j
, count
;
1622 if (task
== TASK_NULL
)
1623 return (KERN_INVALID_ARGUMENT
);
1625 if (exception_mask
& ~EXC_MASK_ALL
)
1626 return (KERN_INVALID_ARGUMENT
);
1628 if (IP_VALID(new_port
)) {
1629 switch (new_behavior
) {
1631 case EXCEPTION_DEFAULT
:
1632 case EXCEPTION_STATE
:
1633 case EXCEPTION_STATE_IDENTITY
:
1637 return (KERN_INVALID_ARGUMENT
);
1643 if (task
->itk_self
== IP_NULL
) {
1646 return (KERN_FAILURE
);
1651 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1652 if (exception_mask
& (1 << i
)) {
1653 for (j
= 0; j
< count
; j
++) {
1655 * search for an identical entry, if found
1656 * set corresponding mask for this exception.
1658 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1659 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1660 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1661 masks
[j
] |= (1 << i
);
1667 masks
[j
] = (1 << i
);
1668 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1669 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1670 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1674 old_port
[i
] = task
->exc_actions
[i
].port
;
1675 task
->exc_actions
[i
].port
= ipc_port_copy_send(new_port
);
1676 task
->exc_actions
[i
].behavior
= new_behavior
;
1677 task
->exc_actions
[i
].flavor
= new_flavor
;
1678 task
->exc_actions
[i
].privileged
= privileged
;
1679 if (count
> *CountCnt
)
1683 old_port
[i
] = IP_NULL
;
1688 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; i
++)
1689 if (IP_VALID(old_port
[i
]))
1690 ipc_port_release_send(old_port
[i
]);
1692 if (IP_VALID(new_port
)) /* consume send right */
1693 ipc_port_release_send(new_port
);
1697 return (KERN_SUCCESS
);
1701 * Routine: thread/task_get_exception_ports [kernel call]
1703 * Clones a send right for each of the thread/task's exception
1704 * ports specified in the mask and returns the behaviour
1705 * and flavor of said port.
1707 * Returns upto [in} CountCnt elements.
1712 * KERN_SUCCESS Extracted a send right.
1713 * KERN_INVALID_ARGUMENT The thread is null,
1714 * Invalid special port,
1715 * Illegal mask bit set.
1716 * KERN_FAILURE The thread is dead.
1720 thread_get_exception_ports(
1722 exception_mask_t exception_mask
,
1723 exception_mask_array_t masks
,
1724 mach_msg_type_number_t
*CountCnt
,
1725 exception_port_array_t ports
,
1726 exception_behavior_array_t behaviors
,
1727 thread_state_flavor_array_t flavors
)
1729 unsigned int i
, j
, count
;
1731 if (thread
== THREAD_NULL
)
1732 return (KERN_INVALID_ARGUMENT
);
1734 if (exception_mask
& ~EXC_MASK_ALL
)
1735 return (KERN_INVALID_ARGUMENT
);
1737 thread_mtx_lock(thread
);
1739 if (!thread
->active
) {
1740 thread_mtx_unlock(thread
);
1742 return (KERN_FAILURE
);
1747 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1748 if (exception_mask
& (1 << i
)) {
1749 for (j
= 0; j
< count
; ++j
) {
1751 * search for an identical entry, if found
1752 * set corresponding mask for this exception.
1754 if ( thread
->exc_actions
[i
].port
== ports
[j
] &&
1755 thread
->exc_actions
[i
].behavior
==behaviors
[j
] &&
1756 thread
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1757 masks
[j
] |= (1 << i
);
1763 masks
[j
] = (1 << i
);
1764 ports
[j
] = ipc_port_copy_send(thread
->exc_actions
[i
].port
);
1765 behaviors
[j
] = thread
->exc_actions
[i
].behavior
;
1766 flavors
[j
] = thread
->exc_actions
[i
].flavor
;
1768 if (count
>= *CountCnt
)
1774 thread_mtx_unlock(thread
);
1778 return (KERN_SUCCESS
);
1782 task_get_exception_ports(
1784 exception_mask_t exception_mask
,
1785 exception_mask_array_t masks
,
1786 mach_msg_type_number_t
*CountCnt
,
1787 exception_port_array_t ports
,
1788 exception_behavior_array_t behaviors
,
1789 thread_state_flavor_array_t flavors
)
1791 unsigned int i
, j
, count
;
1793 if (task
== TASK_NULL
)
1794 return (KERN_INVALID_ARGUMENT
);
1796 if (exception_mask
& ~EXC_MASK_ALL
)
1797 return (KERN_INVALID_ARGUMENT
);
1801 if (task
->itk_self
== IP_NULL
) {
1804 return (KERN_FAILURE
);
1809 for (i
= FIRST_EXCEPTION
; i
< EXC_TYPES_COUNT
; ++i
) {
1810 if (exception_mask
& (1 << i
)) {
1811 for (j
= 0; j
< count
; ++j
) {
1813 * search for an identical entry, if found
1814 * set corresponding mask for this exception.
1816 if ( task
->exc_actions
[i
].port
== ports
[j
] &&
1817 task
->exc_actions
[i
].behavior
== behaviors
[j
] &&
1818 task
->exc_actions
[i
].flavor
== flavors
[j
] ) {
1819 masks
[j
] |= (1 << i
);
1825 masks
[j
] = (1 << i
);
1826 ports
[j
] = ipc_port_copy_send(task
->exc_actions
[i
].port
);
1827 behaviors
[j
] = task
->exc_actions
[i
].behavior
;
1828 flavors
[j
] = task
->exc_actions
[i
].flavor
;
1830 if (count
> *CountCnt
)
1840 return (KERN_SUCCESS
);