|
|
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,1988,1987 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: #include <mach_kdb.h> ! 54: ! 55: #include <mach/boolean.h> ! 56: #include <mach/kern_return.h> ! 57: #include <mach/message.h> ! 58: #include <mach/port.h> ! 59: #include <mach/mig_errors.h> ! 60: #include <mach/thread_status.h> ! 61: #include <mach/exception_types.h> ! 62: #include <ipc/port.h> ! 63: #include <ipc/ipc_entry.h> ! 64: #include <ipc/ipc_object.h> ! 65: #include <ipc/ipc_notify.h> ! 66: #include <ipc/ipc_space.h> ! 67: #include <ipc/ipc_pset.h> ! 68: #include <ipc/ipc_machdep.h> ! 69: #include <kern/etap_macros.h> ! 70: #include <kern/counters.h> ! 71: #include <kern/ipc_tt.h> ! 72: #include <kern/task.h> ! 73: #include <kern/thread.h> ! 74: #include <kern/thread_swap.h> ! 75: #include <kern/processor.h> ! 76: #include <kern/sched.h> ! 77: #include <kern/sched_prim.h> ! 78: #include <kern/host.h> ! 79: #include <kern/misc_protos.h> ! 80: #include <string.h> ! 81: #include <mach/exc.h> /* JMM - will become exception.h */ ! 82: #include <machine/machine_rpc.h> ! 83: ! 84: #if MACH_KDB ! 85: #include <ddb/db_trap.h> ! 86: #endif /* MACH_KDB */ ! 87: ! 88: /* ! 89: * Forward declarations ! 90: */ ! 91: void exception_try_task( ! 92: exception_type_t exception, ! 93: exception_data_t code, ! 94: mach_msg_type_number_t codeCnt); ! 95: ! 96: void exception_no_server(void); ! 97: ! 98: kern_return_t alert_exception_try_task( ! 99: exception_type_t exception, ! 100: exception_data_t code, ! 101: int codeCnt); ! 102: ! 103: #if MACH_KDB ! 104: ! 105: #include <ddb/db_output.h> ! 106: ! 107: #if iPSC386 || iPSC860 ! 108: boolean_t debug_user_with_kdb = TRUE; ! 109: #else ! 110: boolean_t debug_user_with_kdb = FALSE; ! 111: #endif ! 112: ! 113: #endif /* MACH_KDB */ ! 114: ! 115: unsigned long c_thr_exc_raise = 0; ! 116: unsigned long c_thr_exc_raise_state = 0; ! 117: unsigned long c_thr_exc_raise_state_id = 0; ! 118: unsigned long c_tsk_exc_raise = 0; ! 119: unsigned long c_tsk_exc_raise_state = 0; ! 120: unsigned long c_tsk_exc_raise_state_id = 0; ! 121: ! 122: ! 123: #ifdef MACHINE_FAST_EXCEPTION /* from <machine/thread.h> if at all */ ! 124: /* ! 125: * This is the fast, MD code, with lots of stuff in-lined. ! 126: */ ! 127: ! 128: extern int switch_act_swapins; ! 129: ! 130: #ifdef i386 ! 131: /* ! 132: * Temporary: controls the syscall copyin optimization. ! 133: * If TRUE, the exception function will copy in the first n ! 134: * words from the stack of the user thread and store it in ! 135: * the saved state, so that the server doesn't have to do ! 136: * this. ! 137: */ ! 138: boolean_t syscall_exc_copyin = TRUE; ! 139: #endif ! 140: ! 141: /* ! 142: * Routine: exception ! 143: * Purpose: ! 144: * The current thread caught an exception. ! 145: * We make an up-call to the thread's exception server. ! 146: * Conditions: ! 147: * Nothing locked and no resources held. ! 148: * Called from an exception context, so ! 149: * thread_exception_return and thread_kdb_return ! 150: * are possible. ! 151: * Returns: ! 152: * Doesn't return. ! 153: */ ! 154: ! 155: void ! 156: exception( ! 157: exception_type_t exception, ! 158: exception_data_t code, ! 159: mach_msg_type_number_t codeCnt ) ! 160: { ! 161: thread_t self = current_thread(); ! 162: thread_act_t a_self = self->top_act; ! 163: thread_act_t cln_act; ! 164: ipc_port_t exc_port; ! 165: int i; ! 166: struct exception_action *excp = &a_self->exc_actions[exception]; ! 167: int flavor; ! 168: kern_return_t kr; ! 169: ! 170: assert(exception != EXC_RPC_ALERT); ! 171: ! 172: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 173: ! 174: /* ! 175: * Optimized version of retrieve_thread_exception. ! 176: */ ! 177: ! 178: act_lock(a_self); ! 179: assert(a_self->ith_self != IP_NULL); ! 180: exc_port = excp->port; ! 181: if (!IP_VALID(exc_port)) { ! 182: act_unlock(a_self); ! 183: exception_try_task(exception, code, codeCnt); ! 184: /*NOTREACHED*/ ! 185: return; ! 186: } ! 187: flavor = excp->flavor; ! 188: ! 189: #ifdef i386 ! 190: /* For this flavor, we must copy in the first few procedure call ! 191: * args from the user's stack, since that is part of the important ! 192: * state in a syscall exception (this is for performance -- we ! 193: * can do the copyin much faster than the server, even if it is ! 194: * kernel-loaded): ! 195: */ ! 196: if (flavor == i386_SAVED_STATE) { ! 197: struct i386_saved_state *statep = (struct i386_saved_state *) ! 198: act_machine_state_ptr(self->top_act); ! 199: statep->argv_status = FALSE; ! 200: if (syscall_exc_copyin && copyin((char *)statep->uesp, ! 201: (char *)statep->argv, ! 202: i386_SAVED_ARGV_COUNT * sizeof(int)) == 0) { ! 203: /* Indicate success for the server: */ ! 204: statep->argv_status = TRUE; ! 205: } ! 206: } ! 207: #endif ! 208: ! 209: ETAP_EXCEPTION_PROBE(EVENT_BEGIN, self, exception, code); ! 210: ! 211: ip_lock(exc_port); ! 212: act_unlock(a_self); ! 213: if (!ip_active(exc_port)) { ! 214: ip_unlock(exc_port); ! 215: exception_try_task(exception, code, codeCnt); ! 216: /*NOTREACHED*/ ! 217: return; ! 218: } ! 219: ! 220: /* ! 221: * Hold a reference to the port over the exception_raise_* calls ! 222: * so it can't be destroyed. This seems like overkill, but keeps ! 223: * the port from disappearing between now and when ! 224: * ipc_object_copyin_from_kernel is finally called. ! 225: */ ! 226: ip_reference(exc_port); ! 227: exc_port->ip_srights++; ! 228: ip_unlock(exc_port); ! 229: ! 230: switch (excp->behavior) { ! 231: case EXCEPTION_STATE: { ! 232: mach_msg_type_number_t state_cnt; ! 233: { ! 234: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 235: ! 236: state_cnt = state_count[flavor]; ! 237: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 238: if (kr == KERN_SUCCESS) { ! 239: kr = exception_raise_state(exc_port, exception, ! 240: code, codeCnt, ! 241: &flavor, ! 242: state, state_cnt, ! 243: state, &state_cnt); ! 244: if (kr == MACH_MSG_SUCCESS) ! 245: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 246: } ! 247: } ! 248: ! 249: if (kr == KERN_SUCCESS || ! 250: kr == MACH_RCV_PORT_DIED) { ! 251: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code); ! 252: thread_exception_return(); ! 253: /* NOTREACHED*/ ! 254: return; ! 255: } ! 256: } break; ! 257: ! 258: case EXCEPTION_DEFAULT: ! 259: c_thr_exc_raise++; ! 260: kr = exception_raise(exc_port, ! 261: retrieve_act_self_fast(a_self), ! 262: retrieve_task_self_fast(a_self->task), ! 263: exception, ! 264: code, codeCnt); ! 265: ! 266: if (kr == KERN_SUCCESS || ! 267: kr == MACH_RCV_PORT_DIED) { ! 268: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code); ! 269: thread_exception_return(); ! 270: /* NOTREACHED*/ ! 271: return; ! 272: } ! 273: break; ! 274: ! 275: case EXCEPTION_STATE_IDENTITY: { ! 276: mach_msg_type_number_t state_cnt; ! 277: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 278: ! 279: c_thr_exc_raise_state_id++; ! 280: state_cnt = state_count[flavor]; ! 281: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 282: if (kr == KERN_SUCCESS) { ! 283: kr = exception_raise_state_identity(exc_port, ! 284: retrieve_act_self_fast(a_self), ! 285: retrieve_task_self_fast(a_self->task), ! 286: exception, ! 287: code, codeCnt, ! 288: &flavor, ! 289: state, state_cnt, ! 290: state, &state_cnt); ! 291: if (kr == MACH_MSG_SUCCESS) ! 292: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 293: } ! 294: ! 295: if (kr == KERN_SUCCESS || ! 296: kr == MACH_RCV_PORT_DIED) { ! 297: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code); ! 298: thread_exception_return(); ! 299: /* NOTREACHED*/ ! 300: return; ! 301: } ! 302: } break; ! 303: default: ! 304: panic ("bad behavior!"); ! 305: }/* switch */ ! 306: ! 307: /* ! 308: * When a task is being terminated, it's no longer ripped ! 309: * directly out of the rcv from its "kill me" message, and ! 310: * so returns here. The following causes it to return out ! 311: * to the glue code and clean itself up. ! 312: */ ! 313: if ((self->top_act && !self->top_act->active) || ! 314: (self->state & TH_ABORT)) { ! 315: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code); ! 316: thread_exception_return(); ! 317: } ! 318: ! 319: exception_try_task(exception, code, codeCnt); ! 320: /* NOTREACHED */ ! 321: } ! 322: ! 323: /* ! 324: * We only use the machine-independent exception() routine ! 325: * if a faster MD version isn't available. ! 326: */ ! 327: #else /* MACHINE_FAST_EXCEPTION */ ! 328: /* ! 329: * If continuations are not used/supported, the NOTREACHED comments ! 330: * below are incorrect. The exception function is expected to return. ! 331: * So the return statements along the slow paths are important. ! 332: */ ! 333: ! 334: /* ! 335: * Routine: exception ! 336: * Purpose: ! 337: * The current thread caught an exception. ! 338: * We make an up-call to the thread's exception server. ! 339: * Conditions: ! 340: * Nothing locked and no resources held. ! 341: * Called from an exception context, so ! 342: * thread_exception_return and thread_kdb_return ! 343: * are possible. ! 344: * Returns: ! 345: * Doesn't return. ! 346: */ ! 347: ! 348: void ! 349: exception( ! 350: exception_type_t exception, ! 351: exception_data_t code, ! 352: mach_msg_type_number_t codeCnt) ! 353: { ! 354: thread_t self = current_thread(); ! 355: thread_act_t a_self = self->top_act; ! 356: ipc_port_t exc_port; ! 357: int i; ! 358: struct exception_action *excp = &a_self->exc_actions[exception]; ! 359: int flavor; ! 360: kern_return_t kr; ! 361: ! 362: assert(exception != EXC_RPC_ALERT); ! 363: ! 364: if (exception == KERN_SUCCESS) ! 365: panic("exception"); ! 366: ! 367: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 368: ! 369: /* ! 370: * Optimized version of retrieve_thread_exception. ! 371: */ ! 372: ! 373: act_lock(a_self); ! 374: assert(a_self->ith_self != IP_NULL); ! 375: exc_port = excp->port; ! 376: if (!IP_VALID(exc_port)) { ! 377: act_unlock(a_self); ! 378: exception_try_task(exception, code, codeCnt); ! 379: /*NOTREACHED*/ ! 380: return; ! 381: } ! 382: flavor = excp->flavor; ! 383: ! 384: ip_lock(exc_port); ! 385: act_unlock(a_self); ! 386: if (!ip_active(exc_port)) { ! 387: ip_unlock(exc_port); ! 388: exception_try_task(exception, code, codeCnt); ! 389: /*NOTREACHED*/ ! 390: return; ! 391: } ! 392: ! 393: /* ! 394: * Hold a reference to the port over the exception_raise_* calls ! 395: * so it can't be destroyed. This seems like overkill, but keeps ! 396: * the port from disappearing between now and when ! 397: * ipc_object_copyin_from_kernel is finally called. ! 398: */ ! 399: ip_reference(exc_port); ! 400: exc_port->ip_srights++; ! 401: ip_unlock(exc_port); ! 402: ! 403: switch (excp->behavior) { ! 404: case EXCEPTION_STATE: { ! 405: mach_msg_type_number_t state_cnt; ! 406: ! 407: c_thr_exc_raise_state++; ! 408: { ! 409: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 410: ! 411: state_cnt = state_count[flavor]; ! 412: kr = thread_getstatus(a_self, flavor, ! 413: (thread_state_t)state, ! 414: &state_cnt); ! 415: if (kr == KERN_SUCCESS) { ! 416: kr = exception_raise_state(exc_port, exception, ! 417: code, codeCnt, ! 418: &flavor, ! 419: state, state_cnt, ! 420: state, &state_cnt); ! 421: if (kr == MACH_MSG_SUCCESS) ! 422: kr = thread_setstatus(a_self, flavor, ! 423: (thread_state_t)state, ! 424: state_cnt); ! 425: } ! 426: } ! 427: ! 428: if (kr == KERN_SUCCESS || ! 429: kr == MACH_RCV_PORT_DIED) { ! 430: thread_exception_return(); ! 431: /*NOTREACHED*/ ! 432: return; ! 433: } ! 434: } break; ! 435: ! 436: case EXCEPTION_DEFAULT: ! 437: c_thr_exc_raise++; ! 438: kr = exception_raise(exc_port, ! 439: retrieve_act_self_fast(a_self), ! 440: retrieve_task_self_fast(a_self->task), ! 441: exception, ! 442: code, codeCnt); ! 443: ! 444: if (kr == KERN_SUCCESS || ! 445: kr == MACH_RCV_PORT_DIED) { ! 446: thread_exception_return(); ! 447: /*NOTREACHED*/ ! 448: return; ! 449: } ! 450: break; ! 451: ! 452: case EXCEPTION_STATE_IDENTITY: { ! 453: mach_msg_type_number_t state_cnt; ! 454: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 455: ! 456: c_thr_exc_raise_state_id++; ! 457: state_cnt = state_count[flavor]; ! 458: kr = thread_getstatus(a_self, flavor, ! 459: (thread_state_t)state, ! 460: &state_cnt); ! 461: if (kr == KERN_SUCCESS) { ! 462: kr = exception_raise_state_identity(exc_port, ! 463: retrieve_act_self_fast(a_self), ! 464: retrieve_task_self_fast(a_self->task), ! 465: exception, ! 466: code, codeCnt, ! 467: &flavor, ! 468: state, state_cnt, ! 469: state, &state_cnt); ! 470: if (kr == MACH_MSG_SUCCESS) ! 471: kr = thread_setstatus(a_self, flavor, ! 472: (thread_state_t)state, ! 473: state_cnt); ! 474: } ! 475: ! 476: if (kr == KERN_SUCCESS || ! 477: kr == MACH_RCV_PORT_DIED) { ! 478: thread_exception_return(); ! 479: /*NOTREACHED*/ ! 480: return; ! 481: } ! 482: } break; ! 483: default: ! 484: panic ("bad behavior!"); ! 485: }/* switch */ ! 486: ! 487: /* ! 488: * When a task is being terminated, it's no longer ripped ! 489: * directly out of the rcv from its "kill me" message, and ! 490: * so returns here. The following causes it to return out ! 491: * to the glue code and clean itself up. ! 492: */ ! 493: if ((self->top_act && !self->top_act->active) || ! 494: (self->state & TH_ABORT)) { ! 495: thread_exception_return(); ! 496: /*NOTREACHED*/ ! 497: } ! 498: ! 499: exception_try_task(exception, code, codeCnt); ! 500: /* NOTREACHED */ ! 501: return; ! 502: } ! 503: #endif /* defined MACHINE_FAST_EXCEPTION */ ! 504: ! 505: /* ! 506: * Routine: exception_try_task ! 507: * Purpose: ! 508: * The current thread caught an exception. ! 509: * We make an up-call to the task's exception server. ! 510: * Conditions: ! 511: * Nothing locked and no resources held. ! 512: * Called from an exception context, so ! 513: * thread_exception_return and thread_kdb_return ! 514: * are possible. ! 515: * Returns: ! 516: * Doesn't return. ! 517: */ ! 518: ! 519: void ! 520: exception_try_task( ! 521: exception_type_t exception, ! 522: exception_data_t code, ! 523: mach_msg_type_number_t codeCnt) ! 524: { ! 525: thread_act_t a_self = current_act(); ! 526: thread_t self = a_self->thread; ! 527: register task_t task = a_self->task; ! 528: register ipc_port_t exc_port; ! 529: int flavor, i; ! 530: kern_return_t kr; ! 531: ! 532: assert(exception != EXC_RPC_ALERT); ! 533: ! 534: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 535: ! 536: /* ! 537: * Optimized version of retrieve_task_exception. ! 538: */ ! 539: ! 540: itk_lock(task); ! 541: assert(task->itk_self != IP_NULL); ! 542: exc_port = task->exc_actions[exception].port; ! 543: if (exception == EXC_MACH_SYSCALL && exc_port == realhost.host_self) { ! 544: itk_unlock(task); ! 545: restart_mach_syscall(); /* magic ! */ ! 546: /* NOTREACHED */ ! 547: } ! 548: if (!IP_VALID(exc_port)) { ! 549: itk_unlock(task); ! 550: exception_no_server(); ! 551: /*NOTREACHED*/ ! 552: return; ! 553: } ! 554: flavor = task->exc_actions[exception].flavor; ! 555: ! 556: ip_lock(exc_port); ! 557: itk_unlock(task); ! 558: if (!ip_active(exc_port)) { ! 559: ip_unlock(exc_port); ! 560: exception_no_server(); ! 561: /*NOTREACHED*/ ! 562: return; ! 563: } ! 564: ! 565: /* ! 566: * Hold a reference to the port over the exception_raise_* calls ! 567: * (see longer comment in exception()) ! 568: */ ! 569: ip_reference(exc_port); ! 570: exc_port->ip_srights++; ! 571: ip_unlock(exc_port); ! 572: ! 573: switch (task->exc_actions[exception].behavior) { ! 574: case EXCEPTION_STATE: { ! 575: mach_msg_type_number_t state_cnt; ! 576: { ! 577: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 578: ! 579: c_tsk_exc_raise_state++; ! 580: state_cnt = state_count[flavor]; ! 581: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 582: if (kr == KERN_SUCCESS) { ! 583: kr = exception_raise_state(exc_port, exception, ! 584: code, codeCnt, ! 585: &flavor, ! 586: state, state_cnt, ! 587: state, &state_cnt); ! 588: if (kr == MACH_MSG_SUCCESS) ! 589: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 590: } ! 591: } ! 592: ! 593: if (kr == KERN_SUCCESS || ! 594: kr == MACH_RCV_PORT_DIED) { ! 595: ETAP_EXCEPTION_PROBE(EVENT_END, self, exception, code); ! 596: thread_exception_return(); ! 597: /* NOTREACHED*/ ! 598: return; ! 599: } ! 600: } break; ! 601: ! 602: case EXCEPTION_DEFAULT: ! 603: c_tsk_exc_raise++; ! 604: kr = exception_raise(exc_port, ! 605: retrieve_act_self_fast(a_self), ! 606: retrieve_task_self_fast(a_self->task), ! 607: exception, code, codeCnt); ! 608: ! 609: if (kr == KERN_SUCCESS || ! 610: kr == MACH_RCV_PORT_DIED) { ! 611: thread_exception_return(); ! 612: /*NOTREACHED*/ ! 613: return; ! 614: } ! 615: break; ! 616: ! 617: case EXCEPTION_STATE_IDENTITY: { ! 618: mach_msg_type_number_t state_cnt; ! 619: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 620: ! 621: c_tsk_exc_raise_state_id++; ! 622: state_cnt = state_count[flavor]; ! 623: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 624: if (kr == KERN_SUCCESS) { ! 625: kr = exception_raise_state_identity(exc_port, ! 626: retrieve_act_self_fast(a_self), ! 627: retrieve_task_self_fast(a_self->task), ! 628: exception, ! 629: code, codeCnt, ! 630: &flavor, ! 631: state, state_cnt, ! 632: state, &state_cnt); ! 633: if (kr == KERN_SUCCESS) ! 634: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 635: } ! 636: ! 637: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) { ! 638: thread_exception_return(); ! 639: /*NOTREACHED*/ ! 640: return; ! 641: } ! 642: } break; ! 643: ! 644: default: ! 645: panic ("bad behavior!"); ! 646: }/* switch */ ! 647: ! 648: exception_no_server(); ! 649: /*NOTREACHED*/ ! 650: } ! 651: ! 652: /* ! 653: * Routine: exception_no_server ! 654: * Purpose: ! 655: * The current thread took an exception, ! 656: * and no exception server took responsibility ! 657: * for the exception. So good bye, charlie. ! 658: * Conditions: ! 659: * Nothing locked and no resources held. ! 660: * Called from an exception context, so ! 661: * thread_kdb_return is possible. ! 662: * Returns: ! 663: * Doesn't return. ! 664: */ ! 665: ! 666: void ! 667: exception_no_server(void) ! 668: { ! 669: register thread_t self = current_thread(); ! 670: ! 671: /* ! 672: * If this thread is being terminated, cooperate. ! 673: * ! 674: * When a task is dying, it's no longer ripped ! 675: * directly out of the rcv from its "kill me" message, and ! 676: * so returns here. The following causes it to return out ! 677: * to the glue code and clean itself up. ! 678: */ ! 679: if ((thread_should_halt(self)) || (self->state & TH_ABORT)) { ! 680: thread_exception_return(); ! 681: panic("exception_no_server - 1"); ! 682: } ! 683: ! 684: ! 685: if (self->top_act->task == kernel_task) ! 686: panic("kernel task terminating\n"); ! 687: ! 688: #if MACH_KDB ! 689: if (debug_user_with_kdb) { ! 690: /* ! 691: * Debug the exception with kdb. ! 692: * If kdb handles the exception, ! 693: * then thread_kdb_return won't return. ! 694: */ ! 695: db_printf("No exception server, calling kdb...\n"); ! 696: #if iPSC860 ! 697: db_printf("Dropping into ddb, avoiding thread_kdb_return\n"); ! 698: gimmeabreak(); ! 699: #endif ! 700: thread_kdb_return(); ! 701: } ! 702: #endif /* MACH_KDB */ ! 703: ! 704: /* ! 705: * All else failed; terminate task. ! 706: */ ! 707: ! 708: (void) task_terminate(self->top_act->task); ! 709: thread_terminate_self(); ! 710: /*NOTREACHED*/ ! 711: panic("exception_no_server: returning!"); ! 712: } ! 713: ! 714: #ifdef MACHINE_FAST_EXCEPTION /* from <machine/thread.h> if at all */ ! 715: /* ! 716: * Routine: alert_exception ! 717: * Purpose: ! 718: * The current thread caught an exception. ! 719: * We make an up-call to the thread's exception server. ! 720: * Conditions: ! 721: * Nothing locked and no resources held. ! 722: * Returns: ! 723: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated ! 724: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to ! 725: * continue execution ! 726: */ ! 727: ! 728: kern_return_t ! 729: alert_exception( ! 730: exception_type_t exception, ! 731: exception_data_t code, ! 732: int codeCnt ) ! 733: { ! 734: thread_t self = current_thread(); ! 735: thread_act_t a_self = self->top_act; ! 736: thread_act_t cln_act; ! 737: ipc_port_t exc_port; ! 738: int i; ! 739: struct exception_action *excp = &a_self->exc_actions[exception]; ! 740: int flavor; ! 741: kern_return_t kr; ! 742: ! 743: assert(exception == EXC_RPC_ALERT); ! 744: ! 745: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 746: ! 747: /* ! 748: * Optimized version of retrieve_thread_exception. ! 749: */ ! 750: ! 751: act_lock(a_self); ! 752: assert(a_self->ith_self != IP_NULL); ! 753: exc_port = excp->port; ! 754: if (!IP_VALID(exc_port)) { ! 755: act_unlock(a_self); ! 756: return(alert_exception_try_task(exception, code, codeCnt)); ! 757: } ! 758: flavor = excp->flavor; ! 759: ! 760: #ifdef i386 ! 761: /* For this flavor, we must copy in the first few procedure call ! 762: * args from the user's stack, since that is part of the important ! 763: * state in a syscall exception (this is for performance -- we ! 764: * can do the copyin much faster than the server, even if it is ! 765: * kernel-loaded): ! 766: */ ! 767: if (flavor == i386_SAVED_STATE) { ! 768: struct i386_saved_state *statep = (struct i386_saved_state *) ! 769: act_machine_state_ptr(self->top_act); ! 770: statep->argv_status = FALSE; ! 771: if (syscall_exc_copyin && copyin((char *)statep->uesp, ! 772: (char *)statep->argv, ! 773: i386_SAVED_ARGV_COUNT * sizeof(int)) == 0) { ! 774: /* Indicate success for the server: */ ! 775: statep->argv_status = TRUE; ! 776: } ! 777: } ! 778: #endif ! 779: ! 780: ip_lock(exc_port); ! 781: act_unlock(a_self); ! 782: if (!ip_active(exc_port)) { ! 783: ip_unlock(exc_port); ! 784: return(alert_exception_try_task(exception, code, codeCnt)); ! 785: } ! 786: ! 787: /* ! 788: * Hold a reference to the port over the exception_raise_* calls ! 789: * so it can't be destroyed. This seems like overkill, but keeps ! 790: * the port from disappearing between now and when ! 791: * ipc_object_copyin_from_kernel is finally called. ! 792: */ ! 793: ip_reference(exc_port); ! 794: /* CHECKME! */ ! 795: /* exc_port->ip_srights++; ipc_object_copy_from_kernel does this */ ! 796: ip_unlock(exc_port); ! 797: ! 798: switch (excp->behavior) { ! 799: case EXCEPTION_STATE: { ! 800: mach_msg_type_number_t state_cnt; ! 801: { ! 802: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 803: ! 804: state_cnt = state_count[flavor]; ! 805: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 806: if (kr == KERN_SUCCESS) { ! 807: kr = exception_raise_state(exc_port, exception, ! 808: code, codeCnt, ! 809: &flavor, ! 810: state, state_cnt, ! 811: state, &state_cnt); ! 812: if (kr == MACH_MSG_SUCCESS) ! 813: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 814: } ! 815: } ! 816: ip_lock(exc_port); ! 817: ip_release(exc_port); ! 818: ip_unlock(exc_port); ! 819: ! 820: if (kr == KERN_SUCCESS || ! 821: kr == MACH_RCV_PORT_DIED) { ! 822: return(KERN_RPC_TERMINATE_ORPHAN); ! 823: } ! 824: } break; ! 825: ! 826: case EXCEPTION_DEFAULT: ! 827: c_thr_exc_raise++; ! 828: kr = exception_raise(exc_port, ! 829: retrieve_act_self_fast(a_self), ! 830: retrieve_task_self_fast(a_self->task), ! 831: exception, ! 832: code, codeCnt); ! 833: ip_lock(exc_port); ! 834: ip_release(exc_port); ! 835: ip_unlock(exc_port); ! 836: ! 837: if (kr == KERN_SUCCESS || ! 838: kr == MACH_RCV_PORT_DIED) { ! 839: return(KERN_RPC_TERMINATE_ORPHAN); ! 840: } ! 841: break; ! 842: ! 843: case EXCEPTION_STATE_IDENTITY: { ! 844: mach_msg_type_number_t state_cnt; ! 845: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 846: ! 847: c_thr_exc_raise_state_id++; ! 848: state_cnt = state_count[flavor]; ! 849: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 850: if (kr == KERN_SUCCESS) { ! 851: kr = exception_raise_state_identity(exc_port, ! 852: retrieve_act_self_fast(a_self), ! 853: retrieve_task_self_fast(a_self->task), ! 854: exception, ! 855: code, codeCnt, ! 856: &flavor, ! 857: state, state_cnt, ! 858: state, &state_cnt); ! 859: if (kr == MACH_MSG_SUCCESS) ! 860: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 861: } ! 862: ip_lock(exc_port); ! 863: ip_release(exc_port); ! 864: ip_unlock(exc_port); ! 865: ! 866: if (kr == KERN_SUCCESS || ! 867: kr == MACH_RCV_PORT_DIED) { ! 868: return(KERN_RPC_TERMINATE_ORPHAN); ! 869: } ! 870: } break; ! 871: default: ! 872: panic ("bad behavior!"); ! 873: }/* switch */ ! 874: ! 875: /* ! 876: * When a task is being terminated, it's no longer ripped ! 877: * directly out of the rcv from its "kill me" message, and ! 878: * so returns here. The following causes it to return out ! 879: * to the glue code and clean itself up. ! 880: */ ! 881: if (self->top_act && !self->top_act->active) ! 882: return(KERN_RPC_TERMINATE_ORPHAN); ! 883: ! 884: return(alert_exception_try_task(exception, code, codeCnt)); ! 885: } ! 886: #else /* MACHINE_FAST_EXCEPTION */ ! 887: ! 888: /* ! 889: * Routine: alert_exception ! 890: * Purpose: ! 891: * The current thread caught an exception. ! 892: * We make an up-call to the thread's exception server. ! 893: * Conditions: ! 894: * Nothing locked and no resources held. ! 895: * Returns: ! 896: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated ! 897: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to ! 898: * continue execution ! 899: */ ! 900: ! 901: kern_return_t ! 902: alert_exception( ! 903: exception_type_t exception, ! 904: exception_data_t code, ! 905: int codeCnt ) ! 906: { ! 907: thread_t self = current_thread(); ! 908: thread_act_t a_self = self->top_act; ! 909: ipc_port_t exc_port; ! 910: int i; ! 911: struct exception_action *excp = &a_self->exc_actions[exception]; ! 912: int flavor; ! 913: kern_return_t kr; ! 914: ! 915: assert(exception == EXC_RPC_ALERT); ! 916: ! 917: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 918: ! 919: /* ! 920: * Optimized version of retrieve_thread_exception. ! 921: */ ! 922: ! 923: act_lock(a_self); ! 924: assert(a_self->ith_self != IP_NULL); ! 925: exc_port = excp->port; ! 926: if (!IP_VALID(exc_port)) { ! 927: act_unlock(a_self); ! 928: return(alert_exception_try_task(exception, code, codeCnt)); ! 929: } ! 930: flavor = excp->flavor; ! 931: ! 932: ip_lock(exc_port); ! 933: act_unlock(a_self); ! 934: if (!ip_active(exc_port)) { ! 935: ip_unlock(exc_port); ! 936: return(alert_exception_try_task(exception, code, codeCnt)); ! 937: } ! 938: ! 939: /* ! 940: * Hold a reference to the port over the exception_raise_* calls ! 941: * so it can't be destroyed. This seems like overkill, but keeps ! 942: * the port from disappearing between now and when ! 943: * ipc_object_copyin_from_kernel is finally called. ! 944: */ ! 945: ip_reference(exc_port); ! 946: /* CHECKME! */ ! 947: /* exc_port->ip_srights++; ipc_object_copy_from_kernel does this */ ! 948: ip_unlock(exc_port); ! 949: ! 950: switch (excp->behavior) { ! 951: case EXCEPTION_STATE: { ! 952: mach_msg_type_number_t state_cnt; ! 953: rpc_subsystem_t subsystem = ((ipc_port_t)exc_port)->ip_subsystem; ! 954: ! 955: c_thr_exc_raise_state++; ! 956: if (flavor == MACHINE_THREAD_STATE && ! 957: subsystem && ! 958: is_fast_space(exc_port->ip_receiver)) { ! 959: natural_t *statep; ! 960: /* Requested flavor is the same format in which ! 961: * we save state on this machine, so no copy is ! 962: * necessary. Obtain direct pointer to saved state: ! 963: */ ! 964: statep = act_machine_state_ptr(self->top_act); ! 965: state_cnt = MACHINE_THREAD_STATE_COUNT; ! 966: kr = exception_raise_state(exc_port, exception, ! 967: code, codeCnt, ! 968: &flavor, ! 969: statep, state_cnt, ! 970: statep, &state_cnt); ! 971: /* Server is required to return same flavor: */ ! 972: assert(flavor == MACHINE_THREAD_STATE); ! 973: } else { ! 974: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 975: ! 976: state_cnt = state_count[flavor]; ! 977: kr = thread_getstatus(a_self, flavor, ! 978: (thread_state_t)state, ! 979: &state_cnt); ! 980: if (kr == KERN_SUCCESS) { ! 981: kr = exception_raise_state(exc_port, exception, ! 982: code, codeCnt, ! 983: &flavor, ! 984: state, state_cnt, ! 985: state, &state_cnt); ! 986: if (kr == MACH_MSG_SUCCESS) ! 987: kr = thread_setstatus(a_self, flavor, ! 988: (thread_state_t)state, ! 989: state_cnt); ! 990: } ! 991: } ! 992: ip_lock(exc_port); ! 993: ip_release(exc_port); ! 994: ip_unlock(exc_port); ! 995: ! 996: if (kr == KERN_SUCCESS || ! 997: kr == MACH_RCV_PORT_DIED) { ! 998: return(KERN_RPC_TERMINATE_ORPHAN); ! 999: } ! 1000: } break; ! 1001: ! 1002: case EXCEPTION_DEFAULT: ! 1003: c_thr_exc_raise++; ! 1004: kr = exception_raise(exc_port, ! 1005: retrieve_act_self_fast(a_self), ! 1006: retrieve_task_self_fast(a_self->task), ! 1007: exception, ! 1008: code, codeCnt); ! 1009: ip_lock(exc_port); ! 1010: ip_release(exc_port); ! 1011: ip_unlock(exc_port); ! 1012: ! 1013: if (kr == KERN_SUCCESS || ! 1014: kr == MACH_RCV_PORT_DIED) { ! 1015: return(KERN_RPC_TERMINATE_ORPHAN); ! 1016: } ! 1017: break; ! 1018: ! 1019: case EXCEPTION_STATE_IDENTITY: { ! 1020: mach_msg_type_number_t state_cnt; ! 1021: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 1022: ! 1023: c_thr_exc_raise_state_id++; ! 1024: state_cnt = state_count[flavor]; ! 1025: kr = thread_getstatus(a_self, flavor, ! 1026: (thread_state_t)state, ! 1027: &state_cnt); ! 1028: if (kr == KERN_SUCCESS) { ! 1029: kr = exception_raise_state_identity(exc_port, ! 1030: retrieve_act_self_fast(a_self), ! 1031: retrieve_task_self_fast(a_self->task), ! 1032: exception, ! 1033: code, codeCnt, ! 1034: &flavor, ! 1035: state, state_cnt, ! 1036: state, &state_cnt); ! 1037: if (kr == MACH_MSG_SUCCESS) ! 1038: kr = thread_setstatus(a_self, flavor, ! 1039: (thread_state_t)state, ! 1040: state_cnt); ! 1041: } ! 1042: ip_lock(exc_port); ! 1043: ip_release(exc_port); ! 1044: ip_unlock(exc_port); ! 1045: ! 1046: if (kr == KERN_SUCCESS || ! 1047: kr == MACH_RCV_PORT_DIED) { ! 1048: return(KERN_RPC_TERMINATE_ORPHAN); ! 1049: } ! 1050: } break; ! 1051: default: ! 1052: panic ("bad behavior!"); ! 1053: }/* switch */ ! 1054: ! 1055: /* ! 1056: * When a task is being terminated, it's no longer ripped ! 1057: * directly out of the rcv from its "kill me" message, and ! 1058: * so returns here. The following causes it to return out ! 1059: * to the glue code and clean itself up. ! 1060: */ ! 1061: if (thread_should_halt(self)) { ! 1062: return(KERN_RPC_TERMINATE_ORPHAN); ! 1063: } ! 1064: ! 1065: return(alert_exception_try_task(exception, code, codeCnt)); ! 1066: } ! 1067: #endif /* defined MACHINE_FAST_EXCEPTION */ ! 1068: ! 1069: /* ! 1070: * Routine: alert_exception_try_task ! 1071: * Purpose: ! 1072: * The current thread caught an exception. ! 1073: * We make an up-call to the task's exception server. ! 1074: * Conditions: ! 1075: * Nothing locked and no resources held. ! 1076: * Returns: ! 1077: * KERN_RPC_TERMINATE_ORPHAN - if orphan should be terminated ! 1078: * KERN_RPC_CONTINUE_ORPHAN - if orphan should be allowed to ! 1079: * continue execution ! 1080: */ ! 1081: ! 1082: kern_return_t ! 1083: alert_exception_try_task( ! 1084: exception_type_t exception, ! 1085: exception_data_t code, ! 1086: int codeCnt ) ! 1087: { ! 1088: thread_act_t a_self = current_act(); ! 1089: thread_t self = a_self->thread; ! 1090: register task_t task = a_self->task; ! 1091: register ipc_port_t exc_port; ! 1092: int flavor; ! 1093: kern_return_t kr; ! 1094: ! 1095: assert(exception == EXC_RPC_ALERT); ! 1096: ! 1097: self->ith_scatter_list = MACH_MSG_BODY_NULL; ! 1098: ! 1099: /* ! 1100: * Optimized version of retrieve_task_exception. ! 1101: */ ! 1102: ! 1103: itk_lock(task); ! 1104: assert(task->itk_self != IP_NULL); ! 1105: exc_port = task->exc_actions[exception].port; ! 1106: if (!IP_VALID(exc_port)) { ! 1107: itk_unlock(task); ! 1108: return(KERN_RPC_CONTINUE_ORPHAN); ! 1109: } ! 1110: flavor = task->exc_actions[exception].flavor; ! 1111: ! 1112: ip_lock(exc_port); ! 1113: itk_unlock(task); ! 1114: if (!ip_active(exc_port)) { ! 1115: ip_unlock(exc_port); ! 1116: return(KERN_RPC_CONTINUE_ORPHAN); ! 1117: } ! 1118: ! 1119: /* ! 1120: * Hold a reference to the port over the exception_raise_* calls ! 1121: * (see longer comment in exception()) ! 1122: */ ! 1123: ip_reference(exc_port); ! 1124: /* CHECKME! */ ! 1125: /* exc_port->ip_srights++; */ ! 1126: ip_unlock(exc_port); ! 1127: ! 1128: switch (task->exc_actions[exception].behavior) { ! 1129: case EXCEPTION_STATE: { ! 1130: mach_msg_type_number_t state_cnt; ! 1131: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 1132: ! 1133: c_tsk_exc_raise_state++; ! 1134: state_cnt = state_count[flavor]; ! 1135: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 1136: if (kr == KERN_SUCCESS) { ! 1137: kr = exception_raise_state(exc_port, exception, ! 1138: code, codeCnt, ! 1139: &flavor, ! 1140: state, state_cnt, ! 1141: state, &state_cnt); ! 1142: if (kr == KERN_SUCCESS) ! 1143: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 1144: } ! 1145: ip_lock(exc_port); ! 1146: ip_release(exc_port); ! 1147: ip_unlock(exc_port); ! 1148: ! 1149: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) { ! 1150: return(KERN_RPC_TERMINATE_ORPHAN); ! 1151: } ! 1152: } break; ! 1153: ! 1154: case EXCEPTION_DEFAULT: ! 1155: c_tsk_exc_raise++; ! 1156: kr = exception_raise(exc_port, ! 1157: retrieve_act_self_fast(a_self), ! 1158: retrieve_task_self_fast(a_self->task), ! 1159: exception, code, codeCnt); ! 1160: ip_lock(exc_port); ! 1161: ip_release(exc_port); ! 1162: ip_unlock(exc_port); ! 1163: ! 1164: if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { ! 1165: return(KERN_RPC_TERMINATE_ORPHAN); ! 1166: } ! 1167: break; ! 1168: ! 1169: case EXCEPTION_STATE_IDENTITY: { ! 1170: mach_msg_type_number_t state_cnt; ! 1171: natural_t state[ THREAD_MACHINE_STATE_MAX ]; ! 1172: ! 1173: c_tsk_exc_raise_state_id++; ! 1174: state_cnt = state_count[flavor]; ! 1175: kr = thread_getstatus(a_self, flavor, state, &state_cnt); ! 1176: if (kr == KERN_SUCCESS) { ! 1177: kr = exception_raise_state_identity(exc_port, ! 1178: retrieve_act_self_fast(a_self), ! 1179: retrieve_task_self_fast(a_self->task), ! 1180: exception, ! 1181: code, codeCnt, ! 1182: &flavor, ! 1183: state, state_cnt, ! 1184: state, &state_cnt); ! 1185: if (kr == KERN_SUCCESS) ! 1186: kr = thread_setstatus(a_self, flavor, state, state_cnt); ! 1187: } ! 1188: ip_lock(exc_port); ! 1189: ip_release(exc_port); ! 1190: ip_unlock(exc_port); ! 1191: ! 1192: if (kr == MACH_MSG_SUCCESS || kr == MACH_RCV_PORT_DIED) { ! 1193: return(KERN_RPC_TERMINATE_ORPHAN); ! 1194: } ! 1195: } break; ! 1196: ! 1197: default: ! 1198: panic ("bad behavior!"); ! 1199: }/* switch */ ! 1200: ! 1201: return(KERN_RPC_CONTINUE_ORPHAN); ! 1202: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.