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