diff options
Diffstat (limited to 'arch/mips/math-emu/cp1emu.c')
-rw-r--r-- | arch/mips/math-emu/cp1emu.c | 42 |
1 files changed, 36 insertions, 6 deletions
diff --git a/arch/mips/math-emu/cp1emu.c b/arch/mips/math-emu/cp1emu.c index efe008846ed0..506925b2c3f3 100644 --- a/arch/mips/math-emu/cp1emu.c +++ b/arch/mips/math-emu/cp1emu.c @@ -417,14 +417,20 @@ static int microMIPS32_to_MIPS32(union mips_instruction *insn_ptr) case mm_mtc1_op: case mm_cfc1_op: case mm_ctc1_op: + case mm_mfhc1_op: + case mm_mthc1_op: if (insn.mm_fp1_format.op == mm_mfc1_op) op = mfc_op; else if (insn.mm_fp1_format.op == mm_mtc1_op) op = mtc_op; else if (insn.mm_fp1_format.op == mm_cfc1_op) op = cfc_op; - else + else if (insn.mm_fp1_format.op == mm_ctc1_op) op = ctc_op; + else if (insn.mm_fp1_format.op == mm_mfhc1_op) + op = mfhc_op; + else + op = mthc_op; mips32_insn.fp1_format.opcode = cop1_op; mips32_insn.fp1_format.op = op; mips32_insn.fp1_format.rt = @@ -853,20 +859,20 @@ static int isBranchInstr(struct pt_regs *regs, struct mm_decoded_insn dec_insn, * In the Linux kernel, we support selection of FPR format on the * basis of the Status.FR bit. If an FPU is not present, the FR bit * is hardwired to zero, which would imply a 32-bit FPU even for - * 64-bit CPUs so we rather look at TIF_32BIT_REGS. + * 64-bit CPUs so we rather look at TIF_32BIT_FPREGS. * FPU emu is slow and bulky and optimizing this function offers fairly * sizeable benefits so we try to be clever and make this function return * a constant whenever possible, that is on 64-bit kernels without O32 - * compatibility enabled and on 32-bit kernels. + * compatibility enabled and on 32-bit without 64-bit FPU support. */ static inline int cop1_64bit(struct pt_regs *xcp) { #if defined(CONFIG_64BIT) && !defined(CONFIG_MIPS32_O32) return 1; -#elif defined(CONFIG_64BIT) && defined(CONFIG_MIPS32_O32) - return !test_thread_flag(TIF_32BIT_REGS); -#else +#elif defined(CONFIG_32BIT) && !defined(CONFIG_MIPS_O32_FP64_SUPPORT) return 0; +#else + return !test_thread_flag(TIF_32BIT_FPREGS); #endif } @@ -878,6 +884,10 @@ static inline int cop1_64bit(struct pt_regs *xcp) ctx->fpr[x & ~1] >> 32 << 32 | (u32)(si) : \ ctx->fpr[x & ~1] << 32 >> 32 | (u64)(si) << 32) +#define SIFROMHREG(si, x) ((si) = (int)(ctx->fpr[x] >> 32)) +#define SITOHREG(si, x) (ctx->fpr[x] = \ + ctx->fpr[x] << 32 >> 32 | (u64)(si) << 32) + #define DIFROMREG(di, x) ((di) = ctx->fpr[x & ~(cop1_64bit(xcp) == 0)]) #define DITOREG(di, x) (ctx->fpr[x & ~(cop1_64bit(xcp) == 0)] = (di)) @@ -1055,6 +1065,25 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, break; #endif + case mfhc_op: + if (!cpu_has_mips_r2) + goto sigill; + + /* copregister rd -> gpr[rt] */ + if (MIPSInst_RT(ir) != 0) { + SIFROMHREG(xcp->regs[MIPSInst_RT(ir)], + MIPSInst_RD(ir)); + } + break; + + case mthc_op: + if (!cpu_has_mips_r2) + goto sigill; + + /* copregister rd <- gpr[rt] */ + SITOHREG(xcp->regs[MIPSInst_RT(ir)], MIPSInst_RD(ir)); + break; + case mfc_op: /* copregister rd -> gpr[rt] */ if (MIPSInst_RT(ir) != 0) { @@ -1263,6 +1292,7 @@ static int cop1Emulate(struct pt_regs *xcp, struct mips_fpu_struct *ctx, #endif default: +sigill: return SIGILL; } |