]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ipc_host.c
xnu-1228.7.58.tar.gz
[apple/xnu.git] / osfmk / kern / ipc_host.c
1 /*
2 * Copyright (c) 2000-2007 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28 /*
29 * @OSF_COPYRIGHT@
30 */
31 /*
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University
34 * All Rights Reserved.
35 *
36 * Permission to use, copy, modify and distribute this software and its
37 * documentation is hereby granted, provided that both the copyright
38 * notice and this permission notice appear in all copies of the
39 * software, derivative works or modified versions, and any portions
40 * thereof, and that both notices appear in supporting documentation.
41 *
42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45 *
46 * Carnegie Mellon requests users of this software to return to
47 *
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
52 *
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56 /*
57 */
58
59 /*
60 * kern/ipc_host.c
61 *
62 * Routines to implement host ports.
63 */
64 #include <mach/message.h>
65 #include <mach/mach_traps.h>
66 #include <mach/mach_host_server.h>
67 #include <mach/host_priv_server.h>
68 #include <kern/host.h>
69 #include <kern/processor.h>
70 #include <kern/lock.h>
71 #include <kern/task.h>
72 #include <kern/thread.h>
73 #include <kern/ipc_host.h>
74 #include <kern/ipc_kobject.h>
75 #include <kern/misc_protos.h>
76 #include <kern/spl.h>
77 #include <ipc/ipc_port.h>
78 #include <ipc/ipc_space.h>
79
80 /*
81 * Forward declarations
82 */
83
84 void
85 ipc_processor_terminate(
86 processor_t processor);
87
88 void
89 ipc_processor_disable(
90 processor_t processor);
91
92 boolean_t
93 ref_pset_port_locked(
94 ipc_port_t port, boolean_t matchn, processor_set_t *ppset);
95
96 /*
97 * ipc_host_init: set up various things.
98 */
99
100 void ipc_host_init(void)
101 {
102 ipc_port_t port;
103 int i;
104
105 mutex_init(&realhost.lock, 0);
106
107 /*
108 * Allocate and set up the two host ports.
109 */
110 port = ipc_port_alloc_kernel();
111 if (port == IP_NULL)
112 panic("ipc_host_init");
113
114 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY);
115 kernel_set_special_port(&realhost, HOST_SECURITY_PORT,
116 ipc_port_make_send(port));
117
118 port = ipc_port_alloc_kernel();
119 if (port == IP_NULL)
120 panic("ipc_host_init");
121
122 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST);
123 kernel_set_special_port(&realhost, HOST_PORT,
124 ipc_port_make_send(port));
125
126 port = ipc_port_alloc_kernel();
127 if (port == IP_NULL)
128 panic("ipc_host_init");
129
130 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV);
131 kernel_set_special_port(&realhost, HOST_PRIV_PORT,
132 ipc_port_make_send(port));
133
134 /* the rest of the special ports will be set up later */
135
136 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
137 realhost.exc_actions[i].port = IP_NULL;
138 }/* for */
139
140 /*
141 * Set up ipc for default processor set.
142 */
143 ipc_pset_init(&pset0);
144 ipc_pset_enable(&pset0);
145
146 /*
147 * And for master processor
148 */
149 ipc_processor_init(master_processor);
150 ipc_processor_enable(master_processor);
151 }
152
153 /*
154 * Routine: host_self_trap [mach trap]
155 * Purpose:
156 * Give the caller send rights for his own host port.
157 * Conditions:
158 * Nothing locked.
159 * Returns:
160 * MACH_PORT_NULL if there are any resource failures
161 * or other errors.
162 */
163
164 mach_port_name_t
165 host_self_trap(
166 __unused struct host_self_trap_args *args)
167 {
168 ipc_port_t sright;
169 mach_port_name_t name;
170
171 sright = ipc_port_copy_send(current_task()->itk_host);
172 name = ipc_port_copyout_send(sright, current_space());
173 return name;
174 }
175
176 /*
177 * ipc_processor_init:
178 *
179 * Initialize ipc access to processor by allocating port.
180 */
181
182 void
183 ipc_processor_init(
184 processor_t processor)
185 {
186 ipc_port_t port;
187
188 port = ipc_port_alloc_kernel();
189 if (port == IP_NULL)
190 panic("ipc_processor_init");
191 processor->processor_self = port;
192 }
193
194 /*
195 * ipc_processor_enable:
196 *
197 * Enable ipc control of processor by setting port object.
198 */
199 void
200 ipc_processor_enable(
201 processor_t processor)
202 {
203 ipc_port_t myport;
204
205 myport = processor->processor_self;
206 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR);
207 }
208
209 /*
210 * ipc_processor_disable:
211 *
212 * Disable ipc control of processor by clearing port object.
213 */
214 void
215 ipc_processor_disable(
216 processor_t processor)
217 {
218 ipc_port_t myport;
219
220 myport = processor->processor_self;
221 if (myport == IP_NULL)
222 return;
223 ipc_kobject_set(myport, IKO_NULL, IKOT_NONE);
224 }
225
226 /*
227 * ipc_processor_terminate:
228 *
229 * Processor is off-line. Destroy ipc control port.
230 */
231 void
232 ipc_processor_terminate(
233 processor_t processor)
234 {
235 ipc_port_t myport;
236 spl_t s;
237
238 s = splsched();
239 processor_lock(processor);
240 myport = processor->processor_self;
241 if (myport == IP_NULL) {
242 processor_unlock(processor);
243 splx(s);
244 return;
245 }
246
247 processor->processor_self = IP_NULL;
248 processor_unlock(processor);
249 splx(s);
250
251 ipc_port_dealloc_kernel(myport);
252 }
253
254 /*
255 * ipc_pset_init:
256 *
257 * Initialize ipc control of a processor set by allocating its ports.
258 */
259
260 void
261 ipc_pset_init(
262 processor_set_t pset)
263 {
264 ipc_port_t port;
265
266 port = ipc_port_alloc_kernel();
267 if (port == IP_NULL)
268 panic("ipc_pset_init");
269 pset->pset_self = port;
270
271 port = ipc_port_alloc_kernel();
272 if (port == IP_NULL)
273 panic("ipc_pset_init");
274 pset->pset_name_self = port;
275 }
276
277 /*
278 * ipc_pset_enable:
279 *
280 * Enable ipc access to a processor set.
281 */
282 void
283 ipc_pset_enable(
284 processor_set_t pset)
285 {
286 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET);
287 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME);
288 }
289
290 /*
291 * processor_set_default:
292 *
293 * Return ports for manipulating default_processor set.
294 */
295 kern_return_t
296 processor_set_default(
297 host_t host,
298 processor_set_t *pset)
299 {
300 if (host == HOST_NULL)
301 return(KERN_INVALID_ARGUMENT);
302
303 *pset = &pset0;
304
305 return (KERN_SUCCESS);
306 }
307
308 /*
309 * Routine: convert_port_to_host
310 * Purpose:
311 * Convert from a port to a host.
312 * Doesn't consume the port ref; the host produced may be null.
313 * Conditions:
314 * Nothing locked.
315 */
316
317 host_t
318 convert_port_to_host(
319 ipc_port_t port)
320 {
321 host_t host = HOST_NULL;
322
323 if (IP_VALID(port)) {
324 ip_lock(port);
325 if (ip_active(port) &&
326 ((ip_kotype(port) == IKOT_HOST) ||
327 (ip_kotype(port) == IKOT_HOST_PRIV)
328 ))
329 host = (host_t) port->ip_kobject;
330 ip_unlock(port);
331 }
332
333 return host;
334 }
335
336 /*
337 * Routine: convert_port_to_host_priv
338 * Purpose:
339 * Convert from a port to a host.
340 * Doesn't consume the port ref; the host produced may be null.
341 * Conditions:
342 * Nothing locked.
343 */
344
345 host_t
346 convert_port_to_host_priv(
347 ipc_port_t port)
348 {
349 host_t host = HOST_NULL;
350
351 if (IP_VALID(port)) {
352 ip_lock(port);
353 if (ip_active(port) &&
354 (ip_kotype(port) == IKOT_HOST_PRIV))
355 host = (host_t) port->ip_kobject;
356 ip_unlock(port);
357 }
358
359 return host;
360 }
361
362 /*
363 * Routine: convert_port_to_processor
364 * Purpose:
365 * Convert from a port to a processor.
366 * Doesn't consume the port ref;
367 * the processor produced may be null.
368 * Conditions:
369 * Nothing locked.
370 */
371
372 processor_t
373 convert_port_to_processor(
374 ipc_port_t port)
375 {
376 processor_t processor = PROCESSOR_NULL;
377
378 if (IP_VALID(port)) {
379 ip_lock(port);
380 if (ip_active(port) &&
381 (ip_kotype(port) == IKOT_PROCESSOR))
382 processor = (processor_t) port->ip_kobject;
383 ip_unlock(port);
384 }
385
386 return processor;
387 }
388
389 /*
390 * Routine: convert_port_to_pset
391 * Purpose:
392 * Convert from a port to a pset.
393 * Doesn't consume the port ref; produces a pset ref,
394 * which may be null.
395 * Conditions:
396 * Nothing locked.
397 */
398
399 processor_set_t
400 convert_port_to_pset(
401 ipc_port_t port)
402 {
403 boolean_t r;
404 processor_set_t pset = PROCESSOR_SET_NULL;
405
406 r = FALSE;
407 while (!r && IP_VALID(port)) {
408 ip_lock(port);
409 r = ref_pset_port_locked(port, FALSE, &pset);
410 /* port unlocked */
411 }
412 return pset;
413 }
414
415 /*
416 * Routine: convert_port_to_pset_name
417 * Purpose:
418 * Convert from a port to a pset.
419 * Doesn't consume the port ref; produces a pset ref,
420 * which may be null.
421 * Conditions:
422 * Nothing locked.
423 */
424
425 processor_set_name_t
426 convert_port_to_pset_name(
427 ipc_port_t port)
428 {
429 boolean_t r;
430 processor_set_t pset = PROCESSOR_SET_NULL;
431
432 r = FALSE;
433 while (!r && IP_VALID(port)) {
434 ip_lock(port);
435 r = ref_pset_port_locked(port, TRUE, &pset);
436 /* port unlocked */
437 }
438 return pset;
439 }
440
441 boolean_t
442 ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset)
443 {
444 processor_set_t pset;
445
446 pset = PROCESSOR_SET_NULL;
447 if (ip_active(port) &&
448 ((ip_kotype(port) == IKOT_PSET) ||
449 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) {
450 pset = (processor_set_t) port->ip_kobject;
451 }
452
453 *ppset = pset;
454 ip_unlock(port);
455
456 return (TRUE);
457 }
458
459 /*
460 * Routine: convert_host_to_port
461 * Purpose:
462 * Convert from a host to a port.
463 * Produces a naked send right which may be invalid.
464 * Conditions:
465 * Nothing locked.
466 */
467
468 ipc_port_t
469 convert_host_to_port(
470 host_t host)
471 {
472 ipc_port_t port;
473
474 host_get_host_port(host, &port);
475 return port;
476 }
477
478 /*
479 * Routine: convert_processor_to_port
480 * Purpose:
481 * Convert from a processor to a port.
482 * Produces a naked send right which may be invalid.
483 * Conditions:
484 * Nothing locked.
485 */
486
487 ipc_port_t
488 convert_processor_to_port(
489 processor_t processor)
490 {
491 ipc_port_t port;
492 spl_t s;
493
494 s = splsched();
495 processor_lock(processor);
496
497 if (processor->processor_self != IP_NULL)
498 port = ipc_port_make_send(processor->processor_self);
499 else
500 port = IP_NULL;
501
502 processor_unlock(processor);
503 splx(s);
504
505 return port;
506 }
507
508 /*
509 * Routine: convert_pset_to_port
510 * Purpose:
511 * Convert from a pset to a port.
512 * Produces a naked send right
513 * which may be invalid.
514 * Conditions:
515 * Nothing locked.
516 */
517
518 ipc_port_t
519 convert_pset_to_port(
520 processor_set_t pset)
521 {
522 ipc_port_t port = pset->pset_self;
523
524 if (port != IP_NULL)
525 port = ipc_port_make_send(port);
526
527 return port;
528 }
529
530 /*
531 * Routine: convert_pset_name_to_port
532 * Purpose:
533 * Convert from a pset to a port.
534 * Produces a naked send right
535 * which may be invalid.
536 * Conditions:
537 * Nothing locked.
538 */
539
540 ipc_port_t
541 convert_pset_name_to_port(
542 processor_set_name_t pset)
543 {
544 ipc_port_t port = pset->pset_name_self;
545
546 if (port != IP_NULL)
547 port = ipc_port_make_send(port);
548
549 return port;
550 }
551
552 /*
553 * Routine: convert_port_to_host_security
554 * Purpose:
555 * Convert from a port to a host security.
556 * Doesn't consume the port ref; the port produced may be null.
557 * Conditions:
558 * Nothing locked.
559 */
560
561 host_t
562 convert_port_to_host_security(
563 ipc_port_t port)
564 {
565 host_t host = HOST_NULL;
566
567 if (IP_VALID(port)) {
568 ip_lock(port);
569 if (ip_active(port) &&
570 (ip_kotype(port) == IKOT_HOST_SECURITY))
571 host = (host_t) port->ip_kobject;
572 ip_unlock(port);
573 }
574
575 return host;
576 }
577
578 /*
579 * Routine: host_set_exception_ports [kernel call]
580 * Purpose:
581 * Sets the host exception port, flavor and
582 * behavior for the exception types specified by the mask.
583 * There will be one send right per exception per valid
584 * port.
585 * Conditions:
586 * Nothing locked. If successful, consumes
587 * the supplied send right.
588 * Returns:
589 * KERN_SUCCESS Changed the special port.
590 * KERN_INVALID_ARGUMENT The host_priv is not valid,
591 * Illegal mask bit set.
592 * Illegal exception behavior
593 */
594 kern_return_t
595 host_set_exception_ports(
596 host_priv_t host_priv,
597 exception_mask_t exception_mask,
598 ipc_port_t new_port,
599 exception_behavior_t new_behavior,
600 thread_state_flavor_t new_flavor)
601 {
602 register int i;
603 ipc_port_t old_port[EXC_TYPES_COUNT];
604
605 if (host_priv == HOST_PRIV_NULL) {
606 return KERN_INVALID_ARGUMENT;
607 }
608
609 assert(host_priv == &realhost);
610
611 if (exception_mask & ~EXC_MASK_ALL) {
612 return KERN_INVALID_ARGUMENT;
613 }
614
615 if (IP_VALID(new_port)) {
616 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
617 case EXCEPTION_DEFAULT:
618 case EXCEPTION_STATE:
619 case EXCEPTION_STATE_IDENTITY:
620 break;
621 default:
622 return KERN_INVALID_ARGUMENT;
623 }
624 }
625 /* Cannot easily check "new_flavor", but that just means that
626 * the flavor in the generated exception message might be garbage:
627 * GIGO
628 */
629 host_lock(host_priv);
630
631 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
632 if (exception_mask & (1 << i)) {
633 old_port[i] = host_priv->exc_actions[i].port;
634 host_priv->exc_actions[i].port =
635 ipc_port_copy_send(new_port);
636 host_priv->exc_actions[i].behavior = new_behavior;
637 host_priv->exc_actions[i].flavor = new_flavor;
638 } else
639 old_port[i] = IP_NULL;
640 }/* for */
641
642 /*
643 * Consume send rights without any lock held.
644 */
645 host_unlock(host_priv);
646 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
647 if (IP_VALID(old_port[i]))
648 ipc_port_release_send(old_port[i]);
649 if (IP_VALID(new_port)) /* consume send right */
650 ipc_port_release_send(new_port);
651
652 return KERN_SUCCESS;
653 }
654
655 /*
656 * Routine: host_get_exception_ports [kernel call]
657 * Purpose:
658 * Clones a send right for each of the host's exception
659 * ports specified in the mask and returns the behaviour
660 * and flavor of said port.
661 *
662 * Returns upto [in} CountCnt elements.
663 *
664 * Conditions:
665 * Nothing locked.
666 * Returns:
667 * KERN_SUCCESS Extracted a send right.
668 * KERN_INVALID_ARGUMENT Invalid host_priv specified,
669 * Invalid special port,
670 * Illegal mask bit set.
671 * KERN_FAILURE The thread is dead.
672 */
673 kern_return_t
674 host_get_exception_ports(
675 host_priv_t host_priv,
676 exception_mask_t exception_mask,
677 exception_mask_array_t masks,
678 mach_msg_type_number_t * CountCnt,
679 exception_port_array_t ports,
680 exception_behavior_array_t behaviors,
681 thread_state_flavor_array_t flavors )
682 {
683 unsigned int i, j, count;
684
685 if (host_priv == HOST_PRIV_NULL)
686 return KERN_INVALID_ARGUMENT;
687
688 if (exception_mask & ~EXC_MASK_ALL) {
689 return KERN_INVALID_ARGUMENT;
690 }
691
692 assert (host_priv == &realhost);
693
694 host_lock(host_priv);
695
696 count = 0;
697
698 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
699 if (exception_mask & (1 << i)) {
700 for (j = 0; j < count; j++) {
701 /*
702 * search for an identical entry, if found
703 * set corresponding mask for this exception.
704 */
705 if (host_priv->exc_actions[i].port == ports[j] &&
706 host_priv->exc_actions[i].behavior == behaviors[j]
707 && host_priv->exc_actions[i].flavor == flavors[j])
708 {
709 masks[j] |= (1 << i);
710 break;
711 }
712 }/* for */
713 if (j == count) {
714 masks[j] = (1 << i);
715 ports[j] =
716 ipc_port_copy_send(host_priv->exc_actions[i].port);
717 behaviors[j] = host_priv->exc_actions[i].behavior;
718 flavors[j] = host_priv->exc_actions[i].flavor;
719 count++;
720 if (count > *CountCnt) {
721 break;
722 }
723 }
724 }
725 }/* for */
726 host_unlock(host_priv);
727
728 *CountCnt = count;
729 return KERN_SUCCESS;
730 }
731
732 kern_return_t
733 host_swap_exception_ports(
734 host_priv_t host_priv,
735 exception_mask_t exception_mask,
736 ipc_port_t new_port,
737 exception_behavior_t new_behavior,
738 thread_state_flavor_t new_flavor,
739 exception_mask_array_t masks,
740 mach_msg_type_number_t * CountCnt,
741 exception_port_array_t ports,
742 exception_behavior_array_t behaviors,
743 thread_state_flavor_array_t flavors )
744 {
745 unsigned int i,
746 j,
747 count;
748 ipc_port_t old_port[EXC_TYPES_COUNT];
749
750 if (host_priv == HOST_PRIV_NULL)
751 return KERN_INVALID_ARGUMENT;
752
753 if (exception_mask & ~EXC_MASK_ALL) {
754 return KERN_INVALID_ARGUMENT;
755 }
756
757 if (IP_VALID(new_port)) {
758 switch (new_behavior) {
759 case EXCEPTION_DEFAULT:
760 case EXCEPTION_STATE:
761 case EXCEPTION_STATE_IDENTITY:
762 break;
763 default:
764 return KERN_INVALID_ARGUMENT;
765 }
766 }
767 /* Cannot easily check "new_flavor", but that just means that
768 * the flavor in the generated exception message might be garbage:
769 * GIGO */
770
771 host_lock(host_priv);
772
773 count = 0;
774
775 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
776 if (exception_mask & (1 << i)) {
777 for (j = 0; j < count; j++) {
778 /*
779 * search for an identical entry, if found
780 * set corresponding mask for this exception.
781 */
782 if (host_priv->exc_actions[i].port == ports[j] &&
783 host_priv->exc_actions[i].behavior == behaviors[j]
784 && host_priv->exc_actions[i].flavor == flavors[j])
785 {
786 masks[j] |= (1 << i);
787 break;
788 }
789 }/* for */
790 if (j == count) {
791 masks[j] = (1 << i);
792 ports[j] =
793 ipc_port_copy_send(host_priv->exc_actions[i].port);
794 behaviors[j] = host_priv->exc_actions[i].behavior;
795 flavors[j] = host_priv->exc_actions[i].flavor;
796 count++;
797 }
798 old_port[i] = host_priv->exc_actions[i].port;
799 host_priv->exc_actions[i].port =
800 ipc_port_copy_send(new_port);
801 host_priv->exc_actions[i].behavior = new_behavior;
802 host_priv->exc_actions[i].flavor = new_flavor;
803 if (count > *CountCnt) {
804 break;
805 }
806 } else
807 old_port[i] = IP_NULL;
808 }/* for */
809 host_unlock(host_priv);
810
811 /*
812 * Consume send rights without any lock held.
813 */
814 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
815 if (IP_VALID(old_port[i]))
816 ipc_port_release_send(old_port[i]);
817 if (IP_VALID(new_port)) /* consume send right */
818 ipc_port_release_send(new_port);
819 *CountCnt = count;
820
821 return KERN_SUCCESS;
822 }