Hi,

Regarding having the SME check inside the "if we have SVE" check, we were
looking the the
Arm ARM, specifically the following excerpt from section A1.4:

The architecture provides the following:

- A general-purpose register file.
- A SIMD&FP register file.
- If FEAT_SVE or FEAT_SME is implemented, an SVE scalable vector register
file and an
SVE scalable predicate register file.
- if FEAT_SME is implemented, the scalable ZA storage.

Based on this, we were considering the following update to the change in
gdbstub64.c and
we wanted to get your input.

if (isar_feature_aa64_sve(&cpu->isar) || isar_feature_aa64_sme(&cpu->isar))
{
            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);
} else {
            gdb_register_coprocessor(cs, aarch64_gdb_get_fpu_reg,
                                     aarch64_gdb_set_fpu_reg,

 gdb_find_static_feature("aarch64-fpu.xml"),
                                     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);
}

Thanks,
Vacha



On Tue, Aug 19, 2025 at 5:05 AM Peter Maydell <peter.mayd...@linaro.org>
wrote:

> On Mon, 11 Aug 2025 at 20:37, Vacha Bhavsar
> <vacha.bhav...@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.bhav...@oss.qualcomm.com>
> > ---
> >  target/arm/cpu.h       |   1 +
> >  target/arm/gdbstub.c   |   6 ++
> >  target/arm/gdbstub64.c | 122 +++++++++++++++++++++++++++++++++++++++++
> >  target/arm/internals.h |   3 +
> >  4 files changed, 132 insertions(+)
> >
> > diff --git a/target/arm/cpu.h b/target/arm/cpu.h
> > index dc9b6dce4c..8bd66d7049 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..4371a367a0 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);
> > +            }
>
> It's possible to have SME without SVE, so this should not be
> inside the "if we have SVE" check.
>
> >          } 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 08e2858539..047b1f8133 100644
> > --- a/target/arm/gdbstub64.c
> > +++ b/target/arm/gdbstub64.c
> > @@ -249,6 +249,91 @@ 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;
> > +
> > +    switch (reg) {
> > +    /* Svg register */
> > +    case 0:
>
> We should comment what all the cases here are; the usual ploce to
> put such a comment is either on the same line as the case, or else
> on the line immediately after the case if the comment would be
> too long to put on the same line.
>
> The capitalization here is odd, too: the register is either "SVG" or "svg".
>
> > +    {
> > +        int vq = 0;
> > +        if (FIELD_EX64(env->svcr, SVCR, SM)) {
> > +            vq = sve_vqm1_for_el_sm(env, arm_current_el(env),
> > +                     FIELD_EX64(env->svcr, SVCR, SM)) + 1;
> > +        }
> > +        /* 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 len = 0;
> > +        int vq = cpu->sme_max_vq;
> > +        int svl = vq * 16;
> > +        for (int i = 0; i < svl; i++) {
> > +            for (int 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 of 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;
> > +
> > +    switch (reg) {
> > +    case 0:
> > +    {
> > +        /* cannot set svg via gdbstub */
> > +        return 8;
> > +    }
>
> You don't need braces here, because there are no local variables
> in this arm of the switch statement.
>
> > +    case 1:
> > +        aarch64_set_svcr(env, ldq_le_p(buf),
> > +            R_SVCR_SM_MASK | R_SVCR_ZA_MASK);
> > +        return 8;
> > +    case 2:
> > +        int len = 0;
> > +        int vq = cpu->sme_max_vq;
> > +        int svl = vq * 16;
>
> But you do need braces here, because there are local variables.
> This is (a) because our coding style requires that declarations
> go at the top of a block and (b) because clang will complain:
>
> ../../target/arm/gdbstub64.c:310:9: error: label followed by a
> declaration is a C23 extension [-Werror,-Wc23-extensions]
>   310 |         int len = 0;
>       |         ^
>
> > +        for (int i = 0; i < svl; i++) {
> > +            for (int q = 0; q < vq; q++) {
> > +                if (target_big_endian()){
>
> Missing space before the {
>
> > +                    env->za_state.za[i].d[q * 2 + 1] = ldq_p(buf);
> > +                    buf += 8;
> > +                    env->za_state.za[i].d[q * 2] = ldq_p(buf);
> > +                } else{
> > +                    env->za_state.za[i].d[q * 2] = ldq_p(buf);
> > +                    buf += 8;
> > +                    env->za_state.za[i].d[q * 2 + 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);
> > @@ -413,6 +498,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->sme_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 1b3d0244fd..41e05066b9 100644
> > --- a/target/arm/internals.h
> > +++ b/target/arm/internals.h
> > @@ -1802,8 +1802,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);
> > --
>
> thanks
> -- PMM
>

Reply via email to