176d2a049SPalmer Dabbelt /* 276d2a049SPalmer Dabbelt * Copyright (C) 2012 Regents of the University of California 376d2a049SPalmer Dabbelt * 476d2a049SPalmer Dabbelt * This program is free software; you can redistribute it and/or 576d2a049SPalmer Dabbelt * modify it under the terms of the GNU General Public License 676d2a049SPalmer Dabbelt * as published by the Free Software Foundation, version 2. 776d2a049SPalmer Dabbelt * 876d2a049SPalmer Dabbelt * This program is distributed in the hope that it will be useful, 976d2a049SPalmer Dabbelt * but WITHOUT ANY WARRANTY; without even the implied warranty of 1076d2a049SPalmer Dabbelt * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 1176d2a049SPalmer Dabbelt * GNU General Public License for more details. 1276d2a049SPalmer Dabbelt */ 1376d2a049SPalmer Dabbelt 1476d2a049SPalmer Dabbelt #include <linux/kernel.h> 1576d2a049SPalmer Dabbelt #include <linux/init.h> 1676d2a049SPalmer Dabbelt #include <linux/sched.h> 1776d2a049SPalmer Dabbelt #include <linux/sched/debug.h> 1876d2a049SPalmer Dabbelt #include <linux/sched/signal.h> 1976d2a049SPalmer Dabbelt #include <linux/signal.h> 2076d2a049SPalmer Dabbelt #include <linux/kdebug.h> 2176d2a049SPalmer Dabbelt #include <linux/uaccess.h> 2276d2a049SPalmer Dabbelt #include <linux/mm.h> 2376d2a049SPalmer Dabbelt #include <linux/module.h> 2476d2a049SPalmer Dabbelt #include <linux/irq.h> 2576d2a049SPalmer Dabbelt 2676d2a049SPalmer Dabbelt #include <asm/processor.h> 2776d2a049SPalmer Dabbelt #include <asm/ptrace.h> 2876d2a049SPalmer Dabbelt #include <asm/csr.h> 2976d2a049SPalmer Dabbelt 3076d2a049SPalmer Dabbelt int show_unhandled_signals = 1; 3176d2a049SPalmer Dabbelt 3276d2a049SPalmer Dabbelt extern asmlinkage void handle_exception(void); 3376d2a049SPalmer Dabbelt 3476d2a049SPalmer Dabbelt static DEFINE_SPINLOCK(die_lock); 3576d2a049SPalmer Dabbelt 3676d2a049SPalmer Dabbelt void die(struct pt_regs *regs, const char *str) 3776d2a049SPalmer Dabbelt { 3876d2a049SPalmer Dabbelt static int die_counter; 3976d2a049SPalmer Dabbelt int ret; 4076d2a049SPalmer Dabbelt 4176d2a049SPalmer Dabbelt oops_enter(); 4276d2a049SPalmer Dabbelt 4376d2a049SPalmer Dabbelt spin_lock_irq(&die_lock); 4476d2a049SPalmer Dabbelt console_verbose(); 4576d2a049SPalmer Dabbelt bust_spinlocks(1); 4676d2a049SPalmer Dabbelt 4776d2a049SPalmer Dabbelt pr_emerg("%s [#%d]\n", str, ++die_counter); 4876d2a049SPalmer Dabbelt print_modules(); 4976d2a049SPalmer Dabbelt show_regs(regs); 5076d2a049SPalmer Dabbelt 5176d2a049SPalmer Dabbelt ret = notify_die(DIE_OOPS, str, regs, 0, regs->scause, SIGSEGV); 5276d2a049SPalmer Dabbelt 5376d2a049SPalmer Dabbelt bust_spinlocks(0); 5476d2a049SPalmer Dabbelt add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 5576d2a049SPalmer Dabbelt spin_unlock_irq(&die_lock); 5676d2a049SPalmer Dabbelt oops_exit(); 5776d2a049SPalmer Dabbelt 5876d2a049SPalmer Dabbelt if (in_interrupt()) 5976d2a049SPalmer Dabbelt panic("Fatal exception in interrupt"); 6076d2a049SPalmer Dabbelt if (panic_on_oops) 6176d2a049SPalmer Dabbelt panic("Fatal exception"); 6276d2a049SPalmer Dabbelt if (ret != NOTIFY_STOP) 6376d2a049SPalmer Dabbelt do_exit(SIGSEGV); 6476d2a049SPalmer Dabbelt } 6576d2a049SPalmer Dabbelt 6676d2a049SPalmer Dabbelt void do_trap(struct pt_regs *regs, int signo, int code, 6776d2a049SPalmer Dabbelt unsigned long addr, struct task_struct *tsk) 6876d2a049SPalmer Dabbelt { 6976d2a049SPalmer Dabbelt if (show_unhandled_signals && unhandled_signal(tsk, signo) 7076d2a049SPalmer Dabbelt && printk_ratelimit()) { 7176d2a049SPalmer Dabbelt pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x" REG_FMT, 7276d2a049SPalmer Dabbelt tsk->comm, task_pid_nr(tsk), signo, code, addr); 736ab77af4SChristoph Hellwig print_vma_addr(KERN_CONT " in ", instruction_pointer(regs)); 7476d2a049SPalmer Dabbelt pr_cont("\n"); 7576d2a049SPalmer Dabbelt show_regs(regs); 7676d2a049SPalmer Dabbelt } 7776d2a049SPalmer Dabbelt 787ff3a762SEric W. Biederman force_sig_fault(signo, code, (void __user *)addr, tsk); 7976d2a049SPalmer Dabbelt } 8076d2a049SPalmer Dabbelt 8176d2a049SPalmer Dabbelt static void do_trap_error(struct pt_regs *regs, int signo, int code, 8276d2a049SPalmer Dabbelt unsigned long addr, const char *str) 8376d2a049SPalmer Dabbelt { 8476d2a049SPalmer Dabbelt if (user_mode(regs)) { 8576d2a049SPalmer Dabbelt do_trap(regs, signo, code, addr, current); 8676d2a049SPalmer Dabbelt } else { 8776d2a049SPalmer Dabbelt if (!fixup_exception(regs)) 8876d2a049SPalmer Dabbelt die(regs, str); 8976d2a049SPalmer Dabbelt } 9076d2a049SPalmer Dabbelt } 9176d2a049SPalmer Dabbelt 9276d2a049SPalmer Dabbelt #define DO_ERROR_INFO(name, signo, code, str) \ 9376d2a049SPalmer Dabbelt asmlinkage void name(struct pt_regs *regs) \ 9476d2a049SPalmer Dabbelt { \ 9576d2a049SPalmer Dabbelt do_trap_error(regs, signo, code, regs->sepc, "Oops - " str); \ 9676d2a049SPalmer Dabbelt } 9776d2a049SPalmer Dabbelt 9876d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_unknown, 9976d2a049SPalmer Dabbelt SIGILL, ILL_ILLTRP, "unknown exception"); 10076d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_insn_misaligned, 10176d2a049SPalmer Dabbelt SIGBUS, BUS_ADRALN, "instruction address misaligned"); 10276d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_insn_fault, 10376d2a049SPalmer Dabbelt SIGSEGV, SEGV_ACCERR, "instruction access fault"); 10476d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_insn_illegal, 10576d2a049SPalmer Dabbelt SIGILL, ILL_ILLOPC, "illegal instruction"); 10676d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_load_misaligned, 10776d2a049SPalmer Dabbelt SIGBUS, BUS_ADRALN, "load address misaligned"); 10876d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_load_fault, 10976d2a049SPalmer Dabbelt SIGSEGV, SEGV_ACCERR, "load access fault"); 11076d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_store_misaligned, 11176d2a049SPalmer Dabbelt SIGBUS, BUS_ADRALN, "store (or AMO) address misaligned"); 11276d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_store_fault, 11376d2a049SPalmer Dabbelt SIGSEGV, SEGV_ACCERR, "store (or AMO) access fault"); 11476d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_ecall_u, 11576d2a049SPalmer Dabbelt SIGILL, ILL_ILLTRP, "environment call from U-mode"); 11676d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_ecall_s, 11776d2a049SPalmer Dabbelt SIGILL, ILL_ILLTRP, "environment call from S-mode"); 11876d2a049SPalmer Dabbelt DO_ERROR_INFO(do_trap_ecall_m, 11976d2a049SPalmer Dabbelt SIGILL, ILL_ILLTRP, "environment call from M-mode"); 12076d2a049SPalmer Dabbelt 121*ee72e0e7SVincent Chen #ifdef CONFIG_GENERIC_BUG 122*ee72e0e7SVincent Chen static inline unsigned long get_break_insn_length(unsigned long pc) 123*ee72e0e7SVincent Chen { 124*ee72e0e7SVincent Chen bug_insn_t insn; 125*ee72e0e7SVincent Chen 126*ee72e0e7SVincent Chen if (probe_kernel_address((bug_insn_t *)pc, insn)) 127*ee72e0e7SVincent Chen return 0; 128*ee72e0e7SVincent Chen return (((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) ? 4UL : 2UL); 129*ee72e0e7SVincent Chen } 130*ee72e0e7SVincent Chen #endif /* CONFIG_GENERIC_BUG */ 131*ee72e0e7SVincent Chen 13276d2a049SPalmer Dabbelt asmlinkage void do_trap_break(struct pt_regs *regs) 13376d2a049SPalmer Dabbelt { 13476d2a049SPalmer Dabbelt #ifdef CONFIG_GENERIC_BUG 13576d2a049SPalmer Dabbelt if (!user_mode(regs)) { 13676d2a049SPalmer Dabbelt enum bug_trap_type type; 13776d2a049SPalmer Dabbelt 13876d2a049SPalmer Dabbelt type = report_bug(regs->sepc, regs); 13976d2a049SPalmer Dabbelt switch (type) { 14076d2a049SPalmer Dabbelt case BUG_TRAP_TYPE_NONE: 14176d2a049SPalmer Dabbelt break; 14276d2a049SPalmer Dabbelt case BUG_TRAP_TYPE_WARN: 143*ee72e0e7SVincent Chen regs->sepc += get_break_insn_length(regs->sepc); 144*ee72e0e7SVincent Chen break; 14576d2a049SPalmer Dabbelt case BUG_TRAP_TYPE_BUG: 14676d2a049SPalmer Dabbelt die(regs, "Kernel BUG"); 14776d2a049SPalmer Dabbelt } 14876d2a049SPalmer Dabbelt } 14976d2a049SPalmer Dabbelt #endif /* CONFIG_GENERIC_BUG */ 15076d2a049SPalmer Dabbelt 1517ff3a762SEric W. Biederman force_sig_fault(SIGTRAP, TRAP_BRKPT, (void __user *)(regs->sepc), current); 15276d2a049SPalmer Dabbelt } 15376d2a049SPalmer Dabbelt 15476d2a049SPalmer Dabbelt #ifdef CONFIG_GENERIC_BUG 15576d2a049SPalmer Dabbelt int is_valid_bugaddr(unsigned long pc) 15676d2a049SPalmer Dabbelt { 15776d2a049SPalmer Dabbelt bug_insn_t insn; 15876d2a049SPalmer Dabbelt 15976d2a049SPalmer Dabbelt if (pc < PAGE_OFFSET) 16076d2a049SPalmer Dabbelt return 0; 1619bf97390SLuc Van Oostenryck if (probe_kernel_address((bug_insn_t *)pc, insn)) 16276d2a049SPalmer Dabbelt return 0; 163*ee72e0e7SVincent Chen if ((insn & __INSN_LENGTH_MASK) == __INSN_LENGTH_32) 164*ee72e0e7SVincent Chen return (insn == __BUG_INSN_32); 165*ee72e0e7SVincent Chen else 166*ee72e0e7SVincent Chen return ((insn & __COMPRESSED_INSN_MASK) == __BUG_INSN_16); 16776d2a049SPalmer Dabbelt } 16876d2a049SPalmer Dabbelt #endif /* CONFIG_GENERIC_BUG */ 16976d2a049SPalmer Dabbelt 17076d2a049SPalmer Dabbelt void __init trap_init(void) 17176d2a049SPalmer Dabbelt { 17276d2a049SPalmer Dabbelt /* 17376d2a049SPalmer Dabbelt * Set sup0 scratch register to 0, indicating to exception vector 17476d2a049SPalmer Dabbelt * that we are presently executing in the kernel 17576d2a049SPalmer Dabbelt */ 176a3182c91SAnup Patel csr_write(CSR_SSCRATCH, 0); 17776d2a049SPalmer Dabbelt /* Set the exception vector address */ 178a3182c91SAnup Patel csr_write(CSR_STVEC, &handle_exception); 17976d2a049SPalmer Dabbelt /* Enable all interrupts */ 180a3182c91SAnup Patel csr_write(CSR_SIE, -1); 18176d2a049SPalmer Dabbelt } 182