target/arm: Store FPSR cumulative exception bits in env->vfp.fpsr
Currently we store the FPSR cumulative exception bits in the float_status fields, and use env->vfp.fpsr only for the NZCV bits. (The QC bit is stored in env->vfp.qc[].) This works for TCG, but if QEMU was built without CONFIG_TCG (i.e. with KVM support only) then we use the stub versions of vfp_get_fpsr_from_host() and vfp_set_fpsr_to_host() which do nothing, throwing away the cumulative exception bit state. The effect is that if the FPSR state is round-tripped from KVM to QEMU then we lose the cumulative exception bits. In particular, this will happen if the VM is migrated. There is no user-visible bug when using KVM with a QEMU binary that was built with CONFIG_TCG. Fix this by always storing the cumulative exception bits in env->vfp.fpsr. If we are using TCG then we may also keep pending cumulative exception information in the float_status fields, so we continue to fold that in on reads. This change will also be helpful for implementing FEAT_AFP later, because that includes a feature where in some situations we want to cause input denormals to be flushed to zero without affecting the existing state of the FPSR.IDC bit, so we need a place to store IDC which is distinct from the various float_status fields. (Note for stable backports: the bug goes back to4a15527c9f
but this code was refactored in commits ea8618382aba..a8ab8706d4cc461, so fixing it in branches without those refactorings will mean either backporting the refactor or else implementing a conceptually similar fix for the old code.) Cc: qemu-stable@nongnu.org Fixes:4a15527c9f
("target/arm/vfp_helper: Restrict the SoftFloat use to TCG") Signed-off-by: Peter Maydell <peter.maydell@linaro.org> Reviewed-by: Richard Henderson <richard.henderson@linaro.org> Message-id: 20241011162401.3672735-1-peter.maydell@linaro.org
This commit is contained in:
parent
bda8c24cb5
commit
d9c7adb601
@ -59,32 +59,6 @@ static inline int vfp_exceptbits_from_host(int host_bits)
|
||||
return target_bits;
|
||||
}
|
||||
|
||||
/* Convert vfp exception flags to target form. */
|
||||
static inline int vfp_exceptbits_to_host(int target_bits)
|
||||
{
|
||||
int host_bits = 0;
|
||||
|
||||
if (target_bits & 1) {
|
||||
host_bits |= float_flag_invalid;
|
||||
}
|
||||
if (target_bits & 2) {
|
||||
host_bits |= float_flag_divbyzero;
|
||||
}
|
||||
if (target_bits & 4) {
|
||||
host_bits |= float_flag_overflow;
|
||||
}
|
||||
if (target_bits & 8) {
|
||||
host_bits |= float_flag_underflow;
|
||||
}
|
||||
if (target_bits & 0x10) {
|
||||
host_bits |= float_flag_inexact;
|
||||
}
|
||||
if (target_bits & 0x80) {
|
||||
host_bits |= float_flag_input_denormal;
|
||||
}
|
||||
return host_bits;
|
||||
}
|
||||
|
||||
static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
||||
{
|
||||
uint32_t i;
|
||||
@ -99,15 +73,14 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
||||
return vfp_exceptbits_from_host(i);
|
||||
}
|
||||
|
||||
static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
|
||||
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
|
||||
{
|
||||
/*
|
||||
* The exception flags are ORed together when we read fpscr so we
|
||||
* only need to preserve the current state in one of our
|
||||
* float_status values.
|
||||
* Clear out all the exception-flag information in the float_status
|
||||
* values. The caller should have arranged for env->vfp.fpsr to
|
||||
* be the architecturally up-to-date exception flag information first.
|
||||
*/
|
||||
int i = vfp_exceptbits_to_host(val);
|
||||
set_float_exception_flags(i, &env->vfp.fp_status);
|
||||
set_float_exception_flags(0, &env->vfp.fp_status);
|
||||
set_float_exception_flags(0, &env->vfp.fp_status_f16);
|
||||
set_float_exception_flags(0, &env->vfp.standard_fp_status);
|
||||
set_float_exception_flags(0, &env->vfp.standard_fp_status_f16);
|
||||
@ -164,7 +137,7 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vfp_set_fpsr_to_host(CPUARMState *env, uint32_t val)
|
||||
static void vfp_clear_float_status_exc_flags(CPUARMState *env)
|
||||
{
|
||||
}
|
||||
|
||||
@ -216,8 +189,6 @@ void vfp_set_fpsr(CPUARMState *env, uint32_t val)
|
||||
{
|
||||
ARMCPU *cpu = env_archcpu(env);
|
||||
|
||||
vfp_set_fpsr_to_host(env, val);
|
||||
|
||||
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
||||
cpu_isar_feature(aa32_mve, cpu)) {
|
||||
/*
|
||||
@ -231,13 +202,18 @@ void vfp_set_fpsr(CPUARMState *env, uint32_t val)
|
||||
}
|
||||
|
||||
/*
|
||||
* The only FPSR bits we keep in vfp.fpsr are NZCV:
|
||||
* the exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in
|
||||
* fp_status, and QC is in vfp.qc[]. Store the NZCV bits there,
|
||||
* and zero any of the other FPSR bits.
|
||||
* NZCV lives only in env->vfp.fpsr. The cumulative exception flags
|
||||
* IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
|
||||
* extra pending exception information that hasn't yet been folded in
|
||||
* living in the float_status values (for TCG).
|
||||
* Since this FPSR write gives us the up to date values of the exception
|
||||
* flags, we want to store into vfp.fpsr the NZCV and CEXC bits, zeroing
|
||||
* anything else. We also need to clear out the float_status exception
|
||||
* information so that the next vfp_get_fpsr does not fold in stale data.
|
||||
*/
|
||||
val &= FPSR_NZCV_MASK;
|
||||
val &= FPSR_NZCV_MASK | FPSR_CEXC_MASK;
|
||||
env->vfp.fpsr = val;
|
||||
vfp_clear_float_status_exc_flags(env);
|
||||
}
|
||||
|
||||
static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||
|
Loading…
Reference in New Issue
Block a user