diff options
-rw-r--r-- | doc/openocd.texi | 6 | ||||
-rw-r--r-- | src/flash/nor/core.c | 49 | ||||
-rw-r--r-- | src/flash/nor/core.h | 25 | ||||
-rw-r--r-- | src/flash/nor/tcl.c | 53 |
4 files changed, 110 insertions, 23 deletions
diff --git a/doc/openocd.texi b/doc/openocd.texi index cef1cae..74e5e88 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -4746,8 +4746,10 @@ and display that status. The @var{num} parameter is a value shown by @command{flash banks}. @end deffn -@deffn Command {flash info} num -Print info about flash bank @var{num} +@deffn Command {flash info} num [sectors] +Print info about flash bank @var{num}, a list of protection blocks +and their status. Use @option{sectors} to show a list of sectors instead. + The @var{num} parameter is a value shown by @command{flash banks}. This command will first query the hardware, it does not print cached and possibly stale information. diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index cfc4f19..7a62ba1 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -343,8 +343,9 @@ int default_flash_blank_check(struct flash_bank *bank) * 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 @@ -355,13 +356,16 @@ int default_flash_blank_check(struct flash_bank *bank) */ 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) @@ -388,13 +392,21 @@ static int flash_iterate_address_range_inner(struct target *target, return ERROR_FLASH_DST_BREAKS_ALIGNMENT; } - /** @todo: handle erasures that cross into adjacent banks */ - addr -= c->base; last_addr -= c->base; - for (i = 0; i < c->num_sectors; i++) { - struct flash_sector *f = c->sectors + i; + if (iterate_protect_blocks && c->prot_blocks && c->num_prot_blocks) { + block_array = c->prot_blocks; + num_blocks = c->num_prot_blocks; + } else { + block_array = c->sectors; + num_blocks = c->num_sectors; + iterate_protect_blocks = false; + } + + + 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 */ @@ -472,6 +484,7 @@ static int flash_iterate_address_range_inner(struct target *target, */ 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; @@ -491,6 +504,7 @@ static int flash_iterate_address_range(struct target *target, } retval = flash_iterate_address_range_inner(target, pad_reason, addr, cur_length, + iterate_protect_blocks, callback); if (retval != ERROR_OK) break; @@ -506,7 +520,7 @@ int flash_erase_address_range(struct target *target, 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) @@ -521,7 +535,7 @@ int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t le * 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) @@ -762,3 +776,22 @@ int flash_write(struct target *target, struct image *image, { 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; +} diff --git a/src/flash/nor/core.h b/src/flash/nor/core.h index 929ebdb..60d4483 100644 --- a/src/flash/nor/core.h +++ b/src/flash/nor/core.h @@ -46,6 +46,8 @@ struct flash_sector { /** * Indication of erasure status: 0 = not erased, 1 = erased, * other = unknown. Set by @c flash_driver_s::erase_check. + * + * Flag is not used in protection block */ int is_erased; /** @@ -56,6 +58,9 @@ struct flash_sector { * This information must be considered stale immediately. * A million things could make it stale: power cycle, * reset of target, code running on target, etc. + * + * If a flash_bank uses an extra array of protection blocks, + * protection flag is not valid in sector array */ int is_protected; }; @@ -95,9 +100,19 @@ struct flash_bank { * some non-zero value during "probe()" or "auto_probe()". */ int num_sectors; - /** Array of sectors, allocated and initilized by the flash driver */ + /** Array of sectors, allocated and initialized by the flash driver */ struct flash_sector *sectors; + /** + * The number of protection blocks in this bank. This value + * is set intially to 0 and sectors are used as protection blocks. + * Driver probe can set protection blocks array to work with + * protection granularity different than sector size. + */ + int num_prot_blocks; + /** Array of protection blocks, allocated and initilized by the flash driver */ + struct flash_sector *prot_blocks; + struct flash_bank *next; /**< The next flash bank on this chip */ }; @@ -205,5 +220,13 @@ struct flash_bank *get_flash_bank_by_num_noprobe(int num); */ int get_flash_bank_by_addr(struct target *target, uint32_t addr, bool check, struct flash_bank **result_bank); +/** + * Allocate and fill an array of sectors or protection blocks. + * @param offset Offset of first block. + * @param size Size of each block. + * @param num_blocks Number of blocks in array. + * @returns A struct flash_sector pointer or NULL when allocation failed. + */ +struct flash_sector *alloc_block_array(uint32_t offset, uint32_t size, int num_blocks); #endif /* OPENOCD_FLASH_NOR_CORE_H */ diff --git a/src/flash/nor/tcl.c b/src/flash/nor/tcl.c index 9628684..6dd2140 100644 --- a/src/flash/nor/tcl.c +++ b/src/flash/nor/tcl.c @@ -70,16 +70,27 @@ COMMAND_HANDLER(handle_flash_info_command) struct flash_bank *p; int j = 0; int retval; + bool show_sectors = false; + bool prot_block_available; - if (CMD_ARGC != 1) + if (CMD_ARGC < 1 || CMD_ARGC > 2) return ERROR_COMMAND_SYNTAX_ERROR; + if (CMD_ARGC == 2) { + if (strcmp("sectors", CMD_ARGV[1]) == 0) + show_sectors = true; + else + return ERROR_COMMAND_SYNTAX_ERROR; + } + retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; if (p != NULL) { char buf[1024]; + int num_blocks; + struct flash_sector *block_array; /* attempt auto probe */ retval = p->driver->auto_probe(p); @@ -100,22 +111,32 @@ COMMAND_HANDLER(handle_flash_info_command) p->size, p->bus_width, p->chip_width); - for (j = 0; j < p->num_sectors; j++) { - char *protect_state; - if (p->sectors[j].is_protected == 0) + prot_block_available = p->num_prot_blocks && p->prot_blocks; + if (!show_sectors && prot_block_available) { + block_array = p->prot_blocks; + num_blocks = p->num_prot_blocks; + } else { + block_array = p->sectors; + num_blocks = p->num_sectors; + } + + for (j = 0; j < num_blocks; j++) { + char *protect_state = ""; + + if (block_array[j].is_protected == 0) protect_state = "not protected"; - else if (p->sectors[j].is_protected == 1) + else if (block_array[j].is_protected == 1) protect_state = "protected"; - else + else if (!show_sectors || !prot_block_available) protect_state = "protection state unknown"; command_print(CMD_CTX, "\t#%3i: 0x%8.8" PRIx32 " (0x%" PRIx32 " %" PRIi32 "kB) %s", j, - p->sectors[j].offset, - p->sectors[j].size, - p->sectors[j].size >> 10, + block_array[j].offset, + block_array[j].size, + block_array[j].size >> 10, protect_state); } @@ -333,21 +354,27 @@ COMMAND_HANDLER(handle_flash_protect_command) struct flash_bank *p; int retval; + int num_blocks; retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p); if (retval != ERROR_OK) return retval; + if (p->num_prot_blocks) + num_blocks = p->num_prot_blocks; + else + num_blocks = p->num_sectors; + COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first); if (strcmp(CMD_ARGV[2], "last") == 0) - last = p->num_sectors - 1; + last = num_blocks - 1; else COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last); bool set; COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set); - retval = flash_check_sector_parameters(CMD_CTX, first, last, p->num_sectors); + retval = flash_check_sector_parameters(CMD_CTX, first, last, num_blocks); if (retval != ERROR_OK) return retval; @@ -813,7 +840,7 @@ static const struct command_registration flash_exec_command_handlers[] = { .name = "info", .handler = handle_flash_info_command, .mode = COMMAND_EXEC, - .usage = "bank_id", + .usage = "bank_id ['sectors']", .help = "Print information about a flash bank.", }, { @@ -988,6 +1015,8 @@ COMMAND_HANDLER(handle_flash_bank_command) c->default_padded_value = 0xff; c->num_sectors = 0; c->sectors = NULL; + c->num_prot_blocks = 0; + c->prot_blocks = NULL; c->next = NULL; int retval; |