This is an automated email from Gerrit. Andrey Smirnov ([email protected]) just uploaded a new patch set to Gerrit, which you can find at http://openocd.zylin.com/2211
-- gerrit commit bd5d512a74fbcb33eaa59ac9e8504ad3aed9a4b0 Author: Andrey Smirnov <[email protected]> Date: Wed May 14 08:49:44 2014 -0700 armv4_5: Implement 'start_algorithm' and 'wait_algorithm' functions This change introduces the following changes: * Implement armv4_5_start_algorithm and armv4_5_wait_algorithm, so it would be possible to run asynchronous algorithm on ARM v4, v5 and v7 targets * Port 'armv4_5_run_algorithm' and 'armv4_5_wait_algorithm_inner' to use aforementioned functions * Register implemented functions for 'cortex_r4' and 'cortex_a8' targets * For cases when caller does not set the breakpoint up themselves -- add a field to 'struct arm_algorithm' to specify what type of breakpoint(software or hardware) should be used for termination of the algorithm Change-Id: I64e8e351a30d4175c8856caa8125e35275a546bf Signed-off-by: Andrey Smirnov <[email protected]> diff --git a/src/target/arm.h b/src/target/arm.h index 88b5902..7b13499 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -29,6 +29,7 @@ #include <helper/command.h> #include "target.h" +#include "breakpoints.h" /** @@ -195,6 +196,8 @@ struct arm_algorithm { enum arm_mode core_mode; enum arm_state core_state; + + enum breakpoint_type bp_type; }; struct arm_reg { @@ -218,17 +221,31 @@ int arm_init_arch_info(struct target *target, struct arm *arm); /* REVISIT rename this once it's usable by ARMv7-M */ int armv4_5_run_algorithm(struct target *target, - int num_mem_params, struct mem_param *mem_params, - int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info); + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t entry_point, uint32_t exit_point, + int timeout_ms, void *arch_info); + +int armv4_5_start_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t entry_point, uint32_t exit_point, + void *arch_info); + +int armv4_5_wait_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t exit_point, + int timeout_ms, void *arch_info); + int armv4_5_run_algorithm_inner(struct target *target, - int num_mem_params, struct mem_param *mem_params, - int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info, - int (*run_it)(struct target *target, uint32_t exit_point, - int timeout_ms, void *arch_info)); + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t entry_point, uint32_t exit_point, + int timeout_ms, void *arch_info, + int (*run_it)(struct target *target, uint32_t exit_point, + int timeout_ms, void *arch_info)); + int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum); diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index dc77af2..e056048 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -37,6 +37,16 @@ #include "algorithm.h" #include "register.h" +struct armv4_5_algorithm_scratchpad { + enum arm_state core_state; + + uint32_t context[17]; + uint32_t cpsr; + + struct arm_algorithm arm_algorithm_info; +}; + + /* offsets into armv4_5 core register cache */ enum { /* ARMV4_5_CPSR = 31, */ @@ -1166,186 +1176,230 @@ int arm_get_gdb_reg_list(struct target *target, } } -/* wait for execution to complete and check exit point */ -static int armv4_5_run_algorithm_completion(struct target *target, - uint32_t exit_point, - int timeout_ms, - void *arch_info) +static void armv4_5_restore_cpsr_from_scratchpad(struct arm *arm, + const struct armv4_5_algorithm_scratchpad *scratchpad) { - int retval; - struct arm *arm = target_to_arm(target); - - retval = target_wait_state(target, TARGET_HALTED, timeout_ms); - if (retval != ERROR_OK) - return retval; - if (target->state != TARGET_HALTED) { - retval = target_halt(target); - if (retval != ERROR_OK) - return retval; - retval = target_wait_state(target, TARGET_HALTED, 500); - if (retval != ERROR_OK) - return retval; - return ERROR_TARGET_TIMEOUT; - } + arm_set_cpsr(arm, scratchpad->cpsr); + arm->cpsr->dirty = 1; + arm->cpsr->valid = 1; +} - /* fast exit: ARMv5+ code can use BKPT */ - if (exit_point && buf_get_u32(arm->pc->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(arm->pc->value, 0, 32)); - return ERROR_TARGET_TIMEOUT; +static void armv4_5_restore_registers_from_scratchpad(struct arm *arm, + const struct armv4_5_algorithm_scratchpad *scratchpad) +{ + /* restore everything we saved before (17 or 18 registers) */ + for (unsigned int i = 0; i < ARRAY_SIZE(scratchpad->context); i++) { + uint32_t regvalue; + struct reg *r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, + scratchpad->arm_algorithm_info.core_mode, + i); + regvalue = buf_get_u32(r->value, 0, 32); + if (regvalue != scratchpad->context[i]) { + LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", + r->name, scratchpad->context[i]); + buf_set_u32(r->value, 0, 32, scratchpad->context[i]); + r->valid = 1; + r->dirty = 1; + } } - - return ERROR_OK; } -int armv4_5_run_algorithm_inner(struct target *target, - int num_mem_params, struct mem_param *mem_params, - int num_reg_params, struct reg_param *reg_params, - uint32_t entry_point, uint32_t exit_point, - int timeout_ms, void *arch_info, - int (*run_it)(struct target *target, uint32_t exit_point, - int timeout_ms, void *arch_info)) +int armv4_5_start_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t entry_point, uint32_t exit_point, + void *arch_info) { struct arm *arm = target_to_arm(target); struct arm_algorithm *arm_algorithm_info = arch_info; - enum arm_state core_state = arm->core_state; - uint32_t context[17]; - uint32_t cpsr; - int exit_breakpoint_size = 0; - int i; - int retval = ERROR_OK; + + int ret = ERROR_OK; + + assert(arm_algorithm_info->core_state == ARM_STATE_ARM || + arm_algorithm_info->core_state == ARM_STATE_THUMB); + + assert(arm_algorithm_info->bp_type == BKPT_HARD || + arm_algorithm_info->bp_type == BKPT_SOFT); + + struct armv4_5_algorithm_scratchpad *scratchpad; + + scratchpad = target_allocate_algorithm_scratchpad(target, + sizeof(struct armv4_5_algorithm_scratchpad)); + + if (!scratchpad) { + LOG_ERROR("can't allocate a scratchpad area to run the algorithm"); + return ERROR_FAIL; + } + + scratchpad->core_state = arm->core_state; + scratchpad->arm_algorithm_info = *arm_algorithm_info; LOG_DEBUG("Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV4/5 target"); - return ERROR_TARGET_INVALID; + ret = ERROR_TARGET_INVALID; + goto free_scratchpad; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); - return ERROR_TARGET_NOT_HALTED; + ret = ERROR_TARGET_NOT_HALTED; + goto free_scratchpad; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto free_scratchpad; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->is_armv4) { LOG_ERROR("ARMv4 target needs HW breakpoint location"); - return ERROR_FAIL; + ret = ERROR_FAIL; + goto free_scratchpad; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ - for (i = 0; i <= 16; i++) { + for (unsigned int i = 0; i < ARRAY_SIZE(scratchpad->context); i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, - arm_algorithm_info->core_mode, i); + arm_algorithm_info->core_mode, i); if (!r->valid) arm->read_core_reg(target, r, i, - arm_algorithm_info->core_mode); - context[i] = buf_get_u32(r->value, 0, 32); + arm_algorithm_info->core_mode); + scratchpad->context[i] = buf_get_u32(r->value, 0, 32); + } + scratchpad->cpsr = buf_get_u32(arm->cpsr->value, 0, 32); + + for (int i = 0; i < num_mem_params; i++) { + ret = target_write_buffer(target, mem_params[i].address, mem_params[i].size, + mem_params[i].value); + if (ret != ERROR_OK) { + /* We don't need to restore memory here since + * that would be handled by work area API */ + goto free_scratchpad; + } } - cpsr = buf_get_u32(arm->cpsr->value, 0, 32); - for (i = 0; i < num_mem_params; i++) { - retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, - mem_params[i].value); - if (retval != ERROR_OK) - return retval; - } + for (int i = 0; i < num_reg_params; i++) { + if (reg_params[i].direction == PARAM_IN) + continue; - for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); - return ERROR_COMMAND_SYNTAX_ERROR; + ret = ERROR_COMMAND_SYNTAX_ERROR; + goto restore_registers; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", - reg_params[i].reg_name); - return ERROR_COMMAND_SYNTAX_ERROR; + reg_params[i].reg_name); + ret = ERROR_COMMAND_SYNTAX_ERROR; + goto restore_registers; } - retval = armv4_5_set_core_reg(reg, reg_params[i].value); - if (retval != ERROR_OK) - return retval; + ret = armv4_5_set_core_reg(reg, reg_params[i].value); + if (ret != ERROR_OK) + goto restore_registers; } arm->core_state = arm_algorithm_info->core_state; - if (arm->core_state == ARM_STATE_ARM) - exit_breakpoint_size = 4; - else if (arm->core_state == ARM_STATE_THUMB) - exit_breakpoint_size = 2; - else { - LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); - return ERROR_COMMAND_SYNTAX_ERROR; - } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", - arm_algorithm_info->core_mode); + arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, - arm_algorithm_info->core_mode); + arm_algorithm_info->core_mode); arm->cpsr->dirty = 1; arm->cpsr->valid = 1; } /* terminate using a hardware or (ARMv5+) software breakpoint */ if (exit_point) { - retval = breakpoint_add(target, exit_point, - exit_breakpoint_size, BKPT_HARD); - if (retval != ERROR_OK) { + ret = breakpoint_add(target, exit_point, + (arm->core_state == ARM_STATE_ARM) ? 4 : 2, + arm_algorithm_info->bp_type); + if (ret != ERROR_OK) { LOG_ERROR("can't add HW breakpoint to terminate algorithm"); - return ERROR_TARGET_FAILURE; + ret = ERROR_TARGET_FAILURE; + goto restore_cpsr_and_state; } } - retval = target_resume(target, 0, entry_point, 1, 1); - if (retval != ERROR_OK) - return retval; - retval = run_it(target, exit_point, timeout_ms, arch_info); + ret = target_resume(target, 0, entry_point, 1, 1); + if (ret == ERROR_OK) + return ret; if (exit_point) breakpoint_remove(target, exit_point); - if (retval != ERROR_OK) - return retval; +restore_cpsr_and_state: + arm->core_state = scratchpad->core_state; + armv4_5_restore_cpsr_from_scratchpad(arm, scratchpad); + +restore_registers: + armv4_5_restore_registers_from_scratchpad(arm, scratchpad); + +free_scratchpad: + target_free_algorithm_scratchpad(target); + return ret; +} + + + +static int armv4_5_algorithm_epilogue(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t exit_point) +{ - for (i = 0; i < num_mem_params; i++) { + int ret; + const struct armv4_5_algorithm_scratchpad *scratchpad; + struct arm *arm; + + ret = ERROR_OK; + + arm = target_to_arm(target); + scratchpad = target_get_algorithm_scratchpad(target); + + if (!scratchpad) { + LOG_ERROR("scratchpad area was not previously allocated"); + return ERROR_FAIL; + } + + if (exit_point) + breakpoint_remove(target, exit_point); + + for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { - int retvaltemp = target_read_buffer(target, mem_params[i].address, - mem_params[i].size, - mem_params[i].value); - if (retvaltemp != ERROR_OK) - retval = retvaltemp; + ret = target_read_buffer(target, + mem_params[i].address, + mem_params[i].size, + mem_params[i].value); } } - for (i = 0; i < num_reg_params; i++) { + for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { - struct reg *reg = register_get_by_name(arm->core_cache, - reg_params[i].reg_name, - 0); + reg_params[i].reg_name, + 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); - retval = ERROR_COMMAND_SYNTAX_ERROR; + ret = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { - LOG_ERROR( - "BUG: register '%s' size doesn't match reg_params[i].size", - reg_params[i].reg_name); - retval = ERROR_COMMAND_SYNTAX_ERROR; + LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", + reg_params[i].reg_name); + ret = ERROR_COMMAND_SYNTAX_ERROR; continue; } @@ -1353,52 +1407,113 @@ int armv4_5_run_algorithm_inner(struct target *target, } } - /* restore everything we saved before (17 or 18 registers) */ - for (i = 0; i <= 16; i++) { - uint32_t regvalue; - regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, - arm_algorithm_info->core_mode, i).value, 0, 32); - if (regvalue != context[i]) { - LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", - ARMV4_5_CORE_REG_MODE(arm->core_cache, - arm_algorithm_info->core_mode, i).name, context[i]); - buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, - arm_algorithm_info->core_mode, i).value, 0, 32, context[i]); - ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, - i).valid = 1; - ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, - i).dirty = 1; + armv4_5_restore_registers_from_scratchpad(arm, scratchpad); + armv4_5_restore_cpsr_from_scratchpad(arm, scratchpad); + arm->core_state = scratchpad->core_state; + + target_free_algorithm_scratchpad(target); + + return ret; +} + +int armv4_5_wait_algorithm(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t exit_point, int timeout_ms, + void *arch_info) +{ + int ret, err; + struct arm *arm = target_to_arm(target); + + ret = target_wait_state(target, TARGET_HALTED, timeout_ms); + + if (ret != ERROR_OK || + target->state != TARGET_HALTED) { + ret = target_halt(target); + if (ret != ERROR_OK) + goto free_scratchpad; + + ret = target_wait_state(target, TARGET_HALTED, 500); + if (ret != ERROR_OK) + goto free_scratchpad; + + ret = ERROR_TARGET_TIMEOUT; + } else { + /* fast exit: ARMv5+ code can use BKPT */ + if (exit_point && buf_get_u32(arm->pc->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(arm->pc->value, 0, 32)); + ret = ERROR_TARGET_TIMEOUT; } } - arm_set_cpsr(arm, cpsr); - arm->cpsr->dirty = 1; + err = armv4_5_algorithm_epilogue(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point); + return ret ?: err; - arm->core_state = core_state; +free_scratchpad: + target_free_algorithm_scratchpad(target); + return ret; +} - return retval; +int armv4_5_run_algorithm_inner(struct target *target, + int num_mem_params, struct mem_param *mem_params, + int num_reg_params, struct reg_param *reg_params, + uint32_t entry_point, uint32_t exit_point, + int timeout_ms, void *arch_info, + int (*run_it)(struct target *target, uint32_t exit_point, + int timeout_ms, void *arch_info)) +{ + int ret, err; + + ret = armv4_5_start_algorithm(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, exit_point, + arch_info); + + if (ret != ERROR_OK) + return ret; + + ret = run_it(target, exit_point, timeout_ms, arch_info); + + err = armv4_5_algorithm_epilogue(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point); + + return ret ?: err; } + int armv4_5_run_algorithm(struct target *target, - int num_mem_params, - struct mem_param *mem_params, - int num_reg_params, - struct reg_param *reg_params, - uint32_t entry_point, - uint32_t exit_point, - int timeout_ms, - void *arch_info) + int num_mem_params, + struct mem_param *mem_params, + int num_reg_params, + struct reg_param *reg_params, + uint32_t entry_point, + uint32_t exit_point, + int timeout_ms, + void *arch_info) { - return armv4_5_run_algorithm_inner(target, - num_mem_params, - mem_params, - num_reg_params, - reg_params, - entry_point, - exit_point, - timeout_ms, - arch_info, - armv4_5_run_algorithm_completion); + int ret; + + ret = armv4_5_start_algorithm(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + entry_point, exit_point, + arch_info); + + if (ret == ERROR_OK) + ret = armv4_5_wait_algorithm(target, + num_mem_params, mem_params, + num_reg_params, reg_params, + exit_point, timeout_ms, + arch_info); + return ret; } /** diff --git a/src/target/cortex_a.c b/src/target/cortex_a.c index 2ed178b..b30ee10 100644 --- a/src/target/cortex_a.c +++ b/src/target/cortex_a.c @@ -2757,7 +2757,9 @@ struct target_type cortexa_target = { .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, + .start_algorithm = armv4_5_start_algorithm, .run_algorithm = armv4_5_run_algorithm, + .wait_algorithm = armv4_5_wait_algorithm, .add_breakpoint = cortex_a_add_breakpoint, .add_context_breakpoint = cortex_a_add_context_breakpoint, @@ -2834,7 +2836,9 @@ struct target_type cortexr4_target = { .checksum_memory = arm_checksum_memory, .blank_check_memory = arm_blank_check_memory, + .start_algorithm = armv4_5_start_algorithm, .run_algorithm = armv4_5_run_algorithm, + .wait_algorithm = armv4_5_wait_algorithm, .add_breakpoint = cortex_a_add_breakpoint, .add_context_breakpoint = cortex_a_add_context_breakpoint, -- ------------------------------------------------------------------------------ _______________________________________________ OpenOCD-devel mailing list [email protected] https://lists.sourceforge.net/lists/listinfo/openocd-devel
