]> Pileus Git - ~andy/linux/blobdiff - arch/i386/kernel/traps.c
[PATCH] Generic BUG for i386
[~andy/linux] / arch / i386 / kernel / traps.c
index f9bb1f89d687e15fa25ebac75b24eabe91a239c4..2b30dbf8d1170167283d57a7cbe3b0099231c788 100644 (file)
@@ -29,6 +29,8 @@
 #include <linux/kexec.h>
 #include <linux/unwind.h>
 #include <linux/uaccess.h>
+#include <linux/nmi.h>
+#include <linux/bug.h>
 
 #ifdef CONFIG_EISA
 #include <linux/ioport.h>
@@ -91,7 +93,7 @@ asmlinkage void alignment_check(void);
 asmlinkage void spurious_interrupt_bug(void);
 asmlinkage void machine_check(void);
 
-static int kstack_depth_to_print = 24;
+int kstack_depth_to_print = 24;
 #ifdef CONFIG_STACK_UNWIND
 static int call_trace = 1;
 #else
@@ -160,12 +162,19 @@ dump_trace_unwind(struct unwind_frame_info *info, void *data)
 {
        struct ops_and_data *oad = (struct ops_and_data *)data;
        int n = 0;
+       unsigned long sp = UNW_SP(info);
 
+       if (arch_unw_user_mode(info))
+               return -1;
        while (unwind(info) == 0 && UNW_PC(info)) {
                n++;
                oad->ops->address(oad->data, UNW_PC(info));
                if (arch_unw_user_mode(info))
                        break;
+               if ((sp & ~(PAGE_SIZE - 1)) == (UNW_SP(info) & ~(PAGE_SIZE - 1))
+                   && sp > UNW_SP(info))
+                       break;
+               sp = UNW_SP(info);
        }
        return n;
 }
@@ -248,6 +257,7 @@ void dump_trace(struct task_struct *task, struct pt_regs *regs,
                stack = (unsigned long*)context->previous_esp;
                if (!stack)
                        break;
+               touch_nmi_watchdog();
        }
 }
 EXPORT_SYMBOL(dump_trace);
@@ -380,7 +390,7 @@ void show_registers(struct pt_regs *regs)
         * time of the fault..
         */
        if (in_kernel) {
-               u8 __user *eip;
+               u8 *eip;
                int code_bytes = 64;
                unsigned char c;
 
@@ -389,18 +399,20 @@ void show_registers(struct pt_regs *regs)
 
                printk(KERN_EMERG "Code: ");
 
-               eip = (u8 __user *)regs->eip - 43;
-               if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
+               eip = (u8 *)regs->eip - 43;
+               if (eip < (u8 *)PAGE_OFFSET ||
+                       probe_kernel_address(eip, c)) {
                        /* try starting at EIP */
-                       eip = (u8 __user *)regs->eip;
+                       eip = (u8 *)regs->eip;
                        code_bytes = 32;
                }
                for (i = 0; i < code_bytes; i++, eip++) {
-                       if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) {
+                       if (eip < (u8 *)PAGE_OFFSET ||
+                               probe_kernel_address(eip, c)) {
                                printk(" Bad EIP value.");
                                break;
                        }
-                       if (eip == (u8 __user *)regs->eip)
+                       if (eip == (u8 *)regs->eip)
                                printk("<%02x> ", c);
                        else
                                printk("%02x ", c);
@@ -409,43 +421,22 @@ void show_registers(struct pt_regs *regs)
        printk("\n");
 }      
 
-static void handle_BUG(struct pt_regs *regs)
+int is_valid_bugaddr(unsigned long eip)
 {
-       unsigned long eip = regs->eip;
        unsigned short ud2;
 
        if (eip < PAGE_OFFSET)
-               return;
-       if (probe_kernel_address((unsigned short __user *)eip, ud2))
-               return;
-       if (ud2 != 0x0b0f)
-               return;
+               return 0;
+       if (probe_kernel_address((unsigned short *)eip, ud2))
+               return 0;
 
-       printk(KERN_EMERG "------------[ cut here ]------------\n");
-
-#ifdef CONFIG_DEBUG_BUGVERBOSE
-       do {
-               unsigned short line;
-               char *file;
-               char c;
-
-               if (probe_kernel_address((unsigned short __user *)(eip + 2),
-                                       line))
-                       break;
-               if (__get_user(file, (char * __user *)(eip + 4)) ||
-                   (unsigned long)file < PAGE_OFFSET || __get_user(c, file))
-                       file = "<bad filename>";
-
-               printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line);
-               return;
-       } while (0);
-#endif
-       printk(KERN_EMERG "Kernel BUG at [verbose debug info unavailable]\n");
+       return ud2 == 0x0b0f;
 }
 
-/* This is gone through when something in the kernel
- * has done something bad and is about to be terminated.
-*/
+/*
+ * This is gone through when something in the kernel has done something bad and
+ * is about to be terminated.
+ */
 void die(const char * str, struct pt_regs * regs, long err)
 {
        static struct {
@@ -453,7 +444,7 @@ void die(const char * str, struct pt_regs * regs, long err)
                u32 lock_owner;
                int lock_owner_depth;
        } die = {
-               .lock =                 SPIN_LOCK_UNLOCKED,
+               .lock =                 __SPIN_LOCK_UNLOCKED(die.lock),
                .lock_owner =           -1,
                .lock_owner_depth =     0
        };
@@ -477,7 +468,8 @@ void die(const char * str, struct pt_regs * regs, long err)
                unsigned long esp;
                unsigned short ss;
 
-               handle_BUG(regs);
+               report_bug(regs->eip);
+
                printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
 #ifdef CONFIG_PREEMPT
                printk(KERN_EMERG "PREEMPT ");
@@ -708,8 +700,7 @@ mem_parity_error(unsigned char reason, struct pt_regs * regs)
 {
        printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on "
                "CPU %d.\n", reason, smp_processor_id());
-       printk(KERN_EMERG "You probably have a hardware problem with your RAM "
-                       "chips\n");
+       printk(KERN_EMERG "You have some hardware problem, likely on the PCI bus.\n");
        if (panic_on_unrecovered_nmi)
                 panic("NMI: Not continuing");
 
@@ -1118,7 +1109,7 @@ fastcall unsigned long patch_espfix_desc(unsigned long uesp,
  * Must be called with kernel preemption disabled (in this case,
  * local interrupts are disabled at the call-site in entry.S).
  */
-asmlinkage void math_state_restore(struct pt_regs regs)
+asmlinkage void math_state_restore(void)
 {
        struct thread_info *thread = current_thread_info();
        struct task_struct *tsk = thread->task;
@@ -1128,6 +1119,7 @@ asmlinkage void math_state_restore(struct pt_regs regs)
                init_fpu(tsk);
        restore_fpu(tsk);
        thread->status |= TS_USEDFPU;   /* So we fnsave on switch_to() */
+       tsk->fpu_counter++;
 }
 
 #ifndef CONFIG_MATH_EMULATION