|
|
1.1 root 1: /*
2: * Mach Operating System
3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University.
4: * Copyright (c) 1993,1994 The University of Utah and
5: * the Computer Systems Laboratory (CSL).
6: * All rights reserved.
7: *
8: * Permission to use, copy, modify and distribute this software and its
9: * documentation is hereby granted, provided that both the copyright
10: * notice and this permission notice appear in all copies of the
11: * software, derivative works or modified versions, and any portions
12: * thereof, and that both notices appear in supporting documentation.
13: *
14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF
15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY
16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF
17: * THIS SOFTWARE.
18: *
19: * Carnegie Mellon requests users of this software to return to
20: *
21: * Software Distribution Coordinator or [email protected]
22: * School of Computer Science
23: * Carnegie Mellon University
24: * Pittsburgh PA 15213-3890
25: *
26: * any improvements or extensions that they make and grant Carnegie Mellon
27: * the rights to redistribute these changes.
28: */
29: /*
30: * File: ipc/ipc_kmsg.c
31: * Author: Rich Draves
32: * Date: 1989
33: *
34: * Operations on kernel messages.
35: */
36:
37: #include <cpus.h>
38: #include <mach_ipc_compat.h>
39: #include <norma_ipc.h>
40: #include <norma_vm.h>
41:
42: #include <mach/boolean.h>
43: #include <mach/kern_return.h>
44: #include <mach/message.h>
45: #include <mach/port.h>
46: #include <kern/assert.h>
47: #include <kern/kalloc.h>
48: #include <vm/vm_map.h>
49: #include <vm/vm_object.h>
50: #include <vm/vm_kern.h>
51: #include <ipc/port.h>
52: #include <ipc/ipc_entry.h>
53: #include <ipc/ipc_kmsg.h>
54: #include <ipc/ipc_thread.h>
55: #include <ipc/ipc_marequest.h>
56: #include <ipc/ipc_notify.h>
57: #include <ipc/ipc_object.h>
58: #include <ipc/ipc_space.h>
59: #include <ipc/ipc_port.h>
60: #include <ipc/ipc_right.h>
61:
62: #include <ipc/ipc_machdep.h>
63:
64: extern int copyinmap();
65: extern int copyoutmap();
66: void ipc_msg_print(); /* forward */
67:
68: #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
69: #define ptr_align(x) \
70: ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
71:
72: ipc_kmsg_t ipc_kmsg_cache[NCPUS];
73:
74: /*
75: * Routine: ipc_kmsg_enqueue
76: * Purpose:
77: * Enqueue a kmsg.
78: */
79:
80: void
81: ipc_kmsg_enqueue(
82: ipc_kmsg_queue_t queue,
83: ipc_kmsg_t kmsg)
84: {
85: ipc_kmsg_enqueue_macro(queue, kmsg);
86: }
87:
88: /*
89: * Routine: ipc_kmsg_dequeue
90: * Purpose:
91: * Dequeue and return a kmsg.
92: */
93:
94: ipc_kmsg_t
95: ipc_kmsg_dequeue(
96: ipc_kmsg_queue_t queue)
97: {
98: ipc_kmsg_t first;
99:
100: first = ipc_kmsg_queue_first(queue);
101:
102: if (first != IKM_NULL)
103: ipc_kmsg_rmqueue_first_macro(queue, first);
104:
105: return first;
106: }
107:
108: /*
109: * Routine: ipc_kmsg_rmqueue
110: * Purpose:
111: * Pull a kmsg out of a queue.
112: */
113:
114: void
115: ipc_kmsg_rmqueue(
116: ipc_kmsg_queue_t queue,
117: ipc_kmsg_t kmsg)
118: {
119: ipc_kmsg_t next, prev;
120:
121: assert(queue->ikmq_base != IKM_NULL);
122:
123: next = kmsg->ikm_next;
124: prev = kmsg->ikm_prev;
125:
126: if (next == kmsg) {
127: assert(prev == kmsg);
128: assert(queue->ikmq_base == kmsg);
129:
130: queue->ikmq_base = IKM_NULL;
131: } else {
132: if (queue->ikmq_base == kmsg)
133: queue->ikmq_base = next;
134:
135: next->ikm_prev = prev;
136: prev->ikm_next = next;
137: }
138: /* XXX Temporary debug logic */
139: kmsg->ikm_next = IKM_BOGUS;
140: kmsg->ikm_prev = IKM_BOGUS;
141: }
142:
143: /*
144: * Routine: ipc_kmsg_queue_next
145: * Purpose:
146: * Return the kmsg following the given kmsg.
147: * (Or IKM_NULL if it is the last one in the queue.)
148: */
149:
150: ipc_kmsg_t
151: ipc_kmsg_queue_next(
152: ipc_kmsg_queue_t queue,
153: ipc_kmsg_t kmsg)
154: {
155: ipc_kmsg_t next;
156:
157: assert(queue->ikmq_base != IKM_NULL);
158:
159: next = kmsg->ikm_next;
160: if (queue->ikmq_base == next)
161: next = IKM_NULL;
162:
163: return next;
164: }
165:
166: /*
167: * Routine: ipc_kmsg_destroy
168: * Purpose:
169: * Destroys a kernel message. Releases all rights,
170: * references, and memory held by the message.
171: * Frees the message.
172: * Conditions:
173: * No locks held.
174: */
175:
176: void
177: ipc_kmsg_destroy(
178: ipc_kmsg_t kmsg)
179: {
180: ipc_kmsg_queue_t queue;
181: boolean_t empty;
182:
183: /*
184: * ipc_kmsg_clean can cause more messages to be destroyed.
185: * Curtail recursion by queueing messages. If a message
186: * is already queued, then this is a recursive call.
187: */
188:
189: queue = ¤t_thread()->ith_messages;
190: empty = ipc_kmsg_queue_empty(queue);
191: ipc_kmsg_enqueue(queue, kmsg);
192:
193: if (empty) {
194: /* must leave kmsg in queue while cleaning it */
195:
196: while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
197: ipc_kmsg_clean(kmsg);
198: ipc_kmsg_rmqueue(queue, kmsg);
199: ikm_free(kmsg);
200: }
201: }
202: }
203:
204: /*
205: * Routine: ipc_kmsg_clean_body
206: * Purpose:
207: * Cleans the body of a kernel message.
208: * Releases all rights, references, and memory.
209: *
210: * The last type/data pair might stretch past eaddr.
211: * (See the usage in ipc_kmsg_copyout.)
212: * Conditions:
213: * No locks held.
214: */
215:
216: void
217: ipc_kmsg_clean_body(saddr, eaddr)
218: vm_offset_t saddr;
219: vm_offset_t eaddr;
220: {
221: while (saddr < eaddr) {
222: mach_msg_type_long_t *type;
223: mach_msg_type_name_t name;
224: mach_msg_type_size_t size;
225: mach_msg_type_number_t number;
226: boolean_t is_inline, is_port;
227: vm_size_t length;
228:
229: type = (mach_msg_type_long_t *) saddr;
230: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
231: if (((mach_msg_type_t*)type)->msgt_longform) {
232: /* This must be aligned */
233: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
234: (is_misaligned(type))) {
235: saddr = ptr_align(saddr);
236: continue;
237: }
238: name = type->msgtl_name;
239: size = type->msgtl_size;
240: number = type->msgtl_number;
241: saddr += sizeof(mach_msg_type_long_t);
242: } else {
243: name = ((mach_msg_type_t*)type)->msgt_name;
244: size = ((mach_msg_type_t*)type)->msgt_size;
245: number = ((mach_msg_type_t*)type)->msgt_number;
246: saddr += sizeof(mach_msg_type_t);
247: }
248:
249: /* padding (ptrs and ports) ? */
250: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
251: ((size >> 3) == sizeof(natural_t)))
252: saddr = ptr_align(saddr);
253:
254: /* calculate length of data in bytes, rounding up */
255:
256: length = ((number * size) + 7) >> 3;
257:
258: is_port = MACH_MSG_TYPE_PORT_ANY(name);
259:
260: if (is_port) {
261: ipc_object_t *objects;
262: mach_msg_type_number_t i;
263:
264: if (is_inline) {
265: objects = (ipc_object_t *) saddr;
266: /* sanity check */
267: while (eaddr < (vm_offset_t)&objects[number]) number--;
268: } else {
269: objects = (ipc_object_t *)
270: * (vm_offset_t *) saddr;
271: }
272:
273: /* destroy port rights carried in the message */
274:
275: for (i = 0; i < number; i++) {
276: ipc_object_t object = objects[i];
277:
278: if (!IO_VALID(object))
279: continue;
280:
281: ipc_object_destroy(object, name);
282: }
283: }
284:
285: if (is_inline) {
286: /* inline data sizes round up to int boundaries */
287:
288: saddr += (length + 3) &~ 3;
289: } else {
290: vm_offset_t data = * (vm_offset_t *) saddr;
291:
292: /* destroy memory carried in the message */
293:
294: if (length == 0)
295: assert(data == 0);
296: else if (is_port)
297: kfree(data, length);
298: else
299: vm_map_copy_discard((vm_map_copy_t) data);
300:
301: saddr += sizeof(vm_offset_t);
302: }
303: }
304: }
305:
306: /*
307: * Routine: ipc_kmsg_clean
308: * Purpose:
309: * Cleans a kernel message. Releases all rights,
310: * references, and memory held by the message.
311: * Conditions:
312: * No locks held.
313: */
314:
315: void
316: ipc_kmsg_clean(kmsg)
317: ipc_kmsg_t kmsg;
318: {
319: ipc_marequest_t marequest;
320: ipc_object_t object;
321: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
322:
323: marequest = kmsg->ikm_marequest;
324: if (marequest != IMAR_NULL)
325: ipc_marequest_destroy(marequest);
326:
327: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
328: if (IO_VALID(object))
329: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
330:
331: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
332: if (IO_VALID(object))
333: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
334:
335: if (mbits & MACH_MSGH_BITS_COMPLEX) {
336: vm_offset_t saddr, eaddr;
337:
338: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
339: eaddr = (vm_offset_t) &kmsg->ikm_header +
340: kmsg->ikm_header.msgh_size;
341:
342: ipc_kmsg_clean_body(saddr, eaddr);
343: }
344: }
345:
346: /*
347: * Routine: ipc_kmsg_clean_partial
348: * Purpose:
349: * Cleans a partially-acquired kernel message.
350: * eaddr is the address of the type specification
351: * in the body of the message that contained the error.
352: * If dolast, the memory and port rights in this last
353: * type spec are also cleaned. In that case, number
354: * specifies the number of port rights to clean.
355: * Conditions:
356: * Nothing locked.
357: */
358:
359: void
360: ipc_kmsg_clean_partial(kmsg, eaddr, dolast, number)
361: ipc_kmsg_t kmsg;
362: vm_offset_t eaddr;
363: boolean_t dolast;
364: mach_msg_type_number_t number;
365: {
366: ipc_object_t object;
367: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
368: vm_offset_t saddr;
369:
370: assert(kmsg->ikm_marequest == IMAR_NULL);
371:
372: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
373: assert(IO_VALID(object));
374: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
375:
376: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
377: if (IO_VALID(object))
378: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
379:
380: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
381: ipc_kmsg_clean_body(saddr, eaddr);
382:
383: if (dolast) {
384: mach_msg_type_long_t *type;
385: mach_msg_type_name_t name;
386: mach_msg_type_size_t size;
387: mach_msg_type_number_t rnumber;
388: boolean_t is_inline, is_port;
389: vm_size_t length;
390:
391: xxx: type = (mach_msg_type_long_t *) eaddr;
392: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
393: if (((mach_msg_type_t*)type)->msgt_longform) {
394: /* This must be aligned */
395: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
396: (is_misaligned(type))) {
397: eaddr = ptr_align(eaddr);
398: goto xxx;
399: }
400: name = type->msgtl_name;
401: size = type->msgtl_size;
402: rnumber = type->msgtl_number;
403: eaddr += sizeof(mach_msg_type_long_t);
404: } else {
405: name = ((mach_msg_type_t*)type)->msgt_name;
406: size = ((mach_msg_type_t*)type)->msgt_size;
407: rnumber = ((mach_msg_type_t*)type)->msgt_number;
408: eaddr += sizeof(mach_msg_type_t);
409: }
410:
411: /* padding (ptrs and ports) ? */
412: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
413: ((size >> 3) == sizeof(natural_t)))
414: eaddr = ptr_align(eaddr);
415:
416: /* calculate length of data in bytes, rounding up */
417:
418: length = ((rnumber * size) + 7) >> 3;
419:
420: is_port = MACH_MSG_TYPE_PORT_ANY(name);
421:
422: if (is_port) {
423: ipc_object_t *objects;
424: mach_msg_type_number_t i;
425:
426: objects = (ipc_object_t *)
427: (is_inline ? eaddr : * (vm_offset_t *) eaddr);
428:
429: /* destroy port rights carried in the message */
430:
431: for (i = 0; i < number; i++) {
432: ipc_object_t obj = objects[i];
433:
434: if (!IO_VALID(obj))
435: continue;
436:
437: ipc_object_destroy(obj, name);
438: }
439: }
440:
441: if (!is_inline) {
442: vm_offset_t data = * (vm_offset_t *) eaddr;
443:
444: /* destroy memory carried in the message */
445:
446: if (length == 0)
447: assert(data == 0);
448: else if (is_port)
449: kfree(data, length);
450: else
451: vm_map_copy_discard((vm_map_copy_t) data);
452: }
453: }
454: }
455:
456: /*
457: * Routine: ipc_kmsg_free
458: * Purpose:
459: * Free a kernel message buffer.
460: * Conditions:
461: * Nothing locked.
462: */
463:
464: void
465: ipc_kmsg_free(kmsg)
466: ipc_kmsg_t kmsg;
467: {
468: vm_size_t size = kmsg->ikm_size;
469:
470: switch (size) {
471: #if NORMA_IPC
472: case IKM_SIZE_NORMA:
473: /* return it to the norma ipc code */
474: norma_kmsg_put(kmsg);
475: break;
476: #endif /* NORMA_IPC */
477:
478: case IKM_SIZE_NETWORK:
479: /* return it to the network code */
480: net_kmsg_put(kmsg);
481: break;
482:
483: default:
484: kfree((vm_offset_t) kmsg, size);
485: break;
486: }
487: }
488:
489: /*
490: * Routine: ipc_kmsg_get
491: * Purpose:
492: * Allocates a kernel message buffer.
493: * Copies a user message to the message buffer.
494: * Conditions:
495: * Nothing locked.
496: * Returns:
497: * MACH_MSG_SUCCESS Acquired a message buffer.
498: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
499: * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
500: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
501: * MACH_SEND_INVALID_DATA Couldn't copy message data.
502: */
503:
504: mach_msg_return_t
505: ipc_kmsg_get(msg, size, kmsgp)
506: mach_msg_header_t *msg;
507: mach_msg_size_t size;
508: ipc_kmsg_t *kmsgp;
509: {
510: ipc_kmsg_t kmsg;
511:
512: if ((size < sizeof(mach_msg_header_t)) || (size & 3))
513: return MACH_SEND_MSG_TOO_SMALL;
514:
515: if (size <= IKM_SAVED_MSG_SIZE) {
516: kmsg = ikm_cache();
517: if (kmsg != IKM_NULL) {
518: ikm_cache() = IKM_NULL;
519: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
520: } else {
521: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
522: if (kmsg == IKM_NULL)
523: return MACH_SEND_NO_BUFFER;
524: ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
525: }
526: } else {
527: kmsg = ikm_alloc(size);
528: if (kmsg == IKM_NULL)
529: return MACH_SEND_NO_BUFFER;
530: ikm_init(kmsg, size);
531: }
532:
533: if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) {
534: ikm_free(kmsg);
535: return MACH_SEND_INVALID_DATA;
536: }
537:
538: kmsg->ikm_header.msgh_size = size;
539: *kmsgp = kmsg;
540: return MACH_MSG_SUCCESS;
541: }
542:
543: /*
544: * Routine: ipc_kmsg_get_from_kernel
545: * Purpose:
546: * Allocates a kernel message buffer.
547: * Copies a kernel message to the message buffer.
548: * Only resource errors are allowed.
549: * Conditions:
550: * Nothing locked.
551: * Returns:
552: * MACH_MSG_SUCCESS Acquired a message buffer.
553: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
554: */
555:
556: extern mach_msg_return_t
557: ipc_kmsg_get_from_kernel(msg, size, kmsgp)
558: mach_msg_header_t *msg;
559: mach_msg_size_t size;
560: ipc_kmsg_t *kmsgp;
561: {
562: ipc_kmsg_t kmsg;
563:
564: assert(size >= sizeof(mach_msg_header_t));
565: assert((size & 3) == 0);
566:
567: kmsg = ikm_alloc(size);
568: if (kmsg == IKM_NULL)
569: return MACH_SEND_NO_BUFFER;
570: ikm_init(kmsg, size);
571:
572: bcopy((char *) msg, (char *) &kmsg->ikm_header, size);
573:
574: kmsg->ikm_header.msgh_size = size;
575: *kmsgp = kmsg;
576: return MACH_MSG_SUCCESS;
577: }
578:
579: /*
580: * Routine: ipc_kmsg_put
581: * Purpose:
582: * Copies a message buffer to a user message.
583: * Copies only the specified number of bytes.
584: * Frees the message buffer.
585: * Conditions:
586: * Nothing locked. The message buffer must have clean
587: * header (ikm_marequest) fields.
588: * Returns:
589: * MACH_MSG_SUCCESS Copied data out of message buffer.
590: * MACH_RCV_INVALID_DATA Couldn't copy to user message.
591: */
592:
593: mach_msg_return_t
594: ipc_kmsg_put(msg, kmsg, size)
595: mach_msg_header_t *msg;
596: ipc_kmsg_t kmsg;
597: mach_msg_size_t size;
598: {
599: mach_msg_return_t mr;
600:
601: ikm_check_initialized(kmsg, kmsg->ikm_size);
602:
603: if (copyoutmsg((char *) &kmsg->ikm_header, (char *) msg, size))
604: mr = MACH_RCV_INVALID_DATA;
605: else
606: mr = MACH_MSG_SUCCESS;
607:
608: if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
609: (ikm_cache() == IKM_NULL))
610: ikm_cache() = kmsg;
611: else
612: ikm_free(kmsg);
613:
614: return mr;
615: }
616:
617: /*
618: * Routine: ipc_kmsg_put_to_kernel
619: * Purpose:
620: * Copies a message buffer to a kernel message.
621: * Frees the message buffer.
622: * No errors allowed.
623: * Conditions:
624: * Nothing locked.
625: */
626:
627: void
628: ipc_kmsg_put_to_kernel(
629: mach_msg_header_t *msg,
630: ipc_kmsg_t kmsg,
631: mach_msg_size_t size)
632: {
633: #if DIPC
634: assert(!KMSG_IN_DIPC(kmsg));
635: #endif /* DIPC */
636:
637: (void) memcpy((void *) msg, (const void *) &kmsg->ikm_header, size);
638:
639: ikm_free(kmsg);
640: }
641:
642: /*
643: * Routine: ipc_kmsg_copyin_header
644: * Purpose:
645: * "Copy-in" port rights in the header of a message.
646: * Operates atomically; if it doesn't succeed the
647: * message header and the space are left untouched.
648: * If it does succeed the remote/local port fields
649: * contain object pointers instead of port names,
650: * and the bits field is updated. The destination port
651: * will be a valid port pointer.
652: *
653: * The notify argument implements the MACH_SEND_CANCEL option.
654: * If it is not MACH_PORT_NULL, it should name a receive right.
655: * If the processing of the destination port would generate
656: * a port-deleted notification (because the right for the
657: * destination port is destroyed and it had a request for
658: * a dead-name notification registered), and the port-deleted
659: * notification would be sent to the named receive right,
660: * then it isn't sent and the send-once right for the notify
661: * port is quietly destroyed.
662: *
663: * [MACH_IPC_COMPAT] There is an atomicity problem if the
664: * reply port is a compat entry and dies at an inopportune
665: * time. This doesn't have any serious consequences
666: * (an observant user task might conceivably notice that
667: * the destination and reply ports were handled inconsistently),
668: * only happens in compat mode, and is extremely unlikely.
669: * Conditions:
670: * Nothing locked.
671: * Returns:
672: * MACH_MSG_SUCCESS Successful copyin.
673: * MACH_SEND_INVALID_HEADER
674: * Illegal value in the message header bits.
675: * MACH_SEND_INVALID_DEST The space is dead.
676: * MACH_SEND_INVALID_NOTIFY
677: * Notify is non-null and doesn't name a receive right.
678: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
679: * MACH_SEND_INVALID_DEST Can't copyin destination port.
680: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
681: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
682: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
683: */
684:
685: mach_msg_return_t
686: ipc_kmsg_copyin_header(msg, space, notify)
687: mach_msg_header_t *msg;
688: ipc_space_t space;
689: mach_port_t notify;
690: {
691: mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
692: mach_port_t dest_name = msg->msgh_remote_port;
693: mach_port_t reply_name = msg->msgh_local_port;
694: kern_return_t kr;
695:
696: #ifndef MIGRATING_THREADS
697: /* first check for common cases */
698:
699: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
700: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
701: ipc_entry_t entry;
702: ipc_entry_bits_t bits;
703: ipc_port_t dest_port;
704:
705: /* sending an asynchronous message */
706:
707: if (reply_name != MACH_PORT_NULL)
708: break;
709:
710: is_read_lock(space);
711: if (!space->is_active)
712: goto abort_async;
713:
714: /* optimized ipc_entry_lookup */
715:
716: {
717: mach_port_index_t index = MACH_PORT_INDEX(dest_name);
718: mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
719:
720: if (index >= space->is_table_size)
721: goto abort_async;
722:
723: entry = &space->is_table[index];
724: bits = entry->ie_bits;
725:
726: /* check generation number and type bit */
727:
728: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
729: (gen | MACH_PORT_TYPE_SEND))
730: goto abort_async;
731: }
732:
733: /* optimized ipc_right_copyin */
734:
735: assert(IE_BITS_UREFS(bits) > 0);
736:
737: dest_port = (ipc_port_t) entry->ie_object;
738: assert(dest_port != IP_NULL);
739:
740: ip_lock(dest_port);
741: /* can unlock space now without compromising atomicity */
742: is_read_unlock(space);
743:
744: if (!ip_active(dest_port)) {
745: ip_unlock(dest_port);
746: break;
747: }
748:
749: assert(dest_port->ip_srights > 0);
750: dest_port->ip_srights++;
751: ip_reference(dest_port);
752: ip_unlock(dest_port);
753:
754: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
755: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
756: msg->msgh_remote_port = (mach_port_t) dest_port;
757: return MACH_MSG_SUCCESS;
758:
759: abort_async:
760: is_read_unlock(space);
761: break;
762: }
763:
764: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
765: MACH_MSG_TYPE_MAKE_SEND_ONCE): {
766: ipc_entry_num_t size;
767: ipc_entry_t table;
768: ipc_entry_t entry;
769: ipc_entry_bits_t bits;
770: ipc_port_t dest_port, reply_port;
771:
772: /* sending a request message */
773:
774: is_read_lock(space);
775: if (!space->is_active)
776: goto abort_request;
777:
778: size = space->is_table_size;
779: table = space->is_table;
780:
781: /* optimized ipc_entry_lookup of dest_name */
782:
783: {
784: mach_port_index_t index = MACH_PORT_INDEX(dest_name);
785: mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
786:
787: if (index >= size)
788: goto abort_request;
789:
790: entry = &table[index];
791: bits = entry->ie_bits;
792:
793: /* check generation number and type bit */
794:
795: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
796: (gen | MACH_PORT_TYPE_SEND))
797: goto abort_request;
798: }
799:
800: assert(IE_BITS_UREFS(bits) > 0);
801:
802: dest_port = (ipc_port_t) entry->ie_object;
803: assert(dest_port != IP_NULL);
804:
805: /* optimized ipc_entry_lookup of reply_name */
806:
807: {
808: mach_port_index_t index = MACH_PORT_INDEX(reply_name);
809: mach_port_gen_t gen = MACH_PORT_GEN(reply_name);
810:
811: if (index >= size)
812: goto abort_request;
813:
814: entry = &table[index];
815: bits = entry->ie_bits;
816:
817: /* check generation number and type bit */
818:
819: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) !=
820: (gen | MACH_PORT_TYPE_RECEIVE))
821: goto abort_request;
822: }
823:
824: reply_port = (ipc_port_t) entry->ie_object;
825: assert(reply_port != IP_NULL);
826:
827: /*
828: * To do an atomic copyin, need simultaneous
829: * locks on both ports and the space. If
830: * dest_port == reply_port, and simple locking is
831: * enabled, then we will abort. Otherwise it's
832: * OK to unlock twice.
833: */
834:
835: ip_lock(dest_port);
836: if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
837: ip_unlock(dest_port);
838: goto abort_request;
839: }
840: /* can unlock space now without compromising atomicity */
841: is_read_unlock(space);
842:
843: assert(dest_port->ip_srights > 0);
844: dest_port->ip_srights++;
845: ip_reference(dest_port);
846: ip_unlock(dest_port);
847:
848: assert(ip_active(reply_port));
849: assert(reply_port->ip_receiver_name == reply_name);
850: assert(reply_port->ip_receiver == space);
851:
852: reply_port->ip_sorights++;
853: ip_reference(reply_port);
854: ip_unlock(reply_port);
855:
856: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
857: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
858: MACH_MSG_TYPE_PORT_SEND_ONCE));
859: msg->msgh_remote_port = (mach_port_t) dest_port;
860: msg->msgh_local_port = (mach_port_t) reply_port;
861: return MACH_MSG_SUCCESS;
862:
863: abort_request:
864: is_read_unlock(space);
865: break;
866: }
867:
868: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
869: mach_port_index_t index;
870: mach_port_gen_t gen;
871: ipc_entry_t table;
872: ipc_entry_t entry;
873: ipc_entry_bits_t bits;
874: ipc_port_t dest_port;
875:
876: /* sending a reply message */
877:
878: if (reply_name != MACH_PORT_NULL)
879: break;
880:
881: is_write_lock(space);
882: if (!space->is_active)
883: goto abort_reply;
884:
885: /* optimized ipc_entry_lookup */
886:
887: table = space->is_table;
888:
889: index = MACH_PORT_INDEX(dest_name);
890: gen = MACH_PORT_GEN(dest_name);
891:
892: if (index >= space->is_table_size)
893: goto abort_reply;
894:
895: entry = &table[index];
896: bits = entry->ie_bits;
897:
898: /* check generation number, collision bit, and type bit */
899:
900: if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION|
901: MACH_PORT_TYPE_SEND_ONCE)) !=
902: (gen | MACH_PORT_TYPE_SEND_ONCE))
903: goto abort_reply;
904:
905: /* optimized ipc_right_copyin */
906:
907: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
908: assert(IE_BITS_UREFS(bits) == 1);
909: assert((bits & IE_BITS_MAREQUEST) == 0);
910:
911: if (entry->ie_request != 0)
912: goto abort_reply;
913:
914: dest_port = (ipc_port_t) entry->ie_object;
915: assert(dest_port != IP_NULL);
916:
917: ip_lock(dest_port);
918: if (!ip_active(dest_port)) {
919: ip_unlock(dest_port);
920: goto abort_reply;
921: }
922:
923: assert(dest_port->ip_sorights > 0);
924: ip_unlock(dest_port);
925:
926: /* optimized ipc_entry_dealloc */
927:
928: entry->ie_next = table->ie_next;
929: table->ie_next = index;
930: entry->ie_bits = gen;
931: entry->ie_object = IO_NULL;
932: is_write_unlock(space);
933:
934: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
935: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
936: 0));
937: msg->msgh_remote_port = (mach_port_t) dest_port;
938: return MACH_MSG_SUCCESS;
939:
940: abort_reply:
941: is_write_unlock(space);
942: break;
943: }
944:
945: default:
946: /* don't bother optimizing */
947: break;
948: }
949: #endif /* MIGRATING_THREADS */
950:
951: {
952: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
953: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
954: ipc_object_t dest_port, reply_port;
955: ipc_port_t dest_soright, reply_soright;
956: ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
957:
958: if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
959: return MACH_SEND_INVALID_HEADER;
960:
961: if ((reply_type == 0) ?
962: (reply_name != MACH_PORT_NULL) :
963: !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
964: return MACH_SEND_INVALID_HEADER;
965:
966: is_write_lock(space);
967: if (!space->is_active)
968: goto invalid_dest;
969:
970: if (notify != MACH_PORT_NULL) {
971: ipc_entry_t entry;
972:
973: if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
974: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
975: is_write_unlock(space);
976: return MACH_SEND_INVALID_NOTIFY;
977: }
978:
979: notify_port = (ipc_port_t) entry->ie_object;
980: }
981:
982: if (dest_name == reply_name) {
983: ipc_entry_t entry;
984: mach_port_t name = dest_name;
985:
986: /*
987: * Destination and reply ports are the same!
988: * This is a little tedious to make atomic, because
989: * there are 25 combinations of dest_type/reply_type.
990: * However, most are easy. If either is move-sonce,
991: * then there must be an error. If either are
992: * make-send or make-sonce, then we must be looking
993: * at a receive right so the port can't die.
994: * The hard cases are the combinations of
995: * copy-send and make-send.
996: */
997:
998: entry = ipc_entry_lookup(space, name);
999: if (entry == IE_NULL)
1000: goto invalid_dest;
1001:
1002: assert(reply_type != 0); /* because name not null */
1003:
1004: if (!ipc_right_copyin_check(space, name, entry, reply_type))
1005: goto invalid_reply;
1006:
1007: if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
1008: (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
1009: /*
1010: * Why must there be an error? To get a valid
1011: * destination, this entry must name a live
1012: * port (not a dead name or dead port). However
1013: * a successful move-sonce will destroy a
1014: * live entry. Therefore the other copyin,
1015: * whatever it is, would fail. We've already
1016: * checked for reply port errors above,
1017: * so report a destination error.
1018: */
1019:
1020: goto invalid_dest;
1021: } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
1022: (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
1023: (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
1024: (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
1025: kr = ipc_right_copyin(space, name, entry,
1026: dest_type, FALSE,
1027: &dest_port, &dest_soright);
1028: if (kr != KERN_SUCCESS)
1029: goto invalid_dest;
1030:
1031: /*
1032: * Either dest or reply needs a receive right.
1033: * We know the receive right is there, because
1034: * of the copyin_check and copyin calls. Hence
1035: * the port is not in danger of dying. If dest
1036: * used the receive right, then the right needed
1037: * by reply (and verified by copyin_check) will
1038: * still be there.
1039: */
1040:
1041: assert(IO_VALID(dest_port));
1042: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1043: assert(dest_soright == IP_NULL);
1044:
1045: kr = ipc_right_copyin(space, name, entry,
1046: reply_type, TRUE,
1047: &reply_port, &reply_soright);
1048:
1049: assert(kr == KERN_SUCCESS);
1050: assert(reply_port == dest_port);
1051: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1052: assert(reply_soright == IP_NULL);
1053: } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1054: (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
1055: /*
1056: * To make this atomic, just do one copy-send,
1057: * and dup the send right we get out.
1058: */
1059:
1060: kr = ipc_right_copyin(space, name, entry,
1061: dest_type, FALSE,
1062: &dest_port, &dest_soright);
1063: if (kr != KERN_SUCCESS)
1064: goto invalid_dest;
1065:
1066: assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
1067: assert(dest_soright == IP_NULL);
1068:
1069: /*
1070: * It's OK if the port we got is dead now,
1071: * so reply_port is IP_DEAD, because the msg
1072: * won't go anywhere anyway.
1073: */
1074:
1075: reply_port = (ipc_object_t)
1076: ipc_port_copy_send((ipc_port_t) dest_port);
1077: reply_soright = IP_NULL;
1078: } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1079: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
1080: /*
1081: * This is an easy case. Just use our
1082: * handy-dandy special-purpose copyin call
1083: * to get two send rights for the price of one.
1084: */
1085:
1086: kr = ipc_right_copyin_two(space, name, entry,
1087: &dest_port, &dest_soright);
1088: if (kr != KERN_SUCCESS)
1089: goto invalid_dest;
1090:
1091: /* the entry might need to be deallocated */
1092:
1093: if (IE_BITS_TYPE(entry->ie_bits)
1094: == MACH_PORT_TYPE_NONE)
1095: ipc_entry_dealloc(space, name, entry);
1096:
1097: reply_port = dest_port;
1098: reply_soright = IP_NULL;
1099: } else {
1100: ipc_port_t soright;
1101:
1102: assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1103: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
1104: ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1105: (reply_type == MACH_MSG_TYPE_COPY_SEND)));
1106:
1107: /*
1108: * To make this atomic, just do a move-send,
1109: * and dup the send right we get out.
1110: */
1111:
1112: kr = ipc_right_copyin(space, name, entry,
1113: MACH_MSG_TYPE_MOVE_SEND, FALSE,
1114: &dest_port, &soright);
1115: if (kr != KERN_SUCCESS)
1116: goto invalid_dest;
1117:
1118: /* the entry might need to be deallocated */
1119:
1120: if (IE_BITS_TYPE(entry->ie_bits)
1121: == MACH_PORT_TYPE_NONE)
1122: ipc_entry_dealloc(space, name, entry);
1123:
1124: /*
1125: * It's OK if the port we got is dead now,
1126: * so reply_port is IP_DEAD, because the msg
1127: * won't go anywhere anyway.
1128: */
1129:
1130: reply_port = (ipc_object_t)
1131: ipc_port_copy_send((ipc_port_t) dest_port);
1132:
1133: if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
1134: dest_soright = soright;
1135: reply_soright = IP_NULL;
1136: } else {
1137: dest_soright = IP_NULL;
1138: reply_soright = soright;
1139: }
1140: }
1141: } else if (!MACH_PORT_VALID(reply_name)) {
1142: ipc_entry_t entry;
1143:
1144: /*
1145: * No reply port! This is an easy case
1146: * to make atomic. Just copyin the destination.
1147: */
1148:
1149: entry = ipc_entry_lookup(space, dest_name);
1150: if (entry == IE_NULL)
1151: goto invalid_dest;
1152:
1153: kr = ipc_right_copyin(space, dest_name, entry,
1154: dest_type, FALSE,
1155: &dest_port, &dest_soright);
1156: if (kr != KERN_SUCCESS)
1157: goto invalid_dest;
1158:
1159: /* the entry might need to be deallocated */
1160:
1161: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1162: ipc_entry_dealloc(space, dest_name, entry);
1163:
1164: reply_port = (ipc_object_t) reply_name;
1165: reply_soright = IP_NULL;
1166: } else {
1167: ipc_entry_t dest_entry, reply_entry;
1168: ipc_port_t saved_reply;
1169:
1170: /*
1171: * This is the tough case to make atomic.
1172: * The difficult problem is serializing with port death.
1173: * At the time we copyin dest_port, it must be alive.
1174: * If reply_port is alive when we copyin it, then
1175: * we are OK, because we serialize before the death
1176: * of both ports. Assume reply_port is dead at copyin.
1177: * Then if dest_port dies/died after reply_port died,
1178: * we are OK, because we serialize between the death
1179: * of the two ports. So the bad case is when dest_port
1180: * dies after its copyin, reply_port dies before its
1181: * copyin, and dest_port dies before reply_port. Then
1182: * the copyins operated as if dest_port was alive
1183: * and reply_port was dead, which shouldn't have happened
1184: * because they died in the other order.
1185: *
1186: * We handle the bad case by undoing the copyins
1187: * (which is only possible because the ports are dead)
1188: * and failing with MACH_SEND_INVALID_DEST, serializing
1189: * after the death of the ports.
1190: *
1191: * Note that it is easy for a user task to tell if
1192: * a copyin happened before or after a port died.
1193: * For example, suppose both dest and reply are
1194: * send-once rights (types are both move-sonce) and
1195: * both rights have dead-name requests registered.
1196: * If a port dies before copyin, a dead-name notification
1197: * is generated and the dead name's urefs are incremented,
1198: * and if the copyin happens first, a port-deleted
1199: * notification is generated.
1200: *
1201: * Note that although the entries are different,
1202: * dest_port and reply_port might still be the same.
1203: */
1204:
1205: dest_entry = ipc_entry_lookup(space, dest_name);
1206: if (dest_entry == IE_NULL)
1207: goto invalid_dest;
1208:
1209: reply_entry = ipc_entry_lookup(space, reply_name);
1210: if (reply_entry == IE_NULL)
1211: goto invalid_reply;
1212:
1213: assert(dest_entry != reply_entry); /* names are not equal */
1214: assert(reply_type != 0); /* because reply_name not null */
1215:
1216: if (!ipc_right_copyin_check(space, reply_name, reply_entry,
1217: reply_type))
1218: goto invalid_reply;
1219:
1220: kr = ipc_right_copyin(space, dest_name, dest_entry,
1221: dest_type, FALSE,
1222: &dest_port, &dest_soright);
1223: if (kr != KERN_SUCCESS)
1224: goto invalid_dest;
1225:
1226: assert(IO_VALID(dest_port));
1227:
1228: saved_reply = (ipc_port_t) reply_entry->ie_object;
1229: /* might be IP_NULL, if this is a dead name */
1230: if (saved_reply != IP_NULL)
1231: ipc_port_reference(saved_reply);
1232:
1233: kr = ipc_right_copyin(space, reply_name, reply_entry,
1234: reply_type, TRUE,
1235: &reply_port, &reply_soright);
1236: #if MACH_IPC_COMPAT
1237: if (kr != KERN_SUCCESS) {
1238: assert(kr == KERN_INVALID_NAME);
1239:
1240: /*
1241: * Oops. This must have been a compat entry
1242: * and the port died after the check above.
1243: * We should back out the copyin of dest_port,
1244: * and report MACH_SEND_INVALID_REPLY, but
1245: * if dest_port is alive we can't always do that.
1246: * Punt and pretend we got IO_DEAD, skipping
1247: * further hairy atomicity problems.
1248: */
1249:
1250: reply_port = IO_DEAD;
1251: reply_soright = IP_NULL;
1252: goto skip_reply_checks;
1253: }
1254: #else /* MACH_IPC_COMPAT */
1255: assert(kr == KERN_SUCCESS);
1256: #endif /* MACH_IPC_COMPAT */
1257:
1258: if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
1259: ipc_port_t dest = (ipc_port_t) dest_port;
1260: ipc_port_timestamp_t timestamp;
1261: boolean_t must_undo;
1262:
1263: /*
1264: * The reply port died before copyin.
1265: * Check if dest port died before reply.
1266: */
1267:
1268: ip_lock(saved_reply);
1269: assert(!ip_active(saved_reply));
1270: timestamp = saved_reply->ip_timestamp;
1271: ip_unlock(saved_reply);
1272:
1273: ip_lock(dest);
1274: must_undo = (!ip_active(dest) &&
1275: IP_TIMESTAMP_ORDER(dest->ip_timestamp,
1276: timestamp));
1277: ip_unlock(dest);
1278:
1279: if (must_undo) {
1280: /*
1281: * Our worst nightmares are realized.
1282: * Both destination and reply ports
1283: * are dead, but in the wrong order,
1284: * so we must undo the copyins and
1285: * possibly generate a dead-name notif.
1286: */
1287:
1288: ipc_right_copyin_undo(
1289: space, dest_name, dest_entry,
1290: dest_type, dest_port,
1291: dest_soright);
1292: /* dest_entry may be deallocated now */
1293:
1294: ipc_right_copyin_undo(
1295: space, reply_name, reply_entry,
1296: reply_type, reply_port,
1297: reply_soright);
1298: /* reply_entry may be deallocated now */
1299:
1300: is_write_unlock(space);
1301:
1302: if (dest_soright != IP_NULL)
1303: ipc_notify_dead_name(dest_soright,
1304: dest_name);
1305: assert(reply_soright == IP_NULL);
1306:
1307: ipc_port_release(saved_reply);
1308: return MACH_SEND_INVALID_DEST;
1309: }
1310: }
1311:
1312: /* the entries might need to be deallocated */
1313:
1314: if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1315: ipc_entry_dealloc(space, reply_name, reply_entry);
1316:
1317: #if MACH_IPC_COMPAT
1318: skip_reply_checks:
1319: /*
1320: * We jump here if the reply entry was a compat entry
1321: * and the port died on us. In this case, the copyin
1322: * code already deallocated reply_entry.
1323: */
1324: #endif /* MACH_IPC_COMPAT */
1325:
1326: if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1327: ipc_entry_dealloc(space, dest_name, dest_entry);
1328:
1329: if (saved_reply != IP_NULL)
1330: ipc_port_release(saved_reply);
1331: }
1332:
1333: /*
1334: * At this point, dest_port, reply_port,
1335: * dest_soright, reply_soright are all initialized.
1336: * Any defunct entries have been deallocated.
1337: * The space is still write-locked, and we need to
1338: * make the MACH_SEND_CANCEL check. The notify_port pointer
1339: * is still usable, because the copyin code above won't ever
1340: * deallocate a receive right, so its entry still exists
1341: * and holds a ref. Note notify_port might even equal
1342: * dest_port or reply_port.
1343: */
1344:
1345: if ((notify != MACH_PORT_NULL) &&
1346: (dest_soright == notify_port)) {
1347: ipc_port_release_sonce(dest_soright);
1348: dest_soright = IP_NULL;
1349: }
1350:
1351: is_write_unlock(space);
1352:
1353: if (dest_soright != IP_NULL)
1354: ipc_notify_port_deleted(dest_soright, dest_name);
1355:
1356: if (reply_soright != IP_NULL)
1357: ipc_notify_port_deleted(reply_soright, reply_name);
1358:
1359: dest_type = ipc_object_copyin_type(dest_type);
1360: reply_type = ipc_object_copyin_type(reply_type);
1361:
1362: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1363: MACH_MSGH_BITS(dest_type, reply_type));
1364: msg->msgh_remote_port = (mach_port_t) dest_port;
1365: msg->msgh_local_port = (mach_port_t) reply_port;
1366: }
1367:
1368: return MACH_MSG_SUCCESS;
1369:
1370: invalid_dest:
1371: is_write_unlock(space);
1372: return MACH_SEND_INVALID_DEST;
1373:
1374: invalid_reply:
1375: is_write_unlock(space);
1376: return MACH_SEND_INVALID_REPLY;
1377: }
1378:
1379: mach_msg_return_t
1380: ipc_kmsg_copyin_body(kmsg, space, map)
1381: ipc_kmsg_t kmsg;
1382: ipc_space_t space;
1383: vm_map_t map;
1384: {
1385: ipc_object_t dest;
1386: vm_offset_t saddr, eaddr;
1387: boolean_t complex;
1388: mach_msg_return_t mr;
1389: boolean_t use_page_lists, steal_pages;
1390:
1391: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1392: complex = FALSE;
1393: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
1394: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
1395:
1396: #if NORMA_IPC
1397: if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
1398: use_page_lists = TRUE;
1399: steal_pages = TRUE;
1400: }
1401: #endif /* NORMA_IPC */
1402:
1403: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1404: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1405:
1406: while (saddr < eaddr) {
1407: vm_offset_t taddr = saddr;
1408: mach_msg_type_long_t *type;
1409: mach_msg_type_name_t name;
1410: mach_msg_type_size_t size;
1411: mach_msg_type_number_t number;
1412: boolean_t is_inline, longform, dealloc, is_port;
1413: vm_offset_t data;
1414: vm_size_t length;
1415: kern_return_t kr;
1416:
1417: type = (mach_msg_type_long_t *) saddr;
1418:
1419: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
1420: ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
1421: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
1422: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1423: return MACH_SEND_MSG_TOO_SMALL;
1424: }
1425:
1426: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1427: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
1428: if (longform) {
1429: /* This must be aligned */
1430: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1431: (is_misaligned(type))) {
1432: saddr = ptr_align(saddr);
1433: continue;
1434: }
1435: name = type->msgtl_name;
1436: size = type->msgtl_size;
1437: number = type->msgtl_number;
1438: saddr += sizeof(mach_msg_type_long_t);
1439: } else {
1440: name = ((mach_msg_type_t*)type)->msgt_name;
1441: size = ((mach_msg_type_t*)type)->msgt_size;
1442: number = ((mach_msg_type_t*)type)->msgt_number;
1443: saddr += sizeof(mach_msg_type_t);
1444: }
1445:
1446: is_port = MACH_MSG_TYPE_PORT_ANY(name);
1447:
1448: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
1449: (longform && ((type->msgtl_header.msgt_name != 0) ||
1450: (type->msgtl_header.msgt_size != 0) ||
1451: (type->msgtl_header.msgt_number != 0))) ||
1452: (((mach_msg_type_t*)type)->msgt_unused != 0) ||
1453: (dealloc && is_inline)) {
1454: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1455: return MACH_SEND_INVALID_TYPE;
1456: }
1457:
1458: /* padding (ptrs and ports) ? */
1459: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1460: ((size >> 3) == sizeof(natural_t)))
1461: saddr = ptr_align(saddr);
1462:
1463: /* calculate length of data in bytes, rounding up */
1464:
1465: length = ((number * size) + 7) >> 3;
1466:
1467: if (is_inline) {
1468: vm_size_t amount;
1469:
1470: /* inline data sizes round up to int boundaries */
1471:
1472: amount = (length + 3) &~ 3;
1473: if ((eaddr - saddr) < amount) {
1474: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1475: return MACH_SEND_MSG_TOO_SMALL;
1476: }
1477:
1478: data = saddr;
1479: saddr += amount;
1480: } else {
1481: vm_offset_t addr;
1482:
1483: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
1484: saddr = ptr_align(saddr);
1485:
1486: if ((eaddr - saddr) < sizeof(vm_offset_t)) {
1487: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1488: return MACH_SEND_MSG_TOO_SMALL;
1489: }
1490:
1491: /* grab the out-of-line data */
1492:
1493: addr = * (vm_offset_t *) saddr;
1494:
1495: if (length == 0)
1496: data = 0;
1497: else if (is_port) {
1498: data = kalloc(length);
1499: if (data == 0)
1500: goto invalid_memory;
1501:
1502: if (copyinmap(map, (char *) addr,
1503: (char *) data, length) ||
1504: (dealloc &&
1505: (vm_deallocate(map, addr, length) !=
1506: KERN_SUCCESS))) {
1507: kfree(data, length);
1508: goto invalid_memory;
1509: }
1510: } else {
1511: vm_map_copy_t copy;
1512:
1513: if (use_page_lists) {
1514: kr = vm_map_copyin_page_list(map,
1515: addr, length, dealloc,
1516: steal_pages, ©, FALSE);
1517: } else {
1518: kr = vm_map_copyin(map, addr, length,
1519: dealloc, ©);
1520: }
1521: if (kr != KERN_SUCCESS) {
1522: invalid_memory:
1523: ipc_kmsg_clean_partial(kmsg, taddr,
1524: FALSE, 0);
1525: return MACH_SEND_INVALID_MEMORY;
1526: }
1527:
1528: data = (vm_offset_t) copy;
1529: }
1530:
1531: * (vm_offset_t *) saddr = data;
1532: saddr += sizeof(vm_offset_t);
1533: complex = TRUE;
1534: }
1535:
1536: if (is_port) {
1537: mach_msg_type_name_t newname =
1538: ipc_object_copyin_type(name);
1539: ipc_object_t *objects = (ipc_object_t *) data;
1540: mach_msg_type_number_t i;
1541:
1542: if (longform)
1543: type->msgtl_name = newname;
1544: else
1545: ((mach_msg_type_t*)type)->msgt_name = newname;
1546:
1547: for (i = 0; i < number; i++) {
1548: mach_port_t port = (mach_port_t) objects[i];
1549: ipc_object_t object;
1550:
1551: if (!MACH_PORT_VALID(port))
1552: continue;
1553:
1554: kr = ipc_object_copyin(space, port,
1555: name, &object);
1556: if (kr != KERN_SUCCESS) {
1557: ipc_kmsg_clean_partial(kmsg, taddr,
1558: TRUE, i);
1559: return MACH_SEND_INVALID_RIGHT;
1560: }
1561:
1562: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1563: ipc_port_check_circularity(
1564: (ipc_port_t) object,
1565: (ipc_port_t) dest))
1566: kmsg->ikm_header.msgh_bits |=
1567: MACH_MSGH_BITS_CIRCULAR;
1568:
1569: objects[i] = object;
1570: }
1571:
1572: complex = TRUE;
1573: }
1574: }
1575:
1576: if (!complex)
1577: kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
1578:
1579: return MACH_MSG_SUCCESS;
1580: }
1581:
1582: /*
1583: * Routine: ipc_kmsg_copyin
1584: * Purpose:
1585: * "Copy-in" port rights and out-of-line memory
1586: * in the message.
1587: *
1588: * In all failure cases, the message is left holding
1589: * no rights or memory. However, the message buffer
1590: * is not deallocated. If successful, the message
1591: * contains a valid destination port.
1592: * Conditions:
1593: * Nothing locked.
1594: * Returns:
1595: * MACH_MSG_SUCCESS Successful copyin.
1596: * MACH_SEND_INVALID_HEADER
1597: * Illegal value in the message header bits.
1598: * MACH_SEND_INVALID_NOTIFY Bad notify port.
1599: * MACH_SEND_INVALID_DEST Can't copyin destination port.
1600: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
1601: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
1602: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
1603: * MACH_SEND_INVALID_TYPE Bad type specification.
1604: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
1605: */
1606:
1607: mach_msg_return_t
1608: ipc_kmsg_copyin(kmsg, space, map, notify)
1609: ipc_kmsg_t kmsg;
1610: ipc_space_t space;
1611: vm_map_t map;
1612: mach_port_t notify;
1613: {
1614: mach_msg_return_t mr;
1615:
1616: mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
1617: if (mr != MACH_MSG_SUCCESS)
1618: return mr;
1619:
1620: if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
1621: return MACH_MSG_SUCCESS;
1622:
1623: return ipc_kmsg_copyin_body(kmsg, space, map);
1624: }
1625:
1626: /*
1627: * Routine: ipc_kmsg_copyin_from_kernel
1628: * Purpose:
1629: * "Copy-in" port rights and out-of-line memory
1630: * in a message sent from the kernel.
1631: *
1632: * Because the message comes from the kernel,
1633: * the implementation assumes there are no errors
1634: * or peculiarities in the message.
1635: *
1636: * Returns TRUE if queueing the message
1637: * would result in a circularity.
1638: * Conditions:
1639: * Nothing locked.
1640: */
1641:
1642: void
1643: ipc_kmsg_copyin_from_kernel(
1644: ipc_kmsg_t kmsg)
1645: {
1646: mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
1647: mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
1648: mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
1649: ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1650: ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
1651: vm_offset_t saddr, eaddr;
1652:
1653: /* translate the destination and reply ports */
1654:
1655: ipc_object_copyin_from_kernel(remote, rname);
1656: if (IO_VALID(local))
1657: ipc_object_copyin_from_kernel(local, lname);
1658:
1659: /*
1660: * The common case is a complex message with no reply port,
1661: * because that is what the memory_object interface uses.
1662: */
1663:
1664: if (bits == (MACH_MSGH_BITS_COMPLEX |
1665: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
1666: bits = (MACH_MSGH_BITS_COMPLEX |
1667: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
1668:
1669: kmsg->ikm_header.msgh_bits = bits;
1670: } else {
1671: bits = (MACH_MSGH_BITS_OTHER(bits) |
1672: MACH_MSGH_BITS(ipc_object_copyin_type(rname),
1673: ipc_object_copyin_type(lname)));
1674:
1675: kmsg->ikm_header.msgh_bits = bits;
1676: if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
1677: return;
1678: }
1679:
1680: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1681: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1682:
1683: while (saddr < eaddr) {
1684: mach_msg_type_long_t *type;
1685: mach_msg_type_name_t name;
1686: mach_msg_type_size_t size;
1687: mach_msg_type_number_t number;
1688: boolean_t is_inline, longform, is_port;
1689: vm_offset_t data;
1690: vm_size_t length;
1691:
1692: type = (mach_msg_type_long_t *) saddr;
1693: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1694: longform = ((mach_msg_type_t*)type)->msgt_longform;
1695: /* type->msgtl_header.msgt_deallocate not used */
1696: if (longform) {
1697: /* This must be aligned */
1698: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1699: (is_misaligned(type))) {
1700: saddr = ptr_align(saddr);
1701: continue;
1702: }
1703: name = type->msgtl_name;
1704: size = type->msgtl_size;
1705: number = type->msgtl_number;
1706: saddr += sizeof(mach_msg_type_long_t);
1707: } else {
1708: name = ((mach_msg_type_t*)type)->msgt_name;
1709: size = ((mach_msg_type_t*)type)->msgt_size;
1710: number = ((mach_msg_type_t*)type)->msgt_number;
1711: saddr += sizeof(mach_msg_type_t);
1712: }
1713:
1714: /* padding (ptrs and ports) ? */
1715: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1716: ((size >> 3) == sizeof(natural_t)))
1717: saddr = ptr_align(saddr);
1718:
1719: /* calculate length of data in bytes, rounding up */
1720:
1721: length = ((number * size) + 7) >> 3;
1722:
1723: is_port = MACH_MSG_TYPE_PORT_ANY(name);
1724:
1725: if (is_inline) {
1726: /* inline data sizes round up to int boundaries */
1727:
1728: data = saddr;
1729: saddr += (length + 3) &~ 3;
1730: } else {
1731: /*
1732: * The sender should supply ready-made memory
1733: * for us, so we don't need to do anything.
1734: */
1735:
1736: data = * (vm_offset_t *) saddr;
1737: saddr += sizeof(vm_offset_t);
1738: }
1739:
1740: if (is_port) {
1741: mach_msg_type_name_t newname =
1742: ipc_object_copyin_type(name);
1743: ipc_object_t *objects = (ipc_object_t *) data;
1744: mach_msg_type_number_t i;
1745:
1746: if (longform)
1747: type->msgtl_name = newname;
1748: else
1749: ((mach_msg_type_t*)type)->msgt_name = newname;
1750: for (i = 0; i < number; i++) {
1751: ipc_object_t object = objects[i];
1752:
1753: if (!IO_VALID(object))
1754: continue;
1755:
1756: ipc_object_copyin_from_kernel(object, name);
1757:
1758: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1759: ipc_port_check_circularity(
1760: (ipc_port_t) object,
1761: (ipc_port_t) remote))
1762: kmsg->ikm_header.msgh_bits |=
1763: MACH_MSGH_BITS_CIRCULAR;
1764: }
1765: }
1766: }
1767: }
1768:
1769: /*
1770: * Routine: ipc_kmsg_copyout_header
1771: * Purpose:
1772: * "Copy-out" port rights in the header of a message.
1773: * Operates atomically; if it doesn't succeed the
1774: * message header and the space are left untouched.
1775: * If it does succeed the remote/local port fields
1776: * contain port names instead of object pointers,
1777: * and the bits field is updated.
1778: *
1779: * The notify argument implements the MACH_RCV_NOTIFY option.
1780: * If it is not MACH_PORT_NULL, it should name a receive right.
1781: * If the process of receiving the reply port creates a
1782: * new right in the receiving task, then the new right is
1783: * automatically registered for a dead-name notification,
1784: * with the notify port supplying the send-once right.
1785: * Conditions:
1786: * Nothing locked.
1787: * Returns:
1788: * MACH_MSG_SUCCESS Copied out port rights.
1789: * MACH_RCV_INVALID_NOTIFY
1790: * Notify is non-null and doesn't name a receive right.
1791: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1792: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1793: * The space is dead.
1794: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1795: * No room in space for another name.
1796: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1797: * Couldn't allocate memory for the reply port.
1798: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1799: * Couldn't allocate memory for the dead-name request.
1800: */
1801:
1802: mach_msg_return_t
1803: ipc_kmsg_copyout_header(msg, space, notify)
1804: mach_msg_header_t *msg;
1805: ipc_space_t space;
1806: mach_port_t notify;
1807: {
1808: mach_msg_bits_t mbits = msg->msgh_bits;
1809: ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
1810:
1811: assert(IP_VALID(dest));
1812:
1813: #ifndef MIGRATING_THREADS
1814: /* first check for common cases */
1815:
1816: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
1817: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
1818: mach_port_t dest_name;
1819: ipc_port_t nsrequest;
1820:
1821: /* receiving an asynchronous message */
1822:
1823: ip_lock(dest);
1824: if (!ip_active(dest)) {
1825: ip_unlock(dest);
1826: break;
1827: }
1828:
1829: /* optimized ipc_object_copyout_dest */
1830:
1831: assert(dest->ip_srights > 0);
1832: ip_release(dest);
1833:
1834: if (dest->ip_receiver == space)
1835: dest_name = dest->ip_receiver_name;
1836: else
1837: dest_name = MACH_PORT_NULL;
1838:
1839: if ((--dest->ip_srights == 0) &&
1840: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
1841: mach_port_mscount_t mscount;
1842:
1843: dest->ip_nsrequest = IP_NULL;
1844: mscount = dest->ip_mscount;
1845: ip_unlock(dest);
1846:
1847: ipc_notify_no_senders(nsrequest, mscount);
1848: } else
1849: ip_unlock(dest);
1850:
1851: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1852: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
1853: msg->msgh_local_port = dest_name;
1854: msg->msgh_remote_port = MACH_PORT_NULL;
1855: return MACH_MSG_SUCCESS;
1856: }
1857:
1858: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1859: MACH_MSG_TYPE_PORT_SEND_ONCE): {
1860: ipc_entry_t table;
1861: mach_port_index_t index;
1862: ipc_entry_t entry;
1863: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
1864: mach_port_t dest_name, reply_name;
1865: ipc_port_t nsrequest;
1866:
1867: /* receiving a request message */
1868:
1869: if (!IP_VALID(reply))
1870: break;
1871:
1872: is_write_lock(space);
1873: if (!space->is_active ||
1874: ((index = (table = space->is_table)->ie_next) == 0)) {
1875: is_write_unlock(space);
1876: break;
1877: }
1878:
1879: /*
1880: * To do an atomic copyout, need simultaneous
1881: * locks on both ports and the space. If
1882: * dest == reply, and simple locking is
1883: * enabled, then we will abort. Otherwise it's
1884: * OK to unlock twice.
1885: */
1886:
1887: ip_lock(dest);
1888: if (!ip_active(dest) || !ip_lock_try(reply)) {
1889: ip_unlock(dest);
1890: is_write_unlock(space);
1891: break;
1892: }
1893:
1894: if (!ip_active(reply)) {
1895: ip_unlock(reply);
1896: ip_unlock(dest);
1897: is_write_unlock(space);
1898: break;
1899: }
1900:
1901: assert(reply->ip_sorights > 0);
1902: ip_unlock(reply);
1903:
1904: /* optimized ipc_entry_get */
1905:
1906: entry = &table[index];
1907: table->ie_next = entry->ie_next;
1908: entry->ie_request = 0;
1909:
1910: {
1911: mach_port_gen_t gen;
1912:
1913: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
1914: gen = entry->ie_bits + IE_BITS_GEN_ONE;
1915:
1916: reply_name = MACH_PORT_MAKE(index, gen);
1917:
1918: /* optimized ipc_right_copyout */
1919:
1920: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
1921: }
1922:
1923: assert(MACH_PORT_VALID(reply_name));
1924: entry->ie_object = (ipc_object_t) reply;
1925: is_write_unlock(space);
1926:
1927: /* optimized ipc_object_copyout_dest */
1928:
1929: assert(dest->ip_srights > 0);
1930: ip_release(dest);
1931:
1932: if (dest->ip_receiver == space)
1933: dest_name = dest->ip_receiver_name;
1934: else
1935: dest_name = MACH_PORT_NULL;
1936:
1937: if ((--dest->ip_srights == 0) &&
1938: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
1939: mach_port_mscount_t mscount;
1940:
1941: dest->ip_nsrequest = IP_NULL;
1942: mscount = dest->ip_mscount;
1943: ip_unlock(dest);
1944:
1945: ipc_notify_no_senders(nsrequest, mscount);
1946: } else
1947: ip_unlock(dest);
1948:
1949: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1950: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1951: MACH_MSG_TYPE_PORT_SEND));
1952: msg->msgh_local_port = dest_name;
1953: msg->msgh_remote_port = reply_name;
1954: return MACH_MSG_SUCCESS;
1955: }
1956:
1957: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
1958: mach_port_t dest_name;
1959:
1960: /* receiving a reply message */
1961:
1962: ip_lock(dest);
1963: if (!ip_active(dest)) {
1964: ip_unlock(dest);
1965: break;
1966: }
1967:
1968: /* optimized ipc_object_copyout_dest */
1969:
1970: assert(dest->ip_sorights > 0);
1971:
1972: if (dest->ip_receiver == space) {
1973: ip_release(dest);
1974: dest->ip_sorights--;
1975: dest_name = dest->ip_receiver_name;
1976: ip_unlock(dest);
1977: } else {
1978: ip_unlock(dest);
1979:
1980: ipc_notify_send_once(dest);
1981: dest_name = MACH_PORT_NULL;
1982: }
1983:
1984: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1985: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE));
1986: msg->msgh_local_port = dest_name;
1987: msg->msgh_remote_port = MACH_PORT_NULL;
1988: return MACH_MSG_SUCCESS;
1989: }
1990:
1991: default:
1992: /* don't bother optimizing */
1993: break;
1994: }
1995: #endif /* MIGRATING_THREADS */
1996:
1997: {
1998: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
1999: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2000: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
2001: mach_port_t dest_name, reply_name;
2002:
2003: if (IP_VALID(reply)) {
2004: ipc_port_t notify_port;
2005: ipc_entry_t entry;
2006: kern_return_t kr;
2007:
2008: /*
2009: * Handling notify (for MACH_RCV_NOTIFY) is tricky.
2010: * The problem is atomically making a send-once right
2011: * from the notify port and installing it for a
2012: * dead-name request in the new entry, because this
2013: * requires two port locks (on the notify port and
2014: * the reply port). However, we can safely make
2015: * and consume send-once rights for the notify port
2016: * as long as we hold the space locked. This isn't
2017: * an atomicity problem, because the only way
2018: * to detect that a send-once right has been created
2019: * and then consumed if it wasn't needed is by getting
2020: * at the receive right to look at ip_sorights, and
2021: * because the space is write-locked status calls can't
2022: * lookup the notify port receive right. When we make
2023: * the send-once right, we lock the notify port,
2024: * so any status calls in progress will be done.
2025: */
2026:
2027: is_write_lock(space);
2028:
2029: for (;;) {
2030: ipc_port_request_index_t request;
2031:
2032: if (!space->is_active) {
2033: is_write_unlock(space);
2034: return (MACH_RCV_HEADER_ERROR|
2035: MACH_MSG_IPC_SPACE);
2036: }
2037:
2038: if (notify != MACH_PORT_NULL) {
2039: notify_port = ipc_port_lookup_notify(space,
2040: notify);
2041: if (notify_port == IP_NULL) {
2042: is_write_unlock(space);
2043: return MACH_RCV_INVALID_NOTIFY;
2044: }
2045: } else
2046: notify_port = IP_NULL;
2047:
2048: if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
2049: ipc_right_reverse(space, (ipc_object_t) reply,
2050: &reply_name, &entry)) {
2051: /* reply port is locked and active */
2052:
2053: /*
2054: * We don't need the notify_port
2055: * send-once right, but we can't release
2056: * it here because reply port is locked.
2057: * Wait until after the copyout to
2058: * release the notify port right.
2059: */
2060:
2061: assert(entry->ie_bits &
2062: MACH_PORT_TYPE_SEND_RECEIVE);
2063: break;
2064: }
2065:
2066: ip_lock(reply);
2067: if (!ip_active(reply)) {
2068: ip_release(reply);
2069: ip_check_unlock(reply);
2070:
2071: if (notify_port != IP_NULL)
2072: ipc_port_release_sonce(notify_port);
2073:
2074: ip_lock(dest);
2075: is_write_unlock(space);
2076:
2077: reply = IP_DEAD;
2078: reply_name = MACH_PORT_DEAD;
2079: goto copyout_dest;
2080: }
2081:
2082: kr = ipc_entry_get(space, &reply_name, &entry);
2083: if (kr != KERN_SUCCESS) {
2084: ip_unlock(reply);
2085:
2086: if (notify_port != IP_NULL)
2087: ipc_port_release_sonce(notify_port);
2088:
2089: /* space is locked */
2090: kr = ipc_entry_grow_table(space);
2091: if (kr != KERN_SUCCESS) {
2092: /* space is unlocked */
2093:
2094: if (kr == KERN_RESOURCE_SHORTAGE)
2095: return (MACH_RCV_HEADER_ERROR|
2096: MACH_MSG_IPC_KERNEL);
2097: else
2098: return (MACH_RCV_HEADER_ERROR|
2099: MACH_MSG_IPC_SPACE);
2100: }
2101: /* space is locked again; start over */
2102:
2103: continue;
2104: }
2105:
2106: assert(IE_BITS_TYPE(entry->ie_bits)
2107: == MACH_PORT_TYPE_NONE);
2108: assert(entry->ie_object == IO_NULL);
2109:
2110: if (notify_port == IP_NULL) {
2111: /* not making a dead-name request */
2112:
2113: entry->ie_object = (ipc_object_t) reply;
2114: break;
2115: }
2116:
2117: kr = ipc_port_dnrequest(reply, reply_name,
2118: notify_port, &request);
2119: if (kr != KERN_SUCCESS) {
2120: ip_unlock(reply);
2121:
2122: ipc_port_release_sonce(notify_port);
2123:
2124: ipc_entry_dealloc(space, reply_name, entry);
2125: is_write_unlock(space);
2126:
2127: ip_lock(reply);
2128: if (!ip_active(reply)) {
2129: /* will fail next time around loop */
2130:
2131: ip_unlock(reply);
2132: is_write_lock(space);
2133: continue;
2134: }
2135:
2136: kr = ipc_port_dngrow(reply);
2137: /* port is unlocked */
2138: if (kr != KERN_SUCCESS)
2139: return (MACH_RCV_HEADER_ERROR|
2140: MACH_MSG_IPC_KERNEL);
2141:
2142: is_write_lock(space);
2143: continue;
2144: }
2145:
2146: notify_port = IP_NULL; /* don't release right below */
2147:
2148: entry->ie_object = (ipc_object_t) reply;
2149: entry->ie_request = request;
2150: break;
2151: }
2152:
2153: /* space and reply port are locked and active */
2154:
2155: ip_reference(reply); /* hold onto the reply port */
2156:
2157: kr = ipc_right_copyout(space, reply_name, entry,
2158: reply_type, TRUE, (ipc_object_t) reply);
2159: /* reply port is unlocked */
2160: assert(kr == KERN_SUCCESS);
2161:
2162: if (notify_port != IP_NULL)
2163: ipc_port_release_sonce(notify_port);
2164:
2165: ip_lock(dest);
2166: is_write_unlock(space);
2167: } else {
2168: /*
2169: * No reply port! This is an easy case.
2170: * We only need to have the space locked
2171: * when checking notify and when locking
2172: * the destination (to ensure atomicity).
2173: */
2174:
2175: is_read_lock(space);
2176: if (!space->is_active) {
2177: is_read_unlock(space);
2178: return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
2179: }
2180:
2181: if (notify != MACH_PORT_NULL) {
2182: ipc_entry_t entry;
2183:
2184: /* must check notify even though it won't be used */
2185:
2186: if (((entry = ipc_entry_lookup(space, notify))
2187: == IE_NULL) ||
2188: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
2189: is_read_unlock(space);
2190: return MACH_RCV_INVALID_NOTIFY;
2191: }
2192: }
2193:
2194: ip_lock(dest);
2195: is_read_unlock(space);
2196:
2197: reply_name = (mach_port_t) reply;
2198: }
2199:
2200: /*
2201: * At this point, the space is unlocked and the destination
2202: * port is locked. (Lock taken while space was locked.)
2203: * reply_name is taken care of; we still need dest_name.
2204: * We still hold a ref for reply (if it is valid).
2205: *
2206: * If the space holds receive rights for the destination,
2207: * we return its name for the right. Otherwise the task
2208: * managed to destroy or give away the receive right between
2209: * receiving the message and this copyout. If the destination
2210: * is dead, return MACH_PORT_DEAD, and if the receive right
2211: * exists somewhere else (another space, in transit)
2212: * return MACH_PORT_NULL.
2213: *
2214: * Making this copyout operation atomic with the previous
2215: * copyout of the reply port is a bit tricky. If there was
2216: * no real reply port (it wasn't IP_VALID) then this isn't
2217: * an issue. If the reply port was dead at copyout time,
2218: * then we are OK, because if dest is dead we serialize
2219: * after the death of both ports and if dest is alive
2220: * we serialize after reply died but before dest's (later) death.
2221: * So assume reply was alive when we copied it out. If dest
2222: * is alive, then we are OK because we serialize before
2223: * the ports' deaths. So assume dest is dead when we look at it.
2224: * If reply dies/died after dest, then we are OK because
2225: * we serialize after dest died but before reply dies.
2226: * So the hard case is when reply is alive at copyout,
2227: * dest is dead at copyout, and reply died before dest died.
2228: * In this case pretend that dest is still alive, so
2229: * we serialize while both ports are alive.
2230: *
2231: * Because the space lock is held across the copyout of reply
2232: * and locking dest, the receive right for dest can't move
2233: * in or out of the space while the copyouts happen, so
2234: * that isn't an atomicity problem. In the last hard case
2235: * above, this implies that when dest is dead that the
2236: * space couldn't have had receive rights for dest at
2237: * the time reply was copied-out, so when we pretend
2238: * that dest is still alive, we can return MACH_PORT_NULL.
2239: *
2240: * If dest == reply, then we have to make it look like
2241: * either both copyouts happened before the port died,
2242: * or both happened after the port died. This special
2243: * case works naturally if the timestamp comparison
2244: * is done correctly.
2245: */
2246:
2247: copyout_dest:
2248:
2249: if (ip_active(dest)) {
2250: ipc_object_copyout_dest(space, (ipc_object_t) dest,
2251: dest_type, &dest_name);
2252: /* dest is unlocked */
2253: } else {
2254: ipc_port_timestamp_t timestamp;
2255:
2256: timestamp = dest->ip_timestamp;
2257: ip_release(dest);
2258: ip_check_unlock(dest);
2259:
2260: if (IP_VALID(reply)) {
2261: ip_lock(reply);
2262: if (ip_active(reply) ||
2263: IP_TIMESTAMP_ORDER(timestamp,
2264: reply->ip_timestamp))
2265: dest_name = MACH_PORT_DEAD;
2266: else
2267: dest_name = MACH_PORT_NULL;
2268: ip_unlock(reply);
2269: } else
2270: dest_name = MACH_PORT_DEAD;
2271: }
2272:
2273: if (IP_VALID(reply))
2274: ipc_port_release(reply);
2275:
2276: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2277: MACH_MSGH_BITS(reply_type, dest_type));
2278: msg->msgh_local_port = dest_name;
2279: msg->msgh_remote_port = reply_name;
2280: }
2281:
2282: return MACH_MSG_SUCCESS;
2283: }
2284:
2285: /*
2286: * Routine: ipc_kmsg_copyout_object
2287: * Purpose:
2288: * Copy-out a port right. Always returns a name,
2289: * even for unsuccessful return codes. Always
2290: * consumes the supplied object.
2291: * Conditions:
2292: * Nothing locked.
2293: * Returns:
2294: * MACH_MSG_SUCCESS The space acquired the right
2295: * (name is valid) or the object is dead (MACH_PORT_DEAD).
2296: * MACH_MSG_IPC_SPACE No room in space for the right,
2297: * or the space is dead. (Name is MACH_PORT_NULL.)
2298: * MACH_MSG_IPC_KERNEL Kernel resource shortage.
2299: * (Name is MACH_PORT_NULL.)
2300: */
2301:
2302: mach_msg_return_t
2303: ipc_kmsg_copyout_object(space, object, msgt_name, namep)
2304: ipc_space_t space;
2305: ipc_object_t object;
2306: mach_msg_type_name_t msgt_name;
2307: mach_port_t *namep;
2308: {
2309: if (!IO_VALID(object)) {
2310: *namep = (mach_port_t) object;
2311: return MACH_MSG_SUCCESS;
2312: }
2313:
2314: #ifndef MIGRATING_THREADS
2315: /*
2316: * Attempt quick copyout of send rights. We optimize for a
2317: * live port for which the receiver holds send (and not
2318: * receive) rights in his local table.
2319: */
2320:
2321: if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
2322: goto slow_copyout;
2323:
2324: {
2325: register ipc_port_t port = (ipc_port_t) object;
2326: ipc_entry_t entry;
2327:
2328: is_write_lock(space);
2329: if (!space->is_active) {
2330: is_write_unlock(space);
2331: goto slow_copyout;
2332: }
2333:
2334: ip_lock(port);
2335: if (!ip_active(port) ||
2336: !ipc_hash_local_lookup(space, (ipc_object_t) port,
2337: namep, &entry)) {
2338: ip_unlock(port);
2339: is_write_unlock(space);
2340: goto slow_copyout;
2341: }
2342:
2343: /*
2344: * Copyout the send right, incrementing urefs
2345: * unless it would overflow, and consume the right.
2346: */
2347:
2348: assert(port->ip_srights > 1);
2349: port->ip_srights--;
2350: ip_release(port);
2351: ip_unlock(port);
2352:
2353: assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
2354: assert(IE_BITS_UREFS(entry->ie_bits) > 0);
2355: assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
2356:
2357: {
2358: register ipc_entry_bits_t bits = entry->ie_bits + 1;
2359:
2360: if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2361: entry->ie_bits = bits;
2362: }
2363:
2364: is_write_unlock(space);
2365: return MACH_MSG_SUCCESS;
2366: }
2367:
2368: slow_copyout:
2369: #endif /* MIGRATING_THREADS */
2370:
2371: {
2372: kern_return_t kr;
2373:
2374: kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
2375: if (kr != KERN_SUCCESS) {
2376: ipc_object_destroy(object, msgt_name);
2377:
2378: if (kr == KERN_INVALID_CAPABILITY)
2379: *namep = MACH_PORT_DEAD;
2380: else {
2381: *namep = MACH_PORT_NULL;
2382:
2383: if (kr == KERN_RESOURCE_SHORTAGE)
2384: return MACH_MSG_IPC_KERNEL;
2385: else
2386: return MACH_MSG_IPC_SPACE;
2387: }
2388: }
2389:
2390: return MACH_MSG_SUCCESS;
2391: }
2392: }
2393:
2394: /*
2395: * Routine: ipc_kmsg_copyout_body
2396: * Purpose:
2397: * "Copy-out" port rights and out-of-line memory
2398: * in the body of a message.
2399: *
2400: * The error codes are a combination of special bits.
2401: * The copyout proceeds despite errors.
2402: * Conditions:
2403: * Nothing locked.
2404: * Returns:
2405: * MACH_MSG_SUCCESS Successful copyout.
2406: * MACH_MSG_IPC_SPACE No room for port right in name space.
2407: * MACH_MSG_VM_SPACE No room for memory in address space.
2408: * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2409: * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2410: */
2411:
2412: mach_msg_return_t
2413: ipc_kmsg_copyout_body(saddr, eaddr, space, map)
2414: vm_offset_t saddr, eaddr;
2415: ipc_space_t space;
2416: vm_map_t map;
2417: {
2418: mach_msg_return_t mr = MACH_MSG_SUCCESS;
2419: kern_return_t kr;
2420:
2421: while (saddr < eaddr) {
2422: vm_offset_t taddr = saddr;
2423: mach_msg_type_long_t *type;
2424: mach_msg_type_name_t name;
2425: mach_msg_type_size_t size;
2426: mach_msg_type_number_t number;
2427: boolean_t is_inline, longform, is_port;
2428: vm_size_t length;
2429: vm_offset_t addr;
2430:
2431: type = (mach_msg_type_long_t *) saddr;
2432: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
2433: longform = ((mach_msg_type_t*)type)->msgt_longform;
2434: if (longform) {
2435: /* This must be aligned */
2436: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2437: (is_misaligned(type))) {
2438: saddr = ptr_align(saddr);
2439: continue;
2440: }
2441: name = type->msgtl_name;
2442: size = type->msgtl_size;
2443: number = type->msgtl_number;
2444: saddr += sizeof(mach_msg_type_long_t);
2445: } else {
2446: name = ((mach_msg_type_t*)type)->msgt_name;
2447: size = ((mach_msg_type_t*)type)->msgt_size;
2448: number = ((mach_msg_type_t*)type)->msgt_number;
2449: saddr += sizeof(mach_msg_type_t);
2450: }
2451:
2452: /* padding (ptrs and ports) ? */
2453: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2454: ((size >> 3) == sizeof(natural_t)))
2455: saddr = ptr_align(saddr);
2456:
2457: /* calculate length of data in bytes, rounding up */
2458:
2459: length = ((number * size) + 7) >> 3;
2460:
2461: is_port = MACH_MSG_TYPE_PORT_ANY(name);
2462:
2463: if (is_port) {
2464: mach_port_t *objects;
2465: mach_msg_type_number_t i;
2466:
2467: if (!is_inline && (length != 0)) {
2468: /* first allocate memory in the map */
2469:
2470: kr = vm_allocate(map, &addr, length, TRUE);
2471: if (kr != KERN_SUCCESS) {
2472: ipc_kmsg_clean_body(taddr, saddr);
2473: goto vm_copyout_failure;
2474: }
2475: }
2476:
2477: objects = (mach_port_t *)
2478: (is_inline ? saddr : * (vm_offset_t *) saddr);
2479:
2480: /* copyout port rights carried in the message */
2481:
2482: for (i = 0; i < number; i++) {
2483: ipc_object_t object =
2484: (ipc_object_t) objects[i];
2485:
2486: mr |= ipc_kmsg_copyout_object(space, object,
2487: name, &objects[i]);
2488: }
2489: }
2490:
2491: if (is_inline) {
2492: /* inline data sizes round up to int boundaries */
2493:
2494: ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
2495: saddr += (length + 3) &~ 3;
2496: } else {
2497: vm_offset_t data;
2498:
2499: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
2500: saddr = ptr_align(saddr);
2501:
2502: data = * (vm_offset_t *) saddr;
2503:
2504: /* copyout memory carried in the message */
2505:
2506: if (length == 0) {
2507: assert(data == 0);
2508: addr = 0;
2509: } else if (is_port) {
2510: /* copyout to memory allocated above */
2511:
2512: (void) copyoutmap(map, (char *) data,
2513: (char *) addr, length);
2514: kfree(data, length);
2515: } else {
2516: vm_map_copy_t copy = (vm_map_copy_t) data;
2517:
2518: kr = vm_map_copyout(map, &addr, copy);
2519: if (kr != KERN_SUCCESS) {
2520: vm_map_copy_discard(copy);
2521:
2522: vm_copyout_failure:
2523:
2524: addr = 0;
2525: if (longform)
2526: type->msgtl_size = 0;
2527: else
2528: ((mach_msg_type_t*)type)->msgt_size = 0;
2529:
2530: if (kr == KERN_RESOURCE_SHORTAGE)
2531: mr |= MACH_MSG_VM_KERNEL;
2532: else
2533: mr |= MACH_MSG_VM_SPACE;
2534: }
2535: }
2536:
2537: ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
2538: * (vm_offset_t *) saddr = addr;
2539: saddr += sizeof(vm_offset_t);
2540: }
2541: }
2542:
2543: return mr;
2544: }
2545:
2546: /*
2547: * Routine: ipc_kmsg_copyout
2548: * Purpose:
2549: * "Copy-out" port rights and out-of-line memory
2550: * in the message.
2551: * Conditions:
2552: * Nothing locked.
2553: * Returns:
2554: * MACH_MSG_SUCCESS Copied out all rights and memory.
2555: * MACH_RCV_INVALID_NOTIFY Bad notify port.
2556: * Rights and memory in the message are intact.
2557: * MACH_RCV_HEADER_ERROR + special bits
2558: * Rights and memory in the message are intact.
2559: * MACH_RCV_BODY_ERROR + special bits
2560: * The message header was successfully copied out.
2561: * As much of the body was handled as possible.
2562: */
2563:
2564: mach_msg_return_t
2565: ipc_kmsg_copyout(kmsg, space, map, notify)
2566: ipc_kmsg_t kmsg;
2567: ipc_space_t space;
2568: vm_map_t map;
2569: mach_port_t notify;
2570: {
2571: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2572: mach_msg_return_t mr;
2573:
2574: mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
2575: if (mr != MACH_MSG_SUCCESS)
2576: return mr;
2577:
2578: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2579: vm_offset_t saddr, eaddr;
2580:
2581: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2582: eaddr = (vm_offset_t) &kmsg->ikm_header +
2583: kmsg->ikm_header.msgh_size;
2584:
2585: mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2586: if (mr != MACH_MSG_SUCCESS)
2587: mr |= MACH_RCV_BODY_ERROR;
2588: }
2589:
2590: return mr;
2591: }
2592:
2593: /*
2594: * Routine: ipc_kmsg_copyout_pseudo
2595: * Purpose:
2596: * Does a pseudo-copyout of the message.
2597: * This is like a regular copyout, except
2598: * that the ports in the header are handled
2599: * as if they are in the body. They aren't reversed.
2600: *
2601: * The error codes are a combination of special bits.
2602: * The copyout proceeds despite errors.
2603: * Conditions:
2604: * Nothing locked.
2605: * Returns:
2606: * MACH_MSG_SUCCESS Successful copyout.
2607: * MACH_MSG_IPC_SPACE No room for port right in name space.
2608: * MACH_MSG_VM_SPACE No room for memory in address space.
2609: * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2610: * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2611: */
2612:
2613: mach_msg_return_t
2614: ipc_kmsg_copyout_pseudo(
2615: ipc_kmsg_t kmsg,
2616: ipc_space_t space,
2617: vm_map_t map)
2618: {
2619: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2620: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2621: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2622: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2623: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2624: mach_port_t dest_name, reply_name;
2625: mach_msg_return_t mr;
2626:
2627: assert(IO_VALID(dest));
2628:
2629: mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
2630: ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
2631:
2632: kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
2633: kmsg->ikm_header.msgh_remote_port = dest_name;
2634: kmsg->ikm_header.msgh_local_port = reply_name;
2635:
2636: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2637: vm_offset_t saddr, eaddr;
2638:
2639: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2640: eaddr = (vm_offset_t) &kmsg->ikm_header +
2641: kmsg->ikm_header.msgh_size;
2642:
2643: mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2644: }
2645:
2646: return mr;
2647: }
2648:
2649: /*
2650: * Routine: ipc_kmsg_copyout_dest
2651: * Purpose:
2652: * Copies out the destination port in the message.
2653: * Destroys all other rights and memory in the message.
2654: * Conditions:
2655: * Nothing locked.
2656: */
2657:
2658: void
2659: ipc_kmsg_copyout_dest(kmsg, space)
2660: ipc_kmsg_t kmsg;
2661: ipc_space_t space;
2662: {
2663: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2664: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2665: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2666: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2667: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2668: mach_port_t dest_name, reply_name;
2669:
2670: assert(IO_VALID(dest));
2671:
2672: io_lock(dest);
2673: if (io_active(dest)) {
2674: ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2675: /* dest is unlocked */
2676: } else {
2677: io_release(dest);
2678: io_check_unlock(dest);
2679: dest_name = MACH_PORT_DEAD;
2680: }
2681:
2682: if (IO_VALID(reply)) {
2683: ipc_object_destroy(reply, reply_type);
2684: reply_name = MACH_PORT_NULL;
2685: } else
2686: reply_name = (mach_port_t) reply;
2687:
2688: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2689: MACH_MSGH_BITS(reply_type, dest_type));
2690: kmsg->ikm_header.msgh_local_port = dest_name;
2691: kmsg->ikm_header.msgh_remote_port = reply_name;
2692:
2693: if (mbits & MACH_MSGH_BITS_COMPLEX) {
2694: vm_offset_t saddr, eaddr;
2695:
2696: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2697: eaddr = (vm_offset_t) &kmsg->ikm_header +
2698: kmsg->ikm_header.msgh_size;
2699:
2700: ipc_kmsg_clean_body(saddr, eaddr);
2701: }
2702: }
2703:
2704: #if NORMA_IPC || NORMA_VM
2705: /*
2706: * Routine: ipc_kmsg_copyout_to_kernel
2707: * Purpose:
2708: * Copies out the destination and reply ports in the message.
2709: * Leaves all other rights and memory in the message alone.
2710: * Conditions:
2711: * Nothing locked.
2712: *
2713: * Derived from ipc_kmsg_copyout_dest.
2714: * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
2715: * We really do want to save rights and memory.
2716: */
2717:
2718: void
2719: ipc_kmsg_copyout_to_kernel(kmsg, space)
2720: ipc_kmsg_t kmsg;
2721: ipc_space_t space;
2722: {
2723: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2724: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2725: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2726: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2727: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2728: mach_port_t dest_name, reply_name;
2729:
2730: assert(IO_VALID(dest));
2731:
2732: io_lock(dest);
2733: if (io_active(dest)) {
2734: ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2735: /* dest is unlocked */
2736: } else {
2737: io_release(dest);
2738: io_check_unlock(dest);
2739: dest_name = MACH_PORT_DEAD;
2740: }
2741:
2742: reply_name = (mach_port_t) reply;
2743:
2744: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2745: MACH_MSGH_BITS(reply_type, dest_type));
2746: kmsg->ikm_header.msgh_local_port = dest_name;
2747: kmsg->ikm_header.msgh_remote_port = reply_name;
2748: }
2749: #endif /* NORMA_IPC || NORMA_VM */
2750:
2751: #if MACH_IPC_COMPAT
2752:
2753: /*
2754: * Routine: ipc_kmsg_copyin_compat
2755: * Purpose:
2756: * "Copy-in" port rights and out-of-line memory
2757: * in the message.
2758: *
2759: * In all failure cases, the message is left holding
2760: * no rights or memory. However, the message buffer
2761: * is not deallocated. If successful, the message
2762: * contains a valid destination port.
2763: * Conditions:
2764: * Nothing locked.
2765: * Returns:
2766: * MACH_MSG_SUCCESS Successful copyin.
2767: * MACH_SEND_INVALID_DEST Can't copyin destination port.
2768: * MACH_SEND_INVALID_REPLY Can't copyin reply port.
2769: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
2770: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
2771: * MACH_SEND_INVALID_TYPE Bad type specification.
2772: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
2773: */
2774:
2775: mach_msg_return_t
2776: ipc_kmsg_copyin_compat(kmsg, space, map)
2777: ipc_kmsg_t kmsg;
2778: ipc_space_t space;
2779: vm_map_t map;
2780: {
2781: msg_header_t msg;
2782: mach_port_t dest_name;
2783: mach_port_t reply_name;
2784: ipc_object_t dest, reply;
2785: mach_msg_type_name_t dest_type, reply_type;
2786: vm_offset_t saddr, eaddr;
2787: boolean_t complex;
2788: kern_return_t kr;
2789: boolean_t use_page_lists, steal_pages;
2790:
2791: msg = * (msg_header_t *) &kmsg->ikm_header;
2792: dest_name = (mach_port_t) msg.msg_remote_port;
2793: reply_name = (mach_port_t) msg.msg_local_port;
2794:
2795: /* translate the destination and reply ports */
2796:
2797: kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type);
2798: if (kr != KERN_SUCCESS)
2799: return MACH_SEND_INVALID_DEST;
2800:
2801: if (reply_name == MACH_PORT_NULL) {
2802: reply = IO_NULL;
2803: reply_type = 0;
2804: } else {
2805: kr = ipc_object_copyin_header(space, reply_name,
2806: &reply, &reply_type);
2807: if (kr != KERN_SUCCESS) {
2808: ipc_object_destroy(dest, dest_type);
2809: return MACH_SEND_INVALID_REPLY;
2810: }
2811: }
2812:
2813: kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type);
2814: kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size;
2815: kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest;
2816: kmsg->ikm_header.msgh_local_port = (mach_port_t) reply;
2817: kmsg->ikm_header.msgh_seqno = (mach_msg_kind_t) msg.msg_type;
2818: kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id;
2819:
2820: if (msg.msg_simple)
2821: return MACH_MSG_SUCCESS;
2822:
2823: complex = FALSE;
2824: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
2825: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
2826:
2827: #if NORMA_IPC
2828: if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
2829: use_page_lists = TRUE;
2830: steal_pages = TRUE;
2831: }
2832: #endif /* NORMA_IPC */
2833:
2834: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2835: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
2836:
2837: while (saddr < eaddr) {
2838: vm_offset_t taddr = saddr;
2839: mach_msg_type_long_t *type;
2840: mach_msg_type_name_t name;
2841: mach_msg_type_size_t size;
2842: mach_msg_type_number_t number;
2843: boolean_t is_inline, longform, dealloc, is_port;
2844: vm_offset_t data;
2845: vm_size_t length;
2846:
2847: type = (mach_msg_type_long_t *) saddr;
2848:
2849: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
2850: ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
2851: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
2852: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
2853: return MACH_SEND_MSG_TOO_SMALL;
2854: }
2855:
2856: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
2857: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
2858: if (longform) {
2859: /* This must be aligned */
2860: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2861: (is_misaligned(type))) {
2862: saddr = ptr_align(saddr);
2863: continue;
2864: }
2865: name = type->msgtl_name;
2866: size = type->msgtl_size;
2867: number = type->msgtl_number;
2868: saddr += sizeof(mach_msg_type_long_t);
2869: } else {
2870: name = ((mach_msg_type_t*)type)->msgt_name;
2871: size = ((mach_msg_type_t*)type)->msgt_size;
2872: number = ((mach_msg_type_t*)type)->msgt_number;
2873: saddr += sizeof(mach_msg_type_t);
2874: }
2875:
2876: is_port = MSG_TYPE_PORT_ANY(name);
2877:
2878: if (is_port && (size != PORT_T_SIZE_IN_BITS)) {
2879: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
2880: return MACH_SEND_INVALID_TYPE;
2881: }
2882:
2883: /*
2884: * New IPC says these should be zero, but old IPC
2885: * tasks often leave them with random values. So
2886: * we have to clear them.
2887: */
2888:
2889: ((mach_msg_type_t*)type)->msgt_unused = 0;
2890: if (longform) {
2891: type->msgtl_header.msgt_name = 0;
2892: type->msgtl_header.msgt_size = 0;
2893: type->msgtl_header.msgt_number = 0;
2894: }
2895:
2896: /* padding (ptrs and ports) ? */
2897: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2898: ((size >> 3) == sizeof(natural_t)))
2899: saddr = ptr_align(saddr);
2900:
2901: /* calculate length of data in bytes, rounding up */
2902:
2903: length = ((number * size) + 7) >> 3;
2904:
2905: if (is_inline) {
2906: vm_size_t amount;
2907:
2908: /* inline data sizes round up to int boundaries */
2909:
2910: amount = (length + 3) &~ 3;
2911: if ((eaddr - saddr) < amount) {
2912: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
2913: return MACH_SEND_MSG_TOO_SMALL;
2914: }
2915:
2916: data = saddr;
2917: saddr += amount;
2918: } else {
2919: vm_offset_t addr;
2920:
2921: if ((eaddr - saddr) < sizeof(vm_offset_t)) {
2922: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
2923: return MACH_SEND_MSG_TOO_SMALL;
2924: }
2925:
2926: /* grab the out-of-line data */
2927:
2928: addr = * (vm_offset_t *) saddr;
2929:
2930: if (length == 0)
2931: data = 0;
2932: else if (is_port) {
2933: data = kalloc(length);
2934: if (data == 0)
2935: goto invalid_memory;
2936:
2937: if (copyinmap(map, (char *) addr,
2938: (char *) data, length) ||
2939: (dealloc &&
2940: (vm_deallocate(map, addr, length) !=
2941: KERN_SUCCESS))) {
2942: kfree(data, length);
2943: goto invalid_memory;
2944: }
2945: } else {
2946: vm_map_copy_t copy;
2947:
2948: if (use_page_lists) {
2949: kr = vm_map_copyin_page_list(map,
2950: addr, length, dealloc,
2951: steal_pages, ©, FALSE);
2952: } else {
2953: kr = vm_map_copyin(map, addr, length,
2954: dealloc,
2955: ©);
2956: }
2957: if (kr != KERN_SUCCESS) {
2958: invalid_memory:
2959: ipc_kmsg_clean_partial(kmsg, taddr,
2960: FALSE, 0);
2961: return MACH_SEND_INVALID_MEMORY;
2962: }
2963:
2964: data = (vm_offset_t) copy;
2965: }
2966:
2967: * (vm_offset_t *) saddr = data;
2968: saddr += sizeof(vm_offset_t);
2969: complex = TRUE;
2970: }
2971:
2972: if (is_port) {
2973: mach_msg_type_name_t newname =
2974: ipc_object_copyin_type(name);
2975: ipc_object_t *objects = (ipc_object_t *) data;
2976: mach_msg_type_number_t i;
2977:
2978: if (longform)
2979: type->msgtl_name = newname;
2980: else
2981: ((mach_msg_type_t*)type)->msgt_name = newname;
2982:
2983: for (i = 0; i < number; i++) {
2984: mach_port_t port = (mach_port_t) objects[i];
2985: ipc_object_t object;
2986:
2987: if (!MACH_PORT_VALID(port))
2988: continue;
2989:
2990: kr = ipc_object_copyin_compat(space, port,
2991: name, dealloc, &object);
2992: if (kr != KERN_SUCCESS) {
2993: ipc_kmsg_clean_partial(kmsg, taddr,
2994: TRUE, i);
2995: return MACH_SEND_INVALID_RIGHT;
2996: }
2997:
2998: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
2999: ipc_port_check_circularity(
3000: (ipc_port_t) object,
3001: (ipc_port_t) dest))
3002: kmsg->ikm_header.msgh_bits |=
3003: MACH_MSGH_BITS_CIRCULAR;
3004:
3005: objects[i] = object;
3006: }
3007:
3008: complex = TRUE;
3009: }
3010: }
3011:
3012: if (complex)
3013: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
3014:
3015: return MACH_MSG_SUCCESS;
3016: }
3017:
3018: /*
3019: * Routine: ipc_kmsg_copyout_compat
3020: * Purpose:
3021: * "Copy-out" port rights and out-of-line memory
3022: * in the message, producing an old IPC message.
3023: *
3024: * Doesn't bother to handle the header atomically.
3025: * Skips over errors. Problem ports produce MACH_PORT_NULL
3026: * (MACH_PORT_DEAD is never produced), and problem memory
3027: * produces a zero address.
3028: * Conditions:
3029: * Nothing locked.
3030: * Returns:
3031: * MACH_MSG_SUCCESS Copied out rights and memory.
3032: */
3033:
3034: mach_msg_return_t
3035: ipc_kmsg_copyout_compat(kmsg, space, map)
3036: ipc_kmsg_t kmsg;
3037: ipc_space_t space;
3038: vm_map_t map;
3039: {
3040: msg_header_t msg;
3041: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
3042: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
3043: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
3044: mach_port_t dest_name, reply_name;
3045: vm_offset_t saddr, eaddr;
3046: kern_return_t kr;
3047:
3048: assert(IO_VALID(dest));
3049:
3050: io_lock(dest);
3051: if (io_active(dest)) {
3052: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
3053:
3054: ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
3055: /* dest is unlocked */
3056: } else {
3057: io_release(dest);
3058: io_check_unlock(dest);
3059: dest_name = MACH_PORT_NULL;
3060: }
3061:
3062: if (IO_VALID(reply)) {
3063: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
3064:
3065: kr = ipc_object_copyout_compat(space, reply, reply_type,
3066: &reply_name);
3067: if (kr != KERN_SUCCESS) {
3068: ipc_object_destroy(reply, reply_type);
3069: reply_name = MACH_PORT_NULL;
3070: }
3071: } else
3072: reply_name = MACH_PORT_NULL;
3073:
3074: msg.msg_unused = 0;
3075: msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE;
3076: msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size;
3077: msg.msg_type = (integer_t) kmsg->ikm_header.msgh_seqno;
3078: msg.msg_local_port = (port_name_t) dest_name;
3079: msg.msg_remote_port = (port_name_t) reply_name;
3080: msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id;
3081: * (msg_header_t *) &kmsg->ikm_header = msg;
3082:
3083: if (msg.msg_simple)
3084: return MACH_MSG_SUCCESS;
3085:
3086: saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
3087: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
3088:
3089: while (saddr < eaddr) {
3090: vm_offset_t taddr = saddr;
3091: mach_msg_type_long_t *type;
3092: mach_msg_type_name_t name;
3093: mach_msg_type_size_t size;
3094: mach_msg_type_number_t number;
3095: boolean_t is_inline, longform, is_port;
3096: vm_size_t length;
3097: vm_offset_t addr;
3098:
3099: type = (mach_msg_type_long_t *) saddr;
3100: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
3101: longform = ((mach_msg_type_t*)type)->msgt_longform;
3102: if (longform) {
3103: /* This must be aligned */
3104: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3105: (is_misaligned(type))) {
3106: saddr = ptr_align(saddr);
3107: continue;
3108: }
3109: name = type->msgtl_name;
3110: size = type->msgtl_size;
3111: number = type->msgtl_number;
3112: saddr += sizeof(mach_msg_type_long_t);
3113: } else {
3114: name = ((mach_msg_type_t*)type)->msgt_name;
3115: size = ((mach_msg_type_t*)type)->msgt_size;
3116: number = ((mach_msg_type_t*)type)->msgt_number;
3117: saddr += sizeof(mach_msg_type_t);
3118: }
3119:
3120: /* padding (ptrs and ports) ? */
3121: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3122: ((size >> 3) == sizeof(natural_t)))
3123: saddr = ptr_align(saddr);
3124:
3125: /* calculate length of data in bytes, rounding up */
3126:
3127: length = ((number * size) + 7) >> 3;
3128:
3129: is_port = MACH_MSG_TYPE_PORT_ANY(name);
3130:
3131: if (is_port) {
3132: mach_port_t *objects;
3133: mach_msg_type_number_t i;
3134: mach_msg_type_name_t newname;
3135:
3136: if (!is_inline && (length != 0)) {
3137: /* first allocate memory in the map */
3138:
3139: kr = vm_allocate(map, &addr, length, TRUE);
3140: if (kr != KERN_SUCCESS) {
3141: ipc_kmsg_clean_body(taddr, saddr);
3142: goto vm_copyout_failure;
3143: }
3144: }
3145:
3146: newname = ipc_object_copyout_type_compat(name);
3147: if (longform)
3148: type->msgtl_name = newname;
3149: else
3150: ((mach_msg_type_t*)type)->msgt_name = newname;
3151:
3152: objects = (mach_port_t *)
3153: (is_inline ? saddr : * (vm_offset_t *) saddr);
3154:
3155: /* copyout port rights carried in the message */
3156:
3157: for (i = 0; i < number; i++) {
3158: ipc_object_t object =
3159: (ipc_object_t) objects[i];
3160:
3161: if (!IO_VALID(object)) {
3162: objects[i] = MACH_PORT_NULL;
3163: continue;
3164: }
3165:
3166: kr = ipc_object_copyout_compat(space, object,
3167: name, &objects[i]);
3168: if (kr != KERN_SUCCESS) {
3169: ipc_object_destroy(object, name);
3170: objects[i] = MACH_PORT_NULL;
3171: }
3172: }
3173: }
3174:
3175: if (is_inline) {
3176: /* inline data sizes round up to int boundaries */
3177:
3178: saddr += (length + 3) &~ 3;
3179: } else {
3180: vm_offset_t data = * (vm_offset_t *) saddr;
3181:
3182: /* copyout memory carried in the message */
3183:
3184: if (length == 0) {
3185: assert(data == 0);
3186: addr = 0;
3187: } else if (is_port) {
3188: /* copyout to memory allocated above */
3189:
3190: (void) copyoutmap(map, (char *) data,
3191: (char *) addr, length);
3192: kfree(data, length);
3193: } else {
3194: vm_map_copy_t copy = (vm_map_copy_t) data;
3195:
3196: kr = vm_map_copyout(map, &addr, copy);
3197: if (kr != KERN_SUCCESS) {
3198: vm_map_copy_discard(copy);
3199:
3200: vm_copyout_failure:
3201:
3202: addr = 0;
3203: }
3204: }
3205:
3206: * (vm_offset_t *) saddr = addr;
3207: saddr += sizeof(vm_offset_t);
3208: }
3209: }
3210:
3211: return MACH_MSG_SUCCESS;
3212: }
3213:
3214: #endif /* MACH_IPC_COMPAT */
3215:
3216: #include <mach_kdb.h>
3217: #if MACH_KDB
3218:
3219: char *
3220: ipc_type_name(type_name, received)
3221: int type_name;
3222: boolean_t received;
3223: {
3224: switch (type_name) {
3225: case MACH_MSG_TYPE_BOOLEAN:
3226: return "boolean";
3227:
3228: case MACH_MSG_TYPE_INTEGER_16:
3229: return "short";
3230:
3231: case MACH_MSG_TYPE_INTEGER_32:
3232: return "int32";
3233:
3234: case MACH_MSG_TYPE_INTEGER_64:
3235: return "int64";
3236:
3237: case MACH_MSG_TYPE_CHAR:
3238: return "char";
3239:
3240: case MACH_MSG_TYPE_BYTE:
3241: return "byte";
3242:
3243: case MACH_MSG_TYPE_REAL:
3244: return "real";
3245:
3246: case MACH_MSG_TYPE_STRING:
3247: return "string";
3248:
3249: case MACH_MSG_TYPE_PORT_NAME:
3250: return "port_name";
3251:
3252: case MACH_MSG_TYPE_MOVE_RECEIVE:
3253: if (received) {
3254: return "port_receive";
3255: } else {
3256: return "move_receive";
3257: }
3258:
3259: case MACH_MSG_TYPE_MOVE_SEND:
3260: if (received) {
3261: return "port_send";
3262: } else {
3263: return "move_send";
3264: }
3265:
3266: case MACH_MSG_TYPE_MOVE_SEND_ONCE:
3267: if (received) {
3268: return "port_send_once";
3269: } else {
3270: return "move_send_once";
3271: }
3272:
3273: case MACH_MSG_TYPE_COPY_SEND:
3274: return "copy_send";
3275:
3276: case MACH_MSG_TYPE_MAKE_SEND:
3277: return "make_send";
3278:
3279: case MACH_MSG_TYPE_MAKE_SEND_ONCE:
3280: return "make_send_once";
3281:
3282: default:
3283: return (char *) 0;
3284: }
3285: }
3286:
3287: void
3288: ipc_print_type_name(
3289: int type_name)
3290: {
3291: char *name = ipc_type_name(type_name, TRUE);
3292: if (name) {
3293: printf("%s", name);
3294: } else {
3295: printf("type%d", type_name);
3296: }
3297: }
3298:
3299: /*
3300: * ipc_kmsg_print [ debug ]
3301: */
3302: void
3303: ipc_kmsg_print(kmsg)
3304: ipc_kmsg_t kmsg;
3305: {
3306: db_printf("kmsg=0x%x\n", kmsg);
3307: db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
3308: kmsg->ikm_next,
3309: kmsg->ikm_prev,
3310: kmsg->ikm_size,
3311: kmsg->ikm_marequest);
3312: #if NORMA_IPC
3313: db_printf(",page=0x%x,copy=0x%x\n",
3314: kmsg->ikm_page,
3315: kmsg->ikm_copy);
3316: #else /* NORMA_IPC */
3317: db_printf("\n");
3318: #endif /* NORMA_IPC */
3319: ipc_msg_print(&kmsg->ikm_header);
3320: }
3321:
3322: /*
3323: * ipc_msg_print [ debug ]
3324: */
3325: void
3326: ipc_msg_print(msgh)
3327: mach_msg_header_t *msgh;
3328: {
3329: vm_offset_t saddr, eaddr;
3330:
3331: db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
3332: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
3333: db_printf("complex,");
3334: }
3335: if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
3336: db_printf("circular,");
3337: }
3338: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
3339: db_printf("complex_ports,");
3340: }
3341: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
3342: db_printf("complex_data,");
3343: }
3344: if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
3345: db_printf("migrated,");
3346: }
3347: if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
3348: db_printf("unused=0x%x,",
3349: msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
3350: }
3351: db_printf("l=0x%x,r=0x%x\n",
3352: MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
3353: MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3354:
3355: db_printf("msgh_id=%d,size=%d,seqno=%d,",
3356: msgh->msgh_id,
3357: msgh->msgh_size,
3358: msgh->msgh_seqno);
3359:
3360: if (msgh->msgh_remote_port) {
3361: db_printf("remote=0x%x(", msgh->msgh_remote_port);
3362: ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3363: db_printf("),");
3364: } else {
3365: db_printf("remote=null,\n");
3366: }
3367:
3368: if (msgh->msgh_local_port) {
3369: db_printf("local=0x%x(", msgh->msgh_local_port);
3370: ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
3371: db_printf(")\n");
3372: } else {
3373: db_printf("local=null\n");
3374: }
3375:
3376: saddr = (vm_offset_t) (msgh + 1);
3377: eaddr = (vm_offset_t) msgh + msgh->msgh_size;
3378:
3379: while (saddr < eaddr) {
3380: mach_msg_type_long_t *type;
3381: mach_msg_type_name_t name;
3382: mach_msg_type_size_t size;
3383: mach_msg_type_number_t number;
3384: boolean_t is_inline, longform, dealloc, is_port;
3385: vm_size_t length;
3386:
3387: type = (mach_msg_type_long_t *) saddr;
3388:
3389: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
3390: ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
3391: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
3392: db_printf("*** msg too small\n");
3393: return;
3394: }
3395:
3396: is_inline = ((mach_msg_type_t*)type)->msgt_inline;
3397: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
3398: if (longform) {
3399: /* This must be aligned */
3400: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3401: (is_misaligned(type))) {
3402: saddr = ptr_align(saddr);
3403: continue;
3404: }
3405: name = type->msgtl_name;
3406: size = type->msgtl_size;
3407: number = type->msgtl_number;
3408: saddr += sizeof(mach_msg_type_long_t);
3409: } else {
3410: name = ((mach_msg_type_t*)type)->msgt_name;
3411: size = ((mach_msg_type_t*)type)->msgt_size;
3412: number = ((mach_msg_type_t*)type)->msgt_number;
3413: saddr += sizeof(mach_msg_type_t);
3414: }
3415:
3416: db_printf("-- type=");
3417: ipc_print_type_name(name);
3418: if (! is_inline) {
3419: db_printf(",ool");
3420: }
3421: if (dealloc) {
3422: db_printf(",dealloc");
3423: }
3424: if (longform) {
3425: db_printf(",longform");
3426: }
3427: db_printf(",size=%d,number=%d,addr=0x%x\n",
3428: size,
3429: number,
3430: saddr);
3431:
3432: is_port = MACH_MSG_TYPE_PORT_ANY(name);
3433:
3434: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
3435: (longform && ((type->msgtl_header.msgt_name != 0) ||
3436: (type->msgtl_header.msgt_size != 0) ||
3437: (type->msgtl_header.msgt_number != 0))) ||
3438: (((mach_msg_type_t*)type)->msgt_unused != 0) ||
3439: (dealloc && is_inline)) {
3440: db_printf("*** invalid type\n");
3441: return;
3442: }
3443:
3444: /* padding (ptrs and ports) ? */
3445: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3446: ((size >> 3) == sizeof(natural_t)))
3447: saddr = ptr_align(saddr);
3448:
3449: /* calculate length of data in bytes, rounding up */
3450:
3451: length = ((number * size) + 7) >> 3;
3452:
3453: if (is_inline) {
3454: vm_size_t amount;
3455: int i, numwords;
3456:
3457: /* inline data sizes round up to int boundaries */
3458: amount = (length + 3) &~ 3;
3459: if ((eaddr - saddr) < amount) {
3460: db_printf("*** too small\n");
3461: return;
3462: }
3463: numwords = amount / sizeof(int);
3464: if (numwords > 8) {
3465: numwords = 8;
3466: }
3467: for (i = 0; i < numwords; i++) {
3468: db_printf("0x%x\n", ((int *) saddr)[i]);
3469: }
3470: if (numwords < amount / sizeof(int)) {
3471: db_printf("...\n");
3472: }
3473: saddr += amount;
3474: } else {
3475: if ((eaddr - saddr) < sizeof(vm_offset_t)) {
3476: db_printf("*** too small\n");
3477: return;
3478: }
3479: db_printf("0x%x\n", * (vm_offset_t *) saddr);
3480: saddr += sizeof(vm_offset_t);
3481: }
3482: }
3483: }
3484: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.