Example #1
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;
}
Example #2
0
/**
 * ARM-specific bulk write from buffer to address of 8-bit wide NAND.
 * For now this supports ARMv4,ARMv5 and ARMv7-M cores.
 *
 * Enhancements to target_run_algorithm() could enable:
 *   - ARMv6 and ARMv7 cores in ARM mode
 *
 * Different code fragments could handle:
 *   - 16-bit wide data (needs different setup)
 *
 * @param nand Pointer to the arm_nand_data struct that defines the I/O
 * @param data Pointer to the data to be copied to flash
 * @param size Size of the data being copied
 * @return Success or failure of the operation
 */
int arm_nandwrite(struct arm_nand_data *nand, uint8_t *data, int size)
{
	struct target *target = nand->target;
	struct arm_algorithm armv4_5_algo;
	struct armv7m_algorithm armv7m_algo;
	void *arm_algo;
	struct arm *arm = target->arch_info;
	struct reg_param reg_params[3];
	uint32_t target_buf;
	uint32_t exit_var = 0;
	int retval;

	/* Inputs:
	 *  r0	NAND data address (byte wide)
	 *  r1	buffer address
	 *  r2	buffer length
	 */
	static const uint32_t code_armv4_5[] = {
		0xe4d13001,	/* s: ldrb  r3, [r1], #1 */
		0xe5c03000,	/*    strb  r3, [r0]     */
		0xe2522001,	/*    subs  r2, r2, #1   */
		0x1afffffb,	/*    bne   s            */

		/* exit: ARMv4 needs hardware breakpoint */
		0xe1200070,	/* e: bkpt  #0           */
	};

	/* Inputs:
	 *  r0	NAND data address (byte wide)
	 *  r1	buffer address
	 *  r2	buffer length
	 *
	 * see contrib/loaders/flash/armv7m_io.s for src
	 */
	static const uint32_t code_armv7m[] = {
		0x3b01f811,
		0x3a017003,
		0xaffaf47f,
		0xbf00be00,
	};

	int target_code_size = 0;
	const uint32_t *target_code_src = NULL;

	/* set up algorithm */
	if (is_armv7m(target_to_armv7m(target))) {  /* armv7m target */
		armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
		armv7m_algo.core_mode = ARM_MODE_THREAD;
		arm_algo = &armv7m_algo;
		target_code_size = sizeof(code_armv7m);
		target_code_src = code_armv7m;
	} else {
		armv4_5_algo.common_magic = ARM_COMMON_MAGIC;
		armv4_5_algo.core_mode = ARM_MODE_SVC;
		armv4_5_algo.core_state = ARM_STATE_ARM;
		arm_algo = &armv4_5_algo;
		target_code_size = sizeof(code_armv4_5);
		target_code_src = code_armv4_5;
	}

	if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
		retval = arm_code_to_working_area(target, target_code_src, target_code_size,
				nand->chunk_size, &nand->copy_area);
		if (retval != ERROR_OK)
			return retval;
	}

	nand->op = ARM_NAND_WRITE;

	/* copy data to work area */
	target_buf = nand->copy_area->address + target_code_size;
	retval = target_write_buffer(target, target_buf, size, data);
	if (retval != ERROR_OK)
		return retval;

	/* set up parameters */
	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_IN);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_IN);

	buf_set_u32(reg_params[0].value, 0, 32, nand->data);
	buf_set_u32(reg_params[1].value, 0, 32, target_buf);
	buf_set_u32(reg_params[2].value, 0, 32, size);

	/* armv4 must exit using a hardware breakpoint */
	if (arm->is_armv4)
		exit_var = nand->copy_area->address + target_code_size - 4;

	/* use alg to write data from work area to NAND chip */
	retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
			nand->copy_area->address, exit_var, 1000, arm_algo);
	if (retval != ERROR_OK)
		LOG_ERROR("error executing hosted NAND write");

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

	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);
	struct armv7a_common *armv7a = target_to_armv7a(target);
	uint32_t pc, lr, spsr;
	struct reg *r;

	if (!arm->is_semihosting)
		return 0;

	if (is_arm7_9(target_to_arm7_9(target)) ||
	    is_armv7a(armv7a)) {
		uint32_t vbar = 0x00000000;

		if (arm->core_mode != ARM_MODE_SVC)
			return 0;

		if (is_armv7a(armv7a)) {
			struct arm_dpm *dpm = armv7a->arm.dpm;

			*retval = dpm->prepare(dpm);
			if (*retval == ERROR_OK) {
				*retval = dpm->instr_read_data_r0(dpm,
								 ARMV4_5_MRC(15, 0, 0, 12, 0, 0),
								 &vbar);

				dpm->finish(dpm);

				if (*retval != ERROR_OK)
					return 1;
			} else {
				return 1;
			}
		}

		/* Check for PC == 0x00000008 or 0xffff0008: Supervisor Call vector. */
		r = arm->pc;
		pc = buf_get_u32(r->value, 0, 32);
		if (pc != (vbar + 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;
	}

	/* Perform semihosting if we are not waiting on a fileio
	 * operation to complete.
	 */
	if (!arm->semihosting_hit_fileio) {
		*retval = do_semihosting(target);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed semihosting operation");
			return 0;
		}
	}

	/* Post result to target if we are not waiting on a fileio
	 * operation to complete:
	 */
	if (!arm->semihosting_hit_fileio) {
		*retval = post_result(target);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed to post semihosting result");
			return 0;
		}

		*retval = target_resume(target, 1, 0, 0, 0);
		if (*retval != ERROR_OK) {
			LOG_ERROR("Failed to resume target");
			return 0;
		}

		return 1;
	}

	return 0;
}