Mirror the existing support for SVE. Signed-off-by: Richard Henderson <richard.hender...@linaro.org> --- target/arm/cpu.h | 1 + target/arm/internals.h | 3 ++ target/arm/gdbstub.c | 8 ++++ target/arm/gdbstub64.c | 88 ++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 100 insertions(+)
diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 6e97a256fb..9971280577 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -869,6 +869,7 @@ struct ArchCPU { DynamicGDBXMLInfo dyn_sysreg_xml; DynamicGDBXMLInfo dyn_svereg_xml; + DynamicGDBXMLInfo dyn_zareg_xml; DynamicGDBXMLInfo dyn_m_systemreg_xml; DynamicGDBXMLInfo dyn_m_secextreg_xml; diff --git a/target/arm/internals.h b/target/arm/internals.h index a03748aa10..a27e5b3f28 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1343,12 +1343,15 @@ static inline uint64_t pmu_counter_mask(CPUARMState *env) #ifdef TARGET_AARCH64 int arm_gen_dynamic_svereg_xml(CPUState *cpu, int base_reg); +int arm_gen_dynamic_zareg_xml(CPUState *cpu, int base_reg); int aarch64_gdb_get_sve_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_gdb_set_sve_reg(CPUARMState *env, uint8_t *buf, int reg); int aarch64_gdb_get_fpu_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_gdb_set_fpu_reg(CPUARMState *env, uint8_t *buf, int reg); int aarch64_gdb_get_pauth_reg(CPUARMState *env, GByteArray *buf, int reg); int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg); +int aarch64_gdb_get_za_reg(CPUARMState *env, GByteArray *buf, int reg); +int aarch64_gdb_set_za_reg(CPUARMState *env, uint8_t *buf, int reg); void arm_cpu_sve_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_sme_finalize(ARMCPU *cpu, Error **errp); void arm_cpu_pauth_finalize(ARMCPU *cpu, Error **errp); diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 3f799f5d05..60a9ade732 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -488,6 +488,8 @@ const char *arm_gdb_get_dynamic_xml(CPUState *cs, const char *xmlname) return cpu->dyn_sysreg_xml.desc; } else if (strcmp(xmlname, "sve-registers.xml") == 0) { return cpu->dyn_svereg_xml.desc; + } else if (strcmp(xmlname, "za-registers.xml") == 0) { + return cpu->dyn_zareg_xml.desc; } else if (strcmp(xmlname, "arm-m-system.xml") == 0) { return cpu->dyn_m_systemreg_xml.desc; #ifndef CONFIG_USER_ONLY @@ -524,6 +526,12 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) aarch64_gdb_set_pauth_reg, 4, "aarch64-pauth.xml", 0); } + if (cpu_isar_feature(aa64_sme, cpu)) { + int nreg = arm_gen_dynamic_zareg_xml(cs, cs->gdb_num_regs); + gdb_register_coprocessor(cs, aarch64_gdb_get_za_reg, + aarch64_gdb_set_za_reg, nreg, + "za-registers.xml", 0); + } #endif } else { if (arm_feature(env, ARM_FEATURE_NEON)) { diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 3bee892fb7..9210d12c4e 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -244,6 +244,61 @@ int aarch64_gdb_set_pauth_reg(CPUARMState *env, uint8_t *buf, int reg) return 0; } +static int max_svq(ARMCPU *cpu) +{ + return 32 - clz32(cpu->sme_vq.map); +} + +int aarch64_gdb_get_za_reg(CPUARMState *env, GByteArray *buf, int reg) +{ + ARMCPU *cpu = env_archcpu(env); + int max_vq = max_svq(cpu); + int cur_vq = EX_TBFLAG_A64(env->hflags, SVL) + 1; + int i; + + if (reg >= max_vq * 16) { + return 0; + } + + /* If ZA is unset, or reg out of range, the contents are zero. */ + if (FIELD_EX64(env->svcr, SVCR, ZA) && reg < cur_vq * 16) { + for (i = 0; i < cur_vq; i++) { + gdb_get_reg128(buf, env->zarray[reg].d[i * 2 + 1], + env->zarray[reg].d[i * 2]); + } + } else { + cur_vq = 0; + } + + for (i = cur_vq; i < max_vq; i++) { + gdb_get_reg128(buf, 0, 0); + } + + return max_vq * 16; +} + +int aarch64_gdb_set_za_reg(CPUARMState *env, uint8_t *buf, int reg) +{ + ARMCPU *cpu = env_archcpu(env); + uint64_t *p = (uint64_t *) buf; + int max_vq = max_svq(cpu); + int cur_vq = EX_TBFLAG_A64(env->hflags, SVL) + 1; + int i; + + if (reg >= max_vq * 16) { + return 0; + } + + /* If ZA is unset, or reg out of range, the contents are zero. */ + if (FIELD_EX64(env->svcr, SVCR, ZA) && reg < cur_vq * 16) { + for (i = 0; i < cur_vq; i++) { + env->zarray[reg].d[i * 2 + 1] = *p++; + env->zarray[reg].d[i * 2 + 0] = *p++; + } + } + return max_vq * 16; +} + static void output_vector_union_type(GString *s, int reg_width, const char *name) { @@ -376,3 +431,36 @@ int arm_gen_dynamic_svereg_xml(CPUState *cs, int orig_base_reg) info->num = base_reg - orig_base_reg; return info->num; } + +/* + * Generate the xml for SME, with matrix size set to the maximum + * for the cpu. Returns the number of registers generated. + */ +int arm_gen_dynamic_zareg_xml(CPUState *cs, int base_reg) +{ + ARMCPU *cpu = ARM_CPU(cs); + GString *s = g_string_new(NULL); + int vq = max_svq(cpu); + int row_count = vq * 16; + int row_width = vq * 128; + int i; + + g_string_printf(s, "<?xml version=\"1.0\"?>"); + g_string_append_printf(s, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); + g_string_append_printf(s, "<feature name=\"org.gnu.qemu.aarch64.za\">"); + + output_vector_union_type(s, row_width, "zav"); + + for (i = 0; i < row_count; i++) { + g_string_append_printf(s, + "<reg name=\"za%d\" bitsize=\"%d\"" + " regnum=\"%d\" type=\"zav\"/>", + i, row_width, base_reg + i); + } + + g_string_append_printf(s, "</feature>"); + + cpu->dyn_zareg_xml.num = row_count; + cpu->dyn_zareg_xml.desc = g_string_free(s, false); + return row_count; +} -- 2.34.1