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