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