/** Waits for an algorithm in the target. */ int armv7m_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) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; int retval = ERROR_OK; uint32_t pc; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } retval = target_wait_state(target, TARGET_HALTED, timeout_ms); /* If the target fails to halt due to the breakpoint, force a halt */ if (retval != ERROR_OK || target->state != TARGET_HALTED) { if ((retval = target_halt(target)) != ERROR_OK) return retval; if ((retval = target_wait_state(target, TARGET_HALTED, 500)) != ERROR_OK) { return retval; } return ERROR_TARGET_TIMEOUT; } armv7m->load_core_reg_u32(target, ARMV7M_REGISTER_CORE_GP, 15, &pc); if (exit_point && (pc != exit_point)) { LOG_DEBUG("failed algorithm halted at 0x%" PRIx32 ", expected 0x%" PRIx32 , pc, exit_point); return ERROR_TARGET_TIMEOUT; } /* Read memory values to mem_params[] */ for (int i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } /* Copy core register values to reg_params[] */ for (int i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_INVALID_ARGUMENTS; } 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_INVALID_ARGUMENTS; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } for (int i = ARMV7M_NUM_REGS - 1; i >= 0; i--) { uint32_t regvalue; regvalue = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32); if (regvalue != armv7m_algorithm_info->context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, armv7m->core_cache->reg_list[i].name, armv7m_algorithm_info->context[i]); buf_set_u32(armv7m->core_cache->reg_list[i].value, 0, 32, armv7m_algorithm_info->context[i]); armv7m->core_cache->reg_list[i].valid = 1; armv7m->core_cache->reg_list[i].dirty = 1; } } armv7m->core_mode = armv7m_algorithm_info->core_mode; return retval; }
/** Starts a Thumb algorithm in the target. */ int armv7m_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 armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum armv7m_mode core_mode = armv7m->core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ /* Not needed if core register cache is always consistent with target process state */ for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) { if (!armv7m->core_cache->reg_list[i].valid) armv7m->read_core_reg(target, i); armv7m_algorithm_info->context[i] = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { // TODO: Write only out params if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0); // uint32_t regvalue; if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_INVALID_ARGUMENTS; } 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_INVALID_ARGUMENTS; } // regvalue = buf_get_u32(reg_params[i].value, 0, 32); armv7m_set_core_reg(reg, reg_params[i].value); } if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); 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)) { 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; 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; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* 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; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ for (i = 0; i <= 16; i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, 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); } 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 (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; } 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; } retval = armv4_5_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } 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); buf_set_u32(arm->cpsr->value, 0, 5, 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) { LOG_ERROR("can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } 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); if (exit_point) breakpoint_remove(target, exit_point); if (retval != ERROR_OK) return retval; for (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; } } for (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); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); retval = 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; continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* 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; } } arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; arm->core_state = core_state; return retval; }
int mips32_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) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; enum mips32_isa_mode isa_mode = mips32->isa_mode; uint32_t context[MIPS32NUMCOREREGS]; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (mips32->common_magic != MIPS32_COMMON_MAGIC) { LOG_ERROR("current target isn't a MIPS32 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); } for (i = 0; i < num_mem_params; i++) { if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(mips32->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; } 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; } mips32_set_core_reg(reg, reg_params[i].value); } mips32->isa_mode = mips32_algorithm_info->isa_mode; retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(mips32->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; } 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; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, mips32->core_cache->reg_list[i].name, context[i]); buf_set_u32(mips32->core_cache->reg_list[i].value, 0, 32, context[i]); mips32->core_cache->reg_list[i].valid = 1; mips32->core_cache->reg_list[i].dirty = 1; } } mips32->isa_mode = isa_mode; return ERROR_OK; }
/** Starts a Thumb algorithm in the target. */ int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum arm_mode core_mode = armv7m->arm.core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache * Not needed if core register cache is always consistent with target process state */ for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { armv7m_algorithm_info->context[i] = buf_get_u32( armv7m->arm.core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { /* TODO: Write only out params */ 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++) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); /* uint32_t regvalue; */ if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } 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; } /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */ armv7m_set_core_reg(reg, reg_params[i].value); } if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY && armv7m_algorithm_info->core_mode != core_mode) { /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */ if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) { armv7m_algorithm_info->core_mode = ARM_MODE_THREAD; LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); } LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); return retval; }