NOR FLASH: only erase/unlock whole sectors
authorDavid Brownell <dbrownell@users.sourceforge.net>
Fri, 18 Dec 2009 18:16:52 +0000 (10:16 -0800)
committerDavid Brownell <dbrownell@users.sourceforge.net>
Fri, 18 Dec 2009 18:16:52 +0000 (10:16 -0800)
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>
NEWS
src/flash/nor/core.c

diff --git a/NEWS b/NEWS
index 498797b1f4855cd5732f8789330890c487179155..2d01f004904ae4be78ed1395133ed1333356e79f 100644 (file)
--- a/NEWS
+++ b/NEWS
@@ -39,6 +39,8 @@ Flash Layer:
                - <bank_name>: reference the bank with its defined name
                - <driver_name>[.N]: reference the driver's Nth bank
        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:
        ARM9
index c2ea134a393609371be6bfb915476481db8cd24f..1873deede567e56ef93caf230040cabded7fb40a 100644 (file)
@@ -279,11 +279,13 @@ int default_flash_blank_check(struct flash_bank *bank)
 
        return ERROR_OK;
 }
+
 /* 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,
                int (*callback)(struct flash_bank *bank, int first, int last))
 {
        struct flash_bank *c;
+       uint32_t last_addr = addr + length;     /* first address AFTER end */
        int first = -1;
        int last = -1;
        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);
        }
 
-       /* check whether it fits */
+       /* check whether it all fits in this bank */
        if (addr + length - 1 > c->base + c->size - 1)
                return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
 
+       /** @todo: handle erasures that cross into adjacent banks */
+
        addr -= c->base;
 
        for (i = 0; i < c->num_sectors; i++)
        {
-               /* check whether sector overlaps with the given range and is not yet erased */
-               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 */
-                       if (first == -1)
+               struct flash_sector *f = c->sectors + i;
+
+               /* start only on a sector boundary */
+               if (first < 0) {
+                       /* is this the first sector? */
+                       if (addr == f->offset)
                                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)
-               return ERROR_OK;
+       /* invalid start or end address? */
+       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);
 }
 

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)