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 current->thread.esp0 = (unsigned long) regs; 110 force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc, current); 111 } 112 113 #define USR_BKPT 0x1464 114 asmlinkage void trap_c(struct pt_regs *regs) 115 { 116 int sig; 117 unsigned long vector; 118 siginfo_t info; 119 120 vector = (mfcr("psr") >> 16) & 0xff; 121 122 switch (vector) { 123 case VEC_ZERODIV: 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 #ifndef CONFIG_CPU_NO_USER_BKPT 133 if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) 134 #endif 135 { 136 sig = SIGILL; 137 break; 138 } 139 /* gdbserver breakpoint */ 140 case VEC_TRAP1: 141 /* jtagserver breakpoint */ 142 case VEC_BREAKPOINT: 143 info.si_code = TRAP_BRKPT; 144 sig = SIGTRAP; 145 break; 146 case VEC_ACCESS: 147 return buserr(regs); 148 #ifdef CONFIG_CPU_NEED_SOFTALIGN 149 case VEC_ALIGN: 150 return csky_alignment(regs); 151 #endif 152 #ifdef CONFIG_CPU_HAS_FPU 153 case VEC_FPE: 154 return fpu_fpe(regs); 155 case VEC_PRIV: 156 if (fpu_libc_helper(regs)) 157 return; 158 #endif 159 default: 160 sig = SIGSEGV; 161 break; 162 } 163 send_sig(sig, current, 0); 164 } 165 166 asmlinkage void set_esp0(unsigned long ssp) 167 { 168 current->thread.esp0 = ssp; 169 } 170