Esempio n. 1
0
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;
}
Esempio n. 2
0
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;

}
Esempio n. 3
0
/* 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;
}
Esempio n. 4
0
/**
 * 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;
}
Esempio n. 5
0
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);
}
Esempio n. 6
0
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;
}
Esempio n. 8
0
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;
}
Esempio n. 9
0
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;
}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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;
}
Esempio n. 13
0
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;
}
Esempio n. 14
0
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;
}
Esempio n. 15
0
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;
}
Esempio n. 16
0
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;
}
Esempio n. 17
0
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);
}
Esempio n. 19
0
/* 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;
}
Esempio n. 20
0
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;
}
Esempio n. 21
0
/**
 * 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(&reg_params[0], "r0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, count);

	init_reg_param(&reg_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(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);

cleanup:
	target_free_working_area(target, check_algorithm);

	return retval;
}
Esempio n. 22
0
/**
 * 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;
}
Esempio n. 23
0
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);
}
Esempio n. 24
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;
}
Esempio n. 25
0
/**
 * 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(&reg_params[0], "r0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, count);

	init_reg_param(&reg_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(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		destroy_reg_param(&reg_params[2]);
		target_free_working_area(target, check_algorithm);
		return retval;
	}

	*blank = buf_get_u32(reg_params[2].value, 0, 32);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);

	target_free_working_area(target, check_algorithm);

	return ERROR_OK;
}
Esempio n. 26
0
/**
 * 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(&reg_params[0], "r0", 32, PARAM_IN_OUT);
	init_reg_param(&reg_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(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		target_free_working_area(target, crc_algorithm);
		return retval;
	}

	*checksum = buf_get_u32(reg_params[0].value, 0, 32);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);

	target_free_working_area(target, crc_algorithm);

	return ERROR_OK;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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;
	}
}
Esempio n. 29
0
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;
}
Esempio n. 30
0
/**
 * 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(&reg_params[0], "r0", 32, PARAM_IN_OUT);
	init_reg_param(&reg_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(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);

cleanup:
	target_free_working_area(target, crc_algorithm);

	return retval;
}