NOR FLASH: only erase/unlock whole sectors
Much to my surprise, I observed a "flash erase_address ..." command erasing data which I said should not be erased. The issue turns out to be generic NOR flash code which was silently, and rather dangerously, morphing partial-sector references into unrequested whole-sector ones. This patch removes that low-level morphing. If desired, it can and should be done in higher level code. (We might need to fix some stuff in the GDB server code.) Signed-off-by: David Brownell <dbrownell@users.sourceforge.net>__archive__
parent
013b05f7f8
commit
3f18900b19
2
NEWS
2
NEWS
|
@ -39,6 +39,8 @@ Flash Layer:
|
||||||
- <bank_name>: reference the bank with its defined name
|
- <bank_name>: reference the bank with its defined name
|
||||||
- <driver_name>[.N]: reference the driver's Nth bank
|
- <driver_name>[.N]: reference the driver's Nth bank
|
||||||
New 'nand verify' command to check bank against an image file.
|
New 'nand verify' command to check bank against an image file.
|
||||||
|
The "flash erase_address" command now rejects partial sectors;
|
||||||
|
previously it would silently erase extra data.
|
||||||
|
|
||||||
Board, Target, and Interface Configuration Scripts:
|
Board, Target, and Interface Configuration Scripts:
|
||||||
ARM9
|
ARM9
|
||||||
|
|
|
@ -279,11 +279,13 @@ int default_flash_blank_check(struct flash_bank *bank)
|
||||||
|
|
||||||
return ERROR_OK;
|
return ERROR_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* erase given flash region, selects proper bank according to target and address */
|
/* erase given flash region, selects proper bank according to target and address */
|
||||||
static int flash_iterate_address_range(struct target *target, uint32_t addr, uint32_t length,
|
static int flash_iterate_address_range(struct target *target, uint32_t addr, uint32_t length,
|
||||||
int (*callback)(struct flash_bank *bank, int first, int last))
|
int (*callback)(struct flash_bank *bank, int first, int last))
|
||||||
{
|
{
|
||||||
struct flash_bank *c;
|
struct flash_bank *c;
|
||||||
|
uint32_t last_addr = addr + length; /* first address AFTER end */
|
||||||
int first = -1;
|
int first = -1;
|
||||||
int last = -1;
|
int last = -1;
|
||||||
int i;
|
int i;
|
||||||
|
@ -306,26 +308,52 @@ static int flash_iterate_address_range(struct target *target, uint32_t addr, uin
|
||||||
return callback(c, 0, c->num_sectors - 1);
|
return callback(c, 0, c->num_sectors - 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* check whether it fits */
|
/* check whether it all fits in this bank */
|
||||||
if (addr + length - 1 > c->base + c->size - 1)
|
if (addr + length - 1 > c->base + c->size - 1)
|
||||||
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
|
||||||
|
/** @todo: handle erasures that cross into adjacent banks */
|
||||||
|
|
||||||
addr -= c->base;
|
addr -= c->base;
|
||||||
|
|
||||||
for (i = 0; i < c->num_sectors; i++)
|
for (i = 0; i < c->num_sectors; i++)
|
||||||
{
|
{
|
||||||
/* check whether sector overlaps with the given range and is not yet erased */
|
struct flash_sector *f = c->sectors + i;
|
||||||
if (addr < c->sectors[i].offset + c->sectors[i].size && addr + length > c->sectors[i].offset && c->sectors[i].is_erased != 1) {
|
|
||||||
/* if first is not set yet then this is the first sector */
|
/* start only on a sector boundary */
|
||||||
if (first == -1)
|
if (first < 0) {
|
||||||
|
/* is this the first sector? */
|
||||||
|
if (addr == f->offset)
|
||||||
first = i;
|
first = i;
|
||||||
last = i; /* and it is the last one so far in any case */
|
else if (addr < f->offset)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* is this (also?) the last sector? */
|
||||||
|
if (last_addr == f->offset + f->size) {
|
||||||
|
last = i;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* MUST finish on a sector boundary */
|
||||||
|
if (last_addr <= f->offset)
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (first == -1 || last == -1)
|
/* invalid start or end address? */
|
||||||
return ERROR_OK;
|
if (first == -1 || last == -1) {
|
||||||
|
LOG_ERROR("address range 0x%8.8x .. 0x%8.8x "
|
||||||
|
"is not sector-aligned",
|
||||||
|
(unsigned) c->base + addr,
|
||||||
|
(unsigned) last_addr - 1);
|
||||||
|
return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The NOR driver may trim this range down, based on
|
||||||
|
* whether or not a given sector is already erased.
|
||||||
|
*
|
||||||
|
* REVISIT should *we* trim it... ?
|
||||||
|
*/
|
||||||
return callback(c, first, last);
|
return callback(c, first, last);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue