diff options
Diffstat (limited to 'target/arm/gdbstub64.c')
-rw-r--r-- | target/arm/gdbstub64.c | 156 |
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) { |