linux/arch/sh/kernel/traps.c
<<
>>
Prefs
   1#include <linux/bug.h>
   2#include <linux/io.h>
   3#include <linux/types.h>
   4#include <linux/kdebug.h>
   5#include <linux/signal.h>
   6#include <linux/sched.h>
   7#include <linux/uaccess.h>
   8#include <linux/hardirq.h>
   9#include <linux/kernel.h>
  10#include <linux/kexec.h>
  11#include <linux/module.h>
  12#include <asm/unwinder.h>
  13#include <asm/traps.h>
  14
  15static DEFINE_SPINLOCK(die_lock);
  16
  17void die(const char *str, struct pt_regs *regs, long err)
  18{
  19        static int die_counter;
  20
  21        oops_enter();
  22
  23        spin_lock_irq(&die_lock);
  24        console_verbose();
  25        bust_spinlocks(1);
  26
  27        printk("%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter);
  28        print_modules();
  29        show_regs(regs);
  30
  31        printk("Process: %s (pid: %d, stack limit = %p)\n", current->comm,
  32                        task_pid_nr(current), task_stack_page(current) + 1);
  33
  34        if (!user_mode(regs) || in_interrupt())
  35                dump_mem("Stack: ", regs->regs[15], THREAD_SIZE +
  36                         (unsigned long)task_stack_page(current));
  37
  38        notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV);
  39
  40        bust_spinlocks(0);
  41        add_taint(TAINT_DIE);
  42        spin_unlock_irq(&die_lock);
  43        oops_exit();
  44
  45        if (kexec_should_crash(current))
  46                crash_kexec(regs);
  47
  48        if (in_interrupt())
  49                panic("Fatal exception in interrupt");
  50
  51        if (panic_on_oops)
  52                panic("Fatal exception");
  53
  54        do_exit(SIGSEGV);
  55}
  56
  57void die_if_kernel(const char *str, struct pt_regs *regs, long err)
  58{
  59        if (!user_mode(regs))
  60                die(str, regs, err);
  61}
  62
  63/*
  64 * try and fix up kernelspace address errors
  65 * - userspace errors just cause EFAULT to be returned, resulting in SEGV
  66 * - kernel/userspace interfaces cause a jump to an appropriate handler
  67 * - other kernel errors are bad
  68 */
  69void die_if_no_fixup(const char *str, struct pt_regs *regs, long err)
  70{
  71        if (!user_mode(regs)) {
  72                const struct exception_table_entry *fixup;
  73                fixup = search_exception_tables(regs->pc);
  74                if (fixup) {
  75                        regs->pc = fixup->fixup;
  76                        return;
  77                }
  78
  79                die(str, regs, err);
  80        }
  81}
  82
  83#ifdef CONFIG_GENERIC_BUG
  84static void handle_BUG(struct pt_regs *regs)
  85{
  86        const struct bug_entry *bug;
  87        unsigned long bugaddr = regs->pc;
  88        enum bug_trap_type tt;
  89
  90        if (!is_valid_bugaddr(bugaddr))
  91                goto invalid;
  92
  93        bug = find_bug(bugaddr);
  94
  95        /* Switch unwinders when unwind_stack() is called */
  96        if (bug->flags & BUGFLAG_UNWINDER)
  97                unwinder_faulted = 1;
  98
  99        tt = report_bug(bugaddr, regs);
 100        if (tt == BUG_TRAP_TYPE_WARN) {
 101                regs->pc += instruction_size(bugaddr);
 102                return;
 103        }
 104
 105invalid:
 106        die("Kernel BUG", regs, TRAPA_BUG_OPCODE & 0xff);
 107}
 108
 109int is_valid_bugaddr(unsigned long addr)
 110{
 111        insn_size_t opcode;
 112
 113        if (addr < PAGE_OFFSET)
 114                return 0;
 115        if (probe_kernel_address((insn_size_t *)addr, opcode))
 116                return 0;
 117        if (opcode == TRAPA_BUG_OPCODE)
 118                return 1;
 119
 120        return 0;
 121}
 122#endif
 123
 124/*
 125 * Generic trap handler.
 126 */
 127BUILD_TRAP_HANDLER(debug)
 128{
 129        TRAP_HANDLER_DECL;
 130
 131        /* Rewind */
 132        regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
 133
 134        if (notify_die(DIE_TRAP, "debug trap", regs, 0, vec & 0xff,
 135                       SIGTRAP) == NOTIFY_STOP)
 136                return;
 137
 138        force_sig(SIGTRAP, current);
 139}
 140
 141/*
 142 * Special handler for BUG() traps.
 143 */
 144BUILD_TRAP_HANDLER(bug)
 145{
 146        TRAP_HANDLER_DECL;
 147
 148        /* Rewind */
 149        regs->pc -= instruction_size(__raw_readw(regs->pc - 4));
 150
 151        if (notify_die(DIE_TRAP, "bug trap", regs, 0, TRAPA_BUG_OPCODE & 0xff,
 152                       SIGTRAP) == NOTIFY_STOP)
 153                return;
 154
 155#ifdef CONFIG_GENERIC_BUG
 156        if (__kernel_text_address(instruction_pointer(regs))) {
 157                insn_size_t insn = *(insn_size_t *)instruction_pointer(regs);
 158                if (insn == TRAPA_BUG_OPCODE)
 159                        handle_BUG(regs);
 160                return;
 161        }
 162#endif
 163
 164        force_sig(SIGTRAP, current);
 165}
 166
 167BUILD_TRAP_HANDLER(nmi)
 168{
 169        unsigned int cpu = smp_processor_id();
 170        TRAP_HANDLER_DECL;
 171
 172        nmi_enter();
 173        nmi_count(cpu)++;
 174
 175        switch (notify_die(DIE_NMI, "NMI", regs, 0, vec & 0xff, SIGINT)) {
 176        case NOTIFY_OK:
 177        case NOTIFY_STOP:
 178                break;
 179        case NOTIFY_BAD:
 180                die("Fatal Non-Maskable Interrupt", regs, SIGINT);
 181        default:
 182                printk(KERN_ALERT "Got NMI, but nobody cared. Ignoring...\n");
 183                break;
 184        }
 185
 186        nmi_exit();
 187}
 188