mirror of
https://github.com/qemu/qemu.git
synced 2026-07-08 17:46:10 +00:00
linux-user/mips: save/restore FCSR across signal delivery
QEMU keeps the MIPS FPU control/status register (FCSR, fcr31) in
env->active_fpu.fcr31. The rounding mode, flush-to-zero (FS), and
NaN-2008 mode bits in fcr31 are reflected into the derived
env->active_fpu.fp_status via set_float_rounding_mode() and friends;
every architectural write to FCSR goes through helper_ctc1() which
calls restore_fp_status() to keep the two in sync.
Both target_sigcontext variants (O32 and N32/N64) have an sc_fpc_csr
field that holds FCSR, but setup_sigcontext() never wrote it and
restore_sigcontext() never read it. As a result:
- The signal frame always delivered sc_fpc_csr == 0 to the handler,
so sigaction(SA_SIGINFO) handlers that inspect the interrupted
context see the wrong FCSR.
- On sigreturn, active_fpu.fcr31 retained whatever value the signal
handler last installed (if any), and active_fpu.fp_status was
never resynced. Interrupted code resumed with the wrong rounding
mode, FS flag, and NaN-2008 semantics.
Fix setup_sigcontext() to save fcr31 into sc_fpc_csr. Fix
restore_sigcontext() to read it back (masked to fcr31_rw_bitmask as
the kernel does) and call cpu_mips_restore_fp_status() to resync
fp_status from the restored fcr31.
Add cpu_mips_restore_fp_status() in target/mips/fpu.c (which already
defines ieee_rm and includes fpu_helper.h), and declare it in cpu.h.
Fixes: 084d0497a0 ("mips-linux-user: Save and restore fpu and dsp from sigcontext")
Cc: qemu-stable@nongnu.org
Signed-off-by: Matt Turner <mattst88@gmail.com>
Signed-off-by: Helge Deller <deller@gmx.de>
This commit is contained in:
committed by
Helge Deller
parent
3f50dd4666
commit
84b920ccb5
@@ -134,6 +134,7 @@ static inline void setup_sigcontext(CPUMIPSState *regs,
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__put_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
|
||||
}
|
||||
__put_user(regs->active_fpu.fcr31, &sc->sc_fpc_csr);
|
||||
}
|
||||
|
||||
static inline void
|
||||
@@ -165,6 +166,12 @@ restore_sigcontext(CPUMIPSState *regs, struct target_sigcontext *sc)
|
||||
for (i = 0; i < 32; ++i) {
|
||||
__get_user(regs->active_fpu.fpr[i].d, &sc->sc_fpregs[i]);
|
||||
}
|
||||
{
|
||||
uint32_t fcr31;
|
||||
__get_user(fcr31, &sc->sc_fpc_csr);
|
||||
regs->active_fpu.fcr31 = fcr31 & regs->active_fpu.fcr31_rw_bitmask;
|
||||
cpu_mips_restore_fp_status(regs);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
|
||||
@@ -1384,6 +1384,9 @@ void cpu_mips_clock_init(MIPSCPU *cpu);
|
||||
/* helper.c */
|
||||
target_ulong exception_resume_pc(CPUMIPSState *env);
|
||||
|
||||
/* fpu.c */
|
||||
void cpu_mips_restore_fp_status(CPUMIPSState *env);
|
||||
|
||||
/**
|
||||
* mips_cpu_create_with_clock:
|
||||
* @typename: a MIPS CPU type.
|
||||
|
||||
@@ -17,6 +17,11 @@ const FloatRoundMode ieee_rm[4] = {
|
||||
float_round_down
|
||||
};
|
||||
|
||||
void cpu_mips_restore_fp_status(CPUMIPSState *env)
|
||||
{
|
||||
restore_fp_status(env);
|
||||
}
|
||||
|
||||
const char fregnames[32][4] = {
|
||||
"f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7",
|
||||
"f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15",
|
||||
|
||||
Reference in New Issue
Block a user