sh64: Fix up the CONFIG_GENERIC_BUG=n build.
[safe/jmp/linux-2.6] / arch / sh / kernel / traps.c
index bf70827..7b03633 100644 (file)
@@ -2,24 +2,51 @@
 #include <linux/io.h>
 #include <linux/types.h>
 #include <linux/kdebug.h>
+#include <linux/signal.h>
+#include <linux/sched.h>
+#include <linux/uaccess.h>
+#include <linux/hardirq.h>
+#include <asm/unwinder.h>
 #include <asm/system.h>
 
-#ifdef CONFIG_BUG
+#ifdef CONFIG_GENERIC_BUG
 static void handle_BUG(struct pt_regs *regs)
 {
+       const struct bug_entry *bug;
+       unsigned long bugaddr = regs->pc;
        enum bug_trap_type tt;
-       tt = report_bug(regs->pc, regs);
+
+       if (!is_valid_bugaddr(bugaddr))
+               goto invalid;
+
+       bug = find_bug(bugaddr);
+
+       /* Switch unwinders when unwind_stack() is called */
+       if (bug->flags & BUGFLAG_UNWINDER)
+               unwinder_faulted = 1;
+
+       tt = report_bug(bugaddr, regs);
        if (tt == BUG_TRAP_TYPE_WARN) {
-               regs->pc += instruction_size(regs->pc);
+               regs->pc += instruction_size(bugaddr);
                return;
        }
 
+invalid:
        die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
 }
 
 int is_valid_bugaddr(unsigned long addr)
 {
-       return addr >= PAGE_OFFSET;
+       insn_size_t opcode;
+
+       if (addr < PAGE_OFFSET)
+               return 0;
+       if (probe_kernel_address((insn_size_t *)addr, opcode))
+               return 0;
+       if (opcode == TRAPA_BUG_OPCODE)
+               return 1;
+
+       return 0;
 }
 #endif
 
@@ -54,13 +81,36 @@ BUILD_TRAP_HANDLER(bug)
                       SIGTRAP) == NOTIFY_STOP)
                return;
 
-#ifdef CONFIG_BUG
+#ifdef CONFIG_GENERIC_BUG
        if (__kernel_text_address(instruction_pointer(regs))) {
-               opcode_t insn = *(opcode_t *)instruction_pointer(regs);
+               insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
                if (insn == TRAPA_BUG_OPCODE)
                        handle_BUG(regs);
+               return;
        }
 #endif
 
        force_sig(SIGTRAP, current);
 }
+
+BUILD_TRAP_HANDLER(nmi)
+{
+       unsigned int cpu = smp_processor_id();
+       TRAP_HANDLER_DECL;
+
+       nmi_enter();
+       nmi_count(cpu)++;
+
+       switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
+       case NOTIFY_OK:
+       case NOTIFY_STOP:
+               break;
+       case NOTIFY_BAD:
+               die("Fatal Non-Maskable Interrupt", regs, SIGINT);
+       default:
+               printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
+               break;
+       }
+
+       nmi_exit();
+}