diff options
| author | Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com> | 2025-09-09 16:10:11 +0000 |
|---|---|---|
| committer | Peter Maydell <peter.maydell@linaro.org> | 2025-09-16 17:31:54 +0100 |
| commit | 030f0ba11767c7bd4148d9cd4f63e299d38139b3 (patch) | |
| tree | 90e58bcc265dda5fca25f6cb9cbc88d84c9eb1f5 /target/arm/gdbstub64.c | |
| parent | 71cda981208ebcfa403d8e3451d1d5bdef0b0931 (diff) | |
| download | focaccia-qemu-030f0ba11767c7bd4148d9cd4f63e299d38139b3.tar.gz focaccia-qemu-030f0ba11767c7bd4148d9cd4f63e299d38139b3.zip | |
target/arm: Added support for SME register exposure to GDB
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 for AArch64 targets, 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. Note that according to the GDB documentation the ZA register is defined as a vector of bytes; however the target description xml retrieved when using gdb natively on a host with SME capabilities represents the ZA register as a vector of vectors of bytes, so this is a GDB documentation error. We follow GDB's own gdbstub implementation and represent the ZA register as a vector of vectors of bytes as is done by GDB here: https://github.com/bminor/binutils-gdb/blob/5cce2b7006daa7073b98e3d1a3b176199d1381d7/gdb/features/aarch64-sme.c#L50 Signed-off-by: Vacha Bhavsar <vacha.bhavsar@oss.qualcomm.com> Message-id: 20250909161012.2561593-3-vacha.bhavsar@oss.qualcomm.com Reviewed-by: Peter Maydell <peter.maydell@linaro.org> [PMM: fixed minor checkpatch nits] Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'target/arm/gdbstub64.c')
| -rw-r--r-- | target/arm/gdbstub64.c | 119 |
1 files changed, 119 insertions, 0 deletions
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 08e2858539..3bccde2bf2 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -249,6 +249,90 @@ 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) { + case 0: /* svg register */ + { + 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: /* svcr register */ + return gdb_get_reg64(buf, env->svcr); + case 2: /* za register */ + { + 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: /* svg register */ + /* cannot set svg via gdbstub */ + return 8; + case 1: /* svcr register */ + aarch64_set_svcr(env, ldq_le_p(buf), + R_SVCR_SM_MASK | R_SVCR_ZA_MASK); + return 8; + case 2: /* za register */ + { + 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); @@ -413,6 +497,41 @@ 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. */ + + 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) { |