]> git.saurik.com Git - apple/xnu.git/blob - osfmk/kern/ipc_host.c
73cc4d4d399224a91042670259023fcdb98906a1
[apple/xnu.git] / osfmk / kern / ipc_host.c
1 /*
2 * Copyright (c) 2000-2009 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/task.h>
71 #include <kern/thread.h>
72 #include <kern/ipc_host.h>
73 #include <kern/ipc_kobject.h>
74 #include <kern/misc_protos.h>
75 #include <kern/spl.h>
76 #include <ipc/ipc_port.h>
77 #include <ipc/ipc_space.h>
78
79 /*
80 * Forward declarations
81 */
82
83 boolean_t
84 ref_pset_port_locked(
85 ipc_port_t port, boolean_t matchn, processor_set_t *ppset);
86
87 /*
88 * ipc_host_init: set up various things.
89 */
90
91 extern lck_grp_t host_notify_lock_grp;
92 extern lck_attr_t host_notify_lock_attr;
93
94 void ipc_host_init(void)
95 {
96 ipc_port_t port;
97 int i;
98
99 lck_mtx_init(&realhost.lock, &host_notify_lock_grp, &host_notify_lock_attr);
100
101 /*
102 * Allocate and set up the two host ports.
103 */
104 port = ipc_port_alloc_kernel();
105 if (port == IP_NULL)
106 panic("ipc_host_init");
107
108 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_SECURITY);
109 kernel_set_special_port(&realhost, HOST_SECURITY_PORT,
110 ipc_port_make_send(port));
111
112 port = ipc_port_alloc_kernel();
113 if (port == IP_NULL)
114 panic("ipc_host_init");
115
116 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST);
117 kernel_set_special_port(&realhost, HOST_PORT,
118 ipc_port_make_send(port));
119
120 port = ipc_port_alloc_kernel();
121 if (port == IP_NULL)
122 panic("ipc_host_init");
123
124 ipc_kobject_set(port, (ipc_kobject_t) &realhost, IKOT_HOST_PRIV);
125 kernel_set_special_port(&realhost, HOST_PRIV_PORT,
126 ipc_port_make_send(port));
127
128 /* the rest of the special ports will be set up later */
129
130 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
131 realhost.exc_actions[i].port = IP_NULL;
132 }/* for */
133
134 /*
135 * Set up ipc for default processor set.
136 */
137 ipc_pset_init(&pset0);
138 ipc_pset_enable(&pset0);
139
140 /*
141 * And for master processor
142 */
143 ipc_processor_init(master_processor);
144 ipc_processor_enable(master_processor);
145 }
146
147 /*
148 * Routine: host_self_trap [mach trap]
149 * Purpose:
150 * Give the caller send rights for his own host port.
151 * Conditions:
152 * Nothing locked.
153 * Returns:
154 * MACH_PORT_NULL if there are any resource failures
155 * or other errors.
156 */
157
158 mach_port_name_t
159 host_self_trap(
160 __unused struct host_self_trap_args *args)
161 {
162 ipc_port_t sright;
163 mach_port_name_t name;
164
165 sright = ipc_port_copy_send(current_task()->itk_host);
166 name = ipc_port_copyout_send(sright, current_space());
167 return name;
168 }
169
170 /*
171 * ipc_processor_init:
172 *
173 * Initialize ipc access to processor by allocating port.
174 */
175
176 void
177 ipc_processor_init(
178 processor_t processor)
179 {
180 ipc_port_t port;
181
182 port = ipc_port_alloc_kernel();
183 if (port == IP_NULL)
184 panic("ipc_processor_init");
185 processor->processor_self = port;
186 }
187
188 /*
189 * ipc_processor_enable:
190 *
191 * Enable ipc control of processor by setting port object.
192 */
193 void
194 ipc_processor_enable(
195 processor_t processor)
196 {
197 ipc_port_t myport;
198
199 myport = processor->processor_self;
200 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR);
201 }
202
203 /*
204 * ipc_pset_init:
205 *
206 * Initialize ipc control of a processor set by allocating its ports.
207 */
208
209 void
210 ipc_pset_init(
211 processor_set_t pset)
212 {
213 ipc_port_t port;
214
215 port = ipc_port_alloc_kernel();
216 if (port == IP_NULL)
217 panic("ipc_pset_init");
218 pset->pset_self = port;
219
220 port = ipc_port_alloc_kernel();
221 if (port == IP_NULL)
222 panic("ipc_pset_init");
223 pset->pset_name_self = port;
224 }
225
226 /*
227 * ipc_pset_enable:
228 *
229 * Enable ipc access to a processor set.
230 */
231 void
232 ipc_pset_enable(
233 processor_set_t pset)
234 {
235 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET);
236 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME);
237 }
238
239 /*
240 * processor_set_default:
241 *
242 * Return ports for manipulating default_processor set.
243 */
244 kern_return_t
245 processor_set_default(
246 host_t host,
247 processor_set_t *pset)
248 {
249 if (host == HOST_NULL)
250 return(KERN_INVALID_ARGUMENT);
251
252 *pset = &pset0;
253
254 return (KERN_SUCCESS);
255 }
256
257 /*
258 * Routine: convert_port_to_host
259 * Purpose:
260 * Convert from a port to a host.
261 * Doesn't consume the port ref; the host produced may be null.
262 * Conditions:
263 * Nothing locked.
264 */
265
266 host_t
267 convert_port_to_host(
268 ipc_port_t port)
269 {
270 host_t host = HOST_NULL;
271
272 if (IP_VALID(port)) {
273 ip_lock(port);
274 if (ip_active(port) &&
275 ((ip_kotype(port) == IKOT_HOST) ||
276 (ip_kotype(port) == IKOT_HOST_PRIV)
277 ))
278 host = (host_t) port->ip_kobject;
279 ip_unlock(port);
280 }
281
282 return host;
283 }
284
285 /*
286 * Routine: convert_port_to_host_priv
287 * Purpose:
288 * Convert from a port to a host.
289 * Doesn't consume the port ref; the host produced may be null.
290 * Conditions:
291 * Nothing locked.
292 */
293
294 host_t
295 convert_port_to_host_priv(
296 ipc_port_t port)
297 {
298 host_t host = HOST_NULL;
299
300 if (IP_VALID(port)) {
301 ip_lock(port);
302 if (ip_active(port) &&
303 (ip_kotype(port) == IKOT_HOST_PRIV))
304 host = (host_t) port->ip_kobject;
305 ip_unlock(port);
306 }
307
308 return host;
309 }
310
311 /*
312 * Routine: convert_port_to_processor
313 * Purpose:
314 * Convert from a port to a processor.
315 * Doesn't consume the port ref;
316 * the processor produced may be null.
317 * Conditions:
318 * Nothing locked.
319 */
320
321 processor_t
322 convert_port_to_processor(
323 ipc_port_t port)
324 {
325 processor_t processor = PROCESSOR_NULL;
326
327 if (IP_VALID(port)) {
328 ip_lock(port);
329 if (ip_active(port) &&
330 (ip_kotype(port) == IKOT_PROCESSOR))
331 processor = (processor_t) port->ip_kobject;
332 ip_unlock(port);
333 }
334
335 return processor;
336 }
337
338 /*
339 * Routine: convert_port_to_pset
340 * Purpose:
341 * Convert from a port to a pset.
342 * Doesn't consume the port ref; produces a pset ref,
343 * which may be null.
344 * Conditions:
345 * Nothing locked.
346 */
347
348 processor_set_t
349 convert_port_to_pset(
350 ipc_port_t port)
351 {
352 boolean_t r;
353 processor_set_t pset = PROCESSOR_SET_NULL;
354
355 r = FALSE;
356 while (!r && IP_VALID(port)) {
357 ip_lock(port);
358 r = ref_pset_port_locked(port, FALSE, &pset);
359 /* port unlocked */
360 }
361 return pset;
362 }
363
364 /*
365 * Routine: convert_port_to_pset_name
366 * Purpose:
367 * Convert from a port to a pset.
368 * Doesn't consume the port ref; produces a pset ref,
369 * which may be null.
370 * Conditions:
371 * Nothing locked.
372 */
373
374 processor_set_name_t
375 convert_port_to_pset_name(
376 ipc_port_t port)
377 {
378 boolean_t r;
379 processor_set_t pset = PROCESSOR_SET_NULL;
380
381 r = FALSE;
382 while (!r && IP_VALID(port)) {
383 ip_lock(port);
384 r = ref_pset_port_locked(port, TRUE, &pset);
385 /* port unlocked */
386 }
387 return pset;
388 }
389
390 boolean_t
391 ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset)
392 {
393 processor_set_t pset;
394
395 pset = PROCESSOR_SET_NULL;
396 if (ip_active(port) &&
397 ((ip_kotype(port) == IKOT_PSET) ||
398 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) {
399 pset = (processor_set_t) port->ip_kobject;
400 }
401
402 *ppset = pset;
403 ip_unlock(port);
404
405 return (TRUE);
406 }
407
408 /*
409 * Routine: convert_host_to_port
410 * Purpose:
411 * Convert from a host to a port.
412 * Produces a naked send right which may be invalid.
413 * Conditions:
414 * Nothing locked.
415 */
416
417 ipc_port_t
418 convert_host_to_port(
419 host_t host)
420 {
421 ipc_port_t port;
422
423 host_get_host_port(host, &port);
424 return port;
425 }
426
427 /*
428 * Routine: convert_processor_to_port
429 * Purpose:
430 * Convert from a processor to a port.
431 * Produces a naked send right which may be invalid.
432 * Processors are not reference counted, so nothing to release.
433 * Conditions:
434 * Nothing locked.
435 */
436
437 ipc_port_t
438 convert_processor_to_port(
439 processor_t processor)
440 {
441 ipc_port_t port = processor->processor_self;
442
443 if (port != IP_NULL)
444 port = ipc_port_make_send(port);
445 return port;
446 }
447
448 /*
449 * Routine: convert_pset_to_port
450 * Purpose:
451 * Convert from a pset to a port.
452 * Produces a naked send right which may be invalid.
453 * Processor sets are not reference counted, so nothing to release.
454 * Conditions:
455 * Nothing locked.
456 */
457
458 ipc_port_t
459 convert_pset_to_port(
460 processor_set_t pset)
461 {
462 ipc_port_t port = pset->pset_self;
463
464 if (port != IP_NULL)
465 port = ipc_port_make_send(port);
466
467 return port;
468 }
469
470 /*
471 * Routine: convert_pset_name_to_port
472 * Purpose:
473 * Convert from a pset to a port.
474 * Produces a naked send right which may be invalid.
475 * Processor sets are not reference counted, so nothing to release.
476 * Conditions:
477 * Nothing locked.
478 */
479
480 ipc_port_t
481 convert_pset_name_to_port(
482 processor_set_name_t pset)
483 {
484 ipc_port_t port = pset->pset_name_self;
485
486 if (port != IP_NULL)
487 port = ipc_port_make_send(port);
488
489 return port;
490 }
491
492 /*
493 * Routine: convert_port_to_host_security
494 * Purpose:
495 * Convert from a port to a host security.
496 * Doesn't consume the port ref; the port produced may be null.
497 * Conditions:
498 * Nothing locked.
499 */
500
501 host_t
502 convert_port_to_host_security(
503 ipc_port_t port)
504 {
505 host_t host = HOST_NULL;
506
507 if (IP_VALID(port)) {
508 ip_lock(port);
509 if (ip_active(port) &&
510 (ip_kotype(port) == IKOT_HOST_SECURITY))
511 host = (host_t) port->ip_kobject;
512 ip_unlock(port);
513 }
514
515 return host;
516 }
517
518 /*
519 * Routine: host_set_exception_ports [kernel call]
520 * Purpose:
521 * Sets the host exception port, flavor and
522 * behavior for the exception types specified by the mask.
523 * There will be one send right per exception per valid
524 * port.
525 * Conditions:
526 * Nothing locked. If successful, consumes
527 * the supplied send right.
528 * Returns:
529 * KERN_SUCCESS Changed the special port.
530 * KERN_INVALID_ARGUMENT The host_priv is not valid,
531 * Illegal mask bit set.
532 * Illegal exception behavior
533 */
534 kern_return_t
535 host_set_exception_ports(
536 host_priv_t host_priv,
537 exception_mask_t exception_mask,
538 ipc_port_t new_port,
539 exception_behavior_t new_behavior,
540 thread_state_flavor_t new_flavor)
541 {
542 register int i;
543 ipc_port_t old_port[EXC_TYPES_COUNT];
544
545 if (host_priv == HOST_PRIV_NULL) {
546 return KERN_INVALID_ARGUMENT;
547 }
548
549 assert(host_priv == &realhost);
550
551 if (exception_mask & ~EXC_MASK_VALID) {
552 return KERN_INVALID_ARGUMENT;
553 }
554
555 if (IP_VALID(new_port)) {
556 switch (new_behavior & ~MACH_EXCEPTION_CODES) {
557 case EXCEPTION_DEFAULT:
558 case EXCEPTION_STATE:
559 case EXCEPTION_STATE_IDENTITY:
560 break;
561 default:
562 return KERN_INVALID_ARGUMENT;
563 }
564 }
565
566 /*
567 * Check the validity of the thread_state_flavor by calling the
568 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in
569 * osfmk/mach/ARCHITECTURE/thread_status.h
570 */
571 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
572 return (KERN_INVALID_ARGUMENT);
573
574 host_lock(host_priv);
575
576 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
577 if (exception_mask & (1 << i)) {
578 old_port[i] = host_priv->exc_actions[i].port;
579 host_priv->exc_actions[i].port =
580 ipc_port_copy_send(new_port);
581 host_priv->exc_actions[i].behavior = new_behavior;
582 host_priv->exc_actions[i].flavor = new_flavor;
583 } else
584 old_port[i] = IP_NULL;
585 }/* for */
586
587 /*
588 * Consume send rights without any lock held.
589 */
590 host_unlock(host_priv);
591 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++)
592 if (IP_VALID(old_port[i]))
593 ipc_port_release_send(old_port[i]);
594 if (IP_VALID(new_port)) /* consume send right */
595 ipc_port_release_send(new_port);
596
597 return KERN_SUCCESS;
598 }
599
600 /*
601 * Routine: host_get_exception_ports [kernel call]
602 * Purpose:
603 * Clones a send right for each of the host's exception
604 * ports specified in the mask and returns the behaviour
605 * and flavor of said port.
606 *
607 * Returns upto [in} CountCnt elements.
608 *
609 * Conditions:
610 * Nothing locked.
611 * Returns:
612 * KERN_SUCCESS Extracted a send right.
613 * KERN_INVALID_ARGUMENT Invalid host_priv specified,
614 * Invalid special port,
615 * Illegal mask bit set.
616 * KERN_FAILURE The thread is dead.
617 */
618 kern_return_t
619 host_get_exception_ports(
620 host_priv_t host_priv,
621 exception_mask_t exception_mask,
622 exception_mask_array_t masks,
623 mach_msg_type_number_t * CountCnt,
624 exception_port_array_t ports,
625 exception_behavior_array_t behaviors,
626 thread_state_flavor_array_t flavors )
627 {
628 unsigned int i, j, count;
629
630 if (host_priv == HOST_PRIV_NULL)
631 return KERN_INVALID_ARGUMENT;
632
633 if (exception_mask & ~EXC_MASK_VALID) {
634 return KERN_INVALID_ARGUMENT;
635 }
636
637 assert (host_priv == &realhost);
638
639 host_lock(host_priv);
640
641 count = 0;
642
643 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) {
644 if (exception_mask & (1 << i)) {
645 for (j = 0; j < count; j++) {
646 /*
647 * search for an identical entry, if found
648 * set corresponding mask for this exception.
649 */
650 if (host_priv->exc_actions[i].port == ports[j] &&
651 host_priv->exc_actions[i].behavior == behaviors[j]
652 && host_priv->exc_actions[i].flavor == flavors[j])
653 {
654 masks[j] |= (1 << i);
655 break;
656 }
657 }/* for */
658 if (j == count) {
659 masks[j] = (1 << i);
660 ports[j] =
661 ipc_port_copy_send(host_priv->exc_actions[i].port);
662 behaviors[j] = host_priv->exc_actions[i].behavior;
663 flavors[j] = host_priv->exc_actions[i].flavor;
664 count++;
665 if (count > *CountCnt) {
666 break;
667 }
668 }
669 }
670 }/* for */
671 host_unlock(host_priv);
672
673 *CountCnt = count;
674 return KERN_SUCCESS;
675 }
676
677 kern_return_t
678 host_swap_exception_ports(
679 host_priv_t host_priv,
680 exception_mask_t exception_mask,
681 ipc_port_t new_port,
682 exception_behavior_t new_behavior,
683 thread_state_flavor_t new_flavor,
684 exception_mask_array_t masks,
685 mach_msg_type_number_t * CountCnt,
686 exception_port_array_t ports,
687 exception_behavior_array_t behaviors,
688 thread_state_flavor_array_t flavors )
689 {
690 unsigned int i,
691 j,
692 count;
693 ipc_port_t old_port[EXC_TYPES_COUNT];
694
695 if (host_priv == HOST_PRIV_NULL)
696 return KERN_INVALID_ARGUMENT;
697
698 if (exception_mask & ~EXC_MASK_VALID) {
699 return KERN_INVALID_ARGUMENT;
700 }
701
702 if (IP_VALID(new_port)) {
703 switch (new_behavior) {
704 case EXCEPTION_DEFAULT:
705 case EXCEPTION_STATE:
706 case EXCEPTION_STATE_IDENTITY:
707 break;
708 default:
709 return KERN_INVALID_ARGUMENT;
710 }
711 }
712
713 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor))
714 return (KERN_INVALID_ARGUMENT);
715
716 host_lock(host_priv);
717
718 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION);
719 for (count=0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) {
720 if (exception_mask & (1 << i)) {
721 for (j = 0; j < count; j++) {
722 /*
723 * search for an identical entry, if found
724 * set corresponding mask for this exception.
725 */
726 if (host_priv->exc_actions[i].port == ports[j] &&
727 host_priv->exc_actions[i].behavior == behaviors[j]
728 && host_priv->exc_actions[i].flavor == flavors[j])
729 {
730 masks[j] |= (1 << i);
731 break;
732 }
733 }/* for */
734 if (j == count) {
735 masks[j] = (1 << i);
736 ports[j] =
737 ipc_port_copy_send(host_priv->exc_actions[i].port);
738 behaviors[j] = host_priv->exc_actions[i].behavior;
739 flavors[j] = host_priv->exc_actions[i].flavor;
740 count++;
741 }
742 old_port[i] = host_priv->exc_actions[i].port;
743 host_priv->exc_actions[i].port =
744 ipc_port_copy_send(new_port);
745 host_priv->exc_actions[i].behavior = new_behavior;
746 host_priv->exc_actions[i].flavor = new_flavor;
747 } else
748 old_port[i] = IP_NULL;
749 }/* for */
750 host_unlock(host_priv);
751
752 /*
753 * Consume send rights without any lock held.
754 */
755 while (--i >= FIRST_EXCEPTION) {
756 if (IP_VALID(old_port[i]))
757 ipc_port_release_send(old_port[i]);
758 }
759
760 if (IP_VALID(new_port)) /* consume send right */
761 ipc_port_release_send(new_port);
762 *CountCnt = count;
763
764 return KERN_SUCCESS;
765 }