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