aboutsummaryrefslogtreecommitdiffstats
path: root/arch/powerpc/math-emu/math.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/powerpc/math-emu/math.c')
-rw-r--r--arch/powerpc/math-emu/math.c89
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 */
18FLOATFUNC(fre);
19FLOATFUNC(frsqrtes);
20FLOATFUNC(fsqrt);
21FLOATFUNC(fsqrts);
22FLOATFUNC(mtfsf);
23FLOATFUNC(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
16FLOATFUNC(fadd); 31FLOATFUNC(fadd);
17FLOATFUNC(fadds); 32FLOATFUNC(fadds);
18FLOATFUNC(fdiv); 33FLOATFUNC(fdiv);
@@ -42,8 +57,6 @@ FLOATFUNC(mcrfs);
42FLOATFUNC(mffs); 57FLOATFUNC(mffs);
43FLOATFUNC(mtfsb0); 58FLOATFUNC(mtfsb0);
44FLOATFUNC(mtfsb1); 59FLOATFUNC(mtfsb1);
45FLOATFUNC(mtfsf);
46FLOATFUNC(mtfsfi);
47 60
48FLOATFUNC(lfd); 61FLOATFUNC(lfd);
49FLOATFUNC(lfs); 62FLOATFUNC(lfs);
@@ -58,13 +71,9 @@ FLOATFUNC(fnabs);
58FLOATFUNC(fneg); 71FLOATFUNC(fneg);
59 72
60/* Optional */ 73/* Optional */
61FLOATFUNC(fre);
62FLOATFUNC(fres); 74FLOATFUNC(fres);
63FLOATFUNC(frsqrte); 75FLOATFUNC(frsqrte);
64FLOATFUNC(frsqrtes);
65FLOATFUNC(fsel); 76FLOATFUNC(fsel);
66FLOATFUNC(fsqrt);
67FLOATFUNC(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
158static int 166static int
159record_exception(struct pt_regs *regs, int eflag) 167record_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
217int 224int
218do_mathemu(struct pt_regs *regs) 225do_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 *)&current->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 *)&current->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 *)&current->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 *)&current->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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
268 op1 = (void *)&current->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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f); 382 op0 = (void *)&current->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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f); 391 op0 = (void *)&current->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;