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