|
|
1.1.1.4 ! root 1: /* 1.1 root 2: * Mach Operating System 3: * Copyright (c) 1993,1992,1991,1990,1989,1988,1987 Carnegie Mellon University. 4: * All Rights Reserved. 1.1.1.4 ! root 5: * 1.1 root 6: * Permission to use, copy, modify and distribute this software and its 7: * documentation is hereby granted, provided that both the copyright 8: * notice and this permission notice appear in all copies of the 9: * software, derivative works or modified versions, and any portions 10: * thereof, and that both notices appear in supporting documentation. 1.1.1.4 ! root 11: * 1.1 root 12: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 13: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 14: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 1.1.1.4 ! root 15: * 1.1 root 16: * Carnegie Mellon requests users of this software to return to 1.1.1.4 ! root 17: * 1.1 root 18: * Software Distribution Coordinator or [email protected] 19: * School of Computer Science 20: * Carnegie Mellon University 21: * Pittsburgh PA 15213-3890 1.1.1.4 ! root 22: * 1.1 root 23: * any improvements or extensions that they make and grant Carnegie Mellon 24: * the rights to redistribute these changes. 25: */ 26: 27: #include <norma_ipc.h> 28: #include <mach_kdb.h> 29: 30: #include <mach/boolean.h> 31: #include <mach/kern_return.h> 32: #include <mach/message.h> 33: #include <mach/port.h> 34: #include <mach/mig_errors.h> 35: #include <ipc/port.h> 36: #include <ipc/ipc_entry.h> 37: #include <ipc/ipc_object.h> 38: #include <ipc/ipc_space.h> 39: #include <ipc/ipc_port.h> 40: #include <ipc/ipc_pset.h> 41: #include <ipc/mach_msg.h> 42: #include <ipc/ipc_machdep.h> 43: #include <kern/counters.h> 44: #include <kern/ipc_tt.h> 45: #include <kern/task.h> 46: #include <kern/thread.h> 47: #include <kern/processor.h> 48: #include <kern/sched.h> 49: #include <kern/sched_prim.h> 50: #include <mach/machine/vm_types.h> 51: 52: 53: 54: extern void exception(); 55: extern void exception_try_task(); 56: extern void exception_no_server(); 57: 58: extern void exception_raise(); 59: extern kern_return_t exception_parse_reply(); 60: extern void exception_raise_continue(); 61: extern void exception_raise_continue_slow(); 62: extern void exception_raise_continue_fast(); 63: 64: #if MACH_KDB 65: extern void thread_kdb_return(); 66: extern void db_printf(); 67: 68: boolean_t debug_user_with_kdb = FALSE; 69: #endif /* MACH_KDB */ 70: 71: #ifdef KEEP_STACKS 72: /* 73: * Some obsolete architectures don't support kernel stack discarding 74: * or the thread_exception_return, thread_syscall_return continuations. 75: * For these architectures, the NOTREACHED comments below are incorrect. 76: * The exception function is expected to return. 77: * So the return statements along the slow paths are important. 78: */ 1.1.1.4 ! root 79: #endif /* KEEP_STACKS */ 1.1 root 80: 81: /* 82: * Routine: exception 83: * Purpose: 84: * The current thread caught an exception. 85: * We make an up-call to the thread's exception server. 86: * Conditions: 87: * Nothing locked and no resources held. 88: * Called from an exception context, so 89: * thread_exception_return and thread_kdb_return 90: * are possible. 91: * Returns: 92: * Doesn't return. 93: */ 94: 95: void 96: exception(_exception, code, subcode) 97: integer_t _exception, code, subcode; 98: { 99: register ipc_thread_t self = current_thread(); 100: register ipc_port_t exc_port; 101: 102: if (_exception == KERN_SUCCESS) 103: panic("exception"); 104: 105: /* 106: * Optimized version of retrieve_thread_exception. 107: */ 108: 109: ith_lock(self); 110: assert(self->ith_self != IP_NULL); 111: exc_port = self->ith_exception; 112: if (!IP_VALID(exc_port)) { 113: ith_unlock(self); 114: exception_try_task(_exception, code, subcode); 115: /*NOTREACHED*/ 116: return; 117: } 118: 119: ip_lock(exc_port); 120: ith_unlock(self); 121: if (!ip_active(exc_port)) { 122: ip_unlock(exc_port); 123: exception_try_task(_exception, code, subcode); 124: /*NOTREACHED*/ 125: return; 126: } 127: 128: /* 129: * Make a naked send right for the exception port. 130: */ 131: 132: ip_reference(exc_port); 133: exc_port->ip_srights++; 134: ip_unlock(exc_port); 135: 136: /* 137: * If this exception port doesn't work, 138: * we will want to try the task's exception port. 139: * Indicate this by saving the exception state. 140: */ 141: 142: self->ith_exc = _exception; 143: self->ith_exc_code = code; 144: self->ith_exc_subcode = subcode; 145: 146: exception_raise(exc_port, 147: retrieve_thread_self_fast(self), 148: retrieve_task_self_fast(self->task), 149: _exception, code, subcode); 150: /*NOTREACHED*/ 151: } 152: 153: /* 154: * Routine: exception_try_task 155: * Purpose: 156: * The current thread caught an exception. 157: * We make an up-call to the task's exception server. 158: * Conditions: 159: * Nothing locked and no resources held. 160: * Called from an exception context, so 161: * thread_exception_return and thread_kdb_return 162: * are possible. 163: * Returns: 164: * Doesn't return. 165: */ 166: 167: void 168: exception_try_task(_exception, code, subcode) 169: integer_t _exception, code, subcode; 170: { 171: ipc_thread_t self = current_thread(); 172: register task_t task = self->task; 173: register ipc_port_t exc_port; 174: 175: /* 176: * Optimized version of retrieve_task_exception. 177: */ 178: 179: itk_lock(task); 180: assert(task->itk_self != IP_NULL); 181: exc_port = task->itk_exception; 182: if (!IP_VALID(exc_port)) { 183: itk_unlock(task); 184: exception_no_server(); 185: /*NOTREACHED*/ 186: return; 187: } 188: 189: ip_lock(exc_port); 190: itk_unlock(task); 191: if (!ip_active(exc_port)) { 192: ip_unlock(exc_port); 193: exception_no_server(); 194: /*NOTREACHED*/ 195: return; 196: } 197: 198: /* 199: * Make a naked send right for the exception port. 200: */ 201: 202: ip_reference(exc_port); 203: exc_port->ip_srights++; 204: ip_unlock(exc_port); 205: 206: /* 207: * This is the thread's last chance. 208: * Clear the saved exception state. 209: */ 210: 211: self->ith_exc = KERN_SUCCESS; 212: 213: exception_raise(exc_port, 214: retrieve_thread_self_fast(self), 215: retrieve_task_self_fast(task), 216: _exception, code, subcode); 217: /*NOTREACHED*/ 218: } 219: 220: /* 221: * Routine: exception_no_server 222: * Purpose: 223: * The current thread took an exception, 224: * and no exception server took responsibility 225: * for the exception. So good bye, charlie. 226: * Conditions: 227: * Nothing locked and no resources held. 228: * Called from an exception context, so 229: * thread_kdb_return is possible. 230: * Returns: 231: * Doesn't return. 232: */ 233: 234: void 235: exception_no_server() 236: { 237: register ipc_thread_t self = current_thread(); 238: 239: /* 240: * If this thread is being terminated, cooperate. 241: */ 242: 243: while (thread_should_halt(self)) 244: thread_halt_self(); 245: 246: 1.1.1.3 root 247: #if 0 1.1 root 248: if (thread_suspend (self) == KERN_SUCCESS) 249: thread_exception_return (); 1.1.1.2 root 250: #endif 1.1 root 251: 252: #if MACH_KDB 253: if (debug_user_with_kdb) { 254: /* 255: * Debug the exception with kdb. 256: * If kdb handles the exception, 257: * then thread_kdb_return won't return. 258: */ 259: 260: db_printf("No exception server, calling kdb...\n"); 261: thread_kdb_return(); 262: } 1.1.1.4 ! root 263: #endif /* MACH_KDB */ 1.1 root 264: 265: /* 266: * All else failed; terminate task. 267: */ 268: 269: (void) task_terminate(self->task); 270: thread_halt_self(); 271: /*NOTREACHED*/ 272: } 273: 274: #define MACH_EXCEPTION_ID 2400 /* from mach/exc.defs */ 275: #define MACH_EXCEPTION_REPLY_ID (MACH_EXCEPTION_ID + 100) 276: 277: struct mach_exception { 278: mach_msg_header_t Head; 279: mach_msg_type_t threadType; 280: mach_port_t thread; 281: mach_msg_type_t taskType; 282: mach_port_t task; 283: mach_msg_type_t exceptionType; 284: integer_t exception; 285: mach_msg_type_t codeType; 286: integer_t code; 287: mach_msg_type_t subcodeType; 288: integer_t subcode; 289: }; 290: 291: #define INTEGER_T_SIZE_IN_BITS (8 * sizeof(integer_t)) 292: #define INTEGER_T_TYPE MACH_MSG_TYPE_INTEGER_T 293: /* in mach/machine/vm_types.h */ 294: 295: mach_msg_type_t exc_port_proto = { 296: /* msgt_name = */ MACH_MSG_TYPE_PORT_SEND, 297: /* msgt_size = */ PORT_T_SIZE_IN_BITS, 298: /* msgt_number = */ 1, 299: /* msgt_inline = */ TRUE, 300: /* msgt_longform = */ FALSE, 301: /* msgt_deallocate = */ FALSE, 302: /* msgt_unused = */ 0 303: }; 304: 305: mach_msg_type_t exc_code_proto = { 306: /* msgt_name = */ INTEGER_T_TYPE, 307: /* msgt_size = */ INTEGER_T_SIZE_IN_BITS, 308: /* msgt_number = */ 1, 309: /* msgt_inline = */ TRUE, 310: /* msgt_longform = */ FALSE, 311: /* msgt_deallocate = */ FALSE, 312: /* msgt_unused = */ 0 313: }; 314: 315: /* 316: * Routine: exception_raise 317: * Purpose: 318: * Make an exception_raise up-call to an exception server. 319: * 320: * dest_port must be a valid naked send right. 321: * thread_port and task_port are naked send rights. 322: * All three are always consumed. 323: * 324: * self->ith_exc, self->ith_exc_code, self->ith_exc_subcode 325: * must be appropriately initialized. 326: * Conditions: 327: * Nothing locked. We are being called in an exception context, 328: * so thread_exception_return may be called. 329: * Returns: 330: * Doesn't return. 331: */ 332: 333: int exception_raise_misses = 0; 334: 335: void 336: exception_raise(dest_port, thread_port, task_port, 337: _exception, code, subcode) 338: ipc_port_t dest_port; 339: ipc_port_t thread_port; 340: ipc_port_t task_port; 341: integer_t _exception, code, subcode; 342: { 343: ipc_thread_t self = current_thread(); 344: ipc_thread_t receiver; 345: ipc_port_t reply_port; 346: ipc_mqueue_t dest_mqueue; 347: ipc_mqueue_t reply_mqueue; 348: ipc_kmsg_t kmsg; 349: mach_msg_return_t mr; 350: 351: assert(IP_VALID(dest_port)); 352: 353: /* 354: * We will eventually need a message buffer. 355: * Grab the buffer now, while nothing is locked. 356: * This buffer will get handed to the exception server, 357: * and it will give the buffer back with its reply. 358: */ 359: 360: kmsg = ikm_cache(); 361: if (kmsg != IKM_NULL) { 362: ikm_cache() = IKM_NULL; 363: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE); 364: } else { 365: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE); 366: if (kmsg == IKM_NULL) 367: panic("exception_raise"); 368: ikm_init(kmsg, IKM_SAVED_MSG_SIZE); 369: } 370: 371: /* 372: * We need a reply port for the RPC. 373: * Check first for a cached port. 374: */ 375: 376: ith_lock(self); 377: assert(self->ith_self != IP_NULL); 378: 379: reply_port = self->ith_rpc_reply; 380: if (reply_port == IP_NULL) { 381: ith_unlock(self); 382: reply_port = ipc_port_alloc_reply(); 383: ith_lock(self); 384: if ((reply_port == IP_NULL) || 385: (self->ith_rpc_reply != IP_NULL)) 386: panic("exception_raise"); 387: self->ith_rpc_reply = reply_port; 388: } 389: 390: ip_lock(reply_port); 391: assert(ip_active(reply_port)); 392: ith_unlock(self); 393: 394: /* 395: * Make a naked send-once right for the reply port, 396: * to hand to the exception server. 397: * Make an extra reference for the reply port, 398: * to receive on. This protects us against 399: * mach_msg_abort_rpc. 400: */ 401: 402: reply_port->ip_sorights++; 403: ip_reference(reply_port); 404: 405: ip_reference(reply_port); 406: self->ith_port = reply_port; 407: 408: reply_mqueue = &reply_port->ip_messages; 409: imq_lock(reply_mqueue); 410: assert(ipc_kmsg_queue_empty(&reply_mqueue->imq_messages)); 411: ip_unlock(reply_port); 412: 413: /* 414: * Make sure we can queue to the destination port. 415: */ 416: 417: if (!ip_lock_try(dest_port)) { 418: imq_unlock(reply_mqueue); 419: goto slow_exception_raise; 420: } 421: 422: if (!ip_active(dest_port) || 423: #if NORMA_IPC 424: IP_NORMA_IS_PROXY(dest_port) || 1.1.1.4 ! root 425: #endif /* NORMA_IPC */ 1.1 root 426: (dest_port->ip_receiver == ipc_space_kernel)) { 427: imq_unlock(reply_mqueue); 428: ip_unlock(dest_port); 429: goto slow_exception_raise; 430: } 431: 432: /* 433: * Find the destination message queue. 434: */ 435: 436: { 437: register ipc_pset_t dest_pset; 438: 439: dest_pset = dest_port->ip_pset; 440: if (dest_pset == IPS_NULL) 441: dest_mqueue = &dest_port->ip_messages; 442: else 443: dest_mqueue = &dest_pset->ips_messages; 444: } 445: 446: if (!imq_lock_try(dest_mqueue)) { 447: imq_unlock(reply_mqueue); 448: ip_unlock(dest_port); 449: goto slow_exception_raise; 450: } 451: 452: /* 453: * Safe to unlock dest_port, because we hold 454: * dest_mqueue locked. We never bother changing 455: * dest_port->ip_msgcount. 456: */ 457: 458: ip_unlock(dest_port); 459: 460: receiver = ipc_thread_queue_first(&dest_mqueue->imq_threads); 461: if ((receiver == ITH_NULL) || 462: !((receiver->swap_func == (void (*)()) mach_msg_continue) || 463: ((receiver->swap_func == 464: (void (*)()) mach_msg_receive_continue) && 465: (sizeof(struct mach_exception) <= receiver->ith_msize) && 466: ((receiver->ith_option & MACH_RCV_NOTIFY) == 0))) || 467: !thread_handoff(self, exception_raise_continue, receiver)) { 468: imq_unlock(reply_mqueue); 469: imq_unlock(dest_mqueue); 470: goto slow_exception_raise; 471: } 472: counter(c_exception_raise_block++); 473: 474: assert(current_thread() == receiver); 475: 476: /* 477: * We need to finish preparing self for its 478: * time asleep in reply_mqueue. self is left 479: * holding the extra ref for reply_port. 480: */ 481: 482: ipc_thread_enqueue_macro(&reply_mqueue->imq_threads, self); 483: self->ith_state = MACH_RCV_IN_PROGRESS; 484: self->ith_msize = MACH_MSG_SIZE_MAX; 485: imq_unlock(reply_mqueue); 486: 487: /* 488: * Finish extracting receiver from dest_mqueue. 489: */ 490: 491: ipc_thread_rmqueue_first_macro( 492: &dest_mqueue->imq_threads, receiver); 493: imq_unlock(dest_mqueue); 494: 495: /* 496: * Release the receiver's reference for his object. 497: */ 498: { 499: register ipc_object_t object = receiver->ith_object; 500: 501: io_lock(object); 502: io_release(object); 503: io_check_unlock(object); 504: } 505: 506: { 507: register struct mach_exception *exc = 508: (struct mach_exception *) &kmsg->ikm_header; 509: ipc_space_t space = receiver->task->itk_space; 510: 511: /* 512: * We are running as the receiver now. We hold 513: * the following resources, which must be consumed: 514: * kmsg, send-once right for reply_port 515: * send rights for dest_port, thread_port, task_port 516: * Synthesize a kmsg for copyout to the receiver. 517: */ 518: 519: exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 520: MACH_MSG_TYPE_PORT_SEND) | 521: MACH_MSGH_BITS_COMPLEX); 522: exc->Head.msgh_size = sizeof *exc; 523: /* exc->Head.msgh_remote_port later */ 524: /* exc->Head.msgh_local_port later */ 525: exc->Head.msgh_seqno = 0; 526: exc->Head.msgh_id = MACH_EXCEPTION_ID; 527: exc->threadType = exc_port_proto; 528: /* exc->thread later */ 529: exc->taskType = exc_port_proto; 530: /* exc->task later */ 531: exc->exceptionType = exc_code_proto; 532: exc->exception = _exception; 533: exc->codeType = exc_code_proto; 534: exc->code = code; 535: exc->subcodeType = exc_code_proto; 536: exc->subcode = subcode; 537: 538: /* 539: * Check that the receiver can handle the message. 540: */ 541: 542: if (receiver->ith_rcv_size < sizeof(struct mach_exception)) { 543: /* 544: * ipc_kmsg_destroy is a handy way to consume 545: * the resources we hold, but it requires setup. 546: */ 547: 548: exc->Head.msgh_bits = 549: (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 550: MACH_MSG_TYPE_PORT_SEND_ONCE) | 551: MACH_MSGH_BITS_COMPLEX); 552: exc->Head.msgh_remote_port = (mach_port_t) dest_port; 553: exc->Head.msgh_local_port = (mach_port_t) reply_port; 554: exc->thread = (mach_port_t) thread_port; 555: exc->task = (mach_port_t) task_port; 556: 557: ipc_kmsg_destroy(kmsg); 558: thread_syscall_return(MACH_RCV_TOO_LARGE); 559: /*NOTREACHED*/ 560: } 561: 562: is_write_lock(space); 563: assert(space->is_active); 564: 565: /* 566: * To do an atomic copyout, need simultaneous 567: * locks on both ports and the space. 568: */ 569: 570: ip_lock(dest_port); 571: if (!ip_active(dest_port) || 572: !ip_lock_try(reply_port)) { 573: abort_copyout: 574: ip_unlock(dest_port); 575: is_write_unlock(space); 576: 577: /* 578: * Oh well, we have to do the header the slow way. 579: * First make it look like it's in-transit. 580: */ 581: 582: exc->Head.msgh_bits = 583: (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 584: MACH_MSG_TYPE_PORT_SEND_ONCE) | 585: MACH_MSGH_BITS_COMPLEX); 586: exc->Head.msgh_remote_port = (mach_port_t) dest_port; 587: exc->Head.msgh_local_port = (mach_port_t) reply_port; 588: 589: mr = ipc_kmsg_copyout_header(&exc->Head, space, 590: MACH_PORT_NULL); 591: if (mr == MACH_MSG_SUCCESS) 592: goto copyout_body; 593: 594: /* 595: * Ack! Prepare for ipc_kmsg_copyout_dest. 596: * It will consume thread_port and task_port. 597: */ 598: 599: exc->thread = (mach_port_t) thread_port; 600: exc->task = (mach_port_t) task_port; 601: 602: ipc_kmsg_copyout_dest(kmsg, space); 603: (void) ipc_kmsg_put(receiver->ith_msg, kmsg, 604: sizeof(mach_msg_header_t)); 605: thread_syscall_return(mr); 606: /*NOTREACHED*/ 607: } 608: 609: if (!ip_active(reply_port)) { 610: ip_unlock(reply_port); 611: goto abort_copyout; 612: } 613: 614: assert(reply_port->ip_sorights > 0); 615: ip_unlock(reply_port); 616: 617: { 618: register ipc_entry_t table; 619: register ipc_entry_t entry; 620: register mach_port_index_t index; 621: 622: /* optimized ipc_entry_get */ 623: 624: table = space->is_table; 625: index = table->ie_next; 626: 627: if (index == 0) 628: goto abort_copyout; 629: 630: entry = &table[index]; 631: table->ie_next = entry->ie_next; 632: entry->ie_request = 0; 633: 634: { 635: register mach_port_gen_t gen; 636: 637: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); 638: gen = entry->ie_bits + IE_BITS_GEN_ONE; 639: 640: exc->Head.msgh_remote_port = MACH_PORT_MAKE(index, gen); 641: 642: /* optimized ipc_right_copyout */ 643: 644: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); 645: } 646: 647: entry->ie_object = (ipc_object_t) reply_port; 648: is_write_unlock(space); 649: } 650: 651: /* optimized ipc_object_copyout_dest */ 652: 653: assert(dest_port->ip_srights > 0); 654: ip_release(dest_port); 655: 656: exc->Head.msgh_local_port = 657: ((dest_port->ip_receiver == space) ? 658: dest_port->ip_receiver_name : MACH_PORT_NULL); 659: 660: if ((--dest_port->ip_srights == 0) && 661: (dest_port->ip_nsrequest != IP_NULL)) { 662: ipc_port_t nsrequest; 663: mach_port_mscount_t mscount; 664: 665: /* a rather rare case */ 666: 667: nsrequest = dest_port->ip_nsrequest; 668: mscount = dest_port->ip_mscount; 669: dest_port->ip_nsrequest = IP_NULL; 670: ip_unlock(dest_port); 671: 672: ipc_notify_no_senders(nsrequest, mscount); 673: } else 674: ip_unlock(dest_port); 675: 676: copyout_body: 677: /* 678: * Optimized version of ipc_kmsg_copyout_body, 679: * to handle the two ports in the body. 680: */ 681: 682: mr = (ipc_kmsg_copyout_object(space, (ipc_object_t) thread_port, 683: MACH_MSG_TYPE_PORT_SEND, &exc->thread) | 684: ipc_kmsg_copyout_object(space, (ipc_object_t) task_port, 685: MACH_MSG_TYPE_PORT_SEND, &exc->task)); 686: if (mr != MACH_MSG_SUCCESS) { 687: (void) ipc_kmsg_put(receiver->ith_msg, kmsg, 688: kmsg->ikm_header.msgh_size); 689: thread_syscall_return(mr | MACH_RCV_BODY_ERROR); 690: /*NOTREACHED*/ 691: } 692: } 693: 694: /* 695: * Optimized version of ipc_kmsg_put. 696: * We must check ikm_cache after copyoutmsg. 697: */ 698: 699: ikm_check_initialized(kmsg, kmsg->ikm_size); 700: assert(kmsg->ikm_size == IKM_SAVED_KMSG_SIZE); 701: 702: if (copyoutmsg((vm_offset_t) &kmsg->ikm_header, (vm_offset_t)receiver->ith_msg, 703: sizeof(struct mach_exception)) || 704: (ikm_cache() != IKM_NULL)) { 705: mr = ipc_kmsg_put(receiver->ith_msg, kmsg, 706: kmsg->ikm_header.msgh_size); 707: thread_syscall_return(mr); 708: /*NOTREACHED*/ 709: } 710: 711: ikm_cache() = kmsg; 712: thread_syscall_return(MACH_MSG_SUCCESS); 713: /*NOTREACHED*/ 714: #ifndef __GNUC__ 715: return; /* help for the compiler */ 716: #endif 717: 718: slow_exception_raise: { 719: register struct mach_exception *exc = 720: (struct mach_exception *) &kmsg->ikm_header; 721: ipc_kmsg_t reply_kmsg; 722: mach_port_seqno_t reply_seqno; 723: 724: exception_raise_misses++; 725: 726: /* 727: * We hold the following resources, which must be consumed: 728: * kmsg, send-once right and ref for reply_port 729: * send rights for dest_port, thread_port, task_port 730: * Synthesize a kmsg to send. 731: */ 732: 733: exc->Head.msgh_bits = (MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 734: MACH_MSG_TYPE_PORT_SEND_ONCE) | 735: MACH_MSGH_BITS_COMPLEX); 736: exc->Head.msgh_size = sizeof *exc; 737: exc->Head.msgh_remote_port = (mach_port_t) dest_port; 738: exc->Head.msgh_local_port = (mach_port_t) reply_port; 739: exc->Head.msgh_seqno = 0; 740: exc->Head.msgh_id = MACH_EXCEPTION_ID; 741: exc->threadType = exc_port_proto; 742: exc->thread = (mach_port_t) thread_port; 743: exc->taskType = exc_port_proto; 744: exc->task = (mach_port_t) task_port; 745: exc->exceptionType = exc_code_proto; 746: exc->exception = _exception; 747: exc->codeType = exc_code_proto; 748: exc->code = code; 749: exc->subcodeType = exc_code_proto; 750: exc->subcode = subcode; 751: 752: ipc_mqueue_send_always(kmsg); 753: 754: /* 755: * We are left with a ref for reply_port, 756: * which we use to receive the reply message. 757: */ 758: 759: ip_lock(reply_port); 760: if (!ip_active(reply_port)) { 761: ip_unlock(reply_port); 762: exception_raise_continue_slow(MACH_RCV_PORT_DIED, IKM_NULL, /*dummy*/0); 763: /*NOTREACHED*/ 764: return; 765: } 766: 767: imq_lock(reply_mqueue); 768: ip_unlock(reply_port); 769: 770: mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE, 771: MACH_MSG_SIZE_MAX, 772: MACH_MSG_TIMEOUT_NONE, 773: FALSE, exception_raise_continue, 774: &reply_kmsg, &reply_seqno); 775: /* reply_mqueue is unlocked */ 776: 777: exception_raise_continue_slow(mr, reply_kmsg, reply_seqno); 778: /*NOTREACHED*/ 779: } 780: } 781: 782: mach_msg_type_t exc_RetCode_proto = { 783: /* msgt_name = */ MACH_MSG_TYPE_INTEGER_32, 784: /* msgt_size = */ 32, 785: /* msgt_number = */ 1, 786: /* msgt_inline = */ TRUE, 787: /* msgt_longform = */ FALSE, 788: /* msgt_deallocate = */ FALSE, 789: /* msgt_unused = */ 0 790: }; 791: 792: /* 793: * Routine: exception_parse_reply 794: * Purpose: 795: * Parse and consume an exception reply message. 796: * Conditions: 797: * The destination port right has already been consumed. 798: * The message buffer and anything else in it is consumed. 799: * Returns: 800: * The reply return code. 801: */ 802: 803: kern_return_t 804: exception_parse_reply(kmsg) 805: ipc_kmsg_t kmsg; 806: { 807: register mig_reply_header_t *msg = 808: (mig_reply_header_t *) &kmsg->ikm_header; 809: kern_return_t kr; 810: 811: if ((msg->Head.msgh_bits != 812: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0)) || 813: (msg->Head.msgh_size != sizeof *msg) || 814: (msg->Head.msgh_id != MACH_EXCEPTION_REPLY_ID) || 815: (* (int *) &msg->RetCodeType != * (int *) &exc_RetCode_proto)) { 816: /* 817: * Bozo user sent us a misformatted reply. 818: */ 819: 820: kmsg->ikm_header.msgh_remote_port = MACH_PORT_NULL; 821: ipc_kmsg_destroy(kmsg); 822: return MIG_REPLY_MISMATCH; 823: } 824: 825: kr = msg->RetCode; 826: 827: if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) && 828: (ikm_cache() == IKM_NULL)) 829: ikm_cache() = kmsg; 830: else 831: ikm_free(kmsg); 832: 833: return kr; 834: } 835: 836: /* 837: * Routine: exception_raise_continue 838: * Purpose: 839: * Continue after blocking for an exception. 840: * Conditions: 841: * Nothing locked. We are running on a new kernel stack, 842: * with the exception state saved in the thread. From here 843: * control goes back to user space. 844: * Returns: 845: * Doesn't return. 846: */ 847: 848: void 849: exception_raise_continue() 850: { 851: ipc_thread_t self = current_thread(); 852: ipc_port_t reply_port = self->ith_port; 853: ipc_mqueue_t reply_mqueue = &reply_port->ip_messages; 854: ipc_kmsg_t kmsg; 855: mach_port_seqno_t seqno; 856: mach_msg_return_t mr; 857: 858: mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE, 859: MACH_MSG_SIZE_MAX, 860: MACH_MSG_TIMEOUT_NONE, 861: TRUE, exception_raise_continue, 862: &kmsg, &seqno); 863: /* reply_mqueue is unlocked */ 864: 865: exception_raise_continue_slow(mr, kmsg, seqno); 866: /*NOTREACHED*/ 867: } 868: 869: /* 870: * Routine: exception_raise_continue_slow 871: * Purpose: 872: * Continue after finishing an ipc_mqueue_receive 873: * for an exception reply message. 874: * Conditions: 875: * Nothing locked. We hold a ref for reply_port. 876: * Returns: 877: * Doesn't return. 878: */ 879: 880: void 881: exception_raise_continue_slow(mr, kmsg, seqno) 882: mach_msg_return_t mr; 883: ipc_kmsg_t kmsg; 884: mach_port_seqno_t seqno; 885: { 886: ipc_thread_t self = current_thread(); 887: ipc_port_t reply_port = self->ith_port; 888: ipc_mqueue_t reply_mqueue = &reply_port->ip_messages; 889: 890: while (mr == MACH_RCV_INTERRUPTED) { 891: /* 892: * Somebody is trying to force this thread 893: * to a clean point. We must cooperate 894: * and then resume the receive. 895: */ 896: 897: while (thread_should_halt(self)) { 898: /* don't terminate while holding a reference */ 899: if (self->ast & AST_TERMINATE) 900: ipc_port_release(reply_port); 901: thread_halt_self(); 902: } 903: 904: ip_lock(reply_port); 905: if (!ip_active(reply_port)) { 906: ip_unlock(reply_port); 907: mr = MACH_RCV_PORT_DIED; 908: break; 909: } 910: 911: imq_lock(reply_mqueue); 912: ip_unlock(reply_port); 913: 914: mr = ipc_mqueue_receive(reply_mqueue, MACH_MSG_OPTION_NONE, 915: MACH_MSG_SIZE_MAX, 916: MACH_MSG_TIMEOUT_NONE, 917: FALSE, exception_raise_continue, 918: &kmsg, &seqno); 919: /* reply_mqueue is unlocked */ 920: } 921: ipc_port_release(reply_port); 922: 923: assert((mr == MACH_MSG_SUCCESS) || 924: (mr == MACH_RCV_PORT_DIED)); 925: 926: if (mr == MACH_MSG_SUCCESS) { 927: /* 928: * Consume the reply message. 929: */ 930: 931: ipc_port_release_sonce(reply_port); 932: mr = exception_parse_reply(kmsg); 933: } 934: 935: if ((mr == KERN_SUCCESS) || 936: (mr == MACH_RCV_PORT_DIED)) { 937: thread_exception_return(); 938: /*NOTREACHED*/ 939: return; 940: } 941: 942: if (self->ith_exc != KERN_SUCCESS) { 943: exception_try_task(self->ith_exc, 944: self->ith_exc_code, 945: self->ith_exc_subcode); 946: /*NOTREACHED*/ 947: return; 948: } 949: 950: exception_no_server(); 951: /*NOTREACHED*/ 952: } 953: 954: /* 955: * Routine: exception_raise_continue_fast 956: * Purpose: 957: * Special-purpose fast continuation for exceptions. 958: * Conditions: 959: * reply_port is locked and alive. 960: * kmsg is our reply message. 961: * Returns: 962: * Doesn't return. 963: */ 964: 965: void 966: exception_raise_continue_fast(reply_port, kmsg) 967: ipc_port_t reply_port; 968: ipc_kmsg_t kmsg; 969: { 970: ipc_thread_t self = current_thread(); 971: kern_return_t kr; 972: 973: assert(ip_active(reply_port)); 974: assert(reply_port == self->ith_port); 975: assert(reply_port == (ipc_port_t) kmsg->ikm_header.msgh_remote_port); 976: assert(MACH_MSGH_BITS_REMOTE(kmsg->ikm_header.msgh_bits) == 977: MACH_MSG_TYPE_PORT_SEND_ONCE); 978: 979: /* 980: * Release the send-once right (from the message header) 981: * and the saved reference (from self->ith_port). 982: */ 983: 984: reply_port->ip_sorights--; 985: ip_release(reply_port); 986: ip_release(reply_port); 987: ip_unlock(reply_port); 988: 989: /* 990: * Consume the reply message. 991: */ 992: 993: kr = exception_parse_reply(kmsg); 994: if (kr == KERN_SUCCESS) { 995: thread_exception_return(); 996: /*NOTREACHED*/ 997: return; /* help for the compiler */ 998: } 999: 1000: if (self->ith_exc != KERN_SUCCESS) { 1001: exception_try_task(self->ith_exc, 1002: self->ith_exc_code, 1003: self->ith_exc_subcode); 1004: /*NOTREACHED*/ 1005: } 1006: 1007: exception_no_server(); 1008: /*NOTREACHED*/ 1009: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.