mirror of https://github.com/xemu-project/xemu.git
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;
|
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)
|
static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
||||||
{
|
{
|
||||||
uint32_t i;
|
uint32_t i;
|
||||||
|
@ -99,15 +73,14 @@ static uint32_t vfp_get_fpsr_from_host(CPUARMState *env)
|
||||||
return vfp_exceptbits_from_host(i);
|
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
|
* Clear out all the exception-flag information in the float_status
|
||||||
* only need to preserve the current state in one of our
|
* values. The caller should have arranged for env->vfp.fpsr to
|
||||||
* float_status values.
|
* be the architecturally up-to-date exception flag information first.
|
||||||
*/
|
*/
|
||||||
int i = vfp_exceptbits_to_host(val);
|
set_float_exception_flags(0, &env->vfp.fp_status);
|
||||||
set_float_exception_flags(i, &env->vfp.fp_status);
|
|
||||||
set_float_exception_flags(0, &env->vfp.fp_status_f16);
|
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);
|
||||||
set_float_exception_flags(0, &env->vfp.standard_fp_status_f16);
|
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;
|
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);
|
ARMCPU *cpu = env_archcpu(env);
|
||||||
|
|
||||||
vfp_set_fpsr_to_host(env, val);
|
|
||||||
|
|
||||||
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
if (arm_feature(env, ARM_FEATURE_NEON) ||
|
||||||
cpu_isar_feature(aa32_mve, cpu)) {
|
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:
|
* NZCV lives only in env->vfp.fpsr. The cumulative exception flags
|
||||||
* the exception flags IOC|DZC|OFC|UFC|IXC|IDC are stored in
|
* IOC|DZC|OFC|UFC|IXC|IDC also live in env->vfp.fpsr, with possible
|
||||||
* fp_status, and QC is in vfp.qc[]. Store the NZCV bits there,
|
* extra pending exception information that hasn't yet been folded in
|
||||||
* and zero any of the other FPSR bits.
|
* 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;
|
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)
|
static void vfp_set_fpcr_masked(CPUARMState *env, uint32_t val, uint32_t mask)
|
||||||
|
|
Loading…
Reference in New Issue