aboutsummaryrefslogtreecommitdiff
path: root/target/arm/gdbstub64.c
diff options
context:
space:
mode:
Diffstat (limited to 'target/arm/gdbstub64.c')
-rw-r--r--target/arm/gdbstub64.c156
1 files changed, 149 insertions, 7 deletions
diff --git a/target/arm/gdbstub64.c b/target/arm/gdbstub64.c
index 64ee9b3..65d6bbe 100644
--- a/target/arm/gdbstub64.c
+++ b/target/arm/gdbstub64.c
@@ -47,6 +47,7 @@ int aarch64_cpu_gdb_read_register(CPUState *cs, GByteArray *mem_buf, int n)
case 32:
return gdb_get_reg64(mem_buf, env->pc);
case 33:
+ /* pstate is now a 64-bit value; can we simply adjust the xml? */
return gdb_get_reg32(mem_buf, pstate_read(env));
}
/* Unknown register. */
@@ -75,6 +76,7 @@ int aarch64_cpu_gdb_write_register(CPUState *cs, uint8_t *mem_buf, int n)
return 8;
case 33:
/* CPSR */
+ /* pstate is now a 64-bit value; can we simply adjust the xml? */
pstate_write(env, tmp);
return 4;
}
@@ -115,8 +117,22 @@ int aarch64_gdb_set_fpu_reg(CPUState *cs, uint8_t *buf, int reg)
/* 128 bit FP register */
{
uint64_t *q = aa64_vfp_qreg(env, reg);
- q[0] = ldq_le_p(buf);
- q[1] = ldq_le_p(buf + 8);
+
+ /*
+ * On the wire these are target-endian 128 bit values.
+ * In the CPU state these are host-order uint64_t values
+ * with the least-significant one first. This means they're
+ * the other way around for target_big_endian() (which is
+ * only true for us for aarch64_be-linux-user).
+ */
+ if (target_big_endian()) {
+ q[1] = ldq_p(buf);
+ q[0] = ldq_p(buf + 8);
+ } else{
+ q[0] = ldq_p(buf);
+ q[1] = ldq_p(buf + 8);
+ }
+
return 16;
}
case 32:
@@ -192,10 +208,17 @@ int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
case 0 ... 31:
{
int vq, len = 0;
- uint64_t *p = (uint64_t *) buf;
for (vq = 0; vq < cpu->sve_max_vq; vq++) {
- env->vfp.zregs[reg].d[vq * 2 + 1] = *p++;
- env->vfp.zregs[reg].d[vq * 2] = *p++;
+ if (target_big_endian()) {
+ env->vfp.zregs[reg].d[vq * 2 + 1] = ldq_p(buf);
+ buf += 8;
+ env->vfp.zregs[reg].d[vq * 2] = ldq_p(buf);
+ } else{
+ env->vfp.zregs[reg].d[vq * 2] = ldq_p(buf);
+ buf += 8;
+ env->vfp.zregs[reg].d[vq * 2 + 1] = ldq_p(buf);
+ }
+ buf += 8;
len += 16;
}
return len;
@@ -210,9 +233,9 @@ int aarch64_gdb_set_sve_reg(CPUState *cs, uint8_t *buf, int reg)
{
int preg = reg - 34;
int vq, len = 0;
- uint64_t *p = (uint64_t *) buf;
for (vq = 0; vq < cpu->sve_max_vq; vq = vq + 4) {
- env->vfp.pregs[preg].p[vq / 4] = *p++;
+ env->vfp.pregs[preg].p[vq / 4] = ldq_p(buf);
+ buf += 8;
len += 8;
}
return len;
@@ -228,6 +251,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);
@@ -392,6 +499,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)
{