vserver 1.9.5.x5
[linux-2.6.git] / arch / x86_64 / kernel / traps.c
index c0a31a4..72e672e 100644 (file)
 #include <asm/pgalloc.h>
 #include <asm/pda.h>
 #include <asm/proto.h>
+#include <asm/nmi.h>
 
 #include <linux/irq.h>
 
+
 extern struct gate_struct idt_table[256]; 
 
 asmlinkage void divide_error(void);
@@ -72,6 +74,17 @@ asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void call_debug(void);
 
 struct notifier_block *die_chain;
+static DEFINE_SPINLOCK(die_notifier_lock);
+
+int register_die_notifier(struct notifier_block *nb)
+{
+       int err = 0;
+       unsigned long flags;
+       spin_lock_irqsave(&die_notifier_lock, flags);
+       err = notifier_chain_register(&die_chain, nb);
+       spin_unlock_irqrestore(&die_notifier_lock, flags);
+       return err;
+}
 
 static inline void conditional_sti(struct pt_regs *regs)
 {
@@ -311,7 +324,7 @@ void out_of_line_bug(void)
        BUG(); 
 } 
 
-static spinlock_t die_lock = SPIN_LOCK_UNLOCKED;
+static DEFINE_SPINLOCK(die_lock);
 static int die_owner = -1;
 
 void oops_begin(void)
@@ -376,13 +389,20 @@ static inline void die_if_kernel(const char * str, struct pt_regs * regs, long e
                die(str, regs, err);
 }
 
-static inline unsigned long get_cr2(void)
+void die_nmi(char *str, struct pt_regs *regs)
 {
-       unsigned long address;
-
-       /* get the address */
-       __asm__("movq %%cr2,%0":"=r" (address));
-       return address;
+       oops_begin();
+       /*
+        * We are in trouble anyway, lets at least try
+        * to get a message out.
+        */
+       printk(str, safe_smp_processor_id());
+       show_registers(regs);
+       if (panic_on_timeout || panic_on_oops)
+               panic("nmi watchdog");
+       printk("console shuts up ...\n");
+       oops_end();
+       do_exit(SIGSEGV);
 }
 
 static void do_trap(int trapnr, int signr, char *str, 
@@ -458,7 +478,6 @@ asmlinkage void do_##name(struct pt_regs * regs, long error_code) \
 }
 
 DO_ERROR_INFO( 0, SIGFPE,  "divide error", divide_error, FPE_INTDIV, regs->rip)
-DO_ERROR( 3, SIGTRAP, "int3", int3);
 DO_ERROR( 4, SIGSEGV, "overflow", overflow)
 DO_ERROR( 5, SIGSEGV, "bounds", bounds)
 DO_ERROR_INFO( 6, SIGILL,  "invalid operand", invalid_op, ILL_ILLOPN, regs->rip)
@@ -528,8 +547,9 @@ asmlinkage void do_general_protection(struct pt_regs * regs, long error_code)
                        regs->rip = fixup->fixup;
                        return;
                }
-               notify_die(DIE_GPF, "general protection fault", regs, error_code,
-                          13, SIGSEGV); 
+               if (notify_die(DIE_GPF, "general protection fault", regs,
+                                       error_code, 13, SIGSEGV) == NOTIFY_STOP)
+                       return;
                die("general protection fault", regs, error_code);
        }
 }
@@ -563,9 +583,13 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
        printk("Do you have a strange power saving mode enabled?\n");
 }
 
-asmlinkage void default_do_nmi(struct pt_regs * regs)
+asmlinkage void default_do_nmi(struct pt_regs *regs)
 {
-       unsigned char reason = inb(0x61);
+       unsigned char reason = 0;
+
+       /* Only the BSP gets external NMIs from the system.  */
+       if (!smp_processor_id())
+               reason = get_nmi_reason();
 
        if (!(reason & 0xc0)) {
                if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 0, SIGINT)
@@ -586,6 +610,9 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
        }
        if (notify_die(DIE_NMI, "nmi", regs, reason, 0, SIGINT) == NOTIFY_STOP)
                return; 
+
+       /* AK: following checks seem to be broken on modern chipsets. FIXME */
+
        if (reason & 0x80)
                mem_parity_error(reason, regs);
        if (reason & 0x40)
@@ -601,6 +628,15 @@ asmlinkage void default_do_nmi(struct pt_regs * regs)
        inb(0x71);              /* dummy */
 }
 
+asmlinkage void do_int3(struct pt_regs * regs, long error_code)
+{
+       if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) == NOTIFY_STOP) {
+               return;
+       }
+       do_trap(3, SIGTRAP, "int3", regs, error_code, NULL);
+       return;
+}
+
 /* runs on IST stack. */
 asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
 {
@@ -630,6 +666,10 @@ asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
 
        asm("movq %%db6,%0" : "=r" (condition));
 
+       if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code,
+                                               SIGTRAP) == NOTIFY_STOP) {
+               return regs;
+       }
        conditional_sti(regs);
 
        /* Mask out spurious debug traps due to lazy DR7 setting */
@@ -642,7 +682,9 @@ asmlinkage void *do_debug(struct pt_regs * regs, unsigned long error_code)
        tsk->thread.debugreg6 = condition;
 
        /* Mask out spurious TF errors due to lazy TF clearing */
-       if (condition & DR_STEP) {
+       if ((condition & DR_STEP) &&
+           (notify_die(DIE_DEBUGSTEP, "debugstep", regs, condition,
+                       1, SIGTRAP) != NOTIFY_STOP)) {
                /*
                 * The TF error should be masked out only if the current
                 * process is not traced and if the TRAP flag has been set
@@ -834,6 +876,10 @@ asmlinkage void do_spurious_interrupt_bug(struct pt_regs * regs)
 {
 }
 
+asmlinkage void __attribute__((weak)) smp_thermal_interrupt(void)
+{
+}
+
 /*
  *  'math_state_restore()' saves the current math information in the
  * old math state array, and gets the new ones from the current task
@@ -846,7 +892,7 @@ asmlinkage void math_state_restore(void)
        struct task_struct *me = current;
        clts();                 /* Allow maths ops (or we recurse) */
 
-       if (!me->used_math)
+       if (!used_math())
                init_fpu(me);
        restore_fpu_checking(&me->thread.i387.fxsave);
        me->thread_info->status |= TS_USEDFPU;
@@ -862,8 +908,8 @@ void __init trap_init(void)
        set_intr_gate(0,&divide_error);
        set_intr_gate_ist(1,&debug,DEBUG_STACK);
        set_intr_gate_ist(2,&nmi,NMI_STACK);
-       set_system_gate(3,&int3);       /* int3-5 can be called from all */
-       set_system_gate(4,&overflow);
+       set_system_gate(3,&int3);
+       set_system_gate(4,&overflow);   /* int4-5 can be called from all */
        set_system_gate(5,&bounds);
        set_intr_gate(6,&invalid_op);
        set_intr_gate(7,&device_not_available);
@@ -877,7 +923,9 @@ void __init trap_init(void)
        set_intr_gate(15,&spurious_interrupt_bug);
        set_intr_gate(16,&coprocessor_error);
        set_intr_gate(17,&alignment_check);
+#ifdef CONFIG_X86_MCE
        set_intr_gate_ist(18,&machine_check, MCE_STACK); 
+#endif
        set_intr_gate(19,&simd_coprocessor_error);
 
 #ifdef CONFIG_IA32_EMULATION
@@ -900,3 +948,11 @@ static int __init oops_dummy(char *s)
        return -1; 
 } 
 __setup("oops=", oops_dummy); 
+
+static int __init kstack_setup(char *s)
+{
+       kstack_depth_to_print = simple_strtoul(s,NULL,0);
+       return 0;
+}
+__setup("kstack=", kstack_setup);
+