Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 1999  Eddie C. Dost  (ecd@atecom.com)
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 /* The instructions list which may be not implemented by a hardware FPU */
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 /* Optional */
0075 FLOATFUNC(fres);
0076 FLOATFUNC(frsqrte);
0077 FLOATFUNC(fsel);
0078 
0079 
0080 #define OP31        0x1f        /*   31 */
0081 #define LFS     0x30        /*   48 */
0082 #define LFSU        0x31        /*   49 */
0083 #define LFD     0x32        /*   50 */
0084 #define LFDU        0x33        /*   51 */
0085 #define STFS        0x34        /*   52 */
0086 #define STFSU       0x35        /*   53 */
0087 #define STFD        0x36        /*   54 */
0088 #define STFDU       0x37        /*   55 */
0089 #define OP59        0x3b        /*   59 */
0090 #define OP63        0x3f        /*   63 */
0091 
0092 /* Opcode 31: */
0093 /* X-Form: */
0094 #define LFSX        0x217       /*  535 */
0095 #define LFSUX       0x237       /*  567 */
0096 #define LFDX        0x257       /*  599 */
0097 #define LFDUX       0x277       /*  631 */
0098 #define STFSX       0x297       /*  663 */
0099 #define STFSUX      0x2b7       /*  695 */
0100 #define STFDX       0x2d7       /*  727 */
0101 #define STFDUX      0x2f7       /*  759 */
0102 #define STFIWX      0x3d7       /*  983 */
0103 
0104 /* Opcode 59: */
0105 /* A-Form: */
0106 #define FDIVS       0x012       /*   18 */
0107 #define FSUBS       0x014       /*   20 */
0108 #define FADDS       0x015       /*   21 */
0109 #define FSQRTS      0x016       /*   22 */
0110 #define FRES        0x018       /*   24 */
0111 #define FMULS       0x019       /*   25 */
0112 #define FRSQRTES    0x01a       /*   26 */
0113 #define FMSUBS      0x01c       /*   28 */
0114 #define FMADDS      0x01d       /*   29 */
0115 #define FNMSUBS     0x01e       /*   30 */
0116 #define FNMADDS     0x01f       /*   31 */
0117 
0118 /* Opcode 63: */
0119 /* A-Form: */
0120 #define FDIV        0x012       /*   18 */
0121 #define FSUB        0x014       /*   20 */
0122 #define FADD        0x015       /*   21 */
0123 #define FSQRT       0x016       /*   22 */
0124 #define FSEL        0x017       /*   23 */
0125 #define FRE     0x018       /*   24 */
0126 #define FMUL        0x019       /*   25 */
0127 #define FRSQRTE     0x01a       /*   26 */
0128 #define FMSUB       0x01c       /*   28 */
0129 #define FMADD       0x01d       /*   29 */
0130 #define FNMSUB      0x01e       /*   30 */
0131 #define FNMADD      0x01f       /*   31 */
0132 
0133 /* X-Form: */
0134 #define FCMPU       0x000       /*    0 */
0135 #define FRSP        0x00c       /*   12 */
0136 #define FCTIW       0x00e       /*   14 */
0137 #define FCTIWZ      0x00f       /*   15 */
0138 #define FCMPO       0x020       /*   32 */
0139 #define MTFSB1      0x026       /*   38 */
0140 #define FNEG        0x028       /*   40 */
0141 #define MCRFS       0x040       /*   64 */
0142 #define MTFSB0      0x046       /*   70 */
0143 #define FMR     0x048       /*   72 */
0144 #define MTFSFI      0x086       /*  134 */
0145 #define FNABS       0x088       /*  136 */
0146 #define FABS        0x108       /*  264 */
0147 #define MFFS        0x247       /*  583 */
0148 #define MTFSF       0x2c7       /*  711 */
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 //  fpscr &= ~(FPSCR_VX);
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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0333         op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
0334         op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
0335         break;
0336 
0337     case AC:
0338         op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0339         op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
0340         op2 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
0341         break;
0342 
0343     case ABC:
0344         op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0345         op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
0346         op2 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
0347         op3 = (void *)&current->thread.TS_FPR((insn >>  6) & 0x1f);
0348         break;
0349 
0350     case D:
0351         idx = (insn >> 16) & 0x1f;
0352         sdisp = (insn & 0xffff);
0353         op0 = (void *)&current->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 *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0364         op1 = (void *)(regs->gpr[idx] + sdisp);
0365         break;
0366 
0367     case X:
0368         op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0369         break;
0370 
0371     case XA:
0372         op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0373         op1 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
0374         break;
0375 
0376     case XB:
0377         op0 = (void *)&current->thread.TS_FPR((insn >> 21) & 0x1f);
0378         op1 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
0379         break;
0380 
0381     case XE:
0382         idx = (insn >> 16) & 0x1f;
0383         op0 = (void *)&current->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 *)&current->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 *)&regs->ccr;
0399         op1 = (void *)((insn >> 23) & 0x7);
0400         op2 = (void *)&current->thread.TS_FPR((insn >> 16) & 0x1f);
0401         op3 = (void *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
0402         break;
0403 
0404     case XCRL:
0405         op0 = (void *)&regs->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 *)&current->thread.TS_FPR((insn >> 11) & 0x1f);
0422         break;
0423 
0424     default:
0425         goto illegal;
0426     }
0427 
0428     /*
0429      * If we support a HW FPU, we need to ensure the FP state
0430      * is flushed into the thread_struct before attempting
0431      * emulation
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 }