aboutsummaryrefslogtreecommitdiff
path: root/src/target/arm_dpm.c
diff options
context:
space:
mode:
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>2016-06-29 15:39:11 +0200
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>2016-08-09 14:28:43 +0100
commit6f8cf930bc015037e2ad4260c7d360d563644329 (patch)
treed7566e36158c3a1f762143837c23ff9a9e0cfa62 /src/target/arm_dpm.c
parent5d5c9bc4ecbc8c601e77c95b40fa09ec48a79aea (diff)
Fix resume when core state has been modified
Sometimes it is necessary to resume into a different state (ARM/Thumb) than at debug state entry. According to the documentation this should be possible with "arm core_state arm|thumb" before the resume command, however the original code also restores the original CPSR, which overrides whatever state the core was set to. This seems to work on some cores (e.g. Cortex-A5) but not on others (e.g. Cortex-A9). Using the "BX" instruction to set resume PC and core state works on Cortex-A9 and ARM11, but is not sufficient on Cortex-A5, where an explicit write to the PC (MOV pc, r0) is required additionally. Change-Id: Ic03153b4b250fbb8cf6c75f8e329fb34829aa35f Signed-off-by: Matthias Welwarsky <matthias.welwarsky@sysgo.com> Reviewed-on: http://openocd.zylin.com/3386 Tested-by: jenkins Reviewed-by: Alexander Stein <alexanders83@web.de> Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Diffstat (limited to 'src/target/arm_dpm.c')
-rw-r--r--src/target/arm_dpm.c25
1 files changed, 25 insertions, 0 deletions
diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c
index e9dd6303..8ad6575c 100644
--- a/src/target/arm_dpm.c
+++ b/src/target/arm_dpm.c
@@ -229,6 +229,18 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
}
/**
+ * Write to program counter and switch the core state (arm/thumb) according to
+ * the address.
+ */
+static int dpm_write_pc_core_state(struct arm_dpm *dpm, struct reg *r)
+{
+ uint32_t value = buf_get_u32(r->value, 0, 32);
+
+ /* read r0 from DCC; then "BX r0" */
+ return dpm->instr_write_data_r0(dpm, ARMV4_5_BX(0), value);
+}
+
+/**
* 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,
@@ -465,6 +477,19 @@ int arm_dpm_write_dirty_registers(struct arm_dpm *dpm, bool bpwp)
goto done;
arm->cpsr->dirty = false;
+ /* restore the PC, make sure to also switch the core state
+ * to whatever it was set to with "arm core_state" command.
+ * target code will have set PC to an appropriate resume address.
+ */
+ retval = dpm_write_pc_core_state(dpm, arm->pc);
+ if (retval != ERROR_OK)
+ goto done;
+ /* on Cortex-A5 (as found on NXP VF610 SoC), BX instruction
+ * executed in debug state doesn't appear to set the PC,
+ * explicitly set it with a "MOV pc, r0". This doesn't influence
+ * CPSR on Cortex-A9 so it should be OK. Maybe due to different
+ * debug version?
+ */
retval = dpm_write_reg(dpm, arm->pc, 15);
if (retval != ERROR_OK)
goto done;