aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorChuck Ebbert <cebbert@redhat.com>2007-08-10 16:31:11 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-08-11 18:58:14 -0400
commit3dab307e527f2a9bbb4f9d00240374bb93d1945f (patch)
tree3e9a83d6cc1cee1dcfedff700c0b4aeebaa2f8d5 /arch/i386
parent5fe4486c79cdc8dbbb2a9c3f884a5ad0830a5a23 (diff)
i386: Fix double fault handler
The new percpu code has apparently broken the doublefault handler when CONFIG_DEBUG_SPINLOCK is set. Doublefault is handled by a hardware task, making the check SPIN_BUG_ON(lock->owner == current, lock, "recursion"); fault because it uses the FS register to access the percpu data for current, and that register is zero in the new TSS. (The trace I saw was on 2.6.20 where it was GS, but it looks like this will still happen with FS on 2.6.22.) Initializing FS in the doublefault_tss should fix it. AK: Also fix broken ptr_ok() and turn printks into KERN_EMERG AK: And add a PANIC prefix to make clear the system will hang AK: (e.g. x86-64 will recover) Signed-off-by: Chuck Ebbert <cebbert@redhat.com> Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/doublefault.c13
1 files changed, 7 insertions, 6 deletions
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
index 265c5597efb0..40978af630e7 100644
--- a/arch/i386/kernel/doublefault.c
+++ b/arch/i386/kernel/doublefault.c
@@ -13,7 +13,7 @@
13static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; 13static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
14#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) 14#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
15 15
16#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000) 16#define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM)
17 17
18static void doublefault_fn(void) 18static void doublefault_fn(void)
19{ 19{
@@ -23,23 +23,23 @@ static void doublefault_fn(void)
23 store_gdt(&gdt_desc); 23 store_gdt(&gdt_desc);
24 gdt = gdt_desc.address; 24 gdt = gdt_desc.address;
25 25
26 printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); 26 printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
27 27
28 if (ptr_ok(gdt)) { 28 if (ptr_ok(gdt)) {
29 gdt += GDT_ENTRY_TSS << 3; 29 gdt += GDT_ENTRY_TSS << 3;
30 tss = *(u16 *)(gdt+2); 30 tss = *(u16 *)(gdt+2);
31 tss += *(u8 *)(gdt+4) << 16; 31 tss += *(u8 *)(gdt+4) << 16;
32 tss += *(u8 *)(gdt+7) << 24; 32 tss += *(u8 *)(gdt+7) << 24;
33 printk("double fault, tss at %08lx\n", tss); 33 printk(KERN_EMERG "double fault, tss at %08lx\n", tss);
34 34
35 if (ptr_ok(tss)) { 35 if (ptr_ok(tss)) {
36 struct i386_hw_tss *t = (struct i386_hw_tss *)tss; 36 struct i386_hw_tss *t = (struct i386_hw_tss *)tss;
37 37
38 printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp); 38 printk(KERN_EMERG "eip = %08lx, esp = %08lx\n", t->eip, t->esp);
39 39
40 printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", 40 printk(KERN_EMERG "eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
41 t->eax, t->ebx, t->ecx, t->edx); 41 t->eax, t->ebx, t->ecx, t->edx);
42 printk("esi = %08lx, edi = %08lx\n", 42 printk(KERN_EMERG "esi = %08lx, edi = %08lx\n",
43 t->esi, t->edi); 43 t->esi, t->edi);
44 } 44 }
45 } 45 }
@@ -63,6 +63,7 @@ struct tss_struct doublefault_tss __cacheline_aligned = {
63 .cs = __KERNEL_CS, 63 .cs = __KERNEL_CS,
64 .ss = __KERNEL_DS, 64 .ss = __KERNEL_DS,
65 .ds = __USER_DS, 65 .ds = __USER_DS,
66 .fs = __KERNEL_PERCPU,
66 67
67 .__cr3 = __pa(swapper_pg_dir) 68 .__cr3 = __pa(swapper_pg_dir)
68 } 69 }