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