diff options
author | Guo Ren <ren_guo@c-sky.com> | 2018-09-05 02:25:14 -0400 |
---|---|---|
committer | Guo Ren <ren_guo@c-sky.com> | 2018-10-25 12:54:13 -0400 |
commit | e9564df753fd547fcbcd4fd10015c3b1213ef452 (patch) | |
tree | 067236e1b2b5812db80e3ba1ea94b0e2a737a28f /arch/csky/abiv2/fpu.c | |
parent | 013de2d6671d89de3397904749c86a69ac0686f7 (diff) |
csky: Process management and Signal
This patch adds files related to task_switch, sigcontext, signal,
fpu context switch.
Signed-off-by: Guo Ren <ren_guo@c-sky.com>
Cc: Arnd Bergmann <arnd@arndb.de>
Cc: Eric W. Biederman <ebiederm@xmission.com>
Diffstat (limited to 'arch/csky/abiv2/fpu.c')
-rw-r--r-- | arch/csky/abiv2/fpu.c | 275 |
1 files changed, 275 insertions, 0 deletions
diff --git a/arch/csky/abiv2/fpu.c b/arch/csky/abiv2/fpu.c new file mode 100644 index 000000000000..e7e11344005a --- /dev/null +++ b/arch/csky/abiv2/fpu.c | |||
@@ -0,0 +1,275 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. | ||
3 | |||
4 | #include <linux/ptrace.h> | ||
5 | #include <linux/uaccess.h> | ||
6 | #include <abi/reg_ops.h> | ||
7 | |||
8 | #define MTCR_MASK 0xFC00FFE0 | ||
9 | #define MFCR_MASK 0xFC00FFE0 | ||
10 | #define MTCR_DIST 0xC0006420 | ||
11 | #define MFCR_DIST 0xC0006020 | ||
12 | |||
13 | void __init init_fpu(void) | ||
14 | { | ||
15 | mtcr("cr<1, 2>", 0); | ||
16 | } | ||
17 | |||
18 | /* | ||
19 | * fpu_libc_helper() is to help libc to excute: | ||
20 | * - mfcr %a, cr<1, 2> | ||
21 | * - mfcr %a, cr<2, 2> | ||
22 | * - mtcr %a, cr<1, 2> | ||
23 | * - mtcr %a, cr<2, 2> | ||
24 | */ | ||
25 | int fpu_libc_helper(struct pt_regs *regs) | ||
26 | { | ||
27 | int fault; | ||
28 | unsigned long instrptr, regx = 0; | ||
29 | unsigned long index = 0, tmp = 0; | ||
30 | unsigned long tinstr = 0; | ||
31 | u16 instr_hi, instr_low; | ||
32 | |||
33 | instrptr = instruction_pointer(regs); | ||
34 | if (instrptr & 1) | ||
35 | return 0; | ||
36 | |||
37 | fault = __get_user(instr_low, (u16 *)instrptr); | ||
38 | if (fault) | ||
39 | return 0; | ||
40 | |||
41 | fault = __get_user(instr_hi, (u16 *)(instrptr + 2)); | ||
42 | if (fault) | ||
43 | return 0; | ||
44 | |||
45 | tinstr = instr_hi | ((unsigned long)instr_low << 16); | ||
46 | |||
47 | if (((tinstr >> 21) & 0x1F) != 2) | ||
48 | return 0; | ||
49 | |||
50 | if ((tinstr & MTCR_MASK) == MTCR_DIST) { | ||
51 | index = (tinstr >> 16) & 0x1F; | ||
52 | if (index > 13) | ||
53 | return 0; | ||
54 | |||
55 | tmp = tinstr & 0x1F; | ||
56 | if (tmp > 2) | ||
57 | return 0; | ||
58 | |||
59 | regx = *(®s->a0 + index); | ||
60 | |||
61 | if (tmp == 1) | ||
62 | mtcr("cr<1, 2>", regx); | ||
63 | else if (tmp == 2) | ||
64 | mtcr("cr<2, 2>", regx); | ||
65 | else | ||
66 | return 0; | ||
67 | |||
68 | regs->pc += 4; | ||
69 | return 1; | ||
70 | } | ||
71 | |||
72 | if ((tinstr & MFCR_MASK) == MFCR_DIST) { | ||
73 | index = tinstr & 0x1F; | ||
74 | if (index > 13) | ||
75 | return 0; | ||
76 | |||
77 | tmp = ((tinstr >> 16) & 0x1F); | ||
78 | if (tmp > 2) | ||
79 | return 0; | ||
80 | |||
81 | if (tmp == 1) | ||
82 | regx = mfcr("cr<1, 2>"); | ||
83 | else if (tmp == 2) | ||
84 | regx = mfcr("cr<2, 2>"); | ||
85 | else | ||
86 | return 0; | ||
87 | |||
88 | *(®s->a0 + index) = regx; | ||
89 | |||
90 | regs->pc += 4; | ||
91 | return 1; | ||
92 | } | ||
93 | |||
94 | return 0; | ||
95 | } | ||
96 | |||
97 | void fpu_fpe(struct pt_regs *regs) | ||
98 | { | ||
99 | int sig, code; | ||
100 | unsigned int fesr; | ||
101 | |||
102 | fesr = mfcr("cr<2, 2>"); | ||
103 | |||
104 | sig = SIGFPE; | ||
105 | code = FPE_FLTUNK; | ||
106 | |||
107 | if (fesr & FPE_ILLE) { | ||
108 | sig = SIGILL; | ||
109 | code = ILL_ILLOPC; | ||
110 | } else if (fesr & FPE_IDC) { | ||
111 | sig = SIGILL; | ||
112 | code = ILL_ILLOPN; | ||
113 | } else if (fesr & FPE_FEC) { | ||
114 | sig = SIGFPE; | ||
115 | if (fesr & FPE_IOC) | ||
116 | code = FPE_FLTINV; | ||
117 | else if (fesr & FPE_DZC) | ||
118 | code = FPE_FLTDIV; | ||
119 | else if (fesr & FPE_UFC) | ||
120 | code = FPE_FLTUND; | ||
121 | else if (fesr & FPE_OFC) | ||
122 | code = FPE_FLTOVF; | ||
123 | else if (fesr & FPE_IXC) | ||
124 | code = FPE_FLTRES; | ||
125 | } | ||
126 | |||
127 | force_sig_fault(sig, code, (void __user *)regs->pc, current); | ||
128 | } | ||
129 | |||
130 | #define FMFVR_FPU_REGS(vrx, vry) \ | ||
131 | "fmfvrl %0, "#vrx"\n" \ | ||
132 | "fmfvrh %1, "#vrx"\n" \ | ||
133 | "fmfvrl %2, "#vry"\n" \ | ||
134 | "fmfvrh %3, "#vry"\n" | ||
135 | |||
136 | #define FMTVR_FPU_REGS(vrx, vry) \ | ||
137 | "fmtvrl "#vrx", %0\n" \ | ||
138 | "fmtvrh "#vrx", %1\n" \ | ||
139 | "fmtvrl "#vry", %2\n" \ | ||
140 | "fmtvrh "#vry", %3\n" | ||
141 | |||
142 | #define STW_FPU_REGS(a, b, c, d) \ | ||
143 | "stw %0, (%4, "#a")\n" \ | ||
144 | "stw %1, (%4, "#b")\n" \ | ||
145 | "stw %2, (%4, "#c")\n" \ | ||
146 | "stw %3, (%4, "#d")\n" | ||
147 | |||
148 | #define LDW_FPU_REGS(a, b, c, d) \ | ||
149 | "ldw %0, (%4, "#a")\n" \ | ||
150 | "ldw %1, (%4, "#b")\n" \ | ||
151 | "ldw %2, (%4, "#c")\n" \ | ||
152 | "ldw %3, (%4, "#d")\n" | ||
153 | |||
154 | void save_to_user_fp(struct user_fp *user_fp) | ||
155 | { | ||
156 | unsigned long flg; | ||
157 | unsigned long tmp1, tmp2; | ||
158 | unsigned long *fpregs; | ||
159 | |||
160 | local_irq_save(flg); | ||
161 | |||
162 | tmp1 = mfcr("cr<1, 2>"); | ||
163 | tmp2 = mfcr("cr<2, 2>"); | ||
164 | |||
165 | user_fp->fcr = tmp1; | ||
166 | user_fp->fesr = tmp2; | ||
167 | |||
168 | fpregs = &user_fp->vr[0]; | ||
169 | #ifdef CONFIG_CPU_HAS_FPUV2 | ||
170 | #ifdef CONFIG_CPU_HAS_VDSP | ||
171 | asm volatile( | ||
172 | "vstmu.32 vr0-vr3, (%0)\n" | ||
173 | "vstmu.32 vr4-vr7, (%0)\n" | ||
174 | "vstmu.32 vr8-vr11, (%0)\n" | ||
175 | "vstmu.32 vr12-vr15, (%0)\n" | ||
176 | "fstmu.64 vr16-vr31, (%0)\n" | ||
177 | : "+a"(fpregs) | ||
178 | ::"memory"); | ||
179 | #else | ||
180 | asm volatile( | ||
181 | "fstmu.64 vr0-vr31, (%0)\n" | ||
182 | : "+a"(fpregs) | ||
183 | ::"memory"); | ||
184 | #endif | ||
185 | #else | ||
186 | { | ||
187 | unsigned long tmp3, tmp4; | ||
188 | |||
189 | asm volatile( | ||
190 | FMFVR_FPU_REGS(vr0, vr1) | ||
191 | STW_FPU_REGS(0, 4, 16, 20) | ||
192 | FMFVR_FPU_REGS(vr2, vr3) | ||
193 | STW_FPU_REGS(32, 36, 48, 52) | ||
194 | FMFVR_FPU_REGS(vr4, vr5) | ||
195 | STW_FPU_REGS(64, 68, 80, 84) | ||
196 | FMFVR_FPU_REGS(vr6, vr7) | ||
197 | STW_FPU_REGS(96, 100, 112, 116) | ||
198 | "addi %4, 128\n" | ||
199 | FMFVR_FPU_REGS(vr8, vr9) | ||
200 | STW_FPU_REGS(0, 4, 16, 20) | ||
201 | FMFVR_FPU_REGS(vr10, vr11) | ||
202 | STW_FPU_REGS(32, 36, 48, 52) | ||
203 | FMFVR_FPU_REGS(vr12, vr13) | ||
204 | STW_FPU_REGS(64, 68, 80, 84) | ||
205 | FMFVR_FPU_REGS(vr14, vr15) | ||
206 | STW_FPU_REGS(96, 100, 112, 116) | ||
207 | : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3), | ||
208 | "=a"(tmp4), "+a"(fpregs) | ||
209 | ::"memory"); | ||
210 | } | ||
211 | #endif | ||
212 | |||
213 | local_irq_restore(flg); | ||
214 | } | ||
215 | |||
216 | void restore_from_user_fp(struct user_fp *user_fp) | ||
217 | { | ||
218 | unsigned long flg; | ||
219 | unsigned long tmp1, tmp2; | ||
220 | unsigned long *fpregs; | ||
221 | |||
222 | local_irq_save(flg); | ||
223 | |||
224 | tmp1 = user_fp->fcr; | ||
225 | tmp2 = user_fp->fesr; | ||
226 | |||
227 | mtcr("cr<1, 2>", tmp1); | ||
228 | mtcr("cr<2, 2>", tmp2); | ||
229 | |||
230 | fpregs = &user_fp->vr[0]; | ||
231 | #ifdef CONFIG_CPU_HAS_FPUV2 | ||
232 | #ifdef CONFIG_CPU_HAS_VDSP | ||
233 | asm volatile( | ||
234 | "vldmu.32 vr0-vr3, (%0)\n" | ||
235 | "vldmu.32 vr4-vr7, (%0)\n" | ||
236 | "vldmu.32 vr8-vr11, (%0)\n" | ||
237 | "vldmu.32 vr12-vr15, (%0)\n" | ||
238 | "fldmu.64 vr16-vr31, (%0)\n" | ||
239 | : "+a"(fpregs) | ||
240 | ::"memory"); | ||
241 | #else | ||
242 | asm volatile( | ||
243 | "fldmu.64 vr0-vr31, (%0)\n" | ||
244 | : "+a"(fpregs) | ||
245 | ::"memory"); | ||
246 | #endif | ||
247 | #else | ||
248 | { | ||
249 | unsigned long tmp3, tmp4; | ||
250 | |||
251 | asm volatile( | ||
252 | LDW_FPU_REGS(0, 4, 16, 20) | ||
253 | FMTVR_FPU_REGS(vr0, vr1) | ||
254 | LDW_FPU_REGS(32, 36, 48, 52) | ||
255 | FMTVR_FPU_REGS(vr2, vr3) | ||
256 | LDW_FPU_REGS(64, 68, 80, 84) | ||
257 | FMTVR_FPU_REGS(vr4, vr5) | ||
258 | LDW_FPU_REGS(96, 100, 112, 116) | ||
259 | FMTVR_FPU_REGS(vr6, vr7) | ||
260 | "addi %4, 128\n" | ||
261 | LDW_FPU_REGS(0, 4, 16, 20) | ||
262 | FMTVR_FPU_REGS(vr8, vr9) | ||
263 | LDW_FPU_REGS(32, 36, 48, 52) | ||
264 | FMTVR_FPU_REGS(vr10, vr11) | ||
265 | LDW_FPU_REGS(64, 68, 80, 84) | ||
266 | FMTVR_FPU_REGS(vr12, vr13) | ||
267 | LDW_FPU_REGS(96, 100, 112, 116) | ||
268 | FMTVR_FPU_REGS(vr14, vr15) | ||
269 | : "=a"(tmp1), "=a"(tmp2), "=a"(tmp3), | ||
270 | "=a"(tmp4), "+a"(fpregs) | ||
271 | ::"memory"); | ||
272 | } | ||
273 | #endif | ||
274 | local_irq_restore(flg); | ||
275 | } | ||