]> git.hungrycats.org Git - linux/commitdiff
Add doublefault handling with a task gate.
authorLinus Torvalds <torvalds@home.transmeta.com>
Wed, 19 Feb 2003 09:48:59 +0000 (01:48 -0800)
committerLinus Torvalds <torvalds@home.transmeta.com>
Wed, 19 Feb 2003 09:48:59 +0000 (01:48 -0800)
This potentially helps debugging, since otherwise a double fault
would generate a triple fault and then reboot the machine. Now
instead it can print out a note about where the problem happened,
unless all the kernel data structures are truly buggered.

arch/i386/kernel/Makefile
arch/i386/kernel/cpu/common.c
arch/i386/kernel/doublefault.c [new file with mode: 0644]
arch/i386/kernel/head.S
arch/i386/kernel/traps.c
include/asm-i386/desc.h
include/asm-i386/processor.h
include/asm-i386/segment.h

index 02e8222ddf3711343192d096e22b24e231053d97..400829ad9e89ed60e12234465344836062952941 100644 (file)
@@ -6,7 +6,8 @@ EXTRA_TARGETS := head.o init_task.o
 
 obj-y  := process.o semaphore.o signal.o entry.o traps.o irq.o vm86.o \
                ptrace.o i8259.o ioport.o ldt.o setup.o time.o sys_i386.o \
-               pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o
+               pci-dma.o i386_ksyms.o i387.o dmi_scan.o bootflag.o \
+               doublefault.o
 
 obj-y                          += cpu/
 obj-y                          += timers/
index e5ae21380f4bb88408941a4b7fed72a667273ace..a7845172e7deeba14b6e7c7a07991413cc1eb5e0 100644 (file)
@@ -490,6 +490,10 @@ void __init cpu_init (void)
        load_TR_desc();
        load_LDT(&init_mm.context);
 
+       /* Set up doublefault TSS pointer in the GDT */
+       __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss);
+       cpu_gdt_table[cpu][GDT_ENTRY_DOUBLEFAULT_TSS].b &= 0xfffffdff;
+
        /* Clear %fs and %gs. */
        asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs");
 
diff --git a/arch/i386/kernel/doublefault.c b/arch/i386/kernel/doublefault.c
new file mode 100644 (file)
index 0000000..c8eb444
--- /dev/null
@@ -0,0 +1,65 @@
+#include <linux/mm.h>
+#include <linux/sched.h>
+#include <linux/init.h>
+#include <linux/init_task.h>
+#include <linux/fs.h>
+
+#include <asm/uaccess.h>
+#include <asm/pgtable.h>
+#include <asm/desc.h>
+
+#define DOUBLEFAULT_STACKSIZE (1024)
+static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE];
+#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE)
+
+#define ptr_ok(x) ((x) > 0xc0000000 && (x) < 0xc1000000)
+
+static void doublefault_fn(void)
+{
+       struct Xgt_desc_struct gdt_desc = {0, 0};
+       unsigned long gdt, tss;
+
+       __asm__ __volatile__("sgdt %0": "=m" (gdt_desc): :"memory");
+       gdt = gdt_desc.address;
+
+       printk("double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size);
+
+       if (ptr_ok(gdt)) {
+               gdt += GDT_ENTRY_TSS << 3;
+               tss = *(u16 *)(gdt+2);
+               tss += *(u8 *)(gdt+4) << 16;
+               tss += *(u8 *)(gdt+7) << 24;
+               printk("double fault, tss at %08lx\n", tss);
+
+               if (ptr_ok(tss)) {
+                       struct tss_struct *t = (struct tss_struct *)tss;
+
+                       printk("eip = %08lx, esp = %08lx\n", t->eip, t->esp);
+
+                       printk("eax = %08lx, ebx = %08lx, ecx = %08lx, edx = %08lx\n",
+                               t->eax, t->ebx, t->ecx, t->edx);
+                       printk("esi = %08lx, edi = %08lx\n",
+                               t->esi, t->edi);
+               }
+       }
+
+       for (;;) /* nothing */;
+}
+
+struct tss_struct doublefault_tss __cacheline_aligned = {
+       .esp0           = STACK_START,
+       .ss0            = __KERNEL_DS,
+       .ldt            = 0,
+       .bitmap         = INVALID_IO_BITMAP_OFFSET,
+       .io_bitmap      = { [0 ... IO_BITMAP_SIZE ] = ~0 },
+
+       .eip            = (unsigned long) doublefault_fn,
+       .eflags         = 0x00000082,
+       .esp            = STACK_START,
+       .es             = __USER_DS,
+       .cs             = __KERNEL_CS,
+       .ss             = __KERNEL_DS,
+       .ds             = __USER_DS,
+
+       .__cr3          = __pa(swapper_pg_dir)
+};
index 59c5b1d02a13e1344239af709426c9479bd0e2eb..c03351ac5a39365b9c6f9ae053aab55d36469eb7 100644 (file)
@@ -476,6 +476,13 @@ ENTRY(cpu_gdt_table)
        .quad 0x00009a0000000000        /* 0xc0 APM CS 16 code (16 bit) */
        .quad 0x0040920000000000        /* 0xc8 APM DS    data */
 
+       .quad 0x0000000000000000        /* 0xd0 - unused */
+       .quad 0x0000000000000000        /* 0xd8 - unused */
+       .quad 0x0000000000000000        /* 0xe0 - unused */
+       .quad 0x0000000000000000        /* 0xe8 - unused */
+       .quad 0x0000000000000000        /* 0xf0 - unused */
+       .quad 0x0000000000000000        /* 0xf8 - GDT entry 31: double-fault TSS */
+
 #if CONFIG_SMP
        .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */
 #endif
index bca393dbee668c74edd94f157a18f54928bba398..210d9069e14d3b31438cb685ff941dc9320a9d0a 100644 (file)
@@ -775,7 +775,7 @@ void __init trap_init_f00f_bug(void)
 }
 #endif
 
-#define _set_gate(gate_addr,type,dpl,addr) \
+#define _set_gate(gate_addr,type,dpl,addr,seg) \
 do { \
   int __d0, __d1; \
   __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \
@@ -785,7 +785,7 @@ do { \
        :"=m" (*((long *) (gate_addr))), \
         "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \
        :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \
-        "3" ((char *) (addr)),"2" (__KERNEL_CS << 16)); \
+        "3" ((char *) (addr)),"2" ((seg) << 16)); \
 } while (0)
 
 
@@ -797,22 +797,27 @@ do { \
  */
 void set_intr_gate(unsigned int n, void *addr)
 {
-       _set_gate(idt_table+n,14,0,addr);
+       _set_gate(idt_table+n,14,0,addr,__KERNEL_CS);
 }
 
 static void __init set_trap_gate(unsigned int n, void *addr)
 {
-       _set_gate(idt_table+n,15,0,addr);
+       _set_gate(idt_table+n,15,0,addr,__KERNEL_CS);
 }
 
 static void __init set_system_gate(unsigned int n, void *addr)
 {
-       _set_gate(idt_table+n,15,3,addr);
+       _set_gate(idt_table+n,15,3,addr,__KERNEL_CS);
 }
 
 static void __init set_call_gate(void *a, void *addr)
 {
-       _set_gate(a,12,3,addr);
+       _set_gate(a,12,3,addr,__KERNEL_CS);
+}
+
+static void __init set_task_gate(unsigned int n, unsigned int gdt_entry)
+{
+       _set_gate(idt_table+n,5,0,0,(gdt_entry<<3));
 }
 
 
@@ -843,7 +848,7 @@ void __init trap_init(void)
        set_system_gate(5,&bounds);
        set_trap_gate(6,&invalid_op);
        set_trap_gate(7,&device_not_available);
-       set_trap_gate(8,&double_fault);
+       set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS);
        set_trap_gate(9,&coprocessor_segment_overrun);
        set_trap_gate(10,&invalid_TSS);
        set_trap_gate(11,&segment_not_present);
index d42e28c1e3faf90ff9e7fe85038e96c081e93ab9..9361aff2e25c2a2bee549f054c33b50dd0142d5d 100644 (file)
@@ -42,11 +42,13 @@ __asm__ __volatile__ ("movw %w3,0(%2)\n\t" \
        "rorl $16,%%eax" \
        : "=m"(*(n)) : "a" (addr), "r"(n), "ir"(limit), "i"(type))
 
-static inline void set_tss_desc(unsigned int cpu, void *addr)
+static inline void __set_tss_desc(unsigned int cpu, unsigned int entry, void *addr)
 {
-       _set_tssldt_desc(&cpu_gdt_table[cpu][GDT_ENTRY_TSS], (int)addr, 235, 0x89);
+       _set_tssldt_desc(&cpu_gdt_table[cpu][entry], (int)addr, 235, 0x89);
 }
 
+#define set_tss_desc(cpu,addr) __set_tss_desc(cpu, GDT_ENTRY_TSS, addr)
+
 static inline void set_ldt_desc(unsigned int cpu, void *addr, unsigned int size)
 {
        _set_tssldt_desc(&cpu_gdt_table[cpu][GDT_ENTRY_LDT], (int)addr, ((size << 3)-1), 0x82);
index 83fc8ffb9cab253fdb185e0ee6430439e9887ba4..5ed85117e7ef255828538ee226d49270c525a0fb 100644 (file)
@@ -83,6 +83,7 @@ struct cpuinfo_x86 {
 extern struct cpuinfo_x86 boot_cpu_data;
 extern struct cpuinfo_x86 new_cpu_data;
 extern struct tss_struct init_tss[NR_CPUS];
+extern struct tss_struct doublefault_tss;
 
 #ifdef CONFIG_SMP
 extern struct cpuinfo_x86 cpu_data[];
index 3f272860a6b3e81de64b0c2199d3e1ad81b5f126..abe3440a93cebccecbfc0c8ef2e4096d7c8bec21 100644 (file)
  *  23 - APM BIOS support
  *  24 - APM BIOS support
  *  25 - APM BIOS support 
+ *
+ *  26 - unused
+ *  27 - unused
+ *  28 - unused
+ *  29 - unused
+ *  30 - unused
+ *  31 - TSS for double fault handler
  */
 #define GDT_ENTRY_TLS_ENTRIES  3
 #define GDT_ENTRY_TLS_MIN      6
 #define GDT_ENTRY_PNPBIOS_BASE         (GDT_ENTRY_KERNEL_BASE + 6)
 #define GDT_ENTRY_APMBIOS_BASE         (GDT_ENTRY_KERNEL_BASE + 11)
 
+#define GDT_ENTRY_DOUBLEFAULT_TSS      31
+
 /*
- * The GDT has 25 entries but we pad it to cacheline boundary:
+ * The GDT has 32 entries
  */
-#define GDT_ENTRIES 28
+#define GDT_ENTRIES 32
 
 #define GDT_SIZE (GDT_ENTRIES * 8)