[RFC PATCH 12/13] target/arm: Add SME state to kvm_arch_{get, put}_registers

Richard Henderson posted 13 patches 1 month, 3 weeks ago
Maintainers: "Michael S. Tsirkin" <mst@redhat.com>, Cornelia Huck <cohuck@redhat.com>, Paolo Bonzini <pbonzini@redhat.com>, Peter Maydell <peter.maydell@linaro.org>
[RFC PATCH 12/13] target/arm: Add SME state to kvm_arch_{get, put}_registers
Posted by Richard Henderson 1 month, 3 weeks ago
Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
---
 target/arm/kvm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 102 insertions(+), 2 deletions(-)

diff --git a/target/arm/kvm.c b/target/arm/kvm.c
index d05ad1d7e1..6d849573be 100644
--- a/target/arm/kvm.c
+++ b/target/arm/kvm.c
@@ -43,6 +43,11 @@
 #include "target/arm/gtimer.h"
 #include "migration/blocker.h"
 
+/* ??? This probably belongs in asm-arm64/kvm.h */
+#define KVM_REG_ARM64_SME_ZT0 \
+    (KVM_REG_ARM64 | KVM_REG_ARM64_SME | \
+     KVM_REG_ARM64_SME_ZT_BASE | KVM_REG_SIZE_U512)
+
 const KVMCapabilityInfo kvm_arch_required_capabilities[] = {
     KVM_CAP_INFO(DEVICE_CTRL),
     KVM_CAP_LAST_INFO
@@ -2157,10 +2162,39 @@ static int kvm_arch_put_sve(CPUState *cs, uint32_t vq, bool have_ffr)
     return 0;
 }
 
+static int kvm_arch_put_sme(CPUState *cs, uint32_t svq)
+{
+    CPUARMState *env = cpu_env(cs);
+    ARMCPU *cpu = env_archcpu(env);
+    uint64_t tmp[ARM_MAX_VQ * 2];
+    uint64_t *r;
+    int ret;
+
+    for (int n = 0; n < svq * 16; ++n) {
+        r = sve_bswap64(tmp, &env->za_state.za[n].d[0], svq * 2);
+        ret = kvm_set_one_reg(cs, KVM_REG_ARM64_SME_ZAHREG(n, 0), r);
+        if (ret) {
+            return ret;
+        }
+    }
+
+    if (cpu_isar_feature(aa64_sme2, cpu)) {
+        r = sve_bswap64(tmp, env->za_state.zt0, ARRAY_SIZE(env->za_state.zt0));
+        ret = kvm_set_one_reg(cs, KVM_REG_ARM64_SME_ZT0, r);
+        if (ret) {
+            return ret;
+        }
+    }
+    return 0;
+}
+
 int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
 {
     uint64_t val;
     uint32_t fpr;
+    bool sme_sm = false;
+    bool sme_za = false;
+    uint32_t svq = 0;
     int i, ret;
     unsigned int el;
 
@@ -2239,7 +2273,18 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
         }
     }
 
-    if (cpu_isar_feature(aa64_sve, cpu)) {
+    if (cpu_isar_feature(aa64_sme, cpu)) {
+        /* Current SVL is required for either SM or ZA */
+        sme_sm = FIELD_EX64(env->svcr, SVCR, SM);
+        sme_za = FIELD_EX64(env->svcr, SVCR, ZA);
+        if (sme_sm || sme_za) {
+            svq = sve_vqm1_for_el_sm(env, el, true) + 1;
+        }
+    }
+
+    if (sme_sm) {
+        ret = kvm_arch_put_sve(cs, svq, cpu_isar_feature(aa64_sme_fa64, cpu));
+    } else if (cpu_isar_feature(aa64_sve, cpu)) {
         ret = kvm_arch_put_sve(cs, cpu->sve_max_vq, true);
     } else {
         ret = kvm_arch_put_fpsimd(cs);
@@ -2248,6 +2293,13 @@ int kvm_arch_put_registers(CPUState *cs, KvmPutState level, Error **errp)
         return ret;
     }
 
+    if (sme_za) {
+        ret = kvm_arch_put_sme(cs, svq);
+        if (ret) {
+            return ret;
+        }
+    }
+
     fpr = vfp_get_fpsr(env);
     ret = kvm_set_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpsr), &fpr);
     if (ret) {
@@ -2342,11 +2394,41 @@ static int kvm_arch_get_sve(CPUState *cs, uint32_t vq, bool have_ffr)
     return 0;
 }
 
+static int kvm_arch_get_sme(CPUState *cs, uint32_t svq)
+{
+    CPUARMState *env = cpu_env(cs);
+    ARMCPU *cpu = env_archcpu(env);
+    uint64_t *r;
+    int ret;
+
+    for (int n = 0; n < svq * 16; ++n) {
+        r = &env->za_state.za[n].d[0];
+        ret = kvm_get_one_reg(cs, KVM_REG_ARM64_SME_ZAHREG(n, 0), r);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, svq * 2);
+    }
+
+    if (cpu_isar_feature(aa64_sme2, cpu)) {
+        r = env->za_state.zt0;
+        ret = kvm_get_one_reg(cs, KVM_REG_ARM64_SME_ZT0, r);
+        if (ret) {
+            return ret;
+        }
+        sve_bswap64(r, r, ARRAY_SIZE(env->za_state.zt0));
+    }
+    return 0;
+}
+
 int kvm_arch_get_registers(CPUState *cs, Error **errp)
 {
     uint64_t val;
     unsigned int el;
     uint32_t fpr;
+    bool sme_sm = false;
+    bool sme_za = false;
+    uint32_t svq = 0;
     int i, ret;
 
     ARMCPU *cpu = ARM_CPU(cs);
@@ -2424,7 +2506,18 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
         env->spsr = env->banked_spsr[i];
     }
 
-    if (cpu_isar_feature(aa64_sve, cpu)) {
+    if (cpu_isar_feature(aa64_sme, cpu)) {
+        /* Current SVL is required for either SM or ZA */
+        sme_sm = FIELD_EX64(env->svcr, SVCR, SM);
+        sme_za = FIELD_EX64(env->svcr, SVCR, ZA);
+        if (sme_sm || sme_za) {
+            svq = sve_vqm1_for_el_sm(env, el, true) + 1;
+        }
+    }
+
+    if (sme_sm) {
+        ret = kvm_arch_get_sve(cs, svq, cpu_isar_feature(aa64_sme_fa64, cpu));
+    } else if (cpu_isar_feature(aa64_sve, cpu)) {
         ret = kvm_arch_get_sve(cs, cpu->sve_max_vq, true);
     } else {
         ret = kvm_arch_get_fpsimd(cs);
@@ -2433,6 +2526,13 @@ int kvm_arch_get_registers(CPUState *cs, Error **errp)
         return ret;
     }
 
+    if (sme_za) {
+        ret = kvm_arch_get_sme(cs, svq);
+        if (ret) {
+            return ret;
+        }
+    }
+
     ret = kvm_get_one_reg(cs, AARCH64_SIMD_CTRL_REG(fp_regs.fpsr), &fpr);
     if (ret) {
         return ret;
-- 
2.43.0
Re: [RFC PATCH 12/13] target/arm: Add SME state to kvm_arch_{get, put}_registers
Posted by Peter Maydell 1 month, 2 weeks ago
On Mon, 16 Feb 2026 at 03:46, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> Signed-off-by: Richard Henderson <richard.henderson@linaro.org>
> ---
>  target/arm/kvm.c | 104 ++++++++++++++++++++++++++++++++++++++++++++++-
>  1 file changed, 102 insertions(+), 2 deletions(-)

The (currently proposed) KVM ABI imposes some not-necessarily-obvious
restrictions on what order it is OK to write various things in (e.g.
SMCR.SM and other things affecting vector length need to be
put before the vectors themselves). We should have a comment
explaining this so we don't accidentally refactor and
break the ordering requirements later.

thanks
-- PMM