···551551552552 preempt_disable();553553554554+#ifdef CONFIG_PREEMPT555555+ if (!is_fpu_owner()) {556556+ /* We might lose fpu before disabling preempt... */557557+ own_fpu();558558+ BUG_ON(!used_math());559559+ restore_fp(current);560560+ }561561+#endif554562 /*555563 * Unimplemented operation exception. If we've got the full556564 * software emulator on-board, let's use it...···570562 * a bit extreme for what should be an infrequent event.571563 */572564 save_fp(current);565565+ /* Ensure 'resume' not overwrite saved fp context again. */566566+ lose_fpu();567567+568568+ preempt_enable();573569574570 /* Run the emulator */575571 sig = fpu_emulator_cop1Handler (0, regs,576572 ¤t->thread.fpu.soft);577573574574+ preempt_disable();575575+576576+ own_fpu(); /* Using the FPU again. */578577 /*579578 * We can't allow the emulated instruction to leave any of580579 * the cause bit set in $fcr31.···727712 set_used_math();728713 }729714715715+ preempt_enable();716716+730717 if (!cpu_has_fpu) {731718 int sig = fpu_emulator_cop1Handler(0, regs,732719 ¤t->thread.fpu.soft);733720 if (sig)734721 force_sig(sig, current);735722 }736736-737737- preempt_enable();738723739724 return;740725
+27-14
arch/mips/math-emu/cp1emu.c
···79798080/* Convert Mips rounding mode (0..3) to IEEE library modes. */8181static const unsigned char ieee_rm[4] = {8282- IEEE754_RN, IEEE754_RZ, IEEE754_RU, IEEE754_RD8282+ [FPU_CSR_RN] = IEEE754_RN,8383+ [FPU_CSR_RZ] = IEEE754_RZ,8484+ [FPU_CSR_RU] = IEEE754_RU,8585+ [FPU_CSR_RD] = IEEE754_RD,8686+};8787+/* Convert IEEE library modes to Mips rounding mode (0..3). */8888+static const unsigned char mips_rm[4] = {8989+ [IEEE754_RN] = FPU_CSR_RN,9090+ [IEEE754_RZ] = FPU_CSR_RZ,9191+ [IEEE754_RD] = FPU_CSR_RD,9292+ [IEEE754_RU] = FPU_CSR_RU,8393};84948595#if __mips >= 4···378368 }379369 if (MIPSInst_RD(ir) == FPCREG_CSR) {380370 value = ctx->fcr31;371371+ value = (value & ~0x3) | mips_rm[value & 0x3];381372#ifdef CSRTRACE382373 printk("%p gpr[%d]<-csr=%08x\n",383374 (void *) (xcp->cp0_epc),···411400 (void *) (xcp->cp0_epc),412401 MIPSInst_RT(ir), value);413402#endif414414- ctx->fcr31 = value;415415- /* copy new rounding mode and416416- flush bit to ieee library state! */417417- ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0;418418- ieee754_csr.rm = ieee_rm[value & 0x3];403403+ value &= (FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);404404+ ctx->fcr31 &= ~(FPU_CSR_FLUSH | FPU_CSR_ALL_E | FPU_CSR_ALL_S | 0x03);405405+ /* convert to ieee library modes */406406+ ctx->fcr31 |= (value & ~0x3) | ieee_rm[value & 0x3];419407 }420408 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {421409 return SIGFPE;···580570static ieee754##p fpemu_##p##_##name (ieee754##p r, ieee754##p s, \581571 ieee754##p t) \582572{ \583583- struct ieee754_csr ieee754_csr_save; \573573+ struct _ieee754_csr ieee754_csr_save; \584574 s = f1 (s, t); \585575 ieee754_csr_save = ieee754_csr; \586576 s = f2 (s, r); \···709699 rcsr |= FPU_CSR_INV_X | FPU_CSR_INV_S;710700711701 ctx->fcr31 = (ctx->fcr31 & ~FPU_CSR_ALL_X) | rcsr;712712- if (ieee754_csr.nod)713713- ctx->fcr31 |= 0x1000000;714702 if ((ctx->fcr31 >> 5) & ctx->fcr31 & FPU_CSR_ALL_E) {715703 /*printk ("SIGFPE: fpu csr = %08x\n",716704 ctx->fcr31); */···13051297 if (insn == 0)13061298 xcp->cp0_epc += 4; /* skip nops */13071299 else {13081308- /* Update ieee754_csr. Only relevant if we have a13091309- h/w FPU */13101310- ieee754_csr.nod = (ctx->fcr31 & 0x1000000) != 0;13111311- ieee754_csr.rm = ieee_rm[ctx->fcr31 & 0x3];13121312- ieee754_csr.cx = (ctx->fcr31 >> 12) & 0x1f;13001300+ /*13011301+ * The 'ieee754_csr' is an alias of13021302+ * ctx->fcr31. No need to copy ctx->fcr31 to13031303+ * ieee754_csr. But ieee754_csr.rm is ieee13041304+ * library modes. (not mips rounding mode)13051305+ */13061306+ /* convert to ieee library modes */13071307+ ieee754_csr.rm = ieee_rm[ieee754_csr.rm];13131308 sig = cop1Emulate(xcp, ctx);13091309+ /* revert to mips rounding mode */13101310+ ieee754_csr.rm = mips_rm[ieee754_csr.rm];13141311 }1315131213161313 if (cpu_has_fpu)