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