diff --git a/linux-user/sh4/signal.c b/linux-user/sh4/signal.c index cc36425c49..00290d6e40 100644 --- a/linux-user/sh4/signal.c +++ b/linux-user/sh4/signal.c @@ -173,7 +173,12 @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc) for (i=0; i<16; i++) { __get_user(regs->fregs[i], &sc->sc_fpregs[i]); } - __get_user(regs->fpscr, &sc->sc_fpscr); + /* Resync the derived float_status state, not just env->fpscr. */ + { + uint32_t fpscr; + __get_user(fpscr, &sc->sc_fpscr); + cpu_load_fpscr(regs, fpscr); + } __get_user(regs->fpul, &sc->sc_fpul); regs->tra = -1; /* disable syscall checks */ diff --git a/target/sh4/cpu.h b/target/sh4/cpu.h index 4b0f3f6d97..3302702376 100644 --- a/target/sh4/cpu.h +++ b/target/sh4/cpu.h @@ -379,4 +379,7 @@ static inline void cpu_write_sr(CPUSH4State *env, uint32_t sr) env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T)); } +/* Set FPSCR and the derived float_status rounding/flush-to-zero state. */ +void cpu_load_fpscr(CPUSH4State *env, uint32_t val); + #endif /* SH4_CPU_H */ diff --git a/target/sh4/op_helper.c b/target/sh4/op_helper.c index 669bc84cb6..cf0f80e4a5 100644 --- a/target/sh4/op_helper.c +++ b/target/sh4/op_helper.c @@ -204,7 +204,7 @@ void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1) } } -void helper_ld_fpscr(CPUSH4State *env, uint32_t val) +void cpu_load_fpscr(CPUSH4State *env, uint32_t val) { env->fpscr = val & FPSCR_MASK; if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) { @@ -215,6 +215,11 @@ void helper_ld_fpscr(CPUSH4State *env, uint32_t val) set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status); } +void helper_ld_fpscr(CPUSH4State *env, uint32_t val) +{ + cpu_load_fpscr(env, val); +} + static void update_fpscr(CPUSH4State *env, uintptr_t retaddr) { int xcpt, cause, enable;