Commit 8952556536 for qemu.org

commit 8952556536461af0b2fb398438275e19485943dc
Author: Peter Maydell <peter.maydell@linaro.org>
Date:   Wed Feb 18 18:40:14 2026 +0000

    target/arm: Don't squash all ID_AA64ZFR0_EL1 fields for non-SVE

    The ID register ID_AA64ZFR0_EL1's fields are not all for SVE
    exclusive features; some are also used to describe SME on an
    SME-only CPU:

    SVE-only fields:
     * F64MM, F32MM, F16MM, SM4, B16B16, SVEVer

    Fields used for SVE and SME (in some cases there is also a
    field for SME in ID_AA64SMFR0_EL1, but it is just a "present
    or absent" single bit flag and the ZFR0 field then tells you
    what level of support is present):
     * I8MM, SHA3, BF16, BitPerm, EltPerm, AES

    Currently we zero the whole ID_AA64ZFR0_EL1 register in
    arm_cpu_sve_finalize() if SVE is not present, which wipes also the
    fields we need for SME.  Only clear the fields which are SVE-specific
    here, and clear the rest in arm_cpu_sme_finalize() if we
    have neither SME nor SVE.

    This requires us to update our ID_AA64ZFR0 field definitions
    to match the rev M.a.a Arm ARM, as the F16MM SVE-only field
    is not one we had a definition for previously.

    Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
    Reviewed-by: Richard Henderson <richard.henderson@linaro.org>
    Message-id: 20260202133353.2231685-14-peter.maydell@linaro.org

diff --git a/target/arm/cpu-features.h b/target/arm/cpu-features.h
index 83db3fd950..b683c9551a 100644
--- a/target/arm/cpu-features.h
+++ b/target/arm/cpu-features.h
@@ -368,12 +368,14 @@ FIELD(ID_AA64DFR0, HPMN0, 60, 4)

 FIELD(ID_AA64ZFR0, SVEVER, 0, 4)
 FIELD(ID_AA64ZFR0, AES, 4, 4)
+FIELD(ID_AA64ZFR0, ELTPERM, 12, 4)
 FIELD(ID_AA64ZFR0, BITPERM, 16, 4)
 FIELD(ID_AA64ZFR0, BFLOAT16, 20, 4)
 FIELD(ID_AA64ZFR0, B16B16, 24, 4)
 FIELD(ID_AA64ZFR0, SHA3, 32, 4)
 FIELD(ID_AA64ZFR0, SM4, 40, 4)
 FIELD(ID_AA64ZFR0, I8MM, 44, 4)
+FIELD(ID_AA64ZFR0, F16MM, 48, 4)
 FIELD(ID_AA64ZFR0, F32MM, 52, 4)
 FIELD(ID_AA64ZFR0, F64MM, 56, 4)

diff --git a/target/arm/cpu64.c b/target/arm/cpu64.c
index 4d316f5a71..b2be8c9fba 100644
--- a/target/arm/cpu64.c
+++ b/target/arm/cpu64.c
@@ -136,9 +136,17 @@ void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp)
         if (!cpu_isar_feature(aa64_sve, cpu)) {
             /*
              * SVE is disabled and so are all vector lengths.  Good.
-             * Disable all SVE extensions as well.
+             * Disable all SVE extensions as well. Note that some ZFR0
+             * fields are used also by SME so must not be wiped in
+             * an SME-no-SVE config. We will clear the rest in
+             * arm_cpu_sme_finalize() if necessary.
              */
-            SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, F64MM, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, F32MM, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, F16MM, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, SM4, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, B16B16, 0);
+            FIELD_DP64_IDREG(&cpu->isar, ID_AA64ZFR0, SVEVER, 0);
             return;
         }

@@ -338,6 +346,10 @@ void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp)
     if (vq_map == 0) {
         if (!cpu_isar_feature(aa64_sme, cpu)) {
             SET_IDREG(&cpu->isar, ID_AA64SMFR0, 0);
+            if (!cpu_isar_feature(aa64_sve, cpu)) {
+                /* This clears the "SVE or SME" fields in ZFR0 */
+                SET_IDREG(&cpu->isar, ID_AA64ZFR0, 0);
+            }
             return;
         }