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