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>

authored by Chuck Ebbert and committed by Linus Torvalds 3dab307e 5fe4486c

+7 -6
+7 -6
arch/i386/kernel/doublefault.c
··· 13 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; 14 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) 15 16 - #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000) 17 18 static void doublefault_fn(void) 19 { ··· 23 store_gdt(&gdt_desc); 24 gdt = gdt_desc.address; 25 26 - printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); 27 28 if (ptr_ok(gdt)) { 29 gdt += GDT_ENTRY_TSS << 3; 30 tss = *(u16 *)(gdt+2); 31 tss += *(u8 *)(gdt+4) << 16; 32 tss += *(u8 *)(gdt+7) << 24; 33 - printk("double fault, tss at %08lx\n", tss); 34 35 if (ptr_ok(tss)) { 36 struct i386_hw_tss *t = (struct i386_hw_tss *)tss; 37 38 - printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp); 39 40 - printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", 41 t->eax, t->ebx, t->ecx, t->edx); 42 - printk("esi = %08lx, edi = %08lx\n", 43 t->esi, t->edi); 44 } 45 } ··· 63 .cs = __KERNEL_CS, 64 .ss = __KERNEL_DS, 65 .ds = __USER_DS, 66 67 .__cr3 = __pa(swapper_pg_dir) 68 }
··· 13 static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; 14 #define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) 15 16 + #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + MAXMEM) 17 18 static void doublefault_fn(void) 19 { ··· 23 store_gdt(&gdt_desc); 24 gdt = gdt_desc.address; 25 26 + printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); 27 28 if (ptr_ok(gdt)) { 29 gdt += GDT_ENTRY_TSS << 3; 30 tss = *(u16 *)(gdt+2); 31 tss += *(u8 *)(gdt+4) << 16; 32 tss += *(u8 *)(gdt+7) << 24; 33 + printk(KERN_EMERG "double fault, tss at %08lx\n", tss); 34 35 if (ptr_ok(tss)) { 36 struct i386_hw_tss *t = (struct i386_hw_tss *)tss; 37 38 + printk(KERN_EMERG "eip = %08lx, esp = %08lx\n", t->eip, t->esp); 39 40 + printk(KERN_EMERG "eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n", 41 t->eax, t->ebx, t->ecx, t->edx); 42 + printk(KERN_EMERG "esi = %08lx, edi = %08lx\n", 43 t->esi, t->edi); 44 } 45 } ··· 63 .cs = __KERNEL_CS, 64 .ss = __KERNEL_DS, 65 .ds = __USER_DS, 66 + .fs = __KERNEL_PERCPU, 67 68 .__cr3 = __pa(swapper_pg_dir) 69 }