Vacha Bhavsar <vacha.bhav...@oss.qualcomm.com> writes: > 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> > --- > Changes since v3: > - added changes to aarch64_gdb_set_sme_reg() to address the concerns > brought up in review regarding endianness > > 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..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..3d86980bc9 100644 > --- a/target/arm/gdbstub64.c > +++ b/target/arm/gdbstub64.c > @@ -228,6 +228,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: > + { > + 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; > + } > + 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; > + for (int i = 0; i < svl; i++) { > + for (int q = 0; q < vq; q++) { > + if (target_big_endian()){ > + 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); > @@ -392,6 +477,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 c4765e4489..760e1c6490 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);
It would also be nice to add a test for this, see tests/tcg/aarch64/gdbstub/test-sve.py -- Alex Bennée Virtualisation Tech Lead @ Linaro