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