|
|
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 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: * Hardware trap/fault handler. ! 54: */ ! 55: ! 56: #include <cpus.h> ! 57: #include <fast_idle.h> ! 58: #include <mach_kdb.h> ! 59: #include <mach_kgdb.h> ! 60: #include <mach_kdp.h> ! 61: #include <mach_ldebug.h> ! 62: ! 63: #include <types.h> ! 64: #include <i386/eflags.h> ! 65: #include <i386/trap.h> ! 66: #include <i386/pmap.h> ! 67: #include <i386/fpu.h> ! 68: ! 69: #include <mach/exception.h> ! 70: #include <mach/kern_return.h> ! 71: #include <mach/vm_param.h> ! 72: #include <mach/i386/thread_status.h> ! 73: ! 74: #include <vm/vm_kern.h> ! 75: #include <vm/vm_fault.h> ! 76: ! 77: #include <kern/etap_macros.h> ! 78: #include <kern/kern_types.h> ! 79: #include <kern/ast.h> ! 80: #include <kern/thread.h> ! 81: #include <kern/task.h> ! 82: #include <kern/sched.h> ! 83: #include <kern/sched_prim.h> ! 84: #include <kern/exception.h> ! 85: #include <kern/spl.h> ! 86: #include <kern/misc_protos.h> ! 87: ! 88: #if MACH_KGDB ! 89: #include <kgdb/kgdb_defs.h> ! 90: #endif /* MACH_KGDB */ ! 91: ! 92: #include <i386/intel_read_fault.h> ! 93: ! 94: #if MACH_KGDB ! 95: #include <kgdb/kgdb_defs.h> ! 96: #endif /* MACH_KGDB */ ! 97: ! 98: #if MACH_KDB ! 99: #include <ddb/db_watch.h> ! 100: #include <ddb/db_run.h> ! 101: #include <ddb/db_break.h> ! 102: #include <ddb/db_trap.h> ! 103: #endif /* MACH_KDB */ ! 104: ! 105: #include <string.h> ! 106: ! 107: #include <i386/io_emulate.h> ! 108: ! 109: /* ! 110: * Forward declarations ! 111: */ ! 112: extern void user_page_fault_continue( ! 113: kern_return_t kr); ! 114: ! 115: extern boolean_t v86_assist( ! 116: thread_t thread, ! 117: struct i386_saved_state *regs); ! 118: ! 119: extern boolean_t check_io_fault( ! 120: struct i386_saved_state *regs); ! 121: ! 122: extern int inst_fetch( ! 123: int eip, ! 124: int cs); ! 125: ! 126: #if MACH_KDB ! 127: boolean_t debug_all_traps_with_kdb = FALSE; ! 128: extern struct db_watchpoint *db_watchpoint_list; ! 129: extern boolean_t db_watchpoints_inserted; ! 130: extern boolean_t db_breakpoints_inserted; ! 131: ! 132: void ! 133: thread_kdb_return(void) ! 134: { ! 135: register thread_act_t thr_act = current_act(); ! 136: register thread_t cur_thr = current_thread(); ! 137: register struct i386_saved_state *regs = USER_REGS(thr_act); ! 138: ! 139: if (kdb_trap(regs->trapno, regs->err, regs)) { ! 140: #if MACH_LDEBUG ! 141: assert(cur_thr->mutex_count == 0); ! 142: #endif /* MACH_LDEBUG */ ! 143: check_simple_locks(); ! 144: thread_exception_return(); ! 145: /*NOTREACHED*/ ! 146: } ! 147: } ! 148: boolean_t let_ddb_vm_fault = FALSE; ! 149: ! 150: #if NCPUS > 1 ! 151: extern int kdb_active[NCPUS]; ! 152: #endif /* NCPUS > 1 */ ! 153: ! 154: #endif /* MACH_KDB */ ! 155: ! 156: void ! 157: user_page_fault_continue( ! 158: kern_return_t kr) ! 159: { ! 160: register thread_act_t thr_act = current_act(); ! 161: register thread_t cur_thr = current_thread(); ! 162: register struct i386_saved_state *regs = USER_REGS(thr_act); ! 163: ! 164: if (kr == KERN_SUCCESS) { ! 165: #if MACH_KDB ! 166: if (!db_breakpoints_inserted) { ! 167: db_set_breakpoints(); ! 168: } ! 169: if (db_watchpoint_list && ! 170: db_watchpoints_inserted && ! 171: (regs->err & T_PF_WRITE) && ! 172: db_find_watchpoint(thr_act->map, ! 173: (vm_offset_t)regs->cr2, ! 174: regs)) ! 175: kdb_trap(T_WATCHPOINT, 0, regs); ! 176: #endif /* MACH_KDB */ ! 177: thread_exception_return(); ! 178: /*NOTREACHED*/ ! 179: } ! 180: ! 181: #if MACH_KDB ! 182: if (debug_all_traps_with_kdb && ! 183: kdb_trap(regs->trapno, regs->err, regs)) { ! 184: #if MACH_LDEBUG ! 185: assert(cur_thr->mutex_count == 0); ! 186: #endif /* MACH_LDEBUG */ ! 187: check_simple_locks(); ! 188: thread_exception_return(); ! 189: /*NOTREACHED*/ ! 190: } ! 191: #endif /* MACH_KDB */ ! 192: ! 193: i386_exception(EXC_BAD_ACCESS, kr, regs->cr2); ! 194: /*NOTREACHED*/ ! 195: } ! 196: ! 197: /* ! 198: * Fault recovery in copyin/copyout routines. ! 199: */ ! 200: struct recovery { ! 201: int fault_addr; ! 202: int recover_addr; ! 203: }; ! 204: ! 205: extern struct recovery recover_table[]; ! 206: extern struct recovery recover_table_end[]; ! 207: ! 208: /* ! 209: * Recovery from Successful fault in copyout does not ! 210: * return directly - it retries the pte check, since ! 211: * the 386 ignores write protection in kernel mode. ! 212: */ ! 213: extern struct recovery retry_table[]; ! 214: extern struct recovery retry_table_end[]; ! 215: ! 216: char * trap_type[] = {TRAP_NAMES}; ! 217: int TRAP_TYPES = sizeof(trap_type)/sizeof(trap_type[0]); ! 218: ! 219: /* ! 220: * Trap from kernel mode. Only page-fault errors are recoverable, ! 221: * and then only in special circumstances. All other errors are ! 222: * fatal. Return value indicates if trap was handled. ! 223: */ ! 224: boolean_t ! 225: kernel_trap( ! 226: register struct i386_saved_state *regs) ! 227: { ! 228: int exc; ! 229: int code; ! 230: int subcode; ! 231: register int type; ! 232: vm_map_t map; ! 233: kern_return_t result; ! 234: register thread_t thread; ! 235: thread_act_t thr_act; ! 236: etap_data_t probe_data; ! 237: pt_entry_t *pte; ! 238: extern vm_offset_t vm_last_phys; ! 239: ! 240: type = regs->trapno; ! 241: code = regs->err; ! 242: thread = current_thread(); ! 243: thr_act = current_act(); ! 244: ! 245: ETAP_DATA_LOAD(probe_data[0], regs->trapno); ! 246: ETAP_DATA_LOAD(probe_data[1], MACH_PORT_NULL); ! 247: ETAP_DATA_LOAD(probe_data[2], MACH_PORT_NULL); ! 248: ETAP_PROBE_DATA(ETAP_P_EXCEPTION, ! 249: 0, ! 250: thread, ! 251: &probe_data, ! 252: ETAP_DATA_ENTRY*3); ! 253: ! 254: switch (type) { ! 255: case T_PREEMPT: ! 256: return (TRUE); ! 257: ! 258: case T_NO_FPU: ! 259: fpnoextflt(); ! 260: return (TRUE); ! 261: ! 262: case T_FPU_FAULT: ! 263: fpextovrflt(); ! 264: return (TRUE); ! 265: ! 266: case T_FLOATING_POINT_ERROR: ! 267: fpexterrflt(); ! 268: return (TRUE); ! 269: ! 270: case T_PAGE_FAULT: ! 271: /* ! 272: * If the current map is a submap of the kernel map, ! 273: * and the address is within that map, fault on that ! 274: * map. If the same check is done in vm_fault ! 275: * (vm_map_lookup), we may deadlock on the kernel map ! 276: * lock. ! 277: */ ! 278: #if MACH_KDB ! 279: mp_disable_preemption(); ! 280: if (db_active ! 281: #if NCPUS > 1 ! 282: && kdb_active[cpu_number()] ! 283: #endif /* NCPUS > 1 */ ! 284: && !let_ddb_vm_fault) { ! 285: /* ! 286: * Force kdb to handle this one. ! 287: */ ! 288: mp_enable_preemption(); ! 289: return (FALSE); ! 290: } ! 291: mp_enable_preemption(); ! 292: #endif /* MACH_KDB */ ! 293: subcode = regs->cr2; /* get faulting address */ ! 294: ! 295: if (subcode > LINEAR_KERNEL_ADDRESS) { ! 296: map = kernel_map; ! 297: subcode -= LINEAR_KERNEL_ADDRESS; ! 298: } else if (thr_act == THR_ACT_NULL || thread == THREAD_NULL) ! 299: map = kernel_map; ! 300: else { ! 301: map = thr_act->map; ! 302: } ! 303: ! 304: #if MACH_KDB ! 305: /* ! 306: * Check for watchpoint on kernel static data. ! 307: * vm_fault would fail in this case ! 308: */ ! 309: if (map == kernel_map && ! 310: db_watchpoint_list && ! 311: db_watchpoints_inserted && ! 312: (code & T_PF_WRITE) && ! 313: (vm_offset_t)subcode < vm_last_phys && ! 314: ((*(pte = pmap_pte(kernel_pmap, (vm_offset_t)subcode))) & ! 315: INTEL_PTE_WRITE) == 0) { ! 316: *pte = INTEL_PTE_VALID | INTEL_PTE_WRITE | ! 317: pa_to_pte(trunc_page((vm_offset_t)subcode) - ! 318: VM_MIN_KERNEL_ADDRESS); ! 319: result = KERN_SUCCESS; ! 320: } else ! 321: #endif /* MACH_KDB */ ! 322: { ! 323: /* ! 324: * Since the 386 ignores write protection in ! 325: * kernel mode, always try for write permission ! 326: * first. If that fails and the fault was a ! 327: * read fault, retry with read permission. ! 328: */ ! 329: result = vm_fault(map, ! 330: trunc_page((vm_offset_t)subcode), ! 331: VM_PROT_READ|VM_PROT_WRITE, ! 332: FALSE); ! 333: } ! 334: #if MACH_KDB ! 335: if (result == KERN_SUCCESS) { ! 336: /* Look for watchpoints */ ! 337: if (db_watchpoint_list && ! 338: db_watchpoints_inserted && ! 339: (code & T_PF_WRITE) && ! 340: db_find_watchpoint(map, ! 341: (vm_offset_t)subcode, regs)) ! 342: kdb_trap(T_WATCHPOINT, 0, regs); ! 343: } ! 344: else ! 345: #endif /* MACH_KDB */ ! 346: if ((code & T_PF_WRITE) == 0 && ! 347: result == KERN_PROTECTION_FAILURE) ! 348: { ! 349: /* ! 350: * Must expand vm_fault by hand, ! 351: * so that we can ask for read-only access ! 352: * but enter a (kernel)writable mapping. ! 353: */ ! 354: result = intel_read_fault(map, ! 355: trunc_page((vm_offset_t)subcode)); ! 356: } ! 357: ! 358: if (result == KERN_SUCCESS) { ! 359: /* ! 360: * Certain faults require that we back up ! 361: * the EIP. ! 362: */ ! 363: register struct recovery *rp; ! 364: ! 365: for (rp = retry_table; rp < retry_table_end; rp++) { ! 366: if (regs->eip == rp->fault_addr) { ! 367: regs->eip = rp->recover_addr; ! 368: break; ! 369: } ! 370: } ! 371: return (TRUE); ! 372: } ! 373: ! 374: /* fall through */ ! 375: ! 376: case T_GENERAL_PROTECTION: ! 377: ! 378: /* ! 379: * If there is a failure recovery address ! 380: * for this fault, go there. ! 381: */ ! 382: { ! 383: register struct recovery *rp; ! 384: ! 385: for (rp = recover_table; ! 386: rp < recover_table_end; ! 387: rp++) { ! 388: if (regs->eip == rp->fault_addr) { ! 389: regs->eip = rp->recover_addr; ! 390: return (TRUE); ! 391: } ! 392: } ! 393: } ! 394: ! 395: /* ! 396: * Check thread recovery address also - ! 397: * v86 assist uses it. ! 398: */ ! 399: if (thread->recover) { ! 400: regs->eip = thread->recover; ! 401: thread->recover = 0; ! 402: return (TRUE); ! 403: } ! 404: ! 405: /* ! 406: * Unanticipated page-fault errors in kernel ! 407: * should not happen. ! 408: */ ! 409: /* fall through... */ ! 410: ! 411: default: ! 412: /* ! 413: * ...and return failure, so that locore can call into ! 414: * debugger. ! 415: */ ! 416: #if MACH_KDP ! 417: kdp_i386_trap(type, regs, result, regs->cr2); ! 418: #endif ! 419: return (FALSE); ! 420: } ! 421: return (TRUE); ! 422: } ! 423: ! 424: /* ! 425: * Called if both kernel_trap() and kdb_trap() fail. ! 426: */ ! 427: void ! 428: panic_trap( ! 429: register struct i386_saved_state *regs) ! 430: { ! 431: int code; ! 432: register int type; ! 433: ! 434: type = regs->trapno; ! 435: code = regs->err; ! 436: ! 437: printf("trap type %d, code = %x, pc = %x\n", ! 438: type, code, regs->eip); ! 439: panic("trap"); ! 440: } ! 441: ! 442: ! 443: /* ! 444: * Trap from user mode. ! 445: */ ! 446: void ! 447: user_trap( ! 448: register struct i386_saved_state *regs) ! 449: { ! 450: int exc; ! 451: int code; ! 452: int subcode; ! 453: register int type; ! 454: vm_map_t map; ! 455: vm_prot_t prot; ! 456: kern_return_t result; ! 457: register thread_act_t thr_act = current_act(); ! 458: thread_t thread = (thr_act ? thr_act->thread : THREAD_NULL); ! 459: boolean_t kernel_act = thr_act->kernel_loaded; ! 460: etap_data_t probe_data; ! 461: ! 462: if (regs->efl & EFL_VM) { ! 463: /* ! 464: * If hardware assist can handle exception, ! 465: * continue execution. ! 466: */ ! 467: if (v86_assist(thread, regs)) ! 468: return; ! 469: } ! 470: ! 471: type = regs->trapno; ! 472: code = 0; ! 473: subcode = 0; ! 474: ! 475: switch (type) { ! 476: ! 477: case T_DIVIDE_ERROR: ! 478: exc = EXC_ARITHMETIC; ! 479: code = EXC_I386_DIV; ! 480: break; ! 481: ! 482: case T_DEBUG: ! 483: #if MACH_KDP ! 484: /* Trap to KDP */ ! 485: kdp_raise_exception(EXC_BREAKPOINT, EXC_I386_BPTFLT, 0, regs); ! 486: #endif ! 487: #if MACH_KGDB ! 488: if (kgdb_user_trap(regs)) { ! 489: return; ! 490: } ! 491: #endif ! 492: #if MACH_KDB ! 493: if (db_in_single_step()) { ! 494: if (kdb_trap(type, regs->err, regs)) ! 495: return; ! 496: } ! 497: #endif ! 498: exc = EXC_BREAKPOINT; ! 499: code = EXC_I386_SGL; ! 500: break; ! 501: ! 502: case T_INT3: ! 503: ! 504: #if MACH_KDP ! 505: kdp_raise_exception(EXC_BREAKPOINT, EXC_I386_BPTFLT, 0, regs); ! 506: #endif ! 507: #if MACH_KGDB ! 508: if (kgdb_user_trap(regs)) { ! 509: return; ! 510: } ! 511: #endif ! 512: #if MACH_KDB ! 513: { ! 514: thread_act_t curact = current_act(); ! 515: ! 516: if (db_find_breakpoint_here( ! 517: (curact && !curact->kernel_loaded)? ! 518: curact->task: TASK_NULL, ! 519: regs->eip - 1)) { ! 520: if (kdb_trap(type, regs->err, regs)) ! 521: return; ! 522: } ! 523: } ! 524: #endif ! 525: exc = EXC_BREAKPOINT; ! 526: code = EXC_I386_BPT; ! 527: break; ! 528: ! 529: case T_OVERFLOW: ! 530: exc = EXC_ARITHMETIC; ! 531: code = EXC_I386_INTO; ! 532: break; ! 533: ! 534: case T_OUT_OF_BOUNDS: ! 535: exc = EXC_SOFTWARE; ! 536: code = EXC_I386_BOUND; ! 537: break; ! 538: ! 539: case T_INVALID_OPCODE: ! 540: exc = EXC_BAD_INSTRUCTION; ! 541: code = EXC_I386_INVOP; ! 542: break; ! 543: ! 544: case T_NO_FPU: ! 545: case 32: /* XXX */ ! 546: fpnoextflt(); ! 547: return; ! 548: ! 549: case T_FPU_FAULT: ! 550: fpextovrflt(); ! 551: return; ! 552: ! 553: case 10: /* invalid TSS == iret with NT flag set */ ! 554: exc = EXC_BAD_INSTRUCTION; ! 555: code = EXC_I386_INVTSSFLT; ! 556: subcode = regs->err & 0xffff; ! 557: break; ! 558: ! 559: case T_SEGMENT_NOT_PRESENT: ! 560: exc = EXC_BAD_INSTRUCTION; ! 561: code = EXC_I386_SEGNPFLT; ! 562: subcode = regs->err & 0xffff; ! 563: break; ! 564: ! 565: case T_STACK_FAULT: ! 566: exc = EXC_BAD_INSTRUCTION; ! 567: code = EXC_I386_STKFLT; ! 568: subcode = regs->err & 0xffff; ! 569: break; ! 570: ! 571: case T_GENERAL_PROTECTION: ! 572: if (!(regs->efl & EFL_VM)) { ! 573: if (check_io_fault(regs)) ! 574: return; ! 575: } ! 576: exc = EXC_BAD_INSTRUCTION; ! 577: code = EXC_I386_GPFLT; ! 578: subcode = regs->err & 0xffff; ! 579: break; ! 580: ! 581: case T_PAGE_FAULT: ! 582: subcode = regs->cr2; ! 583: prot = VM_PROT_READ|VM_PROT_WRITE; ! 584: if (kernel_act == FALSE) { ! 585: if (!(regs->err & T_PF_WRITE)) ! 586: prot = VM_PROT_READ; ! 587: (void) user_page_fault_continue(vm_fault(thr_act->map, ! 588: trunc_page((vm_offset_t)subcode), ! 589: prot, ! 590: FALSE)); ! 591: /* NOTREACHED */ ! 592: } ! 593: else { ! 594: if (subcode > LINEAR_KERNEL_ADDRESS) { ! 595: map = kernel_map; ! 596: subcode -= LINEAR_KERNEL_ADDRESS; ! 597: } ! 598: result = vm_fault(thr_act->map, ! 599: trunc_page((vm_offset_t)subcode), ! 600: prot, ! 601: FALSE); ! 602: if (result != KERN_SUCCESS) { ! 603: /* ! 604: * Must expand vm_fault by hand, ! 605: * so that we can ask for read-only access ! 606: * but enter a (kernel) writable mapping. ! 607: */ ! 608: result = intel_read_fault(thr_act->map, ! 609: trunc_page((vm_offset_t)subcode)); ! 610: } ! 611: user_page_fault_continue(result); ! 612: /*NOTREACHED*/ ! 613: } ! 614: break; ! 615: ! 616: case T_FLOATING_POINT_ERROR: ! 617: fpexterrflt(); ! 618: return; ! 619: ! 620: default: ! 621: #if MACH_KGDB ! 622: Debugger("Unanticipated user trap"); ! 623: return; ! 624: #endif /* MACH_KGDB */ ! 625: #if MACH_KDB ! 626: if (kdb_trap(type, regs->err, regs)) ! 627: return; ! 628: #endif /* MACH_KDB */ ! 629: printf("user trap type %d, code = %x, pc = %x\n", ! 630: type, regs->err, regs->eip); ! 631: panic("user trap"); ! 632: return; ! 633: } ! 634: ! 635: #if MACH_KDB ! 636: if (debug_all_traps_with_kdb && ! 637: kdb_trap(type, regs->err, regs)) ! 638: return; ! 639: #endif /* MACH_KDB */ ! 640: ! 641: #if ETAP_EVENT_MONITOR ! 642: if (thread != THREAD_NULL) { ! 643: ETAP_DATA_LOAD(probe_data[0], regs->trapno); ! 644: ETAP_DATA_LOAD(probe_data[1], ! 645: thr_act->exc_actions[exc].port); ! 646: ETAP_DATA_LOAD(probe_data[2], ! 647: thr_act->task->exc_actions[exc].port); ! 648: ETAP_PROBE_DATA(ETAP_P_EXCEPTION, ! 649: 0, ! 650: thread, ! 651: &probe_data, ! 652: ETAP_DATA_ENTRY*3); ! 653: } ! 654: #endif /* ETAP_EVENT_MONITOR */ ! 655: ! 656: i386_exception(exc, code, subcode); ! 657: /*NOTREACHED*/ ! 658: } ! 659: ! 660: /* ! 661: * V86 mode assist for interrupt handling. ! 662: */ ! 663: boolean_t v86_assist_on = TRUE; ! 664: boolean_t v86_unsafe_ok = FALSE; ! 665: boolean_t v86_do_sti_cli = TRUE; ! 666: boolean_t v86_do_sti_immediate = FALSE; ! 667: ! 668: #define V86_IRET_PENDING 0x4000 ! 669: ! 670: int cli_count = 0; ! 671: int sti_count = 0; ! 672: ! 673: boolean_t ! 674: v86_assist( ! 675: thread_t thread, ! 676: register struct i386_saved_state *regs) ! 677: { ! 678: register struct v86_assist_state *v86 = &thread->top_act->mact.pcb->ims.v86s; ! 679: ! 680: /* ! 681: * Build an 8086 address. Use only when off is known to be 16 bits. ! 682: */ ! 683: #define Addr8086(seg,off) ((((seg) & 0xffff) << 4) + (off)) ! 684: ! 685: #define EFL_V86_SAFE ( EFL_OF | EFL_DF | EFL_TF \ ! 686: | EFL_SF | EFL_ZF | EFL_AF \ ! 687: | EFL_PF | EFL_CF ) ! 688: struct iret_32 { ! 689: int eip; ! 690: int cs; ! 691: int eflags; ! 692: }; ! 693: struct iret_16 { ! 694: unsigned short ip; ! 695: unsigned short cs; ! 696: unsigned short flags; ! 697: }; ! 698: union iret_struct { ! 699: struct iret_32 iret_32; ! 700: struct iret_16 iret_16; ! 701: }; ! 702: ! 703: struct int_vec { ! 704: unsigned short ip; ! 705: unsigned short cs; ! 706: }; ! 707: ! 708: if (!v86_assist_on) ! 709: return FALSE; ! 710: ! 711: /* ! 712: * If delayed STI pending, enable interrupts. ! 713: * Turn off tracing if on only to delay STI. ! 714: */ ! 715: if (v86->flags & V86_IF_PENDING) { ! 716: v86->flags &= ~V86_IF_PENDING; ! 717: v86->flags |= EFL_IF; ! 718: if ((v86->flags & EFL_TF) == 0) ! 719: regs->efl &= ~EFL_TF; ! 720: } ! 721: ! 722: if (regs->trapno == T_DEBUG) { ! 723: ! 724: if (v86->flags & EFL_TF) { ! 725: /* ! 726: * Trace flag was also set - it has priority ! 727: */ ! 728: return FALSE; /* handle as single-step */ ! 729: } ! 730: /* ! 731: * Fall through to check for interrupts. ! 732: */ ! 733: } ! 734: else if (regs->trapno == T_GENERAL_PROTECTION) { ! 735: /* ! 736: * General protection error - must be an 8086 instruction ! 737: * to emulate. ! 738: */ ! 739: register int eip; ! 740: boolean_t addr_32 = FALSE; ! 741: boolean_t data_32 = FALSE; ! 742: int io_port; ! 743: ! 744: /* ! 745: * Set up error handler for bad instruction/data ! 746: * fetches. ! 747: */ ! 748: __asm__("movl $(addr_error), %0" : : "m" (thread->recover)); ! 749: ! 750: eip = regs->eip; ! 751: while (TRUE) { ! 752: unsigned char opcode; ! 753: ! 754: if (eip > 0xFFFF) { ! 755: thread->recover = 0; ! 756: return FALSE; /* GP fault: IP out of range */ ! 757: } ! 758: ! 759: opcode = *(unsigned char *)Addr8086(regs->cs,eip); ! 760: eip++; ! 761: switch (opcode) { ! 762: case 0xf0: /* lock */ ! 763: case 0xf2: /* repne */ ! 764: case 0xf3: /* repe */ ! 765: case 0x2e: /* cs */ ! 766: case 0x36: /* ss */ ! 767: case 0x3e: /* ds */ ! 768: case 0x26: /* es */ ! 769: case 0x64: /* fs */ ! 770: case 0x65: /* gs */ ! 771: /* ignore prefix */ ! 772: continue; ! 773: ! 774: case 0x66: /* data size */ ! 775: data_32 = TRUE; ! 776: continue; ! 777: ! 778: case 0x67: /* address size */ ! 779: addr_32 = TRUE; ! 780: continue; ! 781: ! 782: case 0xe4: /* inb imm */ ! 783: case 0xe5: /* inw imm */ ! 784: case 0xe6: /* outb imm */ ! 785: case 0xe7: /* outw imm */ ! 786: io_port = *(unsigned char *)Addr8086(regs->cs, eip); ! 787: eip++; ! 788: goto do_in_out; ! 789: ! 790: case 0xec: /* inb dx */ ! 791: case 0xed: /* inw dx */ ! 792: case 0xee: /* outb dx */ ! 793: case 0xef: /* outw dx */ ! 794: case 0x6c: /* insb */ ! 795: case 0x6d: /* insw */ ! 796: case 0x6e: /* outsb */ ! 797: case 0x6f: /* outsw */ ! 798: io_port = regs->edx & 0xffff; ! 799: ! 800: do_in_out: ! 801: if (!data_32) ! 802: opcode |= 0x6600; /* word IO */ ! 803: ! 804: switch (emulate_io(regs, opcode, io_port)) { ! 805: case EM_IO_DONE: ! 806: /* instruction executed */ ! 807: break; ! 808: case EM_IO_RETRY: ! 809: /* port mapped, retry instruction */ ! 810: thread->recover = 0; ! 811: return TRUE; ! 812: case EM_IO_ERROR: ! 813: /* port not mapped */ ! 814: thread->recover = 0; ! 815: return FALSE; ! 816: } ! 817: break; ! 818: ! 819: case 0xfa: /* cli */ ! 820: if (!v86_do_sti_cli) { ! 821: thread->recover = 0; ! 822: return (FALSE); ! 823: } ! 824: ! 825: v86->flags &= ~EFL_IF; ! 826: /* disable simulated interrupts */ ! 827: cli_count++; ! 828: break; ! 829: ! 830: case 0xfb: /* sti */ ! 831: if (!v86_do_sti_cli) { ! 832: thread->recover = 0; ! 833: return (FALSE); ! 834: } ! 835: ! 836: if ((v86->flags & EFL_IF) == 0) { ! 837: if (v86_do_sti_immediate) { ! 838: v86->flags |= EFL_IF; ! 839: } else { ! 840: v86->flags |= V86_IF_PENDING; ! 841: regs->efl |= EFL_TF; ! 842: } ! 843: /* single step to set IF next inst. */ ! 844: } ! 845: sti_count++; ! 846: break; ! 847: ! 848: case 0x9c: /* pushf */ ! 849: { ! 850: int flags; ! 851: vm_offset_t sp; ! 852: int size; ! 853: ! 854: flags = regs->efl; ! 855: if ((v86->flags & EFL_IF) == 0) ! 856: flags &= ~EFL_IF; ! 857: ! 858: if ((v86->flags & EFL_TF) == 0) ! 859: flags &= ~EFL_TF; ! 860: else flags |= EFL_TF; ! 861: ! 862: sp = regs->uesp; ! 863: if (!addr_32) ! 864: sp &= 0xffff; ! 865: else if (sp > 0xffff) ! 866: goto stack_error; ! 867: size = (data_32) ? 4 : 2; ! 868: if (sp < size) ! 869: goto stack_error; ! 870: sp -= size; ! 871: if (copyout((char *)&flags, ! 872: (char *)Addr8086(regs->ss,sp), ! 873: size)) ! 874: goto addr_error; ! 875: if (addr_32) ! 876: regs->uesp = sp; ! 877: else ! 878: regs->uesp = (regs->uesp & 0xffff0000) | sp; ! 879: break; ! 880: } ! 881: ! 882: case 0x9d: /* popf */ ! 883: { ! 884: vm_offset_t sp; ! 885: int nflags; ! 886: ! 887: sp = regs->uesp; ! 888: if (!addr_32) ! 889: sp &= 0xffff; ! 890: else if (sp > 0xffff) ! 891: goto stack_error; ! 892: ! 893: if (data_32) { ! 894: if (sp > 0xffff - sizeof(int)) ! 895: goto stack_error; ! 896: nflags = *(int *)Addr8086(regs->ss,sp); ! 897: sp += sizeof(int); ! 898: } ! 899: else { ! 900: if (sp > 0xffff - sizeof(short)) ! 901: goto stack_error; ! 902: nflags = *(unsigned short *) ! 903: Addr8086(regs->ss,sp); ! 904: sp += sizeof(short); ! 905: } ! 906: if (addr_32) ! 907: regs->uesp = sp; ! 908: else ! 909: regs->uesp = (regs->uesp & 0xffff0000) | sp; ! 910: ! 911: if (v86->flags & V86_IRET_PENDING) { ! 912: v86->flags = nflags & (EFL_TF | EFL_IF); ! 913: v86->flags |= V86_IRET_PENDING; ! 914: } else { ! 915: v86->flags = nflags & (EFL_TF | EFL_IF); ! 916: } ! 917: regs->efl = (regs->efl & ~EFL_V86_SAFE) ! 918: | (nflags & EFL_V86_SAFE); ! 919: break; ! 920: } ! 921: case 0xcf: /* iret */ ! 922: { ! 923: vm_offset_t sp; ! 924: int nflags; ! 925: int size; ! 926: union iret_struct iret_struct; ! 927: ! 928: v86->flags &= ~V86_IRET_PENDING; ! 929: sp = regs->uesp; ! 930: if (!addr_32) ! 931: sp &= 0xffff; ! 932: else if (sp > 0xffff) ! 933: goto stack_error; ! 934: ! 935: if (data_32) { ! 936: if (sp > 0xffff - sizeof(struct iret_32)) ! 937: goto stack_error; ! 938: iret_struct.iret_32 = ! 939: *(struct iret_32 *) Addr8086(regs->ss,sp); ! 940: sp += sizeof(struct iret_32); ! 941: } ! 942: else { ! 943: if (sp > 0xffff - sizeof(struct iret_16)) ! 944: goto stack_error; ! 945: iret_struct.iret_16 = ! 946: *(struct iret_16 *) Addr8086(regs->ss,sp); ! 947: sp += sizeof(struct iret_16); ! 948: } ! 949: if (addr_32) ! 950: regs->uesp = sp; ! 951: else ! 952: regs->uesp = (regs->uesp & 0xffff0000) | sp; ! 953: ! 954: if (data_32) { ! 955: eip = iret_struct.iret_32.eip; ! 956: regs->cs = iret_struct.iret_32.cs & 0xffff; ! 957: nflags = iret_struct.iret_32.eflags; ! 958: } ! 959: else { ! 960: eip = iret_struct.iret_16.ip; ! 961: regs->cs = iret_struct.iret_16.cs; ! 962: nflags = iret_struct.iret_16.flags; ! 963: } ! 964: ! 965: v86->flags = nflags & (EFL_TF | EFL_IF); ! 966: regs->efl = (regs->efl & ~EFL_V86_SAFE) ! 967: | (nflags & EFL_V86_SAFE); ! 968: break; ! 969: } ! 970: default: ! 971: /* ! 972: * Instruction not emulated here. ! 973: */ ! 974: thread->recover = 0; ! 975: return FALSE; ! 976: } ! 977: break; /* exit from 'while TRUE' */ ! 978: } ! 979: regs->eip = (regs->eip & 0xffff0000 | eip); ! 980: } ! 981: else { ! 982: /* ! 983: * Not a trap we handle. ! 984: */ ! 985: thread->recover = 0; ! 986: return FALSE; ! 987: } ! 988: ! 989: if ((v86->flags & EFL_IF) && ((v86->flags & V86_IRET_PENDING)==0)) { ! 990: ! 991: struct v86_interrupt_table *int_table; ! 992: int int_count; ! 993: int vec; ! 994: int i; ! 995: ! 996: int_table = (struct v86_interrupt_table *) v86->int_table; ! 997: int_count = v86->int_count; ! 998: ! 999: vec = 0; ! 1000: for (i = 0; i < int_count; int_table++, i++) { ! 1001: if (!int_table->mask && int_table->count > 0) { ! 1002: int_table->count--; ! 1003: vec = int_table->vec; ! 1004: break; ! 1005: } ! 1006: } ! 1007: if (vec != 0) { ! 1008: /* ! 1009: * Take this interrupt ! 1010: */ ! 1011: vm_offset_t sp; ! 1012: struct iret_16 iret_16; ! 1013: struct int_vec int_vec; ! 1014: ! 1015: sp = regs->uesp & 0xffff; ! 1016: if (sp < sizeof(struct iret_16)) ! 1017: goto stack_error; ! 1018: sp -= sizeof(struct iret_16); ! 1019: iret_16.ip = regs->eip; ! 1020: iret_16.cs = regs->cs; ! 1021: iret_16.flags = regs->efl & 0xFFFF; ! 1022: if ((v86->flags & EFL_TF) == 0) ! 1023: iret_16.flags &= ~EFL_TF; ! 1024: else iret_16.flags |= EFL_TF; ! 1025: ! 1026: (void) memcpy((char *) &int_vec, ! 1027: (char *) (sizeof(struct int_vec) * vec), ! 1028: sizeof (struct int_vec)); ! 1029: if (copyout((char *)&iret_16, ! 1030: (char *)Addr8086(regs->ss,sp), ! 1031: sizeof(struct iret_16))) ! 1032: goto addr_error; ! 1033: regs->uesp = (regs->uesp & 0xFFFF0000) | (sp & 0xffff); ! 1034: regs->eip = int_vec.ip; ! 1035: regs->cs = int_vec.cs; ! 1036: regs->efl &= ~EFL_TF; ! 1037: v86->flags &= ~(EFL_IF | EFL_TF); ! 1038: v86->flags |= V86_IRET_PENDING; ! 1039: } ! 1040: } ! 1041: ! 1042: thread->recover = 0; ! 1043: return TRUE; ! 1044: ! 1045: /* ! 1046: * On address error, report a page fault. ! 1047: * XXX report GP fault - we don`t save ! 1048: * the faulting address. ! 1049: */ ! 1050: addr_error: ! 1051: __asm__("addr_error:;"); ! 1052: thread->recover = 0; ! 1053: return FALSE; ! 1054: ! 1055: /* ! 1056: * On stack address error, return stack fault (12). ! 1057: */ ! 1058: stack_error: ! 1059: thread->recover = 0; ! 1060: regs->trapno = T_STACK_FAULT; ! 1061: return FALSE; ! 1062: } ! 1063: ! 1064: /* ! 1065: * Handle AST traps for i386. ! 1066: * Check for delayed floating-point exception from ! 1067: * AT-bus machines. ! 1068: */ ! 1069: ! 1070: extern void log_thread_action (thread_t, char *); ! 1071: ! 1072: void ! 1073: i386_astintr(int preemption) ! 1074: { ! 1075: int mycpu; ! 1076: ast_t mask = AST_ALL; ! 1077: spl_t s; ! 1078: thread_t self = current_thread(); ! 1079: ! 1080: s = splsched(); /* block interrupts to check reasons */ ! 1081: mp_disable_preemption(); ! 1082: mycpu = cpu_number(); ! 1083: if (need_ast[mycpu] & AST_I386_FP) { ! 1084: /* ! 1085: * AST was for delayed floating-point exception - ! 1086: * FP interrupt occured while in kernel. ! 1087: * Turn off this AST reason and handle the FPU error. ! 1088: */ ! 1089: ! 1090: ast_off(AST_I386_FP); ! 1091: mp_enable_preemption(); ! 1092: splx(s); ! 1093: ! 1094: fpexterrflt(); ! 1095: } ! 1096: else { ! 1097: /* ! 1098: * Not an FPU trap. Handle the AST. ! 1099: * Interrupts are still blocked. ! 1100: */ ! 1101: ! 1102: if (preemption) { ! 1103: ! 1104: /* ! 1105: * We don't want to process any AST if we were in ! 1106: * kernel-mode and the current thread is in any ! 1107: * funny state (waiting and/or suspended). ! 1108: */ ! 1109: ! 1110: thread_lock (self); ! 1111: ! 1112: if (thread_not_preemptable(self) || self->preempt) { ! 1113: ast_off(AST_URGENT); ! 1114: thread_unlock (self); ! 1115: mp_enable_preemption(); ! 1116: splx(s); ! 1117: return; ! 1118: } ! 1119: else mask = AST_PREEMPT; ! 1120: mp_enable_preemption(); ! 1121: ! 1122: /* ! 1123: self->preempt = TH_NOT_PREEMPTABLE; ! 1124: */ ! 1125: ! 1126: thread_unlock (self); ! 1127: } else { ! 1128: mp_enable_preemption(); ! 1129: } ! 1130: ! 1131: ast_taken(preemption, mask, s ! 1132: #if FAST_IDLE ! 1133: ,NO_IDLE_THREAD ! 1134: #endif /* FAST_IDLE */ ! 1135: ); ! 1136: /* ! 1137: self->preempt = TH_PREEMPTABLE; ! 1138: */ ! 1139: } ! 1140: } ! 1141: ! 1142: /* ! 1143: * Handle exceptions for i386. ! 1144: * ! 1145: * If we are an AT bus machine, we must turn off the AST for a ! 1146: * delayed floating-point exception. ! 1147: * ! 1148: * If we are providing floating-point emulation, we may have ! 1149: * to retrieve the real register values from the floating point ! 1150: * emulator. ! 1151: */ ! 1152: void ! 1153: i386_exception( ! 1154: int exc, ! 1155: int code, ! 1156: int subcode) ! 1157: { ! 1158: spl_t s; ! 1159: exception_data_type_t codes[EXCEPTION_CODE_MAX]; ! 1160: ! 1161: /* ! 1162: * Turn off delayed FPU error handling. ! 1163: */ ! 1164: s = splsched(); ! 1165: mp_disable_preemption(); ! 1166: ast_off(AST_I386_FP); ! 1167: mp_enable_preemption(); ! 1168: splx(s); ! 1169: ! 1170: codes[0] = code; /* new exception interface */ ! 1171: codes[1] = subcode; ! 1172: exception(exc, codes, 2); ! 1173: /*NOTREACHED*/ ! 1174: } ! 1175: ! 1176: boolean_t ! 1177: check_io_fault( ! 1178: struct i386_saved_state *regs) ! 1179: { ! 1180: int eip, opcode, io_port; ! 1181: boolean_t data_16 = FALSE; ! 1182: ! 1183: /* ! 1184: * Get the instruction. ! 1185: */ ! 1186: eip = regs->eip; ! 1187: ! 1188: for (;;) { ! 1189: opcode = inst_fetch(eip, regs->cs); ! 1190: eip++; ! 1191: switch (opcode) { ! 1192: case 0x66: /* data-size prefix */ ! 1193: data_16 = TRUE; ! 1194: continue; ! 1195: ! 1196: case 0xf3: /* rep prefix */ ! 1197: case 0x26: /* es */ ! 1198: case 0x2e: /* cs */ ! 1199: case 0x36: /* ss */ ! 1200: case 0x3e: /* ds */ ! 1201: case 0x64: /* fs */ ! 1202: case 0x65: /* gs */ ! 1203: continue; ! 1204: ! 1205: case 0xE4: /* inb imm */ ! 1206: case 0xE5: /* inl imm */ ! 1207: case 0xE6: /* outb imm */ ! 1208: case 0xE7: /* outl imm */ ! 1209: /* port is immediate byte */ ! 1210: io_port = inst_fetch(eip, regs->cs); ! 1211: eip++; ! 1212: break; ! 1213: ! 1214: case 0xEC: /* inb dx */ ! 1215: case 0xED: /* inl dx */ ! 1216: case 0xEE: /* outb dx */ ! 1217: case 0xEF: /* outl dx */ ! 1218: case 0x6C: /* insb */ ! 1219: case 0x6D: /* insl */ ! 1220: case 0x6E: /* outsb */ ! 1221: case 0x6F: /* outsl */ ! 1222: /* port is in DX register */ ! 1223: io_port = regs->edx & 0xFFFF; ! 1224: break; ! 1225: ! 1226: default: ! 1227: return FALSE; ! 1228: } ! 1229: break; ! 1230: } ! 1231: ! 1232: if (data_16) ! 1233: opcode |= 0x6600; /* word IO */ ! 1234: ! 1235: switch (emulate_io(regs, opcode, io_port)) { ! 1236: case EM_IO_DONE: ! 1237: /* instruction executed */ ! 1238: regs->eip = eip; ! 1239: return TRUE; ! 1240: ! 1241: case EM_IO_RETRY: ! 1242: /* port mapped, retry instruction */ ! 1243: return TRUE; ! 1244: ! 1245: case EM_IO_ERROR: ! 1246: /* port not mapped */ ! 1247: return FALSE; ! 1248: } ! 1249: return FALSE; ! 1250: } ! 1251: ! 1252: void ! 1253: kernel_preempt_check (void) ! 1254: { ! 1255: mp_disable_preemption(); ! 1256: if ((need_ast[cpu_number()] & AST_URGENT) && ! 1257: #if NCPUS > 1 ! 1258: get_interrupt_level() == 1 ! 1259: #else /* NCPUS > 1 */ ! 1260: get_interrupt_level() == 0 ! 1261: #endif /* NCPUS > 1 */ ! 1262: ) { ! 1263: mp_enable_preemption_no_check(); ! 1264: __asm__ volatile (" int $0xff"); ! 1265: } else { ! 1266: mp_enable_preemption_no_check(); ! 1267: } ! 1268: } ! 1269: ! 1270: #if MACH_KDB ! 1271: ! 1272: extern void db_i386_state(struct i386_saved_state *regs); ! 1273: ! 1274: #include <ddb/db_output.h> ! 1275: ! 1276: void ! 1277: db_i386_state( ! 1278: struct i386_saved_state *regs) ! 1279: { ! 1280: db_printf("eip %8x\n", regs->eip); ! 1281: db_printf("trap %8x\n", regs->trapno); ! 1282: db_printf("err %8x\n", regs->err); ! 1283: db_printf("efl %8x\n", regs->efl); ! 1284: db_printf("ebp %8x\n", regs->ebp); ! 1285: db_printf("esp %8x\n", regs->esp); ! 1286: db_printf("uesp %8x\n", regs->uesp); ! 1287: db_printf("cs %8x\n", regs->cs & 0xff); ! 1288: db_printf("ds %8x\n", regs->ds & 0xff); ! 1289: db_printf("es %8x\n", regs->es & 0xff); ! 1290: db_printf("fs %8x\n", regs->fs & 0xff); ! 1291: db_printf("gs %8x\n", regs->gs & 0xff); ! 1292: db_printf("ss %8x\n", regs->ss & 0xff); ! 1293: db_printf("eax %8x\n", regs->eax); ! 1294: db_printf("ebx %8x\n", regs->ebx); ! 1295: db_printf("ecx %8x\n", regs->ecx); ! 1296: db_printf("edx %8x\n", regs->edx); ! 1297: db_printf("esi %8x\n", regs->esi); ! 1298: db_printf("edi %8x\n", regs->edi); ! 1299: } ! 1300: ! 1301: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.