static int dpm_add_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (bp->length < 2) return ERROR_COMMAND_SYNTAX_ERROR; if (!dpm->bpwp_enable) return retval; /* FIXME we need a generic solution for software breakpoints. */ if (bp->type == BKPT_SOFT) LOG_DEBUG("using HW bkpt, not SW..."); for (unsigned i = 0; i < dpm->nbp; i++) { if (!dpm->dbp[i].bp) { retval = dpm_bpwp_setup(dpm, &dpm->dbp[i].bpwp, bp->address, bp->length); if (retval == ERROR_OK) dpm->dbp[i].bp = bp; break; } } return retval; }
static int swd_init(struct command_context *ctx) { struct target *target = get_current_target(ctx); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t idcode; int status; /* FIXME validate transport config ... is the * configured DAP present (check IDCODE)? * Is *only* one DAP configured? * * MUST READ IDCODE */ /* Note, debugport_init() does setup too */ uint8_t ack; status = swd_queue_idcode_read(dap, &ack, &idcode); if (status == ERROR_OK) LOG_INFO("SWD IDCODE %#8.8x", idcode); return status; }
/* 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) { 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; } /* 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; } return ERROR_OK; }
/** * Put the debug link into SWD mode, if the target supports it. * The link's initial mode may be either JTAG (for example, * with SWJ-DP after reset) or SWD. * * @param target Enters SWD mode (if possible). * * Note that targets using the JTAG-DP do not support SWD, and that * some targets which could otherwise support it may have have been * configured to disable SWD signaling * * @return ERROR_OK or else a fault code. */ int dap_to_swd(struct target *target) { struct arm *arm = target_to_arm(target); int retval; if (!arm->dap) { LOG_ERROR("SWD mode is not available"); return ERROR_FAIL; } LOG_DEBUG("Enter SWD mode"); /* REVISIT it's ugly to need to make calls to a "jtag" * subsystem if the link may not be in JTAG mode... */ retval = jtag_add_tms_seq(8 * sizeof(jtag2swd_bitseq), jtag2swd_bitseq, TAP_INVALID); if (retval == ERROR_OK) retval = jtag_execute_queue(); /* set up the DAP's ops vector for SWD mode. */ arm->dap->ops = &swd_dap_ops; return retval; }
static void arm9tdmi_build_reg_cache(struct target *target) { struct reg_cache **cache_p = register_get_last_cache_p(&target->reg_cache); struct arm *arm = target_to_arm(target); (*cache_p) = arm_build_reg_cache(target, arm); }
static int cmsis_dap_init(struct command_context *ctx) { struct target *target = get_current_target(ctx); struct arm *arm = target_to_arm(target); struct adiv5_dap *dap = arm->dap; uint32_t idcode; int status; LOG_DEBUG("CMSIS-ADI: cmsis_dap_init"); /* Force the DAP's ops vector for CMSIS-DAP mode. * messy - is there a better way? */ arm->dap->ops = &cmsis_dap_ops; /* FIXME validate transport config ... is the * configured DAP present (check IDCODE)? * Is *only* one DAP configured? * * MUST READ IDCODE */ /* Note, debugport_init() does setup too */ #if 0 const struct swd_driver *swd = jtag_interface->swd; if (!swd || !swd->read_reg || !swd->write_reg || !swd->init) { LOG_ERROR("no SWD driver?"); return ERROR_FAIL; } int retval = swd->init(1); if (retval != ERROR_OK) { LOG_ERROR("unable to init CMSIS-DAP driver"); return retval; } #endif uint8_t ack; status = cmsis_dap_queue_idcode_read(dap, &ack, &idcode); if (status == ERROR_OK) LOG_INFO("IDCODE 0x%08" PRIx32, idcode); /* force clear all sticky faults */ cmsis_dap_queue_ap_abort(dap, &ack); /* this is a workaround to get polling working */ jtag_add_reset(0, 0); return status; }
static int get_gdb_fileio_info(struct target *target, struct gdb_fileio_info *fileio_info) { struct arm *arm = target_to_arm(target); /* To avoid uneccessary duplication, semihosting prepares the * fileio_info structure out-of-band when the target halts. See * do_semihosting for more detail. */ if (!arm->is_semihosting_fileio || !arm->semihosting_hit_fileio) return ERROR_FAIL; return ERROR_OK; }
static int arm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); unsigned num_regs = arm->core_cache->num_regs; struct reg *reg = arm->core_cache->reg_list; int retval = ERROR_OK; for (; num_regs && retval == ERROR_OK; num_regs--, reg++) { if (reg->valid) continue; retval = armv4_5_get_core_reg(reg); } return retval; }
static int armv7m_get_core_reg(struct reg *reg) { int retval; struct arm_reg *armv7m_reg = reg->arch_info; struct target *target = armv7m_reg->target; struct arm *arm = target_to_arm(target); if (target->state != TARGET_HALTED) return ERROR_TARGET_NOT_HALTED; retval = arm->read_core_reg(target, reg, armv7m_reg->num, arm->core_mode); return retval; }
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; }
static int dpm_add_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE; if (dpm->bpwp_enable) { for (unsigned i = 0; i < dpm->nwp; i++) { if (!dpm->dwp[i].wp) { retval = dpm_watchpoint_setup(dpm, i, wp); break; } } } return retval; }
static int post_result(struct target *target) { struct arm *arm = target_to_arm(target); /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target)) || is_armv7a(target_to_armv7a(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result); arm->core_cache->reg_list[0].dirty = 1; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = 1; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = 1; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, arm->semihosting_result); arm->core_cache->reg_list[0].dirty = 1; } return ERROR_OK; }
static int dpm_remove_watchpoint(struct target *target, struct watchpoint *wp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_COMMAND_SYNTAX_ERROR; for (unsigned i = 0; i < dpm->nwp; i++) { if (dpm->dwp[i].wp == wp) { dpm->dwp[i].wp = NULL; dpm->dwp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; }
static int dpm_remove_breakpoint(struct target *target, struct breakpoint *bp) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval = ERROR_INVALID_ARGUMENTS; for (unsigned i = 0; i < dpm->nbp; i++) { if (dpm->dbp[i].bp == bp) { dpm->dbp[i].bp = NULL; dpm->dbp[i].bpwp.dirty = true; /* hardware is updated in write_dirty_registers() */ retval = ERROR_OK; break; } } return retval; }
int arm_arch_state(struct target *target) { struct arm *arm = target_to_arm(target); if (arm->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("BUG: called for a non-ARM target"); return ERROR_FAIL; } LOG_USER("target halted in %s state due to %s, current mode: %s\n" "cpsr: 0x%8.8" PRIx32 " pc: 0x%8.8" PRIx32 "%s", arm_state_strings[arm->core_state], debug_reason_name(target), arm_mode_name(arm->core_mode), buf_get_u32(arm->cpsr->value, 0, 32), buf_get_u32(arm->pc->value, 0, 32), arm->is_semihosting ? ", semihosting" : ""); return ERROR_OK; }
static int armv4_5_set_core_reg(struct reg *reg, uint8_t *buf) { struct arm_reg *reg_arch_info = reg->arch_info; struct target *target = reg_arch_info->target; struct arm *armv4_5_target = target_to_arm(target); uint32_t value = buf_get_u32(buf, 0, 32); if (target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* Except for CPSR, the "reg" command exposes a writeback model * for the register cache. */ if (reg == armv4_5_target->cpsr) { arm_set_cpsr(armv4_5_target, value); /* Older cores need help to be in ARM mode during halt * mode debug, so we clear the J and T bits if we flush. * For newer cores (v6/v7a/v7r) we don't need that, but * it won't hurt since CPSR is always flushed anyway. */ if (armv4_5_target->core_mode != (enum arm_mode)(value & 0x1f)) { LOG_DEBUG("changing ARM core mode to '%s'", arm_mode_name(value & 0x1f)); value &= ~((1 << 24) | (1 << 5)); uint8_t t[4]; buf_set_u32(t, 0, 32, value); armv4_5_target->write_core_reg(target, reg, 16, ARM_MODE_ANY, t); } } else { buf_set_u32(reg->value, 0, 32, value); reg->valid = 1; } reg->dirty = 1; return ERROR_OK; }
static int arm_dpm_read_core_reg(struct target *target, struct reg *r, int regnum, enum arm_mode mode) { struct arm_dpm *dpm = target_to_arm(target)->dpm; int retval; if (regnum < 0 || regnum > 16) return ERROR_COMMAND_SYNTAX_ERROR; if (regnum == 16) { if (mode != ARM_MODE_ANY) regnum = 17; } else mode = dpm_mapmode(dpm->arm, regnum, mode); /* REVISIT what happens if we try to read SPSR in a core mode * which has no such register? */ retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; if (mode != ARM_MODE_ANY) { retval = dpm_modeswitch(dpm, mode); if (retval != ERROR_OK) goto fail; } retval = dpm_read_reg(dpm, r, regnum); if (retval != ERROR_OK) goto fail; /* always clean up, regardless of error */ if (mode != ARM_MODE_ANY) /* (void) */ dpm_modeswitch(dpm, ARM_MODE_ANY); fail: /* (void) */ dpm->finish(dpm); return retval; }
static int gdb_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c) { struct arm *arm = target_to_arm(target); struct gdb_fileio_info *fileio_info = target->fileio_info; /* clear pending status */ arm->semihosting_hit_fileio = false; arm->semihosting_result = result; arm->semihosting_errno = fileio_errno; /* Some fileio results do not match up with what the semihosting * operation expects; for these operations, we munge the results * below: */ switch (arm->semihosting_op) { case 0x05: /* SYS_WRITE */ if (result < 0) arm->semihosting_result = fileio_info->param_3; else arm->semihosting_result = 0; break; case 0x06: /* SYS_READ */ if (result == (int)fileio_info->param_3) arm->semihosting_result = 0; if (result <= 0) arm->semihosting_result = fileio_info->param_3; break; case 0x0a: /* SYS_SEEK */ if (result > 0) arm->semihosting_result = 0; break; } return post_result(target); }
/* Read coprocessor */ static int dpm_mrc(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t *value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MRC p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) CRn, (int) CRm, (int) op2); /* read coprocessor register into R0; return via DCC */ retval = dpm->instr_read_data_r0(dpm, ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2), value); /* (void) */ dpm->finish(dpm); return retval; }
static int dpm_mcr(struct target *target, int cpnum, uint32_t op1, uint32_t op2, uint32_t CRn, uint32_t CRm, uint32_t value) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; int retval; retval = dpm->prepare(dpm); if (retval != ERROR_OK) return retval; LOG_DEBUG("MCR p%d, %d, r0, c%d, c%d, %d", cpnum, (int) op1, (int) CRn, (int) CRm, (int) op2); /* read DCC into r0; then write coprocessor register from R0 */ retval = dpm->instr_write_data_r0(dpm, ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2), value); /* (void) */ dpm->finish(dpm); return retval; }
/** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t check_code_le[] = { #include "../../contrib/loaders/erase_check/armv4_5_erase_check.inc" }; assert(sizeof(check_code_le) % 4 == 0); /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code_le), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code_le) / 4; i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&check_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = check_algorithm->address + sizeof(check_code_le) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval == ERROR_OK) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, check_algorithm); return retval; }
/** * Checks for and processes an ARM semihosting request. This is meant * to be called when the target is stopped due to a debug mode entry. * If the value 0 is returned then there was nothing to process. A non-zero * return value signifies that a request was processed and the target resumed, * or an error was encountered, in which case the caller must return * immediately. * * @param target Pointer to the ARM target to process. This target must * not represent an ARMv6-M or ARMv7-M processor. * @param retval Pointer to a location where the return code will be stored * @return non-zero value if a request was processed or an error encountered */ int arm_semihosting(struct target *target, int *retval) { struct arm *arm = target_to_arm(target); uint32_t pc, lr, spsr; struct reg *r; if (!arm->is_semihosting) return 0; if (is_arm7_9(target_to_arm7_9(target))) { if (arm->core_mode != ARM_MODE_SVC) return 0; /* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */ r = arm->pc; pc = buf_get_u32(r->value, 0, 32); if (pc != 0x00000008 && pc != 0xffff0008) return 0; r = arm_reg_current(arm, 14); lr = buf_get_u32(r->value, 0, 32); /* Core-specific code should make sure SPSR is retrieved * when the above checks pass... */ if (!arm->spsr->valid) { LOG_ERROR("SPSR not valid!"); *retval = ERROR_FAIL; return 1; } spsr = buf_get_u32(arm->spsr->value, 0, 32); /* check instruction that triggered this trap */ if (spsr & (1 << 5)) { /* was in Thumb (or ThumbEE) mode */ uint8_t insn_buf[2]; uint16_t insn; *retval = target_read_memory(target, lr-2, 2, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u16(target, insn_buf); /* SVC 0xab */ if (insn != 0xDFAB) return 0; } else if (spsr & (1 << 24)) { /* was in Jazelle mode */ return 0; } else { /* was in ARM mode */ uint8_t insn_buf[4]; uint32_t insn; *retval = target_read_memory(target, lr-4, 4, 1, insn_buf); if (*retval != ERROR_OK) return 1; insn = target_buffer_get_u32(target, insn_buf); /* SVC 0x123456 */ if (insn != 0xEF123456) return 0; } } else if (is_armv7m(target_to_armv7m(target))) { uint16_t insn; if (target->debug_reason != DBG_REASON_BREAKPOINT) return 0; r = arm->pc; pc = buf_get_u32(r->value, 0, 32); pc &= ~1; *retval = target_read_u16(target, pc, &insn); if (*retval != ERROR_OK) return 1; /* bkpt 0xAB */ if (insn != 0xBEAB) return 0; } else { LOG_ERROR("Unsupported semi-hosting Target"); return 0; } *retval = do_semihosting(target); return 1; }
static int do_semihosting(struct target *target) { struct arm *arm = target_to_arm(target); uint32_t r0 = buf_get_u32(arm->core_cache->reg_list[0].value, 0, 32); uint32_t r1 = buf_get_u32(arm->core_cache->reg_list[1].value, 0, 32); uint8_t params[16]; int retval, result; /* * TODO: lots of security issues are not considered yet, such as: * - no validation on target provided file descriptors * - no safety checks on opened/deleted/renamed file paths * Beware the target app you use this support with. * * TODO: explore mapping requests to GDB's "File-I/O Remote * Protocol Extension" ... when GDB is active. */ switch (r0) { case 0x01: /* SYS_OPEN */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t m = target_buffer_get_u32(target, params+4); uint32_t l = target_buffer_get_u32(target, params+8); if (l <= 255 && m <= 11) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; if (strcmp((char *)fn, ":tt") == 0) { if (m < 4) result = dup(STDIN_FILENO); else result = dup(STDOUT_FILENO); } else { /* cygwin requires the permission setting * otherwise it will fail to reopen a previously * written file */ result = open((char *)fn, open_modeflags[m], 0644); } arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x02: /* SYS_CLOSE */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); result = close(fd); arm->semihosting_errno = errno; } break; case 0x03: /* SYS_WRITEC */ { unsigned char c; retval = target_read_memory(target, r1, 1, 1, &c); if (retval != ERROR_OK) return retval; putchar(c); result = 0; } break; case 0x04: /* SYS_WRITE0 */ do { unsigned char c; retval = target_read_memory(target, r1++, 1, 1, &c); if (retval != ERROR_OK) return retval; if (!c) break; putchar(c); } while (1); result = 0; break; case 0x05: /* SYS_WRITE */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); size_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { retval = target_read_buffer(target, a, l, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = write(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) result = l - result; free(buf); } } break; case 0x06: /* SYS_READ */ retval = target_read_memory(target, r1, 4, 3, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); uint32_t a = target_buffer_get_u32(target, params+4); ssize_t l = target_buffer_get_u32(target, params+8); uint8_t *buf = malloc(l); if (!buf) { result = -1; arm->semihosting_errno = ENOMEM; } else { result = read(fd, buf, l); arm->semihosting_errno = errno; if (result >= 0) { retval = target_write_buffer(target, a, result, buf); if (retval != ERROR_OK) { free(buf); return retval; } result = l - result; } free(buf); } } break; case 0x07: /* SYS_READC */ result = getchar(); break; case 0x08: /* SYS_ISERROR */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = (target_buffer_get_u32(target, params+0) != 0); break; case 0x09: /* SYS_ISTTY */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; result = isatty(target_buffer_get_u32(target, params+0)); break; case 0x0a: /* SYS_SEEK */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); off_t pos = target_buffer_get_u32(target, params+4); result = lseek(fd, pos, SEEK_SET); arm->semihosting_errno = errno; if (result == pos) result = 0; } break; case 0x0c: /* SYS_FLEN */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { int fd = target_buffer_get_u32(target, params+0); struct stat buf; result = fstat(fd, &buf); if (result == -1) { arm->semihosting_errno = errno; result = -1; break; } result = buf.st_size; } break; case 0x0e: /* SYS_REMOVE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); if (l <= 255) { uint8_t fn[256]; retval = target_read_memory(target, a, 1, l, fn); if (retval != ERROR_OK) return retval; fn[l] = 0; result = remove((char *)fn); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x0f: /* SYS_RENAME */ retval = target_read_memory(target, r1, 4, 4, params); if (retval != ERROR_OK) return retval; else { uint32_t a1 = target_buffer_get_u32(target, params+0); uint32_t l1 = target_buffer_get_u32(target, params+4); uint32_t a2 = target_buffer_get_u32(target, params+8); uint32_t l2 = target_buffer_get_u32(target, params+12); if (l1 <= 255 && l2 <= 255) { uint8_t fn1[256], fn2[256]; retval = target_read_memory(target, a1, 1, l1, fn1); if (retval != ERROR_OK) return retval; retval = target_read_memory(target, a2, 1, l2, fn2); if (retval != ERROR_OK) return retval; fn1[l1] = 0; fn2[l2] = 0; result = rename((char *)fn1, (char *)fn2); arm->semihosting_errno = errno; } else { result = -1; arm->semihosting_errno = EINVAL; } } break; case 0x11: /* SYS_TIME */ result = time(NULL); break; case 0x13: /* SYS_ERRNO */ result = arm->semihosting_errno; break; case 0x15: /* SYS_GET_CMDLINE */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); uint32_t l = target_buffer_get_u32(target, params+4); char *arg = "foobar"; uint32_t s = strlen(arg) + 1; if (l < s) result = -1; else { retval = target_write_buffer(target, a, s, (uint8_t *)arg); if (retval != ERROR_OK) return retval; result = 0; } } break; case 0x16: /* SYS_HEAPINFO */ retval = target_read_memory(target, r1, 4, 1, params); if (retval != ERROR_OK) return retval; else { uint32_t a = target_buffer_get_u32(target, params+0); /* tell the remote we have no idea */ memset(params, 0, 4*4); retval = target_write_memory(target, a, 4, 4, params); if (retval != ERROR_OK) return retval; result = 0; } break; case 0x18: /* angel_SWIreason_ReportException */ switch (r1) { case 0x20026: /* ADP_Stopped_ApplicationExit */ fprintf(stderr, "semihosting: *** application exited ***\n"); break; case 0x20000: /* ADP_Stopped_BranchThroughZero */ case 0x20001: /* ADP_Stopped_UndefinedInstr */ case 0x20002: /* ADP_Stopped_SoftwareInterrupt */ case 0x20003: /* ADP_Stopped_PrefetchAbort */ case 0x20004: /* ADP_Stopped_DataAbort */ case 0x20005: /* ADP_Stopped_AddressException */ case 0x20006: /* ADP_Stopped_IRQ */ case 0x20007: /* ADP_Stopped_FIQ */ case 0x20020: /* ADP_Stopped_BreakPoint */ case 0x20021: /* ADP_Stopped_WatchPoint */ case 0x20022: /* ADP_Stopped_StepComplete */ case 0x20023: /* ADP_Stopped_RunTimeErrorUnknown */ case 0x20024: /* ADP_Stopped_InternalError */ case 0x20025: /* ADP_Stopped_UserInterruption */ case 0x20027: /* ADP_Stopped_StackOverflow */ case 0x20028: /* ADP_Stopped_DivisionByZero */ case 0x20029: /* ADP_Stopped_OSSpecific */ default: fprintf(stderr, "semihosting: exception %#x\n", (unsigned) r1); } return target_call_event_callbacks(target, TARGET_EVENT_HALTED); case 0x12: /* SYS_SYSTEM */ /* Provide SYS_SYSTEM functionality. Uses the * libc system command, there may be a reason *NOT* * to use this, but as I can't think of one, I * implemented it this way. */ retval = target_read_memory(target, r1, 4, 2, params); if (retval != ERROR_OK) return retval; else { uint32_t len = target_buffer_get_u32(target, params+4); uint32_t c_ptr = target_buffer_get_u32(target, params); uint8_t cmd[256]; if (len > 255) { result = -1; arm->semihosting_errno = EINVAL; } else { memset(cmd, 0x0, 256); retval = target_read_memory(target, c_ptr, 1, len, cmd); if (retval != ERROR_OK) return retval; else result = system((const char *)cmd); } } break; case 0x0d: /* SYS_TMPNAM */ case 0x10: /* SYS_CLOCK */ case 0x17: /* angel_SWIreason_EnterSVC */ case 0x30: /* SYS_ELAPSED */ case 0x31: /* SYS_TICKFREQ */ default: fprintf(stderr, "semihosting: unsupported call %#x\n", (unsigned) r0); result = -1; arm->semihosting_errno = ENOTSUP; } /* resume execution to the original mode */ /* REVISIT this looks wrong ... ARM11 and Cortex-A8 * should work this way at least sometimes. */ if (is_arm7_9(target_to_arm7_9(target))) { uint32_t spsr; /* return value in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; /* LR --> PC */ buf_set_u32(arm->core_cache->reg_list[15].value, 0, 32, buf_get_u32(arm_reg_current(arm, 14)->value, 0, 32)); arm->core_cache->reg_list[15].dirty = 1; /* saved PSR --> current PSR */ spsr = buf_get_u32(arm->spsr->value, 0, 32); /* REVISIT should this be arm_set_cpsr(arm, spsr) * instead of a partially unrolled version? */ buf_set_u32(arm->cpsr->value, 0, 32, spsr); arm->cpsr->dirty = 1; arm->core_mode = spsr & 0x1f; if (spsr & 0x20) arm->core_state = ARM_STATE_THUMB; } else { /* resume execution, this will be pc+2 to skip over the * bkpt instruction */ /* return result in R0 */ buf_set_u32(arm->core_cache->reg_list[0].value, 0, 32, result); arm->core_cache->reg_list[0].dirty = 1; } return target_resume(target, 1, 0, 0, 0); }
static int jim_mcrmrc(Jim_Interp *interp, int argc, Jim_Obj * const *argv) { struct command_context *context; struct target *target; struct arm *arm; int retval; context = current_command_context(interp); assert(context != NULL); target = get_current_target(context); if (target == NULL) { LOG_ERROR("%s: no current target", __func__); return JIM_ERR; } if (!target_was_examined(target)) { LOG_ERROR("%s: not yet examined", target_name(target)); return JIM_ERR; } arm = target_to_arm(target); if (!is_arm(arm)) { LOG_ERROR("%s: not an ARM", target_name(target)); return JIM_ERR; } if ((argc < 6) || (argc > 7)) { /* FIXME use the command name to verify # params... */ LOG_ERROR("%s: wrong number of arguments", __func__); return JIM_ERR; } int cpnum; uint32_t op1; uint32_t op2; uint32_t CRn; uint32_t CRm; uint32_t value; long l; /* NOTE: parameter sequence matches ARM instruction set usage: * MCR pNUM, op1, rX, CRn, CRm, op2 ; write CP from rX * MRC pNUM, op1, rX, CRn, CRm, op2 ; read CP into rX * The "rX" is necessarily omitted; it uses Tcl mechanisms. */ retval = Jim_GetLong(interp, argv[1], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "coprocessor", (int) l); return JIM_ERR; } cpnum = l; retval = Jim_GetLong(interp, argv[2], &l); if (retval != JIM_OK) return retval; if (l & ~0x7) { LOG_ERROR("%s: %s %d out of range", __func__, "op1", (int) l); return JIM_ERR; } op1 = l; retval = Jim_GetLong(interp, argv[3], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "CRn", (int) l); return JIM_ERR; } CRn = l; retval = Jim_GetLong(interp, argv[4], &l); if (retval != JIM_OK) return retval; if (l & ~0xf) { LOG_ERROR("%s: %s %d out of range", __func__, "CRm", (int) l); return JIM_ERR; } CRm = l; retval = Jim_GetLong(interp, argv[5], &l); if (retval != JIM_OK) return retval; if (l & ~0x7) { LOG_ERROR("%s: %s %d out of range", __func__, "op2", (int) l); return JIM_ERR; } op2 = l; value = 0; /* FIXME don't assume "mrc" vs "mcr" from the number of params; * that could easily be a typo! Check both... * * FIXME change the call syntax here ... simplest to just pass * the MRC() or MCR() instruction to be executed. That will also * let us support the "mrc2" and "mcr2" opcodes (toggling one bit) * if that's ever needed. */ if (argc == 7) { retval = Jim_GetLong(interp, argv[6], &l); if (retval != JIM_OK) return retval; value = l; /* NOTE: parameters reordered! */ /* ARMV4_5_MCR(cpnum, op1, 0, CRn, CRm, op2) */ retval = arm->mcr(target, cpnum, op1, op2, CRn, CRm, value); if (retval != ERROR_OK) return JIM_ERR; } else { /* NOTE: parameters reordered! */ /* ARMV4_5_MRC(cpnum, op1, 0, CRn, CRm, op2) */ retval = arm->mrc(target, cpnum, op1, op2, CRn, CRm, &value); if (retval != ERROR_OK) return JIM_ERR; Jim_SetResult(interp, Jim_NewIntObj(interp, value)); } return JIM_OK; }
/** * Runs ARM code in the target to check whether a memory block holds * all ones. NOR flash which has been erased, and thus may be written, * holds all ones. * */ int arm_blank_check_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *blank) { struct working_area *check_algorithm; struct reg_param reg_params[3]; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/erase_check/armv4_5_erase_check.s for src */ static const uint32_t check_code[] = { /* loop: */ 0xe4d03001, /* ldrb r3, [r0], #1 */ 0xe0022003, /* and r2, r2, r3 */ 0xe2511001, /* subs r1, r1, #1 */ 0x1afffffb, /* bne loop */ /* end: */ 0xe1200070, /* bkpt #0 */ }; /* make sure we have a working area */ retval = target_alloc_working_area(target, sizeof(check_code), &check_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(check_code); i++) { retval = target_write_u32(target, check_algorithm->address + i * sizeof(uint32_t), check_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = check_algorithm->address + sizeof(check_code) - 4; retval = target_run_algorithm(target, 0, NULL, 3, reg_params, check_algorithm->address, exit_var, 10000, &arm_algo); if (retval != ERROR_OK) { destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return retval; } *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, check_algorithm); return ERROR_OK; }
/** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; /* see contrib/loaders/checksum/armv4_5_crc.s for src */ static const uint32_t arm_crc_code[] = { 0xE1A02000, /* mov r2, r0 */ 0xE3E00000, /* mov r0, #0xffffffff */ 0xE1A03001, /* mov r3, r1 */ 0xE3A04000, /* mov r4, #0 */ 0xEA00000B, /* b ncomp */ /* nbyte: */ 0xE7D21004, /* ldrb r1, [r2, r4] */ 0xE59F7030, /* ldr r7, CRC32XOR */ 0xE0200C01, /* eor r0, r0, r1, asl 24 */ 0xE3A05000, /* mov r5, #0 */ /* loop: */ 0xE3500000, /* cmp r0, #0 */ 0xE1A06080, /* mov r6, r0, asl #1 */ 0xE2855001, /* add r5, r5, #1 */ 0xE1A00006, /* mov r0, r6 */ 0xB0260007, /* eorlt r0, r6, r7 */ 0xE3550008, /* cmp r5, #8 */ 0x1AFFFFF8, /* bne loop */ 0xE2844001, /* add r4, r4, #1 */ /* ncomp: */ 0xE1540003, /* cmp r4, r3 */ 0x1AFFFFF1, /* bne nbyte */ /* end: */ 0xe1200070, /* bkpt #0 */ /* CRC32XOR: */ 0x04C11DB7 /* .word 0x04C11DB7 */ }; retval = target_alloc_working_area(target, sizeof(arm_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code); i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), arm_crc_code[i]); if (retval != ERROR_OK) return retval; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = crc_algorithm->address + sizeof(arm_crc_code) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval != ERROR_OK) { LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); return retval; } *checksum = buf_get_u32(reg_params[0].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); target_free_working_area(target, crc_algorithm); 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; } }
static int arm_dpm_full_context(struct target *target) { struct arm *arm = target_to_arm(target); struct arm_dpm *dpm = arm->dpm; struct reg_cache *cache = arm->core_cache; int retval; bool did_read; retval = dpm->prepare(dpm); if (retval != ERROR_OK) goto done; do { enum arm_mode mode = ARM_MODE_ANY; did_read = false; /* We "know" arm_dpm_read_current_registers() was called so * the unmapped registers (R0..R7, PC, AND CPSR) and some * view of R8..R14 are current. We also "know" oddities of * register mapping: special cases for R8..R12 and SPSR. * * Pick some mode with unread registers and read them all. * Repeat until done. */ for (unsigned i = 0; i < cache->num_regs; i++) { struct arm_reg *r; if (cache->reg_list[i].valid) continue; r = cache->reg_list[i].arch_info; /* may need to pick a mode and set CPSR */ if (!did_read) { did_read = true; mode = r->mode; /* For regular (ARM_MODE_ANY) R8..R12 * in case we've entered debug state * in FIQ mode we need to patch mode. */ if (mode != ARM_MODE_ANY) retval = dpm_modeswitch(dpm, mode); else retval = dpm_modeswitch(dpm, ARM_MODE_USR); if (retval != ERROR_OK) goto done; } if (r->mode != mode) continue; /* CPSR was read, so "R16" must mean SPSR */ retval = dpm_read_reg(dpm, &cache->reg_list[i], (r->num == 16) ? 17 : r->num); if (retval != ERROR_OK) goto done; } } while (did_read); retval = dpm_modeswitch(dpm, ARM_MODE_ANY); /* (void) */ dpm->finish(dpm); done: return retval; }
/** * Runs ARM code in the target to calculate a CRC32 checksum. * */ int arm_checksum_memory(struct target *target, uint32_t address, uint32_t count, uint32_t *checksum) { struct working_area *crc_algorithm; struct arm_algorithm arm_algo; struct arm *arm = target_to_arm(target); struct reg_param reg_params[2]; int retval; uint32_t i; uint32_t exit_var = 0; static const uint8_t arm_crc_code_le[] = { #include "../../contrib/loaders/checksum/armv4_5_crc.inc" }; assert(sizeof(arm_crc_code_le) % 4 == 0); retval = target_alloc_working_area(target, sizeof(arm_crc_code_le), &crc_algorithm); if (retval != ERROR_OK) return retval; /* convert code into a buffer in target endianness */ for (i = 0; i < ARRAY_SIZE(arm_crc_code_le) / 4; i++) { retval = target_write_u32(target, crc_algorithm->address + i * sizeof(uint32_t), le_to_h_u32(&arm_crc_code_le[i * 4])); if (retval != ERROR_OK) goto cleanup; } arm_algo.common_magic = ARM_COMMON_MAGIC; arm_algo.core_mode = ARM_MODE_SVC; arm_algo.core_state = ARM_STATE_ARM; init_reg_param(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); /* 20 second timeout/megabyte */ int timeout = 20000 * (1 + (count / (1024 * 1024))); /* armv4 must exit using a hardware breakpoint */ if (arm->is_armv4) exit_var = crc_algorithm->address + sizeof(arm_crc_code_le) - 8; retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address, exit_var, timeout, &arm_algo); if (retval == ERROR_OK) *checksum = buf_get_u32(reg_params[0].value, 0, 32); else LOG_ERROR("error executing ARM crc algorithm"); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }