]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/ipc_host.c
xnu-344.32.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 *
de355530
A
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.
1c79356b 11 *
de355530
A
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
1c79356b
A
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
de355530
A
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.
1c79356b
A
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>
0b4e3aa0 60#include <mach/etap_events.h>
1c79356b
A
61#include <mach/mach_host_server.h>
62#include <kern/host.h>
63#include <kern/processor.h>
0b4e3aa0 64#include <kern/lock.h>
1c79356b
A
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
78void
79ipc_processor_terminate(
80 processor_t processor);
81
82void
83ipc_processor_disable(
84 processor_t processor);
85
86boolean_t
87ref_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
94void ipc_host_init(void)
95{
96 ipc_port_t port;
97 int i;
98
0b4e3aa0
A
99 mutex_init(&realhost.lock, ETAP_MISC_MASTER);
100
1c79356b
A
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
155mach_port_name_t
156host_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
170void
171ipc_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 */
187void
188ipc_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 */
202void
203ipc_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 */
219void
220ipc_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
248void
249ipc_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 */
270void
271ipc_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 */
292void
293ipc_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 */
306void
307ipc_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 */
320kern_return_t
321processor_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
342host_t
343convert_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
370host_t
371convert_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
397processor_t
398convert_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
424processor_set_t
425convert_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
450processor_set_name_t
451convert_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
466boolean_t
467ref_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
498ipc_port_t
499convert_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
518ipc_port_t
519convert_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
549ipc_port_t
550convert_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
576ipc_port_t
577convert_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
602host_t
603convert_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 */
635kern_return_t
636host_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 */
714kern_return_t
715host_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
775kern_return_t
776host_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}