Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^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) }