static int arm920t_read_cp15_interpreted(struct target *target, uint32_t cp15_opcode, uint32_t address, uint32_t *value) { struct arm *armv4_5 = target_to_arm(target); uint32_t* regs_p[1]; uint32_t regs[2]; uint32_t cp15c15 = 0x0; struct reg *r = armv4_5->core_cache->reg_list; /* load address into R1 */ regs[1] = address; arm9tdmi_write_core_regs(target, 0x2, regs); /* read-modify-write CP15 test state register * to enable interpreted access mode */ arm920t_read_cp15_physical(target, CP15PHYS_TESTSTATE, &cp15c15); jtag_execute_queue(); cp15c15 |= 1; /* set interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* execute CP15 instruction and ARM load (reading from coprocessor) */ arm920t_execute_cp15(target, cp15_opcode, ARMV4_5_LDR(0, 1)); /* disable interpreted access mode */ cp15c15 &= ~1U; /* clear interpret mode */ arm920t_write_cp15_physical(target, CP15PHYS_TESTSTATE, cp15c15); /* retrieve value from R0 */ regs_p[0] = value; arm9tdmi_read_core_regs(target, 0x1, regs_p); jtag_execute_queue(); #ifdef _DEBUG_INSTRUCTION_EXECUTION_ LOG_DEBUG("cp15_opcode: %8.8x, address: %8.8x, value: %8.8x", cp15_opcode, address, *value); #endif if (!is_arm_mode(armv4_5->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } r[0].dirty = 1; r[1].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)) { 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 arm_get_gdb_reg_list(struct target *target, struct reg **reg_list[], int *reg_list_size, enum target_register_class reg_class) { struct arm *arm = target_to_arm(target); unsigned int i; if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } switch (reg_class) { case REG_CLASS_GENERAL: *reg_list_size = 26; *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) (*reg_list)[i] = arm_reg_current(arm, i); /* For GDB compatibility, take FPA registers size into account and zero-fill it*/ for (i = 16; i < 24; i++) (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[25] = arm->cpsr; return ERROR_OK; break; case REG_CLASS_ALL: *reg_list_size = (arm->core_type != ARM_MODE_MON ? 48 : 51); *reg_list = malloc(sizeof(struct reg *) * (*reg_list_size)); for (i = 0; i < 16; i++) (*reg_list)[i] = arm_reg_current(arm, i); for (i = 13; i < ARRAY_SIZE(arm_core_regs); i++) { int reg_index = arm->core_cache->reg_list[i].number; if (!(arm_core_regs[i].mode == ARM_MODE_MON && arm->core_type != ARM_MODE_MON)) (*reg_list)[reg_index] = &(arm->core_cache->reg_list[i]); } /* When we supply the target description, there is no need for fake FPA */ for (i = 16; i < 24; i++) { (*reg_list)[i] = &arm_gdb_dummy_fp_reg; (*reg_list)[i]->size = 0; } (*reg_list)[24] = &arm_gdb_dummy_fps_reg; (*reg_list)[24]->size = 0; return ERROR_OK; break; default: LOG_ERROR("not a valid register class type in query."); return ERROR_FAIL; break; } }