summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/flash/arm_nandio.c11
-rw-r--r--src/target/arm7tdmi.c1
-rw-r--r--src/target/arm9tdmi.c1
-rw-r--r--src/target/armv4_5.c21
-rw-r--r--src/target/armv4_5.h1
5 files changed, 27 insertions, 8 deletions
diff --git a/src/flash/arm_nandio.c b/src/flash/arm_nandio.c
index fb501e56..8087221a 100644
--- a/src/flash/arm_nandio.c
+++ b/src/flash/arm_nandio.c
@@ -33,7 +33,6 @@
* For now this only supports ARMv4 and ARMv5 cores.
*
* Enhancements to target_run_algorithm() could enable:
- * - faster writes: on ARMv5+ don't setup/teardown hardware breakpoint
* - ARMv6 and ARMv7 cores in ARM mode
*
* Different code fragments could handle:
@@ -44,8 +43,10 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
{
target_t *target = nand->target;
armv4_5_algorithm_t algo;
+ armv4_5_common_t *armv4_5 = target->arch_info;
reg_param_t reg_params[3];
uint32_t target_buf;
+ uint32_t exit = 0;
int retval;
/* Inputs:
@@ -112,11 +113,13 @@ int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
buf_set_u32(reg_params[1].value, 0, 32, target_buf);
buf_set_u32(reg_params[2].value, 0, 32, size);
+ /* armv4 must exit using a hardware breakpoint */
+ if (armv4_5->is_armv4)
+ exit = nand->copy_area->address + sizeof(code) - 4;
+
/* use alg to write data from work area to NAND chip */
retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
- nand->copy_area->address,
- nand->copy_area->address + sizeof(code) - 4,
- 1000, &algo);
+ nand->copy_area->address, exit, 1000, &algo);
if (retval != ERROR_OK)
LOG_ERROR("error executing hosted NAND write");
diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c
index 929ba1d5..0e978c24 100644
--- a/src/target/arm7tdmi.c
+++ b/src/target/arm7tdmi.c
@@ -828,6 +828,7 @@ int arm7tdmi_target_create(struct target_s *target, Jim_Interp *interp)
arm7tdmi = calloc(1,sizeof(arm7tdmi_common_t));
arm7tdmi_init_arch_info(target, arm7tdmi, target->tap);
+ arm7tdmi->arm7_9_common.armv4_5_common.is_armv4 = true;
return ERROR_OK;
}
diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c
index 8cbc3423..2d2e47f1 100644
--- a/src/target/arm9tdmi.c
+++ b/src/target/arm9tdmi.c
@@ -956,6 +956,7 @@ int arm9tdmi_target_create(struct target_s *target, Jim_Interp *interp)
arm9tdmi_common_t *arm9tdmi = calloc(1,sizeof(arm9tdmi_common_t));
arm9tdmi_init_arch_info(target, arm9tdmi, target->tap);
+ arm9tdmi->arm7_9_common.armv4_5_common.is_armv4 = true;
return ERROR_OK;
}
diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c
index 9f9aa2f5..eedbc702 100644
--- a/src/target/armv4_5.c
+++ b/src/target/armv4_5.c
@@ -532,7 +532,10 @@ static int armv4_5_run_algorithm_completion(struct target_s *target, uint32_t ex
}
return ERROR_TARGET_TIMEOUT;
}
- if (buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32) != exit_point)
+
+ /* fast exit: ARMv5+ code can use BKPT */
+ if (exit_point && buf_get_u32(armv4_5->core_cache->reg_list[15].value,
+ 0, 32) != exit_point)
{
LOG_WARNING("target reentered debug state, but not at the desired exit point: 0x%4.4" PRIx32 "",
buf_get_u32(armv4_5->core_cache->reg_list[15].value, 0, 32));
@@ -570,6 +573,13 @@ int armv4_5_run_algorithm_inner(struct target_s *target, int num_mem_params, mem
if (armv4_5_mode_to_number(armv4_5->core_mode)==-1)
return ERROR_FAIL;
+ /* armv5 and later can terminate with BKPT instruction; less overhead */
+ if (!exit_point && armv4_5->is_armv4)
+ {
+ LOG_ERROR("ARMv4 target needs HW breakpoint location");
+ return ERROR_FAIL;
+ }
+
for (i = 0; i <= 16; i++)
{
if (!ARMV4_5_CORE_REG_MODE(armv4_5->core_cache, armv4_5_algorithm_info->core_mode, i).valid)
@@ -626,9 +636,11 @@ int armv4_5_run_algorithm_inner(struct target_s *target, int num_mem_params, mem
armv4_5->core_cache->reg_list[ARMV4_5_CPSR].valid = 1;
}
- if ((retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD)) != ERROR_OK)
+ /* terminate using a hardware or (ARMv5+) software breakpoint */
+ if (exit_point && (retval = breakpoint_add(target, exit_point,
+ exit_breakpoint_size, BKPT_HARD)) != ERROR_OK)
{
- LOG_ERROR("can't add breakpoint to finish algorithm execution");
+ LOG_ERROR("can't add HW breakpoint to terminate algorithm");
return ERROR_TARGET_FAILURE;
}
@@ -639,7 +651,8 @@ int armv4_5_run_algorithm_inner(struct target_s *target, int num_mem_params, mem
int retvaltemp;
retval = run_it(target, exit_point, timeout_ms, arch_info);
- breakpoint_remove(target, exit_point);
+ if (exit_point)
+ breakpoint_remove(target, exit_point);
if (retval != ERROR_OK)
return retval;
diff --git a/src/target/armv4_5.h b/src/target/armv4_5.h
index aed3a48d..3c8411f0 100644
--- a/src/target/armv4_5.h
+++ b/src/target/armv4_5.h
@@ -76,6 +76,7 @@ typedef struct armv4_5_common_s
reg_cache_t *core_cache;
enum armv4_5_mode core_mode;
enum armv4_5_state core_state;
+ bool is_armv4;
int (*full_context)(struct target_s *target);
int (*read_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode);
int (*write_core_reg)(struct target_s *target, int num, enum armv4_5_mode mode, uint32_t value);