X-Git-Url: https://review.openocd.org/gitweb?a=blobdiff_plain;f=src%2Ftarget%2Farm_dpm.c;h=62c6175524d71830011055699a8cfcbddad9016e;hb=59820c18d0d8be93344b00a10a2a4e56601fb094;hp=b83d17a1fcbf4ccfb09b2d9ece4a9e3c5e7d30cc;hpb=374127301ec1d72033b9d573b72c7abdfd61990d;p=openocd.git diff --git a/src/target/arm_dpm.c b/src/target/arm_dpm.c index b83d17a1fc..62c6175524 100644 --- a/src/target/arm_dpm.c +++ b/src/target/arm_dpm.c @@ -12,9 +12,7 @@ * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the - * Free Software Foundation, Inc., - * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. + * along with this program. If not, see . */ #ifdef HAVE_CONFIG_H @@ -230,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). @@ -467,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; @@ -571,7 +594,7 @@ fail: } static int arm_dpm_write_core_reg(struct target *target, struct reg *r, - int regnum, enum arm_mode mode, uint32_t value) + int regnum, enum arm_mode mode, uint8_t *value) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; @@ -648,14 +671,15 @@ static int arm_dpm_full_context(struct target *target) did_read = true; mode = r->mode; - /* For R8..R12 when we've entered debug - * state in FIQ mode... patch mode. + /* For regular (ARM_MODE_ANY) R8..R12 + * in case we've entered debug state + * in FIQ mode we need to patch mode. */ - if (mode == ARM_MODE_ANY) - mode = ARM_MODE_USR; + if (mode != ARM_MODE_ANY) + retval = dpm_modeswitch(dpm, mode); + else + retval = dpm_modeswitch(dpm, ARM_MODE_USR); - /* REVISIT error checks */ - retval = dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto done; } @@ -948,11 +972,14 @@ int arm_dpm_setup(struct arm_dpm *dpm) arm->read_core_reg = arm_dpm_read_core_reg; arm->write_core_reg = arm_dpm_write_core_reg; - cache = arm_build_reg_cache(target, arm); - if (!cache) - return ERROR_FAIL; + /* avoid duplicating the register cache */ + if (arm->core_cache == NULL) { + cache = arm_build_reg_cache(target, arm); + if (!cache) + return ERROR_FAIL; - *register_get_last_cache_p(&target->reg_cache) = cache; + *register_get_last_cache_p(&target->reg_cache) = cache; + } /* coprocessor access setup */ arm->mrc = dpm_mrc;