Commit | Line | Data |
---|---|---|
081860b9 GR |
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 | ||
2e1661d2 | 109 | force_sig_fault(SIGSEGV, 0, (void __user *)regs->pc); |
081860b9 GR |
110 | } |
111 | ||
112 | #define USR_BKPT 0x1464 | |
113 | asmlinkage void trap_c(struct pt_regs *regs) | |
114 | { | |
115 | int sig; | |
116 | unsigned long vector; | |
117 | siginfo_t info; | |
118 | ||
119 | vector = (mfcr("psr") >> 16) & 0xff; | |
120 | ||
121 | switch (vector) { | |
122 | case VEC_ZERODIV: | |
123 | sig = SIGFPE; | |
124 | break; | |
125 | /* ptrace */ | |
126 | case VEC_TRACE: | |
127 | info.si_code = TRAP_TRACE; | |
128 | sig = SIGTRAP; | |
129 | break; | |
130 | case VEC_ILLEGAL: | |
131 | #ifndef CONFIG_CPU_NO_USER_BKPT | |
132 | if (*(uint16_t *)instruction_pointer(regs) != USR_BKPT) | |
133 | #endif | |
134 | { | |
135 | sig = SIGILL; | |
136 | break; | |
137 | } | |
138 | /* gdbserver breakpoint */ | |
139 | case VEC_TRAP1: | |
140 | /* jtagserver breakpoint */ | |
141 | case VEC_BREAKPOINT: | |
142 | info.si_code = TRAP_BRKPT; | |
143 | sig = SIGTRAP; | |
144 | break; | |
145 | case VEC_ACCESS: | |
146 | return buserr(regs); | |
147 | #ifdef CONFIG_CPU_NEED_SOFTALIGN | |
148 | case VEC_ALIGN: | |
149 | return csky_alignment(regs); | |
150 | #endif | |
151 | #ifdef CONFIG_CPU_HAS_FPU | |
152 | case VEC_FPE: | |
153 | return fpu_fpe(regs); | |
154 | case VEC_PRIV: | |
155 | if (fpu_libc_helper(regs)) | |
156 | return; | |
157 | #endif | |
158 | default: | |
159 | sig = SIGSEGV; | |
160 | break; | |
161 | } | |
162 | send_sig(sig, current, 0); | |
163 | } |