|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 2000 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * The contents of this file constitute Original Code as defined in and ! 7: * are subject to the Apple Public Source License Version 1.1 (the ! 8: * "License"). You may not use this file except in compliance with the ! 9: * License. Please obtain a copy of the License at ! 10: * http://www.apple.com/publicsource and read it before using this file. ! 11: * ! 12: * This Original Code and all software distributed under the License are ! 13: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 14: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 15: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 16: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 17: * License for the specific language governing rights and limitations ! 18: * under the License. ! 19: * ! 20: * @APPLE_LICENSE_HEADER_END@ ! 21: */ ! 22: /* ! 23: * @OSF_COPYRIGHT@ ! 24: */ ! 25: /* ! 26: * Mach Operating System ! 27: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 28: * All Rights Reserved. ! 29: * ! 30: * Permission to use, copy, modify and distribute this software and its ! 31: * documentation is hereby granted, provided that both the copyright ! 32: * notice and this permission notice appear in all copies of the ! 33: * software, derivative works or modified versions, and any portions ! 34: * thereof, and that both notices appear in supporting documentation. ! 35: * ! 36: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 37: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 38: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 39: * ! 40: * Carnegie Mellon requests users of this software to return to ! 41: * ! 42: * Software Distribution Coordinator or [email protected] ! 43: * School of Computer Science ! 44: * Carnegie Mellon University ! 45: * Pittsburgh PA 15213-3890 ! 46: * ! 47: * any improvements or extensions that they make and grant Carnegie Mellon ! 48: * the rights to redistribute these changes. ! 49: */ ! 50: /* ! 51: */ ! 52: /* ! 53: * File: ipc/ipc_kmsg.c ! 54: * Author: Rich Draves ! 55: * Date: 1989 ! 56: * ! 57: * Operations on kernel messages. ! 58: */ ! 59: ! 60: #include <cpus.h> ! 61: #include <dipc.h> ! 62: #include <mach_rt.h> ! 63: #include <norma_vm.h> ! 64: ! 65: #include <mach/boolean.h> ! 66: #include <mach/kern_return.h> ! 67: #include <mach/message.h> ! 68: #include <mach/port.h> ! 69: #include <kern/assert.h> ! 70: #include <kern/kalloc.h> ! 71: #include <kern/thread.h> ! 72: #include <kern/sched_prim.h> ! 73: #if MACH_RT ! 74: #include <kern/rtmalloc.h> ! 75: #endif /* MACH_RT */ ! 76: #include <kern/spl.h> ! 77: #include <kern/misc_protos.h> ! 78: #include <kern/counters.h> ! 79: #include <vm/vm_map.h> ! 80: #include <vm/vm_object.h> ! 81: #include <vm/vm_kern.h> ! 82: #include <ipc/port.h> ! 83: #include <ipc/ipc_entry.h> ! 84: #include <ipc/ipc_kmsg.h> ! 85: #include <ipc/ipc_notify.h> ! 86: #include <ipc/ipc_object.h> ! 87: #include <ipc/ipc_space.h> ! 88: #include <ipc/ipc_port.h> ! 89: #include <ipc/ipc_right.h> ! 90: #include <ipc/ipc_hash.h> ! 91: #include <ipc/ipc_table.h> ! 92: ! 93: #include <string.h> ! 94: ! 95: extern vm_map_t ipc_kernel_copy_map; ! 96: extern vm_size_t ipc_kmsg_max_vm_space; ! 97: extern vm_size_t msg_ool_size_small; ! 98: ! 99: #if MACH_RT ! 100: extern vm_size_t msg_ool_size_small_rt; ! 101: #define MSG_OOL_SIZE_SMALL(rt) ((rt) ? msg_ool_size_small_rt : \ ! 102: msg_ool_size_small) ! 103: #else /* MACH_RT */ ! 104: #define MSG_OOL_SIZE_SMALL(rt) msg_ool_size_small ! 105: #endif /* MACH_RT */ ! 106: ! 107: ! 108: /* ! 109: * Forward declarations ! 110: */ ! 111: ! 112: void ipc_kmsg_clean( ! 113: ipc_kmsg_t kmsg); ! 114: ! 115: void ipc_kmsg_clean_body( ! 116: ipc_kmsg_t kmsg, ! 117: mach_msg_type_number_t number); ! 118: ! 119: void ipc_kmsg_clean_partial( ! 120: ipc_kmsg_t kmsg, ! 121: mach_msg_type_number_t number, ! 122: vm_offset_t paddr, ! 123: vm_size_t length); ! 124: ! 125: mach_msg_return_t ipc_kmsg_copyout_body( ! 126: ipc_kmsg_t kmsg, ! 127: ipc_space_t space, ! 128: vm_map_t map, ! 129: mach_msg_body_t *slist); ! 130: ! 131: mach_msg_return_t ipc_kmsg_copyin_body( ! 132: ipc_kmsg_t kmsg, ! 133: ipc_space_t space, ! 134: vm_map_t map); ! 135: ! 136: void ikm_cache_init(void); ! 137: ! 138: ! 139: /* ! 140: * Routine: ipc_kmsg_enqueue ! 141: * Purpose: ! 142: * Enqueue a kmsg. ! 143: */ ! 144: ! 145: void ! 146: ipc_kmsg_enqueue( ! 147: ipc_kmsg_queue_t queue, ! 148: ipc_kmsg_t kmsg) ! 149: { ! 150: ipc_kmsg_enqueue_macro(queue, kmsg); ! 151: } ! 152: ! 153: /* ! 154: * Routine: ipc_kmsg_dequeue ! 155: * Purpose: ! 156: * Dequeue and return a kmsg. ! 157: */ ! 158: ! 159: ipc_kmsg_t ! 160: ipc_kmsg_dequeue( ! 161: ipc_kmsg_queue_t queue) ! 162: { ! 163: ipc_kmsg_t first; ! 164: ! 165: first = ipc_kmsg_queue_first(queue); ! 166: ! 167: if (first != IKM_NULL) ! 168: ipc_kmsg_rmqueue_first_macro(queue, first); ! 169: ! 170: return first; ! 171: } ! 172: ! 173: /* ! 174: * Routine: ipc_kmsg_rmqueue ! 175: * Purpose: ! 176: * Pull a kmsg out of a queue. ! 177: */ ! 178: ! 179: void ! 180: ipc_kmsg_rmqueue( ! 181: ipc_kmsg_queue_t queue, ! 182: ipc_kmsg_t kmsg) ! 183: { ! 184: ipc_kmsg_t next, prev; ! 185: ! 186: assert(queue->ikmq_base != IKM_NULL); ! 187: ! 188: next = kmsg->ikm_next; ! 189: prev = kmsg->ikm_prev; ! 190: ! 191: if (next == kmsg) { ! 192: assert(prev == kmsg); ! 193: assert(queue->ikmq_base == kmsg); ! 194: ! 195: queue->ikmq_base = IKM_NULL; ! 196: } else { ! 197: if (queue->ikmq_base == kmsg) ! 198: queue->ikmq_base = next; ! 199: ! 200: next->ikm_prev = prev; ! 201: prev->ikm_next = next; ! 202: } ! 203: /* XXX Temporary debug logic */ ! 204: kmsg->ikm_next = IKM_BOGUS; ! 205: kmsg->ikm_prev = IKM_BOGUS; ! 206: } ! 207: ! 208: /* ! 209: * Routine: ipc_kmsg_queue_next ! 210: * Purpose: ! 211: * Return the kmsg following the given kmsg. ! 212: * (Or IKM_NULL if it is the last one in the queue.) ! 213: */ ! 214: ! 215: ipc_kmsg_t ! 216: ipc_kmsg_queue_next( ! 217: ipc_kmsg_queue_t queue, ! 218: ipc_kmsg_t kmsg) ! 219: { ! 220: ipc_kmsg_t next; ! 221: ! 222: assert(queue->ikmq_base != IKM_NULL); ! 223: ! 224: next = kmsg->ikm_next; ! 225: if (queue->ikmq_base == next) ! 226: next = IKM_NULL; ! 227: ! 228: return next; ! 229: } ! 230: ! 231: /* ! 232: * Routine: ipc_kmsg_destroy ! 233: * Purpose: ! 234: * Destroys a kernel message. Releases all rights, ! 235: * references, and memory held by the message. ! 236: * Frees the message. ! 237: * Conditions: ! 238: * No locks held. ! 239: */ ! 240: ! 241: void ! 242: ipc_kmsg_destroy( ! 243: ipc_kmsg_t kmsg) ! 244: { ! 245: ipc_kmsg_queue_t queue; ! 246: boolean_t empty; ! 247: ! 248: /* ! 249: * ipc_kmsg_clean can cause more messages to be destroyed. ! 250: * Curtail recursion by queueing messages. If a message ! 251: * is already queued, then this is a recursive call. ! 252: */ ! 253: ! 254: queue = &(current_thread()->ith_messages); ! 255: empty = ipc_kmsg_queue_empty(queue); ! 256: ipc_kmsg_enqueue(queue, kmsg); ! 257: ! 258: if (empty) { ! 259: /* must leave kmsg in queue while cleaning it */ ! 260: ! 261: while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) { ! 262: ipc_kmsg_clean(kmsg); ! 263: ipc_kmsg_rmqueue(queue, kmsg); ! 264: ikm_free(kmsg); ! 265: } ! 266: } ! 267: } ! 268: ! 269: /* ! 270: * Routine: ipc_kmsg_destroy_dest ! 271: * Purpose: ! 272: * Destroys a kernel message. Releases all rights, ! 273: * references, and memory held by the message (including ! 274: * the destination port reference. ! 275: * Frees the message. ! 276: * Conditions: ! 277: * No locks held. ! 278: */ ! 279: ! 280: ipc_kmsg_destroy_dest( ! 281: ipc_kmsg_t kmsg) ! 282: { ! 283: ipc_port_t port; ! 284: ! 285: port = kmsg->ikm_header.msgh_remote_port; ! 286: ! 287: ipc_port_release(port); ! 288: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; ! 289: ipc_kmsg_destroy(kmsg); ! 290: } ! 291: ! 292: /* ! 293: * Routine: ipc_kmsg_clean_body ! 294: * Purpose: ! 295: * Cleans the body of a kernel message. ! 296: * Releases all rights, references, and memory. ! 297: * ! 298: * Conditions: ! 299: * No locks held. ! 300: */ ! 301: ! 302: void ! 303: ipc_kmsg_clean_body( ! 304: ipc_kmsg_t kmsg, ! 305: mach_msg_type_number_t number) ! 306: { ! 307: mach_msg_descriptor_t *saddr, *eaddr; ! 308: boolean_t rt; ! 309: ! 310: if ( number == 0 ) ! 311: return; ! 312: ! 313: rt = KMSG_IS_RT(kmsg); ! 314: saddr = (mach_msg_descriptor_t *) ! 315: ((mach_msg_base_t *) &kmsg->ikm_header + 1); ! 316: eaddr = saddr + number; ! 317: ! 318: for ( ; saddr < eaddr; saddr++ ) { ! 319: ! 320: switch (saddr->type.type) { ! 321: ! 322: case MACH_MSG_PORT_DESCRIPTOR: { ! 323: mach_msg_port_descriptor_t *dsc; ! 324: ! 325: dsc = &saddr->port; ! 326: ! 327: /* ! 328: * Destroy port rights carried in the message ! 329: */ ! 330: if (!IO_VALID((ipc_object_t) dsc->name)) ! 331: continue; ! 332: ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition); ! 333: break; ! 334: } ! 335: case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: ! 336: case MACH_MSG_OOL_DESCRIPTOR : { ! 337: mach_msg_ool_descriptor_t *dsc; ! 338: ! 339: dsc = &saddr->out_of_line; ! 340: ! 341: /* ! 342: * Destroy memory carried in the message ! 343: */ ! 344: if (dsc->size == 0) { ! 345: assert(dsc->address == (void *) 0); ! 346: } else { ! 347: if (dsc->copy == MACH_MSG_PHYSICAL_COPY && ! 348: dsc->size < MSG_OOL_SIZE_SMALL(rt)) { ! 349: KFREE((vm_offset_t)dsc->address, ! 350: (vm_size_t)dsc->size, ! 351: rt); ! 352: } else { ! 353: vm_map_copy_discard((vm_map_copy_t) dsc->address); ! 354: } ! 355: } ! 356: break; ! 357: } ! 358: case MACH_MSG_OOL_PORTS_DESCRIPTOR : { ! 359: ipc_object_t *objects; ! 360: mach_msg_type_number_t j; ! 361: mach_msg_ool_ports_descriptor_t *dsc; ! 362: ! 363: dsc = &saddr->ool_ports; ! 364: objects = (ipc_object_t *) dsc->address; ! 365: ! 366: if (dsc->count == 0) { ! 367: break; ! 368: } ! 369: ! 370: assert(objects != (ipc_object_t *) 0); ! 371: ! 372: /* destroy port rights carried in the message */ ! 373: ! 374: for (j = 0; j < dsc->count; j++) { ! 375: ipc_object_t object = objects[j]; ! 376: ! 377: if (!IO_VALID(object)) ! 378: continue; ! 379: ! 380: ipc_object_destroy(object, dsc->disposition); ! 381: } ! 382: ! 383: /* destroy memory carried in the message */ ! 384: ! 385: assert(dsc->count != 0); ! 386: ! 387: KFREE((vm_offset_t) dsc->address, ! 388: (vm_size_t) dsc->count * sizeof(mach_port_name_t), ! 389: rt); ! 390: break; ! 391: } ! 392: default : { ! 393: printf("cleanup: don't understand this type of descriptor\n"); ! 394: } ! 395: } ! 396: } ! 397: } ! 398: ! 399: /* ! 400: * Routine: ipc_kmsg_clean_partial ! 401: * Purpose: ! 402: * Cleans a partially-acquired kernel message. ! 403: * number is the index of the type descriptor ! 404: * in the body of the message that contained the error. ! 405: * If dolast, the memory and port rights in this last ! 406: * type spec are also cleaned. In that case, number ! 407: * specifies the number of port rights to clean. ! 408: * Conditions: ! 409: * Nothing locked. ! 410: */ ! 411: ! 412: void ! 413: ipc_kmsg_clean_partial( ! 414: ipc_kmsg_t kmsg, ! 415: mach_msg_type_number_t number, ! 416: vm_offset_t paddr, ! 417: vm_size_t length) ! 418: { ! 419: ipc_object_t object; ! 420: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 421: ! 422: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 423: assert(IO_VALID(object)); ! 424: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 425: ! 426: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 427: if (IO_VALID(object)) ! 428: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 429: ! 430: if (paddr) { ! 431: (void) vm_deallocate(ipc_kernel_copy_map, paddr, length); ! 432: } ! 433: ! 434: ipc_kmsg_clean_body(kmsg, number); ! 435: } ! 436: ! 437: /* ! 438: * Routine: ipc_kmsg_clean ! 439: * Purpose: ! 440: * Cleans a kernel message. Releases all rights, ! 441: * references, and memory held by the message. ! 442: * Conditions: ! 443: * No locks held. ! 444: */ ! 445: ! 446: void ! 447: ipc_kmsg_clean( ! 448: ipc_kmsg_t kmsg) ! 449: { ! 450: ipc_object_t object; ! 451: mach_msg_bits_t mbits; ! 452: ! 453: mbits = kmsg->ikm_header.msgh_bits; ! 454: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 455: if (IO_VALID(object)) ! 456: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 457: ! 458: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 459: if (IO_VALID(object)) ! 460: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 461: ! 462: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 463: mach_msg_body_t *body; ! 464: ! 465: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 466: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count); ! 467: } ! 468: } ! 469: ! 470: /* ! 471: * Routine: ipc_kmsg_free ! 472: * Purpose: ! 473: * Free a kernel message buffer. ! 474: * Conditions: ! 475: * Nothing locked. ! 476: */ ! 477: ! 478: void ! 479: ipc_kmsg_free( ! 480: ipc_kmsg_t kmsg) ! 481: { ! 482: vm_size_t size = kmsg->ikm_size; ! 483: ! 484: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE || ! 485: KMSG_IS_RT(kmsg) || ! 486: !ikm_cache_put(kmsg)) ! 487: KFREE((vm_offset_t) kmsg, size, KMSG_IS_RT(kmsg)); ! 488: } ! 489: ! 490: /* ! 491: * Routine: ipc_kmsg_get ! 492: * Purpose: ! 493: * Allocates a kernel message buffer. ! 494: * Copies a user message to the message buffer. ! 495: * Conditions: ! 496: * Nothing locked. ! 497: * Returns: ! 498: * MACH_MSG_SUCCESS Acquired a message buffer. ! 499: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. ! 500: * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple. ! 501: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 502: * MACH_SEND_INVALID_DATA Couldn't copy message data. ! 503: */ ! 504: ! 505: mach_msg_return_t ! 506: ipc_kmsg_get( ! 507: mach_msg_header_t *msg, ! 508: mach_msg_size_t size, ! 509: ipc_kmsg_t *kmsgp, ! 510: ipc_space_t space) ! 511: { ! 512: mach_msg_size_t msg_and_trailer_size; ! 513: ipc_kmsg_t kmsg; ! 514: mach_msg_format_0_trailer_t *trailer; ! 515: mach_port_name_t dest_name; ! 516: ipc_entry_t dest_entry; ! 517: ipc_port_t dest_port; ! 518: #if MACH_RT ! 519: boolean_t rt = FALSE; ! 520: #endif /* MACH_RT */ ! 521: ! 522: if ((size < sizeof(mach_msg_header_t)) || (size & 3)) ! 523: return MACH_SEND_MSG_TOO_SMALL; ! 524: ! 525: #if 0 /* used to be MACH_RT */ ! 526: /* ! 527: * JMM - We don't do this now, let's not pay the price ! 528: */ ! 529: /* ! 530: * Copyin just the destination mach_port_name_t ! 531: */ ! 532: if (copyinmsg((char *) &msg->msgh_remote_port, ! 533: (char *) &dest_name, ! 534: sizeof(mach_port_name_t))) { ! 535: return MACH_SEND_INVALID_DATA; ! 536: } ! 537: ! 538: /* ! 539: * Validate the space ! 540: */ ! 541: is_write_lock(space); ! 542: if (!space->is_active) { ! 543: is_write_unlock(space); ! 544: return MACH_SEND_INVALID_DEST; ! 545: } ! 546: ! 547: /* ! 548: * Lookup and validate the entry ! 549: */ ! 550: dest_entry = ipc_entry_lookup(space, dest_name); ! 551: if (dest_entry == IE_NULL) { ! 552: is_write_unlock(space); ! 553: return MACH_SEND_INVALID_DEST; ! 554: } ! 555: ! 556: /* ! 557: * Extract the port and check whether it is an RT port ! 558: */ ! 559: dest_port = (ipc_port_t) dest_entry->ie_object; ! 560: if (dest_port == IP_NULL) { ! 561: is_write_unlock(space); ! 562: return MACH_SEND_INVALID_DEST; ! 563: } ! 564: ! 565: rt = IP_RT(dest_port); ! 566: is_write_unlock(space); ! 567: #endif /* 0 used to be MACH_RT */ ! 568: ! 569: msg_and_trailer_size = size + MAX_TRAILER_SIZE; ! 570: ! 571: if (msg_and_trailer_size <= IKM_SAVED_MSG_SIZE) { ! 572: if ( ! 573: #if MACH_RT ! 574: (!rt) && ! 575: #endif /* MACH_RT */ ! 576: ikm_cache_get(&kmsg)) { ! 577: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE); ! 578: } else { ! 579: #if MACH_RT ! 580: if (rt) ! 581: kmsg = ikm_rtalloc(IKM_SAVED_MSG_SIZE); ! 582: else ! 583: #endif /* MACH_RT */ ! 584: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE); ! 585: if (kmsg == IKM_NULL) ! 586: return MACH_SEND_NO_BUFFER; ! 587: ikm_init(kmsg, IKM_SAVED_MSG_SIZE); ! 588: } ! 589: } else { ! 590: #if MACH_RT ! 591: if (rt) ! 592: kmsg = ikm_rtalloc(msg_and_trailer_size); ! 593: else ! 594: #endif /* MACH_RT */ ! 595: kmsg = ikm_alloc(msg_and_trailer_size); ! 596: ! 597: if (kmsg == IKM_NULL) ! 598: return MACH_SEND_NO_BUFFER; ! 599: ikm_init(kmsg, msg_and_trailer_size); ! 600: } ! 601: ! 602: if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) { ! 603: #if MACH_RT ! 604: if (rt) ! 605: KMSG_MARK_RT(kmsg); ! 606: #endif /* MACH_RT */ ! 607: ikm_free(kmsg); ! 608: return MACH_SEND_INVALID_DATA; ! 609: } ! 610: ! 611: kmsg->ikm_header.msgh_size = size; ! 612: #if MACH_RT ! 613: if (rt) ! 614: KMSG_MARK_RT(kmsg); ! 615: #endif /* MACH_RT */ ! 616: ! 617: /* ! 618: * I reserve for the trailer the largest space (MAX_TRAILER_SIZE) ! 619: * However, the internal size field of the trailer (msgh_trailer_size) ! 620: * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize ! 621: * the cases where no implicit data is requested. ! 622: */ ! 623: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)&kmsg->ikm_header + size); ! 624: trailer->msgh_sender = current_thread()->top_act->task->sec_token; ! 625: trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; ! 626: trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; ! 627: ! 628: *kmsgp = kmsg; ! 629: return MACH_MSG_SUCCESS; ! 630: } ! 631: ! 632: /* ! 633: * Routine: ipc_kmsg_get_from_kernel ! 634: * Purpose: ! 635: * Allocates a kernel message buffer. ! 636: * Copies a kernel message to the message buffer. ! 637: * Only resource errors are allowed. ! 638: * Conditions: ! 639: * Nothing locked. ! 640: * Ports in header are ipc_port_t. ! 641: * Returns: ! 642: * MACH_MSG_SUCCESS Acquired a message buffer. ! 643: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 644: */ ! 645: ! 646: mach_msg_return_t ! 647: ipc_kmsg_get_from_kernel( ! 648: mach_msg_header_t *msg, ! 649: mach_msg_size_t size, ! 650: ipc_kmsg_t *kmsgp) ! 651: { ! 652: ipc_kmsg_t kmsg; ! 653: mach_msg_size_t msg_and_trailer_size; ! 654: mach_msg_format_0_trailer_t *trailer; ! 655: ipc_port_t dest_port; ! 656: #if MACH_RT ! 657: boolean_t rt; ! 658: #endif /* MACH_RT */ ! 659: ! 660: assert(size >= sizeof(mach_msg_header_t)); ! 661: assert((size & 3) == 0); ! 662: ! 663: /* round up for ikm_cache */ ! 664: msg_and_trailer_size = size + MAX_TRAILER_SIZE; ! 665: if (msg_and_trailer_size < IKM_SAVED_MSG_SIZE) ! 666: msg_and_trailer_size = IKM_SAVED_MSG_SIZE; ! 667: ! 668: assert(IP_VALID((ipc_port_t) msg->msgh_remote_port)); ! 669: ! 670: #if MACH_RT ! 671: rt = IP_RT((ipc_port_t) msg->msgh_remote_port); ! 672: ! 673: if (rt) ! 674: kmsg = ikm_rtalloc(msg_and_trailer_size); ! 675: else ! 676: #endif /* MACH_RT */ ! 677: kmsg = ikm_alloc(msg_and_trailer_size); ! 678: ! 679: if (kmsg == IKM_NULL) ! 680: return MACH_SEND_NO_BUFFER; ! 681: ikm_init(kmsg, msg_and_trailer_size); ! 682: ! 683: (void) memcpy((void *) &kmsg->ikm_header, (const void *) msg, size); ! 684: ! 685: kmsg->ikm_header.msgh_size = size; ! 686: #if MACH_RT ! 687: if (rt) ! 688: KMSG_MARK_RT(kmsg); ! 689: #endif /* MACH_RT */ ! 690: ! 691: /* ! 692: * I reserve for the trailer the largest space (MAX_TRAILER_SIZE) ! 693: * However, the internal size field of the trailer (msgh_trailer_size) ! 694: * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize ! 695: * the cases where no implicit data is requested. ! 696: */ ! 697: trailer = (mach_msg_format_0_trailer_t *) ((vm_offset_t)&kmsg->ikm_header + size); ! 698: trailer->msgh_sender = KERNEL_SECURITY_TOKEN; ! 699: trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; ! 700: trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; ! 701: ! 702: *kmsgp = kmsg; ! 703: return MACH_MSG_SUCCESS; ! 704: } ! 705: ! 706: /* ! 707: * Routine: ipc_kmsg_send ! 708: * Purpose: ! 709: * Send a message. The message holds a reference ! 710: * for the destination port in the msgh_remote_port field. ! 711: * ! 712: * If unsuccessful, the caller still has possession of ! 713: * the message and must do something with it. If successful, ! 714: * the message is queued, given to a receiver, destroyed, ! 715: * or handled directly by the kernel via mach_msg. ! 716: * Conditions: ! 717: * Nothing locked. ! 718: * Returns: ! 719: * MACH_MSG_SUCCESS The message was accepted. ! 720: * MACH_SEND_TIMED_OUT Caller still has message. ! 721: * MACH_SEND_INTERRUPTED Caller still has message. ! 722: */ ! 723: mach_msg_return_t ! 724: ipc_kmsg_send( ! 725: ipc_kmsg_t kmsg, ! 726: mach_msg_option_t option, ! 727: mach_msg_timeout_t timeout) ! 728: { ! 729: kern_return_t save_wait_result; ! 730: ! 731: ipc_port_t port; ! 732: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 733: assert(IP_VALID(port)); ! 734: ! 735: ip_lock(port); ! 736: ! 737: if (port->ip_receiver == ipc_space_kernel) { ! 738: ! 739: /* ! 740: * We can check ip_receiver == ipc_space_kernel ! 741: * before checking that the port is active because ! 742: * ipc_port_dealloc_kernel clears ip_receiver ! 743: * before destroying a kernel port. ! 744: */ ! 745: assert(ip_active(port)); ! 746: port->ip_messages.imq_seqno++; ! 747: ip_unlock(port); ! 748: ! 749: current_task()->messages_sent++; ! 750: ! 751: /* ! 752: * Call the server routine, and get the reply message to send. ! 753: */ ! 754: kmsg = ipc_kobject_server(kmsg); ! 755: if (kmsg == IKM_NULL) ! 756: return MACH_MSG_SUCCESS; ! 757: ! 758: port = (ipc_port_t) kmsg->ikm_header.msgh_remote_port; ! 759: assert(IP_VALID(port)); ! 760: ip_lock(port); ! 761: /* fall thru with reply - same options */ ! 762: } ! 763: ! 764: /* ! 765: * Can't deliver to a dead port. ! 766: * However, we can pretend it got sent ! 767: * and was then immediately destroyed. ! 768: */ ! 769: if (!ip_active(port)) { ! 770: /* ! 771: * We can't let ipc_kmsg_destroy deallocate ! 772: * the port right, because we might end up ! 773: * in an infinite loop trying to deliver ! 774: * a send-once notification. ! 775: */ ! 776: ! 777: ip_release(port); ! 778: ip_check_unlock(port); ! 779: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; ! 780: ipc_kmsg_destroy(kmsg); ! 781: return MACH_MSG_SUCCESS; ! 782: } ! 783: ! 784: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_CIRCULAR) { ! 785: ip_unlock(port); ! 786: ! 787: /* don't allow the creation of a circular loop */ ! 788: ! 789: ipc_kmsg_destroy(kmsg); ! 790: return MACH_MSG_SUCCESS; ! 791: } ! 792: ! 793: /* ! 794: * We have a valid message and a valid reference on the port. ! 795: * we can unlock the port and call mqueue_send() on it's message ! 796: * queue. ! 797: */ ! 798: ip_unlock(port); ! 799: return (ipc_mqueue_send(&port->ip_messages, kmsg, option, timeout)); ! 800: } ! 801: ! 802: /* ! 803: * Routine: ipc_kmsg_put ! 804: * Purpose: ! 805: * Copies a message buffer to a user message. ! 806: * Copies only the specified number of bytes. ! 807: * Frees the message buffer. ! 808: * Conditions: ! 809: * Nothing locked. The message buffer must have clean ! 810: * header fields. ! 811: * Returns: ! 812: * MACH_MSG_SUCCESS Copied data out of message buffer. ! 813: * MACH_RCV_INVALID_DATA Couldn't copy to user message. ! 814: */ ! 815: ! 816: mach_msg_return_t ! 817: ipc_kmsg_put( ! 818: mach_msg_header_t *msg, ! 819: ipc_kmsg_t kmsg, ! 820: mach_msg_size_t size) ! 821: { ! 822: mach_msg_return_t mr; ! 823: ! 824: ikm_check_initialized(kmsg, kmsg->ikm_size); ! 825: ! 826: if (copyoutmsg((const char *) &kmsg->ikm_header, (char *) msg, size)) ! 827: mr = MACH_RCV_INVALID_DATA; ! 828: else ! 829: mr = MACH_MSG_SUCCESS; ! 830: ! 831: if (kmsg->ikm_size != IKM_SAVED_KMSG_SIZE || ! 832: KMSG_IS_RT(kmsg) || ! 833: !ikm_cache_put(kmsg)) ! 834: ikm_free(kmsg); ! 835: ! 836: return mr; ! 837: } ! 838: ! 839: /* ! 840: * Routine: ipc_kmsg_put_to_kernel ! 841: * Purpose: ! 842: * Copies a message buffer to a kernel message. ! 843: * Frees the message buffer. ! 844: * No errors allowed. ! 845: * Conditions: ! 846: * Nothing locked. ! 847: */ ! 848: ! 849: void ! 850: ipc_kmsg_put_to_kernel( ! 851: mach_msg_header_t *msg, ! 852: ipc_kmsg_t kmsg, ! 853: mach_msg_size_t size) ! 854: { ! 855: (void) memcpy((void *) msg, (const void *) &kmsg->ikm_header, size); ! 856: ! 857: ikm_free(kmsg); ! 858: } ! 859: ! 860: /* ! 861: * Routine: ipc_kmsg_copyin_header ! 862: * Purpose: ! 863: * "Copy-in" port rights in the header of a message. ! 864: * Operates atomically; if it doesn't succeed the ! 865: * message header and the space are left untouched. ! 866: * If it does succeed the remote/local port fields ! 867: * contain object pointers instead of port names, ! 868: * and the bits field is updated. The destination port ! 869: * will be a valid port pointer. ! 870: * ! 871: * The notify argument implements the MACH_SEND_CANCEL option. ! 872: * If it is not MACH_PORT_NULL, it should name a receive right. ! 873: * If the processing of the destination port would generate ! 874: * a port-deleted notification (because the right for the ! 875: * destination port is destroyed and it had a request for ! 876: * a dead-name notification registered), and the port-deleted ! 877: * notification would be sent to the named receive right, ! 878: * then it isn't sent and the send-once right for the notify ! 879: * port is quietly destroyed. ! 880: * ! 881: * Conditions: ! 882: * Nothing locked. ! 883: * Returns: ! 884: * MACH_MSG_SUCCESS Successful copyin. ! 885: * MACH_SEND_INVALID_HEADER ! 886: * Illegal value in the message header bits. ! 887: * MACH_SEND_INVALID_DEST The space is dead. ! 888: * MACH_SEND_INVALID_NOTIFY ! 889: * Notify is non-null and doesn't name a receive right. ! 890: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 891: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 892: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 893: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 894: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 895: */ ! 896: ! 897: mach_msg_return_t ! 898: ipc_kmsg_copyin_header( ! 899: mach_msg_header_t *msg, ! 900: ipc_space_t space, ! 901: mach_port_name_t notify) ! 902: { ! 903: mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR; ! 904: mach_port_name_t dest_name = (mach_port_name_t)msg->msgh_remote_port; ! 905: mach_port_name_t reply_name = (mach_port_name_t)msg->msgh_local_port; ! 906: kern_return_t kr; ! 907: ! 908: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 909: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 910: ipc_object_t dest_port, reply_port; ! 911: ipc_port_t dest_soright, reply_soright; ! 912: ipc_port_t notify_port; ! 913: ! 914: if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ! 915: return MACH_SEND_INVALID_HEADER; ! 916: ! 917: if ((reply_type == 0) ? ! 918: (reply_name != MACH_PORT_NULL) : ! 919: !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type)) ! 920: return MACH_SEND_INVALID_HEADER; ! 921: ! 922: reply_soright = IP_NULL; /* in case we go to invalid dest early */ ! 923: ! 924: is_write_lock(space); ! 925: if (!space->is_active) ! 926: goto invalid_dest; ! 927: ! 928: if (notify != MACH_PORT_NULL) { ! 929: ipc_entry_t entry; ! 930: ! 931: if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) { ! 932: is_write_unlock(space); ! 933: return MACH_SEND_INVALID_NOTIFY; ! 934: } ! 935: if((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) { ! 936: is_write_unlock(space); ! 937: return MACH_SEND_INVALID_NOTIFY; ! 938: } ! 939: ! 940: notify_port = (ipc_port_t) entry->ie_object; ! 941: } ! 942: ! 943: if (dest_name == reply_name) { ! 944: ipc_entry_t entry; ! 945: mach_port_name_t name = dest_name; ! 946: ! 947: /* ! 948: * Destination and reply ports are the same! ! 949: * This is a little tedious to make atomic, because ! 950: * there are 25 combinations of dest_type/reply_type. ! 951: * However, most are easy. If either is move-sonce, ! 952: * then there must be an error. If either are ! 953: * make-send or make-sonce, then we must be looking ! 954: * at a receive right so the port can't die. ! 955: * The hard cases are the combinations of ! 956: * copy-send and make-send. ! 957: */ ! 958: ! 959: entry = ipc_entry_lookup(space, name); ! 960: if (entry == IE_NULL) ! 961: goto invalid_dest; ! 962: ! 963: assert(reply_type != 0); /* because name not null */ ! 964: ! 965: if (!ipc_right_copyin_check(space, name, entry, reply_type)) ! 966: goto invalid_reply; ! 967: ! 968: if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) || ! 969: (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) { ! 970: /* ! 971: * Why must there be an error? To get a valid ! 972: * destination, this entry must name a live ! 973: * port (not a dead name or dead port). However ! 974: * a successful move-sonce will destroy a ! 975: * live entry. Therefore the other copyin, ! 976: * whatever it is, would fail. We've already ! 977: * checked for reply port errors above, ! 978: * so report a destination error. ! 979: */ ! 980: ! 981: goto invalid_dest; ! 982: } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) || ! 983: (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) || ! 984: (reply_type == MACH_MSG_TYPE_MAKE_SEND) || ! 985: (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) { ! 986: kr = ipc_right_copyin(space, name, entry, ! 987: dest_type, FALSE, ! 988: &dest_port, &dest_soright); ! 989: if (kr != KERN_SUCCESS) ! 990: goto invalid_dest; ! 991: ! 992: /* ! 993: * Either dest or reply needs a receive right. ! 994: * We know the receive right is there, because ! 995: * of the copyin_check and copyin calls. Hence ! 996: * the port is not in danger of dying. If dest ! 997: * used the receive right, then the right needed ! 998: * by reply (and verified by copyin_check) will ! 999: * still be there. ! 1000: */ ! 1001: ! 1002: assert(IO_VALID(dest_port)); ! 1003: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1004: assert(dest_soright == IP_NULL); ! 1005: ! 1006: kr = ipc_right_copyin(space, name, entry, ! 1007: reply_type, TRUE, ! 1008: &reply_port, &reply_soright); ! 1009: ! 1010: assert(kr == KERN_SUCCESS); ! 1011: assert(reply_port == dest_port); ! 1012: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1013: assert(reply_soright == IP_NULL); ! 1014: } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1015: (reply_type == MACH_MSG_TYPE_COPY_SEND)) { ! 1016: /* ! 1017: * To make this atomic, just do one copy-send, ! 1018: * and dup the send right we get out. ! 1019: */ ! 1020: ! 1021: kr = ipc_right_copyin(space, name, entry, ! 1022: dest_type, FALSE, ! 1023: &dest_port, &dest_soright); ! 1024: if (kr != KERN_SUCCESS) ! 1025: goto invalid_dest; ! 1026: ! 1027: assert(entry->ie_bits & MACH_PORT_TYPE_SEND); ! 1028: assert(dest_soright == IP_NULL); ! 1029: ! 1030: /* ! 1031: * It's OK if the port we got is dead now, ! 1032: * so reply_port is IP_DEAD, because the msg ! 1033: * won't go anywhere anyway. ! 1034: */ ! 1035: ! 1036: reply_port = (ipc_object_t) ! 1037: ipc_port_copy_send((ipc_port_t) dest_port); ! 1038: reply_soright = IP_NULL; ! 1039: } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1040: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) { ! 1041: /* ! 1042: * This is an easy case. Just use our ! 1043: * handy-dandy special-purpose copyin call ! 1044: * to get two send rights for the price of one. ! 1045: */ ! 1046: ! 1047: kr = ipc_right_copyin_two(space, name, entry, ! 1048: &dest_port, &dest_soright); ! 1049: if (kr != KERN_SUCCESS) ! 1050: goto invalid_dest; ! 1051: ! 1052: /* the entry might need to be deallocated */ ! 1053: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1054: ipc_entry_dealloc(space, name, entry); ! 1055: ! 1056: reply_port = dest_port; ! 1057: reply_soright = IP_NULL; ! 1058: } else { ! 1059: ipc_port_t soright; ! 1060: ! 1061: assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1062: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) || ! 1063: ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1064: (reply_type == MACH_MSG_TYPE_COPY_SEND))); ! 1065: ! 1066: /* ! 1067: * To make this atomic, just do a move-send, ! 1068: * and dup the send right we get out. ! 1069: */ ! 1070: ! 1071: kr = ipc_right_copyin(space, name, entry, ! 1072: MACH_MSG_TYPE_MOVE_SEND, FALSE, ! 1073: &dest_port, &soright); ! 1074: if (kr != KERN_SUCCESS) ! 1075: goto invalid_dest; ! 1076: ! 1077: /* the entry might need to be deallocated */ ! 1078: ! 1079: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1080: ipc_entry_dealloc(space, name, entry); ! 1081: ! 1082: /* ! 1083: * It's OK if the port we got is dead now, ! 1084: * so reply_port is IP_DEAD, because the msg ! 1085: * won't go anywhere anyway. ! 1086: */ ! 1087: ! 1088: reply_port = (ipc_object_t) ! 1089: ipc_port_copy_send((ipc_port_t) dest_port); ! 1090: ! 1091: if (dest_type == MACH_MSG_TYPE_MOVE_SEND) { ! 1092: dest_soright = soright; ! 1093: reply_soright = IP_NULL; ! 1094: } else { ! 1095: dest_soright = IP_NULL; ! 1096: reply_soright = soright; ! 1097: } ! 1098: } ! 1099: } else if (!MACH_PORT_VALID(reply_name)) { ! 1100: ipc_entry_t entry; ! 1101: ! 1102: /* ! 1103: * No reply port! This is an easy case ! 1104: * to make atomic. Just copyin the destination. ! 1105: */ ! 1106: ! 1107: entry = ipc_entry_lookup(space, dest_name); ! 1108: if (entry == IE_NULL) ! 1109: goto invalid_dest; ! 1110: ! 1111: kr = ipc_right_copyin(space, dest_name, entry, ! 1112: dest_type, FALSE, ! 1113: &dest_port, &dest_soright); ! 1114: if (kr != KERN_SUCCESS) ! 1115: goto invalid_dest; ! 1116: ! 1117: /* the entry might need to be deallocated */ ! 1118: ! 1119: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1120: ipc_entry_dealloc(space, dest_name, entry); ! 1121: ! 1122: reply_port = (ipc_object_t) reply_name; ! 1123: reply_soright = IP_NULL; ! 1124: } else { ! 1125: ipc_entry_t dest_entry, reply_entry; ! 1126: ipc_port_t saved_reply; ! 1127: ! 1128: /* ! 1129: * This is the tough case to make atomic. ! 1130: * The difficult problem is serializing with port death. ! 1131: * At the time we copyin dest_port, it must be alive. ! 1132: * If reply_port is alive when we copyin it, then ! 1133: * we are OK, because we serialize before the death ! 1134: * of both ports. Assume reply_port is dead at copyin. ! 1135: * Then if dest_port dies/died after reply_port died, ! 1136: * we are OK, because we serialize between the death ! 1137: * of the two ports. So the bad case is when dest_port ! 1138: * dies after its copyin, reply_port dies before its ! 1139: * copyin, and dest_port dies before reply_port. Then ! 1140: * the copyins operated as if dest_port was alive ! 1141: * and reply_port was dead, which shouldn't have happened ! 1142: * because they died in the other order. ! 1143: * ! 1144: * Note that it is easy for a user task to tell if ! 1145: * a copyin happened before or after a port died. ! 1146: * For example, suppose both dest and reply are ! 1147: * send-once rights (types are both move-sonce) and ! 1148: * both rights have dead-name requests registered. ! 1149: * If a port dies before copyin, a dead-name notification ! 1150: * is generated and the dead name's urefs are incremented, ! 1151: * and if the copyin happens first, a port-deleted ! 1152: * notification is generated. ! 1153: * ! 1154: * Note that although the entries are different, ! 1155: * dest_port and reply_port might still be the same. ! 1156: * ! 1157: * JMM - The code to handle this was too expensive and, anyway, ! 1158: * we intend to separate the dest lookup from the reply copyin ! 1159: * by a wide margin, so the user will have to learn to deal! ! 1160: * I will be making the change soon! ! 1161: */ ! 1162: ! 1163: dest_entry = ipc_entry_lookup(space, dest_name); ! 1164: if (dest_entry == IE_NULL) ! 1165: goto invalid_dest; ! 1166: ! 1167: reply_entry = ipc_entry_lookup(space, reply_name); ! 1168: if (reply_entry == IE_NULL) ! 1169: goto invalid_reply; ! 1170: ! 1171: assert(dest_entry != reply_entry); /* names are not equal */ ! 1172: assert(reply_type != 0); /* because reply_name not null */ ! 1173: ! 1174: if (!ipc_right_copyin_check(space, reply_name, reply_entry, ! 1175: reply_type)) ! 1176: goto invalid_reply; ! 1177: ! 1178: kr = ipc_right_copyin(space, dest_name, dest_entry, ! 1179: dest_type, FALSE, ! 1180: &dest_port, &dest_soright); ! 1181: if (kr != KERN_SUCCESS) ! 1182: goto invalid_dest; ! 1183: ! 1184: assert(IO_VALID(dest_port)); ! 1185: ! 1186: kr = ipc_right_copyin(space, reply_name, reply_entry, ! 1187: reply_type, TRUE, ! 1188: &reply_port, &reply_soright); ! 1189: ! 1190: assert(kr == KERN_SUCCESS); ! 1191: ! 1192: /* the entries might need to be deallocated */ ! 1193: ! 1194: if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1195: ipc_entry_dealloc(space, reply_name, reply_entry); ! 1196: ! 1197: if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1198: ipc_entry_dealloc(space, dest_name, dest_entry); ! 1199: } ! 1200: ! 1201: /* ! 1202: * At this point, dest_port, reply_port, ! 1203: * dest_soright, reply_soright are all initialized. ! 1204: * Any defunct entries have been deallocated. ! 1205: * The space is still write-locked, and we need to ! 1206: * make the MACH_SEND_CANCEL check. The notify_port pointer ! 1207: * is still usable, because the copyin code above won't ever ! 1208: * deallocate a receive right, so its entry still exists ! 1209: * and holds a ref. Note notify_port might even equal ! 1210: * dest_port or reply_port. ! 1211: */ ! 1212: ! 1213: if ((notify != MACH_PORT_NULL) && ! 1214: (dest_soright == notify_port)) { ! 1215: ipc_port_release_sonce(dest_soright); ! 1216: dest_soright = IP_NULL; ! 1217: } ! 1218: ! 1219: is_write_unlock(space); ! 1220: ! 1221: if (dest_soright != IP_NULL) ! 1222: ipc_notify_port_deleted(dest_soright, dest_name); ! 1223: ! 1224: if (reply_soright != IP_NULL) ! 1225: ipc_notify_port_deleted(reply_soright, reply_name); ! 1226: ! 1227: dest_type = ipc_object_copyin_type(dest_type); ! 1228: reply_type = ipc_object_copyin_type(reply_type); ! 1229: ! 1230: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1231: MACH_MSGH_BITS(dest_type, reply_type)); ! 1232: msg->msgh_remote_port = (ipc_port_t)dest_port; ! 1233: msg->msgh_local_port = (ipc_port_t)reply_port; ! 1234: ! 1235: return MACH_MSG_SUCCESS; ! 1236: ! 1237: invalid_reply: ! 1238: is_write_unlock(space); ! 1239: return MACH_SEND_INVALID_REPLY; ! 1240: ! 1241: invalid_dest: ! 1242: is_write_unlock(space); ! 1243: if (reply_soright != IP_NULL) ! 1244: ipc_notify_port_deleted(reply_soright, reply_name); ! 1245: return MACH_SEND_INVALID_DEST; ! 1246: } ! 1247: ! 1248: /* ! 1249: * Routine: ipc_kmsg_copyin_body ! 1250: * Purpose: ! 1251: * "Copy-in" port rights and out-of-line memory ! 1252: * in the message body. ! 1253: * ! 1254: * In all failure cases, the message is left holding ! 1255: * no rights or memory. However, the message buffer ! 1256: * is not deallocated. If successful, the message ! 1257: * contains a valid destination port. ! 1258: * Conditions: ! 1259: * Nothing locked. ! 1260: * Returns: ! 1261: * MACH_MSG_SUCCESS Successful copyin. ! 1262: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 1263: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 1264: * MACH_SEND_INVALID_TYPE Bad type specification. ! 1265: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 1266: * MACH_SEND_INVALID_RT_OOL_SIZE OOL Buffer too large for RT ! 1267: * MACH_MSG_INVALID_RT_DESCRIPTOR Dealloc and RT are incompatible ! 1268: */ ! 1269: ! 1270: mach_msg_return_t ! 1271: ipc_kmsg_copyin_body( ! 1272: ipc_kmsg_t kmsg, ! 1273: ipc_space_t space, ! 1274: vm_map_t map) ! 1275: { ! 1276: ipc_object_t dest; ! 1277: mach_msg_body_t *body; ! 1278: mach_msg_descriptor_t *saddr, *eaddr; ! 1279: boolean_t complex; ! 1280: mach_msg_return_t mr; ! 1281: boolean_t use_page_lists, steal_pages; ! 1282: int i; ! 1283: kern_return_t kr; ! 1284: vm_size_t space_needed = 0; ! 1285: vm_offset_t paddr = 0; ! 1286: mach_msg_descriptor_t *sstart; ! 1287: vm_map_copy_t copy = VM_MAP_COPY_NULL; ! 1288: #if MACH_RT ! 1289: boolean_t rt; ! 1290: #endif /* MACH_RT */ ! 1291: ! 1292: /* ! 1293: * Determine if the target is a kernel port. ! 1294: */ ! 1295: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 1296: complex = FALSE; ! 1297: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest)); ! 1298: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest)); ! 1299: #if MACH_RT ! 1300: rt = KMSG_IS_RT(kmsg); ! 1301: #endif /* MACH_RT */ ! 1302: ! 1303: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 1304: saddr = (mach_msg_descriptor_t *) (body + 1); ! 1305: eaddr = saddr + body->msgh_descriptor_count; ! 1306: ! 1307: /* make sure the message does not ask for more msg descriptors ! 1308: * than the message can hold. ! 1309: */ ! 1310: ! 1311: if (eaddr <= saddr || ! 1312: eaddr > (mach_msg_descriptor_t *) (&kmsg->ikm_header + ! 1313: kmsg->ikm_header.msgh_size)) { ! 1314: ipc_kmsg_clean_partial(kmsg,0,0,0); ! 1315: return MACH_SEND_MSG_TOO_SMALL; ! 1316: } ! 1317: ! 1318: /* ! 1319: * Make an initial pass to determine kernal VM space requirements for ! 1320: * physical copies. ! 1321: */ ! 1322: for (sstart = saddr; sstart < eaddr; sstart++) { ! 1323: ! 1324: if (sstart->type.type == MACH_MSG_OOL_DESCRIPTOR || ! 1325: sstart->type.type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) { ! 1326: ! 1327: assert(!(sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && ! 1328: (use_page_lists || steal_pages))); ! 1329: ! 1330: if (sstart->out_of_line.copy != MACH_MSG_PHYSICAL_COPY && ! 1331: sstart->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) { ! 1332: /* ! 1333: * Invalid copy option ! 1334: */ ! 1335: ipc_kmsg_clean_partial(kmsg,0,0,0); ! 1336: return MACH_SEND_INVALID_TYPE; ! 1337: } ! 1338: ! 1339: if (sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && ! 1340: sstart->out_of_line.size >= MSG_OOL_SIZE_SMALL(rt) && ! 1341: !sstart->out_of_line.deallocate) { ! 1342: ! 1343: /* ! 1344: * Out-of-line memory descriptor, accumulate kernel ! 1345: * memory requirements ! 1346: */ ! 1347: space_needed += round_page(sstart->out_of_line.size); ! 1348: if (space_needed > ipc_kmsg_max_vm_space) { ! 1349: ! 1350: /* ! 1351: * Per message kernel memory limit exceeded ! 1352: */ ! 1353: ipc_kmsg_clean_partial(kmsg,0,0,0); ! 1354: return MACH_MSG_VM_KERNEL; ! 1355: } ! 1356: } ! 1357: } ! 1358: } ! 1359: ! 1360: /* ! 1361: * Allocate space in the pageable kernel ipc copy map for all the ! 1362: * ool data that is to be physically copied. Map is marked wait for ! 1363: * space. ! 1364: */ ! 1365: if (space_needed) { ! 1366: #if MACH_RT ! 1367: if (rt) { ! 1368: ipc_kmsg_clean_partial(kmsg,0,0,0); ! 1369: return MACH_SEND_INVALID_RT_OOL_SIZE; ! 1370: } ! 1371: #endif /* MACH_RT */ ! 1372: if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, ! 1373: TRUE) != KERN_SUCCESS) { ! 1374: ipc_kmsg_clean_partial(kmsg,0,0,0); ! 1375: return MACH_MSG_VM_KERNEL; ! 1376: } ! 1377: } ! 1378: ! 1379: /* ! 1380: * handle the OOL regions and port descriptors. ! 1381: * the check for complex messages was done earlier. ! 1382: */ ! 1383: ! 1384: for (i = 0, sstart = saddr; sstart < eaddr; sstart++) { ! 1385: ! 1386: switch (sstart->type.type) { ! 1387: ! 1388: case MACH_MSG_PORT_DESCRIPTOR: { ! 1389: mach_msg_type_name_t name; ! 1390: ipc_object_t object; ! 1391: mach_msg_port_descriptor_t *dsc; ! 1392: ! 1393: dsc = &sstart->port; ! 1394: ! 1395: /* this is really the type SEND, SEND_ONCE, etc. */ ! 1396: name = dsc->disposition; ! 1397: dsc->disposition = ipc_object_copyin_type(name); ! 1398: ! 1399: if (!MACH_PORT_VALID((mach_port_name_t)dsc->name)) { ! 1400: complex = TRUE; ! 1401: break; ! 1402: } ! 1403: kr = ipc_object_copyin(space, (mach_port_name_t)dsc->name, name, &object); ! 1404: if (kr != KERN_SUCCESS) { ! 1405: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1406: return MACH_SEND_INVALID_RIGHT; ! 1407: } ! 1408: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1409: ipc_port_check_circularity((ipc_port_t) object, ! 1410: (ipc_port_t) dest)) { ! 1411: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 1412: } ! 1413: dsc->name = (ipc_port_t) object; ! 1414: complex = TRUE; ! 1415: break; ! 1416: } ! 1417: case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: ! 1418: case MACH_MSG_OOL_DESCRIPTOR: { ! 1419: vm_size_t length; ! 1420: boolean_t dealloc; ! 1421: vm_offset_t addr; ! 1422: vm_offset_t kaddr; ! 1423: mach_msg_ool_descriptor_t *dsc; ! 1424: ! 1425: dsc = &sstart->out_of_line; ! 1426: #if MACH_RT ! 1427: if ((dealloc = dsc->deallocate) && rt) { ! 1428: /* If RT, we cannot have paddr */ ! 1429: ipc_kmsg_clean_partial(kmsg, i, 0, 0); ! 1430: return MACH_MSG_INVALID_RT_DESCRIPTOR; ! 1431: } ! 1432: #else /* MACH_RT */ ! 1433: dealloc = dsc->deallocate; ! 1434: #endif /* MACH_RT */ ! 1435: addr = (vm_offset_t) dsc->address; ! 1436: ! 1437: length = dsc->size; ! 1438: ! 1439: if (length == 0) { ! 1440: dsc->address = 0; ! 1441: } else if (use_page_lists) { ! 1442: int options; ! 1443: ! 1444: #if MACH_RT ! 1445: assert(!rt); ! 1446: #endif /* MACH_RT */ ! 1447: /* ! 1448: * Use page list copy mechanism if specified. Since the ! 1449: * destination is a kernel port, no RT handling is ! 1450: * necessary. ! 1451: */ ! 1452: if (steal_pages == FALSE) { ! 1453: /* ! 1454: * XXX Temporary Hackaround. ! 1455: * XXX Because the same page ! 1456: * XXX might be in more than one ! 1457: * XXX out of line region, steal ! 1458: * XXX (busy) pages from previous ! 1459: * XXX region so that this copyin ! 1460: * XXX won't block (permanently). ! 1461: */ ! 1462: if (copy != VM_MAP_COPY_NULL) ! 1463: vm_map_copy_steal_pages(copy); ! 1464: } ! 1465: ! 1466: /* ! 1467: * Set up options for copying in page list. ! 1468: * If deallocating, steal pages to prevent ! 1469: * vm code from lazy evaluating deallocation. ! 1470: */ ! 1471: options = VM_PROT_READ; ! 1472: if (dealloc) { ! 1473: options |= VM_MAP_COPYIN_OPT_SRC_DESTROY | ! 1474: VM_MAP_COPYIN_OPT_STEAL_PAGES; ! 1475: } ! 1476: else if (steal_pages) { ! 1477: options |= VM_MAP_COPYIN_OPT_STEAL_PAGES; ! 1478: } ! 1479: ! 1480: if (vm_map_copyin_page_list(map, addr, length, options, ! 1481: ©, FALSE) ! 1482: != KERN_SUCCESS) { ! 1483: ! 1484: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1485: return MACH_SEND_INVALID_MEMORY; ! 1486: } ! 1487: ! 1488: dsc->address = (void *) copy; ! 1489: dsc->copy = MACH_MSG_PAGE_LIST_COPY_T; ! 1490: } else if (length < MSG_OOL_SIZE_SMALL(rt) && ! 1491: dsc->copy == MACH_MSG_PHYSICAL_COPY) { ! 1492: ! 1493: /* ! 1494: * If the data is 'small' enough, always kalloc space for ! 1495: * it and copy it in. The data will be copied out ! 1496: * on the message receive. This is a performance ! 1497: * optimization that assumes the cost of VM operations ! 1498: * dominates the copyin/copyout overhead for 'small' ! 1499: * regions. ! 1500: * If the kernel is the message target, a consistent data ! 1501: * repesentation is needed for ool data since kernel ! 1502: * functions may deallocate the ool data. In this case ! 1503: * a vm_map_copy_t is allocated along with the space for ! 1504: * the data as an optimization. No RT handling is needed. ! 1505: */ ! 1506: if (is_ipc_kobject(ip_kotype((ipc_port_t)dest))) { ! 1507: vm_map_copy_t copy; ! 1508: vm_size_t kalloc_size = sizeof(struct vm_map_copy) + ! 1509: length; ! 1510: ! 1511: #if MACH_RT ! 1512: assert(!rt); ! 1513: #endif /* MACH_RT */ ! 1514: copy = (vm_map_copy_t) kalloc(kalloc_size); ! 1515: if (copy == VM_MAP_COPY_NULL) { ! 1516: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1517: space_needed); ! 1518: return MACH_MSG_VM_KERNEL; ! 1519: } ! 1520: copy->type = VM_MAP_COPY_KERNEL_BUFFER; ! 1521: if (copyin((const char *) addr, (char *) (copy + 1), ! 1522: length)) { ! 1523: kfree((vm_offset_t) copy, kalloc_size); ! 1524: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1525: space_needed); ! 1526: return MACH_SEND_INVALID_MEMORY; ! 1527: } ! 1528: dsc->address = (void *) copy; ! 1529: dsc->copy = MACH_MSG_KALLOC_COPY_T; ! 1530: copy->size = length; ! 1531: copy->offset = 0; ! 1532: copy->cpy_kdata = (vm_offset_t) (copy + 1); ! 1533: copy->cpy_kalloc_size = kalloc_size; ! 1534: } else { ! 1535: if ((kaddr = KALLOC(length, rt)) == (vm_offset_t) 0) { ! 1536: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1537: space_needed); ! 1538: return MACH_MSG_VM_KERNEL; ! 1539: } ! 1540: ! 1541: if (copyin((const char *) addr, (char *) kaddr, ! 1542: length)) { ! 1543: KFREE(kaddr, length, rt); ! 1544: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1545: space_needed); ! 1546: return MACH_SEND_INVALID_MEMORY; ! 1547: } ! 1548: dsc->address = (void *) kaddr; ! 1549: } ! 1550: if (dealloc) { ! 1551: (void) vm_map_remove(map, trunc_page(addr), ! 1552: round_page(addr + length), ! 1553: VM_MAP_REMOVE_WAIT_FOR_KWIRE| ! 1554: VM_MAP_REMOVE_INTERRUPTIBLE); ! 1555: } ! 1556: } else { ! 1557: if ((dsc->copy == MACH_MSG_PHYSICAL_COPY) && !dealloc) { ! 1558: ! 1559: /* ! 1560: * If the request is a physical copy and the source ! 1561: * is not being deallocated, then allocate space ! 1562: * in the kernel's pageable ipc copy map and copy ! 1563: * the data in. The semantics guarantee that the ! 1564: * data will have been physically copied before ! 1565: * the send operation terminates. Thus if the data ! 1566: * is not being deallocated, we must be prepared ! 1567: * to page if the region is sufficiently large. ! 1568: */ ! 1569: if (copyin((const char *) addr, (char *) paddr, ! 1570: length)) { ! 1571: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1572: space_needed); ! 1573: return MACH_SEND_INVALID_MEMORY; ! 1574: } ! 1575: ! 1576: /* ! 1577: * The kernel ipc copy map is marked no_zero_fill. ! 1578: * If the transfer is not a page multiple, we need ! 1579: * to zero fill the balance. ! 1580: */ ! 1581: if (!page_aligned(length)) { ! 1582: (void) memset((void *) (paddr + length), 0, ! 1583: round_page(length) - length); ! 1584: } ! 1585: if (vm_map_copyin(ipc_kernel_copy_map, paddr, length, ! 1586: TRUE, ©) != KERN_SUCCESS) { ! 1587: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1588: space_needed); ! 1589: return MACH_MSG_VM_KERNEL; ! 1590: } ! 1591: paddr += round_page(length); ! 1592: space_needed -= round_page(length); ! 1593: } else { ! 1594: ! 1595: /* ! 1596: * Make a virtual copy of the of the data if requested ! 1597: * or if a physical copy was requested but the source ! 1598: * is being deallocated. This is an invalid ! 1599: * path if RT. ! 1600: */ ! 1601: #if MACH_RT ! 1602: if (rt) { ! 1603: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1604: space_needed); ! 1605: return MACH_SEND_INVALID_TYPE; ! 1606: } ! 1607: #endif /* MACH_RT */ ! 1608: if (vm_map_copyin(map, addr, length, ! 1609: dealloc, ©) != KERN_SUCCESS) { ! 1610: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1611: space_needed); ! 1612: return MACH_SEND_INVALID_MEMORY; ! 1613: } ! 1614: } ! 1615: dsc->address = (void *) copy; ! 1616: } ! 1617: complex = TRUE; ! 1618: break; ! 1619: } ! 1620: case MACH_MSG_OOL_PORTS_DESCRIPTOR: { ! 1621: vm_size_t length; ! 1622: vm_offset_t data; ! 1623: vm_offset_t addr; ! 1624: ipc_object_t *objects; ! 1625: int j; ! 1626: mach_msg_type_name_t name; ! 1627: mach_msg_ool_ports_descriptor_t *dsc; ! 1628: ! 1629: dsc = &sstart->ool_ports; ! 1630: addr = (vm_offset_t) dsc->address; ! 1631: ! 1632: /* calculate length of data in bytes, rounding up */ ! 1633: length = dsc->count * sizeof(mach_port_name_t); ! 1634: ! 1635: if (length == 0) { ! 1636: complex = TRUE; ! 1637: dsc->address = (void *) 0; ! 1638: break; ! 1639: } ! 1640: ! 1641: data = KALLOC(length, rt); ! 1642: ! 1643: if (data == 0) { ! 1644: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1645: return MACH_SEND_NO_BUFFER; ! 1646: } ! 1647: ! 1648: if (copyinmap(map, addr, data, length)) { ! 1649: KFREE(data, length, rt); ! 1650: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1651: return MACH_SEND_INVALID_MEMORY; ! 1652: } ! 1653: ! 1654: if (dsc->deallocate) { ! 1655: (void) vm_deallocate(map, addr, length); ! 1656: } ! 1657: ! 1658: dsc->address = (void *) data; ! 1659: ! 1660: /* this is really the type SEND, SEND_ONCE, etc. */ ! 1661: name = dsc->disposition; ! 1662: dsc->disposition = ipc_object_copyin_type(name); ! 1663: ! 1664: objects = (ipc_object_t *) data; ! 1665: ! 1666: for ( j = 0; j < dsc->count; j++) { ! 1667: mach_port_name_t port = (mach_port_name_t) objects[j]; ! 1668: ipc_object_t object; ! 1669: ! 1670: if (!MACH_PORT_VALID(port)) ! 1671: continue; ! 1672: ! 1673: kr = ipc_object_copyin(space, port, name, &object); ! 1674: ! 1675: if (kr != KERN_SUCCESS) { ! 1676: int k; ! 1677: ! 1678: for(k = 0; k < j; k++) { ! 1679: object = objects[k]; ! 1680: if (!MACH_PORT_VALID(port)) ! 1681: continue; ! 1682: ipc_object_destroy(object, dsc->disposition); ! 1683: } ! 1684: KFREE(data, length, rt); ! 1685: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1686: return MACH_SEND_INVALID_RIGHT; ! 1687: } ! 1688: ! 1689: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1690: ipc_port_check_circularity( ! 1691: (ipc_port_t) object, ! 1692: (ipc_port_t) dest)) ! 1693: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 1694: ! 1695: objects[j] = object; ! 1696: } ! 1697: ! 1698: complex = TRUE; ! 1699: break; ! 1700: } ! 1701: default: { ! 1702: /* ! 1703: * Invalid descriptor ! 1704: */ ! 1705: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1706: return MACH_SEND_INVALID_TYPE; ! 1707: } ! 1708: } ! 1709: i++ ; ! 1710: } ! 1711: ! 1712: if (!complex) ! 1713: kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; ! 1714: return MACH_MSG_SUCCESS; ! 1715: } ! 1716: ! 1717: ! 1718: /* ! 1719: * Routine: ipc_kmsg_copyin ! 1720: * Purpose: ! 1721: * "Copy-in" port rights and out-of-line memory ! 1722: * in the message. ! 1723: * ! 1724: * In all failure cases, the message is left holding ! 1725: * no rights or memory. However, the message buffer ! 1726: * is not deallocated. If successful, the message ! 1727: * contains a valid destination port. ! 1728: * Conditions: ! 1729: * Nothing locked. ! 1730: * Returns: ! 1731: * MACH_MSG_SUCCESS Successful copyin. ! 1732: * MACH_SEND_INVALID_HEADER ! 1733: * Illegal value in the message header bits. ! 1734: * MACH_SEND_INVALID_NOTIFY Bad notify port. ! 1735: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 1736: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 1737: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 1738: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 1739: * MACH_SEND_INVALID_TYPE Bad type specification. ! 1740: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 1741: */ ! 1742: ! 1743: mach_msg_return_t ! 1744: ipc_kmsg_copyin( ! 1745: ipc_kmsg_t kmsg, ! 1746: ipc_space_t space, ! 1747: vm_map_t map, ! 1748: mach_port_name_t notify) ! 1749: { ! 1750: mach_msg_return_t mr; ! 1751: ! 1752: mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify); ! 1753: if (mr != MACH_MSG_SUCCESS) ! 1754: return mr; ! 1755: ! 1756: if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 1757: return MACH_MSG_SUCCESS; ! 1758: ! 1759: return( ipc_kmsg_copyin_body( kmsg, space, map) ); ! 1760: } ! 1761: ! 1762: /* ! 1763: * Routine: ipc_kmsg_copyin_from_kernel ! 1764: * Purpose: ! 1765: * "Copy-in" port rights and out-of-line memory ! 1766: * in a message sent from the kernel. ! 1767: * ! 1768: * Because the message comes from the kernel, ! 1769: * the implementation assumes there are no errors ! 1770: * or peculiarities in the message. ! 1771: * ! 1772: * Returns TRUE if queueing the message ! 1773: * would result in a circularity. ! 1774: * Conditions: ! 1775: * Nothing locked. ! 1776: */ ! 1777: ! 1778: void ! 1779: ipc_kmsg_copyin_from_kernel( ! 1780: ipc_kmsg_t kmsg) ! 1781: { ! 1782: mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits; ! 1783: mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits); ! 1784: mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits); ! 1785: ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 1786: ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 1787: ! 1788: /* translate the destination and reply ports */ ! 1789: ! 1790: ipc_object_copyin_from_kernel(remote, rname); ! 1791: if (IO_VALID(local)) ! 1792: ipc_object_copyin_from_kernel(local, lname); ! 1793: ! 1794: /* ! 1795: * The common case is a complex message with no reply port, ! 1796: * because that is what the memory_object interface uses. ! 1797: */ ! 1798: ! 1799: if (bits == (MACH_MSGH_BITS_COMPLEX | ! 1800: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) { ! 1801: bits = (MACH_MSGH_BITS_COMPLEX | ! 1802: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0)); ! 1803: ! 1804: kmsg->ikm_header.msgh_bits = bits; ! 1805: } else { ! 1806: bits = (MACH_MSGH_BITS_OTHER(bits) | ! 1807: MACH_MSGH_BITS(ipc_object_copyin_type(rname), ! 1808: ipc_object_copyin_type(lname))); ! 1809: ! 1810: kmsg->ikm_header.msgh_bits = bits; ! 1811: if ((bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 1812: return; ! 1813: } ! 1814: { ! 1815: mach_msg_descriptor_t *saddr, *eaddr; ! 1816: mach_msg_body_t *body; ! 1817: ! 1818: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 1819: saddr = (mach_msg_descriptor_t *) (body + 1); ! 1820: eaddr = (mach_msg_descriptor_t *) saddr + body->msgh_descriptor_count; ! 1821: ! 1822: for ( ; saddr < eaddr; saddr++) { ! 1823: ! 1824: switch (saddr->type.type) { ! 1825: ! 1826: case MACH_MSG_PORT_DESCRIPTOR: { ! 1827: mach_msg_type_name_t name; ! 1828: ipc_object_t object; ! 1829: mach_msg_port_descriptor_t *dsc; ! 1830: ! 1831: dsc = &saddr->port; ! 1832: ! 1833: /* this is really the type SEND, SEND_ONCE, etc. */ ! 1834: name = dsc->disposition; ! 1835: object = (ipc_object_t) dsc->name; ! 1836: dsc->disposition = ipc_object_copyin_type(name); ! 1837: ! 1838: if (!IO_VALID(object)) { ! 1839: break; ! 1840: } ! 1841: ! 1842: ipc_object_copyin_from_kernel(object, name); ! 1843: ! 1844: /* CDY avoid circularity when the destination is also */ ! 1845: /* the kernel. This check should be changed into an */ ! 1846: /* assert when the new kobject model is in place since*/ ! 1847: /* ports will not be used in kernel to kernel chats */ ! 1848: ! 1849: if (((ipc_port_t)remote)->ip_receiver != ipc_space_kernel) { ! 1850: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1851: ipc_port_check_circularity((ipc_port_t) object, ! 1852: (ipc_port_t) remote)) { ! 1853: kmsg->ikm_header.msgh_bits |= ! 1854: MACH_MSGH_BITS_CIRCULAR; ! 1855: } ! 1856: } ! 1857: break; ! 1858: } ! 1859: case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: ! 1860: case MACH_MSG_OOL_DESCRIPTOR: { ! 1861: /* ! 1862: * The sender should supply ready-made memory, i.e. ! 1863: * a vm_map_copy_t, so we don't need to do anything. ! 1864: */ ! 1865: break; ! 1866: } ! 1867: case MACH_MSG_OOL_PORTS_DESCRIPTOR: { ! 1868: ipc_object_t *objects; ! 1869: int j; ! 1870: mach_msg_type_name_t name; ! 1871: mach_msg_ool_ports_descriptor_t *dsc; ! 1872: ! 1873: dsc = &saddr->ool_ports; ! 1874: ! 1875: /* this is really the type SEND, SEND_ONCE, etc. */ ! 1876: name = dsc->disposition; ! 1877: dsc->disposition = ipc_object_copyin_type(name); ! 1878: ! 1879: objects = (ipc_object_t *) dsc->address; ! 1880: ! 1881: for ( j = 0; j < dsc->count; j++) { ! 1882: ipc_object_t object = objects[j]; ! 1883: ! 1884: if (!IO_VALID(object)) ! 1885: continue; ! 1886: ! 1887: ipc_object_copyin_from_kernel(object, name); ! 1888: ! 1889: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1890: ipc_port_check_circularity( ! 1891: (ipc_port_t) object, ! 1892: (ipc_port_t) remote)) ! 1893: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 1894: } ! 1895: break; ! 1896: } ! 1897: default: { ! 1898: #if MACH_ASSERT ! 1899: panic("ipc_kmsg_copyin_from_kernel: bad descriptor"); ! 1900: #endif /* MACH_ASSERT */ ! 1901: } ! 1902: } ! 1903: } ! 1904: } ! 1905: } ! 1906: ! 1907: /* ! 1908: * Routine: ipc_kmsg_copyout_header ! 1909: * Purpose: ! 1910: * "Copy-out" port rights in the header of a message. ! 1911: * Operates atomically; if it doesn't succeed the ! 1912: * message header and the space are left untouched. ! 1913: * If it does succeed the remote/local port fields ! 1914: * contain port names instead of object pointers, ! 1915: * and the bits field is updated. ! 1916: * ! 1917: * The notify argument implements the MACH_RCV_NOTIFY option. ! 1918: * If it is not MACH_PORT_NULL, it should name a receive right. ! 1919: * If the process of receiving the reply port creates a ! 1920: * new right in the receiving task, then the new right is ! 1921: * automatically registered for a dead-name notification, ! 1922: * with the notify port supplying the send-once right. ! 1923: * Conditions: ! 1924: * Nothing locked. ! 1925: * Returns: ! 1926: * MACH_MSG_SUCCESS Copied out port rights. ! 1927: * MACH_RCV_INVALID_NOTIFY ! 1928: * Notify is non-null and doesn't name a receive right. ! 1929: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 1930: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 1931: * The space is dead. ! 1932: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 1933: * No room in space for another name. ! 1934: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 1935: * Couldn't allocate memory for the reply port. ! 1936: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 1937: * Couldn't allocate memory for the dead-name request. ! 1938: */ ! 1939: ! 1940: mach_msg_return_t ! 1941: ipc_kmsg_copyout_header( ! 1942: mach_msg_header_t *msg, ! 1943: ipc_space_t space, ! 1944: mach_port_name_t notify) ! 1945: { ! 1946: mach_msg_bits_t mbits = msg->msgh_bits; ! 1947: ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port; ! 1948: ! 1949: assert(IP_VALID(dest)); ! 1950: ! 1951: { ! 1952: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 1953: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 1954: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; ! 1955: mach_port_name_t dest_name, reply_name; ! 1956: ! 1957: if (IP_VALID(reply)) { ! 1958: ipc_port_t notify_port; ! 1959: ipc_entry_t entry; ! 1960: kern_return_t kr; ! 1961: ! 1962: /* ! 1963: * Handling notify (for MACH_RCV_NOTIFY) is tricky. ! 1964: * The problem is atomically making a send-once right ! 1965: * from the notify port and installing it for a ! 1966: * dead-name request in the new entry, because this ! 1967: * requires two port locks (on the notify port and ! 1968: * the reply port). However, we can safely make ! 1969: * and consume send-once rights for the notify port ! 1970: * as long as we hold the space locked. This isn't ! 1971: * an atomicity problem, because the only way ! 1972: * to detect that a send-once right has been created ! 1973: * and then consumed if it wasn't needed is by getting ! 1974: * at the receive right to look at ip_sorights, and ! 1975: * because the space is write-locked status calls can't ! 1976: * lookup the notify port receive right. When we make ! 1977: * the send-once right, we lock the notify port, ! 1978: * so any status calls in progress will be done. ! 1979: */ ! 1980: ! 1981: is_write_lock(space); ! 1982: ! 1983: for (;;) { ! 1984: ipc_port_request_index_t request; ! 1985: ! 1986: if (!space->is_active) { ! 1987: is_write_unlock(space); ! 1988: return (MACH_RCV_HEADER_ERROR| ! 1989: MACH_MSG_IPC_SPACE); ! 1990: } ! 1991: ! 1992: if (notify != MACH_PORT_NULL) { ! 1993: notify_port = ipc_port_lookup_notify(space, ! 1994: notify); ! 1995: if (notify_port == IP_NULL) { ! 1996: is_write_unlock(space); ! 1997: return MACH_RCV_INVALID_NOTIFY; ! 1998: } ! 1999: } else ! 2000: notify_port = IP_NULL; ! 2001: ! 2002: if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 2003: ipc_right_reverse(space, (ipc_object_t) reply, ! 2004: &reply_name, &entry)) { ! 2005: /* reply port is locked and active */ ! 2006: ! 2007: /* ! 2008: * We don't need the notify_port ! 2009: * send-once right, but we can't release ! 2010: * it here because reply port is locked. ! 2011: * Wait until after the copyout to ! 2012: * release the notify port right. ! 2013: */ ! 2014: ! 2015: assert(entry->ie_bits & ! 2016: MACH_PORT_TYPE_SEND_RECEIVE); ! 2017: break; ! 2018: } ! 2019: ! 2020: ip_lock(reply); ! 2021: if (!ip_active(reply)) { ! 2022: ip_release(reply); ! 2023: ip_check_unlock(reply); ! 2024: ! 2025: if (notify_port != IP_NULL) ! 2026: ipc_port_release_sonce(notify_port); ! 2027: ! 2028: ip_lock(dest); ! 2029: is_write_unlock(space); ! 2030: ! 2031: reply = IP_DEAD; ! 2032: reply_name = MACH_PORT_DEAD; ! 2033: goto copyout_dest; ! 2034: } ! 2035: ! 2036: reply_name = (mach_port_name_t)reply; ! 2037: kr = ipc_entry_get(space, &reply_name, &entry); ! 2038: if (kr != KERN_SUCCESS) { ! 2039: ip_unlock(reply); ! 2040: ! 2041: if (notify_port != IP_NULL) ! 2042: ipc_port_release_sonce(notify_port); ! 2043: ! 2044: /* space is locked */ ! 2045: kr = ipc_entry_grow_table(space, ! 2046: ITS_SIZE_NONE); ! 2047: if (kr != KERN_SUCCESS) { ! 2048: /* space is unlocked */ ! 2049: ! 2050: if (kr == KERN_RESOURCE_SHORTAGE) ! 2051: return (MACH_RCV_HEADER_ERROR| ! 2052: MACH_MSG_IPC_KERNEL); ! 2053: else ! 2054: return (MACH_RCV_HEADER_ERROR| ! 2055: MACH_MSG_IPC_SPACE); ! 2056: } ! 2057: /* space is locked again; start over */ ! 2058: ! 2059: continue; ! 2060: } ! 2061: assert(IE_BITS_TYPE(entry->ie_bits) == ! 2062: MACH_PORT_TYPE_NONE); ! 2063: assert(entry->ie_object == IO_NULL); ! 2064: ! 2065: if (notify_port == IP_NULL) { ! 2066: /* not making a dead-name request */ ! 2067: ! 2068: entry->ie_object = (ipc_object_t) reply; ! 2069: break; ! 2070: } ! 2071: ! 2072: kr = ipc_port_dnrequest(reply, reply_name, ! 2073: notify_port, &request); ! 2074: if (kr != KERN_SUCCESS) { ! 2075: ip_unlock(reply); ! 2076: ! 2077: ipc_port_release_sonce(notify_port); ! 2078: ! 2079: ipc_entry_dealloc(space, reply_name, entry); ! 2080: is_write_unlock(space); ! 2081: ! 2082: ip_lock(reply); ! 2083: if (!ip_active(reply)) { ! 2084: /* will fail next time around loop */ ! 2085: ! 2086: ip_unlock(reply); ! 2087: is_write_lock(space); ! 2088: continue; ! 2089: } ! 2090: ! 2091: kr = ipc_port_dngrow(reply, ITS_SIZE_NONE); ! 2092: /* port is unlocked */ ! 2093: if (kr != KERN_SUCCESS) ! 2094: return (MACH_RCV_HEADER_ERROR| ! 2095: MACH_MSG_IPC_KERNEL); ! 2096: ! 2097: is_write_lock(space); ! 2098: continue; ! 2099: } ! 2100: ! 2101: notify_port = IP_NULL; /* don't release right below */ ! 2102: ! 2103: entry->ie_object = (ipc_object_t) reply; ! 2104: entry->ie_request = request; ! 2105: break; ! 2106: } ! 2107: ! 2108: /* space and reply port are locked and active */ ! 2109: ! 2110: ip_reference(reply); /* hold onto the reply port */ ! 2111: ! 2112: kr = ipc_right_copyout(space, reply_name, entry, ! 2113: reply_type, TRUE, (ipc_object_t) reply); ! 2114: /* reply port is unlocked */ ! 2115: assert(kr == KERN_SUCCESS); ! 2116: ! 2117: if (notify_port != IP_NULL) ! 2118: ipc_port_release_sonce(notify_port); ! 2119: ! 2120: ip_lock(dest); ! 2121: is_write_unlock(space); ! 2122: } else { ! 2123: /* ! 2124: * No reply port! This is an easy case. ! 2125: * We only need to have the space locked ! 2126: * when checking notify and when locking ! 2127: * the destination (to ensure atomicity). ! 2128: */ ! 2129: ! 2130: is_read_lock(space); ! 2131: if (!space->is_active) { ! 2132: is_read_unlock(space); ! 2133: return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE; ! 2134: } ! 2135: ! 2136: if (notify != MACH_PORT_NULL) { ! 2137: ipc_entry_t entry; ! 2138: ! 2139: /* must check notify even though it won't be used */ ! 2140: ! 2141: if ((entry = ipc_entry_lookup(space, notify)) == IE_NULL) { ! 2142: is_read_unlock(space); ! 2143: return MACH_RCV_INVALID_NOTIFY; ! 2144: } ! 2145: ! 2146: if ((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_name_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 = (ipc_port_t)dest_name; ! 2237: msg->msgh_remote_port = (ipc_port_t)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( ! 2262: ipc_space_t space, ! 2263: ipc_object_t object, ! 2264: mach_msg_type_name_t msgt_name, ! 2265: mach_port_name_t *namep) ! 2266: { ! 2267: kern_return_t kr; ! 2268: ! 2269: if (!IO_VALID(object)) { ! 2270: *namep = (mach_port_name_t) object; ! 2271: return MACH_MSG_SUCCESS; ! 2272: } ! 2273: ! 2274: kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep); ! 2275: if (kr != KERN_SUCCESS) { ! 2276: ipc_object_destroy(object, msgt_name); ! 2277: ! 2278: if (kr == KERN_INVALID_CAPABILITY) ! 2279: *namep = MACH_PORT_DEAD; ! 2280: else { ! 2281: *namep = MACH_PORT_NULL; ! 2282: ! 2283: if (kr == KERN_RESOURCE_SHORTAGE) ! 2284: return MACH_MSG_IPC_KERNEL; ! 2285: else ! 2286: return MACH_MSG_IPC_SPACE; ! 2287: } ! 2288: } ! 2289: ! 2290: return MACH_MSG_SUCCESS; ! 2291: } ! 2292: ! 2293: /* ! 2294: * Routine: ipc_kmsg_copyout_body ! 2295: * Purpose: ! 2296: * "Copy-out" port rights and out-of-line memory ! 2297: * in the body of a message. ! 2298: * ! 2299: * The error codes are a combination of special bits. ! 2300: * The copyout proceeds despite errors. ! 2301: * Conditions: ! 2302: * Nothing locked. ! 2303: * Returns: ! 2304: * MACH_MSG_SUCCESS Successful copyout. ! 2305: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 2306: * MACH_MSG_VM_SPACE No room for memory in address space. ! 2307: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 2308: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 2309: * MACH_MSG_INVALID_RT_DESCRIPTOR Descriptor incompatible with RT ! 2310: */ ! 2311: ! 2312: mach_msg_return_t ! 2313: ipc_kmsg_copyout_body( ! 2314: ipc_kmsg_t kmsg, ! 2315: ipc_space_t space, ! 2316: vm_map_t map, ! 2317: mach_msg_body_t *slist) ! 2318: { ! 2319: mach_msg_body_t *body; ! 2320: mach_msg_descriptor_t *saddr, *eaddr; ! 2321: mach_msg_return_t mr = MACH_MSG_SUCCESS; ! 2322: kern_return_t kr; ! 2323: vm_offset_t data; ! 2324: mach_msg_descriptor_t *sstart, *send; ! 2325: #if MACH_RT ! 2326: boolean_t rt; ! 2327: #endif /* MACH_RT */ ! 2328: ! 2329: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 2330: saddr = (mach_msg_descriptor_t *) (body + 1); ! 2331: eaddr = saddr + body->msgh_descriptor_count; ! 2332: #if MACH_RT ! 2333: rt = KMSG_IS_RT(kmsg); ! 2334: #endif /* MACH_RT */ ! 2335: ! 2336: /* ! 2337: * Do scatter list setup ! 2338: */ ! 2339: if (slist != MACH_MSG_BODY_NULL) { ! 2340: sstart = (mach_msg_descriptor_t *) (slist + 1); ! 2341: send = sstart + slist->msgh_descriptor_count; ! 2342: } ! 2343: else { ! 2344: sstart = MACH_MSG_DESCRIPTOR_NULL; ! 2345: } ! 2346: ! 2347: for ( ; saddr < eaddr; saddr++ ) { ! 2348: ! 2349: switch (saddr->type.type) { ! 2350: ! 2351: case MACH_MSG_PORT_DESCRIPTOR: { ! 2352: mach_msg_port_descriptor_t *dsc; ! 2353: ! 2354: /* ! 2355: * Copyout port right carried in the message ! 2356: */ ! 2357: dsc = &saddr->port; ! 2358: mr |= ipc_kmsg_copyout_object(space, ! 2359: (ipc_object_t) dsc->name, ! 2360: dsc->disposition, ! 2361: (mach_port_name_t *) &dsc->name); ! 2362: ! 2363: break; ! 2364: } ! 2365: case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: ! 2366: case MACH_MSG_OOL_DESCRIPTOR : { ! 2367: vm_offset_t rcv_addr; ! 2368: vm_offset_t snd_addr; ! 2369: mach_msg_ool_descriptor_t *dsc; ! 2370: mach_msg_copy_options_t copy_option; ! 2371: ! 2372: SKIP_PORT_DESCRIPTORS(sstart, send); ! 2373: ! 2374: dsc = &saddr->out_of_line; ! 2375: ! 2376: assert(dsc->copy != MACH_MSG_KALLOC_COPY_T); ! 2377: assert(dsc->copy != MACH_MSG_PAGE_LIST_COPY_T); ! 2378: ! 2379: copy_option = dsc->copy; ! 2380: ! 2381: if ((snd_addr = (vm_offset_t) dsc->address) != 0) { ! 2382: if (sstart != MACH_MSG_DESCRIPTOR_NULL && ! 2383: sstart->out_of_line.copy == MACH_MSG_OVERWRITE) { ! 2384: ! 2385: /* ! 2386: * There is an overwrite descriptor specified in the ! 2387: * scatter list for this ool data. The descriptor ! 2388: * has already been verified ! 2389: */ ! 2390: rcv_addr = (vm_offset_t) sstart->out_of_line.address; ! 2391: dsc->copy = MACH_MSG_OVERWRITE; ! 2392: } else { ! 2393: dsc->copy = MACH_MSG_ALLOCATE; ! 2394: } ! 2395: ! 2396: if (copy_option == MACH_MSG_PHYSICAL_COPY && ! 2397: dsc->size < MSG_OOL_SIZE_SMALL(rt)) { ! 2398: ! 2399: /* ! 2400: * Sufficiently 'small' data was copied into a kalloc'ed ! 2401: * buffer copy was requested. Just copy it out and ! 2402: * free the buffer. ! 2403: */ ! 2404: if (dsc->copy == MACH_MSG_ALLOCATE) { ! 2405: #if MACH_RT ! 2406: /* ! 2407: * The MACH_MSG_ALLOCATE option is not ! 2408: * compatible with RT behavior. ! 2409: */ ! 2410: if (rt) { ! 2411: mr |= MACH_MSG_INVALID_RT_DESCRIPTOR; ! 2412: KFREE(snd_addr, dsc->size, rt); ! 2413: dsc->address = (void *) 0; ! 2414: INCREMENT_SCATTER(sstart); ! 2415: break; ! 2416: } ! 2417: #endif /* MACH_RT */ ! 2418: ! 2419: /* ! 2420: * If there is no overwrite region, allocate ! 2421: * space in receiver's address space for the ! 2422: * data ! 2423: */ ! 2424: if ((kr = vm_allocate(map, &rcv_addr, dsc->size, ! 2425: TRUE)) != KERN_SUCCESS) { ! 2426: if (kr == KERN_RESOURCE_SHORTAGE) ! 2427: mr |= MACH_MSG_VM_KERNEL; ! 2428: else ! 2429: mr |= MACH_MSG_VM_SPACE; ! 2430: KFREE(snd_addr, dsc->size, rt); ! 2431: dsc->address = (void *) 0; ! 2432: INCREMENT_SCATTER(sstart); ! 2433: break; ! 2434: } ! 2435: } ! 2436: (void) copyoutmap(map, snd_addr, rcv_addr, dsc->size); ! 2437: KFREE(snd_addr, dsc->size, rt); ! 2438: } else { ! 2439: ! 2440: /* ! 2441: * Whether the data was virtually or physically ! 2442: * copied we have a vm_map_copy_t for it. ! 2443: * If there's an overwrite region specified ! 2444: * overwrite it, otherwise do a virtual copy out. ! 2445: */ ! 2446: if (dsc->copy == MACH_MSG_OVERWRITE) { ! 2447: kr = vm_map_copy_overwrite(map, rcv_addr, ! 2448: (vm_map_copy_t) dsc->address, TRUE); ! 2449: } else { ! 2450: kr = vm_map_copyout(map, &rcv_addr, ! 2451: (vm_map_copy_t) dsc->address); ! 2452: } ! 2453: if (kr != KERN_SUCCESS) { ! 2454: if (kr == KERN_RESOURCE_SHORTAGE) ! 2455: mr |= MACH_MSG_VM_KERNEL; ! 2456: else ! 2457: mr |= MACH_MSG_VM_SPACE; ! 2458: vm_map_copy_discard((vm_map_copy_t) dsc->address); ! 2459: dsc->address = 0; ! 2460: INCREMENT_SCATTER(sstart); ! 2461: break; ! 2462: } ! 2463: } ! 2464: dsc->address = (void *) rcv_addr; ! 2465: } ! 2466: INCREMENT_SCATTER(sstart); ! 2467: break; ! 2468: } ! 2469: case MACH_MSG_OOL_PORTS_DESCRIPTOR : { ! 2470: vm_offset_t addr; ! 2471: mach_port_name_t *objects; ! 2472: mach_msg_type_number_t j; ! 2473: vm_size_t length; ! 2474: mach_msg_ool_ports_descriptor_t *dsc; ! 2475: ! 2476: SKIP_PORT_DESCRIPTORS(sstart, send); ! 2477: ! 2478: dsc = &saddr->ool_ports; ! 2479: ! 2480: length = dsc->count * sizeof(mach_port_name_t); ! 2481: ! 2482: if (length != 0) { ! 2483: if (sstart != MACH_MSG_DESCRIPTOR_NULL && ! 2484: sstart->ool_ports.copy == MACH_MSG_OVERWRITE) { ! 2485: ! 2486: /* ! 2487: * There is an overwrite descriptor specified in the ! 2488: * scatter list for this ool data. The descriptor ! 2489: * has already been verified ! 2490: */ ! 2491: addr = (vm_offset_t) sstart->out_of_line.address; ! 2492: dsc->copy = MACH_MSG_OVERWRITE; ! 2493: } ! 2494: else { ! 2495: #if MACH_RT ! 2496: /* ! 2497: * The MACH_MSG_ALLOCATE option is not ! 2498: * compatible with RT behavior. ! 2499: */ ! 2500: if (rt) { ! 2501: mr |= MACH_MSG_INVALID_RT_DESCRIPTOR; ! 2502: ipc_kmsg_clean_body(kmsg, ! 2503: body->msgh_descriptor_count); ! 2504: dsc->address = 0; ! 2505: INCREMENT_SCATTER(sstart); ! 2506: break; ! 2507: } ! 2508: #endif /* MACH_RT */ ! 2509: ! 2510: /* ! 2511: * Dynamically allocate the region ! 2512: */ ! 2513: dsc->copy = MACH_MSG_ALLOCATE; ! 2514: if ((kr = vm_allocate(map, &addr, length, TRUE)) != ! 2515: KERN_SUCCESS) { ! 2516: ipc_kmsg_clean_body(kmsg, ! 2517: body->msgh_descriptor_count); ! 2518: dsc->address = 0; ! 2519: ! 2520: if (kr == KERN_RESOURCE_SHORTAGE){ ! 2521: mr |= MACH_MSG_VM_KERNEL; ! 2522: } else { ! 2523: mr |= MACH_MSG_VM_SPACE; ! 2524: } ! 2525: INCREMENT_SCATTER(sstart); ! 2526: break; ! 2527: } ! 2528: } ! 2529: } else { ! 2530: INCREMENT_SCATTER(sstart); ! 2531: break; ! 2532: } ! 2533: ! 2534: ! 2535: objects = (mach_port_name_t *) dsc->address ; ! 2536: ! 2537: /* copyout port rights carried in the message */ ! 2538: ! 2539: for ( j = 0; j < dsc->count ; j++) { ! 2540: ipc_object_t object = ! 2541: (ipc_object_t) objects[j]; ! 2542: ! 2543: mr |= ipc_kmsg_copyout_object(space, object, ! 2544: dsc->disposition, &objects[j]); ! 2545: } ! 2546: ! 2547: /* copyout to memory allocated above */ ! 2548: ! 2549: data = (vm_offset_t) dsc->address; ! 2550: (void) copyoutmap(map, data, addr, length); ! 2551: KFREE(data, length, rt); ! 2552: ! 2553: dsc->address = (void *) addr; ! 2554: INCREMENT_SCATTER(sstart); ! 2555: break; ! 2556: } ! 2557: default : { ! 2558: panic("untyped IPC copyout body: invalid message descriptor"); ! 2559: } ! 2560: } ! 2561: } ! 2562: return mr; ! 2563: } ! 2564: ! 2565: /* ! 2566: * Routine: ipc_kmsg_copyout ! 2567: * Purpose: ! 2568: * "Copy-out" port rights and out-of-line memory ! 2569: * in the message. ! 2570: * Conditions: ! 2571: * Nothing locked. ! 2572: * Returns: ! 2573: * MACH_MSG_SUCCESS Copied out all rights and memory. ! 2574: * MACH_RCV_INVALID_NOTIFY Bad notify port. ! 2575: * Rights and memory in the message are intact. ! 2576: * MACH_RCV_HEADER_ERROR + special bits ! 2577: * Rights and memory in the message are intact. ! 2578: * MACH_RCV_BODY_ERROR + special bits ! 2579: * The message header was successfully copied out. ! 2580: * As much of the body was handled as possible. ! 2581: */ ! 2582: ! 2583: mach_msg_return_t ! 2584: ipc_kmsg_copyout( ! 2585: ipc_kmsg_t kmsg, ! 2586: ipc_space_t space, ! 2587: vm_map_t map, ! 2588: mach_port_name_t notify, ! 2589: mach_msg_body_t *slist) ! 2590: { ! 2591: mach_msg_return_t mr; ! 2592: ! 2593: mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify); ! 2594: if (mr != MACH_MSG_SUCCESS) ! 2595: return mr; ! 2596: ! 2597: if (kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) { ! 2598: mr = ipc_kmsg_copyout_body(kmsg, space, map, slist); ! 2599: ! 2600: if (mr != MACH_MSG_SUCCESS) ! 2601: mr |= MACH_RCV_BODY_ERROR; ! 2602: } ! 2603: ! 2604: return mr; ! 2605: } ! 2606: ! 2607: /* ! 2608: * Routine: ipc_kmsg_copyout_pseudo ! 2609: * Purpose: ! 2610: * Does a pseudo-copyout of the message. ! 2611: * This is like a regular copyout, except ! 2612: * that the ports in the header are handled ! 2613: * as if they are in the body. They aren't reversed. ! 2614: * ! 2615: * The error codes are a combination of special bits. ! 2616: * The copyout proceeds despite errors. ! 2617: * Conditions: ! 2618: * Nothing locked. ! 2619: * Returns: ! 2620: * MACH_MSG_SUCCESS Successful copyout. ! 2621: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 2622: * MACH_MSG_VM_SPACE No room for memory in address space. ! 2623: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 2624: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 2625: */ ! 2626: ! 2627: mach_msg_return_t ! 2628: ipc_kmsg_copyout_pseudo( ! 2629: ipc_kmsg_t kmsg, ! 2630: ipc_space_t space, ! 2631: vm_map_t map, ! 2632: mach_msg_body_t *slist) ! 2633: { ! 2634: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 2635: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2636: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2637: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2638: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2639: mach_port_name_t dest_name, reply_name; ! 2640: mach_msg_return_t mr; ! 2641: ! 2642: assert(IO_VALID(dest)); ! 2643: ! 2644: mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) | ! 2645: ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name)); ! 2646: ! 2647: kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR; ! 2648: kmsg->ikm_header.msgh_remote_port = (ipc_port_t)dest_name; ! 2649: kmsg->ikm_header.msgh_local_port = (ipc_port_t)reply_name; ! 2650: ! 2651: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 2652: mr |= ipc_kmsg_copyout_body(kmsg, space, map, slist); ! 2653: } ! 2654: ! 2655: return mr; ! 2656: } ! 2657: ! 2658: /* ! 2659: * Routine: ipc_kmsg_copyout_dest ! 2660: * Purpose: ! 2661: * Copies out the destination port in the message. ! 2662: * Destroys all other rights and memory in the message. ! 2663: * Conditions: ! 2664: * Nothing locked. ! 2665: */ ! 2666: ! 2667: void ! 2668: ipc_kmsg_copyout_dest( ! 2669: ipc_kmsg_t kmsg, ! 2670: ipc_space_t space) ! 2671: { ! 2672: mach_msg_bits_t mbits; ! 2673: ipc_object_t dest; ! 2674: ipc_object_t reply; ! 2675: mach_msg_type_name_t dest_type; ! 2676: mach_msg_type_name_t reply_type; ! 2677: mach_port_name_t dest_name, reply_name; ! 2678: ! 2679: mbits = kmsg->ikm_header.msgh_bits; ! 2680: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2681: reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2682: dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2683: reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2684: ! 2685: assert(IO_VALID(dest)); ! 2686: ! 2687: io_lock(dest); ! 2688: if (io_active(dest)) { ! 2689: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 2690: /* dest is unlocked */ ! 2691: } else { ! 2692: io_release(dest); ! 2693: io_check_unlock(dest); ! 2694: dest_name = MACH_PORT_DEAD; ! 2695: } ! 2696: ! 2697: if (IO_VALID(reply)) { ! 2698: ipc_object_destroy(reply, reply_type); ! 2699: reply_name = MACH_PORT_NULL; ! 2700: } else ! 2701: reply_name = (mach_port_name_t) reply; ! 2702: ! 2703: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2704: MACH_MSGH_BITS(reply_type, dest_type)); ! 2705: kmsg->ikm_header.msgh_local_port = (ipc_port_t)dest_name; ! 2706: kmsg->ikm_header.msgh_remote_port = (ipc_port_t)reply_name; ! 2707: ! 2708: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 2709: mach_msg_body_t *body; ! 2710: ! 2711: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 2712: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count); ! 2713: } ! 2714: } ! 2715: ! 2716: /* ! 2717: * Routine: ipc_kmsg_check_scatter ! 2718: * Purpose: ! 2719: * Checks scatter and gather lists for consistency. ! 2720: * ! 2721: * Algorithm: ! 2722: * The gather is assumed valid since it has been copied in. ! 2723: * The scatter list has only been range checked. ! 2724: * Gather list descriptors are sequentially paired with scatter ! 2725: * list descriptors, with port descriptors in either list ignored. ! 2726: * Descriptors are consistent if the type fileds match and size ! 2727: * of the scatter descriptor is less than or equal to the ! 2728: * size of the gather descriptor. A MACH_MSG_ALLOCATE copy ! 2729: * strategy in a scatter descriptor matches any size in the ! 2730: * corresponding gather descriptor assuming they are the same type. ! 2731: * Either list may be larger than the other. During the ! 2732: * subsequent copy out, excess scatter descriptors are ignored ! 2733: * and excess gather descriptors default to dynamic allocation. ! 2734: * ! 2735: * In the case of a size error, a new scatter list is formed ! 2736: * from the gather list copying only the size and type fields. ! 2737: * ! 2738: * Conditions: ! 2739: * Nothing locked. ! 2740: * Returns: ! 2741: * MACH_MSG_SUCCESS Lists are consistent ! 2742: * MACH_RCV_INVALID_TYPE Scatter type does not match ! 2743: * gather type ! 2744: * MACH_RCV_SCATTER_SMALL Scatter size less than gather ! 2745: * size ! 2746: */ ! 2747: ! 2748: mach_msg_return_t ! 2749: ipc_kmsg_check_scatter( ! 2750: ipc_kmsg_t kmsg, ! 2751: mach_msg_option_t option, ! 2752: mach_msg_body_t **slistp, ! 2753: mach_msg_size_t *sizep) ! 2754: { ! 2755: mach_msg_body_t *body; ! 2756: mach_msg_descriptor_t *gstart, *gend; ! 2757: mach_msg_descriptor_t *sstart, *send; ! 2758: mach_msg_return_t mr = MACH_MSG_SUCCESS; ! 2759: ! 2760: assert(*slistp != MACH_MSG_BODY_NULL); ! 2761: assert(*sizep != 0); ! 2762: ! 2763: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 2764: gstart = (mach_msg_descriptor_t *) (body + 1); ! 2765: gend = gstart + body->msgh_descriptor_count; ! 2766: ! 2767: sstart = (mach_msg_descriptor_t *) (*slistp + 1); ! 2768: send = sstart + (*slistp)->msgh_descriptor_count; ! 2769: ! 2770: while (gstart < gend) { ! 2771: mach_msg_descriptor_type_t g_type; ! 2772: ! 2773: /* ! 2774: * Skip port descriptors in gather list. ! 2775: */ ! 2776: g_type = gstart->type.type; ! 2777: ! 2778: if (g_type != MACH_MSG_PORT_DESCRIPTOR) { ! 2779: ! 2780: /* ! 2781: * A scatter list with a 0 descriptor count is treated as an ! 2782: * automatic size mismatch. ! 2783: */ ! 2784: if ((*slistp)->msgh_descriptor_count == 0) { ! 2785: return(MACH_RCV_SCATTER_SMALL); ! 2786: } ! 2787: ! 2788: /* ! 2789: * Skip port descriptors in scatter list. ! 2790: */ ! 2791: while (sstart < send) { ! 2792: if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR) ! 2793: break; ! 2794: sstart++; ! 2795: } ! 2796: ! 2797: /* ! 2798: * No more scatter descriptors, we're done ! 2799: */ ! 2800: if (sstart >= send) { ! 2801: break; ! 2802: } ! 2803: ! 2804: /* ! 2805: * Check type, copy and size fields ! 2806: */ ! 2807: if (g_type == MACH_MSG_OOL_DESCRIPTOR || ! 2808: g_type == MACH_MSG_OOL_VOLATILE_DESCRIPTOR) { ! 2809: if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR && ! 2810: sstart->type.type != MACH_MSG_OOL_VOLATILE_DESCRIPTOR) { ! 2811: return(MACH_RCV_INVALID_TYPE); ! 2812: } ! 2813: if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE && ! 2814: gstart->out_of_line.size > sstart->out_of_line.size) { ! 2815: return(MACH_RCV_SCATTER_SMALL); ! 2816: } ! 2817: } ! 2818: else { ! 2819: if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR) { ! 2820: return(MACH_RCV_INVALID_TYPE); ! 2821: } ! 2822: if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE && ! 2823: gstart->ool_ports.count > sstart->ool_ports.count) { ! 2824: return(MACH_RCV_SCATTER_SMALL); ! 2825: } ! 2826: } ! 2827: sstart++; ! 2828: } ! 2829: gstart++; ! 2830: } ! 2831: ! 2832: return(mr); ! 2833: } ! 2834: ! 2835: ! 2836: /* ! 2837: * We keep a per-processor cache of kernel message buffers. ! 2838: * The cache saves the overhead/locking of using kalloc/kfree. ! 2839: * The per-processor cache seems to miss less than a per-thread cache, ! 2840: * and it also uses less memory. Access to the cache doesn't ! 2841: * require locking. ! 2842: */ ! 2843: #define IKM_STASH 16 /* # of cache entries per cpu */ ! 2844: ipc_kmsg_t ipc_kmsg_cache[ NCPUS ][ IKM_STASH ]; ! 2845: unsigned int ipc_kmsg_cache_avail[NCPUS]; ! 2846: counter(unsigned int c_ipc_kmsg_cache_tries = 0;) ! 2847: counter(unsigned int c_ipc_kmsg_cache_misses = 0;) ! 2848: ! 2849: /* ! 2850: * Routine: ikm_cache_get ! 2851: * Purpose: Attempt to allocate from the per-cpu IKM cache. ! 2852: * Conditions: Nothing locked. ! 2853: * ! 2854: * If the IKM cache for the current cpu is not empty, this routine ! 2855: * will return the address of the block, nulling out the cache. ! 2856: * TRUE is returned for success, FALSE for failure. ! 2857: * Preemption must be disabled while in here. ! 2858: */ ! 2859: ! 2860: boolean_t ! 2861: ikm_cache_get( ! 2862: ipc_kmsg_t * kmsg) ! 2863: { ! 2864: register unsigned int cpu, i; ! 2865: ! 2866: counter(++c_ipc_kmsg_cache_tries); ! 2867: disable_preemption(); ! 2868: cpu = cpu_number(); ! 2869: ! 2870: if (ipc_kmsg_cache_avail[cpu]) { ! 2871: for (i = 0; i < IKM_STASH; i++) { ! 2872: if ( *kmsg = ipc_kmsg_cache[cpu][i] ) { ! 2873: ipc_kmsg_cache[cpu][i] = IKM_NULL; ! 2874: ipc_kmsg_cache_avail[cpu]--; ! 2875: enable_preemption(); ! 2876: return(TRUE); ! 2877: } ! 2878: } ! 2879: } ! 2880: ! 2881: enable_preemption(); ! 2882: counter(++c_ipc_kmsg_cache_misses); ! 2883: return(FALSE); ! 2884: } ! 2885: ! 2886: /* ! 2887: * Routine: ikm_cache_put ! 2888: * Purpose: Attempt to free a block to the per-cpu IKM cache. ! 2889: * Conditions: Nothing locked. ! 2890: * ! 2891: * If the IKM cache for the current cpu is empty, this routine ! 2892: * will store its argument into the cache. ! 2893: * TRUE is returned for success, FALSE for failure. ! 2894: * Preemption must be disabled while in here. ! 2895: */ ! 2896: ! 2897: boolean_t ! 2898: ikm_cache_put( ! 2899: ipc_kmsg_t kmsg) ! 2900: { ! 2901: unsigned int cpu, i; ! 2902: ! 2903: disable_preemption(); ! 2904: cpu = cpu_number(); ! 2905: ! 2906: if (ipc_kmsg_cache_avail[cpu] < IKM_STASH) { ! 2907: for (i = 0; i < IKM_STASH; i++) { ! 2908: if (ipc_kmsg_cache[cpu][i] == IKM_NULL) { ! 2909: ipc_kmsg_cache[cpu][i] = kmsg; ! 2910: ipc_kmsg_cache_avail[cpu]++; ! 2911: enable_preemption(); ! 2912: return(TRUE); ! 2913: } ! 2914: } ! 2915: } ! 2916: ! 2917: enable_preemption(); ! 2918: return(FALSE); ! 2919: } ! 2920: ! 2921: ! 2922: void ! 2923: ikm_cache_init() ! 2924: { ! 2925: unsigned int cpu, i; ! 2926: ! 2927: for (cpu = 0; cpu < NCPUS; ++cpu) { ! 2928: ipc_kmsg_cache_avail[cpu] = 0; ! 2929: for (i = 0; i < IKM_STASH; ++i) ! 2930: ipc_kmsg_cache[cpu][i] = IKM_NULL; ! 2931: } ! 2932: } ! 2933: ! 2934: ! 2935: /* ! 2936: * Routine: ipc_kmsg_copyout_to_kernel ! 2937: * Purpose: ! 2938: * Copies out the destination and reply ports in the message. ! 2939: * Leaves all other rights and memory in the message alone. ! 2940: * Conditions: ! 2941: * Nothing locked. ! 2942: * ! 2943: * Derived from ipc_kmsg_copyout_dest. ! 2944: * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest). ! 2945: * We really do want to save rights and memory. ! 2946: */ ! 2947: ! 2948: void ! 2949: ipc_kmsg_copyout_to_kernel( ! 2950: ipc_kmsg_t kmsg, ! 2951: ipc_space_t space) ! 2952: { ! 2953: ipc_object_t dest; ! 2954: ipc_object_t reply; ! 2955: mach_msg_type_name_t dest_type; ! 2956: mach_msg_type_name_t reply_type; ! 2957: mach_port_name_t dest_name, reply_name; ! 2958: ! 2959: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2960: reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2961: dest_type = MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits); ! 2962: reply_type = MACH_MSGH_BITS_LOCAL(kmsg->ikm_header.msgh_bits); ! 2963: ! 2964: assert(IO_VALID(dest)); ! 2965: ! 2966: io_lock(dest); ! 2967: if (io_active(dest)) { ! 2968: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 2969: /* dest is unlocked */ ! 2970: } else { ! 2971: io_release(dest); ! 2972: io_check_unlock(dest); ! 2973: dest_name = MACH_PORT_DEAD; ! 2974: } ! 2975: ! 2976: reply_name = (mach_port_name_t) reply; ! 2977: ! 2978: kmsg->ikm_header.msgh_bits = ! 2979: (MACH_MSGH_BITS_OTHER(kmsg->ikm_header.msgh_bits) | ! 2980: MACH_MSGH_BITS(reply_type, dest_type)); ! 2981: kmsg->ikm_header.msgh_local_port = (ipc_port_t)dest_name; ! 2982: kmsg->ikm_header.msgh_remote_port = (ipc_port_t)reply_name; ! 2983: } ! 2984: ! 2985: #include <mach_kdb.h> ! 2986: #if MACH_KDB ! 2987: ! 2988: #include <ddb/db_output.h> ! 2989: #include <ipc/ipc_print.h> ! 2990: /* ! 2991: * Forward declarations ! 2992: */ ! 2993: void ipc_msg_print_untyped( ! 2994: mach_msg_body_t *body); ! 2995: ! 2996: char * ipc_type_name( ! 2997: int type_name, ! 2998: boolean_t received); ! 2999: ! 3000: void ipc_print_type_name( ! 3001: int type_name); ! 3002: ! 3003: char * ! 3004: msgh_bit_decode( ! 3005: mach_msg_bits_t bit); ! 3006: ! 3007: char * ! 3008: mm_copy_options_string( ! 3009: mach_msg_copy_options_t option); ! 3010: ! 3011: void db_print_msg_uid(mach_msg_header_t *); ! 3012: ! 3013: ! 3014: char * ! 3015: ipc_type_name( ! 3016: int type_name, ! 3017: boolean_t received) ! 3018: { ! 3019: switch (type_name) { ! 3020: case MACH_MSG_TYPE_PORT_NAME: ! 3021: return "port_name"; ! 3022: ! 3023: case MACH_MSG_TYPE_MOVE_RECEIVE: ! 3024: if (received) { ! 3025: return "port_receive"; ! 3026: } else { ! 3027: return "move_receive"; ! 3028: } ! 3029: ! 3030: case MACH_MSG_TYPE_MOVE_SEND: ! 3031: if (received) { ! 3032: return "port_send"; ! 3033: } else { ! 3034: return "move_send"; ! 3035: } ! 3036: ! 3037: case MACH_MSG_TYPE_MOVE_SEND_ONCE: ! 3038: if (received) { ! 3039: return "port_send_once"; ! 3040: } else { ! 3041: return "move_send_once"; ! 3042: } ! 3043: ! 3044: case MACH_MSG_TYPE_COPY_SEND: ! 3045: return "copy_send"; ! 3046: ! 3047: case MACH_MSG_TYPE_MAKE_SEND: ! 3048: return "make_send"; ! 3049: ! 3050: case MACH_MSG_TYPE_MAKE_SEND_ONCE: ! 3051: return "make_send_once"; ! 3052: ! 3053: default: ! 3054: return (char *) 0; ! 3055: } ! 3056: } ! 3057: ! 3058: void ! 3059: ipc_print_type_name( ! 3060: int type_name) ! 3061: { ! 3062: char *name = ipc_type_name(type_name, TRUE); ! 3063: if (name) { ! 3064: printf("%s", name); ! 3065: } else { ! 3066: printf("type%d", type_name); ! 3067: } ! 3068: } ! 3069: ! 3070: /* ! 3071: * ipc_kmsg_print [ debug ] ! 3072: */ ! 3073: void ! 3074: ipc_kmsg_print( ! 3075: ipc_kmsg_t kmsg) ! 3076: { ! 3077: iprintf("kmsg=0x%x\n", kmsg); ! 3078: iprintf("ikm_next=0x%x, prev=0x%x, size=%d", ! 3079: kmsg->ikm_next, ! 3080: kmsg->ikm_prev, ! 3081: kmsg->ikm_size); ! 3082: printf("\n"); ! 3083: ipc_msg_print(&kmsg->ikm_header); ! 3084: } ! 3085: ! 3086: char * ! 3087: msgh_bit_decode( ! 3088: mach_msg_bits_t bit) ! 3089: { ! 3090: switch (bit) { ! 3091: case MACH_MSGH_BITS_COMPLEX: return "complex"; ! 3092: case MACH_MSGH_BITS_CIRCULAR: return "circular"; ! 3093: case MACH_MSGH_BITS_RTALLOC: return "rtmalloc"; ! 3094: default: return (char *) 0; ! 3095: } ! 3096: } ! 3097: ! 3098: /* ! 3099: * ipc_msg_print [ debug ] ! 3100: */ ! 3101: void ! 3102: ipc_msg_print( ! 3103: mach_msg_header_t *msgh) ! 3104: { ! 3105: mach_msg_bits_t mbits; ! 3106: unsigned int bit, i; ! 3107: char *bit_name; ! 3108: int needs_comma; ! 3109: ! 3110: mbits = msgh->msgh_bits; ! 3111: iprintf("msgh_bits=0x%x: l=0x%x,r=0x%x\n", ! 3112: mbits, ! 3113: MACH_MSGH_BITS_LOCAL(msgh->msgh_bits), ! 3114: MACH_MSGH_BITS_REMOTE(msgh->msgh_bits)); ! 3115: ! 3116: mbits = MACH_MSGH_BITS_OTHER(mbits) & ~MACH_MSGH_BITS_UNUSED; ! 3117: db_indent += 2; ! 3118: if (mbits) ! 3119: iprintf("decoded bits: "); ! 3120: needs_comma = 0; ! 3121: for (i = 0, bit = 1; i < sizeof(mbits) * 8; ++i, bit <<= 1) { ! 3122: if ((mbits & bit) == 0) ! 3123: continue; ! 3124: bit_name = msgh_bit_decode((mach_msg_bits_t)bit); ! 3125: if (bit_name) ! 3126: printf("%s%s", needs_comma ? "," : "", bit_name); ! 3127: else ! 3128: printf("%sunknown(0x%x),", needs_comma ? "," : "", bit); ! 3129: ++needs_comma; ! 3130: } ! 3131: if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) { ! 3132: printf("%sunused=0x%x,", needs_comma ? "," : "", ! 3133: msgh->msgh_bits & MACH_MSGH_BITS_UNUSED); ! 3134: } ! 3135: printf("\n"); ! 3136: db_indent -= 2; ! 3137: ! 3138: needs_comma = 1; ! 3139: if (msgh->msgh_remote_port) { ! 3140: iprintf("remote=0x%x(", msgh->msgh_remote_port); ! 3141: ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits)); ! 3142: printf(")"); ! 3143: } else { ! 3144: iprintf("remote=null"); ! 3145: } ! 3146: ! 3147: if (msgh->msgh_local_port) { ! 3148: printf("%slocal=0x%x(", needs_comma ? "," : "", ! 3149: msgh->msgh_local_port); ! 3150: ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits)); ! 3151: printf(")\n"); ! 3152: } else { ! 3153: printf("local=null\n"); ! 3154: } ! 3155: ! 3156: iprintf("msgh_id=%d, size=%d\n", ! 3157: msgh->msgh_id, ! 3158: msgh->msgh_size); ! 3159: ! 3160: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 3161: ipc_msg_print_untyped((mach_msg_body_t *) (msgh + 1)); ! 3162: } ! 3163: } ! 3164: ! 3165: ! 3166: char * ! 3167: mm_copy_options_string( ! 3168: mach_msg_copy_options_t option) ! 3169: { ! 3170: char *name; ! 3171: ! 3172: switch (option) { ! 3173: case MACH_MSG_PHYSICAL_COPY: ! 3174: name = "PHYSICAL"; ! 3175: break; ! 3176: case MACH_MSG_VIRTUAL_COPY: ! 3177: name = "VIRTUAL"; ! 3178: break; ! 3179: case MACH_MSG_OVERWRITE: ! 3180: name = "OVERWRITE"; ! 3181: break; ! 3182: case MACH_MSG_ALLOCATE: ! 3183: name = "ALLOCATE"; ! 3184: break; ! 3185: case MACH_MSG_KALLOC_COPY_T: ! 3186: name = "KALLOC_COPY_T"; ! 3187: break; ! 3188: case MACH_MSG_PAGE_LIST_COPY_T: ! 3189: name = "PAGE_LIST_COPY_T"; ! 3190: break; ! 3191: default: ! 3192: name = "unknown"; ! 3193: break; ! 3194: } ! 3195: return name; ! 3196: } ! 3197: ! 3198: void ! 3199: ipc_msg_print_untyped( ! 3200: mach_msg_body_t *body) ! 3201: { ! 3202: mach_msg_descriptor_t *saddr, *send; ! 3203: mach_msg_descriptor_type_t type; ! 3204: ! 3205: iprintf("%d descriptors %d: \n", body->msgh_descriptor_count); ! 3206: ! 3207: saddr = (mach_msg_descriptor_t *) (body + 1); ! 3208: send = saddr + body->msgh_descriptor_count; ! 3209: ! 3210: for ( ; saddr < send; saddr++ ) { ! 3211: ! 3212: type = saddr->type.type; ! 3213: ! 3214: switch (type) { ! 3215: ! 3216: case MACH_MSG_PORT_DESCRIPTOR: { ! 3217: mach_msg_port_descriptor_t *dsc; ! 3218: ! 3219: dsc = &saddr->port; ! 3220: iprintf("-- PORT name = 0x%x disp = ", dsc->name); ! 3221: ipc_print_type_name(dsc->disposition); ! 3222: printf("\n"); ! 3223: break; ! 3224: } ! 3225: case MACH_MSG_OOL_VOLATILE_DESCRIPTOR: ! 3226: case MACH_MSG_OOL_DESCRIPTOR: { ! 3227: mach_msg_ool_descriptor_t *dsc; ! 3228: ! 3229: dsc = &saddr->out_of_line; ! 3230: iprintf("-- OOL%s addr = 0x%x size = 0x%x copy = %s %s\n", ! 3231: type == MACH_MSG_OOL_DESCRIPTOR ? "" : " VOLATILE", ! 3232: dsc->address, dsc->size, ! 3233: mm_copy_options_string(dsc->copy), ! 3234: dsc->deallocate ? "DEALLOC" : ""); ! 3235: break; ! 3236: } ! 3237: case MACH_MSG_OOL_PORTS_DESCRIPTOR : { ! 3238: mach_msg_ool_ports_descriptor_t *dsc; ! 3239: ! 3240: dsc = &saddr->ool_ports; ! 3241: ! 3242: iprintf("-- OOL_PORTS addr = 0x%x count = 0x%x ", ! 3243: dsc->address, dsc->count); ! 3244: printf("disp = "); ! 3245: ipc_print_type_name(dsc->disposition); ! 3246: printf(" copy = %s %s\n", ! 3247: mm_copy_options_string(dsc->copy), ! 3248: dsc->deallocate ? "DEALLOC" : ""); ! 3249: break; ! 3250: } ! 3251: ! 3252: default: { ! 3253: iprintf("-- UNKNOWN DESCRIPTOR 0x%x\n", type); ! 3254: break; ! 3255: } ! 3256: } ! 3257: } ! 3258: } ! 3259: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.