summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2007-04-24 21:17:45 +0000
committerjhb <jhb@FreeBSD.org>2007-04-24 21:17:45 +0000
commitf98690eabe7bc9093b1dea1146b7389b03ead106 (patch)
tree610a4c73d0d92b669772e965766a2e350f38bff5
parentcafaaf6a395869780ffefbd420ab2cc885b4852f (diff)
downloadFreeBSD-src-f98690eabe7bc9093b1dea1146b7389b03ead106.zip
FreeBSD-src-f98690eabe7bc9093b1dea1146b7389b03ead106.tar.gz
Fix the triple fault used as a last resort during a reboot to actually
fault. The previous method zero'd out the page tables, invalidated the TLB, and then entered a spin loop. The idea was that the instruction after the TLB invalidate would result in a page fault and the page fault and subsequent double fault wouldn't be able to determine the physical page for their fault handlers' first instruction. This stopped working when PGE (PG_G PTE/PDE bit) support was added as a TLB invalidate via %cr3 reload doesn't clear TLB entries with PG_G set. Thus, the CPU was still able to map the virtual address for the spin loop and happily performed its infinite loop. The triple fault now uses a much more deterministic sledge-hammer approach to generate a triple fault. First, the IDT descriptor is set to point to an empty IDT, so any interrupts (including a double fault) will instantly fault. Second, we trigger a int 3 breakpoint to force an interrupt and kick off a triple fault. MFC after: 3 days
-rw-r--r--sys/amd64/amd64/vm_machdep.c11
-rw-r--r--sys/i386/i386/vm_machdep.c10
2 files changed, 15 insertions, 6 deletions
diff --git a/sys/amd64/amd64/vm_machdep.c b/sys/amd64/amd64/vm_machdep.c
index 0bc3604..ad256b4 100644
--- a/sys/amd64/amd64/vm_machdep.c
+++ b/sys/amd64/amd64/vm_machdep.c
@@ -457,6 +457,7 @@ cpu_reset()
static void
cpu_reset_real()
{
+ struct region_descriptor null_idt;
int b;
disable_intr();
@@ -494,14 +495,18 @@ cpu_reset_real()
outb(0x92, b | 0x1);
DELAY(500000); /* wait 0.5 sec to see if that did it */
}
+
printf("No known reset method worked, attempting CPU shutdown\n");
DELAY(1000000); /* wait 1 sec for printf to complete */
- /* Force a shutdown by unmapping entire address space. */
- bzero((caddr_t)PML4map, PAGE_SIZE);
+ /* Wipe the IDT. */
+ null_idt.rd_limit = 0;
+ null_idt.rd_base = 0;
+ lidt(&null_idt);
/* "good night, sweet prince .... <THUNK!>" */
- invltlb();
+ breakpoint();
+
/* NOTREACHED */
while(1);
}
diff --git a/sys/i386/i386/vm_machdep.c b/sys/i386/i386/vm_machdep.c
index 25e5a96..b0e4d21 100644
--- a/sys/i386/i386/vm_machdep.c
+++ b/sys/i386/i386/vm_machdep.c
@@ -590,6 +590,7 @@ cpu_reset()
static void
cpu_reset_real()
{
+ struct region_descriptor null_idt;
#ifndef PC98
int b;
#endif
@@ -656,11 +657,14 @@ cpu_reset_real()
printf("No known reset method worked, attempting CPU shutdown\n");
DELAY(1000000); /* wait 1 sec for printf to complete */
- /* Force a shutdown by unmapping entire address space. */
- bzero((caddr_t)PTD, NBPTD);
+ /* Wipe the IDT. */
+ null_idt.rd_limit = 0;
+ null_idt.rd_base = 0;
+ lidt(&null_idt);
/* "good night, sweet prince .... <THUNK!>" */
- invltlb();
+ breakpoint();
+
/* NOTREACHED */
while(1);
}
OpenPOWER on IntegriCloud