xref: /linux/arch/csky/kernel/traps.c (revision b0ae5e26b863f74aeaf73684d04dfb6fb72f836c)
1081860b9SGuo Ren // SPDX-License-Identifier: GPL-2.0
2081860b9SGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
3081860b9SGuo Ren 
4081860b9SGuo Ren #include <linux/sched.h>
5081860b9SGuo Ren #include <linux/signal.h>
6081860b9SGuo Ren #include <linux/kernel.h>
7081860b9SGuo Ren #include <linux/mm.h>
8081860b9SGuo Ren #include <linux/module.h>
9081860b9SGuo Ren #include <linux/user.h>
10081860b9SGuo Ren #include <linux/string.h>
11081860b9SGuo Ren #include <linux/linkage.h>
12081860b9SGuo Ren #include <linux/init.h>
13081860b9SGuo Ren #include <linux/ptrace.h>
14081860b9SGuo Ren #include <linux/kallsyms.h>
15081860b9SGuo Ren #include <linux/rtc.h>
16081860b9SGuo Ren #include <linux/uaccess.h>
1733e53ae1SGuo Ren #include <linux/kprobes.h>
185bc46ce2SGuo Ren #include <linux/kdebug.h>
195bc46ce2SGuo Ren #include <linux/sched/debug.h>
20081860b9SGuo Ren 
21081860b9SGuo Ren #include <asm/setup.h>
22081860b9SGuo Ren #include <asm/traps.h>
23081860b9SGuo Ren #include <asm/pgalloc.h>
24081860b9SGuo Ren #include <asm/siginfo.h>
25081860b9SGuo Ren 
26081860b9SGuo Ren #include <asm/mmu_context.h>
27081860b9SGuo Ren 
28081860b9SGuo Ren #ifdef CONFIG_CPU_HAS_FPU
29081860b9SGuo Ren #include <abi/fpu.h>
30081860b9SGuo Ren #endif
31081860b9SGuo Ren 
325bc46ce2SGuo Ren int show_unhandled_signals = 1;
335bc46ce2SGuo Ren 
34081860b9SGuo Ren /* Defined in entry.S */
35081860b9SGuo Ren asmlinkage void csky_trap(void);
36081860b9SGuo Ren 
37081860b9SGuo Ren asmlinkage void csky_systemcall(void);
38081860b9SGuo Ren asmlinkage void csky_cmpxchg(void);
39081860b9SGuo Ren asmlinkage void csky_get_tls(void);
40081860b9SGuo Ren asmlinkage void csky_irq(void);
41081860b9SGuo Ren 
42*b0ae5e26SGuo Ren asmlinkage void csky_pagefault(void);
43081860b9SGuo Ren 
44081860b9SGuo Ren /* Defined in head.S */
45081860b9SGuo Ren asmlinkage void _start_smp_secondary(void);
46081860b9SGuo Ren 
47081860b9SGuo Ren void __init pre_trap_init(void)
48081860b9SGuo Ren {
49081860b9SGuo Ren 	int i;
50081860b9SGuo Ren 
51081860b9SGuo Ren 	mtcr("vbr", vec_base);
52081860b9SGuo Ren 
53081860b9SGuo Ren 	for (i = 1; i < 128; i++)
54081860b9SGuo Ren 		VEC_INIT(i, csky_trap);
55081860b9SGuo Ren }
56081860b9SGuo Ren 
57081860b9SGuo Ren void __init trap_init(void)
58081860b9SGuo Ren {
59081860b9SGuo Ren 	VEC_INIT(VEC_AUTOVEC, csky_irq);
60081860b9SGuo Ren 
61081860b9SGuo Ren 	/* setup trap0 trap2 trap3 */
62081860b9SGuo Ren 	VEC_INIT(VEC_TRAP0, csky_systemcall);
63081860b9SGuo Ren 	VEC_INIT(VEC_TRAP2, csky_cmpxchg);
64081860b9SGuo Ren 	VEC_INIT(VEC_TRAP3, csky_get_tls);
65081860b9SGuo Ren 
66081860b9SGuo Ren 	/* setup MMU TLB exception */
67*b0ae5e26SGuo Ren 	VEC_INIT(VEC_TLBINVALIDL, csky_pagefault);
68*b0ae5e26SGuo Ren 	VEC_INIT(VEC_TLBINVALIDS, csky_pagefault);
69*b0ae5e26SGuo Ren 	VEC_INIT(VEC_TLBMODIFIED, csky_pagefault);
70081860b9SGuo Ren 
71081860b9SGuo Ren #ifdef CONFIG_CPU_HAS_FPU
72081860b9SGuo Ren 	init_fpu();
73081860b9SGuo Ren #endif
74081860b9SGuo Ren 
75081860b9SGuo Ren #ifdef CONFIG_SMP
76081860b9SGuo Ren 	mtcr("cr<28, 0>", virt_to_phys(vec_base));
77081860b9SGuo Ren 
78081860b9SGuo Ren 	VEC_INIT(VEC_RESET, (void *)virt_to_phys(_start_smp_secondary));
79081860b9SGuo Ren #endif
80081860b9SGuo Ren }
81081860b9SGuo Ren 
825bc46ce2SGuo Ren static DEFINE_SPINLOCK(die_lock);
83081860b9SGuo Ren 
845bc46ce2SGuo Ren void die(struct pt_regs *regs, const char *str)
855bc46ce2SGuo Ren {
865bc46ce2SGuo Ren 	static int die_counter;
875bc46ce2SGuo Ren 	int ret;
885bc46ce2SGuo Ren 
895bc46ce2SGuo Ren 	oops_enter();
905bc46ce2SGuo Ren 
915bc46ce2SGuo Ren 	spin_lock_irq(&die_lock);
92081860b9SGuo Ren 	console_verbose();
935bc46ce2SGuo Ren 	bust_spinlocks(1);
945bc46ce2SGuo Ren 
955bc46ce2SGuo Ren 	pr_emerg("%s [#%d]\n", str, ++die_counter);
965bc46ce2SGuo Ren 	print_modules();
97081860b9SGuo Ren 	show_regs(regs);
985bc46ce2SGuo Ren 	show_stack(current, (unsigned long *)regs->regs[4], KERN_INFO);
995bc46ce2SGuo Ren 
1005bc46ce2SGuo Ren 	ret = notify_die(DIE_OOPS, str, regs, 0, trap_no(regs), SIGSEGV);
1015bc46ce2SGuo Ren 
1025bc46ce2SGuo Ren 	bust_spinlocks(0);
103081860b9SGuo Ren 	add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE);
1045bc46ce2SGuo Ren 	spin_unlock_irq(&die_lock);
1055bc46ce2SGuo Ren 	oops_exit();
1065bc46ce2SGuo Ren 
1075bc46ce2SGuo Ren 	if (in_interrupt())
1085bc46ce2SGuo Ren 		panic("Fatal exception in interrupt");
1095bc46ce2SGuo Ren 	if (panic_on_oops)
1105bc46ce2SGuo Ren 		panic("Fatal exception");
1115bc46ce2SGuo Ren 	if (ret != NOTIFY_STOP)
112081860b9SGuo Ren 		do_exit(SIGSEGV);
113081860b9SGuo Ren }
114081860b9SGuo Ren 
1155bc46ce2SGuo Ren void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr)
116081860b9SGuo Ren {
1179c0e343dSGuo Ren 	struct task_struct *tsk = current;
118081860b9SGuo Ren 
1195bc46ce2SGuo Ren 	if (show_unhandled_signals && unhandled_signal(tsk, signo)
1205bc46ce2SGuo Ren 	    && printk_ratelimit()) {
1215bc46ce2SGuo Ren 		pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx",
1225bc46ce2SGuo Ren 			tsk->comm, task_pid_nr(tsk), signo, code, addr);
1235bc46ce2SGuo Ren 		print_vma_addr(KERN_CONT " in ", instruction_pointer(regs));
1245bc46ce2SGuo Ren 		pr_cont("\n");
1255bc46ce2SGuo Ren 		show_regs(regs);
1265bc46ce2SGuo Ren 	}
127081860b9SGuo Ren 
1285bc46ce2SGuo Ren 	force_sig_fault(signo, code, (void __user *)addr);
1295bc46ce2SGuo Ren }
1305bc46ce2SGuo Ren 
1315bc46ce2SGuo Ren static void do_trap_error(struct pt_regs *regs, int signo, int code,
1325bc46ce2SGuo Ren 	unsigned long addr, const char *str)
1335bc46ce2SGuo Ren {
1345bc46ce2SGuo Ren 	current->thread.trap_no = trap_no(regs);
1355bc46ce2SGuo Ren 
1365bc46ce2SGuo Ren 	if (user_mode(regs)) {
1375bc46ce2SGuo Ren 		do_trap(regs, signo, code, addr);
1385bc46ce2SGuo Ren 	} else {
1395bc46ce2SGuo Ren 		if (!fixup_exception(regs))
1405bc46ce2SGuo Ren 			die(regs, str);
1415bc46ce2SGuo Ren 	}
1425bc46ce2SGuo Ren }
1435bc46ce2SGuo Ren 
1445bc46ce2SGuo Ren #define DO_ERROR_INFO(name, signo, code, str)				\
1455bc46ce2SGuo Ren asmlinkage __visible void name(struct pt_regs *regs)			\
1465bc46ce2SGuo Ren {									\
1475bc46ce2SGuo Ren 	do_trap_error(regs, signo, code, regs->pc, "Oops - " str);	\
1485bc46ce2SGuo Ren }
1495bc46ce2SGuo Ren 
1505bc46ce2SGuo Ren DO_ERROR_INFO(do_trap_unknown,
1515bc46ce2SGuo Ren 	SIGILL, ILL_ILLTRP, "unknown exception");
1525bc46ce2SGuo Ren DO_ERROR_INFO(do_trap_zdiv,
1535bc46ce2SGuo Ren 	SIGFPE, FPE_INTDIV, "error zero div exception");
1545bc46ce2SGuo Ren DO_ERROR_INFO(do_trap_buserr,
1555bc46ce2SGuo Ren 	SIGSEGV, ILL_ILLADR, "error bus error exception");
1565bc46ce2SGuo Ren 
1575bc46ce2SGuo Ren asmlinkage void do_trap_misaligned(struct pt_regs *regs)
1585bc46ce2SGuo Ren {
1595bc46ce2SGuo Ren #ifdef CONFIG_CPU_NEED_SOFTALIGN
1605bc46ce2SGuo Ren 	csky_alignment(regs);
1615bc46ce2SGuo Ren #else
1625bc46ce2SGuo Ren 	current->thread.trap_no = trap_no(regs);
1635bc46ce2SGuo Ren 	do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->pc,
1645bc46ce2SGuo Ren 		      "Oops - load/store address misaligned");
1655bc46ce2SGuo Ren #endif
1665bc46ce2SGuo Ren }
1675bc46ce2SGuo Ren 
1685bc46ce2SGuo Ren asmlinkage void do_trap_bkpt(struct pt_regs *regs)
1695bc46ce2SGuo Ren {
17033e53ae1SGuo Ren #ifdef CONFIG_KPROBES
17133e53ae1SGuo Ren 	if (kprobe_single_step_handler(regs))
17233e53ae1SGuo Ren 		return;
17333e53ae1SGuo Ren #endif
1748f6bb793SGuo Ren #ifdef CONFIG_UPROBES
1758f6bb793SGuo Ren 	if (uprobe_single_step_handler(regs))
1768f6bb793SGuo Ren 		return;
1778f6bb793SGuo Ren #endif
1785bc46ce2SGuo Ren 	if (user_mode(regs)) {
1795bc46ce2SGuo Ren 		send_sig(SIGTRAP, current, 0);
1805bc46ce2SGuo Ren 		return;
1815bc46ce2SGuo Ren 	}
1825bc46ce2SGuo Ren 
1835bc46ce2SGuo Ren 	do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->pc,
1845bc46ce2SGuo Ren 		      "Oops - illegal trap exception");
1855bc46ce2SGuo Ren }
1865bc46ce2SGuo Ren 
1875bc46ce2SGuo Ren asmlinkage void do_trap_illinsn(struct pt_regs *regs)
1885bc46ce2SGuo Ren {
1895bc46ce2SGuo Ren 	current->thread.trap_no = trap_no(regs);
1905bc46ce2SGuo Ren 
19133e53ae1SGuo Ren #ifdef CONFIG_KPROBES
19233e53ae1SGuo Ren 	if (kprobe_breakpoint_handler(regs))
19333e53ae1SGuo Ren 		return;
19433e53ae1SGuo Ren #endif
1958f6bb793SGuo Ren #ifdef CONFIG_UPROBES
1968f6bb793SGuo Ren 	if (uprobe_breakpoint_handler(regs))
1978f6bb793SGuo Ren 		return;
1988f6bb793SGuo Ren #endif
199081860b9SGuo Ren #ifndef CONFIG_CPU_NO_USER_BKPT
2005bc46ce2SGuo Ren 	if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) {
2015bc46ce2SGuo Ren 		send_sig(SIGTRAP, current, 0);
2025bc46ce2SGuo Ren 		return;
203081860b9SGuo Ren 	}
204081860b9SGuo Ren #endif
2055bc46ce2SGuo Ren 
2065bc46ce2SGuo Ren 	do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc,
2075bc46ce2SGuo Ren 		      "Oops - illegal instruction exception");
2085bc46ce2SGuo Ren }
2095bc46ce2SGuo Ren 
2105bc46ce2SGuo Ren asmlinkage void do_trap_fpe(struct pt_regs *regs)
2115bc46ce2SGuo Ren {
2125bc46ce2SGuo Ren #ifdef CONFIG_CPU_HAS_FP
213081860b9SGuo Ren 	return fpu_fpe(regs);
2145bc46ce2SGuo Ren #else
2155bc46ce2SGuo Ren 	do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc,
2165bc46ce2SGuo Ren 		      "Oops - fpu instruction exception");
2175bc46ce2SGuo Ren #endif
2185bc46ce2SGuo Ren }
2195bc46ce2SGuo Ren 
2205bc46ce2SGuo Ren asmlinkage void do_trap_priv(struct pt_regs *regs)
2215bc46ce2SGuo Ren {
2225bc46ce2SGuo Ren #ifdef CONFIG_CPU_HAS_FP
2235bc46ce2SGuo Ren 	if (user_mode(regs) && fpu_libc_helper(regs))
224081860b9SGuo Ren 		return;
225081860b9SGuo Ren #endif
2265bc46ce2SGuo Ren 	do_trap_error(regs, SIGILL, ILL_PRVOPC, regs->pc,
2275bc46ce2SGuo Ren 		      "Oops - illegal privileged exception");
228081860b9SGuo Ren }
2299c0e343dSGuo Ren 
2305bc46ce2SGuo Ren asmlinkage void trap_c(struct pt_regs *regs)
2315bc46ce2SGuo Ren {
2325bc46ce2SGuo Ren 	switch (trap_no(regs)) {
2335bc46ce2SGuo Ren 	case VEC_ZERODIV:
2345bc46ce2SGuo Ren 		do_trap_zdiv(regs);
2355bc46ce2SGuo Ren 		break;
2365bc46ce2SGuo Ren 	case VEC_TRACE:
2375bc46ce2SGuo Ren 		do_trap_bkpt(regs);
2385bc46ce2SGuo Ren 		break;
2395bc46ce2SGuo Ren 	case VEC_ILLEGAL:
2405bc46ce2SGuo Ren 		do_trap_illinsn(regs);
2415bc46ce2SGuo Ren 		break;
2425bc46ce2SGuo Ren 	case VEC_TRAP1:
2435bc46ce2SGuo Ren 	case VEC_BREAKPOINT:
2445bc46ce2SGuo Ren 		do_trap_bkpt(regs);
2455bc46ce2SGuo Ren 		break;
2465bc46ce2SGuo Ren 	case VEC_ACCESS:
2475bc46ce2SGuo Ren 		do_trap_buserr(regs);
2485bc46ce2SGuo Ren 		break;
2495bc46ce2SGuo Ren 	case VEC_ALIGN:
2505bc46ce2SGuo Ren 		do_trap_misaligned(regs);
2515bc46ce2SGuo Ren 		break;
2525bc46ce2SGuo Ren 	case VEC_FPE:
2535bc46ce2SGuo Ren 		do_trap_fpe(regs);
2545bc46ce2SGuo Ren 		break;
2555bc46ce2SGuo Ren 	case VEC_PRIV:
2565bc46ce2SGuo Ren 		do_trap_priv(regs);
2575bc46ce2SGuo Ren 		break;
2585bc46ce2SGuo Ren 	default:
2595bc46ce2SGuo Ren 		do_trap_unknown(regs);
2605bc46ce2SGuo Ren 		break;
2615bc46ce2SGuo Ren 	}
262081860b9SGuo Ren }
263