]> Pileus Git - ~andy/linux/blobdiff - arch/mips/math-emu/cp1emu.c
Merge tag 'fixes-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/arm...
[~andy/linux] / arch / mips / math-emu / cp1emu.c
index efe008846ed056759dd2e66c83a54cfe2d4d789c..0b4e2e38294bf174132fcb4036cc958a370cfbec 100644 (file)
@@ -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;
        }
 
@@ -1508,10 +1538,10 @@ static int fpux_emu(struct pt_regs *xcp, struct mips_fpu_struct *ctx,
                break;
        }
 
-       case 0x7:               /* 7 */
-               if (MIPSInst_FUNC(ir) != pfetch_op) {
+       case 0x3:
+               if (MIPSInst_FUNC(ir) != pfetch_op)
                        return SIGILL;
-               }
+
                /* ignore prefx operation */
                break;