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