1 // SPDX-License-Identifier: GPL-2.0
2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
4 #include <linux/ptrace.h>
5 #include <linux/uaccess.h>
6 #include <abi/reg_ops.h>
8 #define MTCR_MASK 0xFC00FFE0
9 #define MFCR_MASK 0xFC00FFE0
10 #define MTCR_DIST 0xC0006420
11 #define MFCR_DIST 0xC0006020
13 void __init
init_fpu(void)
19 * fpu_libc_helper() is to help libc to excute:
25 int fpu_libc_helper(struct pt_regs
*regs
)
28 unsigned long instrptr
, regx
= 0;
29 unsigned long index
= 0, tmp
= 0;
30 unsigned long tinstr
= 0;
31 u16 instr_hi
, instr_low
;
33 instrptr
= instruction_pointer(regs
);
37 fault
= __get_user(instr_low
, (u16
*)instrptr
);
41 fault
= __get_user(instr_hi
, (u16
*)(instrptr
+ 2));
45 tinstr
= instr_hi
| ((unsigned long)instr_low
<< 16);
47 if (((tinstr
>> 21) & 0x1F) != 2)
50 if ((tinstr
& MTCR_MASK
) == MTCR_DIST
) {
51 index
= (tinstr
>> 16) & 0x1F;
59 regx
= *(®s
->a0
+ index
);
62 mtcr("cr<1, 2>", regx
);
64 mtcr("cr<2, 2>", regx
);
72 if ((tinstr
& MFCR_MASK
) == MFCR_DIST
) {
73 index
= tinstr
& 0x1F;
77 tmp
= ((tinstr
>> 16) & 0x1F);
82 regx
= mfcr("cr<1, 2>");
84 regx
= mfcr("cr<2, 2>");
88 *(®s
->a0
+ index
) = regx
;
97 void fpu_fpe(struct pt_regs
*regs
)
102 fesr
= mfcr("cr<2, 2>");
107 if (fesr
& FPE_ILLE
) {
110 } else if (fesr
& FPE_IDC
) {
113 } else if (fesr
& FPE_FEC
) {
117 else if (fesr
& FPE_DZC
)
119 else if (fesr
& FPE_UFC
)
121 else if (fesr
& FPE_OFC
)
123 else if (fesr
& FPE_IXC
)
127 force_sig_fault(sig
, code
, (void __user
*)regs
->pc
);
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"
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"
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"
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"
154 void save_to_user_fp(struct user_fp
*user_fp
)
157 unsigned long tmp1
, tmp2
;
158 unsigned long *fpregs
;
162 tmp1
= mfcr("cr<1, 2>");
163 tmp2
= mfcr("cr<2, 2>");
166 user_fp
->fesr
= tmp2
;
168 fpregs
= &user_fp
->vr
[0];
169 #ifdef CONFIG_CPU_HAS_FPUV2
170 #ifdef CONFIG_CPU_HAS_VDSP
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"
181 "fstmu.64 vr0-vr31, (%0)\n"
187 unsigned long tmp3
, tmp4
;
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)
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
)
213 local_irq_restore(flg
);
216 void restore_from_user_fp(struct user_fp
*user_fp
)
219 unsigned long tmp1
, tmp2
;
220 unsigned long *fpregs
;
225 tmp2
= user_fp
->fesr
;
227 mtcr("cr<1, 2>", tmp1
);
228 mtcr("cr<2, 2>", tmp2
);
230 fpregs
= &user_fp
->vr
[0];
231 #ifdef CONFIG_CPU_HAS_FPUV2
232 #ifdef CONFIG_CPU_HAS_VDSP
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"
243 "fldmu.64 vr0-vr31, (%0)\n"
249 unsigned long tmp3
, tmp4
;
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
)
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
)
274 local_irq_restore(flg
);