/** 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; 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 erase check code into a buffer in target endianness */ uint8_t erase_check_code_8[sizeof(erase_check_code)]; target_buffer_set_u32_array(target, erase_check_code_8, ARRAY_SIZE(erase_check_code), erase_check_code); target_write_buffer(target, erase_check_algorithm->address, sizeof(erase_check_code), erase_check_code_8); mips32_info.common_magic = MIPS32_COMMON_MAGIC; mips32_info.isa_mode = MIPS32_ISA_MIPS32; init_reg_param(®_params[0], "r4", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r5", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r6", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0xff); int 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) *blank = buf_get_u32(reg_params[2].value, 0, 32); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** Checks whether a memory region is zeroed. */ int xmc4xxx_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; static const uint8_t erase_check_code[] = { #include "../../../contrib/loaders/erase_check/armv7m_0_erase_check.inc" }; /* 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(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0x00); 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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
static int msp432_exec_cmd(struct target *target, struct msp432_algo_params *algo_params, uint32_t command) { int retval; /* Make sure the given params do not include the command */ buf_set_u32(algo_params->flash_command, 0, 32, FLASH_NO_COMMAND); buf_set_u32(algo_params->return_code, 0, 32, 0); buf_set_u32(algo_params->buffer1_status, 0, 32, BUFFER_INACTIVE); buf_set_u32(algo_params->buffer2_status, 0, 32, BUFFER_INACTIVE); /* Write out parameters to target memory */ retval = target_write_buffer(target, ALGO_PARAMS_BASE_ADDR, sizeof(struct msp432_algo_params), (uint8_t *)algo_params); if (ERROR_OK != retval) return retval; /* Write out command to target memory */ retval = target_write_buffer(target, ALGO_FLASH_COMMAND_ADDR, sizeof(command), (uint8_t *)&command); return retval; }
/** Generates a CRC32 checksum of a memory region. */ int armv7m_checksum_memory(struct target *target, target_addr_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; static const uint8_t cortex_m_crc_code[] = { #include "../../contrib/loaders/checksum/armv7m_crc.inc" }; retval = target_alloc_working_area(target, sizeof(cortex_m_crc_code), &crc_algorithm); if (retval != ERROR_OK) return retval; retval = target_write_buffer(target, crc_algorithm->address, sizeof(cortex_m_crc_code), (uint8_t *)cortex_m_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(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); 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_m_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(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
static int loadDriver(struct ecosflash_flash_bank *info) { size_t buf_cnt; size_t image_size; struct image image; image.base_address_set = 0; image.start_address_set = 0; struct target *target = info->target; int retval; if ((retval = image_open(&image, info->driverPath, NULL)) != ERROR_OK) { return retval; } info->start_address = image.start_address; image_size = 0x0; int i; for (i = 0; i < image.num_sections; i++) { void *buffer = malloc(image.sections[i].size); if ((retval = image_read_section(&image, i, 0x0, image.sections[i].size, buffer, &buf_cnt)) != ERROR_OK) { free(buffer); image_close(&image); return retval; } target_write_buffer(target, image.sections[i].base_address, buf_cnt, buffer); image_size += buf_cnt; LOG_DEBUG("%zu bytes written at address 0x%8.8" PRIx32 "", buf_cnt, image.sections[i].base_address); free(buffer); } image_close(&image); return ERROR_OK; }
static int smi_write_buffer(struct flash_bank *bank, uint8_t *buffer, uint32_t address, uint32_t len) { struct target *target = bank->target; struct stmsmi_flash_bank *stmsmi_info = bank->driver_priv; uint32_t io_base = stmsmi_info->io_base; int retval; LOG_DEBUG("%s: address=0x%08" PRIx32 " len=0x%08" PRIx32, __FUNCTION__, address, len); retval = smi_write_enable(bank); if (retval != ERROR_OK) return retval; /* HW mode, write burst mode */ SMI_SET_HWWB_MODE(); retval = target_write_buffer(target, address, len, buffer); if (retval != ERROR_OK) return retval; return ERROR_OK; }
/* 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[1]; 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_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) ); 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(®_params[0], "r0", 32, PARAM_OUT); /* spifi clk speed */ /* 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); /* Run the algorithm */ LOG_DEBUG("Running SPIFI init algorithm"); retval = target_run_algorithm(target, 0 , NULL, 1, 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(®_params[0]); return retval; }
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(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* page size */ init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; }
int mips32_run_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info) { struct mips32_common *mips32 = target_to_mips32(target); struct mips32_algorithm *mips32_algorithm_info = arch_info; enum mips32_isa_mode isa_mode = mips32->isa_mode; uint32_t context[MIPS32NUMCOREREGS]; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); /* NOTE: mips32_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (mips32->common_magic != MIPS32_COMMON_MAGIC) { LOG_ERROR("current target isn't a MIPS32 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { if (!mips32->core_cache->reg_list[i].valid) mips32->read_core_reg(target, i); context[i] = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); } for (i = 0; i < num_mem_params; i++) { if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } mips32_set_core_reg(reg, reg_params[i].value); } mips32->isa_mode = mips32_algorithm_info->isa_mode; retval = mips32_run_and_wait(target, entry_point, timeout_ms, exit_point, mips32); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { if ((retval = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) { return retval; } } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(mips32->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before */ for (i = 0; i < MIPS32NUMCOREREGS; i++) { uint32_t regvalue; regvalue = buf_get_u32(mips32->core_cache->reg_list[i].value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32, mips32->core_cache->reg_list[i].name, context[i]); buf_set_u32(mips32->core_cache->reg_list[i].value, 0, 32, context[i]); mips32->core_cache->reg_list[i].valid = 1; mips32->core_cache->reg_list[i].dirty = 1; } } mips32->isa_mode = isa_mode; return ERROR_OK; }
/** 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(®_params[0], "r0", 32, PARAM_IN_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); buf_set_u32(reg_params[1].value, 0, 32, count); 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(®_params[0]); destroy_reg_param(®_params[1]); cleanup: target_free_working_area(target, crc_algorithm); return retval; }
static int msp432_write(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; struct msp432_bank *msp432_bank = bank->driver_priv; struct msp432_algo_params algo_params; uint32_t size; uint32_t data_ready = BUFFER_DATA_READY; long long start_ms; long long elapsed_ms; int retval; if (TARGET_HALTED != target->state) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } /* * Block attempts to write to read-only sectors of flash * The TVL region in sector 1 of the info flash is always read-only * The BSL region in sectors 2 and 3 of the info flash may be unlocked * The helper algorithm will hang on attempts to write to TVL */ if (1 == bank->bank_number) { /* Set read-only start to TVL sector */ uint32_t start = 0x1000; /* Set read-only end after BSL region if locked */ uint32_t end = (msp432_bank->unlock_bsl) ? 0x2000 : 0x4000; /* Check if request includes anything in read-only sectors */ if ((offset + count - 1) < start || offset >= end) { /* The request includes no bytes in read-only sectors */ /* Fall out and process the request normally */ } else { /* Send a request for anything before read-only sectors */ if (offset < start) { uint32_t start_count = MIN(start - offset, count); retval = msp432_write(bank, buffer, offset, start_count); if (ERROR_OK != retval) return retval; } /* Send a request for anything after read-only sectors */ if ((offset + count - 1) >= end) { uint32_t skip = end - offset; count -= skip; offset += skip; buffer += skip; return msp432_write(bank, buffer, offset, count); } else { /* Request is entirely in read-only sectors */ return ERROR_OK; } } } retval = msp432_init(bank); if (ERROR_OK != retval) return retval; /* Initialize algorithm parameters to default values */ msp432_init_params(&algo_params); /* Set up parameters for requested flash write operation */ buf_set_u32(algo_params.address, 0, 32, bank->base + offset); buf_set_u32(algo_params.length, 0, 32, count); /* Check if this is the info bank */ if (1 == bank->bank_number) { /* And flag if BSL is unlocked */ if (msp432_bank->unlock_bsl) buf_set_u32(algo_params.unlock_bsl, 0, 32, FLASH_UNLOCK_BSL); } /* Set up flash helper algorithm to continuous flash mode */ retval = msp432_exec_cmd(target, &algo_params, FLASH_CONTINUOUS); if (ERROR_OK != retval) { (void)msp432_quit(bank); return retval; } /* Write requested data, one buffer at a time */ start_ms = timeval_ms(); while (count > 0) { if (count > ALGO_BUFFER_SIZE) size = ALGO_BUFFER_SIZE; else size = count; /* Put next block of data to flash into buffer */ retval = target_write_buffer(target, ALGO_BUFFER1_ADDR, size, buffer); if (ERROR_OK != retval) { LOG_ERROR("Unable to write data to target memory"); (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; } /* Signal the flash helper algorithm that data is ready to flash */ retval = target_write_buffer(target, ALGO_BUFFER1_STATUS_ADDR, sizeof(data_ready), (uint8_t *)&data_ready); if (ERROR_OK != retval) { (void)msp432_quit(bank); return ERROR_FLASH_OPERATION_FAILED; } retval = msp432_wait_inactive(target, 1); if (ERROR_OK != retval) { (void)msp432_quit(bank); return retval; } count -= size; buffer += size; elapsed_ms = timeval_ms() - start_ms; if (elapsed_ms > 500) keep_alive(); } /* Confirm that the flash helper algorithm is finished */ retval = msp432_wait_return_code(target); if (ERROR_OK != retval) { (void)msp432_quit(bank); return retval; } retval = msp432_quit(bank); if (ERROR_OK != retval) return retval; return retval; }
/** 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(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); cleanup: target_free_working_area(target, erase_check_algorithm); return retval; }
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 *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), &fm3_info->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, fm3_info->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, if write algorithm already allocated */ if (fm3_info->write_algorithm) { target_free_working_area(target, fm3_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(®_params[0], "r0", 32, PARAM_OUT); /* source start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* target start address */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* number of halfwords to program */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_params[4], "r4", 32, PARAM_OUT); /* Flash Sequence address 1 */ init_reg_param(®_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, fm3_info->write_algorithm->address, 8, fm3_flash_write_code); if (retval != ERROR_OK) break; /* Patching 'local variable address' for different RAM addresses */ if (fm3_info->write_algorithm->address != 0x1FFF8008) { /* Algorithm: u32DummyRead: */ retval = target_write_u32(target, (fm3_info->write_algorithm->address) + sizeof(fm3_flash_write_code) - 8, (fm3_info->write_algorithm->address) - 8); if (retval != ERROR_OK) break; /* Algorithm: u32FlashResult: */ retval = target_write_u32(target, (fm3_info->write_algorithm->address) + sizeof(fm3_flash_write_code) - 4, (fm3_info->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, fm3_info->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; }
int armv4_5_run_algorithm_inner(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info, int (*run_it)(struct target *target, uint32_t exit_point, int timeout_ms, void *arch_info)) { struct arm *arm = target_to_arm(target); struct arm_algorithm *arm_algorithm_info = arch_info; enum arm_state core_state = arm->core_state; uint32_t context[17]; uint32_t cpsr; int exit_breakpoint_size = 0; int i; int retval = ERROR_OK; LOG_DEBUG("Running algorithm"); if (arm_algorithm_info->common_magic != ARM_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV4/5 target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } if (!is_arm_mode(arm->core_mode)) { LOG_ERROR("not a valid arm core mode - communication failure?"); return ERROR_FAIL; } /* armv5 and later can terminate with BKPT instruction; less overhead */ if (!exit_point && arm->is_armv4) { LOG_ERROR("ARMv4 target needs HW breakpoint location"); return ERROR_FAIL; } /* save r0..pc, cpsr-or-spsr, and then cpsr-for-sure; * they'll be restored later. */ for (i = 0; i <= 16; i++) { struct reg *r; r = &ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i); if (!r->valid) arm->read_core_reg(target, r, i, arm_algorithm_info->core_mode); context[i] = buf_get_u32(r->value, 0, 32); } cpsr = buf_get_u32(arm->cpsr->value, 0, 32); for (i = 0; i < num_mem_params; i++) { retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } retval = armv4_5_set_core_reg(reg, reg_params[i].value); if (retval != ERROR_OK) return retval; } arm->core_state = arm_algorithm_info->core_state; if (arm->core_state == ARM_STATE_ARM) exit_breakpoint_size = 4; else if (arm->core_state == ARM_STATE_THUMB) exit_breakpoint_size = 2; else { LOG_ERROR("BUG: can't execute algorithms when not in ARM or Thumb state"); return ERROR_COMMAND_SYNTAX_ERROR; } if (arm_algorithm_info->core_mode != ARM_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", arm_algorithm_info->core_mode); buf_set_u32(arm->cpsr->value, 0, 5, arm_algorithm_info->core_mode); arm->cpsr->dirty = 1; arm->cpsr->valid = 1; } /* terminate using a hardware or (ARMv5+) software breakpoint */ if (exit_point) { retval = breakpoint_add(target, exit_point, exit_breakpoint_size, BKPT_HARD); if (retval != ERROR_OK) { LOG_ERROR("can't add HW breakpoint to terminate algorithm"); return ERROR_TARGET_FAILURE; } } retval = target_resume(target, 0, entry_point, 1, 1); if (retval != ERROR_OK) return retval; retval = run_it(target, exit_point, timeout_ms, arch_info); if (exit_point) breakpoint_remove(target, exit_point); if (retval != ERROR_OK) return retval; for (i = 0; i < num_mem_params; i++) { if (mem_params[i].direction != PARAM_OUT) { int retvaltemp = target_read_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retvaltemp != ERROR_OK) retval = retvaltemp; } } for (i = 0; i < num_reg_params; i++) { if (reg_params[i].direction != PARAM_OUT) { struct reg *reg = register_get_by_name(arm->core_cache, reg_params[i].reg_name, 0); if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } if (reg->size != reg_params[i].size) { LOG_ERROR( "BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); retval = ERROR_COMMAND_SYNTAX_ERROR; continue; } buf_set_u32(reg_params[i].value, 0, 32, buf_get_u32(reg->value, 0, 32)); } } /* restore everything we saved before (17 or 18 registers) */ for (i = 0; i <= 16; i++) { uint32_t regvalue; regvalue = buf_get_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32); if (regvalue != context[i]) { LOG_DEBUG("restoring register %s with value 0x%8.8" PRIx32 "", ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).name, context[i]); buf_set_u32(ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).value, 0, 32, context[i]); ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).valid = 1; ARMV4_5_CORE_REG_MODE(arm->core_cache, arm_algorithm_info->core_mode, i).dirty = 1; } } arm_set_cpsr(arm, cpsr); arm->cpsr->dirty = 1; arm->core_state = core_state; return retval; }
/** * 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(®_params[0], "r0", 32, PARAM_IN); init_reg_param(®_params[1], "r1", 32, PARAM_IN); init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }
static int lpc2000_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct lpc2000_flash_bank *lpc2000_info = bank->driver_priv; struct target *target = bank->target; uint32_t dst_min_alignment; uint32_t bytes_remaining = count; uint32_t bytes_written = 0; int first_sector = 0; int last_sector = 0; uint32_t param_table[5]; uint32_t result_table[4]; int status_code; int i; struct working_area *download_area; int retval = ERROR_OK; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset + count > bank->size) return ERROR_FLASH_DST_OUT_OF_BANK; dst_min_alignment = lpc2000_info->cmd51_dst_boundary; if (offset % dst_min_alignment) { LOG_WARNING("offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32, offset, dst_min_alignment); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } for (i = 0; i < bank->num_sectors; i++) { if (offset >= bank->sectors[i].offset) first_sector = i; if (offset + DIV_ROUND_UP(count, dst_min_alignment) * dst_min_alignment > bank->sectors[i].offset) last_sector = i; } LOG_DEBUG("first_sector: %i, last_sector: %i", first_sector, last_sector); /* check if exception vectors should be flashed */ if ((offset == 0) && (count >= 0x20) && lpc2000_info->calc_checksum) { uint32_t checksum = 0; for (i = 0; i < 8; i++) { LOG_DEBUG("Vector 0x%2.2x: 0x%8.8" PRIx32, i * 4, buf_get_u32(buffer + (i * 4), 0, 32)); if (i != lpc2000_info->checksum_vector) checksum += buf_get_u32(buffer + (i * 4), 0, 32); } checksum = 0 - checksum; LOG_DEBUG("checksum: 0x%8.8" PRIx32, checksum); uint32_t original_value = buf_get_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32); if (original_value != checksum) { LOG_WARNING("Verification will fail since checksum in image (0x%8.8" PRIx32 ") " "to be written to flash is different from calculated vector " "checksum (0x%8.8" PRIx32 ").", original_value, checksum); LOG_WARNING("To remove this warning modify build tools on developer PC " "to inject correct LPC vector checksum."); } buf_set_u32(buffer + (lpc2000_info->checksum_vector * 4), 0, 32, checksum); } /* allocate a working area */ if (target_alloc_working_area(target, lpc2000_info->cmd51_max_buffer, &download_area) != ERROR_OK) { LOG_ERROR("no working area specified, can't write LPC2000 internal flash"); return ERROR_FLASH_OPERATION_FAILED; } while (bytes_remaining > 0) { uint32_t thisrun_bytes; if (bytes_remaining >= lpc2000_info->cmd51_max_buffer) thisrun_bytes = lpc2000_info->cmd51_max_buffer; else if (bytes_remaining >= 1024) thisrun_bytes = 1024; else if ((bytes_remaining >= 512) || (!lpc2000_info->cmd51_can_256b)) thisrun_bytes = 512; else thisrun_bytes = 256; /* Prepare sectors */ param_table[0] = first_sector; param_table[1] = last_sector; status_code = lpc2000_iap_call(bank, 50, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 prepare sectors returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining >= thisrun_bytes) { retval = target_write_buffer(bank->target, download_area->address, thisrun_bytes, buffer + bytes_written); if (retval != ERROR_OK) { retval = ERROR_FLASH_OPERATION_FAILED; break; } } else { uint8_t *last_buffer = malloc(thisrun_bytes); memcpy(last_buffer, buffer + bytes_written, bytes_remaining); memset(last_buffer + bytes_remaining, 0xff, thisrun_bytes - bytes_remaining); target_write_buffer(bank->target, download_area->address, thisrun_bytes, last_buffer); free(last_buffer); } LOG_DEBUG("writing 0x%" PRIx32 " bytes to address 0x%" PRIx32, thisrun_bytes, bank->base + offset + bytes_written); /* Write data */ param_table[0] = bank->base + offset + bytes_written; param_table[1] = download_area->address; param_table[2] = thisrun_bytes; param_table[3] = lpc2000_info->cclk; status_code = lpc2000_iap_call(bank, 51, param_table, result_table); switch (status_code) { case ERROR_FLASH_OPERATION_FAILED: retval = ERROR_FLASH_OPERATION_FAILED; break; case LPC2000_CMD_SUCCESS: break; case LPC2000_INVALID_SECTOR: retval = ERROR_FLASH_SECTOR_INVALID; break; default: LOG_WARNING("lpc2000 returned %i", status_code); retval = ERROR_FLASH_OPERATION_FAILED; break; } /* Exit if error occured */ if (retval != ERROR_OK) break; if (bytes_remaining > thisrun_bytes) bytes_remaining -= thisrun_bytes; else bytes_remaining = 0; bytes_written += thisrun_bytes; } target_free_working_area(target, download_area); return retval; }
static int stm32lx_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t halfpages_number; uint32_t bytes_remaining = 0; uint32_t address = bank->base + offset; uint32_t bytes_written = 0; int retval, retval2; if (bank->target->state != TARGET_HALTED) { LOG_ERROR("Target not halted"); return ERROR_TARGET_NOT_HALTED; } if (offset & 0x3) { LOG_ERROR("offset 0x%" PRIx32 " breaks required 4-byte alignment", offset); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; /* first we need to write any unaligned head bytes upto * the next 128 byte page */ if (offset % 128) bytes_remaining = MIN(count, 128 - (offset % 128)); while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } offset += bytes_written; count -= bytes_written; /* this should always pass this check here */ assert((offset % 128) == 0); /* calculate half pages */ halfpages_number = count / 128; if (halfpages_number) { retval = stm32lx_write_half_pages(bank, buffer + bytes_written, offset, 128 * halfpages_number); if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE) { /* attempt slow memory writes */ LOG_WARNING("couldn't use block writes, falling back to single memory accesses"); halfpages_number = 0; } else { if (retval != ERROR_OK) return ERROR_FAIL; } } /* write any remaining bytes */ uint32_t page_bytes_written = 128 * halfpages_number; bytes_written += page_bytes_written; address += page_bytes_written; bytes_remaining = count - page_bytes_written; retval = stm32lx_unlock_program_memory(bank); if (retval != ERROR_OK) return retval; while (bytes_remaining > 0) { uint8_t value[4] = {0xff, 0xff, 0xff, 0xff}; /* copy remaining bytes into the write buffer */ uint32_t bytes_to_write = MIN(4, bytes_remaining); memcpy(value, buffer + bytes_written, bytes_to_write); retval = target_write_buffer(target, address, 4, value); if (retval != ERROR_OK) goto reset_pg_and_lock; bytes_written += bytes_to_write; bytes_remaining -= bytes_to_write; address += 4; retval = stm32lx_wait_until_bsy_clear(bank); if (retval != ERROR_OK) goto reset_pg_and_lock; } reset_pg_and_lock: retval2 = stm32lx_lock_program_memory(bank); if (retval == ERROR_OK) retval = retval2; return retval; }
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(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); return retval; }
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(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
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(®_params[0], "r0", 32, PARAM_IN_OUT); /* Start address */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* Sector count */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* Erase command */ init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); retval = lpcspifi_set_hw_mode(bank); return retval; }
static int lpcspifi_write(struct flash_bank *bank, 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, 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(®_params[0], "r0", 32, PARAM_IN_OUT); /* buffer start, status (out) */ init_reg_param(®_params[1], "r1", 32, PARAM_OUT); /* buffer end */ init_reg_param(®_params[2], "r2", 32, PARAM_OUT); /* target address */ init_reg_param(®_params[3], "r3", 32, PARAM_OUT); /* count (halfword-16bit) */ init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); /* Switch to HW mode before return to prompt */ retval = lpcspifi_set_hw_mode(bank); return retval; }
static int str7x_write_block(struct flash_bank *bank, const 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 *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; /* 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), &write_algorithm) != ERROR_OK) { return ERROR_TARGET_RESOURCE_NOT_AVAILABLE; } uint8_t code[sizeof(str7x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str7x_flash_write_code), str7x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* 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(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_OUT); init_reg_param(®_params[4], "r4", 32, PARAM_IN); init_reg_param(®_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); retval = target_run_algorithm(target, 0, NULL, 6, reg_params, write_algorithm->address, write_algorithm->address + (sizeof(str7x_flash_write_code) - 4), 10000, &arm_algo); if (retval != 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, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); destroy_reg_param(®_params[5]); return retval; }
/** Checks whether a memory region is zeroed. */ int xmc4xxx_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_0_erase_check.s for src */ static const uint8_t erase_check_code[] = { /* loop: */ 0x03, 0x78, /* ldrb r3, [r0] */ 0x01, 0x30, /* adds r0, #1 */ 0x1A, 0x43, /* orrs 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(®_params[0], "r0", 32, PARAM_OUT); buf_set_u32(reg_params[0].value, 0, 32, address); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); buf_set_u32(reg_params[1].value, 0, 32, count); init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT); buf_set_u32(reg_params[2].value, 0, 32, 0x00); 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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); target_free_working_area(target, erase_check_algorithm); return retval; }
/** Starts a Thumb algorithm in the target. */ int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, target_addr_t entry_point, target_addr_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum arm_mode core_mode = armv7m->arm.core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache * Not needed if core register cache is always consistent with target process state */ for (unsigned i = 0; i < armv7m->arm.core_cache->num_regs; i++) { armv7m_algorithm_info->context[i] = buf_get_u32( armv7m->arm.core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { /* TODO: Write only out params */ retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value); if (retval != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(armv7m->arm.core_cache, reg_params[i].reg_name, 0); /* uint32_t regvalue; */ if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_COMMAND_SYNTAX_ERROR; } /* regvalue = buf_get_u32(reg_params[i].value, 0, 32); */ armv7m_set_core_reg(reg, reg_params[i].value); } if (armv7m_algorithm_info->core_mode != ARM_MODE_ANY && armv7m_algorithm_info->core_mode != core_mode) { /* we cannot set ARM_MODE_HANDLER, so use ARM_MODE_THREAD instead */ if (armv7m_algorithm_info->core_mode == ARM_MODE_HANDLER) { armv7m_algorithm_info->core_mode = ARM_MODE_THREAD; LOG_INFO("ARM_MODE_HANDLER not currently supported, using ARM_MODE_THREAD instead"); } LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->arm.core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } /* save previous core mode */ armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); return retval; }
/** Starts a Thumb algorithm in the target. */ int armv7m_start_algorithm(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_params, uint32_t entry_point, uint32_t exit_point, void *arch_info) { struct armv7m_common *armv7m = target_to_armv7m(target); struct armv7m_algorithm *armv7m_algorithm_info = arch_info; enum armv7m_mode core_mode = armv7m->core_mode; int retval = ERROR_OK; /* NOTE: armv7m_run_algorithm requires that each algorithm uses a software breakpoint * at the exit point */ if (armv7m_algorithm_info->common_magic != ARMV7M_COMMON_MAGIC) { LOG_ERROR("current target isn't an ARMV7M target"); return ERROR_TARGET_INVALID; } if (target->state != TARGET_HALTED) { LOG_WARNING("target not halted"); return ERROR_TARGET_NOT_HALTED; } /* refresh core register cache */ /* Not needed if core register cache is always consistent with target process state */ for (unsigned i = 0; i < ARMV7M_NUM_REGS; i++) { if (!armv7m->core_cache->reg_list[i].valid) armv7m->read_core_reg(target, i); armv7m_algorithm_info->context[i] = buf_get_u32(armv7m->core_cache->reg_list[i].value, 0, 32); } for (int i = 0; i < num_mem_params; i++) { // TODO: Write only out params if ((retval = target_write_buffer(target, mem_params[i].address, mem_params[i].size, mem_params[i].value)) != ERROR_OK) return retval; } for (int i = 0; i < num_reg_params; i++) { struct reg *reg = register_get_by_name(armv7m->core_cache, reg_params[i].reg_name, 0); // uint32_t regvalue; if (!reg) { LOG_ERROR("BUG: register '%s' not found", reg_params[i].reg_name); return ERROR_INVALID_ARGUMENTS; } if (reg->size != reg_params[i].size) { LOG_ERROR("BUG: register '%s' size doesn't match reg_params[i].size", reg_params[i].reg_name); return ERROR_INVALID_ARGUMENTS; } // regvalue = buf_get_u32(reg_params[i].value, 0, 32); armv7m_set_core_reg(reg, reg_params[i].value); } if (armv7m_algorithm_info->core_mode != ARMV7M_MODE_ANY) { LOG_DEBUG("setting core_mode: 0x%2.2x", armv7m_algorithm_info->core_mode); buf_set_u32(armv7m->core_cache->reg_list[ARMV7M_CONTROL].value, 0, 1, armv7m_algorithm_info->core_mode); armv7m->core_cache->reg_list[ARMV7M_CONTROL].dirty = 1; armv7m->core_cache->reg_list[ARMV7M_CONTROL].valid = 1; } armv7m_algorithm_info->core_mode = core_mode; retval = target_resume(target, 0, entry_point, 1, 1); return retval; }
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 */ 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; } }; armv7m_info.common_magic = ARMV7M_COMMON_MAGIC; armv7m_info.core_mode = ARMV7M_MODE_ANY; init_reg_param(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN_OUT); 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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
/* 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, const 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(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_params[3], "r3", 32, PARAM_IN); init_reg_param(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); destroy_reg_param(®_params[4]); return retval; }
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(®_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(®_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; }
static int str9x_write_block(struct flash_bank *bank, const uint8_t *buffer, uint32_t offset, uint32_t count) { struct target *target = bank->target; uint32_t buffer_size = 32768; struct working_area *write_algorithm; struct working_area *source; uint32_t address = bank->base + offset; struct reg_param reg_params[4]; struct arm_algorithm arm_algo; int retval = ERROR_OK; /* see contib/loaders/flash/str9x.s for src */ static const 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: */ 0xe1200070, /* bkpt #0 */ }; /* flash write code */ if (target_alloc_working_area(target, sizeof(str9x_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(str9x_flash_write_code)]; target_buffer_set_u32_array(target, code, ARRAY_SIZE(str9x_flash_write_code), str9x_flash_write_code); target_write_buffer(target, write_algorithm->address, sizeof(code), code); /* 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(®_params[0], "r0", 32, PARAM_OUT); init_reg_param(®_params[1], "r1", 32, PARAM_OUT); init_reg_param(®_params[2], "r2", 32, PARAM_OUT); init_reg_param(®_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); retval = target_run_algorithm(target, 0, NULL, 4, reg_params, write_algorithm->address, 0, 10000, &arm_algo); if (retval != 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, write_algorithm); destroy_reg_param(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_params[2]); destroy_reg_param(®_params[3]); return retval; }
static int lpc288x_write(struct flash_bank *bank, uint8_t *buffer, uint32_t offset, uint32_t count) { uint8_t page_buffer[FLASH_PAGE_SIZE]; uint32_t status, source_offset, dest_offset; struct target *target = bank->target; uint32_t bytes_remaining = count; uint32_t first_sector, last_sector, sector, page; int i; /* probed? halted? */ status = lpc288x_system_ready(bank); if (status != ERROR_OK) return status; /* Initialise search indices */ first_sector = last_sector = 0xffffffff; /* validate the write range... */ for (i = 0; i < bank->num_sectors; i++) { if ((offset >= bank->sectors[i].offset) && (offset < (bank->sectors[i].offset + bank->sectors[i].size)) && (first_sector == 0xffffffff)) { first_sector = i; /* all writes must start on a sector boundary... */ if (offset % bank->sectors[i].size) { LOG_INFO( "offset 0x%" PRIx32 " breaks required alignment 0x%" PRIx32 "", offset, bank->sectors[i].size); return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } } if (((offset + count) > bank->sectors[i].offset) && ((offset + count) <= (bank->sectors[i].offset + bank->sectors[i].size)) && (last_sector == 0xffffffff)) last_sector = i; } /* Range check... */ if (first_sector == 0xffffffff || last_sector == 0xffffffff) { LOG_INFO("Range check failed %" PRIx32 " %" PRIx32 "", offset, count); return ERROR_FLASH_DST_OUT_OF_BANK; } /* Configure the flash controller timing */ lpc288x_set_flash_clk(bank); /* initialise the offsets */ source_offset = 0; dest_offset = 0; for (sector = first_sector; sector <= last_sector; sector++) { for (page = 0; page < bank->sectors[sector].size / FLASH_PAGE_SIZE; page++) { if (bytes_remaining == 0) { count = 0; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); } else if (bytes_remaining < FLASH_PAGE_SIZE) { count = bytes_remaining; memset(page_buffer, 0xFF, FLASH_PAGE_SIZE); memcpy(page_buffer, &buffer[source_offset], count); } else { count = FLASH_PAGE_SIZE; memcpy(page_buffer, &buffer[source_offset], count); } /* Wait for flash to become ready */ if (lpc288x_wait_status_busy(bank, 1000) != ERROR_OK) return ERROR_FLASH_OPERATION_FAILED; /* fill flash data latches with 1's */ target_write_u32(target, F_CTRL, FC_CS | FC_SET_DATA | FC_WEN | FC_FUNC); target_write_u32(target, F_CTRL, FC_CS | FC_WEN | FC_FUNC); if (target_write_buffer(target, offset + dest_offset, FLASH_PAGE_SIZE, page_buffer) != ERROR_OK) { LOG_INFO("Write to flash buffer failed"); return ERROR_FLASH_OPERATION_FAILED; } dest_offset += FLASH_PAGE_SIZE; source_offset += count; bytes_remaining -= count; lpc288x_load_timer(LOAD_TIMER_WRITE, target); target_write_u32(target, F_CTRL, FC_PROG_REQ | FC_PROTECT | FC_FUNC | FC_CS); } } return ERROR_OK; }