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