int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
{
int retval;
+ int num_blocks;
+
+ if (bank->num_prot_blocks)
+ num_blocks = bank->num_prot_blocks;
+ else
+ num_blocks = bank->num_sectors;
+
/* callers may not supply illegal parameters ... */
- if (first < 0 || first > last || last >= bank->num_sectors) {
- LOG_ERROR("illegal sector range");
+ if (first < 0 || first > last || last >= num_blocks) {
+ LOG_ERROR("illegal protection block range");
return ERROR_FAIL;
}
* the target could have reset, power cycled, been hot plugged,
* the application could have run, etc.
*
- * Drivers only receive valid sector range.
+ * Drivers only receive valid protection block range.
*/
retval = bank->driver->protect(bank, set, first, last);
if (retval != ERROR_OK)
- LOG_ERROR("failed setting protection for areas %d to %d", first, last);
+ LOG_ERROR("failed setting protection for blocks %d to %d", first, last);
return retval;
}
return i;
}
+void default_flash_free_driver_priv(struct flash_bank *bank)
+{
+ free(bank->driver_priv);
+ bank->driver_priv = NULL;
+}
+
+void flash_free_all_banks(void)
+{
+ struct flash_bank *bank = flash_banks;
+ while (bank) {
+ struct flash_bank *next = bank->next;
+ if (bank->driver->free_driver_priv)
+ bank->driver->free_driver_priv(bank);
+ else
+ LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name);
+
+ free(bank->name);
+ free(bank->sectors);
+ free(bank->prot_blocks);
+ free(bank);
+ bank = next;
+ }
+ flash_banks = NULL;
+}
+
struct flash_bank *get_flash_bank_by_name_noprobe(const char *name)
{
unsigned requested = get_flash_name_index(name);
goto done;
for (nBytes = 0; nBytes < chunk; nBytes++) {
- if (buffer[nBytes] != 0xFF) {
+ if (buffer[nBytes] != bank->erased_value) {
bank->sectors[i].is_erased = 0;
break;
}
struct target *target = bank->target;
int i;
int retval;
- int fast_check = 0;
- uint32_t blank;
if (bank->target->state != TARGET_HALTED) {
LOG_ERROR("Target not halted");
return ERROR_TARGET_NOT_HALTED;
}
+ struct target_memory_check_block *block_array;
+ block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
+ if (block_array == NULL)
+ return default_flash_mem_blank_check(bank);
+
for (i = 0; i < bank->num_sectors; i++) {
- uint32_t address = bank->base + bank->sectors[i].offset;
- uint32_t size = bank->sectors[i].size;
+ block_array[i].address = bank->base + bank->sectors[i].offset;
+ block_array[i].size = bank->sectors[i].size;
+ block_array[i].result = UINT32_MAX; /* erase state unknown */
+ }
- retval = target_blank_check_memory(target, address, size, &blank);
- if (retval != ERROR_OK) {
- fast_check = 0;
+ bool fast_check = true;
+ for (i = 0; i < bank->num_sectors; ) {
+ retval = target_blank_check_memory(target,
+ block_array + i, bank->num_sectors - i,
+ bank->erased_value);
+ if (retval < 1) {
+ /* Run slow fallback if the first run gives no result
+ * otherwise use possibly incomplete results */
+ if (i == 0)
+ fast_check = false;
break;
}
- if (blank == 0xFF)
- bank->sectors[i].is_erased = 1;
- else
- bank->sectors[i].is_erased = 0;
- fast_check = 1;
+ i += retval; /* add number of blocks done this round */
}
- if (!fast_check) {
+ if (fast_check) {
+ for (i = 0; i < bank->num_sectors; i++)
+ bank->sectors[i].is_erased = block_array[i].result;
+ retval = ERROR_OK;
+ } else {
LOG_USER("Running slow fallback erase check - add working memory");
- return default_flash_mem_blank_check(bank);
+ retval = default_flash_mem_blank_check(bank);
}
+ free(block_array);
- return ERROR_OK;
+ return retval;
}
/* Manipulate given flash region, selecting the bank according to target
* and address. Maps an address range to a set of sectors, and issues
* the callback() on that set ... e.g. to erase or unprotect its members.
*
- * (Note a current bad assumption: that protection operates on the same
- * size sectors as erase operations use.)
+ * Parameter iterate_protect_blocks switches iteration of protect block
+ * instead of erase sectors. If there is no protect blocks array, sectors
+ * are used in iteration, so compatibility for old flash drivers is retained.
*
* The "pad_reason" parameter is a kind of boolean: when it's NULL, the
* range must fit those sectors exactly. This is clearly safe; it can't
*/
static int flash_iterate_address_range_inner(struct target *target,
char *pad_reason, uint32_t addr, uint32_t length,
+ bool iterate_protect_blocks,
int (*callback)(struct flash_bank *bank, int first, int last))
{
struct flash_bank *c;
+ struct flash_sector *block_array;
uint32_t last_addr = addr + length; /* first address AFTER end */
int first = -1;
int last = -1;
int i;
+ int num_blocks;
int retval = get_flash_bank_by_addr(target, addr, true, &c);
if (retval != ERROR_OK)
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
- /** @todo: handle erasures that cross into adjacent banks */
+ if (c->prot_blocks == NULL || c->num_prot_blocks == 0) {
+ /* flash driver does not define protect blocks, use sectors instead */
+ iterate_protect_blocks = false;
+ }
+
+ if (iterate_protect_blocks) {
+ block_array = c->prot_blocks;
+ num_blocks = c->num_prot_blocks;
+ } else {
+ block_array = c->sectors;
+ num_blocks = c->num_sectors;
+ }
addr -= c->base;
last_addr -= c->base;
- for (i = 0; i < c->num_sectors; i++) {
- struct flash_sector *f = c->sectors + i;
+ for (i = 0; i < num_blocks; i++) {
+ struct flash_sector *f = &block_array[i];
uint32_t end = f->offset + f->size;
/* start only on a sector boundary */
*/
static int flash_iterate_address_range(struct target *target,
char *pad_reason, uint32_t addr, uint32_t length,
+ bool iterate_protect_blocks,
int (*callback)(struct flash_bank *bank, int first, int last))
{
struct flash_bank *c;
}
retval = flash_iterate_address_range_inner(target,
pad_reason, addr, cur_length,
+ iterate_protect_blocks,
callback);
if (retval != ERROR_OK)
break;
bool pad, uint32_t addr, uint32_t length)
{
return flash_iterate_address_range(target, pad ? "erase" : NULL,
- addr, length, &flash_driver_erase);
+ addr, length, false, &flash_driver_erase);
}
static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
* and doesn't restore it.
*/
return flash_iterate_address_range(target, "unprotect",
- addr, length, &flash_driver_unprotect);
+ addr, length, true, &flash_driver_unprotect);
}
static int compare_section(const void *a, const void *b)
uint32_t buffer_size;
uint8_t *buffer;
int section_last;
- uint32_t run_address = sections[section]->base_address + section_offset;
+ target_addr_t run_address = sections[section]->base_address + section_offset;
uint32_t run_size = sections[section]->size - section_offset;
int pad_bytes = 0;
if (retval != ERROR_OK)
goto done;
if (c == NULL) {
- LOG_WARNING("no flash bank found for address %" PRIx32, run_address);
+ LOG_WARNING("no flash bank found for address " TARGET_ADDR_FMT, run_address);
section++; /* and skip it */
section_offset = 0;
continue;
/* if we have multiple sections within our image,
* flash programming could fail due to alignment issues
* attempt to rebuild a consecutive buffer for the flash loader */
- pad_bytes = (sections[section_last + 1]->base_address) - (run_address + run_size);
+ target_addr_t run_next_addr = run_address + run_size;
+ if (sections[section_last + 1]->base_address < run_next_addr) {
+ LOG_ERROR("Section at " TARGET_ADDR_FMT
+ " overlaps section ending at " TARGET_ADDR_FMT,
+ sections[section_last + 1]->base_address,
+ run_next_addr);
+ LOG_ERROR("Flash write aborted.");
+ retval = ERROR_FAIL;
+ goto done;
+ }
+
+ pad_bytes = sections[section_last + 1]->base_address - run_next_addr;
padding[section_last] = pad_bytes;
run_size += sections[++section_last]->size;
run_size += pad_bytes;
{
return flash_write_unlock(target, image, written, erase, false);
}
+
+struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, int num_blocks)
+{
+ int i;
+
+ struct flash_sector *array = calloc(num_blocks, sizeof(struct flash_sector));
+ if (array == NULL)
+ return NULL;
+
+ for (i = 0; i < num_blocks; i++) {
+ array[i].offset = offset;
+ array[i].size = size;
+ array[i].is_erased = -1;
+ array[i].is_protected = -1;
+ offset += size;
+ }
+
+ return array;
+}