Currently smcr_write() implicitly assumes that SME implies SVE, because it will call sve_vqm1_sve_for_el() when SMCR.SM is 0, and sve_vqm1_sve_for_el() will assert in that situation.
This is the only place where we call that function without it being guarded by a check on whether SVE is implemented. Adjust smcr_write() so that it also avoids asking for the SVE vector length when SVE is not implemented. Signed-off-by: Peter Maydell <[email protected]> --- I did think about making sve_vqm1_sve_for_el() return some value rather than asserting, but (a) what would be the right value? and (b) this was the only place that needed fixing. --- target/arm/helper.c | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/target/arm/helper.c b/target/arm/helper.c index dce648b482..a3dd84a2d6 100644 --- a/target/arm/helper.c +++ b/target/arm/helper.c @@ -4936,12 +4936,12 @@ static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri, uint64_t value) { int cur_el = arm_current_el(env); - int old_len = sve_vqm1_for_el(env, cur_el); + ARMCPU *cpu = env_archcpu(env); + int old_len = cpu_isar_feature(aa64_sve, cpu) ? sve_vqm1_for_el(env, cur_el) : 0; uint64_t valid_mask = R_SMCR_LEN_MASK | R_SMCR_FA64_MASK; - int new_len; QEMU_BUILD_BUG_ON(ARM_MAX_VQ > R_SMCR_LEN_MASK + 1); - if (cpu_isar_feature(aa64_sme2, env_archcpu(env))) { + if (cpu_isar_feature(aa64_sme2, cpu)) { valid_mask |= R_SMCR_EZT0_MASK; } value &= valid_mask; @@ -4953,10 +4953,17 @@ static void smcr_write(CPUARMState *env, const ARMCPRegInfo *ri, * current values for simplicity. But for QEMU internals, we must still * apply the narrower SVL to the Zregs and Pregs -- see the comment * above aarch64_sve_narrow_vq. + * + * If the CPU has only SME and not SVE, then turning streaming mode + * on and off can't ever change the SVL; we must avoid calling + * sve_vqm1_for_el() to ask for the SVE vector length when SM is 0 + * because it will assert. */ - new_len = sve_vqm1_for_el(env, cur_el); - if (new_len < old_len) { - aarch64_sve_narrow_vq(env, new_len + 1); + if (cpu_isar_feature(aa64_sve, cpu)) { + int new_len = sve_vqm1_for_el(env, cur_el); + if (new_len < old_len) { + aarch64_sve_narrow_vq(env, new_len + 1); + } } } -- 2.43.0
