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