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