diff --git a/src/flash/arm_nandio.c b/src/flash/arm_nandio.c index fb501e561..8087221ab 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 929ba1d56..0e978c24d 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 8cbc34236..2d2e47f10 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 9f9aa2f5f..eedbc702d 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 aed3a48de..3c8411f04 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);