@samitouri / QOSamiQemu / commits / a740f17ed0

linux-user/sh4: restore FP rounding mode on sigreturn

The SH4 FPSCR rounding-mode (RM) and denormal (DN) bits are not held only in env->fpscr: they are also reflected into the derived env->fp_status via set_float_rounding_mode()/set_flush_to_zero(). The guest keeps the two in sync by routing every write to FPSCR through helper_ld_fpscr(). restore_sigcontext() wrote the saved value straight into env->fpscr and never touched env->fp_status, so on sigreturn the interrupted code resumed with whatever FP rounding mode and flush-to-zero setting the signal handler last installed. (regs->flags = 0 forces the FR/SZ/PR TB flags to be recomputed, but fp_status is runtime float state, not a TB flag, so it was left stale.) This is the FP analogue of the T/M/Q bit problem just fixed for the integer status register. Factor the FPSCR -> fp_status synchronisation out of helper_ld_fpscr() into cpu_load_fpscr() and use it from restore_sigcontext() so the rounding mode round-trips correctly across signal delivery. Fixes: c3b5bc8ab3 ("SH4: Signal handling for the user space emulator, by Magnus Damm.") Cc: qemu-stable@nongnu.org Reviewed-by: Yoshinori Sato <yoshinori.sato@nifty.com> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Signed-off-by: Matt Turner <mattst88@gmail.com> Signed-off-by: Helge Deller <deller@gmx.de>

Matt Turner committed May 25, 2026 at 11:26 UTC a740f17ed0fbc5cd38e3cb12136c58d38aba098d
3 files changed +15 -2
linux-user/sh4/signal.c
+6 -1
@@ -173,7 +173,12 @@ static void restore_sigcontext(CPUSH4State *regs, struct target_sigcontext *sc)
173 for (i=0; i<16; i++) {
174 __get_user(regs->fregs[i], &sc->sc_fpregs[i]);
175 }
176 - __get_user(regs->fpscr, &sc->sc_fpscr);
176 + /* Resync the derived float_status state, not just env->fpscr. */
177 + {
178 + uint32_t fpscr;
179 + __get_user(fpscr, &sc->sc_fpscr);
180 + cpu_load_fpscr(regs, fpscr);
181 + }
182 __get_user(regs->fpul, &sc->sc_fpul);
183
184 regs->tra = -1; /* disable syscall checks */
target/sh4/cpu.h
+3
@@ -379,4 +379,7 @@ static inline void cpu_write_sr(CPUSH4State *env, uint32_t sr)
379 env->sr = sr & ~((1u << SR_M) | (1u << SR_Q) | (1u << SR_T));
380 }
381
382 +/* Set FPSCR and the derived float_status rounding/flush-to-zero state. */
383 +void cpu_load_fpscr(CPUSH4State *env, uint32_t val);
384 +
385 #endif /* SH4_CPU_H */
target/sh4/op_helper.c
+6 -1
@@ -204,7 +204,7 @@ void helper_macw(CPUSH4State *env, int32_t arg0, int32_t arg1)
204 }
205 }
206
207 -void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
207 +void cpu_load_fpscr(CPUSH4State *env, uint32_t val)
208 {
209 env->fpscr = val & FPSCR_MASK;
210 if ((val & FPSCR_RM_MASK) == FPSCR_RM_ZERO) {
@@ -215,6 +215,11 @@ void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
215 set_flush_to_zero((val & FPSCR_DN) != 0, &env->fp_status);
216 }
217
218 +void helper_ld_fpscr(CPUSH4State *env, uint32_t val)
219 +{
220 + cpu_load_fpscr(env, val);
221 +}
222 +
223 static void update_fpscr(CPUSH4State *env, uintptr_t retaddr)
224 {
225 int xcpt, cause, enable;