Exemplo n.º 1
0
/** Load data into core via DTR then move it to r0 then
 *  execute one instruction via ITR
 *
 *  The final executed instruction (\p opcode) should read data from r0.
 *
 * \pre arm11_run_instr_data_prepare() /  arm11_run_instr_data_finish() block
 *
 * \param arm11		Target state variable.
 * \param opcode	ARM opcode to read r0 act upon it
 * \param data		Data word that will be written to r0 before \p opcode is executed
 *
 */
void arm11_run_instr_data_to_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 data)
{
    /* MRC p14,0,r0,c0,c5,0 */
    arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data);

    arm11_run_instr_no_data1(arm11, opcode);
}
Exemplo n.º 2
0
/** Execute one instruction via ITR
 *  then load r0 into DTR and read DTR from core.
 *
 *  The first executed instruction (\p opcode) should write data to r0.
 *
 * \pre arm11_run_instr_data_prepare() /  arm11_run_instr_data_finish() block
 *
 * \param arm11		Target state variable.
 * \param opcode	ARM opcode to write r0 with the value of interest
 * \param data		Pointer to a data word that receives the value from r0 after \p opcode was executed.
 *
 */
void arm11_run_instr_data_from_core_via_r0(arm11_common_t * arm11, u32 opcode, u32 * data)
{
    arm11_run_instr_no_data1(arm11, opcode);

    /* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */
    arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1);
}
Exemplo n.º 3
0
/** Execute one instruction via ITR
 *  then load r0 into DTR and read DTR from core.
 *
 *  The first executed instruction (\p opcode) should write data to r0.
 *
 * \pre arm11_run_instr_data_prepare() /  arm11_run_instr_data_finish() block
 *
 * \param arm11		Target state variable.
 * \param opcode	ARM opcode to write r0 with the value of interest
 * \param data		Pointer to a data word that receives the value from r0 after \p opcode was executed.
 *
 */
int arm11_run_instr_data_from_core_via_r0(struct arm11_common * arm11, uint32_t opcode, uint32_t * data)
{
	int retval;
	retval = arm11_run_instr_no_data1(arm11, opcode);
	if (retval != ERROR_OK)
		return retval;

	/* MCR p14,0,R0,c0,c5,0 (move r0 -> wDTR -> local var) */
	arm11_run_instr_data_from_core(arm11, 0xEE000E15, data, 1);

	return ERROR_OK;
}
Exemplo n.º 4
0
/** Load data into core via DTR then move it to r0 then
 *  execute one instruction via ITR
 *
 *  The final executed instruction (\p opcode) should read data from r0.
 *
 * \pre arm11_run_instr_data_prepare() /  arm11_run_instr_data_finish() block
 *
 * \param arm11		Target state variable.
 * \param opcode	ARM opcode to read r0 act upon it
 * \param data		Data word that will be written to r0 before \p opcode is executed
 *
 */
int arm11_run_instr_data_to_core_via_r0(struct arm11_common * arm11, uint32_t opcode, uint32_t data)
{
	int retval;
	/* MRC p14,0,r0,c0,c5,0 */
	retval = arm11_run_instr_data_to_core1(arm11, 0xEE100E15, data);
	if (retval != ERROR_OK)
		return retval;

	retval = arm11_run_instr_no_data1(arm11, opcode);
	if (retval != ERROR_OK)
		return retval;

	return ERROR_OK;
}
Exemplo n.º 5
0
/**
 * Save processor state.  This is called after a HALT instruction
 * succeeds, and on other occasions the processor enters debug mode
 * (breakpoint, watchpoint, etc).  Caller has updated arm11->dscr.
 */
static int arm11_debug_entry(struct arm11_common *arm11)
{
	int retval;

	arm11->arm.target->state = TARGET_HALTED;
	arm_dpm_report_dscr(arm11->arm.dpm, arm11->dscr);

	/* REVISIT entire cache should already be invalid !!! */
	register_cache_invalidate(arm11->arm.core_cache);

	/* See e.g. ARM1136 TRM, "14.8.4 Entering Debug state" */

	/* maybe save wDTR (pending DCC write to debug SW, e.g. libdcc) */
	arm11->is_wdtr_saved = !!(arm11->dscr & DSCR_DTR_TX_FULL);
	if (arm11->is_wdtr_saved)
	{
		arm11_add_debug_SCAN_N(arm11, 0x05, ARM11_TAP_DEFAULT);

		arm11_add_IR(arm11, ARM11_INTEST, ARM11_TAP_DEFAULT);

		struct scan_field	chain5_fields[3];

		arm11_setup_field(arm11, 32, NULL,
				&arm11->saved_wdtr, chain5_fields + 0);
		arm11_setup_field(arm11,  1, NULL, NULL,		chain5_fields + 1);
		arm11_setup_field(arm11,  1, NULL, NULL,		chain5_fields + 2);

		arm11_add_dr_scan_vc(arm11->arm.target->tap, ARRAY_SIZE(chain5_fields), chain5_fields, TAP_DRPAUSE);

	}

	/* DSCR: set the Execute ARM instruction enable bit.
	 *
	 * ARM1176 spec says this is needed only for wDTR/rDTR's "ITR mode",
	 * but not to issue ITRs(?).  The ARMv7 arch spec says it's required
	 * for executing instructions via ITR.
	 */
	CHECK_RETVAL(arm11_write_DSCR(arm11, DSCR_ITR_EN | arm11->dscr));


	/* From the spec:
	   Before executing any instruction in debug state you have to drain the write buffer.
	   This ensures that no imprecise Data Aborts can return at a later point:*/

	/** \todo TODO: Test drain write buffer. */

#if 0
	while (1)
	{
		/* MRC p14,0,R0,c5,c10,0 */
		//	arm11_run_instr_no_data1(arm11, /*0xee150e1a*/0xe320f000);

		/* mcr	   15, 0, r0, cr7, cr10, {4} */
		arm11_run_instr_no_data1(arm11, 0xee070f9a);

		uint32_t dscr = arm11_read_DSCR(arm11);

		LOG_DEBUG("DRAIN, DSCR %08x", dscr);

		if (dscr & ARM11_DSCR_STICKY_IMPRECISE_DATA_ABORT)
		{
			arm11_run_instr_no_data1(arm11, 0xe320f000);

			dscr = arm11_read_DSCR(arm11);

			LOG_DEBUG("DRAIN, DSCR %08x (DONE)", dscr);

			break;
		}
	}
#endif

	/* Save registers.
	 *
	 * NOTE:  ARM1136 TRM suggests saving just R0 here now, then
	 * CPSR and PC after the rDTR stuff.  We do it all at once.
	 */
	retval = arm_dpm_read_current_registers(&arm11->dpm);
	if (retval != ERROR_OK)
		LOG_ERROR("DPM REG READ -- fail");

	retval = arm11_run_instr_data_prepare(arm11);
	if (retval != ERROR_OK)
		return retval;

	/* maybe save rDTR (pending DCC read from debug SW, e.g. libdcc) */
	arm11->is_rdtr_saved = !!(arm11->dscr & DSCR_DTR_RX_FULL);
	if (arm11->is_rdtr_saved)
	{
		/* MRC p14,0,R0,c0,c5,0 (move rDTR -> r0 (-> wDTR -> local var)) */
		retval = arm11_run_instr_data_from_core_via_r0(arm11,
				0xEE100E15, &arm11->saved_rdtr);
		if (retval != ERROR_OK)
			return retval;
	}

	/* REVISIT Now that we've saved core state, there's may also
	 * be MMU and cache state to care about ...
	 */

	if (arm11->simulate_reset_on_next_halt)
	{
		arm11->simulate_reset_on_next_halt = false;

		LOG_DEBUG("Reset c1 Control Register");

		/* Write 0 (reset value) to Control register 0 to disable MMU/Cache etc. */

		/* MCR p15,0,R0,c1,c0,0 */
		retval = arm11_run_instr_data_to_core_via_r0(arm11, 0xee010f10, 0);
		if (retval != ERROR_OK)
			return retval;

	}

	if (arm11->arm.target->debug_reason == DBG_REASON_WATCHPOINT) {
		uint32_t wfar;

		/* MRC p15, 0, <Rd>, c6, c0, 1 ; Read WFAR */
		retval = arm11_run_instr_data_from_core_via_r0(arm11,
				ARMV4_5_MRC(15, 0, 0, 6, 0, 1),
				&wfar);
		if (retval != ERROR_OK)
			return retval;
		arm_dpm_report_wfar(arm11->arm.dpm, wfar);
	}


	retval = arm11_run_instr_data_finish(arm11);
	if (retval != ERROR_OK)
		return retval;

	return ERROR_OK;
}
Exemplo n.º 6
0
/*
* no_increment - in the future we may want to be able
* to read/write a range of data to a "port". a "port" is an action on
* read memory address for some peripheral.
*/
static int arm11_write_memory_inner(struct target *target,
		uint32_t address, uint32_t size,
		uint32_t count, const uint8_t *buffer,
		bool no_increment)
{
	int retval;

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target was not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_DEBUG("ADDR %08" PRIx32 "  SIZE %08" PRIx32 "  COUNT %08" PRIx32 "", address, size, count);

	struct arm11_common *arm11 = target_to_arm11(target);

	retval = arm11_run_instr_data_prepare(arm11);
	if (retval != ERROR_OK)
		return retval;

	/* load r0 with buffer address */
	/* MRC p14,0,r0,c0,c5,0 */
	retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
	if (retval != ERROR_OK)
		return retval;

	/* burst writes are not used for single words as those may well be
	 * reset init script writes.
	 *
	 * The other advantage is that as burst writes are default, we'll
	 * now exercise both burst and non-burst code paths with the
	 * default settings, increasing code coverage.
	 */
	bool burst = arm11->memwrite_burst && (count > 1);

	switch (size)
	{
	case 1:
		{
			arm11->arm.core_cache->reg_list[1].dirty = true;

			for (size_t i = 0; i < count; i++)
			{
				/* load r1 from DCC with byte data */
				/* MRC p14,0,r1,c0,c5,0 */
				retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, *buffer++);
				if (retval != ERROR_OK)
					return retval;

				/* write r1 to memory */
				/* strb    r1, [r0], #1 */
				/* strb    r1, [r0] */
				retval = arm11_run_instr_no_data1(arm11,
					!no_increment
						? 0xe4c01001
						: 0xe5c01000);
				if (retval != ERROR_OK)
					return retval;
			}

			break;
		}

	case 2:
		{
			arm11->arm.core_cache->reg_list[1].dirty = true;

			for (size_t i = 0; i < count; i++)
			{
				uint16_t value;
				memcpy(&value, buffer + i * sizeof(uint16_t), sizeof(uint16_t));

				/* load r1 from DCC with halfword data */
				/* MRC p14,0,r1,c0,c5,0 */
				retval = arm11_run_instr_data_to_core1(arm11, 0xee101e15, value);
				if (retval != ERROR_OK)
					return retval;

				/* write r1 to memory */
				/* strh    r1, [r0], #2 */
				/* strh    r1, [r0] */
				retval = arm11_run_instr_no_data1(arm11,
					!no_increment
						? 0xe0c010b2
						: 0xe1c010b0);
				if (retval != ERROR_OK)
					return retval;
			}

			break;
		}

	case 4: {
		/* stream word data through DCC directly to memory */
		/* increment:		STC p14,c5,[R0],#4 */
		/* no increment:	STC p14,c5,[R0]*/
		uint32_t instr = !no_increment ? 0xeca05e01 : 0xed805e00;

		/** \todo TODO: buffer cast to uint32_t* causes alignment warnings */
		uint32_t *words = (uint32_t*)(void *)buffer;

		/* "burst" here just means trusting each instruction executes
		 * fully before we run the next one:  per-word roundtrips, to
		 * check the Ready flag, are not used.
		 */
		if (!burst)
			retval = arm11_run_instr_data_to_core(arm11,
					instr, words, count);
		else
			retval = arm11_run_instr_data_to_core_noack(arm11,
					instr, words, count);
		if (retval != ERROR_OK)
			return retval;

		break;
	}
	}

	/* r0 verification */
	if (!no_increment)
	{
		uint32_t r0;

		/* MCR p14,0,R0,c0,c5,0 */
		retval = arm11_run_instr_data_from_core(arm11, 0xEE000E15, &r0, 1);
		if (retval != ERROR_OK)
			return retval;

		if (address + size * count != r0)
		{
			LOG_ERROR("Data transfer failed. Expected end "
					"address 0x%08x, got 0x%08x",
					(unsigned) (address + size * count),
					(unsigned) r0);

			if (burst)
				LOG_ERROR("use 'arm11 memwrite burst disable' to disable fast burst mode");

			if (arm11->memwrite_error_fatal)
				return ERROR_FAIL;
		}
	}

	return arm11_run_instr_data_finish(arm11);
}
Exemplo n.º 7
0
/* target memory access
 * size: 1 = byte (8bit), 2 = half-word (16bit), 4 = word (32bit)
 * count: number of items of <size>
 *
 * arm11_config_memrw_no_increment - in the future we may want to be able
 * to read/write a range of data to a "port". a "port" is an action on
 * read memory address for some peripheral.
 */
static int arm11_read_memory_inner(struct target *target,
		uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer,
		bool arm11_config_memrw_no_increment)
{
	/** \todo TODO: check if buffer cast to uint32_t* and uint16_t* might cause alignment problems */
	int retval;

	if (target->state != TARGET_HALTED)
	{
		LOG_WARNING("target was not halted");
		return ERROR_TARGET_NOT_HALTED;
	}

	LOG_DEBUG("ADDR %08" PRIx32 "  SIZE %08" PRIx32 "  COUNT %08" PRIx32 "", address, size, count);

	struct arm11_common *arm11 = target_to_arm11(target);

	retval = arm11_run_instr_data_prepare(arm11);
	if (retval != ERROR_OK)
		return retval;

	/* MRC p14,0,r0,c0,c5,0 */
	retval = arm11_run_instr_data_to_core1(arm11, 0xee100e15, address);
	if (retval != ERROR_OK)
		return retval;

	switch (size)
	{
	case 1:
		arm11->arm.core_cache->reg_list[1].dirty = true;

		for (size_t i = 0; i < count; i++)
		{
			/* ldrb    r1, [r0], #1 */
			/* ldrb    r1, [r0] */
			CHECK_RETVAL(arm11_run_instr_no_data1(arm11,
					!arm11_config_memrw_no_increment ? 0xe4d01001 : 0xe5d01000));

			uint32_t res;
			/* MCR p14,0,R1,c0,c5,0 */
			CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1));

			*buffer++ = res;
		}

		break;

	case 2:
		{
			arm11->arm.core_cache->reg_list[1].dirty = true;

			for (size_t i = 0; i < count; i++)
			{
				/* ldrh    r1, [r0], #2 */
				CHECK_RETVAL(arm11_run_instr_no_data1(arm11,
					!arm11_config_memrw_no_increment ? 0xe0d010b2 : 0xe1d010b0));

				uint32_t res;

				/* MCR p14,0,R1,c0,c5,0 */
				CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, 0xEE001E15, &res, 1));

				uint16_t svalue = res;
				memcpy(buffer + i * sizeof(uint16_t), &svalue, sizeof(uint16_t));
			}

			break;
		}

	case 4:
		{
		uint32_t instr = !arm11_config_memrw_no_increment ? 0xecb05e01 : 0xed905e00;
		/** \todo TODO: buffer cast to uint32_t* causes alignment warnings */
		uint32_t *words = (uint32_t *)(void *)buffer;

		/* LDC p14,c5,[R0],#4 */
		/* LDC p14,c5,[R0] */
		CHECK_RETVAL(arm11_run_instr_data_from_core(arm11, instr, words, count));
		break;
		}
	}

	return arm11_run_instr_data_finish(arm11);
}