Changeset View
Changeset View
Standalone View
Standalone View
sys/i386/i386/trap.c
Show First 20 Lines • Show All 110 Lines • ▼ Show 20 Lines | |||||
void trap(struct trapframe *frame); | void trap(struct trapframe *frame); | ||||
void syscall(struct trapframe *frame); | void syscall(struct trapframe *frame); | ||||
static int trap_pfault(struct trapframe *, int, vm_offset_t); | static int trap_pfault(struct trapframe *, int, vm_offset_t); | ||||
static void trap_fatal(struct trapframe *, vm_offset_t); | static void trap_fatal(struct trapframe *, vm_offset_t); | ||||
void dblfault_handler(void); | void dblfault_handler(void); | ||||
extern inthand_t IDTVEC(lcall_syscall); | |||||
#define MAX_TRAP_MSG 32 | #define MAX_TRAP_MSG 32 | ||||
static char *trap_msg[] = { | |||||
"", /* 0 unused */ | struct trap_data { | ||||
"privileged instruction fault", /* 1 T_PRIVINFLT */ | bool ei; | ||||
"", /* 2 unused */ | const char *msg; | ||||
"breakpoint instruction fault", /* 3 T_BPTFLT */ | |||||
"", /* 4 unused */ | |||||
"", /* 5 unused */ | |||||
"arithmetic trap", /* 6 T_ARITHTRAP */ | |||||
"", /* 7 unused */ | |||||
"", /* 8 unused */ | |||||
"general protection fault", /* 9 T_PROTFLT */ | |||||
"trace trap", /* 10 T_TRCTRAP */ | |||||
"", /* 11 unused */ | |||||
"page fault", /* 12 T_PAGEFLT */ | |||||
"", /* 13 unused */ | |||||
"alignment fault", /* 14 T_ALIGNFLT */ | |||||
"", /* 15 unused */ | |||||
"", /* 16 unused */ | |||||
"", /* 17 unused */ | |||||
"integer divide fault", /* 18 T_DIVIDE */ | |||||
"non-maskable interrupt trap", /* 19 T_NMI */ | |||||
"overflow trap", /* 20 T_OFLOW */ | |||||
"FPU bounds check fault", /* 21 T_BOUND */ | |||||
"FPU device not available", /* 22 T_DNA */ | |||||
"double fault", /* 23 T_DOUBLEFLT */ | |||||
"FPU operand fetch fault", /* 24 T_FPOPFLT */ | |||||
"invalid TSS fault", /* 25 T_TSSFLT */ | |||||
"segment not present fault", /* 26 T_SEGNPFLT */ | |||||
"stack fault", /* 27 T_STKFLT */ | |||||
"machine check trap", /* 28 T_MCHK */ | |||||
"SIMD floating-point exception", /* 29 T_XMMFLT */ | |||||
"reserved (unknown) fault", /* 30 T_RESERVED */ | |||||
"", /* 31 unused (reserved) */ | |||||
"DTrace pid return trap", /* 32 T_DTRACE_RET */ | |||||
}; | }; | ||||
static const struct trap_data trap_data[] = { | |||||
[T_PRIVINFLT] = { .ei = true, .msg = "privileged instruction fault" }, | |||||
[T_BPTFLT] = { .ei = false, .msg = "breakpoint instruction fault" }, | |||||
[T_ARITHTRAP] = { .ei = true, .msg = "arithmetic trap" }, | |||||
[T_PROTFLT] = { .ei = true, .msg = "general protection fault" }, | |||||
[T_TRCTRAP] = { .ei = false, .msg = "trace trap" }, | |||||
[T_PAGEFLT] = { .ei = true, .msg = "page fault" }, | |||||
[T_ALIGNFLT] = { .ei = true, .msg = "alignment fault" }, | |||||
[T_DIVIDE] = { .ei = true, .msg = "integer divide fault" }, | |||||
[T_NMI] = { .ei = false, .msg = "non-maskable interrupt trap" }, | |||||
[T_OFLOW] = { .ei = true, .msg = "overflow trap" }, | |||||
[T_BOUND] = { .ei = true, .msg = "FPU bounds check fault" }, | |||||
[T_DNA] = { .ei = true, .msg = "FPU device not available" }, | |||||
[T_DOUBLEFLT] = { .ei = false, .msg = "double fault" }, | |||||
[T_FPOPFLT] = { .ei = true, .msg = "FPU operand fetch fault" }, | |||||
[T_TSSFLT] = { .ei = true, .msg = "invalid TSS fault" }, | |||||
[T_SEGNPFLT] = { .ei = true, .msg = "segment not present fault" }, | |||||
[T_STKFLT] = { .ei = true, .msg = "stack fault" }, | |||||
[T_MCHK] = { .ei = true, .msg = "machine check trap" }, | |||||
[T_XMMFLT] = { .ei = true, .msg = "SIMD floating-point exception" }, | |||||
[T_DTRACE_RET] ={ .ei = true, .msg = "DTrace pid return trap" }, | |||||
}; | |||||
static bool | |||||
trap_enable_intr(int trapno) | |||||
{ | |||||
MPASS(trapno > 0); | |||||
if (trapno < nitems(trap_data) && trap_data[trapno].msg != NULL) | |||||
return (trap_data[trapno].ei); | |||||
return (false); | |||||
} | |||||
static const char * | |||||
trap_msg(int trapno) | |||||
{ | |||||
const char *res; | |||||
static const char unkn[] = "UNKNOWN"; | |||||
res = NULL; | |||||
if (trapno < nitems(trap_data)) | |||||
res = trap_data[trapno].msg; | |||||
if (res == NULL) | |||||
res = unkn; | |||||
return (res); | |||||
} | |||||
#if defined(I586_CPU) && !defined(NO_F00F_HACK) | #if defined(I586_CPU) && !defined(NO_F00F_HACK) | ||||
int has_f00f_bug = 0; /* Initialized so that it can be patched. */ | int has_f00f_bug = 0; /* Initialized so that it can be patched. */ | ||||
#endif | #endif | ||||
static int prot_fault_translation = 0; | static int prot_fault_translation = 0; | ||||
SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, | SYSCTL_INT(_machdep, OID_AUTO, prot_fault_translation, CTLFLAG_RW, | ||||
&prot_fault_translation, 0, "Select signal to deliver on protection fault"); | &prot_fault_translation, 0, "Select signal to deliver on protection fault"); | ||||
static int uprintf_signal; | static int uprintf_signal; | ||||
Show All 29 Lines | #endif | ||||
p = td->td_proc; | p = td->td_proc; | ||||
signo = 0; | signo = 0; | ||||
ucode = 0; | ucode = 0; | ||||
addr = 0; | addr = 0; | ||||
VM_CNT_INC(v_trap); | VM_CNT_INC(v_trap); | ||||
type = frame->tf_trapno; | type = frame->tf_trapno; | ||||
KASSERT((read_eflags() & PSL_I) == 0, | |||||
("trap: interrupts enaabled, type %d frame %p", type, frame)); | |||||
#ifdef SMP | #ifdef SMP | ||||
/* Handler for NMI IPIs used for stopping CPUs. */ | /* Handler for NMI IPIs used for stopping CPUs. */ | ||||
if (type == T_NMI && ipi_nmi_handler() == 0) | if (type == T_NMI && ipi_nmi_handler() == 0) | ||||
return; | return; | ||||
#endif /* SMP */ | #endif /* SMP */ | ||||
#ifdef KDB | #ifdef KDB | ||||
if (kdb_active) { | if (kdb_active) { | ||||
Show All 40 Lines | #ifdef KDTRACE_HOOKS | ||||
* want to fault. On returning from the probe, the no-fault | * want to fault. On returning from the probe, the no-fault | ||||
* flag is cleared and finally re-scheduling is enabled. | * flag is cleared and finally re-scheduling is enabled. | ||||
*/ | */ | ||||
if ((type == T_PROTFLT || type == T_PAGEFLT) && | if ((type == T_PROTFLT || type == T_PAGEFLT) && | ||||
dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type)) | dtrace_trap_func != NULL && (*dtrace_trap_func)(frame, type)) | ||||
return; | return; | ||||
#endif | #endif | ||||
if ((frame->tf_eflags & PSL_I) == 0) { | |||||
/* | /* | ||||
* Buggy application or kernel code has disabled | * We must not allow context switches until %cr2 is read. | ||||
* interrupts and then trapped. Enabling interrupts | * Also, for some Cyrix CPUs, %cr2 is clobbered by interrupts. | ||||
* now is wrong, but it is better than running with | * All faults use interrupt gates, so %cr2 can be safely read | ||||
* interrupts disabled until they are accidentally | * now, before optional enable of the interrupts below. | ||||
* enabled later. | |||||
*/ | */ | ||||
if (TRAPF_USERMODE(frame) && | if (type == T_PAGEFLT) | ||||
eva = rcr2(); | |||||
/* | |||||
* Buggy application or kernel code has disabled interrupts | |||||
* and then trapped. Enabling interrupts now is wrong, but it | |||||
* is better than running with interrupts disabled until they | |||||
* are accidentally enabled later. | |||||
*/ | |||||
if ((frame->tf_eflags & PSL_I) == 0 && TRAPF_USERMODE(frame) && | |||||
(curpcb->pcb_flags & PCB_VM86CALL) == 0) | (curpcb->pcb_flags & PCB_VM86CALL) == 0) | ||||
uprintf( | uprintf("pid %ld (%s): trap %d with interrupts disabled\n", | ||||
"pid %ld (%s): trap %d with interrupts disabled\n", | |||||
(long)curproc->p_pid, curthread->td_name, type); | (long)curproc->p_pid, curthread->td_name, type); | ||||
else if (type != T_NMI && type != T_BPTFLT && | |||||
type != T_TRCTRAP && | |||||
frame->tf_eip != (int)cpu_switch_load_gs) { | |||||
/* | /* | ||||
* XXX not quite right, since this may be for a | * Conditionally reenable interrupts. If we hold a spin lock, | ||||
* multiple fault in user mode. | * then we must not reenable interrupts. This might be a | ||||
*/ | |||||
printf("kernel trap %d with interrupts disabled\n", | |||||
type); | |||||
/* | |||||
* Page faults need interrupts disabled until later, | |||||
* and we shouldn't enable interrupts while holding | |||||
* a spin lock. | |||||
*/ | |||||
if (type != T_PAGEFLT && | |||||
td->td_md.md_spinlock_count == 0) | |||||
enable_intr(); | |||||
} | |||||
} | |||||
eva = 0; | |||||
if (type == T_PAGEFLT) { | |||||
/* | |||||
* For some Cyrix CPUs, %cr2 is clobbered by | |||||
* interrupts. This problem is worked around by using | |||||
* an interrupt gate for the pagefault handler. We | |||||
* are finally ready to read %cr2 and conditionally | |||||
* reenable interrupts. If we hold a spin lock, then | |||||
* we must not reenable interrupts. This might be a | |||||
* spurious page fault. | * spurious page fault. | ||||
*/ | */ | ||||
eva = rcr2(); | if (trap_enable_intr(type) && td->td_md.md_spinlock_count == 0 && | ||||
if (td->td_md.md_spinlock_count == 0) | frame->tf_eip != (int)cpu_switch_load_gs) | ||||
enable_intr(); | enable_intr(); | ||||
} | |||||
if (TRAPF_USERMODE(frame) && (curpcb->pcb_flags & PCB_VM86CALL) == 0) { | if (TRAPF_USERMODE(frame) && (curpcb->pcb_flags & PCB_VM86CALL) == 0) { | ||||
/* user trap */ | /* user trap */ | ||||
td->td_pticks = 0; | td->td_pticks = 0; | ||||
td->td_frame = frame; | td->td_frame = frame; | ||||
addr = frame->tf_eip; | addr = frame->tf_eip; | ||||
if (td->td_cowgen != p->p_cowgen) | if (td->td_cowgen != p->p_cowgen) | ||||
▲ Show 20 Lines • Show All 263 Lines • ▼ Show 20 Lines | #endif | ||||
* Invalid segment selectors and out of bounds | * Invalid segment selectors and out of bounds | ||||
* %eip's and %esp's can be set up in user mode. | * %eip's and %esp's can be set up in user mode. | ||||
* This causes a fault in kernel mode when the | * This causes a fault in kernel mode when the | ||||
* kernel tries to return to user mode. We want | * kernel tries to return to user mode. We want | ||||
* to get this fault so that we can fix the | * to get this fault so that we can fix the | ||||
* problem here and not have to check all the | * problem here and not have to check all the | ||||
* selectors and pointers when the user changes | * selectors and pointers when the user changes | ||||
* them. | * them. | ||||
* | |||||
* N.B. Comparing to long mode, 32-bit mode | |||||
* does not push %esp on the trap frame, | |||||
* because iretl faulted while in ring 0. As | |||||
* the consequence, there is no need to fixup | |||||
* the stack pointer for doreti_iret_fault, | |||||
* the fixup and the complimentary trap() call | |||||
* are executed on the main thread stack, not | |||||
* on the trampoline stack. | |||||
*/ | */ | ||||
if (frame->tf_eip == (int)doreti_iret) { | if (frame->tf_eip == (int)doreti_iret + setidt_disp) { | ||||
frame->tf_eip = (int)doreti_iret_fault; | frame->tf_eip = (int)doreti_iret_fault + | ||||
setidt_disp; | |||||
return; | return; | ||||
} | } | ||||
if (type == T_STKFLT) | if (type == T_STKFLT) | ||||
break; | break; | ||||
if (frame->tf_eip == (int)doreti_popl_ds) { | if (frame->tf_eip == (int)doreti_popl_ds + | ||||
frame->tf_eip = (int)doreti_popl_ds_fault; | setidt_disp) { | ||||
frame->tf_eip = (int)doreti_popl_ds_fault + | |||||
setidt_disp; | |||||
return; | return; | ||||
} | } | ||||
if (frame->tf_eip == (int)doreti_popl_es) { | if (frame->tf_eip == (int)doreti_popl_es + | ||||
frame->tf_eip = (int)doreti_popl_es_fault; | setidt_disp) { | ||||
frame->tf_eip = (int)doreti_popl_es_fault + | |||||
setidt_disp; | |||||
return; | return; | ||||
} | } | ||||
if (frame->tf_eip == (int)doreti_popl_fs) { | if (frame->tf_eip == (int)doreti_popl_fs + | ||||
frame->tf_eip = (int)doreti_popl_fs_fault; | setidt_disp) { | ||||
frame->tf_eip = (int)doreti_popl_fs_fault + | |||||
setidt_disp; | |||||
return; | return; | ||||
} | } | ||||
if (curpcb->pcb_onfault != NULL) { | if (curpcb->pcb_onfault != NULL) { | ||||
frame->tf_eip = (int)curpcb->pcb_onfault; | frame->tf_eip = (int)curpcb->pcb_onfault; | ||||
return; | return; | ||||
} | } | ||||
break; | break; | ||||
Show All 10 Lines | case T_TSSFLT: | ||||
if (frame->tf_eflags & PSL_NT) { | if (frame->tf_eflags & PSL_NT) { | ||||
frame->tf_eflags &= ~PSL_NT; | frame->tf_eflags &= ~PSL_NT; | ||||
return; | return; | ||||
} | } | ||||
break; | break; | ||||
case T_TRCTRAP: /* trace trap */ | case T_TRCTRAP: /* trace trap */ | ||||
kernel_trctrap: | kernel_trctrap: | ||||
if (frame->tf_eip == (int)IDTVEC(lcall_syscall)) { | |||||
/* | /* | ||||
* We've just entered system mode via the | |||||
* syscall lcall. Continue single stepping | |||||
* silently until the syscall handler has | |||||
* saved the flags. | |||||
*/ | |||||
return; | |||||
} | |||||
if (frame->tf_eip == (int)IDTVEC(lcall_syscall) + 1) { | |||||
/* | |||||
* The syscall handler has now saved the | |||||
* flags. Stop single stepping it. | |||||
*/ | |||||
frame->tf_eflags &= ~PSL_T; | |||||
return; | |||||
} | |||||
/* | |||||
* Ignore debug register trace traps due to | * Ignore debug register trace traps due to | ||||
* accesses in the user's address space, which | * accesses in the user's address space, which | ||||
* can happen under several conditions such as | * can happen under several conditions such as | ||||
* if a user sets a watchpoint on a buffer and | * if a user sets a watchpoint on a buffer and | ||||
* then passes that buffer to a system call. | * then passes that buffer to a system call. | ||||
* We still want to get TRCTRAPS for addresses | * We still want to get TRCTRAPS for addresses | ||||
* in kernel space because that is useful when | * in kernel space because that is useful when | ||||
* debugging the kernel. | * debugging the kernel. | ||||
▲ Show 20 Lines • Show All 50 Lines • ▼ Show 20 Lines | #endif /* DEV_ISA */ | ||||
ksiginfo_init_trap(&ksi); | ksiginfo_init_trap(&ksi); | ||||
ksi.ksi_signo = signo; | ksi.ksi_signo = signo; | ||||
ksi.ksi_code = ucode; | ksi.ksi_code = ucode; | ||||
ksi.ksi_addr = (void *)addr; | ksi.ksi_addr = (void *)addr; | ||||
ksi.ksi_trapno = type; | ksi.ksi_trapno = type; | ||||
if (uprintf_signal) { | if (uprintf_signal) { | ||||
uprintf("pid %d comm %s: signal %d err %x code %d type %d " | uprintf("pid %d comm %s: signal %d err %x code %d type %d " | ||||
"addr 0x%x esp 0x%08x eip 0x%08x " | "addr 0x%x ss 0x%04x esp 0x%08x cs 0x%04x eip 0x%08x " | ||||
"<%02x %02x %02x %02x %02x %02x %02x %02x>\n", | "<%02x %02x %02x %02x %02x %02x %02x %02x>\n", | ||||
p->p_pid, p->p_comm, signo, frame->tf_err, ucode, type, | p->p_pid, p->p_comm, signo, frame->tf_err, ucode, type, | ||||
addr, frame->tf_esp, frame->tf_eip, | addr, frame->tf_ss, frame->tf_esp, frame->tf_cs, | ||||
frame->tf_eip, | |||||
fubyte((void *)(frame->tf_eip + 0)), | fubyte((void *)(frame->tf_eip + 0)), | ||||
fubyte((void *)(frame->tf_eip + 1)), | fubyte((void *)(frame->tf_eip + 1)), | ||||
fubyte((void *)(frame->tf_eip + 2)), | fubyte((void *)(frame->tf_eip + 2)), | ||||
fubyte((void *)(frame->tf_eip + 3)), | fubyte((void *)(frame->tf_eip + 3)), | ||||
fubyte((void *)(frame->tf_eip + 4)), | fubyte((void *)(frame->tf_eip + 4)), | ||||
fubyte((void *)(frame->tf_eip + 5)), | fubyte((void *)(frame->tf_eip + 5)), | ||||
fubyte((void *)(frame->tf_eip + 6)), | fubyte((void *)(frame->tf_eip + 6)), | ||||
fubyte((void *)(frame->tf_eip + 7))); | fubyte((void *)(frame->tf_eip + 7))); | ||||
▲ Show 20 Lines • Show All 60 Lines • ▼ Show 20 Lines | if (__predict_false((td->td_pflags & TDP_NOFAULTING) != 0)) { | ||||
if (td->td_critnest != 0 || | if (td->td_critnest != 0 || | ||||
WITNESS_CHECK(WARN_SLEEPOK | WARN_GIANTOK, NULL, | WITNESS_CHECK(WARN_SLEEPOK | WARN_GIANTOK, NULL, | ||||
"Kernel page fault") != 0) { | "Kernel page fault") != 0) { | ||||
trap_fatal(frame, eva); | trap_fatal(frame, eva); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
va = trunc_page(eva); | va = trunc_page(eva); | ||||
if (va >= KERNBASE) { | if (va >= PMAP_TRM_MIN_ADDRESS) { | ||||
/* | /* | ||||
* Don't allow user-mode faults in kernel address space. | * Don't allow user-mode faults in kernel address space. | ||||
* An exception: if the faulting address is the invalid | * An exception: if the faulting address is the invalid | ||||
* instruction entry in the IDT, then the Intel Pentium | * instruction entry in the IDT, then the Intel Pentium | ||||
* F00F bug workaround was triggered, and we need to | * F00F bug workaround was triggered, and we need to | ||||
* treat it is as an illegal instruction, and not a page | * treat it is as an illegal instruction, and not a page | ||||
* fault. | * fault. | ||||
*/ | */ | ||||
#if defined(I586_CPU) && !defined(NO_F00F_HACK) | #if defined(I586_CPU) && !defined(NO_F00F_HACK) | ||||
if ((eva == (unsigned int)&idt[6]) && has_f00f_bug) | if ((eva == (unsigned int)&idt[6]) && has_f00f_bug) | ||||
return (-2); | return (-2); | ||||
#endif | #endif | ||||
if (usermode) | if (usermode) | ||||
return (SIGSEGV); | return (SIGSEGV); | ||||
trap_fatal(frame, eva); | |||||
map = kernel_map; | return (-1); | ||||
} else { | } else { | ||||
map = &p->p_vmspace->vm_map; | map = usermode ? &p->p_vmspace->vm_map : kernel_map; | ||||
/* | /* | ||||
* When accessing a user-space address, kernel must be | * Kernel cannot access a user-space address directly | ||||
* ready to accept the page fault, and provide a | * because user pages are not mapped. Also, page | ||||
* handling routine. Since accessing the address | * faults must not be caused during the interrupts. | ||||
* without the handler is a bug, do not try to handle | |||||
* it normally, and panic immediately. | |||||
*/ | */ | ||||
if (!usermode && (td->td_intr_nesting_level != 0 || | if (!usermode && td->td_intr_nesting_level != 0) { | ||||
curpcb->pcb_onfault == NULL)) { | |||||
trap_fatal(frame, eva); | trap_fatal(frame, eva); | ||||
return (-1); | return (-1); | ||||
} | } | ||||
} | } | ||||
/* | /* | ||||
* If the trap was caused by errant bits in the PTE then panic. | * If the trap was caused by errant bits in the PTE then panic. | ||||
*/ | */ | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | |||||
static void | static void | ||||
trap_fatal(frame, eva) | trap_fatal(frame, eva) | ||||
struct trapframe *frame; | struct trapframe *frame; | ||||
vm_offset_t eva; | vm_offset_t eva; | ||||
{ | { | ||||
int code, ss, esp; | int code, ss, esp; | ||||
u_int type; | u_int type; | ||||
struct soft_segment_descriptor softseg; | struct soft_segment_descriptor softseg; | ||||
char *msg; | |||||
code = frame->tf_err; | code = frame->tf_err; | ||||
type = frame->tf_trapno; | type = frame->tf_trapno; | ||||
sdtossd(&gdt[IDXSEL(frame->tf_cs & 0xffff)].sd, &softseg); | sdtossd(&gdt[IDXSEL(frame->tf_cs & 0xffff)].sd, &softseg); | ||||
if (type <= MAX_TRAP_MSG) | printf("\n\nFatal trap %d: %s while in %s mode\n", type, trap_msg(type), | ||||
msg = trap_msg[type]; | |||||
else | |||||
msg = "UNKNOWN"; | |||||
printf("\n\nFatal trap %d: %s while in %s mode\n", type, msg, | |||||
frame->tf_eflags & PSL_VM ? "vm86" : | frame->tf_eflags & PSL_VM ? "vm86" : | ||||
ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel"); | ISPL(frame->tf_cs) == SEL_UPL ? "user" : "kernel"); | ||||
#ifdef SMP | #ifdef SMP | ||||
/* two separate prints in case of a trap on an unmapped page */ | /* two separate prints in case of a trap on an unmapped page */ | ||||
printf("cpuid = %d; ", PCPU_GET(cpuid)); | printf("cpuid = %d; ", PCPU_GET(cpuid)); | ||||
printf("apic id = %02x\n", PCPU_GET(apic_id)); | printf("apic id = %02x\n", PCPU_GET(apic_id)); | ||||
#endif | #endif | ||||
if (type == T_PAGEFLT) { | if (type == T_PAGEFLT) { | ||||
▲ Show 20 Lines • Show All 46 Lines • ▼ Show 20 Lines | if (debugger_on_panic || kdb_active) { | ||||
if (kdb_trap(type, 0, frame)) { | if (kdb_trap(type, 0, frame)) { | ||||
frame->tf_err = code; /* restore error code */ | frame->tf_err = code; /* restore error code */ | ||||
return; | return; | ||||
} | } | ||||
frame->tf_err = code; /* restore error code */ | frame->tf_err = code; /* restore error code */ | ||||
} | } | ||||
#endif | #endif | ||||
printf("trap number = %d\n", type); | printf("trap number = %d\n", type); | ||||
if (type <= MAX_TRAP_MSG) | if (trap_msg(type) != NULL) | ||||
panic("%s", trap_msg[type]); | panic("%s", trap_msg(type)); | ||||
else | else | ||||
panic("unknown/reserved trap"); | panic("unknown/reserved trap"); | ||||
} | } | ||||
/* | /* | ||||
* Double fault handler. Called when a fault occurs while writing | * Double fault handler. Called when a fault occurs while writing | ||||
* a frame for a trap/exception onto the stack. This usually occurs | * a frame for a trap/exception onto the stack. This usually occurs | ||||
* when the stack overflows (such is the case with infinite recursion, | * when the stack overflows (such is the case with infinite recursion, | ||||
* for example). | * for example). | ||||
* | * | ||||
* XXX Note that the current PTD gets replaced by IdlePTD when the | * XXX Note that the current PTD gets replaced by IdlePTD when the | ||||
* task switch occurs. This means that the stack that was active at | * task switch occurs. This means that the stack that was active at | ||||
* the time of the double fault is not available at <kstack> unless | * the time of the double fault is not available at <kstack> unless | ||||
* the machine was idle when the double fault occurred. The downside | * the machine was idle when the double fault occurred. The downside | ||||
* of this is that "trace <ebp>" in ddb won't work. | * of this is that "trace <ebp>" in ddb won't work. | ||||
*/ | */ | ||||
void | void | ||||
dblfault_handler() | dblfault_handler(void) | ||||
{ | { | ||||
#ifdef KDTRACE_HOOKS | #ifdef KDTRACE_HOOKS | ||||
if (dtrace_doubletrap_func != NULL) | if (dtrace_doubletrap_func != NULL) | ||||
(*dtrace_doubletrap_func)(); | (*dtrace_doubletrap_func)(); | ||||
#endif | #endif | ||||
printf("\nFatal double fault:\n"); | printf("\nFatal double fault:\n"); | ||||
printf("eip = 0x%x\n", PCPU_GET(common_tss.tss_eip)); | printf("eip = 0x%x\n", PCPU_GET(common_tssp)->tss_eip); | ||||
printf("esp = 0x%x\n", PCPU_GET(common_tss.tss_esp)); | printf("esp = 0x%x\n", PCPU_GET(common_tssp)->tss_esp); | ||||
printf("ebp = 0x%x\n", PCPU_GET(common_tss.tss_ebp)); | printf("ebp = 0x%x\n", PCPU_GET(common_tssp)->tss_ebp); | ||||
#ifdef SMP | #ifdef SMP | ||||
/* two separate prints in case of a trap on an unmapped page */ | /* two separate prints in case of a trap on an unmapped page */ | ||||
printf("cpuid = %d; ", PCPU_GET(cpuid)); | printf("cpuid = %d; ", PCPU_GET(cpuid)); | ||||
printf("apic id = %02x\n", PCPU_GET(apic_id)); | printf("apic id = %02x\n", PCPU_GET(apic_id)); | ||||
#endif | #endif | ||||
panic("double fault"); | panic("double fault"); | ||||
} | } | ||||
▲ Show 20 Lines • Show All 112 Lines • Show Last 20 Lines |