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.
* 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 */
-
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 */
*/
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)
{
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;
+}
/**
* 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;
/**
* 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;
};
* 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 */
};
*/
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 */
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);
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);
}
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;
.name = "info",
.handler = handle_flash_info_command,
.mode = COMMAND_EXEC,
- .usage = "bank_id",
+ .usage = "bank_id ['sectors']",
.help = "Print information about a flash bank.",
},
{
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;