Exemplo n.º 1
0
/** Generates a CRC32 checksum of a memory region. */
int armv7m_checksum_memory(struct target *target,
		uint32_t address, uint32_t count, uint32_t* checksum)
{
	struct working_area *crc_algorithm;
	struct armv7m_algorithm armv7m_info;
	struct reg_param reg_params[2];
	int retval;

	/* see contib/loaders/checksum/armv7m_crc.s for src */

	static const uint16_t cortex_m3_crc_code[] = {
		0x4602,					/* mov	r2, r0 */
		0xF04F, 0x30FF,			/* mov	r0, #0xffffffff */
		0x460B,					/* mov	r3, r1 */
		0xF04F, 0x0400,			/* mov	r4, #0 */
		0xE013,					/* b	ncomp */
								/* nbyte: */
		0x5D11,					/* ldrb	r1, [r2, r4] */
		0xF8DF, 0x7028,			/* ldr		r7, CRC32XOR */
		0xEA80, 0x6001,			/* eor		r0, r0, r1, asl #24 */

		0xF04F, 0x0500,			/* mov		r5, #0 */
								/* loop: */
		0x2800,					/* cmp		r0, #0 */
		0xEA4F, 0x0640,			/* mov		r6, r0, asl #1 */
		0xF105, 0x0501,			/* add		r5, r5, #1 */
		0x4630,					/* mov		r0, r6 */
		0xBFB8,					/* it		lt */
		0xEA86, 0x0007,			/* eor		r0, r6, r7 */
		0x2D08, 				/* cmp		r5, #8 */
		0xD1F4,					/* bne		loop */

		0xF104, 0x0401,			/* add	r4, r4, #1 */
								/* ncomp: */
		0x429C,					/* cmp	r4, r3 */
		0xD1E9,					/* bne	nbyte */
		0xBE00,     			/* bkpt #0 */
		0x1DB7, 0x04C1			/* CRC32XOR:	.word 0x04C11DB7 */
	};

	uint32_t i;

	if (target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(cortex_m3_crc_code); i++)
		if ((retval = target_write_u16(target, crc_algorithm->address + i*sizeof(uint16_t), cortex_m3_crc_code[i])) != ERROR_OK)
		{
			return retval;
		}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;

	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);

	int timeout = 20000 * (1 + (count / (1024 * 1024)));

	if ((retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
		crc_algorithm->address, crc_algorithm->address + (sizeof(cortex_m3_crc_code)-6), timeout, &armv7m_info)) != ERROR_OK)
	{
		LOG_ERROR("error executing cortex_m3 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;
}
Exemplo n.º 2
0
/** Checks whether a memory region is zeroed. */
int mips32_blank_check_memory(struct target *target,
		uint32_t address, uint32_t count, uint32_t *blank)
{
	struct working_area *erase_check_algorithm;
	struct reg_param reg_params[3];
	struct mips32_algorithm mips32_info;
	int retval;
	uint32_t i;

	static const uint32_t erase_check_code[] = {
						/* nbyte: */
		0x80880000,		/* lb		$t0, ($a0) */
		0x00C83024,		/* and		$a2, $a2, $t0 */
		0x24A5FFFF,		/* addiu	$a1, $a1, -1 */
		0x14A0FFFC,		/* bne		$a1, $zero, nbyte */
		0x24840001,		/* addiu	$a0, $a0, 1 */
		0x7000003F		/* sdbbp */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(erase_check_code); i++) {
		target_write_u32(target, erase_check_algorithm->address + i*sizeof(uint32_t),
				erase_check_code[i]);
	}

	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
	mips32_info.isa_mode = MIPS32_ISA_MIPS32;

	init_reg_param(&reg_params[0], "a0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

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

	init_reg_param(&reg_params[2], "a2", 32, PARAM_IN_OUT);
	buf_set_u32(reg_params[2].value, 0, 32, 0xff);

	retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
			erase_check_algorithm->address,
			erase_check_algorithm->address + (sizeof(erase_check_code)-4),
			10000, &mips32_info);
	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, erase_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, erase_check_algorithm);

	return ERROR_OK;
}
Exemplo n.º 3
0
/** Generates a CRC32 checksum of a memory region. */
int armv7m_checksum_memory(struct target *target,
	uint32_t address, uint32_t count, uint32_t *checksum)
{
	struct working_area *crc_algorithm;
	struct armv7m_algorithm armv7m_info;
	struct reg_param reg_params[2];
	int retval;

	/* see contrib/loaders/checksum/armv7m_crc.s for src */

	static const uint8_t cortex_m3_crc_code[] = {
		/* main: */
		0x02, 0x46,			/* mov		r2, r0 */
		0x00, 0x20,			/* movs		r0, #0 */
		0xC0, 0x43,			/* mvns		r0, r0 */
		0x0A, 0x4E,			/* ldr		r6, CRC32XOR */
		0x0B, 0x46,			/* mov		r3, r1 */
		0x00, 0x24,			/* movs		r4, #0 */
		0x0D, 0xE0,			/* b		ncomp */
		/* nbyte: */
		0x11, 0x5D,			/* ldrb		r1, [r2, r4] */
		0x09, 0x06,			/* lsls		r1, r1, #24 */
		0x48, 0x40,			/* eors		r0, r0, r1 */
		0x00, 0x25,			/* movs		r5, #0 */
		/* loop: */
		0x00, 0x28,			/* cmp		r0, #0 */
		0x02, 0xDA,			/* bge		notset */
		0x40, 0x00,			/* lsls		r0, r0, #1 */
		0x70, 0x40,			/* eors		r0, r0, r6 */
		0x00, 0xE0,			/* b		cont */
		/* notset: */
		0x40, 0x00,			/* lsls		r0, r0, #1 */
		/* cont: */
		0x01, 0x35,			/* adds		r5, r5, #1 */
		0x08, 0x2D,			/* cmp		r5, #8 */
		0xF6, 0xD1,			/* bne		loop */
		0x01, 0x34,			/* adds		r4, r4, #1 */
		/* ncomp: */
		0x9C, 0x42,			/* cmp		r4, r3 */
		0xEF, 0xD1,			/* bne		nbyte */
		0x00, 0xBE,			/* bkpt		#0 */
		0xB7, 0x1D, 0xC1, 0x04	/* CRC32XOR:	.word	0x04c11db7 */
	};

	retval = target_alloc_working_area(target, sizeof(cortex_m3_crc_code), &crc_algorithm);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_buffer(target, crc_algorithm->address,
			sizeof(cortex_m3_crc_code), (uint8_t *)cortex_m3_crc_code);
	if (retval != ERROR_OK)
		goto cleanup;

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	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);

	int timeout = 20000 * (1 + (count / (1024 * 1024)));

	retval = target_run_algorithm(target, 0, NULL, 2, reg_params, crc_algorithm->address,
			crc_algorithm->address + (sizeof(cortex_m3_crc_code) - 6),
			timeout, &armv7m_info);

	if (retval == ERROR_OK)
		*checksum = buf_get_u32(reg_params[0].value, 0, 32);
	else
		LOG_ERROR("error executing cortex_m crc algorithm");

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

cleanup:
	target_free_working_area(target, crc_algorithm);

	return retval;
}
Exemplo n.º 4
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;
}
Exemplo n.º 5
0
static int str7x_write_block(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct str7x_flash_bank *str7x_info = bank->driver_priv;
	struct target *target = bank->target;
	uint32_t buffer_size = 32768;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[6];
	struct arm_algorithm armv4_5_info;
	int retval = ERROR_OK;

	/* see contib/loaders/flash/str7x.s for src */

	static const uint32_t str7x_flash_write_code[] = {
					/* write:				*/
		0xe3a04201, /*	mov r4, #0x10000000	*/
		0xe5824000, /*	str r4, [r2, #0x0]	*/
		0xe5821010, /*	str r1, [r2, #0x10]	*/
		0xe4904004, /*	ldr r4, [r0], #4	*/
		0xe5824008, /*	str r4, [r2, #0x8]	*/
		0xe4904004, /*	ldr r4, [r0], #4	*/
		0xe582400c, /*	str r4, [r2, #0xc]	*/
		0xe3a04209, /*	mov r4, #0x90000000	*/
		0xe5824000, /*	str r4, [r2, #0x0]	*/
		            /* busy:				*/
		0xe5924000, /*	ldr r4, [r2, #0x0]	*/
		0xe1140005,	/*	tst r4, r5			*/
		0x1afffffc, /*	bne busy			*/
		0xe5924014, /*	ldr r4, [r2, #0x14]	*/
		0xe31400ff, /*	tst r4, #0xff		*/
		0x03140c01, /*	tsteq r4, #0x100	*/
		0x1a000002, /*	bne exit			*/
		0xe2811008, /*	add r1, r1, #0x8	*/
		0xe2533001, /*	subs r3, r3, #1		*/
		0x1affffec, /*	bne write			*/
					/* exit:				*/
		0xeafffffe, /*	b exit				*/
	};

	/* flash write code */
	if (target_alloc_working_area_try(target, sizeof(str7x_flash_write_code),
			&str7x_info->write_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	target_write_buffer(target, str7x_info->write_algorithm->address,
			sizeof(str7x_flash_write_code),
			(uint8_t*)str7x_flash_write_code);

	/* memory buffer */
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
			/* if we already allocated the writing code, but failed to get a
			 * buffer, free the algorithm */
			if (str7x_info->write_algorithm)
				target_free_working_area(target, str7x_info->write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv4_5_info.common_magic = ARM_COMMON_MAGIC;
	armv4_5_info.core_mode = ARM_MODE_SVC;
	armv4_5_info.core_state = ARM_STATE_ARM;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
	init_reg_param(&reg_params[4], "r4", 32, PARAM_IN);
	init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);

	while (count > 0)
	{
		uint32_t thisrun_count = (count > (buffer_size / 8)) ? (buffer_size / 8) : count;

		target_write_buffer(target, source->address, thisrun_count * 8, buffer);

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, str7x_get_flash_adr(bank, FLASH_CR0));
		buf_set_u32(reg_params[3].value, 0, 32, thisrun_count);
		buf_set_u32(reg_params[5].value, 0, 32, str7x_info->busy_bits);

		if ((retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
				str7x_info->write_algorithm->address,
				str7x_info->write_algorithm->address + (sizeof(str7x_flash_write_code) - 4),
				10000, &armv4_5_info)) != ERROR_OK)
		{
			break;
		}

		if (buf_get_u32(reg_params[4].value, 0, 32) != 0x00)
		{
			retval = str7x_result(bank);
			break;
		}

		buffer += thisrun_count * 8;
		address += thisrun_count * 8;
		count -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, str7x_info->write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
	destroy_reg_param(&reg_params[5]);

	return retval;
}
Exemplo n.º 6
0
static int lpcspifi_erase(struct flash_bank *bank, int first, int last)
{
	struct target *target = bank->target;
	struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_info;
	struct working_area *erase_algorithm;
	int retval = ERROR_OK;
	int sector;

	LOG_DEBUG("erase from sector %d to sector %d", first, last);

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

	if ((first < 0) || (last < first) || (last >= bank->num_sectors)) {
		LOG_ERROR("Flash sector invalid");
		return ERROR_FLASH_SECTOR_INVALID;
	}

	if (!(lpcspifi_info->probed)) {
		LOG_ERROR("Flash bank not probed");
		return ERROR_FLASH_BANK_NOT_PROBED;
	}

	for (sector = first; sector <= last; sector++) {
		if (bank->sectors[sector].is_protected) {
			LOG_ERROR("Flash sector %d protected", sector);
			return ERROR_FAIL;
		}
	}

	/* If we're erasing the entire chip and the flash supports
	 * it, use a bulk erase instead of going sector-by-sector. */
	if (first == 0 && last == (bank->num_sectors - 1)
		&& lpcspifi_info->dev->chip_erase_cmd != lpcspifi_info->dev->erase_cmd) {
		LOG_DEBUG("Chip supports the bulk erase command."\
		" Will use bulk erase instead of sector-by-sector erase.");
		retval = lpcspifi_bulk_erase(bank);

		if (retval == ERROR_OK) {
			retval = lpcspifi_set_hw_mode(bank);
			return retval;
		} else
			LOG_WARNING("Bulk flash erase failed. Falling back to sector-by-sector erase.");
	}

	retval = lpcspifi_set_hw_mode(bank);
	if (retval != ERROR_OK)
		return retval;

	/* see contrib/loaders/flash/lpcspifi_erase.S for src */
	static const uint8_t lpcspifi_flash_erase_code[] = {
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
		0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
		0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
		0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
		0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
		0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
		0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
		0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
		0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
		0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
		0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
		0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
		0x00, 0xf0, 0x52, 0xf8, 0x4f, 0xf0, 0x06, 0x09,
		0x00, 0xf0, 0x3b, 0xf8, 0x00, 0xf0, 0x48, 0xf8,
		0x00, 0xf0, 0x4a, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
		0x00, 0xf0, 0x33, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
		0x00, 0xf0, 0x2f, 0xf8, 0x00, 0xf0, 0x3c, 0xf8,
		0x19, 0xf0, 0x02, 0x0f, 0x00, 0xf0, 0x45, 0x80,
		0x00, 0xf0, 0x3a, 0xf8, 0x4f, 0xea, 0x02, 0x09,
		0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xea, 0x10, 0x49,
		0x00, 0xf0, 0x1f, 0xf8, 0x4f, 0xea, 0x10, 0x29,
		0x00, 0xf0, 0x1b, 0xf8, 0x4f, 0xea, 0x00, 0x09,
		0x00, 0xf0, 0x17, 0xf8, 0x00, 0xf0, 0x24, 0xf8,
		0x00, 0xf0, 0x26, 0xf8, 0x4f, 0xf0, 0x05, 0x09,
		0x00, 0xf0, 0x0f, 0xf8, 0x4f, 0xf0, 0x00, 0x09,
		0x00, 0xf0, 0x0b, 0xf8, 0x00, 0xf0, 0x18, 0xf8,
		0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4, 0xf0, 0xaf,
		0x01, 0x39, 0xf9, 0xb1, 0x18, 0x44, 0xff, 0xf7,
		0xbf, 0xbf, 0x4f, 0xf4, 0x40, 0x5a, 0xc4, 0xf2,
		0x08, 0x0a, 0xca, 0xf8, 0x08, 0x90, 0xda, 0xf8,
		0x0c, 0x90, 0x19, 0xf0, 0x10, 0x0f, 0x7f, 0xf4,
		0xfa, 0xaf, 0xda, 0xf8, 0x08, 0x90, 0x70, 0x47,
		0x4f, 0xf0, 0xff, 0x08, 0x00, 0xf0, 0x02, 0xb8,
		0x4f, 0xf0, 0x00, 0x08, 0x4f, 0xf4, 0x80, 0x4a,
		0xc4, 0xf2, 0x0f, 0x0a, 0xca, 0xf8, 0xab, 0x80,
		0x70, 0x47, 0x00, 0x20, 0x00, 0xbe, 0xff, 0xff
	};

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;


	/* Get memory for spifi initialization algorithm */
	retval = target_alloc_working_area(target, sizeof(lpcspifi_flash_erase_code),
		&erase_algorithm);
	if (retval != ERROR_OK) {
		LOG_ERROR("Insufficient working area. You must configure a working"\
			" area of at least %zdB in order to erase SPIFI flash.",
			sizeof(lpcspifi_flash_erase_code));
		return retval;
	}

	/* Write algorithm to working area */
	retval = target_write_buffer(target, erase_algorithm->address,
		sizeof(lpcspifi_flash_erase_code), lpcspifi_flash_erase_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, erase_algorithm);
		return retval;
	}

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* Start address */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* Sector count */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* Erase command */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);	/* Sector size */

	buf_set_u32(reg_params[0].value, 0, 32, bank->sectors[first].offset);
	buf_set_u32(reg_params[1].value, 0, 32, last - first + 1);
	buf_set_u32(reg_params[2].value, 0, 32, lpcspifi_info->dev->erase_cmd);
	buf_set_u32(reg_params[3].value, 0, 32, bank->sectors[first].size);

	/* Run the algorithm */
	retval = target_run_algorithm(target, 0 , NULL, 4, reg_params,
		erase_algorithm->address,
		erase_algorithm->address + sizeof(lpcspifi_flash_erase_code) - 4,
		3000*(last - first + 1), &armv7m_info);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing flash erase algorithm");

	target_free_working_area(target, erase_algorithm);

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

	retval = lpcspifi_set_hw_mode(bank);

	return retval;
}
Exemplo n.º 7
0
/* call LPC1700/LPC2000 IAP function
 * uses 180 bytes working area
 * 0x0 to 0x7: jump gate (BX to thumb state, b -2 to wait)
 * 0x8 to 0x1f: command parameter table (1+5 words)
 * 0x20 to 0x33: command result table (1+4 words)
 * 0x34 to 0xb3: stack (only 128b needed)
 */
static int lpc2000_iap_call(struct flash_bank *bank,
	int code,
	uint32_t param_table[5],
	uint32_t result_table[4])
{
	int retval;
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
	struct target *target = bank->target;
	struct mem_param mem_params[2];
	struct reg_param reg_params[5];
	struct arm_algorithm arm_algo;	/* for LPC2000 */
	struct armv7m_algorithm armv7m_info;	/* for LPC1700 */
	uint32_t status_code;
	uint32_t iap_entry_point = 0;	/* to make compiler happier */

	/* regrab previously allocated working_area, or allocate a new one */
	if (!lpc2000_info->iap_working_area) {
		uint8_t jump_gate[8];

		/* make sure we have a working area */
		if (target_alloc_working_area(target, 180,
				&lpc2000_info->iap_working_area) != ERROR_OK) {
			LOG_ERROR("no working area specified, can't write LPC2000 internal flash");
			return ERROR_FLASH_OPERATION_FAILED;
		}

		/* write IAP code to working area */
		switch (lpc2000_info->variant) {
			case lpc1700:
				target_buffer_set_u32(target, jump_gate, ARMV4_5_T_BX(12));
				target_buffer_set_u32(target, jump_gate + 4, ARMV5_T_BKPT(0));
				break;
			case lpc2000_v1:
			case lpc2000_v2:
				target_buffer_set_u32(target, jump_gate, ARMV4_5_BX(12));
				target_buffer_set_u32(target, jump_gate + 4, ARMV4_5_B(0xfffffe, 0));
				break;
			default:
				LOG_ERROR("BUG: unknown lpc2000_info->variant encountered");
				exit(-1);
		}

		retval = target_write_memory(target,
				lpc2000_info->iap_working_area->address, 4, 2, jump_gate);
		if (retval != ERROR_OK) {
			LOG_ERROR(
				"Write memory at address 0x%8.8" PRIx32 " failed (check work_area definition)",
				lpc2000_info->iap_working_area->address);
			return retval;
		}
	}

	switch (lpc2000_info->variant) {
		case lpc1700:
			armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
			armv7m_info.core_mode = ARMV7M_MODE_ANY;
			iap_entry_point = 0x1fff1ff1;
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			arm_algo.common_magic = ARM_COMMON_MAGIC;
			arm_algo.core_mode = ARM_MODE_SVC;
			arm_algo.core_state = ARM_STATE_ARM;
			iap_entry_point = 0x7ffffff1;
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}

	/* command parameter table */
	init_mem_param(&mem_params[0], lpc2000_info->iap_working_area->address + 8, 6 * 4,
		PARAM_OUT);
	target_buffer_set_u32(target, mem_params[0].value, code);
	target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
	target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
	target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
	target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
	target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, lpc2000_info->iap_working_area->address + 0x08);

	/* command result table */
	init_mem_param(&mem_params[1],
		lpc2000_info->iap_working_area->address + 0x20,
		5 * 4,
		PARAM_IN);

	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, lpc2000_info->iap_working_area->address + 0x20);

	/* IAP entry point */
	init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
	buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);

	switch (lpc2000_info->variant) {
		case lpc1700:
			/* IAP stack */
			init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32,
					lpc2000_info->iap_working_area->address + 0xb4);

			/* return address */
			init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32,
					(lpc2000_info->iap_working_area->address + 0x04) | 1);
			/* bit0 of LR = 1 to return in Thumb mode */

			target_run_algorithm(target, 2, mem_params, 5, reg_params,
					lpc2000_info->iap_working_area->address, 0, 10000, &armv7m_info);
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			/* IAP stack */
			init_reg_param(&reg_params[3], "sp_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32,
					lpc2000_info->iap_working_area->address + 0xb4);

			/* return address */
			init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32,
					lpc2000_info->iap_working_area->address + 0x04);

			target_run_algorithm(target, 2, mem_params, 5, reg_params,
					lpc2000_info->iap_working_area->address,
					lpc2000_info->iap_working_area->address + 0x4,
					10000, &arm_algo);
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}

	status_code = target_buffer_get_u32(target, mem_params[1].value);
	result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
	result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
	result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
	result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);

	LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32
			", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8"
			PRIx32 ") completed with result = %8.8" PRIx32,
			code, param_table[0], param_table[1], param_table[2],
			param_table[3], param_table[4], status_code);

	destroy_mem_param(&mem_params[0]);
	destroy_mem_param(&mem_params[1]);

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

	return status_code;
}
Exemplo n.º 8
0
/**
 * ARM-specific bulk write from buffer to address of 8-bit wide NAND.
 * For now this only supports ARMv4 and ARMv5 cores.
 *
 * Enhancements to target_run_algorithm() could enable:
 *   - ARMv6 and ARMv7 cores in ARM mode
 *
 * Different code fragments could handle:
 *   - Thumb2 cores like Cortex-M (needs different byteswapping)
 *   - 16-bit wide data (needs different setup too)
 *
 * @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 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[] = {
		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           */
	};

	if (nand->op != ARM_NAND_WRITE || !nand->copy_area) {
		retval = arm_code_to_working_area(target, code, sizeof(code),
				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 + sizeof(code);
	retval = target_write_buffer(target, target_buf, size, data);
	if (retval != ERROR_OK)
		return retval;

	/* set up algorithm and parameters */
	algo.common_magic = ARM_COMMON_MAGIC;
	algo.core_mode = ARM_MODE_SVC;
	algo.core_state = ARM_STATE_ARM;

	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 + sizeof(code) - 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, &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;
}
Exemplo n.º 9
0
/* Start a low level flash write for the specified region */
static int nrf5_ll_flash_write(struct nrf5_info *chip, uint32_t offset, const uint8_t *buffer, uint32_t bytes)
{
	struct target *target = chip->target;
	uint32_t buffer_size = 8192;
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = NRF5_FLASH_BASE + offset;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;


	LOG_DEBUG("Writing buffer to flash offset=0x%"PRIx32" bytes=0x%"PRIx32, offset, bytes);
	assert(bytes % 4 == 0);

	/* allocate working area with flash programming code */
	if (target_alloc_working_area(target, sizeof(nrf5_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_WARNING("no working area available, falling back to slow memory writes");

		for (; bytes > 0; bytes -= 4) {
			retval = target_write_memory(chip->target, offset, 4, 1, buffer);
			if (retval != ERROR_OK)
				return retval;

			retval = nrf5_wait_for_nvmc(chip);
			if (retval != ERROR_OK)
				return retval;

			offset += 4;
			buffer += 4;
		}

		return ERROR_OK;
	}

	LOG_WARNING("using fast async flash loader. This is currently supported");
	LOG_WARNING("only with ST-Link and CMSIS-DAP. If you have issues, add");
	LOG_WARNING("\"set WORKAREASIZE 0\" before sourcing nrf51.cfg/nrf52.cfg to disable it");

	retval = target_write_buffer(target, write_algorithm->address,
				sizeof(nrf5_flash_write_code),
				nrf5_flash_write_code);
	if (retval != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
		buffer_size /= 2;
		buffer_size &= ~3UL; /* Make sure it's 4 byte aligned */
		if (buffer_size <= 256) {
			/* free working area, write algorithm already allocated */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("No large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* byte count */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* buffer start */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* buffer end */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT);	/* target address */

	buf_set_u32(reg_params[0].value, 0, 32, bytes);
	buf_set_u32(reg_params[1].value, 0, 32, source->address);
	buf_set_u32(reg_params[2].value, 0, 32, source->address + source->size);
	buf_set_u32(reg_params[3].value, 0, 32, address);

	retval = target_run_flash_async_algorithm(target, buffer, bytes/4, 4,
			0, NULL,
			4, reg_params,
			source->address, source->size,
			write_algorithm->address, 0,
			&armv7m_info);

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

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

	return retval;
}
Exemplo n.º 10
0
static int lpc2000_iap_call(struct flash_bank *bank, struct working_area *iap_working_area, int code,
		uint32_t param_table[5], uint32_t result_table[4])
{
	struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv;
	struct target *target = bank->target;

	struct arm_algorithm arm_algo;	/* for LPC2000 */
	struct armv7m_algorithm armv7m_info;	/* for LPC1700 */
	uint32_t iap_entry_point = 0;	/* to make compiler happier */

	switch (lpc2000_info->variant) {
		case lpc800:
		case lpc1100:
		case lpc1700:
		case lpc_auto:
			armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
			armv7m_info.core_mode = ARM_MODE_THREAD;
			iap_entry_point = 0x1fff1ff1;
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			arm_algo.common_magic = ARM_COMMON_MAGIC;
			arm_algo.core_mode = ARM_MODE_SVC;
			arm_algo.core_state = ARM_STATE_ARM;
			iap_entry_point = 0x7ffffff1;
			break;
		case lpc4300:
			armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
			armv7m_info.core_mode = ARM_MODE_THREAD;
			/* read out IAP entry point from ROM driver table at 0x10400100 */
			target_read_u32(target, 0x10400100, &iap_entry_point);
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}

	struct mem_param mem_params[2];

	/* command parameter table */
	init_mem_param(&mem_params[0], iap_working_area->address + 8, 6 * 4, PARAM_OUT);
	target_buffer_set_u32(target, mem_params[0].value, code);
	target_buffer_set_u32(target, mem_params[0].value + 0x04, param_table[0]);
	target_buffer_set_u32(target, mem_params[0].value + 0x08, param_table[1]);
	target_buffer_set_u32(target, mem_params[0].value + 0x0c, param_table[2]);
	target_buffer_set_u32(target, mem_params[0].value + 0x10, param_table[3]);
	target_buffer_set_u32(target, mem_params[0].value + 0x14, param_table[4]);

	struct reg_param reg_params[5];

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, iap_working_area->address + 0x08);

	/* command result table */
	init_mem_param(&mem_params[1], iap_working_area->address + 0x20, 5 * 4, PARAM_IN);

	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	buf_set_u32(reg_params[1].value, 0, 32, iap_working_area->address + 0x20);

	/* IAP entry point */
	init_reg_param(&reg_params[2], "r12", 32, PARAM_OUT);
	buf_set_u32(reg_params[2].value, 0, 32, iap_entry_point);

	switch (lpc2000_info->variant) {
		case lpc800:
		case lpc1100:
		case lpc1700:
		case lpc4300:
		case lpc_auto:
			/* IAP stack */
			init_reg_param(&reg_params[3], "sp", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32,
				iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack);

			/* return address */
			init_reg_param(&reg_params[4], "lr", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32, (iap_working_area->address + 0x04) | 1);
			/* bit0 of LR = 1 to return in Thumb mode */

			target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address, 0, 10000,
					&armv7m_info);
			break;
		case lpc2000_v1:
		case lpc2000_v2:
			/* IAP stack */
			init_reg_param(&reg_params[3], "sp_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[3].value, 0, 32,
				iap_working_area->address + IAP_CODE_LEN + lpc2000_info->iap_max_stack);

			/* return address */
			init_reg_param(&reg_params[4], "lr_svc", 32, PARAM_OUT);
			buf_set_u32(reg_params[4].value, 0, 32, iap_working_area->address + 0x04);

			target_run_algorithm(target, 2, mem_params, 5, reg_params, iap_working_area->address,
					iap_working_area->address + 0x4, 10000, &arm_algo);
			break;
		default:
			LOG_ERROR("BUG: unknown lpc2000->variant encountered");
			exit(-1);
	}

	int status_code = target_buffer_get_u32(target, mem_params[1].value);
	result_table[0] = target_buffer_get_u32(target, mem_params[1].value + 0x04);
	result_table[1] = target_buffer_get_u32(target, mem_params[1].value + 0x08);
	result_table[2] = target_buffer_get_u32(target, mem_params[1].value + 0x0c);
	result_table[3] = target_buffer_get_u32(target, mem_params[1].value + 0x10);

	LOG_DEBUG("IAP command = %i (0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32 ", 0x%8.8" PRIx32
			") completed with result = %8.8x",
			code, param_table[0], param_table[1], param_table[2], param_table[3], param_table[4], status_code);

	destroy_mem_param(&mem_params[0]);
	destroy_mem_param(&mem_params[1]);

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

	return status_code;
}
Exemplo n.º 11
0
static int mrvlqspi_flash_write(struct flash_bank *bank, const uint8_t *buffer,
	uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	struct mrvlqspi_flash_bank *mrvlqspi_info = bank->driver_priv;
	int retval = ERROR_OK;
	uint32_t page_size, fifo_size;
	struct working_area *fifo;
	struct reg_param reg_params[6];
	struct armv7m_algorithm armv7m_info;
	struct working_area *write_algorithm;
	int sector;

	LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
		offset, count);

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

	if (offset + count > mrvlqspi_info->dev->size_in_bytes) {
		LOG_WARNING("Writes past end of flash. Extra data discarded.");
		count = mrvlqspi_info->dev->size_in_bytes - offset;
	}

	/* Check sector protection */
	for (sector = 0; sector < bank->num_sectors; sector++) {
		/* Start offset in or before this sector? */
		/* End offset in or behind this sector? */
		if ((offset <
			(bank->sectors[sector].offset + bank->sectors[sector].size))
			&& ((offset + count - 1) >= bank->sectors[sector].offset)
			&& bank->sectors[sector].is_protected) {
			LOG_ERROR("Flash sector %d protected", sector);
			return ERROR_FAIL;
		}
	}

	page_size = mrvlqspi_info->dev->pagesize;

	/* See contrib/loaders/flash/mrvlqspi.S for src */
	static const uint8_t mrvlqspi_flash_write_code[] = {
		0x4f, 0xf0, 0x00, 0x0a, 0xa2, 0x44, 0x92, 0x45,
		0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6b, 0xf8,
		0x5f, 0xf0, 0x01, 0x08, 0xc5, 0xf8, 0x1c, 0x80,
		0x5f, 0xf0, 0x06, 0x08, 0xc5, 0xf8, 0x10, 0x80,
		0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0, 0x6b, 0xf8,
		0x00, 0xf0, 0x7d, 0xf8, 0x5f, 0xf0, 0x31, 0x08,
		0xc5, 0xf8, 0x1c, 0x80, 0x90, 0x46, 0xc5, 0xf8,
		0x14, 0x80, 0x5f, 0xf0, 0x02, 0x08, 0xc5, 0xf8,
		0x10, 0x80, 0x5f, 0xf0, 0x01, 0x09, 0x00, 0xf0,
		0x5a, 0xf8, 0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1,
		0x00, 0x0f, 0x00, 0xf0, 0x8b, 0x80, 0x47, 0x68,
		0x47, 0x45, 0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8,
		0x01, 0x9b, 0x00, 0xf0, 0x30, 0xf8, 0x8f, 0x42,
		0x28, 0xbf, 0x00, 0xf1, 0x08, 0x07, 0x47, 0x60,
		0x01, 0x3b, 0x00, 0x2b, 0x00, 0xf0, 0x05, 0x80,
		0x02, 0xf1, 0x01, 0x02, 0x92, 0x45, 0x7f, 0xf4,
		0xe4, 0xaf, 0x00, 0xf0, 0x50, 0xf8, 0xa2, 0x44,
		0x00, 0xf0, 0x2d, 0xf8, 0x5f, 0xf0, 0x01, 0x08,
		0xc5, 0xf8, 0x1c, 0x80, 0x5f, 0xf0, 0x00, 0x08,
		0xc5, 0xf8, 0x20, 0x80, 0x5f, 0xf0, 0x05, 0x08,
		0xc5, 0xf8, 0x10, 0x80, 0x5f, 0xf0, 0x00, 0x09,
		0x00, 0xf0, 0x29, 0xf8, 0x00, 0xf0, 0x13, 0xf8,
		0x09, 0xf0, 0x01, 0x09, 0xb9, 0xf1, 0x00, 0x0f,
		0xf8, 0xd1, 0x00, 0xf0, 0x34, 0xf8, 0x00, 0x2b,
		0xa4, 0xd1, 0x00, 0xf0, 0x53, 0xb8, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0x08, 0x68, 0xfa, 0xd4,
		0xc5, 0xf8, 0x08, 0x90, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0xc8, 0x68, 0xfa, 0xd4,
		0xd5, 0xf8, 0x0c, 0x90, 0x70, 0x47, 0xd5, 0xf8,
		0x04, 0x80, 0x48, 0xf4, 0x00, 0x78, 0xc5, 0xf8,
		0x04, 0x80, 0xd5, 0xf8, 0x04, 0x80, 0x5f, 0xea,
		0x88, 0x58, 0xfa, 0xd4, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x48, 0xf0, 0x01, 0x08, 0xc5, 0xf8,
		0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea,
		0x88, 0x78, 0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80,
		0x69, 0xf3, 0x4d, 0x38, 0x48, 0xf4, 0x00, 0x48,
		0xc5, 0xf8, 0x04, 0x80, 0x70, 0x47, 0xd5, 0xf8,
		0x00, 0x80, 0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5,
		0xd5, 0xf8, 0x00, 0x80, 0x5f, 0xea, 0x48, 0x68,
		0xfa, 0xd5, 0xd5, 0xf8, 0x04, 0x80, 0x48, 0xf4,
		0x80, 0x48, 0xc5, 0xf8, 0x04, 0x80, 0xd5, 0xf8,
		0x04, 0x80, 0x5f, 0xea, 0x08, 0x48, 0xfa, 0xd4,
		0xd5, 0xf8, 0x00, 0x80, 0x28, 0xf0, 0x01, 0x08,
		0xc5, 0xf8, 0x00, 0x80, 0xd5, 0xf8, 0x00, 0x80,
		0x5f, 0xea, 0x88, 0x78, 0xfa, 0xd5, 0x70, 0x47,
		0x00, 0x20, 0x50, 0x60, 0x30, 0x46, 0x00, 0xbe
	};

	if (target_alloc_working_area(target, sizeof(mrvlqspi_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_ERROR("Insufficient working area. You must configure"\
			" a working area > %zdB in order to write to SPIFI flash.",
			sizeof(mrvlqspi_flash_write_code));
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	retval = target_write_buffer(target, write_algorithm->address,
			sizeof(mrvlqspi_flash_write_code),
			mrvlqspi_flash_write_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return retval;
	}

	/* FIFO allocation */
	fifo_size = target_get_working_area_avail(target);

	if (fifo_size == 0) {
		/* if we already allocated the writing code but failed to get fifo
		 * space, free the algorithm */
		target_free_working_area(target, write_algorithm);

		LOG_ERROR("Insufficient working area. Please allocate at least"\
			" %zdB of working area to enable flash writes.",
			sizeof(mrvlqspi_flash_write_code) + 1
		);

		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	} else if (fifo_size < page_size)
		LOG_WARNING("Working area size is limited; flash writes may be"\
			" slow. Increase working area size to at least %zdB"\
			" to reduce write times.",
			(size_t)(sizeof(mrvlqspi_flash_write_code) + page_size)
		);

	if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);	/* buffer start, status (out) */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);	/* buffer end */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);	/* target address */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);	/* count (halfword-16bit) */
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);	/* page size */
	init_reg_param(&reg_params[5], "r5", 32, PARAM_OUT);	/* qspi base address */

	buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
	buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
	buf_set_u32(reg_params[2].value, 0, 32, offset);
	buf_set_u32(reg_params[3].value, 0, 32, count);
	buf_set_u32(reg_params[4].value, 0, 32, page_size);
	buf_set_u32(reg_params[5].value, 0, 32, (uint32_t) mrvlqspi_info->reg_base);

	retval = target_run_flash_async_algorithm(target, buffer, count, 1,
			0, NULL,
			6, reg_params,
			fifo->address, fifo->size,
			write_algorithm->address, 0,
			&armv7m_info
	);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing flash write algorithm");

	target_free_working_area(target, fifo);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
	destroy_reg_param(&reg_params[5]);

	return retval;
}
Exemplo n.º 12
0
static int fm4_flash_write(struct flash_bank *bank, const uint8_t *buffer,
		uint32_t offset, uint32_t byte_count)
{
	struct target *target = bank->target;
	struct working_area *code_workarea, *data_workarea;
	struct reg_param reg_params[6];
	struct armv7m_algorithm armv7m_algo;
	uint32_t halfword_count = DIV_ROUND_UP(byte_count, 2);
	uint32_t result;
	unsigned i;
	int retval;
	const uint8_t write_block_code[] = {
#include "../../../contrib/loaders/flash/fm4/write.inc"
	};

	LOG_DEBUG("Spansion FM4 write at 0x%08" PRIx32 " (%" PRId32 " bytes)",
		offset, byte_count);

	if (offset & 0x1) {
		LOG_ERROR("offset 0x%" PRIx32 " breaks required 2-byte alignment",
			offset);
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}
	if (byte_count & 0x1) {
		LOG_WARNING("length %" PRId32 " is not 2-byte aligned, rounding up",
			byte_count);
	}

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

	retval = fm4_disable_hw_watchdog(target);
	if (retval != ERROR_OK)
		return retval;

	retval = target_alloc_working_area(target, sizeof(write_block_code),
			&code_workarea);
	if (retval != ERROR_OK) {
		LOG_ERROR("No working area available for write code.");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}
	retval = target_write_buffer(target, code_workarea->address,
			sizeof(write_block_code), write_block_code);
	if (retval != ERROR_OK)
		goto err_write_code;

	retval = target_alloc_working_area(target,
		MIN(halfword_count * 2, target_get_working_area_avail(target)),
		&data_workarea);
	if (retval != ERROR_OK) {
		LOG_ERROR("No working area available for write data.");
		retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		goto err_alloc_data;
	}

	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_algo.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);
	init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);

	retval = fm4_enter_flash_cpu_programming_mode(target);
	if (retval != ERROR_OK)
		goto err_flash_mode;

	while (byte_count > 0) {
		uint32_t halfwords = MIN(halfword_count, data_workarea->size / 2);
		uint32_t addr = bank->base + offset;

		LOG_DEBUG("copying %" PRId32 " bytes to SRAM 0x%08" PRIx32,
			MIN(halfwords * 2, byte_count), data_workarea->address);

		retval = target_write_buffer(target, data_workarea->address,
			MIN(halfwords * 2, byte_count), buffer);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error writing data buffer");
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_write_data;
		}

		LOG_DEBUG("writing 0x%08" PRIx32 "-0x%08" PRIx32 " (%" PRId32 "x)",
			addr, addr + halfwords * 2 - 1, halfwords);

		buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
		buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
		buf_set_u32(reg_params[2].value, 0, 32, addr);
		buf_set_u32(reg_params[3].value, 0, 32, data_workarea->address);
		buf_set_u32(reg_params[4].value, 0, 32, halfwords);

		retval = target_run_algorithm(target,
				0, NULL,
				ARRAY_SIZE(reg_params), reg_params,
				code_workarea->address, 0,
				5 * 60 * 1000, &armv7m_algo);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error executing flash sector erase "
				"programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run;
		}

		result = buf_get_u32(reg_params[5].value, 0, 32);
		if (result == 2) {
			LOG_ERROR("Timeout error from flash write "
				"programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run_ret;
		} else if (result != 0) {
			LOG_ERROR("Unexpected error %d from flash write "
				"programming algorithm", result);
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run_ret;
		} else
			retval = ERROR_OK;

		halfword_count -= halfwords;
		offset += halfwords * 2;
		buffer += halfwords * 2;
		byte_count -= MIN(halfwords * 2, byte_count);
	}

err_run_ret:
err_run:
err_write_data:
	retval = fm4_enter_flash_cpu_rom_mode(target);

err_flash_mode:
	for (i = 0; i < ARRAY_SIZE(reg_params); i++)
		destroy_reg_param(&reg_params[i]);

	target_free_working_area(target, data_workarea);
err_alloc_data:
err_write_code:
	target_free_working_area(target, code_workarea);

	return retval;
}
Exemplo n.º 13
0
static int fm4_flash_erase(struct flash_bank *bank, int first, int last)
{
	struct target *target = bank->target;
	struct working_area *workarea;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_algo;
	unsigned i;
	int retval, sector;
	const uint8_t erase_sector_code[] = {
#include "../../../contrib/loaders/flash/fm4/erase.inc"
	};

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

	LOG_DEBUG("Spansion FM4 erase sectors %d to %d", first, last);

	retval = fm4_disable_hw_watchdog(target);
	if (retval != ERROR_OK)
		return retval;

	retval = fm4_enter_flash_cpu_programming_mode(target);
	if (retval != ERROR_OK)
		return retval;

	retval = target_alloc_working_area(target, sizeof(erase_sector_code),
			&workarea);
	if (retval != ERROR_OK) {
		LOG_ERROR("No working area available.");
		retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		goto err_alloc_code;
	}
	retval = target_write_buffer(target, workarea->address,
			sizeof(erase_sector_code), erase_sector_code);
	if (retval != ERROR_OK)
		goto err_write_code;

	armv7m_algo.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_algo.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);

	for (sector = first; sector <= last; sector++) {
		uint32_t addr = bank->base + bank->sectors[sector].offset;
		uint32_t result;

		buf_set_u32(reg_params[0].value, 0, 32, (addr & ~0xffff) | 0xAA8);
		buf_set_u32(reg_params[1].value, 0, 32, (addr & ~0xffff) | 0x554);
		buf_set_u32(reg_params[2].value, 0, 32, addr);

		retval = target_run_algorithm(target,
				0, NULL,
				ARRAY_SIZE(reg_params), reg_params,
				workarea->address, 0,
				1000, &armv7m_algo);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error executing flash sector erase "
				"programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run;
		}

		result = buf_get_u32(reg_params[3].value, 0, 32);
		if (result == 2) {
			LOG_ERROR("Timeout error from flash sector erase programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run_ret;
		} else if (result != 0) {
			LOG_ERROR("Unexpected error %d from flash sector erase programming algorithm", result);
			retval = ERROR_FLASH_OPERATION_FAILED;
			goto err_run_ret;
		} else
			retval = ERROR_OK;

		bank->sectors[sector].is_erased = 1;
	}

err_run_ret:
err_run:
	for (i = 0; i < ARRAY_SIZE(reg_params); i++)
		destroy_reg_param(&reg_params[i]);

err_write_code:
	target_free_working_area(target, workarea);

err_alloc_code:
	if (retval != ERROR_OK)
		fm4_enter_flash_cpu_rom_mode(target);
	else
		retval = fm4_enter_flash_cpu_rom_mode(target);

	return retval;
}
Exemplo n.º 14
0
/** Checks whether a memory region is zeroed. */
int armv7m_blank_check_memory(struct target *target,
		uint32_t address, uint32_t count, uint32_t* blank)
{
	struct working_area *erase_check_algorithm;
	struct reg_param reg_params[3];
	struct armv7m_algorithm armv7m_info;
	int retval;
	uint32_t i;

	static const uint16_t erase_check_code[] =
	{
		/* loop: */
		0xF810, 0x3B01,		/* ldrb r3, [r0], #1 */
		0xEA02, 0x0203,		/* and  r2, r2, r3 */
		0x3901,				/* subs	r1, r1, #1 */
		0xD1F9,				/* bne	loop */
		0xBE00,     		/* bkpt #0 */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(erase_check_code), &erase_check_algorithm) != ERROR_OK)
	{
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(erase_check_code); i++)
		target_write_u16(target, erase_check_algorithm->address + i*sizeof(uint16_t), erase_check_code[i]);

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;

	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);

	if ((retval = target_run_algorithm(target, 0, NULL, 3, reg_params,
			erase_check_algorithm->address, erase_check_algorithm->address + (sizeof(erase_check_code)-2), 10000, &armv7m_info)) != 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, erase_check_algorithm);
		return 0;
	}

	*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, erase_check_algorithm);

	return ERROR_OK;
}
Exemplo n.º 15
0
static int str9x_write_block(struct flash_bank *bank,
		uint8_t *buffer, uint32_t offset, uint32_t count)
{
	struct str9x_flash_bank *str9x_info = bank->driver_priv;
	struct target *target = bank->target;
	uint32_t buffer_size = 8192;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[4];
	struct arm_algorithm armv4_5_info;
	int retval = ERROR_OK;

	uint32_t str9x_flash_write_code[] = {
					/* write:				*/
		0xe3c14003,	/*	bic	r4, r1, #3		*/
		0xe3a03040,	/*	mov	r3, #0x40		*/
		0xe1c430b0,	/*	strh r3, [r4, #0]	*/
		0xe0d030b2,	/*	ldrh r3, [r0], #2	*/
		0xe0c130b2,	/*	strh r3, [r1], #2	*/
		0xe3a03070,	/*	mov r3, #0x70		*/
		0xe1c430b0,	/*	strh r3, [r4, #0]	*/
					/* busy:				*/
		0xe5d43000,	/*	ldrb r3, [r4, #0]	*/
		0xe3130080,	/*	tst r3, #0x80		*/
		0x0afffffc,	/*	beq busy			*/
		0xe3a05050,	/*	mov	r5, #0x50		*/
		0xe1c450b0,	/*	strh r5, [r4, #0]	*/
		0xe3a050ff,	/*	mov	r5, #0xFF		*/
		0xe1c450b0,	/*	strh r5, [r4, #0]	*/
		0xe3130012,	/*	tst	r3, #0x12		*/
		0x1a000001,	/*	bne exit			*/
		0xe2522001,	/*	subs r2, r2, #1		*/
		0x1affffed,	/*	bne write			*/
					/* exit:				*/
		0xeafffffe,	/*	b exit				*/
	};

	/* flash write code */
	if (target_alloc_working_area(target, 4 * 19, &str9x_info->write_algorithm) != ERROR_OK)
	{
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	target_write_buffer(target, str9x_info->write_algorithm->address, 19 * 4, (uint8_t*)str9x_flash_write_code);

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
			/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
			if (str9x_info->write_algorithm)
				target_free_working_area(target, str9x_info->write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv4_5_info.common_magic = ARM_COMMON_MAGIC;
	armv4_5_info.core_mode = ARM_MODE_SVC;
	armv4_5_info.core_state = ARM_STATE_ARM;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);

	while (count > 0)
	{
		uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;

		target_write_buffer(target, source->address, thisrun_count * 2, buffer);

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);

		if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, str9x_info->write_algorithm->address, str9x_info->write_algorithm->address + (18 * 4), 10000, &armv4_5_info)) != ERROR_OK)
		{
			LOG_ERROR("error executing str9x flash write algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) != 0x80)
		{
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		buffer += thisrun_count * 2;
		address += thisrun_count * 2;
		count -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, str9x_info->write_algorithm);

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

	return retval;
}
Exemplo n.º 16
0
static int msp432_init(struct flash_bank *bank)
{
	struct target *target = bank->target;
	struct msp432_bank *msp432_bank = bank->driver_priv;
	struct msp432_algo_params algo_params;
	struct reg_param reg_params[1];

	const uint8_t *loader_code;
	uint32_t loader_size;
	uint32_t algo_entry_addr;
	int retval;

	/* Make sure we've probed the flash to get the device and size */
	retval = msp432_auto_probe(bank);
	if (ERROR_OK != retval)
		return retval;

	/* Choose appropriate flash helper algorithm */
	switch (msp432_bank->device_type) {
		case MSP432P401X:
		case MSP432P401X_DEPR:
		case MSP432P401X_GUESS:
		default:
			loader_code = msp432p401x_algo;
			loader_size = sizeof(msp432p401x_algo);
			algo_entry_addr = P4_ALGO_ENTRY_ADDR;
			break;
		case MSP432P411X:
		case MSP432P411X_GUESS:
			loader_code = msp432p411x_algo;
			loader_size = sizeof(msp432p411x_algo);
			algo_entry_addr = P4_ALGO_ENTRY_ADDR;
			break;
		case MSP432E401Y:
		case MSP432E411Y:
		case MSP432E4X_GUESS:
			loader_code = msp432e4x_algo;
			loader_size = sizeof(msp432e4x_algo);
			algo_entry_addr = E4_ALGO_ENTRY_ADDR;
			break;
	}

	/* Issue warnings if this is a device we may not be able to flash */
	if (MSP432P401X_GUESS == msp432_bank->device_type ||
		MSP432P411X_GUESS == msp432_bank->device_type) {
		/* Explicit device type check failed. Report this. */
		LOG_WARNING(
			"msp432: Unrecognized MSP432P4 Device ID and Hardware "
			"Rev (%04X, %02X)", msp432_bank->device_id,
			msp432_bank->hardware_rev);
	} else if (MSP432P401X_DEPR == msp432_bank->device_type) {
		LOG_WARNING(
			"msp432: MSP432P401x pre-production device (deprecated "
			"silicon)\n" SUPPORT_MESSAGE);
	} else if (MSP432E4X_GUESS == msp432_bank->device_type) {
		/* Explicit device type check failed. Report this. */
		LOG_WARNING(
			"msp432: Unrecognized MSP432E4 DID0 and DID1 values "
			"(%08X, %08X)", msp432_bank->device_id,
			msp432_bank->hardware_rev);
	}

	/* Check for working area to use for flash helper algorithm */
	if (NULL != msp432_bank->working_area)
		target_free_working_area(target, msp432_bank->working_area);
	retval = target_alloc_working_area(target, ALGO_WORKING_SIZE,
				&msp432_bank->working_area);
	if (ERROR_OK != retval)
		return retval;

	/* Confirm the defined working address is the area we need to use */
	if (ALGO_BASE_ADDR != msp432_bank->working_area->address)
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	/* Write flash helper algorithm into target memory */
	retval = target_write_buffer(target, ALGO_BASE_ADDR, loader_size,
				loader_code);
	if (ERROR_OK != retval)
		return retval;

	/* Initialize the ARMv7 specific info to run the algorithm */
	msp432_bank->armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	msp432_bank->armv7m_info.core_mode = ARM_MODE_THREAD;

	/* Initialize algorithm parameters to default values */
	msp432_init_params(&algo_params);

	/* Write out parameters to target memory */
	retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR,
				sizeof(algo_params), (uint8_t *)&algo_params);
	if (ERROR_OK != retval)
		return retval;

	/* Initialize stack pointer for flash helper algorithm */
	init_reg_param(&reg_params[0], "sp", 32, PARAM_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, ALGO_STACK_POINTER_ADDR);

	/* Begin executing the flash helper algorithm */
	retval = target_start_algorithm(target, 0, 0, 1, reg_params,
				algo_entry_addr, 0, &msp432_bank->armv7m_info);
	destroy_reg_param(&reg_params[0]);
	if (ERROR_OK != retval) {
		LOG_ERROR("msp432: Failed to start flash helper algorithm");
		return retval;
	}

	/*
	 * At this point, the algorithm is running on the target and
	 * ready to receive commands and data to flash the target
	 */

	/* Issue the init command to the flash helper algorithm */
	retval = msp432_exec_cmd(target, &algo_params, FLASH_INIT);
	if (ERROR_OK != retval)
		return retval;

	retval = msp432_wait_return_code(target);

	return retval;
}
Exemplo n.º 17
0
/* Un-initialize the ssp module and initialize the SPIFI module */
static int lpcspifi_set_hw_mode(struct flash_bank *bank)
{
	struct target *target = bank->target;
	struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
	uint32_t ssp_base = lpcspifi_info->ssp_base;
	struct armv7m_algorithm armv7m_info;
	struct working_area *spifi_init_algorithm;
	struct reg_param reg_params[2];
	int retval = ERROR_OK;

	LOG_DEBUG("Uninitializing LPC43xx SSP");
	/* Turn off the SSP module */
	retval = ssp_write_reg(target, ssp_base, SSP_CR1, 0x00000000);
	if (retval != ERROR_OK)
		return retval;

	/* see contrib/loaders/flash/lpcspifi_init.S for src */
	static const uint8_t spifi_init_code[] = {
		0x4f, 0xea, 0x00, 0x08, 0xa1, 0xb0, 0x00, 0xaf,
		0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
		0x4f, 0xf0, 0xf3, 0x02, 0xc3, 0xf8, 0x8c, 0x21,
		0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
		0x4f, 0xf4, 0xc0, 0x42, 0xc4, 0xf2, 0x08, 0x02,
		0x4f, 0xf4, 0xc0, 0x41, 0xc4, 0xf2, 0x08, 0x01,
		0x4f, 0xf4, 0xc0, 0x40, 0xc4, 0xf2, 0x08, 0x00,
		0x4f, 0xf0, 0xd3, 0x04, 0xc0, 0xf8, 0x9c, 0x41,
		0x20, 0x46, 0xc1, 0xf8, 0x98, 0x01, 0x01, 0x46,
		0xc2, 0xf8, 0x94, 0x11, 0xc3, 0xf8, 0x90, 0x11,
		0x4f, 0xf4, 0xc0, 0x43, 0xc4, 0xf2, 0x08, 0x03,
		0x4f, 0xf0, 0x13, 0x02, 0xc3, 0xf8, 0xa0, 0x21,
		0x40, 0xf2, 0x18, 0x13, 0xc1, 0xf2, 0x40, 0x03,
		0x1b, 0x68, 0x1c, 0x68, 0x40, 0xf2, 0xb4, 0x30,
		0xc1, 0xf2, 0x00, 0x00, 0x4f, 0xf0, 0x03, 0x01,
		0x4f, 0xf0, 0xc0, 0x02, 0x4f, 0xea, 0x08, 0x03,
		0xa0, 0x47, 0x00, 0xf0, 0x00, 0xb8, 0x00, 0xbe
	};

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;


	LOG_DEBUG("Allocating working area for SPIFI init algorithm");
	/* Get memory for spifi initialization algorithm */
	retval = target_alloc_working_area(target, sizeof(spifi_init_code)
		+ SPIFI_INIT_STACK_SIZE, &spifi_init_algorithm);
	if (retval != ERROR_OK) {
		LOG_ERROR("Insufficient working area to initialize SPIFI "\
			"module. You must allocate at least %zdB of working "\
			"area in order to use this driver.",
			sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE
		);

		return retval;
	}

	LOG_DEBUG("Writing algorithm to working area at 0x%08" PRIx32,
		spifi_init_algorithm->address);
	/* Write algorithm to working area */
	retval = target_write_buffer(target,
		spifi_init_algorithm->address,
		sizeof(spifi_init_code),
		spifi_init_code
	);

	if (retval != ERROR_OK) {
		target_free_working_area(target, spifi_init_algorithm);
		return retval;
	}

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);		/* spifi clk speed */
	/* the spifi_init() rom API makes use of the stack */
	init_reg_param(&reg_params[1], "sp", 32, PARAM_OUT);

	/* For now, the algorithm will set up the SPIFI module
	 * @ the IRC clock speed. In the future, it could be made
	 * a bit smarter to use other clock sources if the user has
	 * already configured them in order to speed up memory-
	 * mapped reads. */
	buf_set_u32(reg_params[0].value, 0, 32, 12);
	/* valid stack pointer */
	buf_set_u32(reg_params[1].value, 0, 32, (spifi_init_algorithm->address +
		sizeof(spifi_init_code) + SPIFI_INIT_STACK_SIZE) & ~7UL);

	/* Run the algorithm */
	LOG_DEBUG("Running SPIFI init algorithm");
	retval = target_run_algorithm(target, 0 , NULL, 2, reg_params,
		spifi_init_algorithm->address,
		spifi_init_algorithm->address + sizeof(spifi_init_code) - 2,
		1000, &armv7m_info);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing SPIFI init algorithm");

	target_free_working_area(target, spifi_init_algorithm);

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

	return retval;
}
Exemplo n.º 18
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;
}
Exemplo n.º 19
0
static int lpcspifi_write(struct flash_bank *bank, const uint8_t *buffer,
	uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	struct lpcspifi_flash_bank *lpcspifi_info = bank->driver_priv;
	uint32_t page_size, fifo_size;
	struct working_area *fifo;
	struct reg_param reg_params[5];
	struct armv7m_algorithm armv7m_info;
	struct working_area *write_algorithm;
	int sector;
	int retval = ERROR_OK;

	LOG_DEBUG("offset=0x%08" PRIx32 " count=0x%08" PRIx32,
		offset, count);

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

	if (offset + count > lpcspifi_info->dev->size_in_bytes) {
		LOG_WARNING("Writes past end of flash. Extra data discarded.");
		count = lpcspifi_info->dev->size_in_bytes - offset;
	}

	/* Check sector protection */
	for (sector = 0; sector < bank->num_sectors; sector++) {
		/* Start offset in or before this sector? */
		/* End offset in or behind this sector? */
		if ((offset <
				(bank->sectors[sector].offset + bank->sectors[sector].size))
			&& ((offset + count - 1) >= bank->sectors[sector].offset)
			&& bank->sectors[sector].is_protected) {
			LOG_ERROR("Flash sector %d protected", sector);
			return ERROR_FAIL;
		}
	}

	page_size = lpcspifi_info->dev->pagesize;

	retval = lpcspifi_set_hw_mode(bank);
	if (retval != ERROR_OK)
		return retval;

	/* see contrib/loaders/flash/lpcspifi_write.S for src */
	static const uint8_t lpcspifi_flash_write_code[] = {
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x08, 0x0a,
		0x4f, 0xf0, 0xea, 0x08, 0xca, 0xf8, 0x8c, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x90, 0x81,
		0x4f, 0xf0, 0x40, 0x08, 0xca, 0xf8, 0x94, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x98, 0x81,
		0x4f, 0xf0, 0xed, 0x08, 0xca, 0xf8, 0x9c, 0x81,
		0x4f, 0xf0, 0x44, 0x08, 0xca, 0xf8, 0xa0, 0x81,
		0x4f, 0xf4, 0xc0, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf4, 0x00, 0x68, 0xca, 0xf8, 0x14, 0x80,
		0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0x4f, 0xf0, 0xff, 0x08, 0xca, 0xf8, 0xab, 0x80,
		0x4f, 0xf0, 0x00, 0x0a, 0xc4, 0xf2, 0x05, 0x0a,
		0x4f, 0xf0, 0x00, 0x08, 0xc0, 0xf2, 0x00, 0x18,
		0xca, 0xf8, 0x94, 0x80, 0x4f, 0xf4, 0x00, 0x5a,
		0xc4, 0xf2, 0x05, 0x0a, 0x4f, 0xf0, 0x01, 0x08,
		0xca, 0xf8, 0x00, 0x87, 0x4f, 0xf4, 0x40, 0x5a,
		0xc4, 0xf2, 0x08, 0x0a, 0x4f, 0xf0, 0x07, 0x08,
		0xca, 0xf8, 0x00, 0x80, 0x4f, 0xf0, 0x02, 0x08,
		0xca, 0xf8, 0x10, 0x80, 0xca, 0xf8, 0x04, 0x80,
		0x4f, 0xf0, 0x00, 0x0b, 0xa3, 0x44, 0x93, 0x45,
		0x7f, 0xf6, 0xfc, 0xaf, 0x00, 0xf0, 0x6a, 0xf8,
		0x4f, 0xf0, 0x06, 0x09, 0x00, 0xf0, 0x53, 0xf8,
		0x00, 0xf0, 0x60, 0xf8, 0x00, 0xf0, 0x62, 0xf8,
		0x4f, 0xf0, 0x05, 0x09, 0x00, 0xf0, 0x4b, 0xf8,
		0x4f, 0xf0, 0x00, 0x09, 0x00, 0xf0, 0x47, 0xf8,
		0x00, 0xf0, 0x54, 0xf8, 0x19, 0xf0, 0x02, 0x0f,
		0x00, 0xf0, 0x5d, 0x80, 0x00, 0xf0, 0x52, 0xf8,
		0x4f, 0xf0, 0x02, 0x09, 0x00, 0xf0, 0x3b, 0xf8,
		0x4f, 0xea, 0x12, 0x49, 0x00, 0xf0, 0x37, 0xf8,
		0x4f, 0xea, 0x12, 0x29, 0x00, 0xf0, 0x33, 0xf8,
		0x4f, 0xea, 0x02, 0x09, 0x00, 0xf0, 0x2f, 0xf8,
		0xd0, 0xf8, 0x00, 0x80, 0xb8, 0xf1, 0x00, 0x0f,
		0x00, 0xf0, 0x47, 0x80, 0x47, 0x68, 0x47, 0x45,
		0x3f, 0xf4, 0xf6, 0xaf, 0x17, 0xf8, 0x01, 0x9b,
		0x00, 0xf0, 0x21, 0xf8, 0x8f, 0x42, 0x28, 0xbf,
		0x00, 0xf1, 0x08, 0x07, 0x47, 0x60, 0x01, 0x3b,
		0xbb, 0xb3, 0x02, 0xf1, 0x01, 0x02, 0x93, 0x45,
		0x7f, 0xf4, 0xe6, 0xaf, 0x00, 0xf0, 0x22, 0xf8,
		0xa3, 0x44, 0x00, 0xf0, 0x23, 0xf8, 0x4f, 0xf0,
		0x05, 0x09, 0x00, 0xf0, 0x0c, 0xf8, 0x4f, 0xf0,
		0x00, 0x09, 0x00, 0xf0, 0x08, 0xf8, 0x00, 0xf0,
		0x15, 0xf8, 0x19, 0xf0, 0x01, 0x0f, 0x7f, 0xf4,
		0xf0, 0xaf, 0xff, 0xf7, 0xa7, 0xbf, 0x4f, 0xf4,
		0x40, 0x5a, 0xc4, 0xf2, 0x08, 0x0a, 0xca, 0xf8,
		0x08, 0x90, 0xda, 0xf8, 0x0c, 0x90, 0x19, 0xf0,
		0x10, 0x0f, 0x7f, 0xf4, 0xfa, 0xaf, 0xda, 0xf8,
		0x08, 0x90, 0x70, 0x47, 0x4f, 0xf0, 0xff, 0x08,
		0x00, 0xf0, 0x02, 0xb8, 0x4f, 0xf0, 0x00, 0x08,
		0x4f, 0xf4, 0x80, 0x4a, 0xc4, 0xf2, 0x0f, 0x0a,
		0xca, 0xf8, 0xab, 0x80, 0x70, 0x47, 0x00, 0x20,
		0x50, 0x60, 0xff, 0xf7, 0xef, 0xff, 0x30, 0x46,
		0x00, 0xbe, 0xff, 0xff
	};

	if (target_alloc_working_area(target, sizeof(lpcspifi_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_ERROR("Insufficient working area. You must configure"\
			" a working area > %zdB in order to write to SPIFI flash.",
			sizeof(lpcspifi_flash_write_code));
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	retval = target_write_buffer(target, write_algorithm->address,
			sizeof(lpcspifi_flash_write_code),
			lpcspifi_flash_write_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return retval;
	}

	/* FIFO allocation */
	fifo_size = target_get_working_area_avail(target);

	if (fifo_size == 0) {
		/* if we already allocated the writing code but failed to get fifo
		 * space, free the algorithm */
		target_free_working_area(target, write_algorithm);

		LOG_ERROR("Insufficient working area. Please allocate at least"\
			" %zdB of working area to enable flash writes.",
			sizeof(lpcspifi_flash_write_code) + 1
		);

		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	} else if (fifo_size < page_size)
		LOG_WARNING("Working area size is limited; flash writes may be"\
			" slow. Increase working area size to at least %zdB"\
			" to reduce write times.",
			(size_t)(sizeof(lpcspifi_flash_write_code) + page_size)
		);
	else if (fifo_size > 0x2000) /* Beyond this point, we start to get diminishing returns */
		fifo_size = 0x2000;

	if (target_alloc_working_area(target, fifo_size, &fifo) != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);		/* buffer start, status (out) */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);		/* buffer end */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);		/* target address */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT);		/* count (halfword-16bit) */
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);		/* page size */

	buf_set_u32(reg_params[0].value, 0, 32, fifo->address);
	buf_set_u32(reg_params[1].value, 0, 32, fifo->address + fifo->size);
	buf_set_u32(reg_params[2].value, 0, 32, offset);
	buf_set_u32(reg_params[3].value, 0, 32, count);
	buf_set_u32(reg_params[4].value, 0, 32, page_size);

	retval = target_run_flash_async_algorithm(target, buffer, count, 1,
			0, NULL,
			5, reg_params,
			fifo->address, fifo->size,
			write_algorithm->address, 0,
			&armv7m_info
	);

	if (retval != ERROR_OK)
		LOG_ERROR("Error executing flash write algorithm");

	target_free_working_area(target, fifo);
	target_free_working_area(target, write_algorithm);

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

	/* Switch to HW mode before return to prompt */
	retval = lpcspifi_set_hw_mode(bank);
	return retval;
}
Exemplo n.º 20
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;
}
Exemplo n.º 21
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;
}
Exemplo n.º 22
0
/** Checks whether a memory region is erased. */
int armv7m_blank_check_memory(struct target *target,
	target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
{
	struct working_area *erase_check_algorithm;
	struct reg_param reg_params[3];
	struct armv7m_algorithm armv7m_info;
	const uint8_t *code;
	uint32_t code_size;
	int retval;

	static const uint8_t erase_check_code[] = {
#include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
	};
	static const uint8_t zero_erase_check_code[] = {
#include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
	};

	switch (erased_value) {
	case 0x00:
		code = zero_erase_check_code;
		code_size = sizeof(zero_erase_check_code);
		break;
	case 0xff:
	default:
		code = erase_check_code;
		code_size = sizeof(erase_check_code);
	}

	/* make sure we have a working area */
	if (target_alloc_working_area(target, code_size,
		&erase_check_algorithm) != ERROR_OK)
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	retval = target_write_buffer(target, erase_check_algorithm->address,
			code_size, code);
	if (retval != ERROR_OK)
		goto cleanup;

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	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, erased_value);

	retval = target_run_algorithm(target,
			0,
			NULL,
			3,
			reg_params,
			erase_check_algorithm->address,
			erase_check_algorithm->address + (code_size - 2),
			10000,
			&armv7m_info);

	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, erase_check_algorithm);

	return retval;
}
Exemplo n.º 23
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;
}
Exemplo n.º 24
0
/* If this fn returns ERROR_TARGET_RESOURCE_NOT_AVAILABLE, then the caller can fall
 * back to another mechanism that does not require onboard RAM
 *
 * Caller should not check for other return values specifically
 */
static int aduc702x_write_block(struct flash_bank *bank,
	uint8_t *buffer,
	uint32_t offset,
	uint32_t count)
{
	struct target *target = bank->target;
	uint32_t buffer_size = 7000;
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[6];
	struct arm_algorithm arm_algo;
	int retval = ERROR_OK;

	if (((count%2) != 0) || ((offset%2) != 0)) {
		LOG_ERROR("write block must be multiple of two bytes in offset & length");
		return ERROR_FAIL;
	}

	/* parameters:

	r0 - address of source data (absolute)
	r1 - number of halfwords to be copied
	r2 - start address in flash (offset from beginning of flash memory)
	r3 - exit code
	r4 - base address of flash controller (0xFFFFF800)

	registers:

	r5 - scratch
	r6 - set to 2, used to write flash command

	*/
	static const uint32_t aduc702x_flash_write_code[] = {
		/* <_start>: */
		0xe3a05008,	/* mov	r5, #8	; 0x8 */
		0xe5845004,	/* str	r5, [r4, #4] */
		0xe3a06002,	/* mov	r6, #2	; 0x2 */
		/* <next>: */
		0xe1c421b0,	/* strh	r2, [r4, #16] */
		0xe0d050b2,	/* ldrh	r5, [r0], #2 */
		0xe1c450bc,	/* strh	r5, [r4, #12] */
		0xe5c46008,	/* strb	r6, [r4, #8] */
		/* <wait_complete>: */
		0xe1d430b0,	/* ldrh	r3, [r4] */
		0xe3130004,	/* tst	r3, #4	; 0x4 */
		0x1afffffc,	/* bne	1001c <wait_complete> */
		0xe2822002,	/* add	r2, r2, #2	; 0x2 */
		0xe2511001,	/* subs	r1, r1, #1	; 0x1 */
		0x0a000001,	/* beq	1003c <done> */
		0xe3130001,	/* tst	r3, #1	; 0x1 */
		0x1afffff3,	/* bne	1000c <next> */
		/* <done>: */
		0xeafffffe	/* b	1003c <done> */
	};

	/* flash write code */
	if (target_alloc_working_area(target, sizeof(aduc702x_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	uint8_t code[sizeof(aduc702x_flash_write_code)];
	target_buffer_set_u32_array(target, code, ARRAY_SIZE(aduc702x_flash_write_code),
			aduc702x_flash_write_code);
	retval = target_write_buffer(target, write_algorithm->address, sizeof(code), code);
	if (retval != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
		buffer_size /= 2;
		if (buffer_size <= 256) {
			/* we already allocated the writing code, but failed to get a buffer,
			 *free the algorithm */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	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);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT);

	while (count > 0) {
		uint32_t thisrun_count = (count > buffer_size) ? buffer_size : count;

		retval = target_write_buffer(target, source->address, thisrun_count, buffer);
		if (retval != ERROR_OK)
			break;

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, thisrun_count/2);
		buf_set_u32(reg_params[2].value, 0, 32, address);
		buf_set_u32(reg_params[4].value, 0, 32, 0xFFFFF800);

		retval = target_run_algorithm(target, 0, NULL, 5,
				reg_params, write_algorithm->address,
				write_algorithm->address +
				sizeof(aduc702x_flash_write_code) - 4,
				10000, &arm_algo);
		if (retval != ERROR_OK) {
			LOG_ERROR("error executing aduc702x flash write algorithm");
			break;
		}

		if ((buf_get_u32(reg_params[3].value, 0, 32) & 1) != 1) {
			/* FIX!!!! what does this mean??? replace w/sensible error message */
			LOG_ERROR("aduc702x detected error writing flash");
			retval = ERROR_FAIL;
			break;
		}

		buffer += thisrun_count;
		address += thisrun_count;
		count -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

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

	return retval;
}
Exemplo n.º 25
0
int mips32_checksum_memory(struct target *target, uint32_t address,
		uint32_t count, uint32_t *checksum)
{
	struct working_area *crc_algorithm;
	struct reg_param reg_params[2];
	struct mips32_algorithm mips32_info;
	int retval;
	uint32_t i;

	/* see contib/loaders/checksum/mips32.s for src */

	static const uint32_t mips_crc_code[] = {
		0x248C0000,		/* addiu	$t4, $a0, 0 */
		0x24AA0000,		/* addiu	$t2, $a1, 0 */
		0x2404FFFF,		/* addiu	$a0, $zero, 0xffffffff */
		0x10000010,		/* beq		$zero, $zero, ncomp */
		0x240B0000,		/* addiu	$t3, $zero, 0 */
						/* nbyte: */
		0x81850000,		/* lb		$a1, ($t4) */
		0x218C0001,		/* addi		$t4, $t4, 1 */
		0x00052E00,		/* sll		$a1, $a1, 24 */
		0x3C0204C1,		/* lui		$v0, 0x04c1 */
		0x00852026,		/* xor		$a0, $a0, $a1 */
		0x34471DB7,		/* ori		$a3, $v0, 0x1db7 */
		0x00003021,		/* addu		$a2, $zero, $zero */
						/* loop: */
		0x00044040,		/* sll		$t0, $a0, 1 */
		0x24C60001,		/* addiu	$a2, $a2, 1 */
		0x28840000,		/* slti		$a0, $a0, 0 */
		0x01074826,		/* xor		$t1, $t0, $a3 */
		0x0124400B,		/* movn		$t0, $t1, $a0 */
		0x28C30008,		/* slti		$v1, $a2, 8 */
		0x1460FFF9,		/* bne		$v1, $zero, loop */
		0x01002021,		/* addu		$a0, $t0, $zero */
						/* ncomp: */
		0x154BFFF0,		/* bne		$t2, $t3, nbyte */
		0x256B0001,		/* addiu	$t3, $t3, 1 */
		0x7000003F,		/* sdbbp */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(mips_crc_code), &crc_algorithm) != ERROR_OK)
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	/* convert flash writing code into a buffer in target endianness */
	for (i = 0; i < ARRAY_SIZE(mips_crc_code); i++)
		target_write_u32(target, crc_algorithm->address + i*sizeof(uint32_t), mips_crc_code[i]);

	mips32_info.common_magic = MIPS32_COMMON_MAGIC;
	mips32_info.isa_mode = MIPS32_ISA_MIPS32;

	init_reg_param(&reg_params[0], "a0", 32, PARAM_IN_OUT);
	buf_set_u32(reg_params[0].value, 0, 32, address);

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

	int timeout = 20000 * (1 + (count / (1024 * 1024)));

	retval = target_run_algorithm(target, 0, NULL, 2, reg_params,
			crc_algorithm->address, crc_algorithm->address + (sizeof(mips_crc_code)-4), timeout,
			&mips32_info);
	if (retval != ERROR_OK) {
		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;
}
Exemplo n.º 26
0
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count)
{
	struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
	struct target *target = bank->target;
	uint32_t buffer_size = 16384;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;

	uint8_t stm32x_flash_write_code[] = {
									/* write: */
		0xDF, 0xF8, 0x24, 0x40,		/* ldr	r4, STM32_FLASH_CR */
		0x09, 0x4D,					/* ldr	r5, STM32_FLASH_SR */
		0x4F, 0xF0, 0x01, 0x03,		/* mov	r3, #1 */
		0x23, 0x60,					/* str	r3, [r4, #0] */
		0x30, 0xF8, 0x02, 0x3B,		/* ldrh r3, [r0], #2 */
		0x21, 0xF8, 0x02, 0x3B,		/* strh r3, [r1], #2 */
									/* busy: */
		0x2B, 0x68,					/* ldr 	r3, [r5, #0] */
		0x13, 0xF0, 0x01, 0x0F,		/* tst 	r3, #0x01 */
		0xFB, 0xD0,					/* beq 	busy */
		0x13, 0xF0, 0x14, 0x0F,		/* tst	r3, #0x14 */
		0x01, 0xD1,					/* bne	exit */
		0x01, 0x3A,					/* subs	r2, r2, #1 */
		0xED, 0xD1,					/* bne	write */
									/* exit: */
		0xFE, 0xE7,					/* b exit */
		0x10, 0x20, 0x02, 0x40,		/* STM32_FLASH_CR:	.word 0x40022010 */
		0x0C, 0x20, 0x02, 0x40		/* STM32_FLASH_SR:	.word 0x4002200C */
	};

	/* flash write code */
	if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code), &stm32x_info->write_algorithm) != ERROR_OK)
	{
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address, sizeof(stm32x_flash_write_code), stm32x_flash_write_code)) != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK)
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
			/* if we already allocated the writing code, but failed to get a buffer, free the algorithm */
			if (stm32x_info->write_algorithm)
				target_free_working_area(target, stm32x_info->write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	};

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN);

	while (count > 0)
	{
		uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;

		if ((retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer)) != ERROR_OK)
			break;

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);

		if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params, stm32x_info->write_algorithm->address, \
				stm32x_info->write_algorithm->address + (sizeof(stm32x_flash_write_code) - 10), 10000, &armv7m_info)) != ERROR_OK)
		{
			LOG_ERROR("error executing stm32x flash write algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
		{
			LOG_ERROR("flash memory not erased before writing");
			/* Clear but report errors */
			target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR);
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
		{
			LOG_ERROR("flash memory write protected");
			/* Clear but report errors */
			target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR);
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		buffer += thisrun_count * 2;
		address += thisrun_count * 2;
		count -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, stm32x_info->write_algorithm);

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

	return retval;
}
Exemplo n.º 27
0
Arquivo: fm3.c Projeto: olerem/openocd
static int fm3_write_block(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct fm3_flash_bank *fm3_info = bank->driver_priv;
	struct target *target = bank->target;
	uint32_t buffer_size = 2048;		/* 8192 for MB9Bxx6! */
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[6];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;
	uint32_t u32FlashType;
	uint32_t u32FlashSeqAddress1;
	uint32_t u32FlashSeqAddress2;

	u32FlashType = (uint32_t) fm3_info->flashtype;

	if (u32FlashType == fm3_flash_type1) {
		u32FlashSeqAddress1 = 0x00001550;
		u32FlashSeqAddress2 = 0x00000AA8;
	} else if (u32FlashType == fm3_flash_type2) {
		u32FlashSeqAddress1 = 0x00000AA8;
		u32FlashSeqAddress2 = 0x00000554;
	} else {
		LOG_ERROR("Flash/Device type unknown!");
		return ERROR_FLASH_OPERATION_FAILED;
	}

	/* RAMCODE used for fm3 Flash programming:                 */
	/* R0 keeps source start address         (u32Source)       */
	/* R1 keeps target start address         (u32Target)       */
	/* R2 keeps number of halfwords to write (u32Count)        */
	/* R3 keeps Flash Sequence address 1     (u32FlashSeq1)    */
	/* R4 keeps Flash Sequence address 2     (u32FlashSeq2)    */
	/* R5 returns result value               (u32FlashResult)  */

	const uint8_t fm3_flash_write_code[] = {
								/*    fm3_FLASH_IF->FASZ &= 0xFFFD;           */
	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x4F, 0xF6, 0xFD, 0x76,		/*        MOVW     R6, #0xFFFD                */
	0x35, 0x40,					/*        ANDS     R5, R5, R6                 */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x35, 0x60,					/*        STR      R5, [R6]                   */
								/*    fm3_FLASH_IF->FASZ |= 1;                */
	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
	0x2D, 0x68,					/*        LDR      R5, [R3]                   */
	0x55, 0xF0, 0x01, 0x05,		/*        ORRS.W   R5, R5, #1                 */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x35, 0x60,					/*        STR      R5, [R6]                   */
								/*    u32DummyRead = fm3_FLASH_IF->FASZ;      */
	0x28, 0x4D,					/*        LDR.N    R5, ??u32DummyRead         */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x36, 0x68,					/*        LDR      R6, [R6]                   */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
								/*    u32FlashResult = FLASH_WRITE_NO_RESULT  */
	0x26, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x00, 0x26,					/*        MOVS     R6, #0                     */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
								/*    while ((u32Count > 0 )                  */
								/*      && (u32FlashResult                    */
								/*          == FLASH_WRITE_NO_RESULT))        */
	0x01, 0x2A,					/* L0:    CMP      R2, #1                     */
	0x2C, 0xDB,					/*        BLT.N    L1                         */
	0x24, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x00, 0x2D,					/*        CMP      R5, #0                     */
	0x28, 0xD1,					/*        BNE.N    L1                         */
								/*    *u32FlashSeq1 = FLASH_WRITE_1;          */
	0xAA, 0x25,					/*        MOVS     R5, #0xAA                  */
	0x1D, 0x60,					/*        STR      R5, [R3]                   */
								/*    *u32FlashSeq2 = FLASH_WRITE_2;          */
	0x55, 0x25,					/*        MOVS     R5, #0x55                  */
	0x25, 0x60,					/*        STR      R5, [R4]                   */
								/*    *u32FlashSeq1 = FLASH_WRITE_3;          */
	0xA0, 0x25,					/*        MOVS     R5, #0xA0                  */
	0x1D, 0x60,					/*        STRH     R5, [R3]                   */
								/*    *(volatile uint16_t*)u32Target          */
								/*      = *(volatile uint16_t*)u32Source;     */
	0x05, 0x88,					/*        LDRH     R5, [R0]                   */
	0x0D, 0x80,					/*        STRH     R5, [R1]                   */
								/*    while (u32FlashResult                   */
								/*           == FLASH_WRITE_NO_RESTULT)       */
	0x1E, 0x4D,					/* L2:    LDR.N    R5, ??u32FlashResult       */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x00, 0x2D,					/*        CMP      R5, #0                     */
	0x11, 0xD1,					/*        BNE.N    L3                         */
								/*    if ((*(volatile uint16_t*)u32Target     */
								/*        & FLASH_DQ5) == FLASH_DQ5)          */
	0x0D, 0x88,					/*        LDRH     R5, [R1]                   */
	0xAD, 0x06,					/*        LSLS     R5, R5, #0x1A              */
	0x02, 0xD5,					/*        BPL.N    L4                         */
								/*    u32FlashResult = FLASH_WRITE_TIMEOUT    */
	0x1A, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x02, 0x26,					/*        MOVS     R6, #2                     */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
								/*    if ((*(volatile uint16_t *)u32Target    */
								/*         & FLASH_DQ7)                       */
								/*        == (*(volatile uint16_t*)u32Source  */
								/*            & FLASH_DQ7))                   */
	0x0D, 0x88,					/* L4:    LDRH     R5, [R1]                   */
	0x15, 0xF0, 0x80, 0x05,		/*        ANDS.W   R5, R5, #0x80              */
	0x06, 0x88,					/*        LDRH     R6, [R0]                   */
	0x16, 0xF0, 0x80, 0x06,		/*        ANDS.W   R6, R6, #0x80              */
	0xB5, 0x42,					/*        CMP      R5, R6                     */
	0xED, 0xD1,					/*        BNE.N    L2                         */
								/*    u32FlashResult = FLASH_WRITE_OKAY       */
	0x15, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x01, 0x26,					/*        MOVS     R6, #1                     */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
	0xE9, 0xE7,					/*        B.N      L2                         */
								/*    if (u32FlashResult                      */
								/*        != FLASH_WRITE_TIMEOUT)             */
	0x13, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x02, 0x2D,					/*        CMP      R5, #2                     */
	0x02, 0xD0,					/*        BEQ.N    L5                         */
								/*    u32FlashResult = FLASH_WRITE_NO_RESULT  */
	0x11, 0x4D,					/*        LDR.N    R5, ??u32FlashResult       */
	0x00, 0x26,					/*        MOVS     R6, #0                     */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
								/*    u32Count--;                             */
	0x52, 0x1E,					/* L5:    SUBS     R2, R2, #1                 */
								/*    u32Source += 2;                         */
	0x80, 0x1C,					/*        ADDS     R0, R0, #2                 */
								/*    u32Target += 2;                         */
	0x89, 0x1C,					/*        ADDS     R1, R1, #2                 */
	0xD0, 0xE7,					/*        B.N      L0                         */
								/*    fm3_FLASH_IF->FASZ &= 0xFFFE;           */
	0x5F, 0xF0, 0x80, 0x45,		/* L1:    MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x4F, 0xF6, 0xFE, 0x76,		/*        MOVW     R6, #0xFFFE                */
	0x35, 0x40,					/*        ANDS     R5, R5, R6                 */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x35, 0x60,					/*        STR      R5, [R6]                   */
								/*    fm3_FLASH_IF->FASZ |= 2;                */
	0x5F, 0xF0, 0x80, 0x45,		/*        MOVS.W   R5, #(fm3_FLASH_IF->FASZ)  */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
	0x55, 0xF0, 0x02, 0x05,		/*        ORRS.W   R5, R5, #2                 */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x35, 0x60,					/*        STR      R5, [R6]                   */
								/*    u32DummyRead = fm3_FLASH_IF->FASZ;      */
	0x04, 0x4D,					/*        LDR.N    R5, ??u32DummyRead         */
	0x5F, 0xF0, 0x80, 0x46,		/*        MOVS.W   R6, #(fm3_FLASH_IF->FASZ)  */
	0x36, 0x68,					/*        LDR      R6, [R6]                   */
	0x2E, 0x60,					/*        STR      R6, [R5]                   */
								/*    copy u32FlashResult to R3 for return    */
								/*      value                                 */
	0xDF, 0xF8, 0x08, 0x50,		/*        LDR.W    R5, ??u32FlashResult       */
	0x2D, 0x68,					/*        LDR      R5, [R5]                   */
								/*    Breakpoint here                         */
	0x00, 0xBE,					/*        BKPT     #0                         */

	/* The following address pointers assume, that the code is running from   */
	/* address 0x1FFF8008. These address pointers will be patched, if a       */
	/* different start address in RAM is used (e.g. for Flash type 2)!        */
	0x00, 0x80, 0xFF, 0x1F,     /* u32DummyRead address in RAM (0x1FFF8000)   */
	0x04, 0x80, 0xFF, 0x1F      /* u32FlashResult address in RAM (0x1FFF8004) */
	};

	LOG_INFO("Fujitsu MB9B500: FLASH Write ...");

	/* disable HW watchdog */
	retval = target_write_u32(target, 0x40011C00, 0x1ACCE551);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, 0x40011C00, 0xE5331AAE);
	if (retval != ERROR_OK)
		return retval;

	retval = target_write_u32(target, 0x40011008, 0x00000000);
	if (retval != ERROR_OK)
		return retval;

	count = count / 2;		/* number bytes -> number halfwords */

	/* check code alignment */
	if (offset & 0x1) {
		LOG_WARNING("offset 0x%" PRIx32 " breaks required 2-byte alignment", offset);
		return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
	}

	/* allocate working area with flash programming code */
	if (target_alloc_working_area(target, sizeof(fm3_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	}

	retval = target_write_buffer(target, write_algorithm->address,
		sizeof(fm3_flash_write_code), fm3_flash_write_code);
	if (retval != ERROR_OK)
		return retval;



	/* memory buffer */
	while (target_alloc_working_area(target, buffer_size, &source) != ERROR_OK) {
		buffer_size /= 2;
		if (buffer_size <= 256) {
			/* free working area, write algorithm already allocated */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("No large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT); /* source start address */
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT); /* target start address */
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */
	init_reg_param(&reg_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */
	init_reg_param(&reg_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */
	init_reg_param(&reg_params[5], "r5", 32, PARAM_IN);  /* result */

	/* write code buffer and use Flash programming code within fm3           */
	/* Set breakpoint to 0 with time-out of 1000 ms                          */
	while (count > 0) {
		uint32_t thisrun_count = (count > (buffer_size / 2)) ? (buffer_size / 2) : count;

		retval = target_write_buffer(target, write_algorithm->address, 8,
				fm3_flash_write_code);
		if (retval != ERROR_OK)
			break;

		/* Patching 'local variable address' for different RAM addresses */
		if (write_algorithm->address != 0x1FFF8008) {
			/* Algorithm: u32DummyRead: */
			retval = target_write_u32(target, (write_algorithm->address)
				+ sizeof(fm3_flash_write_code) - 8, (write_algorithm->address) - 8);
			if (retval != ERROR_OK)
				break;

			/* Algorithm: u32FlashResult: */
			retval = target_write_u32(target, (write_algorithm->address)
				+ sizeof(fm3_flash_write_code) - 4, (write_algorithm->address) - 4);
			if (retval != ERROR_OK)
				break;
		}

		retval = target_write_buffer(target, source->address, thisrun_count * 2, buffer);
		if (retval != ERROR_OK)
			break;

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
		buf_set_u32(reg_params[3].value, 0, 32, u32FlashSeqAddress1);
		buf_set_u32(reg_params[4].value, 0, 32, u32FlashSeqAddress2);

		retval = target_run_algorithm(target, 0, NULL, 6, reg_params,
				write_algorithm->address, 0, 1000, &armv7m_info);
		if (retval != ERROR_OK) {
			LOG_ERROR("Error executing fm3 Flash programming algorithm");
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		if (buf_get_u32(reg_params[5].value, 0, 32) != ERROR_OK) {
			LOG_ERROR("Fujitsu MB9[A/B]FXXX: Flash programming ERROR (Timeout) -> Reg R3: %x",
				buf_get_u32(reg_params[5].value, 0, 32));
			retval = ERROR_FLASH_OPERATION_FAILED;
			break;
		}

		buffer  += thisrun_count * 2;
		address += thisrun_count * 2;
		count   -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

	destroy_reg_param(&reg_params[0]);
	destroy_reg_param(&reg_params[1]);
	destroy_reg_param(&reg_params[2]);
	destroy_reg_param(&reg_params[3]);
	destroy_reg_param(&reg_params[4]);
	destroy_reg_param(&reg_params[5]);

	return retval;
}
Exemplo n.º 28
0
static int stm32lx_write_half_pages(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct target *target = bank->target;
	uint32_t buffer_size = 16384;
	struct working_area *write_algorithm;
	struct working_area *source;
	uint32_t address = bank->base + offset;

	struct reg_param reg_params[3];
	struct armv7m_algorithm armv7m_info;

	int retval = ERROR_OK;

	/* see contib/loaders/flash/stm32lx.S for src */

	static const uint8_t stm32lx_flash_write_code[] = {
		/* write_word: */
		0x00, 0x23,             /* movs r3, #0 */
		0x04, 0xe0,             /* b test_done */

		/* write_word: */
		0x51, 0xf8, 0x04, 0xcb, /* ldr ip, [r1], #4 */
		0x40, 0xf8, 0x04, 0xcb, /* str ip, [r0], #4 */
		0x01, 0x33,             /* adds r3, #1 */

		/* test_done: */
		0x93, 0x42,             /* cmp r3, r2 */
		0xf8, 0xd3,             /* bcc write_word */
		0x00, 0xbe,             /* bkpt 0 */
	};

	/* Check if there is an even number of half pages (128bytes) */
	if (count % 128) {
		LOG_ERROR("there should be an even number "
				"of half pages = 128 bytes (count = %" PRIi32 " bytes)", count);
		return ERROR_FAIL;
	}

	/* flash write code */
	if (target_alloc_working_area(target, sizeof(stm32lx_flash_write_code),
			&write_algorithm) != ERROR_OK) {
		LOG_DEBUG("no working area for block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	/* Write the flashing code */
	retval = target_write_buffer(target,
			write_algorithm->address,
			sizeof(stm32lx_flash_write_code),
			(uint8_t *)stm32lx_flash_write_code);
	if (retval != ERROR_OK) {
		target_free_working_area(target, write_algorithm);
		return retval;
	}

	/* Allocate half pages memory */
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK) {
		if (buffer_size > 1024)
			buffer_size -= 1024;
		else
			buffer_size /= 2;

		if (buffer_size <= 256) {
			/* we already allocated the writing code, but failed to get a
			 * buffer, free the algorithm */
			target_free_working_area(target, write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	}

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;
	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);

	/* Enable half-page write */
	retval = stm32lx_enable_write_half_page(bank);
	if (retval != ERROR_OK) {
		target_free_working_area(target, source);
		target_free_working_area(target, write_algorithm);

		destroy_reg_param(&reg_params[0]);
		destroy_reg_param(&reg_params[1]);
		destroy_reg_param(&reg_params[2]);
		return retval;
	}

	struct armv7m_common *armv7m = target_to_armv7m(target);
	if (armv7m == NULL) {

		/* something is very wrong if armv7m is NULL */
		LOG_ERROR("unable to get armv7m target");
		return retval;
	}

	/* save any DEMCR flags and configure target to catch any Hard Faults */
	uint32_t demcr_save = armv7m->demcr;
	armv7m->demcr = VC_HARDERR;

	/* Loop while there are bytes to write */
	while (count > 0) {
		uint32_t this_count;
		this_count = (count > buffer_size) ? buffer_size : count;

		/* Write the next half pages */
		retval = target_write_buffer(target, source->address, this_count, buffer);
		if (retval != ERROR_OK)
			break;

		/* 4: Store useful information in the registers */
		/* the destination address of the copy (R0) */
		buf_set_u32(reg_params[0].value, 0, 32, address);
		/* The source address of the copy (R1) */
		buf_set_u32(reg_params[1].value, 0, 32, source->address);
		/* The length of the copy (R2) */
		buf_set_u32(reg_params[2].value, 0, 32, this_count / 4);

		/* 5: Execute the bunch of code */
		retval = target_run_algorithm(target, 0, NULL, sizeof(reg_params)
				/ sizeof(*reg_params), reg_params,
				write_algorithm->address, 0, 10000, &armv7m_info);
		if (retval != ERROR_OK)
			break;

		/* check for Hard Fault */
		if (armv7m->exception_number == 3)
			break;

		/* 6: Wait while busy */
		retval = stm32lx_wait_until_bsy_clear(bank);
		if (retval != ERROR_OK)
			break;

		buffer += this_count;
		address += this_count;
		count -= this_count;
	}

	/* restore previous flags */
	armv7m->demcr = demcr_save;

	if (armv7m->exception_number == 3) {

		/* the stm32l15x devices seem to have an issue when blank.
		 * if a ram loader is executed on a blank device it will
		 * Hard Fault, this issue does not happen for a already programmed device.
		 * A related issue is described in the stm32l151xx errata (Doc ID 17721 Rev 6 - 2.1.3).
		 * The workaround of handling the Hard Fault exception does work, but makes the
		 * loader more complicated, as a compromise we manually write the pages, programming time
		 * is reduced by 50% using this slower method.
		 */

		LOG_WARNING("couldn't use loader, falling back to page memory writes");

		while (count > 0) {
			uint32_t this_count;
			this_count = (count > 128) ? 128 : count;

			/* Write the next half pages */
			retval = target_write_buffer(target, address, this_count, buffer);
			if (retval != ERROR_OK)
				break;

			/* Wait while busy */
			retval = stm32lx_wait_until_bsy_clear(bank);
			if (retval != ERROR_OK)
				break;

			buffer += this_count;
			address += this_count;
			count -= this_count;
		}
	}

	if (retval == ERROR_OK)
		retval = stm32lx_lock_program_memory(bank);

	target_free_working_area(target, source);
	target_free_working_area(target, write_algorithm);

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

	return retval;
}
Exemplo n.º 29
0
/** Checks whether a memory region is zeroed. */
int armv7m_blank_check_memory(struct target *target,
	uint32_t address, uint32_t count, uint32_t *blank)
{
	struct working_area *erase_check_algorithm;
	struct reg_param reg_params[3];
	struct armv7m_algorithm armv7m_info;
	int retval;

	/* see contrib/loaders/erase_check/armv7m_erase_check.s for src */

	static const uint8_t erase_check_code[] = {
		/* loop: */
		0x03, 0x78,		/* ldrb	r3, [r0] */
		0x01, 0x30,		/* adds	r0, #1 */
		0x1A, 0x40,		/* ands	r2, r2, r3 */
		0x01, 0x39,		/* subs	r1, r1, #1 */
		0xFA, 0xD1,		/* bne	loop */
		0x00, 0xBE		/* bkpt	#0 */
	};

	/* make sure we have a working area */
	if (target_alloc_working_area(target, sizeof(erase_check_code),
		&erase_check_algorithm) != ERROR_OK)
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;

	retval = target_write_buffer(target, erase_check_algorithm->address,
			sizeof(erase_check_code), (uint8_t *)erase_check_code);
	if (retval != ERROR_OK)
		return retval;

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARM_MODE_THREAD;

	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);

	retval = target_run_algorithm(target,
			0,
			NULL,
			3,
			reg_params,
			erase_check_algorithm->address,
			erase_check_algorithm->address + (sizeof(erase_check_code) - 2),
			10000,
			&armv7m_info);

	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]);

	target_free_working_area(target, erase_check_algorithm);

	return retval;
}
Exemplo n.º 30
0
// This is a helper function for the write function which follows.
//  Getting write right can also take a lot of time and playing
//  around with a new chip. 
// The key idea is that code to be programmed into the chip is placed
//  in a buffer in on-chip sram. A routine to do the programming is
//  loaded into on-chip sram as well. The controlling function starts the
//  programming code and keeps the buffer full. This is much faster than
//  trying to program each word individually. Studying this code carefully
//  is well worth while.
static int stm32x_write_block(struct flash_bank *bank, uint8_t *buffer,
		uint32_t offset, uint32_t count)
{
	struct stm32x_flash_bank *stm32x_info = bank->driver_priv;
	struct target *target = bank->target;
	uint32_t buffer_size = 16384;
	struct working_area *source;
	uint32_t address = bank->base + offset;
	struct reg_param reg_params[4];
	struct armv7m_algorithm armv7m_info;
	int retval = ERROR_OK;

	/* see contib/loaders/flash/stm32x.s for src */
	// This is a very nice piece of documentation. Not all drivers provide
	//  it. It's the source program for the assembly code that follows.

	static const uint8_t stm32x_flash_write_code[] = {
									/* #define STM32_FLASH_CR_OFFSET	0x10 */
									/* #define STM32_FLASH_SR_OFFSET	0x0C */
									/* write: */
		0x08, 0x4c,					/* ldr	r4, STM32_FLASH_BASE */
		0x1c, 0x44,					/* add	r4, r3 */
									/* write_half_word: */
		0x01, 0x23,					/* movs	r3, #0x01 */
		0x23, 0x61,					/* str	r3, [r4, #STM32_FLASH_CR_OFFSET] */
		0x30, 0xf8, 0x02, 0x3b,		/* ldrh	r3, [r0], #0x02 */
		0x21, 0xf8, 0x02, 0x3b,		/* strh	r3, [r1], #0x02 */
									/* busy: */
		0xe3, 0x68,					/* ldr	r3, [r4, #STM32_FLASH_SR_OFFSET] */
		0x13, 0xf0, 0x01, 0x0f,		/* tst	r3, #0x01 */
		0xfb, 0xd0,					/* beq	busy */
		0x13, 0xf0, 0x14, 0x0f,		/* tst	r3, #0x14 */
		0x01, 0xd1,					/* bne	exit */
		0x01, 0x3a,					/* subs	r2, r2, #0x01 */
		0xf0, 0xd1,					/* bne	write_half_word */
									/* exit: */
		0x00, 0xbe,					/* bkpt	#0x00 */
		0x00, 0x20, 0x02, 0x40,		/* STM32_FLASH_BASE: .word 0x40022000 */
	};

	/* flash write code */
	if (target_alloc_working_area(target, sizeof(stm32x_flash_write_code),
			&stm32x_info->write_algorithm) != ERROR_OK)
	{
		LOG_WARNING("no working area available, can't do block memory writes");
		return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
	};

	if ((retval = target_write_buffer(target, stm32x_info->write_algorithm->address,
			sizeof(stm32x_flash_write_code),
			(uint8_t*)stm32x_flash_write_code)) != ERROR_OK)
		return retval;

	/* memory buffer */
	while (target_alloc_working_area_try(target, buffer_size, &source) != ERROR_OK)
	{
		buffer_size /= 2;
		if (buffer_size <= 256)
		{
			/* if we already allocated the writing code, but failed to get a
			 * buffer, free the algorithm */
			if (stm32x_info->write_algorithm)
				target_free_working_area(target, stm32x_info->write_algorithm);

			LOG_WARNING("no large enough working area available, can't do block memory writes");
			return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
		}
	};

	// I do not know exactly how the following code works. The effect seems to
	//  be to allow placing specific values in specific registers for the call to the
	//  assembly language routine that writes memory segments. A structure with an
	//  entry for each register seems to be created.

	armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
	armv7m_info.core_mode = ARMV7M_MODE_ANY;

	init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
	init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
	init_reg_param(&reg_params[2], "r2", 32, PARAM_OUT);
	init_reg_param(&reg_params[3], "r3", 32, PARAM_IN_OUT);

	// OK, I understand the code again.
	while (count > 0)
	{
		uint32_t thisrun_count = (count > (buffer_size / 2)) ?
				(buffer_size / 2) : count;

		if ((retval = target_write_buffer(target, source->address,
				thisrun_count * 2, buffer)) != ERROR_OK)
			break;

		buf_set_u32(reg_params[0].value, 0, 32, source->address);
		buf_set_u32(reg_params[1].value, 0, 32, address);
		buf_set_u32(reg_params[2].value, 0, 32, thisrun_count);
		buf_set_u32(reg_params[3].value, 0, 32, stm32x_info->register_offset);

		if ((retval = target_run_algorithm(target, 0, NULL, 4, reg_params,
				stm32x_info->write_algorithm->address,
				0,
				10000, &armv7m_info)) != ERROR_OK)
		{
			LOG_ERROR("error executing stm32x flash write algorithm");
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_PGERR)
		{
			LOG_ERROR("flash memory not erased before writing");
			/* Clear but report errors */
			target_write_u32(target, STM32_FLASH_SR, FLASH_PGERR);
			retval = ERROR_FAIL;
			break;
		}

		if (buf_get_u32(reg_params[3].value, 0, 32) & FLASH_WRPRTERR)
		{
			LOG_ERROR("flash memory write protected");
			/* Clear but report errors */
			target_write_u32(target, STM32_FLASH_SR, FLASH_WRPRTERR);
			retval = ERROR_FAIL;
			break;
		}

		buffer += thisrun_count * 2;
		address += thisrun_count * 2;
		count -= thisrun_count;
	}

	target_free_working_area(target, source);
	target_free_working_area(target, stm32x_info->write_algorithm);

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

	return retval;
}