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 #include <linux/kdebug.h> 19 #include <linux/sched/debug.h> 20 21 #include <asm/setup.h> 22 #include <asm/traps.h> 23 #include <asm/pgalloc.h> 24 #include <asm/siginfo.h> 25 26 #include <asm/mmu_context.h> 27 28 #ifdef CONFIG_CPU_HAS_FPU 29 #include <abi/fpu.h> 30 #endif 31 32 int show_unhandled_signals = 1; 33 34 /* Defined in entry.S */ 35 asmlinkage void csky_trap(void); 36 37 asmlinkage void csky_systemcall(void); 38 asmlinkage void csky_cmpxchg(void); 39 asmlinkage void csky_get_tls(void); 40 asmlinkage void csky_irq(void); 41 42 asmlinkage void csky_tlbinvalidl(void); 43 asmlinkage void csky_tlbinvalids(void); 44 asmlinkage void csky_tlbmodified(void); 45 46 /* Defined in head.S */ 47 asmlinkage void _start_smp_secondary(void); 48 49 void __init pre_trap_init(void) 50 { 51 int i; 52 53 mtcr("vbr", vec_base); 54 55 for (i = 1; i < 128; i++) 56 VEC_INIT(i, csky_trap); 57 } 58 59 void __init trap_init(void) 60 { 61 VEC_INIT(VEC_AUTOVEC, csky_irq); 62 63 /* setup trap0 trap2 trap3 */ 64 VEC_INIT(VEC_TRAP0, csky_systemcall); 65 VEC_INIT(VEC_TRAP2, csky_cmpxchg); 66 VEC_INIT(VEC_TRAP3, csky_get_tls); 67 68 /* setup MMU TLB exception */ 69 VEC_INIT(VEC_TLBINVALIDL, csky_tlbinvalidl); 70 VEC_INIT(VEC_TLBINVALIDS, csky_tlbinvalids); 71 VEC_INIT(VEC_TLBMODIFIED, csky_tlbmodified); 72 73 #ifdef CONFIG_CPU_HAS_FPU 74 init_fpu(); 75 #endif 76 77 #ifdef CONFIG_SMP 78 mtcr("cr<28, 0>", virt_to_phys(vec_base)); 79 80 VEC_INIT(VEC_RESET, (void *)virt_to_phys(_start_smp_secondary)); 81 #endif 82 } 83 84 static DEFINE_SPINLOCK(die_lock); 85 86 void die(struct pt_regs *regs, const char *str) 87 { 88 static int die_counter; 89 int ret; 90 91 oops_enter(); 92 93 spin_lock_irq(&die_lock); 94 console_verbose(); 95 bust_spinlocks(1); 96 97 pr_emerg("%s [#%d]\n", str, ++die_counter); 98 print_modules(); 99 show_regs(regs); 100 show_stack(current, (unsigned long *)regs->regs[4], KERN_INFO); 101 102 ret = notify_die(DIE_OOPS, str, regs, 0, trap_no(regs), SIGSEGV); 103 104 bust_spinlocks(0); 105 add_taint(TAINT_DIE, LOCKDEP_NOW_UNRELIABLE); 106 spin_unlock_irq(&die_lock); 107 oops_exit(); 108 109 if (in_interrupt()) 110 panic("Fatal exception in interrupt"); 111 if (panic_on_oops) 112 panic("Fatal exception"); 113 if (ret != NOTIFY_STOP) 114 do_exit(SIGSEGV); 115 } 116 117 void do_trap(struct pt_regs *regs, int signo, int code, unsigned long addr) 118 { 119 struct task_struct *tsk = current; 120 121 if (show_unhandled_signals && unhandled_signal(tsk, signo) 122 && printk_ratelimit()) { 123 pr_info("%s[%d]: unhandled signal %d code 0x%x at 0x%08lx", 124 tsk->comm, task_pid_nr(tsk), signo, code, addr); 125 print_vma_addr(KERN_CONT " in ", instruction_pointer(regs)); 126 pr_cont("\n"); 127 show_regs(regs); 128 } 129 130 force_sig_fault(signo, code, (void __user *)addr); 131 } 132 133 static void do_trap_error(struct pt_regs *regs, int signo, int code, 134 unsigned long addr, const char *str) 135 { 136 current->thread.trap_no = trap_no(regs); 137 138 if (user_mode(regs)) { 139 do_trap(regs, signo, code, addr); 140 } else { 141 if (!fixup_exception(regs)) 142 die(regs, str); 143 } 144 } 145 146 #define DO_ERROR_INFO(name, signo, code, str) \ 147 asmlinkage __visible void name(struct pt_regs *regs) \ 148 { \ 149 do_trap_error(regs, signo, code, regs->pc, "Oops - " str); \ 150 } 151 152 DO_ERROR_INFO(do_trap_unknown, 153 SIGILL, ILL_ILLTRP, "unknown exception"); 154 DO_ERROR_INFO(do_trap_zdiv, 155 SIGFPE, FPE_INTDIV, "error zero div exception"); 156 DO_ERROR_INFO(do_trap_buserr, 157 SIGSEGV, ILL_ILLADR, "error bus error exception"); 158 159 asmlinkage void do_trap_misaligned(struct pt_regs *regs) 160 { 161 #ifdef CONFIG_CPU_NEED_SOFTALIGN 162 csky_alignment(regs); 163 #else 164 current->thread.trap_no = trap_no(regs); 165 do_trap_error(regs, SIGBUS, BUS_ADRALN, regs->pc, 166 "Oops - load/store address misaligned"); 167 #endif 168 } 169 170 asmlinkage void do_trap_bkpt(struct pt_regs *regs) 171 { 172 #ifdef CONFIG_KPROBES 173 if (kprobe_single_step_handler(regs)) 174 return; 175 #endif 176 #ifdef CONFIG_UPROBES 177 if (uprobe_single_step_handler(regs)) 178 return; 179 #endif 180 if (user_mode(regs)) { 181 send_sig(SIGTRAP, current, 0); 182 return; 183 } 184 185 do_trap_error(regs, SIGILL, ILL_ILLTRP, regs->pc, 186 "Oops - illegal trap exception"); 187 } 188 189 asmlinkage void do_trap_illinsn(struct pt_regs *regs) 190 { 191 current->thread.trap_no = trap_no(regs); 192 193 #ifdef CONFIG_KPROBES 194 if (kprobe_breakpoint_handler(regs)) 195 return; 196 #endif 197 #ifdef CONFIG_UPROBES 198 if (uprobe_breakpoint_handler(regs)) 199 return; 200 #endif 201 #ifndef CONFIG_CPU_NO_USER_BKPT 202 if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) { 203 send_sig(SIGTRAP, current, 0); 204 return; 205 } 206 #endif 207 208 do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, 209 "Oops - illegal instruction exception"); 210 } 211 212 asmlinkage void do_trap_fpe(struct pt_regs *regs) 213 { 214 #ifdef CONFIG_CPU_HAS_FP 215 return fpu_fpe(regs); 216 #else 217 do_trap_error(regs, SIGILL, ILL_ILLOPC, regs->pc, 218 "Oops - fpu instruction exception"); 219 #endif 220 } 221 222 asmlinkage void do_trap_priv(struct pt_regs *regs) 223 { 224 #ifdef CONFIG_CPU_HAS_FP 225 if (user_mode(regs) && fpu_libc_helper(regs)) 226 return; 227 #endif 228 do_trap_error(regs, SIGILL, ILL_PRVOPC, regs->pc, 229 "Oops - illegal privileged exception"); 230 } 231 232 asmlinkage void trap_c(struct pt_regs *regs) 233 { 234 switch (trap_no(regs)) { 235 case VEC_ZERODIV: 236 do_trap_zdiv(regs); 237 break; 238 case VEC_TRACE: 239 do_trap_bkpt(regs); 240 break; 241 case VEC_ILLEGAL: 242 do_trap_illinsn(regs); 243 break; 244 case VEC_TRAP1: 245 case VEC_BREAKPOINT: 246 do_trap_bkpt(regs); 247 break; 248 case VEC_ACCESS: 249 do_trap_buserr(regs); 250 break; 251 case VEC_ALIGN: 252 do_trap_misaligned(regs); 253 break; 254 case VEC_FPE: 255 do_trap_fpe(regs); 256 break; 257 case VEC_PRIV: 258 do_trap_priv(regs); 259 break; 260 default: 261 do_trap_unknown(regs); 262 break; 263 } 264 } 265