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 #ifdef CONFIG_UPROBES 134 if (uprobe_single_step_handler(regs)) 135 return; 136 #endif 137 info.si_code = TRAP_TRACE; 138 sig = SIGTRAP; 139 break; 140 case VEC_ILLEGAL: 141 tsk->thread.trap_no = vector; 142 #ifdef CONFIG_KPROBES 143 if (kprobe_breakpoint_handler(regs)) 144 return; 145 #endif 146 #ifdef CONFIG_UPROBES 147 if (uprobe_breakpoint_handler(regs)) 148 return; 149 #endif 150 die_if_kernel("Kernel mode ILLEGAL", regs, vector); 151 #ifndef CONFIG_CPU_NO_USER_BKPT 152 if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) 153 #endif 154 { 155 sig = SIGILL; 156 break; 157 } 158 /* gdbserver breakpoint */ 159 case VEC_TRAP1: 160 /* jtagserver breakpoint */ 161 case VEC_BREAKPOINT: 162 die_if_kernel("Kernel mode BKPT", regs, vector); 163 info.si_code = TRAP_BRKPT; 164 sig = SIGTRAP; 165 break; 166 case VEC_ACCESS: 167 tsk->thread.trap_no = vector; 168 return buserr(regs); 169 #ifdef CONFIG_CPU_NEED_SOFTALIGN 170 case VEC_ALIGN: 171 tsk->thread.trap_no = vector; 172 return csky_alignment(regs); 173 #endif 174 #ifdef CONFIG_CPU_HAS_FPU 175 case VEC_FPE: 176 tsk->thread.trap_no = vector; 177 die_if_kernel("Kernel mode FPE", regs, vector); 178 return fpu_fpe(regs); 179 case VEC_PRIV: 180 tsk->thread.trap_no = vector; 181 die_if_kernel("Kernel mode PRIV", regs, vector); 182 if (fpu_libc_helper(regs)) 183 return; 184 #endif 185 default: 186 sig = SIGSEGV; 187 break; 188 } 189 190 tsk->thread.trap_no = vector; 191 192 send_sig(sig, current, 0); 193 } 194