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