Fix resume when core state has been modified 86/3386/7
authorMatthias Welwarsky <matthias.welwarsky@sysgo.com>
Wed, 29 Jun 2016 13:39:11 +0000 (15:39 +0200)
committerAndreas Fritiofson <andreas.fritiofson@gmail.com>
Tue, 9 Aug 2016 13:28:43 +0000 (14:28 +0100)
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>
src/target/arm11.c
src/target/arm_dpm.c

index 5f1607396227dd40ce134238c1f36119847bed15..cbe4d4503f8473e1b00766897fb03486bf7cf407 100644 (file)
@@ -418,11 +418,33 @@ static uint32_t arm11_nextpc(struct arm11_common *arm11, int current, uint32_t a
 {
        void *value = arm11->arm.pc->value;
 
-       if (!current)
-               buf_set_u32(value, 0, 32, address);
-       else
+       /* use the current program counter */
+       if (current)
                address = buf_get_u32(value, 0, 32);
 
+       /* Make sure that the gdb thumb fixup does not
+        * kill the return address
+        */
+       switch (arm11->arm.core_state) {
+               case ARM_STATE_ARM:
+                       address &= 0xFFFFFFFC;
+                       break;
+               case ARM_STATE_THUMB:
+                       /* When the return address is loaded into PC
+                        * bit 0 must be 1 to stay in Thumb state
+                        */
+                       address |= 0x1;
+                       break;
+
+               /* catch-all for JAZELLE and THUMB_EE */
+               default:
+                       break;
+       }
+
+       buf_set_u32(value, 0, 32, address);
+       arm11->arm.pc->dirty = 1;
+       arm11->arm.pc->valid = 1;
+
        return address;
 }
 
index e9dd6303d72d9dd7024be9d2e95a0918fa9cf6a7..8ad6575cf697d74985660994b4e3b91d3832bbd3 100644 (file)
@@ -228,6 +228,18 @@ static int dpm_write_reg(struct arm_dpm *dpm, struct reg *r, unsigned regnum)
        return retval;
 }
 
+/**
+ * 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).
@@ -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;

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)