diff --git a/target/arm/cpu.h b/target/arm/cpu.h index 7c226a112d..39f2b2e54d 100644 --- a/target/arm/cpu.h +++ b/target/arm/cpu.h @@ -943,6 +943,7 @@ struct ArchCPU { DynamicGDBFeatureInfo dyn_smereg_feature; DynamicGDBFeatureInfo dyn_m_systemreg_feature; DynamicGDBFeatureInfo dyn_m_secextreg_feature; + DynamicGDBFeatureInfo dyn_tls_feature; /* Timers used by the generic (architected) timer */ QEMUTimer *gt_timer[NUM_GTIMERS]; diff --git a/target/arm/gdbstub.c b/target/arm/gdbstub.c index 1ca3e647a8..8865f27089 100644 --- a/target/arm/gdbstub.c +++ b/target/arm/gdbstub.c @@ -583,6 +583,12 @@ void arm_cpu_register_gdb_regs_for_features(ARMCPU *cpu) 0); } #endif + + /* All AArch64 CPUs have at least TPIDR */ + gdb_register_coprocessor(cs, aarch64_gdb_get_tls_reg, + aarch64_gdb_set_tls_reg, + arm_gen_dynamic_tls_feature(cs, cs->gdb_num_regs), + 0); #endif } else { if (arm_feature(env, ARM_FEATURE_NEON)) { diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c index 5ad00fe771..3bc7ff45d5 100644 --- a/target/arm/gdbstub64.c +++ b/target/arm/gdbstub64.c @@ -387,6 +387,44 @@ int aarch64_gdb_set_sme2_reg(CPUState *cs, uint8_t *buf, int reg) return 0; } +int aarch64_gdb_get_tls_reg(CPUState *cs, GByteArray *buf, int reg) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + switch (reg) { + case 0: /* TPIDR_EL0 */ + return gdb_get_reg64(buf, env->cp15.tpidr_el[0]); + case 1: /* TPIDR2_EL0 */ + return gdb_get_reg64(buf, env->cp15.tpidr2_el0); + default: + /* gdbstub asked for something out of range */ + break; + } + + return 0; +} + +int aarch64_gdb_set_tls_reg(CPUState *cs, uint8_t *buf, int reg) +{ + ARMCPU *cpu = ARM_CPU(cs); + CPUARMState *env = &cpu->env; + + switch (reg) { + case 0: /* TPIDR_EL0 */ + env->cp15.tpidr_el[0] = ldq_p(buf); + return 8; + case 1: /* TPIDR2_EL0 */ + env->cp15.tpidr2_el0 = ldq_p(buf); + return 8; + 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); @@ -586,6 +624,31 @@ GDBFeature *arm_gen_dynamic_smereg_feature(CPUState *cs, int base_reg) return &cpu->dyn_smereg_feature.desc; } +GDBFeature *arm_gen_dynamic_tls_feature(CPUState *cs, int base_reg) +{ + ARMCPU *cpu = ARM_CPU(cs); + GDBFeatureBuilder builder; + int reg = 0; + + gdb_feature_builder_init(&builder, &cpu->dyn_tls_feature.desc, + "org.gnu.gdb.aarch64.tls", "tls-registers.xml", + base_reg); + + /* + * This feature must always have "tpidr", and may also have "tpidr2" + * if the CPU has that register. + */ + gdb_feature_builder_append_reg(&builder, "tpidr", 64, + reg++, "data_ptr", NULL); + if (cpu_isar_feature(aa64_sme, cpu)) { + gdb_feature_builder_append_reg(&builder, "tpidr2", 64, + reg++, "data_ptr", NULL); + } + gdb_feature_builder_end(&builder); + + return &cpu->dyn_tls_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 bf44066f71..f86f421a3d 100644 --- a/target/arm/internals.h +++ b/target/arm/internals.h @@ -1716,6 +1716,7 @@ 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); +GDBFeature *arm_gen_dynamic_tls_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); @@ -1728,6 +1729,8 @@ int aarch64_gdb_get_pauth_reg(CPUState *cs, GByteArray *buf, int reg); int aarch64_gdb_set_pauth_reg(CPUState *cs, uint8_t *buf, int reg); int aarch64_gdb_get_tag_ctl_reg(CPUState *cs, GByteArray *buf, int reg); int aarch64_gdb_set_tag_ctl_reg(CPUState *cs, uint8_t *buf, int reg); +int aarch64_gdb_get_tls_reg(CPUState *cs, GByteArray *buf, int reg); +int aarch64_gdb_set_tls_reg(CPUState *cs, 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);