^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) * Hardware exception handling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) * Copyright (C) 2010 Tobias Klauser <tklauser@distanz.ch>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright (C) 2004 Microtronix Datacom Ltd.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Copyright (C) 2001 Vic Phillips
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8) * This file is subject to the terms and conditions of the GNU General
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) * Public License. See the file COPYING in the main directory of this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) * archive for more details.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include <linux/sched.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14) #include <linux/sched/debug.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #include <linux/kernel.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #include <linux/signal.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17) #include <linux/export.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #include <linux/mm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19) #include <linux/ptrace.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) #include <asm/traps.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) #include <asm/sections.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) #include <linux/uaccess.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25) static DEFINE_SPINLOCK(die_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) static void _send_sig(int signo, int code, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) force_sig_fault(signo, code, (void __user *) addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32) void die(const char *str, struct pt_regs *regs, long err)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) console_verbose();
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35) spin_lock_irq(&die_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) pr_warn("Oops: %s, sig: %ld\n", str, err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) show_regs(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) spin_unlock_irq(&die_lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40) * do_exit() should take care of panic'ing from an interrupt
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) * context so we don't handle it here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43) do_exit(err);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) void _exception(int signo, struct pt_regs *regs, int code, unsigned long addr)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) if (!user_mode(regs))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49) die("Exception in kernel mode", regs, signo);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) _send_sig(signo, code, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) * The show_stack() is external API which we do not use ourselves.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) int kstack_depth_to_print = 48;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) void show_stack(struct task_struct *task, unsigned long *stack,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) const char *loglvl)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63) unsigned long *endstack, addr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66) if (!stack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) if (task)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) stack = (unsigned long *)task->thread.ksp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) stack = (unsigned long *)&stack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) addr = (unsigned long) stack;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) endstack = (unsigned long *) PAGE_ALIGN(addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) printk("%sStack from %08lx:", loglvl, (unsigned long)stack);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) for (i = 0; i < kstack_depth_to_print; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) if (stack + 1 > endstack)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) if (i % 8 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) printk("%s\n ", loglvl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) printk("%s %08lx", loglvl, *stack++);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85) printk("%s\nCall Trace:", loglvl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) i = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) while (stack + 1 <= endstack) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88) addr = *stack++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) * If the address is either in the text segment of the
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) * kernel, or in the region which contains vmalloc'ed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) * memory, it *may* be the address of a calling
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) * routine; if so, print it so that someone tracing
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * down the cause of the crash will be able to figure
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) * out the call path that was taken.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) if (((addr >= (unsigned long) _stext) &&
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) (addr <= (unsigned long) _etext))) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) if (i % 4 == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) pr_emerg("\n ");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) printk("%s [<%08lx>]", loglvl, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) i++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) printk("%s\n", loglvl);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) void __init trap_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) /* Nothing to do here */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* Breakpoint handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) asmlinkage void breakpoint_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) * The breakpoint entry code has moved the PC on by 4 bytes, so we must
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) * move it back. This could be done on the host but we do it here
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) * because monitor.S of JTAG gdbserver does it too.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) fp->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) _exception(SIGTRAP, fp, TRAP_BRKPT, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) #ifndef CONFIG_NIOS2_ALIGNMENT_TRAP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) /* Alignment exception handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) asmlinkage void handle_unaligned_c(struct pt_regs *fp, int cause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) unsigned long addr = RDCTL(CTL_BADADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) cause >>= 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) fp->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) if (fixup_exception(fp))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) if (!user_mode(fp)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) pr_alert("Unaligned access from kernel mode, this might be a hardware\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) pr_alert("problem, dump registers and restart the instruction\n");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) pr_alert(" BADADDR 0x%08lx\n", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) pr_alert(" cause %d\n", cause);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) pr_alert(" op-code 0x%08lx\n", *(unsigned long *)(fp->ea));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) show_regs(fp);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) _exception(SIGBUS, fp, BUS_ADRALN, addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) #endif /* CONFIG_NIOS2_ALIGNMENT_TRAP */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) /* Illegal instruction handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) asmlinkage void handle_illegal_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) fp->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) _exception(SIGILL, fp, ILL_ILLOPC, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) /* Supervisor instruction handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) asmlinkage void handle_supervisor_instr(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) fp->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) _exception(SIGILL, fp, ILL_PRVOPC, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) /* Division error handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) asmlinkage void handle_diverror_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) fp->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) _exception(SIGFPE, fp, FPE_INTDIV, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) /* Unhandled exception handler */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) asmlinkage void unhandled_exception(struct pt_regs *regs, int cause)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) unsigned long addr = RDCTL(CTL_BADADDR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) cause /= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) pr_emerg("Unhandled exception #%d in %s mode (badaddr=0x%08lx)\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) cause, user_mode(regs) ? "user" : "kernel", addr);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) regs->ea -= 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) show_regs(regs);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) pr_emerg("opcode: 0x%08lx\n", *(unsigned long *)(regs->ea));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) asmlinkage void handle_trap_1_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) _send_sig(SIGUSR1, 0, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) asmlinkage void handle_trap_2_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) _send_sig(SIGUSR2, 0, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) asmlinkage void handle_trap_3_c(struct pt_regs *fp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) _send_sig(SIGILL, ILL_ILLTRP, fp->ea);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) }