Originally flash/nor infrastructure assumed protection blocks identical
to erase sectors. This assumption is not valid for many flash types.
Driver code fixed the problem either by increasing sector size to
size of protection block or by defining more protection block than
really existed in device. Both cases had drawbacks.
The change retains compatibility with the old driver.
Updated driver can set protection blocks table independent
of sector table.
Change-Id: I27f6d267528ad9ed9fe0a85f05436a8ec17603a4
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/3545
Tested-by: jenkins
Reviewed-by: Steven Stallion <stallion@squareup.com>
Reviewed-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
The @var{num} parameter is a value shown by @command{flash banks}.
@end deffn
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.
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.
*
* 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
*
* 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,
*/
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;
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;
uint32_t last_addr = addr + length; /* first address AFTER end */
int first = -1;
int last = -1;
int i;
int retval = get_flash_bank_by_addr(target, addr, true, &c);
if (retval != ERROR_OK)
int retval = get_flash_bank_by_addr(target, addr, true, &c);
if (retval != ERROR_OK)
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
}
- /** @todo: handle erasures that cross into adjacent banks */
-
addr -= c->base;
last_addr -= c->base;
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 */
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,
*/
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;
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,
}
retval = flash_iterate_address_range_inner(target,
pad_reason, addr, cur_length,
+ iterate_protect_blocks,
callback);
if (retval != ERROR_OK)
break;
callback);
if (retval != ERROR_OK)
break;
bool pad, uint32_t addr, uint32_t length)
{
return flash_iterate_address_range(target, pad ? "erase" : NULL,
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)
}
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",
* 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)
}
static int compare_section(const void *a, const void *b)
{
return flash_write_unlock(target, image, written, erase, false);
}
{
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.
/**
* 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
* This information must be considered stale immediately.
* A million things could make it stale: power cycle,
* reset of target, code running on target, etc.
* 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
* some non-zero value during "probe()" or "auto_probe()".
*/
int num_sectors;
* 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;
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 */
};
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);
*/
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 */
#endif /* OPENOCD_FLASH_NOR_CORE_H */
struct flash_bank *p;
int j = 0;
int retval;
struct flash_bank *p;
int j = 0;
int retval;
+ bool show_sectors = false;
+ bool prot_block_available;
+ if (CMD_ARGC < 1 || CMD_ARGC > 2)
return ERROR_COMMAND_SYNTAX_ERROR;
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];
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);
/* attempt auto probe */
retval = p->driver->auto_probe(p);
p->size,
p->bus_width,
p->chip_width);
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";
protect_state = "not protected";
- else if (p->sectors[j].is_protected == 1)
+ else if (block_array[j].is_protected == 1)
protect_state = "protected";
protect_state = "protected";
+ 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,
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,
struct flash_bank *p;
int retval;
struct flash_bank *p;
int retval;
retval = CALL_COMMAND_HANDLER(flash_command_get_bank, 0, &p);
if (retval != ERROR_OK)
return retval;
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)
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[1], first);
if (strcmp(CMD_ARGV[2], "last") == 0)
- last = p->num_sectors - 1;
else
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], last);
bool set;
COMMAND_PARSE_ON_OFF(CMD_ARGV[3], set);
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;
if (retval != ERROR_OK)
return retval;
.name = "info",
.handler = handle_flash_info_command,
.mode = COMMAND_EXEC,
.name = "info",
.handler = handle_flash_info_command,
.mode = COMMAND_EXEC,
+ .usage = "bank_id ['sectors']",
.help = "Print information about a flash bank.",
},
{
.help = "Print information about a flash bank.",
},
{
c->default_padded_value = 0xff;
c->num_sectors = 0;
c->sectors = NULL;
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;
c->next = NULL;
int retval;