0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043
0044
0045
0046
0047
0048
0049
0050
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065
0066
0067
0068 #include <linux/types.h>
0069 #include <linux/sched.h>
0070 #include <linux/mm.h>
0071 #include <linux/perf_event.h>
0072 #include <linux/uaccess.h>
0073
0074 #include "sfp-util_32.h"
0075 #include <math-emu/soft-fp.h>
0076 #include <math-emu/single.h>
0077 #include <math-emu/double.h>
0078 #include <math-emu/quad.h>
0079
0080 #define FLOATFUNC(x) extern int x(void *,void *,void *)
0081
0082
0083
0084
0085
0086 #define FSQRTQ 0x02b
0087 #define FADDQ 0x043
0088 #define FSUBQ 0x047
0089 #define FMULQ 0x04b
0090 #define FDIVQ 0x04f
0091 #define FDMULQ 0x06e
0092 #define FQTOS 0x0c7
0093 #define FQTOD 0x0cb
0094 #define FITOQ 0x0cc
0095 #define FSTOQ 0x0cd
0096 #define FDTOQ 0x0ce
0097 #define FQTOI 0x0d3
0098 #define FCMPQ 0x053
0099 #define FCMPEQ 0x057
0100
0101 #define FSQRTS 0x029
0102 #define FSQRTD 0x02a
0103 #define FADDS 0x041
0104 #define FADDD 0x042
0105 #define FSUBS 0x045
0106 #define FSUBD 0x046
0107 #define FMULS 0x049
0108 #define FMULD 0x04a
0109 #define FDIVS 0x04d
0110 #define FDIVD 0x04e
0111 #define FSMULD 0x069
0112 #define FDTOS 0x0c6
0113 #define FSTOD 0x0c9
0114 #define FSTOI 0x0d1
0115 #define FDTOI 0x0d2
0116 #define FABSS 0x009
0117 #define FCMPS 0x051
0118 #define FCMPES 0x055
0119 #define FCMPD 0x052
0120 #define FCMPED 0x056
0121 #define FMOVS 0x001
0122 #define FNEGS 0x005
0123 #define FITOS 0x0c4
0124 #define FITOD 0x0c8
0125
0126 #define FSR_TEM_SHIFT 23UL
0127 #define FSR_TEM_MASK (0x1fUL << FSR_TEM_SHIFT)
0128 #define FSR_AEXC_SHIFT 5UL
0129 #define FSR_AEXC_MASK (0x1fUL << FSR_AEXC_SHIFT)
0130 #define FSR_CEXC_SHIFT 0UL
0131 #define FSR_CEXC_MASK (0x1fUL << FSR_CEXC_SHIFT)
0132
0133 static int do_one_mathemu(u32 insn, unsigned long *fsr, unsigned long *fregs);
0134
0135
0136
0137
0138
0139
0140
0141
0142
0143
0144 int do_mathemu(struct pt_regs *regs, struct task_struct *fpt)
0145 {
0146
0147
0148
0149
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164 int i;
0165 int retcode = 0;
0166 unsigned long insn;
0167
0168 perf_sw_event(PERF_COUNT_SW_EMULATION_FAULTS, 1, regs, 0);
0169
0170 #ifdef DEBUG_MATHEMU
0171 printk("In do_mathemu()... pc is %08lx\n", regs->pc);
0172 printk("fpqdepth is %ld\n", fpt->thread.fpqdepth);
0173 for (i = 0; i < fpt->thread.fpqdepth; i++)
0174 printk("%d: %08lx at %08lx\n", i, fpt->thread.fpqueue[i].insn,
0175 (unsigned long)fpt->thread.fpqueue[i].insn_addr);
0176 #endif
0177
0178 if (fpt->thread.fpqdepth == 0) {
0179 #ifdef DEBUG_MATHEMU
0180 printk("precise trap at %08lx\n", regs->pc);
0181 #endif
0182 if (!get_user(insn, (u32 __user *) regs->pc)) {
0183 retcode = do_one_mathemu(insn, &fpt->thread.fsr, fpt->thread.float_regs);
0184 if (retcode) {
0185
0186 regs->pc = regs->npc;
0187 regs->npc += 4;
0188 }
0189 }
0190 return retcode;
0191 }
0192
0193
0194 for (i = 0; i < fpt->thread.fpqdepth; i++) {
0195 retcode = do_one_mathemu(fpt->thread.fpqueue[i].insn, &(fpt->thread.fsr), fpt->thread.float_regs);
0196 if (!retcode)
0197 break;
0198 }
0199
0200 if (retcode)
0201 fpt->thread.fsr &= ~(0x3000 | FSR_CEXC_MASK);
0202 else
0203 fpt->thread.fsr &= ~0x3000;
0204 fpt->thread.fpqdepth = 0;
0205
0206 return retcode;
0207 }
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 static inline int record_exception(unsigned long *pfsr, int eflag)
0218 {
0219 unsigned long fsr = *pfsr;
0220 int would_trap;
0221
0222
0223 would_trap = (fsr & ((long)eflag << FSR_TEM_SHIFT)) != 0UL;
0224
0225
0226 if (would_trap != 0) {
0227 eflag &= ((fsr & FSR_TEM_MASK) >> FSR_TEM_SHIFT);
0228 if ((eflag & (eflag - 1)) != 0) {
0229 if (eflag & FP_EX_INVALID)
0230 eflag = FP_EX_INVALID;
0231 else if (eflag & FP_EX_OVERFLOW)
0232 eflag = FP_EX_OVERFLOW;
0233 else if (eflag & FP_EX_UNDERFLOW)
0234 eflag = FP_EX_UNDERFLOW;
0235 else if (eflag & FP_EX_DIVZERO)
0236 eflag = FP_EX_DIVZERO;
0237 else if (eflag & FP_EX_INEXACT)
0238 eflag = FP_EX_INEXACT;
0239 }
0240 }
0241
0242
0243
0244
0245
0246
0247
0248 fsr &= ~(FSR_CEXC_MASK);
0249 fsr |= ((long)eflag << FSR_CEXC_SHIFT);
0250
0251
0252
0253
0254
0255
0256
0257 if (would_trap == 0)
0258 fsr |= ((long)eflag << FSR_AEXC_SHIFT);
0259
0260
0261 if (would_trap != 0)
0262 fsr |= (1UL << 14);
0263
0264 *pfsr = fsr;
0265
0266 return (would_trap ? 0 : 1);
0267 }
0268
0269 typedef union {
0270 u32 s;
0271 u64 d;
0272 u64 q[2];
0273 } *argp;
0274
0275 static int do_one_mathemu(u32 insn, unsigned long *pfsr, unsigned long *fregs)
0276 {
0277
0278 int type = 0;
0279
0280
0281
0282 #define TYPE(dummy, r, ru, b, bu, a, au) type = (au << 2) | (a << 0) | (bu << 5) | (b << 3) | (ru << 8) | (r << 6)
0283 int freg;
0284 argp rs1 = NULL, rs2 = NULL, rd = NULL;
0285 FP_DECL_EX;
0286 FP_DECL_S(SA); FP_DECL_S(SB); FP_DECL_S(SR);
0287 FP_DECL_D(DA); FP_DECL_D(DB); FP_DECL_D(DR);
0288 FP_DECL_Q(QA); FP_DECL_Q(QB); FP_DECL_Q(QR);
0289 int IR;
0290 long fsr;
0291
0292 #ifdef DEBUG_MATHEMU
0293 printk("In do_mathemu(), emulating %08lx\n", insn);
0294 #endif
0295
0296 if ((insn & 0xc1f80000) == 0x81a00000) {
0297 switch ((insn >> 5) & 0x1ff) {
0298 case FSQRTQ: TYPE(3,3,1,3,1,0,0); break;
0299 case FADDQ:
0300 case FSUBQ:
0301 case FMULQ:
0302 case FDIVQ: TYPE(3,3,1,3,1,3,1); break;
0303 case FDMULQ: TYPE(3,3,1,2,1,2,1); break;
0304 case FQTOS: TYPE(3,1,1,3,1,0,0); break;
0305 case FQTOD: TYPE(3,2,1,3,1,0,0); break;
0306 case FITOQ: TYPE(3,3,1,1,0,0,0); break;
0307 case FSTOQ: TYPE(3,3,1,1,1,0,0); break;
0308 case FDTOQ: TYPE(3,3,1,2,1,0,0); break;
0309 case FQTOI: TYPE(3,1,0,3,1,0,0); break;
0310 case FSQRTS: TYPE(2,1,1,1,1,0,0); break;
0311 case FSQRTD: TYPE(2,2,1,2,1,0,0); break;
0312 case FADDD:
0313 case FSUBD:
0314 case FMULD:
0315 case FDIVD: TYPE(2,2,1,2,1,2,1); break;
0316 case FADDS:
0317 case FSUBS:
0318 case FMULS:
0319 case FDIVS: TYPE(2,1,1,1,1,1,1); break;
0320 case FSMULD: TYPE(2,2,1,1,1,1,1); break;
0321 case FDTOS: TYPE(2,1,1,2,1,0,0); break;
0322 case FSTOD: TYPE(2,2,1,1,1,0,0); break;
0323 case FSTOI: TYPE(2,1,0,1,1,0,0); break;
0324 case FDTOI: TYPE(2,1,0,2,1,0,0); break;
0325 case FITOS: TYPE(2,1,1,1,0,0,0); break;
0326 case FITOD: TYPE(2,2,1,1,0,0,0); break;
0327 case FMOVS:
0328 case FABSS:
0329 case FNEGS: TYPE(2,1,0,1,0,0,0); break;
0330 }
0331 } else if ((insn & 0xc1f80000) == 0x81a80000) {
0332 switch ((insn >> 5) & 0x1ff) {
0333 case FCMPS: TYPE(3,0,0,1,1,1,1); break;
0334 case FCMPES: TYPE(3,0,0,1,1,1,1); break;
0335 case FCMPD: TYPE(3,0,0,2,1,2,1); break;
0336 case FCMPED: TYPE(3,0,0,2,1,2,1); break;
0337 case FCMPQ: TYPE(3,0,0,3,1,3,1); break;
0338 case FCMPEQ: TYPE(3,0,0,3,1,3,1); break;
0339 }
0340 }
0341
0342 if (!type) {
0343 #ifdef DEBUG_MATHEMU
0344 printk("attempt to emulate unrecognised FPop!\n");
0345 #endif
0346 return 0;
0347 }
0348
0349
0350 freg = (*pfsr >> 14) & 0xf;
0351
0352 *pfsr &= ~0x1c000;
0353
0354 freg = ((insn >> 14) & 0x1f);
0355 switch (type & 0x3) {
0356 case 3:
0357 if (freg & 3) {
0358
0359 *pfsr |= (6 << 14);
0360 return 0;
0361 }
0362 fallthrough;
0363 case 2:
0364 if (freg & 1) {
0365 *pfsr |= (6 << 14);
0366 return 0;
0367 }
0368 }
0369 rs1 = (argp)&fregs[freg];
0370 switch (type & 0x7) {
0371 case 7: FP_UNPACK_QP (QA, rs1); break;
0372 case 6: FP_UNPACK_DP (DA, rs1); break;
0373 case 5: FP_UNPACK_SP (SA, rs1); break;
0374 }
0375 freg = (insn & 0x1f);
0376 switch ((type >> 3) & 0x3) {
0377 case 3:
0378 if (freg & 3) {
0379
0380 *pfsr |= (6 << 14);
0381 return 0;
0382 }
0383 fallthrough;
0384 case 2:
0385 if (freg & 1) {
0386 *pfsr |= (6 << 14);
0387 return 0;
0388 }
0389 }
0390 rs2 = (argp)&fregs[freg];
0391 switch ((type >> 3) & 0x7) {
0392 case 7: FP_UNPACK_QP (QB, rs2); break;
0393 case 6: FP_UNPACK_DP (DB, rs2); break;
0394 case 5: FP_UNPACK_SP (SB, rs2); break;
0395 }
0396 freg = ((insn >> 25) & 0x1f);
0397 switch ((type >> 6) & 0x3) {
0398 case 0:
0399 if (freg) {
0400
0401 *pfsr |= (6 << 14);
0402 return 0;
0403 }
0404 break;
0405 case 3:
0406 if (freg & 3) {
0407
0408 *pfsr |= (6 << 14);
0409 return 0;
0410 }
0411 fallthrough;
0412 case 2:
0413 if (freg & 1) {
0414 *pfsr |= (6 << 14);
0415 return 0;
0416 }
0417 fallthrough;
0418 case 1:
0419 rd = (void *)&fregs[freg];
0420 break;
0421 }
0422 #ifdef DEBUG_MATHEMU
0423 printk("executing insn...\n");
0424 #endif
0425
0426 switch ((insn >> 5) & 0x1ff) {
0427
0428 case FADDS: FP_ADD_S (SR, SA, SB); break;
0429 case FADDD: FP_ADD_D (DR, DA, DB); break;
0430 case FADDQ: FP_ADD_Q (QR, QA, QB); break;
0431
0432 case FSUBS: FP_SUB_S (SR, SA, SB); break;
0433 case FSUBD: FP_SUB_D (DR, DA, DB); break;
0434 case FSUBQ: FP_SUB_Q (QR, QA, QB); break;
0435
0436 case FMULS: FP_MUL_S (SR, SA, SB); break;
0437 case FSMULD: FP_CONV (D, S, 2, 1, DA, SA);
0438 FP_CONV (D, S, 2, 1, DB, SB);
0439 case FMULD: FP_MUL_D (DR, DA, DB); break;
0440 case FDMULQ: FP_CONV (Q, D, 4, 2, QA, DA);
0441 FP_CONV (Q, D, 4, 2, QB, DB);
0442 case FMULQ: FP_MUL_Q (QR, QA, QB); break;
0443
0444 case FDIVS: FP_DIV_S (SR, SA, SB); break;
0445 case FDIVD: FP_DIV_D (DR, DA, DB); break;
0446 case FDIVQ: FP_DIV_Q (QR, QA, QB); break;
0447
0448 case FSQRTS: FP_SQRT_S (SR, SB); break;
0449 case FSQRTD: FP_SQRT_D (DR, DB); break;
0450 case FSQRTQ: FP_SQRT_Q (QR, QB); break;
0451
0452 case FMOVS: rd->s = rs2->s; break;
0453 case FABSS: rd->s = rs2->s & 0x7fffffff; break;
0454 case FNEGS: rd->s = rs2->s ^ 0x80000000; break;
0455
0456 case FSTOI: FP_TO_INT_S (IR, SB, 32, 1); break;
0457 case FDTOI: FP_TO_INT_D (IR, DB, 32, 1); break;
0458 case FQTOI: FP_TO_INT_Q (IR, QB, 32, 1); break;
0459
0460 case FITOS: IR = rs2->s; FP_FROM_INT_S (SR, IR, 32, int); break;
0461 case FITOD: IR = rs2->s; FP_FROM_INT_D (DR, IR, 32, int); break;
0462 case FITOQ: IR = rs2->s; FP_FROM_INT_Q (QR, IR, 32, int); break;
0463
0464 case FSTOD: FP_CONV (D, S, 2, 1, DR, SB); break;
0465 case FSTOQ: FP_CONV (Q, S, 4, 1, QR, SB); break;
0466 case FDTOQ: FP_CONV (Q, D, 4, 2, QR, DB); break;
0467 case FDTOS: FP_CONV (S, D, 1, 2, SR, DB); break;
0468 case FQTOS: FP_CONV (S, Q, 1, 4, SR, QB); break;
0469 case FQTOD: FP_CONV (D, Q, 2, 4, DR, QB); break;
0470
0471 case FCMPS:
0472 case FCMPES:
0473 FP_CMP_S(IR, SB, SA, 3);
0474 if (IR == 3 &&
0475 (((insn >> 5) & 0x1ff) == FCMPES ||
0476 FP_ISSIGNAN_S(SA) ||
0477 FP_ISSIGNAN_S(SB)))
0478 FP_SET_EXCEPTION (FP_EX_INVALID);
0479 break;
0480 case FCMPD:
0481 case FCMPED:
0482 FP_CMP_D(IR, DB, DA, 3);
0483 if (IR == 3 &&
0484 (((insn >> 5) & 0x1ff) == FCMPED ||
0485 FP_ISSIGNAN_D(DA) ||
0486 FP_ISSIGNAN_D(DB)))
0487 FP_SET_EXCEPTION (FP_EX_INVALID);
0488 break;
0489 case FCMPQ:
0490 case FCMPEQ:
0491 FP_CMP_Q(IR, QB, QA, 3);
0492 if (IR == 3 &&
0493 (((insn >> 5) & 0x1ff) == FCMPEQ ||
0494 FP_ISSIGNAN_Q(QA) ||
0495 FP_ISSIGNAN_Q(QB)))
0496 FP_SET_EXCEPTION (FP_EX_INVALID);
0497 }
0498 if (!FP_INHIBIT_RESULTS) {
0499 switch ((type >> 6) & 0x7) {
0500 case 0: fsr = *pfsr;
0501 if (IR == -1) IR = 2;
0502
0503 fsr &= ~0xc00; fsr |= (IR << 10);
0504 *pfsr = fsr;
0505 break;
0506 case 1: rd->s = IR; break;
0507 case 5: FP_PACK_SP (rd, SR); break;
0508 case 6: FP_PACK_DP (rd, DR); break;
0509 case 7: FP_PACK_QP (rd, QR); break;
0510 }
0511 }
0512 if (_fex == 0)
0513 return 1;
0514 return record_exception(pfsr, _fex);
0515 }