From 093565f2299e17b9488a3a58197f6d9bab0cca9e Mon Sep 17 00:00:00 2001 From: Matthew Dillon Date: Fri, 29 Oct 2010 12:00:35 -0700 Subject: [PATCH] kernel - Make the x86-64 double-fault exception operational * Finish implementing the double-fault exception. Only cpu0 implemented the proper interrupt stack configuration before. Now all cpus implement the proper interrupt stack. * For x86-64 use the idle thread stack for the double-fault exception stack for now (probably not the best idea but better than nothing). * For both i386 and x86-64, when a double fault occurs, report whether it is a generic double fault or whether it is due to a kernel stack guard. --- sys/platform/pc32/i386/trap.c | 22 ++++++++++++++++++++-- sys/platform/pc64/x86_64/machdep.c | 8 ++++---- sys/platform/pc64/x86_64/mp_machdep.c | 9 ++++++--- sys/platform/pc64/x86_64/trap.c | 25 ++++++++++++++++++++++++- 4 files changed, 54 insertions(+), 10 deletions(-) diff --git a/sys/platform/pc32/i386/trap.c b/sys/platform/pc32/i386/trap.c index e7b9192cf6..ac750a6d7a 100644 --- a/sys/platform/pc32/i386/trap.c +++ b/sys/platform/pc32/i386/trap.c @@ -1139,19 +1139,37 @@ trap_fatal(struct trapframe *frame, vm_offset_t eva) * the machine was idle when the double fault occurred. The downside * of this is that "trace " in ddb won't work. */ +static __inline +int +in_kstack_guard(register_t rptr) +{ + thread_t td = curthread; + + if ((char *)rptr >= td->td_kstack && + (char *)rptr < td->td_kstack + PAGE_SIZE) { + return 1; + } + return 0; +} + void dblfault_handler(void) { struct mdglobaldata *gd = mdcpu; - kprintf("\nFatal double fault:\n"); + if (in_kstack_guard(gd->gd_common_tss.tss_esp) || + in_kstack_guard(gd->gd_common_tss.tss_ebp)) { + kprintf0("DOUBLE FAULT - KERNEL STACK GUARD HIT!\n"); + } else { + kprintf0("DOUBLE FAULT:\n"); + } kprintf("eip = 0x%x\n", gd->gd_common_tss.tss_eip); kprintf("esp = 0x%x\n", gd->gd_common_tss.tss_esp); kprintf("ebp = 0x%x\n", gd->gd_common_tss.tss_ebp); #ifdef SMP /* three separate prints in case of a trap on an unmapped page */ kprintf("mp_lock = %08x; ", mp_lock); - kprintf("cpuid = %d; ", mycpu->gd_cpuid); + kprintf("cpuid = %d; ", gd->mi.gd_cpuid); kprintf("lapic.id = %08x\n", lapic.id); #endif panic("double fault"); diff --git a/sys/platform/pc64/x86_64/machdep.c b/sys/platform/pc64/x86_64/machdep.c index 045c28d0dc..2c7604f28d 100644 --- a/sys/platform/pc64/x86_64/machdep.c +++ b/sys/platform/pc64/x86_64/machdep.c @@ -1164,8 +1164,6 @@ struct region_descriptor r_gdt, r_idt; extern int has_f00f_bug; #endif -static char dblfault_stack[PAGE_SIZE] __aligned(16); - /* JG proc0paddr is a virtual address */ void *proc0paddr; /* JG alignment? */ @@ -1810,8 +1808,10 @@ hammer_time(u_int64_t modulep, u_int64_t physfree) gd->gd_common_tss.tss_rsp0 &= ~(register_t)0xF; gd->gd_rsp0 = gd->gd_common_tss.tss_rsp0; - /* doublefault stack space, runs on ist1 */ - gd->gd_common_tss.tss_ist1 = (long)&dblfault_stack[sizeof(dblfault_stack)]; + /* double fault stack */ + gd->gd_common_tss.tss_ist1 = + (long)&gd->mi.gd_prvspace->idlestack[ + sizeof(gd->mi.gd_prvspace->idlestack)]; /* Set the IO permission bitmap (empty due to tss seg limit) */ gd->gd_common_tss.tss_iobase = sizeof(struct x86_64tss); diff --git a/sys/platform/pc64/x86_64/mp_machdep.c b/sys/platform/pc64/x86_64/mp_machdep.c index 5a7dd686bf..3709c4ba89 100644 --- a/sys/platform/pc64/x86_64/mp_machdep.c +++ b/sys/platform/pc64/x86_64/mp_machdep.c @@ -614,9 +614,12 @@ init_secondary(void) #endif md->gd_tss_gdt = &gdt[myid * NGDT + GPROC0_SEL]; md->gd_common_tssd = *md->gd_tss_gdt; -#if 0 /* JG XXX */ - md->gd_common_tss.tss_ist1 = (long)&doublefault_stack[PAGE_SIZE]; -#endif + + /* double fault stack */ + md->gd_common_tss.tss_ist1 = + (long)&md->mi.gd_prvspace->idlestack[ + sizeof(md->mi.gd_prvspace->idlestack)]; + ltr(gsel_tss); /* diff --git a/sys/platform/pc64/x86_64/trap.c b/sys/platform/pc64/x86_64/trap.c index b5e0215794..40ce142aab 100644 --- a/sys/platform/pc64/x86_64/trap.c +++ b/sys/platform/pc64/x86_64/trap.c @@ -996,10 +996,33 @@ trap_fatal(struct trapframe *frame, vm_offset_t eva) * when the stack overflows (such is the case with infinite recursion, * for example). */ +static __inline +int +in_kstack_guard(register_t rptr) +{ + thread_t td = curthread; + + if ((char *)rptr >= td->td_kstack && + (char *)rptr < td->td_kstack + PAGE_SIZE) { + return 1; + } + return 0; +} + void dblfault_handler(struct trapframe *frame) { - kprintf0("DOUBLE FAULT\n"); + thread_t td = curthread; + + if (in_kstack_guard(frame->tf_rsp) || in_kstack_guard(frame->tf_rbp)) { + kprintf0("DOUBLE FAULT - KERNEL STACK GUARD HIT!\n"); + if (in_kstack_guard(frame->tf_rsp)) + frame->tf_rsp = (register_t)(td->td_kstack + PAGE_SIZE); + if (in_kstack_guard(frame->tf_rbp)) + frame->tf_rbp = (register_t)(td->td_kstack + PAGE_SIZE); + } else { + kprintf0("DOUBLE FAULT\n"); + } kprintf("\nFatal double fault\n"); kprintf("rip = 0x%lx\n", frame->tf_rip); kprintf("rsp = 0x%lx\n", frame->tf_rsp); -- 2.11.4.GIT