[PATCH 1/2] target/arm: Implement SME2 support in gdbstub

Peter Maydell posted 2 patches 4 weeks, 1 day ago
Maintainers: Peter Maydell <peter.maydell@linaro.org>
There is a newer version of this series
[PATCH 1/2] target/arm: Implement SME2 support in gdbstub
Posted by Peter Maydell 4 weeks, 1 day ago
For SME2, we need to expose the new ZT0 register in the gdbstub XML.
gdb documents that the requirements are:

> The ‘org.gnu.gdb.aarch64.sme2’ feature is optional.  If present,
> then the ‘org.gnu.gdb.aarch64.sme’ feature must also be present.
> The ‘org.gnu.gdb.aarch64.sme2’ feature should contain the
> following:
>
>    - ZT0 is a register of 512 bits (64 bytes).  It is defined as a
>      vector of bytes.

Implement this.

Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
---
 target/arm/cpu.h       |  1 +
 target/arm/internals.h |  3 ++
 target/arm/gdbstub.c   |  7 ++++
 target/arm/gdbstub64.c | 76 ++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 87 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index bf221e6f973..912f7a87e42 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -939,6 +939,7 @@ struct ArchCPU {
     DynamicGDBFeatureInfo dyn_sysreg_feature;
     DynamicGDBFeatureInfo dyn_svereg_feature;
     DynamicGDBFeatureInfo dyn_smereg_feature;
+    DynamicGDBFeatureInfo dyn_sme2reg_feature;
     DynamicGDBFeatureInfo dyn_m_systemreg_feature;
     DynamicGDBFeatureInfo dyn_m_secextreg_feature;
 
diff --git a/target/arm/internals.h b/target/arm/internals.h
index f539bbe58e1..c41c1f224a5 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1715,10 +1715,13 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env)
 
 GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cpu, int base_reg);
 GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cpu, int base_reg);
+GDBFeature *arm_gen_dynamic_sme2reg_feature(CPUState *cpu, int base_reg);
 int aarch64_gdb_get_sve_reg(CPUState *cs, GByteArray *buf, int reg);
 int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg);
 int aarch64_gdb_get_sme_reg(CPUState *cs, GByteArray *buf, int reg);
 int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg);
+int aarch64_gdb_get_sme2_reg(CPUState *cs, GByteArray *buf, int reg);
+int aarch64_gdb_set_sme2_reg(CPUState *cs, uint8_t *buf, int reg);
 int aarch64_gdb_get_fpu_reg(CPUState *cs, GByteArray *buf, int reg);
 int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg);
 int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg);
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index 8d2229f5192..7cac2a5965e 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -554,6 +554,13 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
                 arm_gen_dynamic_smereg_feature(cs, cs->gdb_num_regs);
             gdb_register_coprocessor(cs, aarch64_gdb_get_sme_reg,
                                      aarch64_gdb_set_sme_reg, sme_feature, 0);
+            if (isar_feature_aa64_sme2(&cpu->isar)) {
+                GDBFeature *sme2_feature =
+                    arm_gen_dynamic_sme2reg_feature(cs, cs->gdb_num_regs);
+                gdb_register_coprocessor(cs, aarch64_gdb_get_sme2_reg,
+                                         aarch64_gdb_set_sme2_reg,
+                                         sme2_feature, 0);
+            }
         }
         /*
          * Note that we report pauth information via the feature name
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 65d6bbe65fb..7f7d706324e 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -335,6 +335,58 @@ int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
     return 0;
 }
 
+int aarch64_gdb_get_sme2_reg(CPUState *cs, GByteArray *buf, int reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    int len = 0;
+
+    switch (reg) {
+    case 0: /* ZT0 */
+        for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i+= 2) {
+            len += gdb_get_reg128(buf, env->za_state.zt0[i + 1],
+                                  env->za_state.zt0[i]);
+        }
+        return len;
+    default:
+        /* gdbstub asked for something out of range */
+        qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
+        break;
+    }
+
+    return 0;
+}
+
+int aarch64_gdb_set_sme2_reg(CPUState *cs, uint8_t *buf, int reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    int len = 0;
+
+    switch (reg) {
+    case 0: /* ZT0 */
+        for (int i = 0; i < ARRAY_SIZE(env->za_state.zt0); i += 2) {
+            if (target_big_endian()) {
+                env->za_state.zt0[i + 1] = ldq_p(buf);
+                buf += 8;
+                env->za_state.zt0[i] = ldq_p(buf);
+            } else {
+                env->za_state.zt0[i] = ldq_p(buf);
+                buf += 8;
+                env->za_state.zt0[i + 1] = ldq_p(buf);
+            }
+            buf += 8;
+            len += 16;
+        }
+        return len;
+    default:
+        /* gdbstub asked for something out of range */
+        break;
+    }
+
+    return 0;
+}
+
 int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
 {
     ARMCPU *cpu = ARM_CPU(cs);
@@ -534,6 +586,30 @@ GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cs, int base_reg)
     return &cpu->dyn_smereg_feature.desc;
 }
 
+GDBFeature *arm_gen_dynamic_sme2reg_feature(CPUState *cs, int base_reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    GDBFeatureBuilder builder;
+    int reg = 0;
+
+    gdb_feature_builder_init(&builder, &cpu->dyn_sme2reg_feature.desc,
+                             "org.gnu.gdb.aarch64.sme2", "sme2-registers.xml",
+                             base_reg);
+
+
+    /* Create the sme2_bv vector type (a 64 byte vector) */
+    gdb_feature_builder_append_tag(
+        &builder, "<vector id=\"sme2_bv\" type=\"uint8\" count=\"64\"/>");
+
+    /* Define the ZT0 register */
+    gdb_feature_builder_append_reg(&builder, "zt0", 64 * 8, reg++,
+                                   "sme2_bv", NULL);
+
+    gdb_feature_builder_end(&builder);
+
+    return &cpu->dyn_sme2reg_feature.desc;
+}
+
 #ifdef CONFIG_USER_ONLY
 int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
 {
-- 
2.43.0


Re: [PATCH 1/2] target/arm: Implement SME2 support in gdbstub
Posted by Richard Henderson 4 weeks ago
On 10/16/25 05:21, Peter Maydell wrote:
> For SME2, we need to expose the new ZT0 register in the gdbstub XML.
> gdb documents that the requirements are:
> 
>> The ‘org.gnu.gdb.aarch64.sme2’ feature is optional.  If present,
>> then the ‘org.gnu.gdb.aarch64.sme’ feature must also be present.
>> The ‘org.gnu.gdb.aarch64.sme2’ feature should contain the
>> following:
>>
>>     - ZT0 is a register of 512 bits (64 bytes).  It is defined as a
>>       vector of bytes.
> 
> Implement this.
> 
> Signed-off-by: Peter Maydell <peter.maydell@linaro.org>

The size of ZT0 is fixed at 512 bits.
There's no need for the xml to be dynamically generated.


r~

Re: [PATCH 1/2] target/arm: Implement SME2 support in gdbstub
Posted by Peter Maydell 4 weeks ago
On Thu, 16 Oct 2025 at 22:17, Richard Henderson
<richard.henderson@linaro.org> wrote:
>
> On 10/16/25 05:21, Peter Maydell wrote:
> > For SME2, we need to expose the new ZT0 register in the gdbstub XML.
> > gdb documents that the requirements are:
> >
> >> The ‘org.gnu.gdb.aarch64.sme2’ feature is optional.  If present,
> >> then the ‘org.gnu.gdb.aarch64.sme’ feature must also be present.
> >> The ‘org.gnu.gdb.aarch64.sme2’ feature should contain the
> >> following:
> >>
> >>     - ZT0 is a register of 512 bits (64 bytes).  It is defined as a
> >>       vector of bytes.
> >
> > Implement this.
> >
> > Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
>
> The size of ZT0 is fixed at 512 bits.
> There's no need for the xml to be dynamically generated.

I suppose not. GDB upstream dynamically generates the XML,
though, so there's no upstream XML file for us to use.

-- PMM