1/* 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/* 29 * @OSF_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 */ 58 59#include <mach/boolean.h> 60#include <mach/port.h> 61#include <mach/mig.h> 62#include <mach/mig_errors.h> 63#include <mach/mach_types.h> 64#include <mach/mach_traps.h> 65 66#include <kern/ipc_tt.h> 67#include <kern/ipc_mig.h> 68#include <kern/kalloc.h> 69#include <kern/task.h> 70#include <kern/thread.h> 71#include <kern/ipc_kobject.h> 72#include <kern/misc_protos.h> 73 74#include <ipc/port.h> 75#include <ipc/ipc_kmsg.h> 76#include <ipc/ipc_entry.h> 77#include <ipc/ipc_object.h> 78#include <ipc/ipc_mqueue.h> 79#include <ipc/ipc_space.h> 80#include <ipc/ipc_port.h> 81#include <ipc/ipc_pset.h> 82#include <ipc/ipc_notify.h> 83#include <vm/vm_map.h> 84 85#include <libkern/OSAtomic.h> 86 87/* 88 * Routine: mach_msg_send_from_kernel 89 * Purpose: 90 * Send a message from the kernel. 91 * 92 * This is used by the client side of KernelUser interfaces 93 * to implement SimpleRoutines. Currently, this includes 94 * memory_object messages. 95 * Conditions: 96 * Nothing locked. 97 * Returns: 98 * MACH_MSG_SUCCESS Sent the message. 99 * MACH_SEND_INVALID_DEST Bad destination port. 100 * MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer 101 * or destination is above kernel limit 102 */ 103 104#if IKM_SUPPORT_LEGACY 105 106#undef mach_msg_send_from_kernel 107mach_msg_return_t mach_msg_send_from_kernel( 108 mach_msg_header_t *msg, 109 mach_msg_size_t send_size); 110 111mach_msg_return_t 112mach_msg_send_from_kernel( 113 mach_msg_header_t *msg, 114 mach_msg_size_t send_size) 115{ 116 ipc_kmsg_t kmsg; 117 mach_msg_return_t mr; 118 119 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 120 if (mr != MACH_MSG_SUCCESS) 121 return mr; 122 123 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 124 if (mr != MACH_MSG_SUCCESS) { 125 ipc_kmsg_free(kmsg); 126 return mr; 127 } 128 129 mr = ipc_kmsg_send(kmsg, 130 MACH_SEND_KERNEL_DEFAULT, 131 MACH_MSG_TIMEOUT_NONE); 132 if (mr != MACH_MSG_SUCCESS) { 133 ipc_kmsg_destroy(kmsg); 134 } 135 136 return mr; 137} 138 139#endif /* IKM_SUPPORT_LEGACY */ 140 141mach_msg_return_t 142mach_msg_send_from_kernel_proper( 143 mach_msg_header_t *msg, 144 mach_msg_size_t send_size) 145{ 146 ipc_kmsg_t kmsg; 147 mach_msg_return_t mr; 148 149 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 150 if (mr != MACH_MSG_SUCCESS) 151 return mr; 152 153 mr = ipc_kmsg_copyin_from_kernel(kmsg); 154 if (mr != MACH_MSG_SUCCESS) { 155 ipc_kmsg_free(kmsg); 156 return mr; 157 } 158 159 mr = ipc_kmsg_send(kmsg, 160 MACH_SEND_KERNEL_DEFAULT, 161 MACH_MSG_TIMEOUT_NONE); 162 if (mr != MACH_MSG_SUCCESS) { 163 ipc_kmsg_destroy(kmsg); 164 } 165 166 return mr; 167} 168 169mach_msg_return_t 170mach_msg_send_from_kernel_with_options( 171 mach_msg_header_t *msg, 172 mach_msg_size_t send_size, 173 mach_msg_option_t option, 174 mach_msg_timeout_t timeout_val) 175{ 176 ipc_kmsg_t kmsg; 177 mach_msg_return_t mr; 178 179 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 180 if (mr != MACH_MSG_SUCCESS) 181 return mr; 182 183 mr = ipc_kmsg_copyin_from_kernel(kmsg); 184 if (mr != MACH_MSG_SUCCESS) { 185 ipc_kmsg_free(kmsg); 186 return mr; 187 } 188 189#if 11938665 190 /* 191 * Until we are sure of its effects, we are disabling 192 * importance donation from the kernel-side of user 193 * threads in importance-donating tasks - unless the 194 * option to force importance donation is passed in. 195 */ 196 if ((option & MACH_SEND_IMPORTANCE) == 0) 197 option |= MACH_SEND_NOIMPORTANCE; 198#endif 199 mr = ipc_kmsg_send(kmsg, option, timeout_val); 200 201 if (mr != MACH_MSG_SUCCESS) { 202 ipc_kmsg_destroy(kmsg); 203 } 204 205 return mr; 206} 207 208 209#if IKM_SUPPORT_LEGACY 210 211mach_msg_return_t 212mach_msg_send_from_kernel_with_options_legacy( 213 mach_msg_header_t *msg, 214 mach_msg_size_t send_size, 215 mach_msg_option_t option, 216 mach_msg_timeout_t timeout_val) 217{ 218 ipc_kmsg_t kmsg; 219 mach_msg_return_t mr; 220 221 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 222 if (mr != MACH_MSG_SUCCESS) 223 return mr; 224 225 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 226 if (mr != MACH_MSG_SUCCESS) { 227 ipc_kmsg_free(kmsg); 228 return mr; 229 } 230 231#if 11938665 232 /* 233 * Until we are sure of its effects, we are disabling 234 * importance donation from the kernel-side of user 235 * threads in importance-donating tasks. 236 */ 237 option |= MACH_SEND_NOIMPORTANCE; 238#endif 239 mr = ipc_kmsg_send(kmsg, option, timeout_val); 240 241 if (mr != MACH_MSG_SUCCESS) { 242 ipc_kmsg_destroy(kmsg); 243 } 244 245 return mr; 246} 247 248#endif /* IKM_SUPPORT_LEGACY */ 249 250/* 251 * Routine: mach_msg_rpc_from_kernel 252 * Purpose: 253 * Send a message from the kernel and receive a reply. 254 * Uses ith_rpc_reply for the reply port. 255 * 256 * This is used by the client side of KernelUser interfaces 257 * to implement Routines. 258 * Conditions: 259 * Nothing locked. 260 * Returns: 261 * MACH_MSG_SUCCESS Sent the message. 262 * MACH_RCV_PORT_DIED The reply port was deallocated. 263 */ 264 265mach_msg_return_t mach_msg_rpc_from_kernel_body(mach_msg_header_t *msg, 266 mach_msg_size_t send_size, mach_msg_size_t rcv_size, boolean_t legacy); 267 268#if IKM_SUPPORT_LEGACY 269 270#undef mach_msg_rpc_from_kernel 271mach_msg_return_t 272mach_msg_rpc_from_kernel( 273 mach_msg_header_t *msg, 274 mach_msg_size_t send_size, 275 mach_msg_size_t rcv_size); 276 277mach_msg_return_t 278mach_msg_rpc_from_kernel( 279 mach_msg_header_t *msg, 280 mach_msg_size_t send_size, 281 mach_msg_size_t rcv_size) 282{ 283 return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, TRUE); 284} 285 286#endif /* IKM_SUPPORT_LEGACY */ 287 288mach_msg_return_t 289mach_msg_rpc_from_kernel_proper( 290 mach_msg_header_t *msg, 291 mach_msg_size_t send_size, 292 mach_msg_size_t rcv_size) 293{ 294 return mach_msg_rpc_from_kernel_body(msg, send_size, rcv_size, FALSE); 295} 296 297mach_msg_return_t 298mach_msg_rpc_from_kernel_body( 299 mach_msg_header_t *msg, 300 mach_msg_size_t send_size, 301 mach_msg_size_t rcv_size, 302#if !IKM_SUPPORT_LEGACY 303 __unused 304#endif 305 boolean_t legacy) 306{ 307 thread_t self = current_thread(); 308 ipc_port_t reply; 309 ipc_kmsg_t kmsg; 310 mach_port_seqno_t seqno; 311 mach_msg_return_t mr; 312 313 assert(msg->msgh_local_port == MACH_PORT_NULL); 314 315 mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg); 316 if (mr != MACH_MSG_SUCCESS) 317 return mr; 318 319 reply = self->ith_rpc_reply; 320 if (reply == IP_NULL) { 321 reply = ipc_port_alloc_reply(); 322 if ((reply == IP_NULL) || 323 (self->ith_rpc_reply != IP_NULL)) 324 panic("mach_msg_rpc_from_kernel"); 325 self->ith_rpc_reply = reply; 326 } 327 328 /* insert send-once right for the reply port */ 329 kmsg->ikm_header->msgh_local_port = reply; 330 kmsg->ikm_header->msgh_bits |= 331 MACH_MSGH_BITS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE); 332 333#if IKM_SUPPORT_LEGACY 334 if(legacy) 335 mr = ipc_kmsg_copyin_from_kernel_legacy(kmsg); 336 else 337 mr = ipc_kmsg_copyin_from_kernel(kmsg); 338#else 339 mr = ipc_kmsg_copyin_from_kernel(kmsg); 340#endif 341 if (mr != MACH_MSG_SUCCESS) { 342 ipc_kmsg_free(kmsg); 343 return mr; 344 } 345 mr = ipc_kmsg_send(kmsg, 346 MACH_SEND_KERNEL_DEFAULT, 347 MACH_MSG_TIMEOUT_NONE); 348 if (mr != MACH_MSG_SUCCESS) { 349 ipc_kmsg_destroy(kmsg); 350 return mr; 351 } 352 353 for (;;) { 354 ipc_mqueue_t mqueue; 355 356 assert(reply->ip_pset_count == 0); 357 assert(ip_active(reply)); 358 359 /* JMM - why this check? */ 360 if (!self->active) { 361 ipc_port_dealloc_reply(reply); 362 self->ith_rpc_reply = IP_NULL; 363 return MACH_RCV_INTERRUPTED; 364 } 365 366 self->ith_continuation = (void (*)(mach_msg_return_t))0; 367 368 mqueue = &reply->ip_messages; 369 ipc_mqueue_receive(mqueue, 370 MACH_MSG_OPTION_NONE, 371 MACH_MSG_SIZE_MAX, 372 MACH_MSG_TIMEOUT_NONE, 373 THREAD_INTERRUPTIBLE); 374 375 mr = self->ith_state; 376 kmsg = self->ith_kmsg; 377 seqno = self->ith_seqno; 378 379 if (mr == MACH_MSG_SUCCESS) 380 { 381 break; 382 } 383 384 assert(mr == MACH_RCV_INTERRUPTED); 385 386 assert(reply == self->ith_rpc_reply); 387 388 if (self->handlers) { 389 ipc_port_dealloc_reply(reply); 390 self->ith_rpc_reply = IP_NULL; 391 return(mr); 392 } 393 } 394 395 /* 396 * Check to see how much of the message/trailer can be received. 397 * We chose the maximum trailer that will fit, since we don't 398 * have options telling us which trailer elements the caller needed. 399 */ 400 if (rcv_size >= kmsg->ikm_header->msgh_size) { 401 mach_msg_format_0_trailer_t *trailer = (mach_msg_format_0_trailer_t *) 402 ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size); 403 404 if (rcv_size >= kmsg->ikm_header->msgh_size + MAX_TRAILER_SIZE) { 405 /* Enough room for a maximum trailer */ 406 trailer->msgh_trailer_size = MAX_TRAILER_SIZE; 407 } 408 else if (rcv_size < kmsg->ikm_header->msgh_size + 409 trailer->msgh_trailer_size) { 410 /* no room for even the basic (default) trailer */ 411 trailer->msgh_trailer_size = 0; 412 } 413 assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0); 414 rcv_size = kmsg->ikm_header->msgh_size + trailer->msgh_trailer_size; 415 mr = MACH_MSG_SUCCESS; 416 } else { 417 mr = MACH_RCV_TOO_LARGE; 418 } 419 420 421 /* 422 * We want to preserve rights and memory in reply! 423 * We don't have to put them anywhere; just leave them 424 * as they are. 425 */ 426#if IKM_SUPPORT_LEGACY 427 if(legacy) 428 ipc_kmsg_copyout_to_kernel_legacy(kmsg, ipc_space_reply); 429 else 430 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); 431#else 432 ipc_kmsg_copyout_to_kernel(kmsg, ipc_space_reply); 433#endif 434 ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size); 435 return mr; 436} 437 438 439/************** These Calls are set up for kernel-loaded tasks/threads **************/ 440 441/* 442 * Routine: mach_msg_overwrite 443 * Purpose: 444 * Like mach_msg_overwrite_trap except that message buffers 445 * live in kernel space. Doesn't handle any options. 446 * 447 * This is used by in-kernel server threads to make 448 * kernel calls, to receive request messages, and 449 * to send reply messages. 450 * Conditions: 451 * Nothing locked. 452 * Returns: 453 */ 454 455mach_msg_return_t 456mach_msg_overwrite( 457 mach_msg_header_t *msg, 458 mach_msg_option_t option, 459 mach_msg_size_t send_size, 460 mach_msg_size_t rcv_size, 461 mach_port_name_t rcv_name, 462 __unused mach_msg_timeout_t msg_timeout, 463 __unused mach_port_name_t notify, 464 __unused mach_msg_header_t *rcv_msg, 465 __unused mach_msg_size_t rcv_msg_size) 466{ 467 ipc_space_t space = current_space(); 468 vm_map_t map = current_map(); 469 ipc_kmsg_t kmsg; 470 mach_port_seqno_t seqno; 471 mach_msg_return_t mr; 472 mach_msg_trailer_size_t trailer_size; 473 474 if (option & MACH_SEND_MSG) { 475 mach_msg_size_t msg_and_trailer_size; 476 mach_msg_max_trailer_t *max_trailer; 477 478 if ((send_size < sizeof(mach_msg_header_t)) || (send_size & 3)) 479 return MACH_SEND_MSG_TOO_SMALL; 480 481 if (send_size > MACH_MSG_SIZE_MAX - MAX_TRAILER_SIZE) 482 return MACH_SEND_TOO_LARGE; 483 484 msg_and_trailer_size = send_size + MAX_TRAILER_SIZE; 485 kmsg = ipc_kmsg_alloc(msg_and_trailer_size); 486 487 if (kmsg == IKM_NULL) 488 return MACH_SEND_NO_BUFFER; 489 490 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, send_size); 491 492 kmsg->ikm_header->msgh_size = send_size; 493 494 /* 495 * Reserve for the trailer the largest space (MAX_TRAILER_SIZE) 496 * However, the internal size field of the trailer (msgh_trailer_size) 497 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize 498 * the cases where no implicit data is requested. 499 */ 500 max_trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + send_size); 501 max_trailer->msgh_sender = current_thread()->task->sec_token; 502 max_trailer->msgh_audit = current_thread()->task->audit_token; 503 max_trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0; 504 max_trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE; 505 506 mr = ipc_kmsg_copyin(kmsg, space, map, &option); 507 508 if (mr != MACH_MSG_SUCCESS) { 509 ipc_kmsg_free(kmsg); 510 return mr; 511 } 512 513 do { 514 mr = ipc_kmsg_send(kmsg, MACH_MSG_OPTION_NONE, MACH_MSG_TIMEOUT_NONE); 515 } while (mr == MACH_SEND_INTERRUPTED); 516 517 assert(mr == MACH_MSG_SUCCESS); 518 } 519 520 if (option & MACH_RCV_MSG) { 521 thread_t self = current_thread(); 522 523 do { 524 ipc_object_t object; 525 ipc_mqueue_t mqueue; 526 527 mr = ipc_mqueue_copyin(space, rcv_name, 528 &mqueue, &object); 529 if (mr != MACH_MSG_SUCCESS) 530 return mr; 531 /* hold ref for object */ 532 533 self->ith_continuation = (void (*)(mach_msg_return_t))0; 534 ipc_mqueue_receive(mqueue, 535 MACH_MSG_OPTION_NONE, 536 MACH_MSG_SIZE_MAX, 537 MACH_MSG_TIMEOUT_NONE, 538 THREAD_ABORTSAFE); 539 mr = self->ith_state; 540 kmsg = self->ith_kmsg; 541 seqno = self->ith_seqno; 542 543 io_release(object); 544 545 } while (mr == MACH_RCV_INTERRUPTED); 546 if (mr != MACH_MSG_SUCCESS) 547 return mr; 548 549 550 trailer_size = ipc_kmsg_add_trailer(kmsg, space, option, current_thread(), seqno, TRUE, 551 kmsg->ikm_header->msgh_remote_port->ip_context); 552 553 if (rcv_size < (kmsg->ikm_header->msgh_size + trailer_size)) { 554 ipc_kmsg_copyout_dest(kmsg, space); 555 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 556 ipc_kmsg_free(kmsg); 557 return MACH_RCV_TOO_LARGE; 558 } 559 560 mr = ipc_kmsg_copyout(kmsg, space, map, MACH_MSG_BODY_NULL); 561 if (mr != MACH_MSG_SUCCESS) { 562 if ((mr &~ MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) { 563 ipc_kmsg_put_to_kernel(msg, kmsg, 564 kmsg->ikm_header->msgh_size + trailer_size); 565 } else { 566 ipc_kmsg_copyout_dest(kmsg, space); 567 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, sizeof *msg); 568 ipc_kmsg_free(kmsg); 569 } 570 571 return mr; 572 } 573 574 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, 575 kmsg->ikm_header->msgh_size + trailer_size); 576 ipc_kmsg_free(kmsg); 577 } 578 579 return MACH_MSG_SUCCESS; 580} 581 582/* 583 * Routine: mig_get_reply_port 584 * Purpose: 585 * Called by client side interfaces living in the kernel 586 * to get a reply port. 587 */ 588mach_port_t 589mig_get_reply_port(void) 590{ 591 return (MACH_PORT_NULL); 592} 593 594/* 595 * Routine: mig_dealloc_reply_port 596 * Purpose: 597 * Called by client side interfaces to get rid of a reply port. 598 */ 599 600void 601mig_dealloc_reply_port( 602 __unused mach_port_t reply_port) 603{ 604} 605 606/* 607 * Routine: mig_put_reply_port 608 * Purpose: 609 * Called by client side interfaces after each RPC to 610 * let the client recycle the reply port if it wishes. 611 */ 612void 613mig_put_reply_port( 614 __unused mach_port_t reply_port) 615{ 616} 617 618/* 619 * mig_strncpy.c - by Joshua Block 620 * 621 * mig_strncp -- Bounded string copy. Does what the library routine strncpy 622 * OUGHT to do: Copies the (null terminated) string in src into dest, a 623 * buffer of length len. Assures that the copy is still null terminated 624 * and doesn't overflow the buffer, truncating the copy if necessary. 625 * 626 * Parameters: 627 * 628 * dest - Pointer to destination buffer. 629 * 630 * src - Pointer to source string. 631 * 632 * len - Length of destination buffer. 633 */ 634int 635mig_strncpy( 636 char *dest, 637 const char *src, 638 int len) 639{ 640 int i = 0; 641 642 if (len > 0) 643 if (dest != NULL) { 644 if (src != NULL) 645 for (i=1; i<len; i++) 646 if (! (*dest++ = *src++)) 647 return i; 648 *dest = '\0'; 649 } 650 return i; 651} 652 653char * 654mig_user_allocate( 655 vm_size_t size) 656{ 657 return (char *)kalloc(size); 658} 659 660void 661mig_user_deallocate( 662 char *data, 663 vm_size_t size) 664{ 665 kfree(data, size); 666} 667 668/* 669 * Routine: mig_object_init 670 * Purpose: 671 * Initialize the base class portion of a MIG object. We 672 * will lazy init the port, so just clear it for now. 673 */ 674kern_return_t 675mig_object_init( 676 mig_object_t mig_object, 677 const IMIGObject *interface) 678{ 679 if (mig_object == MIG_OBJECT_NULL) 680 return KERN_INVALID_ARGUMENT; 681 mig_object->pVtbl = (const IMIGObjectVtbl *)interface; 682 mig_object->port = MACH_PORT_NULL; 683 return KERN_SUCCESS; 684} 685 686/* 687 * Routine: mig_object_destroy 688 * Purpose: 689 * The object is being freed. This call lets us clean 690 * up any state we have have built up over the object's 691 * lifetime. 692 * Conditions: 693 * Since notifications and the port hold references on 694 * on the object, neither can exist when this is called. 695 * This is a good place to assert() that condition. 696 */ 697void 698mig_object_destroy( 699 __assert_only mig_object_t mig_object) 700{ 701 assert(mig_object->port == MACH_PORT_NULL); 702 return; 703} 704 705/* 706 * Routine: mig_object_reference 707 * Purpose: 708 * Pure virtual helper to invoke the MIG object's AddRef 709 * method. 710 * Conditions: 711 * MIG object port may be locked. 712 */ 713void 714mig_object_reference( 715 mig_object_t mig_object) 716{ 717 assert(mig_object != MIG_OBJECT_NULL); 718 mig_object->pVtbl->AddRef((IMIGObject *)mig_object); 719} 720 721/* 722 * Routine: mig_object_deallocate 723 * Purpose: 724 * Pure virtual helper to invoke the MIG object's Release 725 * method. 726 * Conditions: 727 * Nothing locked. 728 */ 729void 730mig_object_deallocate( 731 mig_object_t mig_object) 732{ 733 assert(mig_object != MIG_OBJECT_NULL); 734 mig_object->pVtbl->Release((IMIGObject *)mig_object); 735} 736 737/* 738 * Routine: convert_mig_object_to_port [interface] 739 * Purpose: 740 * Base implementation of MIG outtrans routine to convert from 741 * a mig object reference to a new send right on the object's 742 * port. The object reference is consumed. 743 * Returns: 744 * IP_NULL - Null MIG object supplied 745 * Otherwise, a newly made send right for the port 746 * Conditions: 747 * Nothing locked. 748 */ 749ipc_port_t 750convert_mig_object_to_port( 751 mig_object_t mig_object) 752{ 753 ipc_port_t port; 754 boolean_t deallocate = TRUE; 755 756 if (mig_object == MIG_OBJECT_NULL) 757 return IP_NULL; 758 759 port = mig_object->port; 760 while ((port == IP_NULL) || 761 ((port = ipc_port_make_send(port)) == IP_NULL)) { 762 ipc_port_t previous; 763 764 /* 765 * Either the port was never set up, or it was just 766 * deallocated out from under us by the no-senders 767 * processing. In either case, we must: 768 * Attempt to make one 769 * Arrange for no senders 770 * Try to atomically register it with the object 771 * Destroy it if we are raced. 772 */ 773 port = ipc_port_alloc_kernel(); 774 ip_lock(port); 775 ipc_kobject_set_atomically(port, 776 (ipc_kobject_t) mig_object, 777 IKOT_MIG); 778 779 /* make a sonce right for the notification */ 780 port->ip_sorights++; 781 ip_reference(port); 782 783 ipc_port_nsrequest(port, 1, port, &previous); 784 /* port unlocked */ 785 786 assert(previous == IP_NULL); 787 788 if (OSCompareAndSwapPtr((void *)IP_NULL, (void *)port, 789 (void * volatile *)&mig_object->port)) { 790 deallocate = FALSE; 791 } else { 792 ipc_port_dealloc_kernel(port); 793 port = mig_object->port; 794 } 795 } 796 797 if (deallocate) 798 mig_object->pVtbl->Release((IMIGObject *)mig_object); 799 800 return (port); 801} 802 803 804/* 805 * Routine: convert_port_to_mig_object [interface] 806 * Purpose: 807 * Base implementation of MIG intrans routine to convert from 808 * an incoming port reference to a new reference on the 809 * underlying object. A new reference must be created, because 810 * the port's reference could go away asynchronously. 811 * Returns: 812 * NULL - Not an active MIG object port or iid not supported 813 * Otherwise, a reference to the underlying MIG interface 814 * Conditions: 815 * Nothing locked. 816 */ 817mig_object_t 818convert_port_to_mig_object( 819 ipc_port_t port, 820 const MIGIID *iid) 821{ 822 mig_object_t mig_object; 823 void *ppv; 824 825 if (!IP_VALID(port)) 826 return NULL; 827 828 ip_lock(port); 829 if (!ip_active(port) || (ip_kotype(port) != IKOT_MIG)) { 830 ip_unlock(port); 831 return NULL; 832 } 833 834 /* 835 * Our port points to some MIG object interface. Now 836 * query it to get a reference to the desired interface. 837 */ 838 ppv = NULL; 839 mig_object = (mig_object_t)port->ip_kobject; 840 mig_object->pVtbl->QueryInterface((IMIGObject *)mig_object, iid, &ppv); 841 ip_unlock(port); 842 return (mig_object_t)ppv; 843} 844 845/* 846 * Routine: mig_object_no_senders [interface] 847 * Purpose: 848 * Base implementation of a no-senders notification handler 849 * for MIG objects. If there truly are no more senders, must 850 * destroy the port and drop its reference on the object. 851 * Returns: 852 * TRUE - port deallocate and reference dropped 853 * FALSE - more senders arrived, re-registered for notification 854 * Conditions: 855 * Nothing locked. 856 */ 857 858boolean_t 859mig_object_no_senders( 860 ipc_port_t port, 861 mach_port_mscount_t mscount) 862{ 863 mig_object_t mig_object; 864 865 ip_lock(port); 866 if (port->ip_mscount > mscount) { 867 ipc_port_t previous; 868 869 /* 870 * Somebody created new send rights while the 871 * notification was in-flight. Just create a 872 * new send-once right and re-register with 873 * the new (higher) mscount threshold. 874 */ 875 /* make a sonce right for the notification */ 876 port->ip_sorights++; 877 ip_reference(port); 878 ipc_port_nsrequest(port, mscount, port, &previous); 879 /* port unlocked */ 880 881 assert(previous == IP_NULL); 882 return (FALSE); 883 } 884 885 /* 886 * Clear the port pointer while we have it locked. 887 */ 888 mig_object = (mig_object_t)port->ip_kobject; 889 mig_object->port = IP_NULL; 890 891 /* 892 * Bring the sequence number and mscount in 893 * line with ipc_port_destroy assertion. 894 */ 895 port->ip_mscount = 0; 896 port->ip_messages.imq_seqno = 0; 897 ipc_port_destroy(port); /* releases lock */ 898 899 /* 900 * Release the port's reference on the object. 901 */ 902 mig_object->pVtbl->Release((IMIGObject *)mig_object); 903 return (TRUE); 904} 905 906/* 907 * Kernel implementation of the notification chain for MIG object 908 * is kept separate from the actual objects, since there are expected 909 * to be much fewer of them than actual objects. 910 * 911 * The implementation of this part of MIG objects is coming 912 * "Real Soon Now"(TM). 913 */ 914