diff options
-rw-r--r-- | arch/mips/include/asm/cpu-features.h | 11 | ||||
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 204 | ||||
-rw-r--r-- | arch/mips/math-emu/ieee754.c | 11 |
3 files changed, 144 insertions, 82 deletions
diff --git a/arch/mips/include/asm/cpu-features.h b/arch/mips/include/asm/cpu-features.h index f56cc97..f75dd70 100644 --- a/arch/mips/include/asm/cpu-features.h +++ b/arch/mips/include/asm/cpu-features.h @@ -183,6 +183,17 @@ /* * Shortcuts ... */ +#define cpu_has_mips_2_3_4_5 (cpu_has_mips_2 | cpu_has_mips_3_4_5) +#define cpu_has_mips_3_4_5 (cpu_has_mips_3 | cpu_has_mips_4_5) +#define cpu_has_mips_4_5 (cpu_has_mips_4 | cpu_has_mips_5) + +#define cpu_has_mips_2_3_4_5_r (cpu_has_mips_2 | cpu_has_mips_3_4_5_r) +#define cpu_has_mips_3_4_5_r (cpu_has_mips_3 | cpu_has_mips_4_5_r) +#define cpu_has_mips_4_5_r (cpu_has_mips_4 | cpu_has_mips_5_r) +#define cpu_has_mips_5_r (cpu_has_mips_5 | cpu_has_mips_r) + +#define cpu_has_mips_4_5_r2 (cpu_has_mips_4_5 | cpu_has_mips_r2) + #define cpu_has_mips32 (cpu_has_mips32r1 | cpu_has_mips32r2) #define cpu_has_mips64 (cpu_has_mips64r1 | cpu_has_mips64r2) #define cpu_has_mips_r1 (cpu_has_mips32r1 | cpu_has_mips64r1) diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index 584e0b8..972a7e2 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -35,6 +35,7 @@ */ #include <linux/sched.h> #include <linux/debugfs.h> +#include <linux/kconfig.h> #include <linux/percpu-defs.h> #include <linux/perf_event.h> @@ -50,22 +51,13 @@ #include "ieee754.h" -/* Strap kernel emulator for full MIPS IV emulation */ - -#ifdef __mips -#undef __mips -#endif -#define __mips 4 - /* Function which emulates a floating point instruction. */ static int fpu_emu(struct pt_regs *, struct mips_fpu_struct *, mips_instruction); -#if __mips >= 4 && __mips != 32 static int fpux_emu(struct pt_regs *, struct mips_fpu_struct *, mips_instruction, void *__user *); -#endif /* Control registers */ @@ -95,7 +87,6 @@ static const unsigned char mips_rm[4] = { [IEEE754_RU] = FPU_CSR_RU, }; -#if __mips >= 4 /* convert condition code register number to csr bit */ static const unsigned int fpucondbit[8] = { FPU_CSR_COND0, @@ -107,7 +98,6 @@ static const unsigned int fpucondbit[8] = { FPU_CSR_COND6, FPU_CSR_COND7 }; -#endif /* (microMIPS) Convert 16-bit register encoding to 32-bit register encoding. */ static const unsigned int reg16to32map[8] = {16, 17, 2, 3, 4, 5, 6, 7}; @@ -860,13 +850,13 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, */ static inline int cop1_64bit(struct pt_regs *xcp) { -#if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) - return 1; -#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) - return 0; -#else + if (config_enabled(CONFIG_64BIT) && !config_enabled(CONFIG_MIPS32_O32)) + return 1; + else if (config_enabled(CONFIG_32BIT) && + !config_enabled(CONFIG_MIPS_O32_FP64_SUPPORT)) + return 0; + return !test_thread_flag(TIF_32BIT_FPREGS); -#endif } #define SIFROMREG(si, x) \ @@ -1070,8 +1060,10 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, case cop1_op: switch (MIPSInst_RS(ir)) { -#if defined(__mips64) case dmfc_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + /* copregister fs -> gpr[rt] */ if (MIPSInst_RT(ir) != 0) { DIFROMREG(xcp->regs[MIPSInst_RT(ir)], @@ -1080,10 +1072,12 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; case dmtc_op: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + /* copregister fs <- rt */ DITOREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); break; -#endif case mfhc_op: if (!cpu_has_mips_r2) @@ -1173,16 +1167,18 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } case bc_op:{ + unsigned int cbit; int likely = 0; if (delay_slot(xcp)) return SIGILL; -#if __mips >= 4 - cond = ctx->fcr31 & fpucondbit[MIPSInst_RT(ir) >> 2]; -#else - cond = ctx->fcr31 & FPU_CSR_COND; -#endif + if (cpu_has_mips_4_5_r) + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; + else + cbit = FPU_CSR_COND; + cond = ctx->fcr31 & cbit; + switch (MIPSInst_RT(ir) & 3) { case bcfl_op: likely = 1; @@ -1235,23 +1231,32 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, switch (MIPSInst_OPCODE(ir)) { case lwc1_op: + goto emul; case swc1_op: -#if (__mips >= 2 || defined(__mips64)) + goto emul; case ldc1_op: case sdc1_op: -#endif + if (cpu_has_mips_2_3_4_5 || + cpu_has_mips64) + goto emul; + + return SIGILL; + goto emul; case cop1_op: -#if __mips >= 4 && __mips != 32 - case cop1x_op: -#endif - /* its one of ours */ goto emul; -#if __mips >= 4 + case cop1x_op: + if (cpu_has_mips_4_5 || cpu_has_mips64) + /* its one of ours */ + goto emul; + + return SIGILL; case spec_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (MIPSInst_FUNC(ir) == movc_op) goto emul; break; -#endif } /* @@ -1291,17 +1296,22 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } break; -#if __mips >= 4 && __mips != 32 case cop1x_op:{ - int sig = fpux_emu(xcp, ctx, ir, fault_addr); + int sig; + + if (!cpu_has_mips_4_5 && !cpu_has_mips64) + return SIGILL; + + sig = fpux_emu(xcp, ctx, ir, fault_addr); if (sig) return sig; break; } -#endif -#if __mips >= 4 case spec_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (MIPSInst_FUNC(ir) != movc_op) return SIGILL; cond = fpucondbit[MIPSInst_RT(ir) >> 2]; @@ -1309,8 +1319,6 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, xcp->regs[MIPSInst_RD(ir)] = xcp->regs[MIPSInst_RS(ir)]; break; -#endif - default: sigill: return SIGILL; @@ -1339,8 +1347,6 @@ static const unsigned char cmptab[8] = { }; -#if __mips >= 4 && __mips != 32 - /* * Additional MIPS4 instructions */ @@ -1571,7 +1577,6 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, return 0; } -#endif @@ -1588,9 +1593,7 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, union ieee754dp d; union ieee754sp s; int w; -#ifdef __mips64 s64 l; -#endif } rv; /* resulting value */ MIPS_FPU_EMU_INC_STATS(cp1ops); @@ -1617,21 +1620,34 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto scopbop; /* unary ops */ -#if __mips >= 2 || defined(__mips64) case fsqrt_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + handler.u = ieee754sp_sqrt; goto scopuop; -#endif -#if __mips >= 4 && __mips != 32 + /* + * Note that on some MIPS IV implementations such as the + * R5000 and R8000 the FSQRT and FRECIP instructions do not + * achieve full IEEE-754 accuracy - however this emulator does. + */ case frsqrt_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_sp_rsqrt; goto scopuop; case frecip_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_sp_recip; goto scopuop; -#endif -#if __mips >= 4 + case fmovc_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) @@ -1639,16 +1655,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, SPFROMREG(rv.s, MIPSInst_FS(ir)); break; case fmovz_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] != 0) return 0; SPFROMREG(rv.s, MIPSInst_FS(ir)); break; case fmovn_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] == 0) return 0; SPFROMREG(rv.s, MIPSInst_FS(ir)); break; -#endif case fabs_op: handler.u = ieee754sp_abs; goto scopuop; @@ -1712,7 +1733,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto copcsr; } -#if __mips >= 2 || defined(__mips64) case fround_op: case ftrunc_op: case fceil_op: @@ -1720,6 +1740,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, unsigned int oldrm = ieee754_csr.rm; union ieee754sp fs; + if (!cpu_has_mips_2_3_4_5 && !cpu_has_mips64) + return SIGILL; + SPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; rv.w = ieee754sp_tint(fs); @@ -1727,12 +1750,13 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rfmt = w_fmt; goto copcsr; } -#endif /* __mips >= 2 */ -#if defined(__mips64) case fcvtl_op:{ union ieee754sp fs; + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + SPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754sp_tlong(fs); rfmt = l_fmt; @@ -1746,6 +1770,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, unsigned int oldrm = ieee754_csr.rm; union ieee754sp fs; + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + SPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; rv.l = ieee754sp_tlong(fs); @@ -1753,7 +1780,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rfmt = l_fmt; goto copcsr; } -#endif /* defined(__mips64) */ default: if (MIPSInst_FUNC(ir) >= fcmp_op) { @@ -1802,21 +1828,33 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto dcopbop; /* unary ops */ -#if __mips >= 2 || defined(__mips64) case fsqrt_op: + if (!cpu_has_mips_2_3_4_5_r) + return SIGILL; + handler.u = ieee754dp_sqrt; goto dcopuop; -#endif -#if __mips >= 4 && __mips != 32 + /* + * Note that on some MIPS IV implementations such as the + * R5000 and R8000 the FSQRT and FRECIP instructions do not + * achieve full IEEE-754 accuracy - however this emulator does. + */ case frsqrt_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_dp_rsqrt; goto dcopuop; case frecip_op: + if (!cpu_has_mips_4_5_r2) + return SIGILL; + handler.u = fpemu_dp_recip; goto dcopuop; -#endif -#if __mips >= 4 case fmovc_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + cond = fpucondbit[MIPSInst_FT(ir) >> 2]; if (((ctx->fcr31 & cond) != 0) != ((MIPSInst_FT(ir) & 1) != 0)) @@ -1824,16 +1862,21 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, DPFROMREG(rv.d, MIPSInst_FS(ir)); break; case fmovz_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] != 0) return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; case fmovn_op: + if (!cpu_has_mips_4_5_r) + return SIGILL; + if (xcp->regs[MIPSInst_FT(ir)] == 0) return 0; DPFROMREG(rv.d, MIPSInst_FS(ir)); break; -#endif case fabs_op: handler.u = ieee754dp_abs; goto dcopuop; @@ -1886,7 +1929,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, goto copcsr; } -#if __mips >= 2 || defined(__mips64) case fround_op: case ftrunc_op: case fceil_op: @@ -1894,6 +1936,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, unsigned int oldrm = ieee754_csr.rm; union ieee754dp fs; + if (!cpu_has_mips_2_3_4_5_r) + return SIGILL; + DPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; rv.w = ieee754dp_tint(fs); @@ -1901,12 +1946,13 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rfmt = w_fmt; goto copcsr; } -#endif -#if defined(__mips64) case fcvtl_op:{ union ieee754dp fs; + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DPFROMREG(fs, MIPSInst_FS(ir)); rv.l = ieee754dp_tlong(fs); rfmt = l_fmt; @@ -1920,6 +1966,9 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, unsigned int oldrm = ieee754_csr.rm; union ieee754dp fs; + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DPFROMREG(fs, MIPSInst_FS(ir)); ieee754_csr.rm = ieee_rm[modeindex(MIPSInst_FUNC(ir))]; rv.l = ieee754dp_tlong(fs); @@ -1927,7 +1976,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, rfmt = l_fmt; goto copcsr; } -#endif /* __mips >= 3 */ default: if (MIPSInst_FUNC(ir) >= fcmp_op) { @@ -1978,9 +2026,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; } -#if defined(__mips64) case l_fmt:{ u64 bits; + + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DIFROMREG(bits, MIPSInst_FS(ir)); switch (MIPSInst_FUNC(ir)) { @@ -1999,7 +2050,6 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, } break; } -#endif default: return SIGILL; @@ -2022,18 +2072,19 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, * Now we can safely write the result back to the register file. */ switch (rfmt) { - case -1:{ -#if __mips >= 4 - cond = fpucondbit[MIPSInst_FD(ir) >> 2]; -#else - cond = FPU_CSR_COND; -#endif + unsigned int cbit; + case -1: + + if (cpu_has_mips_4_5_r) + cbit = fpucondbit[MIPSInst_RT(ir) >> 2]; + else + cbit = FPU_CSR_COND; if (rv.w) - ctx->fcr31 |= cond; + ctx->fcr31 |= cbit; else - ctx->fcr31 &= ~cond; + ctx->fcr31 &= ~cbit; break; - } + case d_fmt: DPTOREG(rv.d, MIPSInst_FD(ir)); break; @@ -2043,11 +2094,12 @@ static int fpu_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx, case w_fmt: SITOREG(rv.w, MIPSInst_FD(ir)); break; -#if defined(__mips64) case l_fmt: + if (!cpu_has_mips_3_4_5 && !cpu_has_mips64) + return SIGILL; + DITOREG(rv.l, MIPSInst_FD(ir)); break; -#endif default: return SIGILL; } diff --git a/arch/mips/math-emu/ieee754.c b/arch/mips/math-emu/ieee754.c index 26f785e..68c2996 100644 --- a/arch/mips/math-emu/ieee754.c +++ b/arch/mips/math-emu/ieee754.c @@ -45,15 +45,14 @@ /* special constants */ - -#if (defined(BYTE_ORDER) && BYTE_ORDER == LITTLE_ENDIAN) || defined(__MIPSEL__) -#define SPSTR(s, b, m) {m, b, s} -#define DPSTR(s, b, mh, ml) {ml, mh, b, s} -#endif - #ifdef __MIPSEB__ #define SPSTR(s, b, m) {s, b, m} #define DPSTR(s, b, mh, ml) {s, b, mh, ml} +#elif defined(__MIPSEL__) +#define SPSTR(s, b, m) {m, b, s} +#define DPSTR(s, b, mh, ml) {ml, mh, b, s} +#else /* !defined (__MIPSEB__) && !defined (__MIPSEL__) */ +#error "MIPS but neither __MIPSEB__ nor __MIPSEL__?" #endif const struct ieee754dp_const __ieee754dp_spcvals[] = { |