diff options
Diffstat (limited to 'arch/powerpc/math-emu/math.c')
-rw-r--r-- | arch/powerpc/math-emu/math.c | 89 |
1 files changed, 27 insertions, 62 deletions
diff --git a/arch/powerpc/math-emu/math.c b/arch/powerpc/math-emu/math.c index 0328e66e0799..ab151f040502 100644 --- a/arch/powerpc/math-emu/math.c +++ b/arch/powerpc/math-emu/math.c | |||
@@ -7,12 +7,27 @@ | |||
7 | 7 | ||
8 | #include <asm/uaccess.h> | 8 | #include <asm/uaccess.h> |
9 | #include <asm/reg.h> | 9 | #include <asm/reg.h> |
10 | #include <asm/switch_to.h> | ||
10 | 11 | ||
11 | #include <asm/sfp-machine.h> | 12 | #include <asm/sfp-machine.h> |
12 | #include <math-emu/double.h> | 13 | #include <math-emu/double.h> |
13 | 14 | ||
14 | #define FLOATFUNC(x) extern int x(void *, void *, void *, void *) | 15 | #define FLOATFUNC(x) extern int x(void *, void *, void *, void *) |
15 | 16 | ||
17 | /* The instructions list which may be not implemented by a hardware FPU */ | ||
18 | FLOATFUNC(fre); | ||
19 | FLOATFUNC(frsqrtes); | ||
20 | FLOATFUNC(fsqrt); | ||
21 | FLOATFUNC(fsqrts); | ||
22 | FLOATFUNC(mtfsf); | ||
23 | FLOATFUNC(mtfsfi); | ||
24 | |||
25 | #ifdef CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED | ||
26 | #undef FLOATFUNC(x) | ||
27 | #define FLOATFUNC(x) static inline int x(void *op1, void *op2, void *op3, \ | ||
28 | void *op4) { } | ||
29 | #endif | ||
30 | |||
16 | FLOATFUNC(fadd); | 31 | FLOATFUNC(fadd); |
17 | FLOATFUNC(fadds); | 32 | FLOATFUNC(fadds); |
18 | FLOATFUNC(fdiv); | 33 | FLOATFUNC(fdiv); |
@@ -42,8 +57,6 @@ FLOATFUNC(mcrfs); | |||
42 | FLOATFUNC(mffs); | 57 | FLOATFUNC(mffs); |
43 | FLOATFUNC(mtfsb0); | 58 | FLOATFUNC(mtfsb0); |
44 | FLOATFUNC(mtfsb1); | 59 | FLOATFUNC(mtfsb1); |
45 | FLOATFUNC(mtfsf); | ||
46 | FLOATFUNC(mtfsfi); | ||
47 | 60 | ||
48 | FLOATFUNC(lfd); | 61 | FLOATFUNC(lfd); |
49 | FLOATFUNC(lfs); | 62 | FLOATFUNC(lfs); |
@@ -58,13 +71,9 @@ FLOATFUNC(fnabs); | |||
58 | FLOATFUNC(fneg); | 71 | FLOATFUNC(fneg); |
59 | 72 | ||
60 | /* Optional */ | 73 | /* Optional */ |
61 | FLOATFUNC(fre); | ||
62 | FLOATFUNC(fres); | 74 | FLOATFUNC(fres); |
63 | FLOATFUNC(frsqrte); | 75 | FLOATFUNC(frsqrte); |
64 | FLOATFUNC(frsqrtes); | ||
65 | FLOATFUNC(fsel); | 76 | FLOATFUNC(fsel); |
66 | FLOATFUNC(fsqrt); | ||
67 | FLOATFUNC(fsqrts); | ||
68 | 77 | ||
69 | 78 | ||
70 | #define OP31 0x1f /* 31 */ | 79 | #define OP31 0x1f /* 31 */ |
@@ -154,7 +163,6 @@ FLOATFUNC(fsqrts); | |||
154 | #define XEU 15 | 163 | #define XEU 15 |
155 | #define XFLB 10 | 164 | #define XFLB 10 |
156 | 165 | ||
157 | #ifdef CONFIG_MATH_EMULATION | ||
158 | static int | 166 | static int |
159 | record_exception(struct pt_regs *regs, int eflag) | 167 | record_exception(struct pt_regs *regs, int eflag) |
160 | { | 168 | { |
@@ -212,7 +220,6 @@ record_exception(struct pt_regs *regs, int eflag) | |||
212 | 220 | ||
213 | return (fpscr & FPSCR_FEX) ? 1 : 0; | 221 | return (fpscr & FPSCR_FEX) ? 1 : 0; |
214 | } | 222 | } |
215 | #endif /* CONFIG_MATH_EMULATION */ | ||
216 | 223 | ||
217 | int | 224 | int |
218 | do_mathemu(struct pt_regs *regs) | 225 | do_mathemu(struct pt_regs *regs) |
@@ -222,56 +229,13 @@ do_mathemu(struct pt_regs *regs) | |||
222 | signed short sdisp; | 229 | signed short sdisp; |
223 | u32 insn = 0; | 230 | u32 insn = 0; |
224 | int idx = 0; | 231 | int idx = 0; |
225 | #ifdef CONFIG_MATH_EMULATION | ||
226 | int (*func)(void *, void *, void *, void *); | 232 | int (*func)(void *, void *, void *, void *); |
227 | int type = 0; | 233 | int type = 0; |
228 | int eflag, trap; | 234 | int eflag, trap; |
229 | #endif | ||
230 | 235 | ||
231 | if (get_user(insn, (u32 *)pc)) | 236 | if (get_user(insn, (u32 *)pc)) |
232 | return -EFAULT; | 237 | return -EFAULT; |
233 | 238 | ||
234 | #ifndef CONFIG_MATH_EMULATION | ||
235 | switch (insn >> 26) { | ||
236 | case LFD: | ||
237 | idx = (insn >> 16) & 0x1f; | ||
238 | sdisp = (insn & 0xffff); | ||
239 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | ||
240 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
241 | lfd(op0, op1, op2, op3); | ||
242 | break; | ||
243 | case LFDU: | ||
244 | idx = (insn >> 16) & 0x1f; | ||
245 | sdisp = (insn & 0xffff); | ||
246 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | ||
247 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
248 | lfd(op0, op1, op2, op3); | ||
249 | regs->gpr[idx] = (unsigned long)op1; | ||
250 | break; | ||
251 | case STFD: | ||
252 | idx = (insn >> 16) & 0x1f; | ||
253 | sdisp = (insn & 0xffff); | ||
254 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | ||
255 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
256 | stfd(op0, op1, op2, op3); | ||
257 | break; | ||
258 | case STFDU: | ||
259 | idx = (insn >> 16) & 0x1f; | ||
260 | sdisp = (insn & 0xffff); | ||
261 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | ||
262 | op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp); | ||
263 | stfd(op0, op1, op2, op3); | ||
264 | regs->gpr[idx] = (unsigned long)op1; | ||
265 | break; | ||
266 | case OP63: | ||
267 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | ||
268 | op1 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f); | ||
269 | fmr(op0, op1, op2, op3); | ||
270 | break; | ||
271 | default: | ||
272 | goto illegal; | ||
273 | } | ||
274 | #else /* CONFIG_MATH_EMULATION */ | ||
275 | switch (insn >> 26) { | 239 | switch (insn >> 26) { |
276 | case LFS: func = lfs; type = D; break; | 240 | case LFS: func = lfs; type = D; break; |
277 | case LFSU: func = lfs; type = DU; break; | 241 | case LFSU: func = lfs; type = DU; break; |
@@ -416,21 +380,16 @@ do_mathemu(struct pt_regs *regs) | |||
416 | case XE: | 380 | case XE: |
417 | idx = (insn >> 16) & 0x1f; | 381 | idx = (insn >> 16) & 0x1f; |
418 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | 382 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); |
419 | if (!idx) { | 383 | op1 = (void *)((idx ? regs->gpr[idx] : 0) |
420 | if (((insn >> 1) & 0x3ff) == STFIWX) | 384 | + regs->gpr[(insn >> 11) & 0x1f]); |
421 | op1 = (void *)(regs->gpr[(insn >> 11) & 0x1f]); | ||
422 | else | ||
423 | goto illegal; | ||
424 | } else { | ||
425 | op1 = (void *)(regs->gpr[idx] + regs->gpr[(insn >> 11) & 0x1f]); | ||
426 | } | ||
427 | |||
428 | break; | 385 | break; |
429 | 386 | ||
430 | case XEU: | 387 | case XEU: |
431 | idx = (insn >> 16) & 0x1f; | 388 | idx = (insn >> 16) & 0x1f; |
389 | if (!idx) | ||
390 | goto illegal; | ||
432 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); | 391 | op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f); |
433 | op1 = (void *)((idx ? regs->gpr[idx] : 0) | 392 | op1 = (void *)(regs->gpr[idx] |
434 | + regs->gpr[(insn >> 11) & 0x1f]); | 393 | + regs->gpr[(insn >> 11) & 0x1f]); |
435 | break; | 394 | break; |
436 | 395 | ||
@@ -465,6 +424,13 @@ do_mathemu(struct pt_regs *regs) | |||
465 | goto illegal; | 424 | goto illegal; |
466 | } | 425 | } |
467 | 426 | ||
427 | /* | ||
428 | * If we support a HW FPU, we need to ensure the FP state | ||
429 | * is flushed into the thread_struct before attempting | ||
430 | * emulation | ||
431 | */ | ||
432 | flush_fp_to_thread(current); | ||
433 | |||
468 | eflag = func(op0, op1, op2, op3); | 434 | eflag = func(op0, op1, op2, op3); |
469 | 435 | ||
470 | if (insn & 1) { | 436 | if (insn & 1) { |
@@ -485,7 +451,6 @@ do_mathemu(struct pt_regs *regs) | |||
485 | default: | 451 | default: |
486 | break; | 452 | break; |
487 | } | 453 | } |
488 | #endif /* CONFIG_MATH_EMULATION */ | ||
489 | 454 | ||
490 | regs->nip += 4; | 455 | regs->nip += 4; |
491 | return 0; | 456 | return 0; |