aboutsummaryrefslogtreecommitdiff
path: root/src/target/arm_dpm.c
diff options
context:
space:
mode:
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>2016-09-03 23:20:58 +0200
committerMatthias Welwarsky <matthias.welwarsky@sysgo.com>2017-02-10 14:01:38 +0100
commita3b9e12aecc3021bc3022eca93d07f7d11255b3b (patch)
tree82b35ea3737b66feeadfdff5846759c355cc50c2 /src/target/arm_dpm.c
parentdf32af234cae1f24b0a0f3abf4b50859f9d26740 (diff)
aarch64: introduce dpm extension for ARMv8
Add or move ARMv8 related dpm function to their own source module Change-Id: Id93d50be0b8635bd40ddb2a74fe8746ff840d736 Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com>
Diffstat (limited to 'src/target/arm_dpm.c')
-rw-r--r--src/target/arm_dpm.c324
1 files changed, 75 insertions, 249 deletions
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index 55f253e4..00ebebae 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -21,6 +21,7 @@
#include "arm.h"
#include "arm_dpm.h"
+#include "armv8_dpm.h"
#include <jtag/jtag.h>
#include "register.h"
#include "breakpoints.h"
@@ -130,11 +131,11 @@ int dpm_modeswitch(struct arm_dpm *dpm, enum arm_mode mode)
return retval;
}
-
-static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just read the register -- rely on the core mode being right */
+static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
uint32_t value;
- int retval = ERROR_FAIL;
+ int retval;
switch (regnum) {
case 0 ... 14:
@@ -165,8 +166,8 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
/* core-specific ... ? */
LOG_WARNING("Jazelle PC adjustment unknown");
break;
- case ARM_STATE_AARCH64:
- LOG_ERROR("AARCH64: 32bit read requested");
+ default:
+ LOG_WARNING("unknow core state");
break;
}
break;
@@ -190,57 +191,10 @@ static int dpm_read_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
return retval;
}
-static int dpm_read_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- uint64_t value;
- uint32_t i;
- int retval = ERROR_FAIL;
-
- switch (regnum) {
- case 0 ... 30:
- i = 0xd5130400 + regnum; /* msr dbgdtr_el0,reg */
- retval = dpm->instr_read_data_dcc_64(dpm, i, &value);
- break;
- case 31: /* SP */
- i = 0x910003e0;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
- case 32: /* PC */
- i = 0xd53b4520;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
- case 33: /* CPSR */
- i = 0xd53b4500;
- retval = dpm->instr_read_data_r0_64(dpm, i, &value);
- break;
-
- default:
- break;
- }
-
- if (retval == ERROR_OK) {
- buf_set_u64(r->value, 0, 64, value);
- r->valid = true;
- r->dirty = false;
- LOG_DEBUG("READ: %s, %16.16llx", r->name, (long long)value);
- }
-
- return retval;
-}
-
-
-/* just read the register -- rely on the core mode being right */
-static int dpm_read_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- if (r->size == 64)
- return dpm_read_reg64(dpm, r, regnum);
- else
- return dpm_read_reg32(dpm, r, regnum);
-}
-
-static int dpm_write_reg32(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
+/* just write the register -- rely on the core mode being right */
+static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
{
- int retval = ERROR_FAIL;
+ int retval;
uint32_t value = buf_get_u32(r->value, 0, 32);
switch (regnum) {
@@ -290,51 +244,19 @@ static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
}
-static int dpm_write_reg64(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- int retval = ERROR_FAIL;
- uint32_t i;
- uint64_t value = buf_get_u64(r->value, 0, 64);
-
- switch (regnum) {
- case 0 ... 30:
- i = 0xd5330400 + regnum;
- retval = dpm->instr_write_data_dcc_64(dpm, i, value);
- break;
- case 32: /* PC */
- i = 0xd51b4520;
- retval = dpm->instr_write_data_r0_64(dpm, i, value);
- break;
- default:
- LOG_DEBUG("register %s (%16.16llx) not defined", r->name,
- (unsigned long long)value);
- break;
- }
-
- if (retval == ERROR_OK) {
- r->dirty = false;
- LOG_DEBUG("WRITE: %s, %16.16llx", r->name, (unsigned long long)value);
- }
-
- return retval;
-}
-
-/* just write the register -- rely on the core mode being right */
-static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
-{
- if (r->size == 64)
- return dpm_write_reg64(dpm, r, regnum);
- else
- return dpm_write_reg32(dpm, r, regnum);
-}
-
-static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
+/**
+ * Read basic registers of the the current context: R0 to R15, and CPSR;
+ * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
+ * In normal operation this is called on entry to halting debug state,
+ * possibly after some other operations supporting restore of debug state
+ * or making sure the CPU is fully idle (drain write buffer, etc).
+ */
+int arm_dpm_read_current_registers(struct arm_dpm *dpm)
{
struct arm *arm = dpm->arm;
- uint32_t cpsr, instr, core_regs;
+ uint32_t cpsr;
int retval;
struct reg *r;
- enum arm_state core_state = arm->core_state;
retval = dpm->prepare(dpm);
if (retval != ERROR_OK)
@@ -349,25 +271,16 @@ static int arm_dpm_read_current_registers_i(struct arm_dpm *dpm)
}
r->dirty = true;
- if (core_state == ARM_STATE_AARCH64)
- instr = 0xd53b4500; /* mrs x0, dspsr_el0 */
- else
- instr = ARMV4_5_MRS(0, 0);
- retval = dpm->instr_read_data_r0(dpm, instr, &cpsr);
+ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRS(0, 0), &cpsr);
if (retval != ERROR_OK)
goto fail;
/* update core mode and state, plus shadow mapping for R8..R14 */
arm_set_cpsr(arm, cpsr);
- if (core_state == ARM_STATE_AARCH64)
- /* arm_set_cpsr changes core_state, restore it for now */
- arm->core_state = ARM_STATE_AARCH64;
-
- core_regs = arm->core_cache->num_regs;
/* REVISIT we can probably avoid reading R1..R14, saving time... */
- for (unsigned i = 1; i < core_regs; i++) {
- r = dpm->arm_reg_current(arm, i);
+ for (unsigned i = 1; i < 16; i++) {
+ r = arm_reg_current(arm, i);
if (r->valid)
continue;
@@ -388,23 +301,6 @@ fail:
return retval;
}
-/**
- * Read basic registers of the the current context: R0 to R15, and CPSR;
- * sets the core mode (such as USR or IRQ) and state (such as ARM or Thumb).
- * In normal operation this is called on entry to halting debug state,
- * possibly after some other operations supporting restore of debug state
- * or making sure the CPU is fully idle (drain write buffer, etc).
- */
-int arm_dpm_read_current_registers(struct arm_dpm *dpm)
-{
- return arm_dpm_read_current_registers_i(dpm);
-}
-
-int arm_dpm_read_current_registers_64(struct arm_dpm *dpm)
-{
- return arm_dpm_read_current_registers_i(dpm);
-}
-
/* Avoid needless I/O ... leave breakpoints and watchpoints alone
* unless they're removed, or need updating because of single-stepping
* or running debugger code.
@@ -453,14 +349,59 @@ done:
static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp);
-
-static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
+/**
+ * Writes all modified core registers for all processor modes. In normal
+ * operation this is called on exit from halting debug state.
+ *
+ * @param dpm: represents the processor
+ * @param bpwp: true ensures breakpoints and watchpoints are set,
+ * false ensures they are cleared
+ */
+int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
{
struct arm *arm = dpm->arm;
struct reg_cache *cache = arm->core_cache;
int retval;
bool did_write;
+ retval = dpm->prepare(dpm);
+ if (retval != ERROR_OK)
+ goto done;
+
+ /* If we're managing hardware breakpoints for this core, enable
+ * or disable them as requested.
+ *
+ * REVISIT We don't yet manage them for ANY cores. Eventually
+ * we should be able to assume we handle them; but until then,
+ * cope with the hand-crafted breakpoint code.
+ */
+ if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
+ for (unsigned i = 0; i < dpm->nbp; i++) {
+ struct dpm_bp *dbp = dpm->dbp + i;
+ struct breakpoint *bp = dbp->bp;
+
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
+ bp ? &bp->set : NULL);
+ if (retval != ERROR_OK)
+ goto done;
+ }
+ }
+
+ /* enable/disable watchpoints */
+ for (unsigned i = 0; i < dpm->nwp; i++) {
+ struct dpm_wp *dwp = dpm->dwp + i;
+ struct watchpoint *wp = dwp->wp;
+
+ retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
+ wp ? &wp->set : NULL);
+ if (retval != ERROR_OK)
+ goto done;
+ }
+
+ /* NOTE: writes to breakpoint and watchpoint registers might
+ * be queued, and need (efficient/batched) flushing later.
+ */
+
/* Scan the registers until we find one that's both dirty and
* eligible for flushing. Flush that and everything else that
* shares the same core mode setting. Typically this won't
@@ -564,106 +505,6 @@ static int arm_dpm_write_dirty_registers_32(struct arm_dpm *dpm)
goto done;
cache->reg_list[0].dirty = false;
-done:
- return retval;
-}
-
-static int arm_dpm_write_dirty_registers_64(struct arm_dpm *dpm)
-{
- struct arm *arm = dpm->arm;
- struct reg_cache *cache = arm->core_cache;
- int retval;
-
- /* Scan the registers until we find one that's both dirty and
- * eligible for flushing. Flush that and everything else that
- * shares the same core mode setting. Typically this won't
- * actually find anything to do...
- */
-
- /* check everything except our scratch register R0 */
- for (unsigned i = 1; i <= 32; i++) {
- struct arm_reg *r;
- unsigned regnum;
-
- if (!cache->reg_list[i].dirty)
- continue;
-
- r = cache->reg_list[i].arch_info;
- regnum = r->num;
- retval = dpm_write_reg(dpm,
- &cache->reg_list[i],
- regnum);
- if (retval != ERROR_OK)
- goto done;
- }
-
- /* flush R0 -- it's *very* dirty by now */
- retval = dpm_write_reg(dpm, &cache->reg_list[0], 0);
- if (retval != ERROR_OK)
- goto done;
- cache->reg_list[0].dirty = false;
-
-done:
- return retval;
-}
-
-/**
- * Writes all modified core registers for all processor modes. In normal
- * operation this is called on exit from halting debug state.
- *
- * @param dpm: represents the processor
- * @param bpwp: true ensures breakpoints and watchpoints are set,
- * false ensures they are cleared
- */
-int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
-{
- struct arm *arm = dpm->arm;
- struct reg_cache *cache = arm->core_cache;
- int retval;
-
- retval = dpm->prepare(dpm);
- if (retval != ERROR_OK)
- goto done;
-
- /* If we're managing hardware breakpoints for this core, enable
- * or disable them as requested.
- *
- * REVISIT We don't yet manage them for ANY cores. Eventually
- * we should be able to assume we handle them; but until then,
- * cope with the hand-crafted breakpoint code.
- */
- if (arm->target->type->add_breakpoint == dpm_add_breakpoint) {
- for (unsigned i = 0; i < dpm->nbp; i++) {
- struct dpm_bp *dbp = dpm->dbp + i;
- struct breakpoint *bp = dbp->bp;
-
- retval = dpm_maybe_update_bpwp(dpm, bpwp, &dbp->bpwp,
- bp ? &bp->set : NULL);
- if (retval != ERROR_OK)
- goto done;
- }
- }
-
- /* enable/disable watchpoints */
- for (unsigned i = 0; i < dpm->nwp; i++) {
- struct dpm_wp *dwp = dpm->dwp + i;
- struct watchpoint *wp = dwp->wp;
-
- retval = dpm_maybe_update_bpwp(dpm, bpwp, &dwp->bpwp,
- wp ? &wp->set : NULL);
- if (retval != ERROR_OK)
- goto done;
- }
-
- /* NOTE: writes to breakpoint and watchpoint registers might
- * be queued, and need (efficient/batched) flushing later.
- */
-
- if (cache->reg_list[0].size == 64)
- retval = arm_dpm_write_dirty_registers_64(dpm);
- else
- retval = arm_dpm_write_dirty_registers_32(dpm);
-
/* (void) */ dpm->finish(dpm);
done:
return retval;
@@ -1133,20 +974,15 @@ int arm_dpm_setup(struct arm_dpm *dpm)
/* register access setup */
arm->full_context = arm_dpm_full_context;
- arm->read_core_reg = arm->read_core_reg ? : arm_dpm_read_core_reg;
- arm->write_core_reg = arm->write_core_reg ? : arm_dpm_write_core_reg;
+ arm->read_core_reg = arm_dpm_read_core_reg;
+ arm->write_core_reg = arm_dpm_write_core_reg;
if (arm->core_cache != NULL) {
- if (arm->core_state == ARM_STATE_AARCH64) {
- cache = armv8_build_reg_cache(target);
- target->reg_cache = cache;
- } else {
- cache = arm_build_reg_cache(target, arm);
- *register_get_last_cache_p(&target->reg_cache) = cache;
- }
-
+ cache = arm_build_reg_cache(target, arm);
if (!cache)
return ERROR_FAIL;
+
+ *register_get_last_cache_p(&target->reg_cache) = cache;
}
/* coprocessor access setup */
@@ -1163,20 +999,10 @@ int arm_dpm_setup(struct arm_dpm *dpm)
target->type->add_watchpoint = dpm_add_watchpoint;
target->type->remove_watchpoint = dpm_remove_watchpoint;
-
- if (dpm->arm_reg_current == 0)
- dpm->arm_reg_current = arm_reg_current;
-
/* FIXME add vector catch support */
- if (arm->core_state == ARM_STATE_AARCH64) {
- dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
- dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
- } else {
- dpm->nbp = 1 + ((dpm->didr >> 12) & 0xf);
- dpm->nwp = 1 + ((dpm->didr >> 20) & 0xf);
- }
-
+ dpm->nbp = 1 + ((dpm->didr >> 24) & 0xf);
+ dpm->nwp = 1 + ((dpm->didr >> 28) & 0xf);
dpm->dbp = calloc(dpm->nbp, sizeof *dpm->dbp);
dpm->dwp = calloc(dpm->nwp, sizeof *dpm->dwp);