]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_object.c
xnu-344.21.74.tar.gz
[apple/xnu.git] / osfmk / ipc / ipc_object.c
CommitLineData
1c79356b
A
1/*
2 * Copyright (c) 2000 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
d7e50217 6 * Copyright (c) 1999-2003 Apple Computer, Inc. All Rights Reserved.
1c79356b 7 *
d7e50217
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,
d7e50217
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 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 * File: ipc/ipc_object.c
57 * Author: Rich Draves
58 * Date: 1989
59 *
60 * Functions to manipulate IPC objects.
61 */
62
63#include <mach_rt.h>
64
65#include <mach/boolean.h>
66#include <mach/kern_return.h>
67#include <mach/port.h>
68#include <mach/message.h>
69#include <kern/misc_protos.h>
70#include <ipc/port.h>
71#include <ipc/ipc_space.h>
72#include <ipc/ipc_entry.h>
73#include <ipc/ipc_object.h>
74#include <ipc/ipc_hash.h>
75#include <ipc/ipc_right.h>
76#include <ipc/ipc_notify.h>
77#include <ipc/ipc_pset.h>
78
79zone_t ipc_object_zones[IOT_NUMBER];
80
81/*
82 * Routine: ipc_object_reference
83 * Purpose:
84 * Take a reference to an object.
85 */
86
87void
88ipc_object_reference(
89 ipc_object_t object)
90{
91 io_lock(object);
92 assert(object->io_references > 0);
93 io_reference(object);
94 io_unlock(object);
95}
96
97/*
98 * Routine: ipc_object_release
99 * Purpose:
100 * Release a reference to an object.
101 */
102
103void
104ipc_object_release(
105 ipc_object_t object)
106{
107 io_lock(object);
108 assert(object->io_references > 0);
109 io_release(object);
110 io_check_unlock(object);
111}
112
113/*
114 * Routine: ipc_object_translate
115 * Purpose:
116 * Look up an object in a space.
117 * Conditions:
118 * Nothing locked before. If successful, the object
119 * is returned locked. The caller doesn't get a ref.
120 * Returns:
121 * KERN_SUCCESS Object returned locked.
122 * KERN_INVALID_TASK The space is dead.
123 * KERN_INVALID_NAME The name doesn't denote a right.
124 * KERN_INVALID_RIGHT Name doesn't denote the correct right.
125 */
126
127kern_return_t
128ipc_object_translate(
129 ipc_space_t space,
130 mach_port_name_t name,
131 mach_port_right_t right,
132 ipc_object_t *objectp)
133{
134 ipc_entry_t entry;
135 ipc_object_t object;
136 kern_return_t kr;
137
138 kr = ipc_right_lookup_read(space, name, &entry);
139 if (kr != KERN_SUCCESS)
140 return kr;
141 /* space is read-locked and active */
142
143 if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) {
144 is_read_unlock(space);
145 return KERN_INVALID_RIGHT;
146 }
147
148 object = entry->ie_object;
149 assert(object != IO_NULL);
150
151 io_lock(object);
152 is_read_unlock(space);
153
154 *objectp = object;
155 return KERN_SUCCESS;
156}
157
158/*
159 * Routine: ipc_object_translate_two
160 * Purpose:
161 * Look up two objects in a space.
162 * Conditions:
163 * Nothing locked before. If successful, the objects
164 * are returned locked. The caller doesn't get a ref.
165 * Returns:
166 * KERN_SUCCESS Objects returned locked.
167 * KERN_INVALID_TASK The space is dead.
168 * KERN_INVALID_NAME A name doesn't denote a right.
169 * KERN_INVALID_RIGHT A name doesn't denote the correct right.
170 */
171
172kern_return_t
173ipc_object_translate_two(
174 ipc_space_t space,
175 mach_port_name_t name1,
176 mach_port_right_t right1,
177 ipc_object_t *objectp1,
178 mach_port_name_t name2,
179 mach_port_right_t right2,
180 ipc_object_t *objectp2)
181{
182 ipc_entry_t entry1;
183 ipc_entry_t entry2;
184 ipc_object_t object;
185 kern_return_t kr;
186
187 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2);
188 if (kr != KERN_SUCCESS)
189 return kr;
190 /* space is read-locked and active */
191
192 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) {
193 is_read_unlock(space);
194 return KERN_INVALID_RIGHT;
195 }
196
197 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) {
198 is_read_unlock(space);
199 return KERN_INVALID_RIGHT;
200 }
201
202 object = entry1->ie_object;
203 assert(object != IO_NULL);
204 io_lock(object);
205 *objectp1 = object;
206
207 object = entry2->ie_object;
208 assert(object != IO_NULL);
209 io_lock(object);
210 *objectp2 = object;
211
212 is_read_unlock(space);
213 return KERN_SUCCESS;
214}
215
216/*
217 * Routine: ipc_object_alloc_dead
218 * Purpose:
219 * Allocate a dead-name entry.
220 * Conditions:
221 * Nothing locked.
222 * Returns:
223 * KERN_SUCCESS The dead name is allocated.
224 * KERN_INVALID_TASK The space is dead.
225 * KERN_NO_SPACE No room for an entry in the space.
226 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
227 */
228
229kern_return_t
230ipc_object_alloc_dead(
231 ipc_space_t space,
232 mach_port_name_t *namep)
233{
234 ipc_entry_t entry;
235 kern_return_t kr;
236
237 int i;
238
239
240 kr = ipc_entry_alloc(space, namep, &entry);
241 if (kr != KERN_SUCCESS)
242 return kr;
243 /* space is write-locked */
244
245 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
246
247 assert(entry->ie_object == IO_NULL);
248 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
249
250 is_write_unlock(space);
251 return KERN_SUCCESS;
252}
253
254/*
255 * Routine: ipc_object_alloc_dead_name
256 * Purpose:
257 * Allocate a dead-name entry, with a specific name.
258 * Conditions:
259 * Nothing locked.
260 * Returns:
261 * KERN_SUCCESS The dead name is allocated.
262 * KERN_INVALID_TASK The space is dead.
263 * KERN_NAME_EXISTS The name already denotes a right.
264 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
265 */
266
267kern_return_t
268ipc_object_alloc_dead_name(
269 ipc_space_t space,
270 mach_port_name_t name)
271{
272 ipc_entry_t entry;
273 kern_return_t kr;
274
275 int i;
276
277
278 kr = ipc_entry_alloc_name(space, name, &entry);
279 if (kr != KERN_SUCCESS)
280 return kr;
281 /* space is write-locked */
282
283 if (ipc_right_inuse(space, name, entry))
284 return KERN_NAME_EXISTS;
285
286 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */
287
288 assert(entry->ie_object == IO_NULL);
289 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1;
290
291 is_write_unlock(space);
292 return KERN_SUCCESS;
293}
294
295/*
296 * Routine: ipc_object_alloc
297 * Purpose:
298 * Allocate an object.
299 * Conditions:
300 * Nothing locked. If successful, the object is returned locked.
301 * The caller doesn't get a reference for the object.
302 * Returns:
303 * KERN_SUCCESS The object is allocated.
304 * KERN_INVALID_TASK The space is dead.
305 * KERN_NO_SPACE No room for an entry in the space.
306 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
307 */
308
309kern_return_t
310ipc_object_alloc(
311 ipc_space_t space,
312 ipc_object_type_t otype,
313 mach_port_type_t type,
314 mach_port_urefs_t urefs,
315 mach_port_name_t *namep,
316 ipc_object_t *objectp)
317{
318 ipc_object_t object;
319 ipc_entry_t entry;
320 kern_return_t kr;
321
322 assert(otype < IOT_NUMBER);
323 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
324 assert(type != MACH_PORT_TYPE_NONE);
325 assert(urefs <= MACH_PORT_UREFS_MAX);
326
327 object = io_alloc(otype);
328 if (object == IO_NULL)
329 return KERN_RESOURCE_SHORTAGE;
330
331 if (otype == IOT_PORT) {
332 ipc_port_t port = (ipc_port_t)object;
333
334 bzero((char *)port, sizeof(*port));
335 } else if (otype == IOT_PORT_SET) {
336 ipc_pset_t pset = (ipc_pset_t)object;
337
338 bzero((char *)pset, sizeof(*pset));
339 }
340
341 io_lock_init(object);
342 *namep = (mach_port_name_t)object;
343 kr = ipc_entry_alloc(space, namep, &entry);
344 if (kr != KERN_SUCCESS) {
345 io_free(otype, object);
346 return kr;
347 }
348 /* space is write-locked */
349
350 entry->ie_bits |= type | urefs;
351 entry->ie_object = object;
352
353 io_lock(object);
354 is_write_unlock(space);
355
356 object->io_references = 1; /* for entry, not caller */
357 object->io_bits = io_makebits(TRUE, otype, 0);
358
359 *objectp = object;
360 return KERN_SUCCESS;
361}
362
363/*
364 * Routine: ipc_object_alloc_name
365 * Purpose:
366 * Allocate an object, with a specific name.
367 * Conditions:
368 * Nothing locked. If successful, the object is returned locked.
369 * The caller doesn't get a reference for the object.
370 * Returns:
371 * KERN_SUCCESS The object is allocated.
372 * KERN_INVALID_TASK The space is dead.
373 * KERN_NAME_EXISTS The name already denotes a right.
374 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory.
375 */
376
377kern_return_t
378ipc_object_alloc_name(
379 ipc_space_t space,
380 ipc_object_type_t otype,
381 mach_port_type_t type,
382 mach_port_urefs_t urefs,
383 mach_port_name_t name,
384 ipc_object_t *objectp)
385{
386 ipc_object_t object;
387 ipc_entry_t entry;
388 kern_return_t kr;
389
390 assert(otype < IOT_NUMBER);
391 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type);
392 assert(type != MACH_PORT_TYPE_NONE);
393 assert(urefs <= MACH_PORT_UREFS_MAX);
394
395 object = io_alloc(otype);
396 if (object == IO_NULL)
397 return KERN_RESOURCE_SHORTAGE;
398
399 if (otype == IOT_PORT) {
400 ipc_port_t port = (ipc_port_t)object;
401
402 bzero((char *)port, sizeof(*port));
403 } else if (otype == IOT_PORT_SET) {
404 ipc_pset_t pset = (ipc_pset_t)object;
405
406 bzero((char *)pset, sizeof(*pset));
407 }
408
409 io_lock_init(object);
410 kr = ipc_entry_alloc_name(space, name, &entry);
411 if (kr != KERN_SUCCESS) {
412 io_free(otype, object);
413 return kr;
414 }
415 /* space is write-locked */
416
417 if (ipc_right_inuse(space, name, entry)) {
418 io_free(otype, object);
419 return KERN_NAME_EXISTS;
420 }
421
422 entry->ie_bits |= type | urefs;
423 entry->ie_object = object;
424
425 io_lock(object);
426 is_write_unlock(space);
427
428 object->io_references = 1; /* for entry, not caller */
429 object->io_bits = io_makebits(TRUE, otype, 0);
430
431 *objectp = object;
432 return KERN_SUCCESS;
433}
434
435/*
436 * Routine: ipc_object_copyin_type
437 * Purpose:
438 * Convert a send type name to a received type name.
439 */
440
441mach_msg_type_name_t
442ipc_object_copyin_type(
443 mach_msg_type_name_t msgt_name)
444{
445 switch (msgt_name) {
446
447 case MACH_MSG_TYPE_MOVE_RECEIVE:
448 case MACH_MSG_TYPE_COPY_RECEIVE:
449 return MACH_MSG_TYPE_PORT_RECEIVE;
450
451 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
452 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
453 return MACH_MSG_TYPE_PORT_SEND_ONCE;
454
455 case MACH_MSG_TYPE_MOVE_SEND:
456 case MACH_MSG_TYPE_MAKE_SEND:
457 case MACH_MSG_TYPE_COPY_SEND:
458 return MACH_MSG_TYPE_PORT_SEND;
459
460 default:
461 return MACH_MSG_TYPE_PORT_NONE;
462 }
463}
464
465/*
466 * Routine: ipc_object_copyin
467 * Purpose:
468 * Copyin a capability from a space.
469 * If successful, the caller gets a ref
470 * for the resulting object, unless it is IO_DEAD.
471 * Conditions:
472 * Nothing locked.
473 * Returns:
474 * KERN_SUCCESS Acquired an object, possibly IO_DEAD.
475 * KERN_INVALID_TASK The space is dead.
476 * KERN_INVALID_NAME Name doesn't exist in space.
477 * KERN_INVALID_RIGHT Name doesn't denote correct right.
478 */
479
480kern_return_t
481ipc_object_copyin(
482 ipc_space_t space,
483 mach_port_name_t name,
484 mach_msg_type_name_t msgt_name,
485 ipc_object_t *objectp)
486{
487 ipc_entry_t entry;
488 ipc_port_t soright;
489 kern_return_t kr;
490
491 int i;
492
493 /*
494 * Could first try a read lock when doing
495 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND,
496 * and MACH_MSG_TYPE_MAKE_SEND_ONCE.
497 */
498
499 kr = ipc_right_lookup_write(space, name, &entry);
500 if (kr != KERN_SUCCESS)
501 return kr;
502 /* space is write-locked and active */
503
504 kr = ipc_right_copyin(space, name, entry,
505 msgt_name, TRUE,
506 objectp, &soright);
507 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
508 ipc_entry_dealloc(space, name, entry);
509 is_write_unlock(space);
510
511 if ((kr == KERN_SUCCESS) && (soright != IP_NULL))
512 ipc_notify_port_deleted(soright, name);
513
514 return kr;
515}
516
517/*
518 * Routine: ipc_object_copyin_from_kernel
519 * Purpose:
520 * Copyin a naked capability from the kernel.
521 *
522 * MACH_MSG_TYPE_MOVE_RECEIVE
523 * The receiver must be ipc_space_kernel.
524 * Consumes the naked receive right.
525 * MACH_MSG_TYPE_COPY_SEND
526 * A naked send right must be supplied.
527 * The port gains a reference, and a send right
528 * if the port is still active.
529 * MACH_MSG_TYPE_MAKE_SEND
530 * The receiver must be ipc_space_kernel.
531 * The port gains a reference and a send right.
532 * MACH_MSG_TYPE_MOVE_SEND
533 * Consumes a naked send right.
534 * MACH_MSG_TYPE_MAKE_SEND_ONCE
535 * The port gains a reference and a send-once right.
536 * Receiver also be the caller of device subsystem,
537 * so no assertion.
538 * MACH_MSG_TYPE_MOVE_SEND_ONCE
539 * Consumes a naked send-once right.
540 * Conditions:
541 * Nothing locked.
542 */
543
544void
545ipc_object_copyin_from_kernel(
546 ipc_object_t object,
547 mach_msg_type_name_t msgt_name)
548{
549 assert(IO_VALID(object));
550
551 switch (msgt_name) {
552 case MACH_MSG_TYPE_MOVE_RECEIVE: {
553 ipc_port_t port = (ipc_port_t) object;
554
555 ip_lock(port);
556 assert(ip_active(port));
557 assert(port->ip_receiver_name != MACH_PORT_NULL);
558 assert(port->ip_receiver == ipc_space_kernel);
559
560 /* relevant part of ipc_port_clear_receiver */
561 ipc_port_set_mscount(port, 0);
562
563 port->ip_receiver_name = MACH_PORT_NULL;
564 port->ip_destination = IP_NULL;
565 ip_unlock(port);
566 break;
567 }
568
569 case MACH_MSG_TYPE_COPY_SEND: {
570 ipc_port_t port = (ipc_port_t) object;
571
572 ip_lock(port);
573 if (ip_active(port)) {
574 assert(port->ip_srights > 0);
575 port->ip_srights++;
576 }
577 ip_reference(port);
578 ip_unlock(port);
579 break;
580 }
581
582 case MACH_MSG_TYPE_MAKE_SEND: {
583 ipc_port_t port = (ipc_port_t) object;
584
585 ip_lock(port);
586 assert(ip_active(port));
587 assert(port->ip_receiver_name != MACH_PORT_NULL);
588 assert(port->ip_receiver == ipc_space_kernel);
589
590 ip_reference(port);
591 port->ip_mscount++;
592 port->ip_srights++;
593 ip_unlock(port);
594 break;
595 }
596
597 case MACH_MSG_TYPE_MOVE_SEND:
598 /* move naked send right into the message */
599 break;
600
601 case MACH_MSG_TYPE_MAKE_SEND_ONCE: {
602 ipc_port_t port = (ipc_port_t) object;
603
604 ip_lock(port);
605 assert(ip_active(port));
606 assert(port->ip_receiver_name != MACH_PORT_NULL);
607
608 ip_reference(port);
609 port->ip_sorights++;
610 ip_unlock(port);
611 break;
612 }
613
614 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
615 /* move naked send-once right into the message */
616 break;
617
618 default:
619 panic("ipc_object_copyin_from_kernel: strange rights");
620 }
621}
622
623/*
624 * Routine: ipc_object_destroy
625 * Purpose:
626 * Destroys a naked capability.
627 * Consumes a ref for the object.
628 *
629 * A receive right should be in limbo or in transit.
630 * Conditions:
631 * Nothing locked.
632 */
633
634void
635ipc_object_destroy(
636 ipc_object_t object,
637 mach_msg_type_name_t msgt_name)
638{
639 assert(IO_VALID(object));
640 assert(io_otype(object) == IOT_PORT);
641
642 switch (msgt_name) {
643 case MACH_MSG_TYPE_PORT_SEND:
644 ipc_port_release_send((ipc_port_t) object);
645 break;
646
647 case MACH_MSG_TYPE_PORT_SEND_ONCE:
648 ipc_notify_send_once((ipc_port_t) object);
649 break;
650
651 case MACH_MSG_TYPE_PORT_RECEIVE:
652 ipc_port_release_receive((ipc_port_t) object);
653 break;
654
655 default:
656 panic("ipc_object_destroy: strange rights");
657 }
658}
659
660/*
661 * Routine: ipc_object_copyout
662 * Purpose:
663 * Copyout a capability, placing it into a space.
664 * If successful, consumes a ref for the object.
665 * Conditions:
666 * Nothing locked.
667 * Returns:
668 * KERN_SUCCESS Copied out object, consumed ref.
669 * KERN_INVALID_TASK The space is dead.
670 * KERN_INVALID_CAPABILITY The object is dead.
671 * KERN_NO_SPACE No room in space for another right.
672 * KERN_RESOURCE_SHORTAGE No memory available.
673 * KERN_UREFS_OVERFLOW Urefs limit exceeded
674 * and overflow wasn't specified.
675 */
676
677kern_return_t
678ipc_object_copyout(
679 ipc_space_t space,
680 ipc_object_t object,
681 mach_msg_type_name_t msgt_name,
682 boolean_t overflow,
683 mach_port_name_t *namep)
684{
685 mach_port_name_t name;
686 ipc_entry_t entry;
687 kern_return_t kr;
688
689 assert(IO_VALID(object));
690 assert(io_otype(object) == IOT_PORT);
691
692 is_write_lock(space);
693
694 for (;;) {
695 if (!space->is_active) {
696 is_write_unlock(space);
697 return KERN_INVALID_TASK;
698 }
699
700 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
701 ipc_right_reverse(space, object, &name, &entry)) {
702 /* object is locked and active */
703
704 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
705 break;
706 }
707
708 name = (mach_port_name_t)object;
709 kr = ipc_entry_get(space, &name, &entry);
710 if (kr != KERN_SUCCESS) {
711 /* unlocks/locks space, so must start again */
712
713 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
714 if (kr != KERN_SUCCESS)
715 return kr; /* space is unlocked */
716
717 continue;
718 }
719
720 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
721 assert(entry->ie_object == IO_NULL);
722
723 io_lock(object);
724 if (!io_active(object)) {
725 io_unlock(object);
726 ipc_entry_dealloc(space, name, entry);
727 is_write_unlock(space);
728 return KERN_INVALID_CAPABILITY;
729 }
730
731 entry->ie_object = object;
732 break;
733 }
734
735 /* space is write-locked and active, object is locked and active */
736
737 kr = ipc_right_copyout(space, name, entry,
738 msgt_name, overflow, object);
739 /* object is unlocked */
740 is_write_unlock(space);
741
742 if (kr == KERN_SUCCESS)
743 *namep = name;
744 return kr;
745}
746
747/*
748 * Routine: ipc_object_copyout_name
749 * Purpose:
750 * Copyout a capability, placing it into a space.
751 * The specified name is used for the capability.
752 * If successful, consumes a ref for the object.
753 * Conditions:
754 * Nothing locked.
755 * Returns:
756 * KERN_SUCCESS Copied out object, consumed ref.
757 * KERN_INVALID_TASK The space is dead.
758 * KERN_INVALID_CAPABILITY The object is dead.
759 * KERN_RESOURCE_SHORTAGE No memory available.
760 * KERN_UREFS_OVERFLOW Urefs limit exceeded
761 * and overflow wasn't specified.
762 * KERN_RIGHT_EXISTS Space has rights under another name.
763 * KERN_NAME_EXISTS Name is already used.
764 */
765
766kern_return_t
767ipc_object_copyout_name(
768 ipc_space_t space,
769 ipc_object_t object,
770 mach_msg_type_name_t msgt_name,
771 boolean_t overflow,
772 mach_port_name_t name)
773{
774 mach_port_name_t oname;
775 ipc_entry_t oentry;
776 ipc_entry_t entry;
777 kern_return_t kr;
778
779 int i;
780
781 assert(IO_VALID(object));
782 assert(io_otype(object) == IOT_PORT);
783
784 kr = ipc_entry_alloc_name(space, name, &entry);
785 if (kr != KERN_SUCCESS)
786 return kr;
787 /* space is write-locked and active */
788
789 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
790 ipc_right_reverse(space, object, &oname, &oentry)) {
791 /* object is locked and active */
792
793 if (name != oname) {
794 io_unlock(object);
795
796 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
797 ipc_entry_dealloc(space, name, entry);
798
799 is_write_unlock(space);
800 return KERN_RIGHT_EXISTS;
801 }
802
803 assert(entry == oentry);
804 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
805 } else {
806 if (ipc_right_inuse(space, name, entry))
807 return KERN_NAME_EXISTS;
808
809 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
810 assert(entry->ie_object == IO_NULL);
811
812 io_lock(object);
813 if (!io_active(object)) {
814 io_unlock(object);
815 ipc_entry_dealloc(space, name, entry);
816 is_write_unlock(space);
817 return KERN_INVALID_CAPABILITY;
818 }
819
820 entry->ie_object = object;
821 }
822
823 /* space is write-locked and active, object is locked and active */
824
825 kr = ipc_right_copyout(space, name, entry,
826 msgt_name, overflow, object);
827 /* object is unlocked */
828 is_write_unlock(space);
829 return kr;
830}
831
832/*
833 * Routine: ipc_object_copyout_dest
834 * Purpose:
835 * Translates/consumes the destination right of a message.
836 * This is unlike normal copyout because the right is consumed
837 * in a funny way instead of being given to the receiving space.
838 * The receiver gets his name for the port, if he has receive
839 * rights, otherwise MACH_PORT_NULL.
840 * Conditions:
841 * The object is locked and active. Nothing else locked.
842 * The object is unlocked and loses a reference.
843 */
844
845void
846ipc_object_copyout_dest(
847 ipc_space_t space,
848 ipc_object_t object,
849 mach_msg_type_name_t msgt_name,
850 mach_port_name_t *namep)
851{
852 mach_port_name_t name;
853
854 assert(IO_VALID(object));
855 assert(io_active(object));
856
857 io_release(object);
858
859 /*
860 * If the space is the receiver/owner of the object,
861 * then we quietly consume the right and return
862 * the space's name for the object. Otherwise
863 * we destroy the right and return MACH_PORT_NULL.
864 */
865
866 switch (msgt_name) {
867 case MACH_MSG_TYPE_PORT_SEND: {
868 ipc_port_t port = (ipc_port_t) object;
869 ipc_port_t nsrequest = IP_NULL;
870 mach_port_mscount_t mscount;
871
872 if (port->ip_receiver == space)
873 name = port->ip_receiver_name;
874 else
875 name = MACH_PORT_NULL;
876
877 assert(port->ip_srights > 0);
878 if (--port->ip_srights == 0 &&
879 port->ip_nsrequest != IP_NULL) {
880 nsrequest = port->ip_nsrequest;
881 port->ip_nsrequest = IP_NULL;
882 mscount = port->ip_mscount;
883 ip_unlock(port);
884 ipc_notify_no_senders(nsrequest, mscount);
885 } else
886 ip_unlock(port);
887 break;
888 }
889
890 case MACH_MSG_TYPE_PORT_SEND_ONCE: {
891 ipc_port_t port = (ipc_port_t) object;
892
893 assert(port->ip_sorights > 0);
894
895 if (port->ip_receiver == space) {
896 /* quietly consume the send-once right */
897
898 port->ip_sorights--;
899 name = port->ip_receiver_name;
900 ip_unlock(port);
901 } else {
902 /*
903 * A very bizarre case. The message
904 * was received, but before this copyout
905 * happened the space lost receive rights.
906 * We can't quietly consume the soright
907 * out from underneath some other task,
908 * so generate a send-once notification.
909 */
910
911 ip_reference(port); /* restore ref */
912 ip_unlock(port);
913
914 ipc_notify_send_once(port);
915 name = MACH_PORT_NULL;
916 }
917
918 break;
919 }
920
921 default:
922 panic("ipc_object_copyout_dest: strange rights");
923 }
924
925 *namep = name;
926}
927
928/*
929 * Routine: ipc_object_rename
930 * Purpose:
931 * Rename an entry in a space.
932 * Conditions:
933 * Nothing locked.
934 * Returns:
935 * KERN_SUCCESS Renamed the entry.
936 * KERN_INVALID_TASK The space was dead.
937 * KERN_INVALID_NAME oname didn't denote an entry.
938 * KERN_NAME_EXISTS nname already denoted an entry.
939 * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry.
940 */
941
942kern_return_t
943ipc_object_rename(
944 ipc_space_t space,
945 mach_port_name_t oname,
946 mach_port_name_t nname)
947{
948 ipc_entry_t oentry, nentry;
949 kern_return_t kr;
950
951 int i;
952
953 kr = ipc_entry_alloc_name(space, nname, &nentry);
954 if (kr != KERN_SUCCESS)
955 return kr;
956
957 /* space is write-locked and active */
958
959 if (ipc_right_inuse(space, nname, nentry)) {
960 /* space is unlocked */
961 return KERN_NAME_EXISTS;
962 }
963
964 /* don't let ipc_entry_lookup see the uninitialized new entry */
965
966 if ((oname == nname) ||
967 ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) {
968 ipc_entry_dealloc(space, nname, nentry);
969 is_write_unlock(space);
970 return KERN_INVALID_NAME;
971 }
972
973 kr = ipc_right_rename(space, oname, oentry, nname, nentry);
974 /* space is unlocked */
975 return kr;
976}
977
978#if MACH_ASSERT
979/*
980 * Check whether the object is a port if so, free it. But
981 * keep track of that fact.
982 */
983void
984io_free(
985 unsigned int otype,
986 ipc_object_t object)
987{
988 ipc_port_t port;
989
990 if (otype == IOT_PORT) {
991 port = (ipc_port_t) object;
992#if MACH_ASSERT
993 ipc_port_track_dealloc(port);
994#endif /* MACH_ASSERT */
995 }
996 zfree(ipc_object_zones[otype], (vm_offset_t) object);
997}
998#endif /* MACH_ASSERT */
999
1000#include <mach_kdb.h>
1001#if MACH_KDB
1002
1003#include <ddb/db_output.h>
1004
1005#define printf kdbprintf
1006
1007/*
1008 * Routine: ipc_object_print
1009 * Purpose:
1010 * Pretty-print an object for kdb.
1011 */
1012
1013char *ikot_print_array[IKOT_MAX_TYPE] = {
1014 "(NONE) ",
1015 "(THREAD) ",
1016 "(TASK) ",
1017 "(HOST) ",
1018 "(HOST_PRIV) ",
1019 "(PROCESSOR) ",
1020 "(PSET) ",
1021 "(PSET_NAME) ",
1022 "(TIMER) ",
1023 "(PAGER_REQUEST) ",
1024 "(DEVICE) ", /* 10 */
1025 "(XMM_OBJECT) ",
1026 "(XMM_PAGER) ",
1027 "(XMM_KERNEL) ",
1028 "(XMM_REPLY) ",
1029 "(NOTDEF 15) ",
1030 "(NOTDEF 16) ",
1031 "(HOST_SECURITY) ",
1032 "(LEDGER) ",
1033 "(MASTER_DEVICE) ",
1034 "(ACTIVATION) ", /* 20 */
1035 "(SUBSYSTEM) ",
1036 "(IO_DONE_QUEUE) ",
1037 "(SEMAPHORE) ",
1038 "(LOCK_SET) ",
1039 "(CLOCK) ",
1040 "(CLOCK_CTRL) ", /* 26 */
1041 "(IOKIT_SPARE) ", /* 27 */
1042 "(NAMED_MEM_ENTRY) ", /* 28 */
1043 "(IOKIT_CONNECT) ",
1044 "(IOKIT_OBJECT) ", /* 30 */
1045 "(UPL) ",
1046 /* << new entries here */
1047 "(UNKNOWN) " /* magic catchall */
1048};
1049/* Please keep in sync with kern/ipc_kobject.h */
1050
1051void
1052ipc_object_print(
1053 ipc_object_t object)
1054{
1055 int kotype;
1056
1057 iprintf("%s", io_active(object) ? "active" : "dead");
1058 printf(", refs=%d", object->io_references);
1059 printf(", otype=%d", io_otype(object));
1060 kotype = io_kotype(object);
1061 if (kotype >= 0 && kotype < IKOT_MAX_TYPE)
1062 printf(", kotype=%d %s\n", io_kotype(object),
1063 ikot_print_array[kotype]);
1064 else
1065 printf(", kotype=0x%x %s\n", io_kotype(object),
1066 ikot_print_array[IKOT_UNKNOWN]);
1067}
1068
1069#endif /* MACH_KDB */