[PATCH] target/arm: Added support for SME register exposure to GDB

Vacha Bhavsar posted 1 patch 7 months ago
Patches applied successfully (tree, apply log)
git fetch https://github.com/patchew-project/qemu tags/patchew/20250708221438.347643-1-vacha.bhavsar@oss.qualcomm.com
Maintainers: Peter Maydell <peter.maydell@linaro.org>
There is a newer version of this series
target/arm/cpu.h       |   1 +
target/arm/gdbstub.c   |   6 +++
target/arm/gdbstub64.c | 119 +++++++++++++++++++++++++++++++++++++++++
target/arm/internals.h |   3 ++
4 files changed, 129 insertions(+)
[PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Vacha Bhavsar 7 months ago
The QEMU GDB stub does not expose the ZA storage SME register to GDB via
the remote serial protocol, which can be a useful functionality to debug SME
code. To provide this functionality in Aarch64 target, this patch registers the
SME register set with the GDB stub. To do so, this patch implements the
aarch64_gdb_get_sme_reg() and aarch64_gdb_set_sme_reg() functions to
specify how to get and set the SME registers, and the
arm_gen_dynamic_smereg_feature() function to generate the target
description in XML format to indicate the target architecture supports SME.
Finally, this patch includes a dyn_smereg_feature structure to hold this
GDB XML description of the SME registers for each CPU.

Signed-off-by: Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com>
---
 target/arm/cpu.h       |   1 +
 target/arm/gdbstub.c   |   6 +++
 target/arm/gdbstub64.c | 119 +++++++++++++++++++++++++++++++++++++++++
 target/arm/internals.h |   3 ++
 4 files changed, 129 insertions(+)

diff --git a/target/arm/cpu.h b/target/arm/cpu.h
index c8cf0ab417..c37ea7dcd2 100644
--- a/target/arm/cpu.h
+++ b/target/arm/cpu.h
@@ -933,6 +933,7 @@ struct ArchCPU {
 
     DynamicGDBFeatureInfo dyn_sysreg_feature;
     DynamicGDBFeatureInfo dyn_svereg_feature;
+    DynamicGDBFeatureInfo dyn_smereg_feature;
     DynamicGDBFeatureInfo dyn_m_systemreg_feature;
     DynamicGDBFeatureInfo dyn_m_secextreg_feature;
 
diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
index ce4497ad7c..9c942c77cc 100644
--- a/target/arm/gdbstub.c
+++ b/target/arm/gdbstub.c
@@ -531,6 +531,12 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu)
             GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs, cs->gdb_num_regs);
             gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
                                      aarch64_gdb_set_sve_reg, feature, 0);
+            if (isar_feature_aa64_sme(&cpu->isar)) {
+                GDBFeature *sme_feature = 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);
+            }
         } else {
             gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
                                      aarch64_gdb_set_fpu_reg,
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 64ee9b3b56..e2fc874b38 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -228,6 +228,88 @@ int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
     return 0;
 }
 
+int aarch64_gdb_get_sme_reg(CPUState *cs, GByteArray *buf, int reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+    bool streaming_mode = ((env->svcr & 0x01) != 0);
+
+    switch (reg) {
+    /* Svg register */
+    case 0:
+    {
+        int vq;
+        if (streaming_mode) {
+            vq = sve_vqm1_for_el_sm(env, arm_current_el(env),
+                     streaming_mode) + 1;
+        } else {
+            vq = 0;
+        }
+        /* svg = vector granules (2 * vector quardwords) in streaming mode */
+        return gdb_get_reg64(buf, vq * 2);
+    }
+    case 1:
+        return gdb_get_reg64(buf, env->svcr);
+    case 2:
+    {
+        int q;
+        int len = 0;
+        int vq = cpu->sve_max_vq;
+        int svl = vq * 16;
+        for (int i = 0; i < svl; i++) {
+            for (q = 0; q < vq; q++) {
+                len += gdb_get_reg128(buf,
+                           env->za_state.za[i].d[q * 2 + 1],
+                           env->za_state.za[i].d[q * 2]);
+            }
+        }
+        return len;
+    }
+    default:
+        /* gdbstub asked for something out our range */
+        qemu_log_mask(LOG_UNIMP, "%s: out of range register %d", __func__, reg);
+        break;
+    }
+
+    return 0;
+}
+
+int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    CPUARMState *env = &cpu->env;
+
+    /* The first 32 registers are the zregs */
+    switch (reg) {
+    /* The first 32 registers are the zregs */
+    case 0:
+    {
+        /* cannot set svg via gdbstub */
+        return 0;
+    }
+    case 1:
+        env->svcr = *buf & 0x03;
+        return 8;
+    case 2:
+        int vq, len = 0;
+        int svl = cpu->sve_max_vq * 16;
+        uint64_t *p = (uint64_t *) buf;
+        for (int i = 0; i < svl; i++) {
+            for (vq = 0; vq < cpu->sve_max_vq; vq++) {
+                env->za_state.za[i].d[vq * 2 + 1] = *p++;
+                env->za_state.za[i].d[vq * 2] = *p++;
+                len += 16;
+            }
+        }
+        return len;
+    default:
+        /* gdbstub asked for something out our range */
+        break;
+    }
+
+    return 0;
+}
+
 int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
 {
     ARMCPU *cpu = ARM_CPU(cs);
@@ -392,6 +474,43 @@ GDBFeature *arm_gen_dynamic_svereg_feature(CPUState *cs, int base_reg)
     return &cpu->dyn_svereg_feature.desc;
 }
 
+GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cs, int base_reg)
+{
+    ARMCPU *cpu = ARM_CPU(cs);
+    int vq = cpu->sve_max_vq;
+    int svl = vq * 16;
+    GDBFeatureBuilder builder;
+    int reg = 0;
+
+    gdb_feature_builder_init(&builder, &cpu->dyn_smereg_feature.desc,
+        "org.gnu.gdb.aarch64.sme", "sme-registers.xml", base_reg);
+
+
+    /* Create the sme_bv vector type. */
+    gdb_feature_builder_append_tag(&builder,
+        "<vector id=\"sme_bv\" type=\"uint8\" count=\"%d\"/>",
+        svl);
+
+    /* Create the sme_bvv vector type. */
+    gdb_feature_builder_append_tag(
+        &builder, "<vector id=\"sme_bvv\" type=\"sme_bv\" count=\"%d\"/>",
+        svl);
+
+    /* Define the svg, svcr, and za registers. */
+
+    /* fpscr & status registers */
+    gdb_feature_builder_append_reg(&builder, "svg", 64, reg++,
+        "int", NULL);
+    gdb_feature_builder_append_reg(&builder, "svcr", 64, reg++,
+        "int", NULL);
+    gdb_feature_builder_append_reg(&builder, "za", svl * svl * 8, reg++,
+        "sme_bvv", NULL);
+
+    gdb_feature_builder_end(&builder);
+
+    return &cpu->dyn_smereg_feature.desc;
+}
+
 #ifdef CONFIG_USER_ONLY
 int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
 {
diff --git a/target/arm/internals.h b/target/arm/internals.h
index 21a8d67edd..af090b9b8e 100644
--- a/target/arm/internals.h
+++ b/target/arm/internals.h
@@ -1808,8 +1808,11 @@ 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);
 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_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);
-- 
2.34.1
Re: [PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Peter Maydell 6 months, 4 weeks ago
On Tue, 8 Jul 2025 at 23:14, Vacha Bhavsar
<vacha.bhavsar@oss.qualcomm.com> wrote:
>
> The QEMU GDB stub does not expose the ZA storage SME register to GDB via
> the remote serial protocol, which can be a useful functionality to debug SME
> code. To provide this functionality in Aarch64 target, this patch registers the
> SME register set with the GDB stub. To do so, this patch implements the
> aarch64_gdb_get_sme_reg() and aarch64_gdb_set_sme_reg() functions to
> specify how to get and set the SME registers, and the
> arm_gen_dynamic_smereg_feature() function to generate the target
> description in XML format to indicate the target architecture supports SME.
> Finally, this patch includes a dyn_smereg_feature structure to hold this
> GDB XML description of the SME registers for each CPU.
>
> Signed-off-by: Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com>



> +int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +
> +    /* The first 32 registers are the zregs */
> +    switch (reg) {
> +    /* The first 32 registers are the zregs */

You don't need the same comment twice, and it also doesn't
look like it makes sense here, because the zregs are
SVE regs, not SME regs.

> +    case 0:
> +    {
> +        /* cannot set svg via gdbstub */
> +        return 0;
> +    }
> +    case 1:
> +        env->svcr = *buf & 0x03;

This will update env->svcr but won't have the correct effects
on the CPU (e.g. zeroing the ZA storage); I think you need to
call aarch64_set_svcr() here. Also you've declared
SVCR in the XML as a 64-bit register, so you should read it out
of the buffer as a 64-bit value, not short-cut by reading just
one byte.

> +        return 8;
> +    case 2:
> +        int vq, len = 0;
> +        int svl = cpu->sve_max_vq * 16;
> +        uint64_t *p = (uint64_t *) buf;

I know this is what the existing SVE code does, but does
this really do the right thing on a big-endian host ?

> +        for (int i = 0; i < svl; i++) {
> +            for (vq = 0; vq < cpu->sve_max_vq; vq++) {
> +                env->za_state.za[i].d[vq * 2 + 1] = *p++;
> +                env->za_state.za[i].d[vq * 2] = *p++;
> +                len += 16;
> +            }
> +        }
> +        return len;
> +    default:
> +        /* gdbstub asked for something out our range */

"out of"

> +        break;
> +    }
> +
> +    return 0;
> +}

(PS: I would consider this close enough to being a bugfix to be
OK with putting it into 10.1 in the first rc cycle or so even
if it misses softfreeze.)

thanks
-- PMM
Re: [PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Vacha Bhavsar 6 months, 4 weeks ago
Hi Peter,

Thank you for the feedback! I have sent over a revised version of this
patch with appropriate changes. I have removed the unnecessary comments
regarding the zregs, and also corrected the typo, "out our" to "out of" in
the comments. Additionally, I have used aarch64_set_svcr to correctly set
the 64 bit value of SVCR.

Regarding your question on whether the code handling the reading of the ZA
storage would work on a big-endian host, I believe it would. I think this
also applies to the pre-existing SVE code as well, based off of what I have
read from this GDB documentation (
https://sourceware.org/gdb/download/onlinedocs/gdb#Packets) which states
the following:

‘P n…=r…’
Write register n… with value r…. The register number n is in hexadecimal,
and r… contains two hex digits for each byte in the register (target byte
order).

From this, I believe the QEMU GDB stub is already expecting the register
content in target byte order, leaving this responsibility to the client.
Based on this, I believe the pre-existing SVE code and my SME code should
correctly work on big-endian hosts.

Looking forward to your feedback!

Thanks,
Vacha

On Mon, Jul 14, 2025 at 6:30 AM Peter Maydell <peter.maydell@linaro.org>
wrote:

> On Tue, 8 Jul 2025 at 23:14, Vacha Bhavsar
> <vacha.bhavsar@oss.qualcomm.com> wrote:
> >
> > The QEMU GDB stub does not expose the ZA storage SME register to GDB via
> > the remote serial protocol, which can be a useful functionality to debug
> SME
> > code. To provide this functionality in Aarch64 target, this patch
> registers the
> > SME register set with the GDB stub. To do so, this patch implements the
> > aarch64_gdb_get_sme_reg() and aarch64_gdb_set_sme_reg() functions to
> > specify how to get and set the SME registers, and the
> > arm_gen_dynamic_smereg_feature() function to generate the target
> > description in XML format to indicate the target architecture supports
> SME.
> > Finally, this patch includes a dyn_smereg_feature structure to hold this
> > GDB XML description of the SME registers for each CPU.
> >
> > Signed-off-by: Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com>
>
>
>
> > +int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
> > +{
> > +    ARMCPU *cpu = ARM_CPU(cs);
> > +    CPUARMState *env = &cpu->env;
> > +
> > +    /* The first 32 registers are the zregs */
> > +    switch (reg) {
> > +    /* The first 32 registers are the zregs */
>
> You don't need the same comment twice, and it also doesn't
> look like it makes sense here, because the zregs are
> SVE regs, not SME regs.
>
> > +    case 0:
> > +    {
> > +        /* cannot set svg via gdbstub */
> > +        return 0;
> > +    }
> > +    case 1:
> > +        env->svcr = *buf & 0x03;
>
> This will update env->svcr but won't have the correct effects
> on the CPU (e.g. zeroing the ZA storage); I think you need to
> call aarch64_set_svcr() here. Also you've declared
> SVCR in the XML as a 64-bit register, so you should read it out
> of the buffer as a 64-bit value, not short-cut by reading just
> one byte.
>
> > +        return 8;
> > +    case 2:
> > +        int vq, len = 0;
> > +        int svl = cpu->sve_max_vq * 16;
> > +        uint64_t *p = (uint64_t *) buf;
>
> I know this is what the existing SVE code does, but does
> this really do the right thing on a big-endian host ?
>
> > +        for (int i = 0; i < svl; i++) {
> > +            for (vq = 0; vq < cpu->sve_max_vq; vq++) {
> > +                env->za_state.za[i].d[vq * 2 + 1] = *p++;
> > +                env->za_state.za[i].d[vq * 2] = *p++;
> > +                len += 16;
> > +            }
> > +        }
> > +        return len;
> > +    default:
> > +        /* gdbstub asked for something out our range */
>
> "out of"
>
> > +        break;
> > +    }
> > +
> > +    return 0;
> > +}
>
> (PS: I would consider this close enough to being a bugfix to be
> OK with putting it into 10.1 in the first rc cycle or so even
> if it misses softfreeze.)
>
> thanks
> -- PMM
>
Re: [PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Peter Maydell 6 months, 4 weeks ago
On Mon, 14 Jul 2025 at 18:44, Vacha Bhavsar
<vacha.bhavsar@oss.qualcomm.com> wrote:
> Regarding your question on whether the code handling the reading of the ZA storage would work on a big-endian host, I believe it would. I think this also applies to the pre-existing SVE code as well, based off of what I have read from this GDB documentation (https://sourceware.org/gdb/download/onlinedocs/gdb#Packets) which states the following:
>
> ‘P n…=r…’
> Write register n… with value r…. The register number n is in hexadecimal, and r… contains two hex digits for each byte in the register (target byte order).
>
> From this, I believe the QEMU GDB stub is already expecting the register content in target byte order, leaving this responsibility to the client. Based on this, I believe the pre-existing SVE code and my SME code should correctly work on big-endian hosts.

"target byte order" from gdb's point of view means "the byte
order of the guest, i.e. arm", which is always little endian.
This is not the same as the order of bytes within a uint64_t
in QEMU's CPU struct, which is host byte order.

-- PMM
Re: [PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Richard Henderson 7 months ago
On 7/8/25 16:14, Vacha Bhavsar wrote:
> +            if (isar_feature_aa64_sme(&cpu->isar)) {

Preferred usage is cpu_isar_feature(aa64_sme, cpu)

Otherwise,
Reviewed-by: Richard Henderson <richard.henderson@linaro.org>

PS: I tried this myself a few weeks ago and got an error from gdb.  I had assumed that gdb 
simply wasn't prepared for the vector-of-vectors type.  I guess I should have investigated 
further -- it may have just been an xml typo.


r~
Re: [PATCH] target/arm: Added support for SME register exposure to GDB
Posted by Vacha Bhavsar 7 months ago
+ richard.henderson@linaro.org

Hi Richard,


I'm an intern working with Joel Jones and he mentioned you've worked quite
a bit on SME on QEMU. We were wondering if you could take a look at this
patch as the deadline for the soft freeze is fast approaching and we'd like
it to make it to the next release.



Thanks,

Vacha

On Tue, Jul 8, 2025 at 6:14 PM Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com>
wrote:

> The QEMU GDB stub does not expose the ZA storage SME register to GDB via
> the remote serial protocol, which can be a useful functionality to debug
> SME
> code. To provide this functionality in Aarch64 target, this patch
> registers the
> SME register set with the GDB stub. To do so, this patch implements the
> aarch64_gdb_get_sme_reg() and aarch64_gdb_set_sme_reg() functions to
> specify how to get and set the SME registers, and the
> arm_gen_dynamic_smereg_feature() function to generate the target
> description in XML format to indicate the target architecture supports SME.
> Finally, this patch includes a dyn_smereg_feature structure to hold this
> GDB XML description of the SME registers for each CPU.
>
> Signed-off-by: Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com>
> ---
>  target/arm/cpu.h       |   1 +
>  target/arm/gdbstub.c   |   6 +++
>  target/arm/gdbstub64.c | 119 +++++++++++++++++++++++++++++++++++++++++
>  target/arm/internals.h |   3 ++
>  4 files changed, 129 insertions(+)
>
> diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> index c8cf0ab417..c37ea7dcd2 100644
> --- a/target/arm/cpu.h
> +++ b/target/arm/cpu.h
> @@ -933,6 +933,7 @@ struct ArchCPU {
>
>      DynamicGDBFeatureInfo dyn_sysreg_feature;
>      DynamicGDBFeatureInfo dyn_svereg_feature;
> +    DynamicGDBFeatureInfo dyn_smereg_feature;
>      DynamicGDBFeatureInfo dyn_m_systemreg_feature;
>      DynamicGDBFeatureInfo dyn_m_secextreg_feature;
>
> diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c
> index ce4497ad7c..9c942c77cc 100644
> --- a/target/arm/gdbstub.c
> +++ b/target/arm/gdbstub.c
> @@ -531,6 +531,12 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU
> *cpu)
>              GDBFeature *feature = arm_gen_dynamic_svereg_feature(cs,
> cs->gdb_num_regs);
>              gdb_register_coprocessor(cs, aarch64_gdb_get_sve_reg,
>                                       aarch64_gdb_set_sve_reg, feature, 0);
> +            if (isar_feature_aa64_sme(&cpu->isar)) {
> +                GDBFeature *sme_feature =
> 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);
> +            }
>          } else {
>              gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
>                                       aarch64_gdb_set_fpu_reg,
> diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
> index 64ee9b3b56..e2fc874b38 100644
> --- a/target/arm/gdbstub64.c
> +++ b/target/arm/gdbstub64.c
> @@ -228,6 +228,88 @@ int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t
> *buf, int reg)
>      return 0;
>  }
>
> +int aarch64_gdb_get_sme_reg(CPUState *cs, GByteArray *buf, int reg)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +    bool streaming_mode = ((env->svcr & 0x01) != 0);
> +
> +    switch (reg) {
> +    /* Svg register */
> +    case 0:
> +    {
> +        int vq;
> +        if (streaming_mode) {
> +            vq = sve_vqm1_for_el_sm(env, arm_current_el(env),
> +                     streaming_mode) + 1;
> +        } else {
> +            vq = 0;
> +        }
> +        /* svg = vector granules (2 * vector quardwords) in streaming
> mode */
> +        return gdb_get_reg64(buf, vq * 2);
> +    }
> +    case 1:
> +        return gdb_get_reg64(buf, env->svcr);
> +    case 2:
> +    {
> +        int q;
> +        int len = 0;
> +        int vq = cpu->sve_max_vq;
> +        int svl = vq * 16;
> +        for (int i = 0; i < svl; i++) {
> +            for (q = 0; q < vq; q++) {
> +                len += gdb_get_reg128(buf,
> +                           env->za_state.za[i].d[q * 2 + 1],
> +                           env->za_state.za[i].d[q * 2]);
> +            }
> +        }
> +        return len;
> +    }
> +    default:
> +        /* gdbstub asked for something out our range */
> +        qemu_log_mask(LOG_UNIMP, "%s: out of range register %d",
> __func__, reg);
> +        break;
> +    }
> +
> +    return 0;
> +}
> +
> +int aarch64_gdb_set_sme_reg(CPUState *cs, uint8_t *buf, int reg)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    CPUARMState *env = &cpu->env;
> +
> +    /* The first 32 registers are the zregs */
> +    switch (reg) {
> +    /* The first 32 registers are the zregs */
> +    case 0:
> +    {
> +        /* cannot set svg via gdbstub */
> +        return 0;
> +    }
> +    case 1:
> +        env->svcr = *buf & 0x03;
> +        return 8;
> +    case 2:
> +        int vq, len = 0;
> +        int svl = cpu->sve_max_vq * 16;
> +        uint64_t *p = (uint64_t *) buf;
> +        for (int i = 0; i < svl; i++) {
> +            for (vq = 0; vq < cpu->sve_max_vq; vq++) {
> +                env->za_state.za[i].d[vq * 2 + 1] = *p++;
> +                env->za_state.za[i].d[vq * 2] = *p++;
> +                len += 16;
> +            }
> +        }
> +        return len;
> +    default:
> +        /* gdbstub asked for something out our range */
> +        break;
> +    }
> +
> +    return 0;
> +}
> +
>  int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg)
>  {
>      ARMCPU *cpu = ARM_CPU(cs);
> @@ -392,6 +474,43 @@ GDBFeature *arm_gen_dynamic_svereg_feature(CPUState
> *cs, int base_reg)
>      return &cpu->dyn_svereg_feature.desc;
>  }
>
> +GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cs, int base_reg)
> +{
> +    ARMCPU *cpu = ARM_CPU(cs);
> +    int vq = cpu->sve_max_vq;
> +    int svl = vq * 16;
> +    GDBFeatureBuilder builder;
> +    int reg = 0;
> +
> +    gdb_feature_builder_init(&builder, &cpu->dyn_smereg_feature.desc,
> +        "org.gnu.gdb.aarch64.sme", "sme-registers.xml", base_reg);
> +
> +
> +    /* Create the sme_bv vector type. */
> +    gdb_feature_builder_append_tag(&builder,
> +        "<vector id=\"sme_bv\" type=\"uint8\" count=\"%d\"/>",
> +        svl);
> +
> +    /* Create the sme_bvv vector type. */
> +    gdb_feature_builder_append_tag(
> +        &builder, "<vector id=\"sme_bvv\" type=\"sme_bv\" count=\"%d\"/>",
> +        svl);
> +
> +    /* Define the svg, svcr, and za registers. */
> +
> +    /* fpscr & status registers */
> +    gdb_feature_builder_append_reg(&builder, "svg", 64, reg++,
> +        "int", NULL);
> +    gdb_feature_builder_append_reg(&builder, "svcr", 64, reg++,
> +        "int", NULL);
> +    gdb_feature_builder_append_reg(&builder, "za", svl * svl * 8, reg++,
> +        "sme_bvv", NULL);
> +
> +    gdb_feature_builder_end(&builder);
> +
> +    return &cpu->dyn_smereg_feature.desc;
> +}
> +
>  #ifdef CONFIG_USER_ONLY
>  int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg)
>  {
> diff --git a/target/arm/internals.h b/target/arm/internals.h
> index 21a8d67edd..af090b9b8e 100644
> --- a/target/arm/internals.h
> +++ b/target/arm/internals.h
> @@ -1808,8 +1808,11 @@ 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);
>  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_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);
> --
> 2.34.1
>
>