0001
0002
0003
0004
0005
0006 #include <linux/types.h>
0007 #include <linux/sched.h>
0008
0009 #include <linux/uaccess.h>
0010 #include <asm/reg.h>
0011 #include <asm/switch_to.h>
0012
0013 #include <asm/sfp-machine.h>
0014 #include <math-emu/double.h>
0015
0016 #define FLOATFUNC(x) extern int x(void *, void *, void *, void *)
0017
0018
0019 FLOATFUNC(fre);
0020 FLOATFUNC(frsqrtes);
0021 FLOATFUNC(fsqrt);
0022 FLOATFUNC(fsqrts);
0023 FLOATFUNC(mtfsf);
0024 FLOATFUNC(mtfsfi);
0025
0026 #ifdef CONFIG_MATH_EMULATION_HW_UNIMPLEMENTED
0027 #undef FLOATFUNC(x)
0028 #define FLOATFUNC(x) static inline int x(void *op1, void *op2, void *op3, \
0029 void *op4) { }
0030 #endif
0031
0032 FLOATFUNC(fadd);
0033 FLOATFUNC(fadds);
0034 FLOATFUNC(fdiv);
0035 FLOATFUNC(fdivs);
0036 FLOATFUNC(fmul);
0037 FLOATFUNC(fmuls);
0038 FLOATFUNC(fsub);
0039 FLOATFUNC(fsubs);
0040
0041 FLOATFUNC(fmadd);
0042 FLOATFUNC(fmadds);
0043 FLOATFUNC(fmsub);
0044 FLOATFUNC(fmsubs);
0045 FLOATFUNC(fnmadd);
0046 FLOATFUNC(fnmadds);
0047 FLOATFUNC(fnmsub);
0048 FLOATFUNC(fnmsubs);
0049
0050 FLOATFUNC(fctiw);
0051 FLOATFUNC(fctiwz);
0052 FLOATFUNC(frsp);
0053
0054 FLOATFUNC(fcmpo);
0055 FLOATFUNC(fcmpu);
0056
0057 FLOATFUNC(mcrfs);
0058 FLOATFUNC(mffs);
0059 FLOATFUNC(mtfsb0);
0060 FLOATFUNC(mtfsb1);
0061
0062 FLOATFUNC(lfd);
0063 FLOATFUNC(lfs);
0064
0065 FLOATFUNC(stfd);
0066 FLOATFUNC(stfs);
0067 FLOATFUNC(stfiwx);
0068
0069 FLOATFUNC(fabs);
0070 FLOATFUNC(fmr);
0071 FLOATFUNC(fnabs);
0072 FLOATFUNC(fneg);
0073
0074
0075 FLOATFUNC(fres);
0076 FLOATFUNC(frsqrte);
0077 FLOATFUNC(fsel);
0078
0079
0080 #define OP31 0x1f
0081 #define LFS 0x30
0082 #define LFSU 0x31
0083 #define LFD 0x32
0084 #define LFDU 0x33
0085 #define STFS 0x34
0086 #define STFSU 0x35
0087 #define STFD 0x36
0088 #define STFDU 0x37
0089 #define OP59 0x3b
0090 #define OP63 0x3f
0091
0092
0093
0094 #define LFSX 0x217
0095 #define LFSUX 0x237
0096 #define LFDX 0x257
0097 #define LFDUX 0x277
0098 #define STFSX 0x297
0099 #define STFSUX 0x2b7
0100 #define STFDX 0x2d7
0101 #define STFDUX 0x2f7
0102 #define STFIWX 0x3d7
0103
0104
0105
0106 #define FDIVS 0x012
0107 #define FSUBS 0x014
0108 #define FADDS 0x015
0109 #define FSQRTS 0x016
0110 #define FRES 0x018
0111 #define FMULS 0x019
0112 #define FRSQRTES 0x01a
0113 #define FMSUBS 0x01c
0114 #define FMADDS 0x01d
0115 #define FNMSUBS 0x01e
0116 #define FNMADDS 0x01f
0117
0118
0119
0120 #define FDIV 0x012
0121 #define FSUB 0x014
0122 #define FADD 0x015
0123 #define FSQRT 0x016
0124 #define FSEL 0x017
0125 #define FRE 0x018
0126 #define FMUL 0x019
0127 #define FRSQRTE 0x01a
0128 #define FMSUB 0x01c
0129 #define FMADD 0x01d
0130 #define FNMSUB 0x01e
0131 #define FNMADD 0x01f
0132
0133
0134 #define FCMPU 0x000
0135 #define FRSP 0x00c
0136 #define FCTIW 0x00e
0137 #define FCTIWZ 0x00f
0138 #define FCMPO 0x020
0139 #define MTFSB1 0x026
0140 #define FNEG 0x028
0141 #define MCRFS 0x040
0142 #define MTFSB0 0x046
0143 #define FMR 0x048
0144 #define MTFSFI 0x086
0145 #define FNABS 0x088
0146 #define FABS 0x108
0147 #define MFFS 0x247
0148 #define MTFSF 0x2c7
0149
0150
0151 #define AB 2
0152 #define AC 3
0153 #define ABC 4
0154 #define D 5
0155 #define DU 6
0156 #define X 7
0157 #define XA 8
0158 #define XB 9
0159 #define XCR 11
0160 #define XCRB 12
0161 #define XCRI 13
0162 #define XCRL 16
0163 #define XE 14
0164 #define XEU 15
0165 #define XFLB 10
0166
0167 static int
0168 record_exception(struct pt_regs *regs, int eflag)
0169 {
0170 u32 fpscr;
0171
0172 fpscr = __FPU_FPSCR;
0173
0174 if (eflag) {
0175 fpscr |= FPSCR_FX;
0176 if (eflag & EFLAG_OVERFLOW)
0177 fpscr |= FPSCR_OX;
0178 if (eflag & EFLAG_UNDERFLOW)
0179 fpscr |= FPSCR_UX;
0180 if (eflag & EFLAG_DIVZERO)
0181 fpscr |= FPSCR_ZX;
0182 if (eflag & EFLAG_INEXACT)
0183 fpscr |= FPSCR_XX;
0184 if (eflag & EFLAG_INVALID)
0185 fpscr |= FPSCR_VX;
0186 if (eflag & EFLAG_VXSNAN)
0187 fpscr |= FPSCR_VXSNAN;
0188 if (eflag & EFLAG_VXISI)
0189 fpscr |= FPSCR_VXISI;
0190 if (eflag & EFLAG_VXIDI)
0191 fpscr |= FPSCR_VXIDI;
0192 if (eflag & EFLAG_VXZDZ)
0193 fpscr |= FPSCR_VXZDZ;
0194 if (eflag & EFLAG_VXIMZ)
0195 fpscr |= FPSCR_VXIMZ;
0196 if (eflag & EFLAG_VXVC)
0197 fpscr |= FPSCR_VXVC;
0198 if (eflag & EFLAG_VXSOFT)
0199 fpscr |= FPSCR_VXSOFT;
0200 if (eflag & EFLAG_VXSQRT)
0201 fpscr |= FPSCR_VXSQRT;
0202 if (eflag & EFLAG_VXCVI)
0203 fpscr |= FPSCR_VXCVI;
0204 }
0205
0206
0207 if (fpscr & (FPSCR_VXSNAN | FPSCR_VXISI | FPSCR_VXIDI |
0208 FPSCR_VXZDZ | FPSCR_VXIMZ | FPSCR_VXVC |
0209 FPSCR_VXSOFT | FPSCR_VXSQRT | FPSCR_VXCVI))
0210 fpscr |= FPSCR_VX;
0211
0212 fpscr &= ~(FPSCR_FEX);
0213 if (((fpscr & FPSCR_VX) && (fpscr & FPSCR_VE)) ||
0214 ((fpscr & FPSCR_OX) && (fpscr & FPSCR_OE)) ||
0215 ((fpscr & FPSCR_UX) && (fpscr & FPSCR_UE)) ||
0216 ((fpscr & FPSCR_ZX) && (fpscr & FPSCR_ZE)) ||
0217 ((fpscr & FPSCR_XX) && (fpscr & FPSCR_XE)))
0218 fpscr |= FPSCR_FEX;
0219
0220 __FPU_FPSCR = fpscr;
0221
0222 return (fpscr & FPSCR_FEX) ? 1 : 0;
0223 }
0224
0225 int
0226 do_mathemu(struct pt_regs *regs)
0227 {
0228 void *op0 = NULL, *op1 = NULL, *op2 = NULL, *op3 = NULL;
0229 unsigned long pc = regs->nip;
0230 signed short sdisp;
0231 u32 insn = 0;
0232 int idx = 0;
0233 int (*func)(void *, void *, void *, void *);
0234 int type = 0;
0235 int eflag, trap;
0236
0237 if (get_user(insn, (u32 __user *)pc))
0238 return -EFAULT;
0239
0240 switch (insn >> 26) {
0241 case LFS: func = lfs; type = D; break;
0242 case LFSU: func = lfs; type = DU; break;
0243 case LFD: func = lfd; type = D; break;
0244 case LFDU: func = lfd; type = DU; break;
0245 case STFS: func = stfs; type = D; break;
0246 case STFSU: func = stfs; type = DU; break;
0247 case STFD: func = stfd; type = D; break;
0248 case STFDU: func = stfd; type = DU; break;
0249
0250 case OP31:
0251 switch ((insn >> 1) & 0x3ff) {
0252 case LFSX: func = lfs; type = XE; break;
0253 case LFSUX: func = lfs; type = XEU; break;
0254 case LFDX: func = lfd; type = XE; break;
0255 case LFDUX: func = lfd; type = XEU; break;
0256 case STFSX: func = stfs; type = XE; break;
0257 case STFSUX: func = stfs; type = XEU; break;
0258 case STFDX: func = stfd; type = XE; break;
0259 case STFDUX: func = stfd; type = XEU; break;
0260 case STFIWX: func = stfiwx; type = XE; break;
0261 default:
0262 goto illegal;
0263 }
0264 break;
0265
0266 case OP59:
0267 switch ((insn >> 1) & 0x1f) {
0268 case FDIVS: func = fdivs; type = AB; break;
0269 case FSUBS: func = fsubs; type = AB; break;
0270 case FADDS: func = fadds; type = AB; break;
0271 case FSQRTS: func = fsqrts; type = XB; break;
0272 case FRES: func = fres; type = XB; break;
0273 case FMULS: func = fmuls; type = AC; break;
0274 case FRSQRTES: func = frsqrtes;type = XB; break;
0275 case FMSUBS: func = fmsubs; type = ABC; break;
0276 case FMADDS: func = fmadds; type = ABC; break;
0277 case FNMSUBS: func = fnmsubs; type = ABC; break;
0278 case FNMADDS: func = fnmadds; type = ABC; break;
0279 default:
0280 goto illegal;
0281 }
0282 break;
0283
0284 case OP63:
0285 if (insn & 0x20) {
0286 switch ((insn >> 1) & 0x1f) {
0287 case FDIV: func = fdiv; type = AB; break;
0288 case FSUB: func = fsub; type = AB; break;
0289 case FADD: func = fadd; type = AB; break;
0290 case FSQRT: func = fsqrt; type = XB; break;
0291 case FRE: func = fre; type = XB; break;
0292 case FSEL: func = fsel; type = ABC; break;
0293 case FMUL: func = fmul; type = AC; break;
0294 case FRSQRTE: func = frsqrte; type = XB; break;
0295 case FMSUB: func = fmsub; type = ABC; break;
0296 case FMADD: func = fmadd; type = ABC; break;
0297 case FNMSUB: func = fnmsub; type = ABC; break;
0298 case FNMADD: func = fnmadd; type = ABC; break;
0299 default:
0300 goto illegal;
0301 }
0302 break;
0303 }
0304
0305 switch ((insn >> 1) & 0x3ff) {
0306 case FCMPU: func = fcmpu; type = XCR; break;
0307 case FRSP: func = frsp; type = XB; break;
0308 case FCTIW: func = fctiw; type = XB; break;
0309 case FCTIWZ: func = fctiwz; type = XB; break;
0310 case FCMPO: func = fcmpo; type = XCR; break;
0311 case MTFSB1: func = mtfsb1; type = XCRB; break;
0312 case FNEG: func = fneg; type = XB; break;
0313 case MCRFS: func = mcrfs; type = XCRL; break;
0314 case MTFSB0: func = mtfsb0; type = XCRB; break;
0315 case FMR: func = fmr; type = XB; break;
0316 case MTFSFI: func = mtfsfi; type = XCRI; break;
0317 case FNABS: func = fnabs; type = XB; break;
0318 case FABS: func = fabs; type = XB; break;
0319 case MFFS: func = mffs; type = X; break;
0320 case MTFSF: func = mtfsf; type = XFLB; break;
0321 default:
0322 goto illegal;
0323 }
0324 break;
0325
0326 default:
0327 goto illegal;
0328 }
0329
0330 switch (type) {
0331 case AB:
0332 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0333 op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f);
0334 op2 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f);
0335 break;
0336
0337 case AC:
0338 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0339 op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f);
0340 op2 = (void *)¤t->thread.TS_FPR((insn >> 6) & 0x1f);
0341 break;
0342
0343 case ABC:
0344 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0345 op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f);
0346 op2 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f);
0347 op3 = (void *)¤t->thread.TS_FPR((insn >> 6) & 0x1f);
0348 break;
0349
0350 case D:
0351 idx = (insn >> 16) & 0x1f;
0352 sdisp = (insn & 0xffff);
0353 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0354 op1 = (void *)((idx ? regs->gpr[idx] : 0) + sdisp);
0355 break;
0356
0357 case DU:
0358 idx = (insn >> 16) & 0x1f;
0359 if (!idx)
0360 goto illegal;
0361
0362 sdisp = (insn & 0xffff);
0363 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0364 op1 = (void *)(regs->gpr[idx] + sdisp);
0365 break;
0366
0367 case X:
0368 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0369 break;
0370
0371 case XA:
0372 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0373 op1 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f);
0374 break;
0375
0376 case XB:
0377 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0378 op1 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f);
0379 break;
0380
0381 case XE:
0382 idx = (insn >> 16) & 0x1f;
0383 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0384 op1 = (void *)((idx ? regs->gpr[idx] : 0)
0385 + regs->gpr[(insn >> 11) & 0x1f]);
0386 break;
0387
0388 case XEU:
0389 idx = (insn >> 16) & 0x1f;
0390 if (!idx)
0391 goto illegal;
0392 op0 = (void *)¤t->thread.TS_FPR((insn >> 21) & 0x1f);
0393 op1 = (void *)(regs->gpr[idx]
0394 + regs->gpr[(insn >> 11) & 0x1f]);
0395 break;
0396
0397 case XCR:
0398 op0 = (void *)®s->ccr;
0399 op1 = (void *)((insn >> 23) & 0x7);
0400 op2 = (void *)¤t->thread.TS_FPR((insn >> 16) & 0x1f);
0401 op3 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f);
0402 break;
0403
0404 case XCRL:
0405 op0 = (void *)®s->ccr;
0406 op1 = (void *)((insn >> 23) & 0x7);
0407 op2 = (void *)((insn >> 18) & 0x7);
0408 break;
0409
0410 case XCRB:
0411 op0 = (void *)((insn >> 21) & 0x1f);
0412 break;
0413
0414 case XCRI:
0415 op0 = (void *)((insn >> 23) & 0x7);
0416 op1 = (void *)((insn >> 12) & 0xf);
0417 break;
0418
0419 case XFLB:
0420 op0 = (void *)((insn >> 17) & 0xff);
0421 op1 = (void *)¤t->thread.TS_FPR((insn >> 11) & 0x1f);
0422 break;
0423
0424 default:
0425 goto illegal;
0426 }
0427
0428
0429
0430
0431
0432
0433 flush_fp_to_thread(current);
0434
0435 eflag = func(op0, op1, op2, op3);
0436
0437 if (insn & 1) {
0438 regs->ccr &= ~(0x0f000000);
0439 regs->ccr |= (__FPU_FPSCR >> 4) & 0x0f000000;
0440 }
0441
0442 trap = record_exception(regs, eflag);
0443 if (trap)
0444 return 1;
0445
0446 switch (type) {
0447 case DU:
0448 case XEU:
0449 regs->gpr[idx] = (unsigned long)op1;
0450 break;
0451
0452 default:
0453 break;
0454 }
0455
0456 regs_add_return_ip(regs, 4);
0457 return 0;
0458
0459 illegal:
0460 return -ENOSYS;
0461 }