NOR: Allocate the right amount of memory
[openocd.git] / src / flash / nor / core.c
index 2dbf1142fed2ef6b3b793b4d1fde777624e53b16..fe5372b6cd7cb901a752d0336289764f739708cc 100644 (file)
@@ -1,4 +1,7 @@
 /***************************************************************************
+ *   Copyright (C) 2005 by Dominic Rath <Dominic.Rath@gmx.de>              *
+ *   Copyright (C) 2007,2008 Ã˜yvind Harboe <oyvind.harboe@zylin.com>       *
+ *   Copyright (C) 2008 by Spencer Oliver <spen@spen-soft.co.uk>           *
  *   Copyright (C) 2009 Zachary T Welch <zw@superlucidity.net>             *
  *                                                                         *
  *   This program is free software; you can redistribute it and/or modify  *
 #ifdef HAVE_CONFIG_H
 #include <config.h>
 #endif
-#include <flash/flash.h>
+#include <flash/common.h>
+#include <flash/nor/core.h>
 #include <flash/nor/imp.h>
 #include <target/image.h>
 
-// in flash.c, to be moved here
-extern struct flash_driver *flash_drivers[];
-extern struct flash_bank *flash_banks;
 
-struct flash_driver *flash_driver_find_by_name(const char *name)
-{
-       for (unsigned i = 0; flash_drivers[i]; i++)
-       {
-               if (strcmp(name, flash_drivers[i]->name) == 0)
-                       return flash_drivers[i];
-       }
-       return NULL;
-}
+struct flash_bank *flash_banks;
 
 int flash_driver_erase(struct flash_bank *bank, int first, int last)
 {
@@ -79,7 +72,6 @@ int flash_driver_write(struct flash_bank *bank,
        return retval;
 }
 
-
 void flash_bank_add(struct flash_bank *bank)
 {
        /* put flash bank in linked list */
@@ -107,11 +99,194 @@ struct flash_bank *flash_bank_list(void)
        return flash_banks;
 }
 
+struct flash_bank *get_flash_bank_by_num_noprobe(int num)
+{
+       struct flash_bank *p;
+       int i = 0;
+
+       for (p = flash_banks; p; p = p->next)
+       {
+               if (i++ == num)
+               {
+                       return p;
+               }
+       }
+       LOG_ERROR("flash bank %d does not exist", num);
+       return NULL;
+}
+
+int flash_get_bank_count(void)
+{
+       struct flash_bank *p;
+       int i = 0;
+       for (p = flash_banks; p; p = p->next)
+       {
+               i++;
+       }
+       return i;
+}
+
+struct flash_bank *get_flash_bank_by_name(const char *name)
+{
+       unsigned requested = get_flash_name_index(name);
+       unsigned found = 0;
+
+       struct flash_bank *bank;
+       for (bank = flash_banks; NULL != bank; bank = bank->next)
+       {
+               if (strcmp(bank->name, name) == 0)
+                       return bank;
+               if (!flash_driver_name_matches(bank->driver->name, name))
+                       continue;
+               if (++found < requested)
+                       continue;
+               return bank;
+       }
+       return NULL;
+}
+
+struct flash_bank *get_flash_bank_by_num(int num)
+{
+       struct flash_bank *p = get_flash_bank_by_num_noprobe(num);
+       int retval;
+
+       if (p == NULL)
+               return NULL;
+
+       retval = p->driver->auto_probe(p);
+
+       if (retval != ERROR_OK)
+       {
+               LOG_ERROR("auto_probe failed %d\n", retval);
+               return NULL;
+       }
+       return p;
+}
+
+/* lookup flash bank by address */
+struct flash_bank *get_flash_bank_by_addr(struct target *target, uint32_t addr)
+{
+       struct flash_bank *c;
+
+       /* cycle through bank list */
+       for (c = flash_banks; c; c = c->next)
+       {
+               int retval;
+               retval = c->driver->auto_probe(c);
+
+               if (retval != ERROR_OK)
+               {
+                       LOG_ERROR("auto_probe failed %d\n", retval);
+                       return NULL;
+               }
+               /* check whether address belongs to this flash bank */
+               if ((addr >= c->base) && (addr <= c->base + (c->size - 1)) && target == c->target)
+                       return c;
+       }
+       LOG_ERROR("No flash at address 0x%08" PRIx32 "\n", addr);
+       return NULL;
+}
+
+int default_flash_mem_blank_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       const int buffer_size = 1024;
+       int i;
+       uint32_t nBytes;
+       int retval = ERROR_OK;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       uint8_t *buffer = malloc(buffer_size);
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint32_t j;
+               bank->sectors[i].is_erased = 1;
+
+               for (j = 0; j < bank->sectors[i].size; j += buffer_size)
+               {
+                       uint32_t chunk;
+                       chunk = buffer_size;
+                       if (chunk > (j - bank->sectors[i].size))
+                       {
+                               chunk = (j - bank->sectors[i].size);
+                       }
+
+                       retval = target_read_memory(target, bank->base + bank->sectors[i].offset + j, 4, chunk/4, buffer);
+                       if (retval != ERROR_OK)
+                       {
+                               goto done;
+                       }
+
+                       for (nBytes = 0; nBytes < chunk; nBytes++)
+                       {
+                               if (buffer[nBytes] != 0xFF)
+                               {
+                                       bank->sectors[i].is_erased = 0;
+                                       break;
+                               }
+                       }
+               }
+       }
+
+       done:
+       free(buffer);
+
+       return retval;
+}
+
+int default_flash_blank_check(struct flash_bank *bank)
+{
+       struct target *target = bank->target;
+       int i;
+       int retval;
+       int fast_check = 0;
+       uint32_t blank;
+
+       if (bank->target->state != TARGET_HALTED)
+       {
+               LOG_ERROR("Target not halted");
+               return ERROR_TARGET_NOT_HALTED;
+       }
+
+       for (i = 0; i < bank->num_sectors; i++)
+       {
+               uint32_t address = bank->base + bank->sectors[i].offset;
+               uint32_t size = bank->sectors[i].size;
+
+               if ((retval = target_blank_check_memory(target, address, size, &blank)) != ERROR_OK)
+               {
+                       fast_check = 0;
+                       break;
+               }
+               if (blank == 0xFF)
+                       bank->sectors[i].is_erased = 1;
+               else
+                       bank->sectors[i].is_erased = 0;
+               fast_check = 1;
+       }
+
+       if (!fast_check)
+       {
+               LOG_USER("Running slow fallback erase check - add working memory");
+               return default_flash_mem_blank_check(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,
+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;
@@ -134,30 +309,57 @@ 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);
 }
 
-int flash_erase_address_range(struct target *target, uint32_t addr, uint32_t length)
+int flash_erase_address_range(struct target *target,
+               uint32_t addr, uint32_t length)
 {
        return flash_iterate_address_range(target,
                        addr, length, &flash_driver_erase);
@@ -199,7 +401,7 @@ int flash_write_unlock(struct target *target, struct image *image,
        }
 
        /* allocate padding array */
-       padding = malloc(image->num_sections * sizeof(padding));
+       padding = calloc(image->num_sections, sizeof(*padding));
 
        /* loop until we reach end of the image */
        while (section < image->num_sections)

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)