1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4 #include <linux/sched.h> 5 #include <linux/signal.h> 6 #include <linux/kernel.h> 7 #include <linux/mm.h> 8 #include <linux/module.h> 9 #include <linux/user.h> 10 #include <linux/string.h> 11 #include <linux/linkage.h> 12 #include <linux/init.h> 13 #include <linux/ptrace.h> 14 #include <linux/kallsyms.h> 15 #include <linux/rtc.h> 16 #include <linux/uaccess.h> 17 18 #include <asm/setup.h> 19 #include <asm/traps.h> 20 #include <asm/pgalloc.h> 21 #include <asm/siginfo.h> 22 23 #include <asm/mmu_context.h> 24 25 #ifdef CONFIG_CPU_HAS_FPU 26 #include <abi/fpu.h> 27 #endif 28 29 /* Defined in entry.S */ 30 asmlinkage void csky_trap(void); 31 32 asmlinkage void csky_systemcall(void); 33 asmlinkage void csky_cmpxchg(void); 34 asmlinkage void csky_get_tls(void); 35 asmlinkage void csky_irq(void); 36 37 asmlinkage void csky_tlbinvalidl(void); 38 asmlinkage void csky_tlbinvalids(void); 39 asmlinkage void csky_tlbmodified(void); 40 41 /* Defined in head.S */ 42 asmlinkage void _start_smp_secondary(void); 43 44 void __init pre_trap_init(void) 45 { 46 int i; 47 48 mtcr("vbr", vec_base); 49 50 for (i = 1; i < 128; i++) 51 VEC_INIT(i, csky_trap); 52 } 53 54 void __init trap_init(void) 55 { 56 VEC_INIT(VEC_AUTOVEC, csky_irq); 57 58 /* setup trap0 trap2 trap3 */ 59 VEC_INIT(VEC_TRAP0, csky_systemcall); 60 VEC_INIT(VEC_TRAP2, csky_cmpxchg); 61 VEC_INIT(VEC_TRAP3, csky_get_tls); 62 63 /* setup MMU TLB exception */ 64 VEC_INIT(VEC_TLBINVALIDL, csky_tlbinvalidl); 65 VEC_INIT(VEC_TLBINVALIDS, csky_tlbinvalids); 66 VEC_INIT(VEC_TLBMODIFIED, csky_tlbmodified); 67 68 #ifdef CONFIG_CPU_HAS_FPU 69 init_fpu(); 70 #endif 71 72 #ifdef CONFIG_SMP 73 mtcr("cr<28, 0>", virt_to_phys(vec_base)); 74 75 VEC_INIT(VEC_RESET, (void *)virt_to_phys(_start_smp_secondary)); 76 #endif 77 } 78 79 void die_if_kernel(char *str, struct pt_regs *regs, int nr) 80 { 81 if (user_mode(regs)) 82 return; 83 84 console_verbose(); 85 pr_err("%s: %08x\n", str, nr); 86 show_regs(regs); 87 add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 88 do_exit(SIGSEGV); 89 } 90 91 void buserr(struct pt_regs *regs) 92 { 93 #ifdef CONFIG_CPU_CK810 94 static unsigned long prev_pc; 95 96 if ((regs->pc == prev_pc) && prev_pc != 0) { 97 prev_pc = 0; 98 } else { 99 prev_pc = regs->pc; 100 return; 101 } 102 #endif 103 104 die_if_kernel("Kernel mode BUS error", regs, 0); 105 106 pr_err("User mode Bus Error\n"); 107 show_regs(regs); 108 109 force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc, current); 110 } 111 112 #define USR_BKPT 0x1464 113 asmlinkage void trap_c(struct pt_regs *regs) 114 { 115 int sig; 116 unsigned long vector; 117 siginfo_t info; 118 119 vector = (mfcr("psr") >> 16) & 0xff; 120 121 switch (vector) { 122 case VEC_ZERODIV: 123 die_if_kernel("Kernel mode ZERO DIV", regs, vector); 124 sig = SIGFPE; 125 break; 126 /* ptrace */ 127 case VEC_TRACE: 128 info.si_code = TRAP_TRACE; 129 sig = SIGTRAP; 130 break; 131 case VEC_ILLEGAL: 132 die_if_kernel("Kernel mode ILLEGAL", regs, vector); 133 #ifndef CONFIG_CPU_NO_USER_BKPT 134 if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) 135 #endif 136 { 137 sig = SIGILL; 138 break; 139 } 140 /* gdbserver breakpoint */ 141 case VEC_TRAP1: 142 /* jtagserver breakpoint */ 143 case VEC_BREAKPOINT: 144 die_if_kernel("Kernel mode BKPT", regs, vector); 145 info.si_code = TRAP_BRKPT; 146 sig = SIGTRAP; 147 break; 148 case VEC_ACCESS: 149 return buserr(regs); 150 #ifdef CONFIG_CPU_NEED_SOFTALIGN 151 case VEC_ALIGN: 152 return csky_alignment(regs); 153 #endif 154 #ifdef CONFIG_CPU_HAS_FPU 155 case VEC_FPE: 156 die_if_kernel("Kernel mode FPE", regs, vector); 157 return fpu_fpe(regs); 158 case VEC_PRIV: 159 die_if_kernel("Kernel mode PRIV", regs, vector); 160 if (fpu_libc_helper(regs)) 161 return; 162 #endif 163 default: 164 sig = SIGSEGV; 165 break; 166 } 167 send_sig(sig, current, 0); 168 } 169