// SPDX-License-Identifier: GPL-2.0 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #ifdef CONFIG_CPU_HAS_FPU #include #endif /* Defined in entry.S */ asmlinkage void csky_trap(void); asmlinkage void csky_systemcall(void); asmlinkage void csky_cmpxchg(void); asmlinkage void csky_get_tls(void); asmlinkage void csky_irq(void); asmlinkage void csky_tlbinvalidl(void); asmlinkage void csky_tlbinvalids(void); asmlinkage void csky_tlbmodified(void); /* Defined in head.S */ asmlinkage void _start_smp_secondary(void); void __init pre_trap_init(void) { int i; mtcr("vbr", vec_base); for (i = 1; i < 128; i++) VEC_INIT(i, csky_trap); } void __init trap_init(void) { VEC_INIT(VEC_AUTOVEC, csky_irq); /* setup trap0 trap2 trap3 */ VEC_INIT(VEC_TRAP0, csky_systemcall); VEC_INIT(VEC_TRAP2, csky_cmpxchg); VEC_INIT(VEC_TRAP3, csky_get_tls); /* setup MMU TLB exception */ VEC_INIT(VEC_TLBINVALIDL, csky_tlbinvalidl); VEC_INIT(VEC_TLBINVALIDS, csky_tlbinvalids); VEC_INIT(VEC_TLBMODIFIED, csky_tlbmodified); #ifdef CONFIG_CPU_HAS_FPU init_fpu(); #endif #ifdef CONFIG_SMP mtcr("cr<28, 0>", virt_to_phys(vec_base)); VEC_INIT(VEC_RESET, (void *)virt_to_phys(_start_smp_secondary)); #endif } void die_if_kernel(char *str, struct pt_regs *regs, int nr) { if (user_mode(regs)) return; console_verbose(); pr_err("%s: %08x\n", str, nr); show_regs(regs); add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); do_exit(SIGSEGV); } void buserr(struct pt_regs *regs) { #ifdef CONFIG_CPU_CK810 static unsigned long prev_pc; if ((regs->pc == prev_pc) && prev_pc != 0) { prev_pc = 0; } else { prev_pc = regs->pc; return; } #endif die_if_kernel("Kernel mode BUS error", regs, 0); pr_err("User mode Bus Error\n"); show_regs(regs); force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc); } #define USR_BKPT 0x1464 asmlinkage void trap_c(struct pt_regs *regs) { int sig; unsigned long vector; siginfo_t info; vector = (mfcr("psr") >> 16) & 0xff; switch (vector) { case VEC_ZERODIV: die_if_kernel("Kernel mode ZERO DIV", regs, vector); sig = SIGFPE; break; /* ptrace */ case VEC_TRACE: info.si_code = TRAP_TRACE; sig = SIGTRAP; break; case VEC_ILLEGAL: die_if_kernel("Kernel mode ILLEGAL", regs, vector); #ifndef CONFIG_CPU_NO_USER_BKPT if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) #endif { sig = SIGILL; break; } /* gdbserver breakpoint */ case VEC_TRAP1: /* jtagserver breakpoint */ case VEC_BREAKPOINT: die_if_kernel("Kernel mode BKPT", regs, vector); info.si_code = TRAP_BRKPT; sig = SIGTRAP; break; case VEC_ACCESS: return buserr(regs); #ifdef CONFIG_CPU_NEED_SOFTALIGN case VEC_ALIGN: return csky_alignment(regs); #endif #ifdef CONFIG_CPU_HAS_FPU case VEC_FPE: die_if_kernel("Kernel mode FPE", regs, vector); return fpu_fpe(regs); case VEC_PRIV: die_if_kernel("Kernel mode PRIV", regs, vector); if (fpu_libc_helper(regs)) return; #endif default: sig = SIGSEGV; break; } send_sig(sig, current, 0); }