flash/nor: add support of STM32WB on top STM32L4 flash driver
[fw/openocd] / src / flash / nor / core.c
index f05c68b823410e53251a4e758227544331f34c15..043ff13c8dfa69a087c213a08f265d79927a8b31 100644 (file)
@@ -68,6 +68,11 @@ int flash_driver_protect(struct flash_bank *bank, int set, int first, int last)
        /* force "set" to 0/1 */
        set = !!set;
 
+       if (bank->driver->protect == NULL) {
+               LOG_ERROR("Flash protection is not supported.");
+               return ERROR_FLASH_OPER_UNSUPPORTED;
+       }
+
        /* DANGER!
         *
         * We must not use any cached information about protection state!!!!
@@ -94,7 +99,8 @@ int flash_driver_write(struct flash_bank *bank,
        retval = bank->driver->write(bank, buffer, offset, count);
        if (retval != ERROR_OK) {
                LOG_ERROR(
-                       "error writing to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
+                       "error writing to flash at address " TARGET_ADDR_FMT
+                       " at offset 0x%8.8" PRIx32,
                        bank->base,
                        offset);
        }
@@ -112,7 +118,8 @@ int flash_driver_read(struct flash_bank *bank,
        retval = bank->driver->read(bank, buffer, offset, count);
        if (retval != ERROR_OK) {
                LOG_ERROR(
-                       "error reading to flash at address 0x%08" PRIx32 " at offset 0x%8.8" PRIx32,
+                       "error reading to flash at address " TARGET_ADDR_FMT
+                       " at offset 0x%8.8" PRIx32,
                        bank->base,
                        offset);
        }
@@ -188,9 +195,17 @@ void flash_free_all_banks(void)
                else
                        LOG_WARNING("Flash driver of %s does not support free_driver_priv()", bank->name);
 
+               /* For 'virtual' flash driver bank->sectors and bank->prot_blocks pointers are copied from
+                * master flash_bank structure. They point to memory locations allocated by master flash driver
+                * so master driver is responsible for releasing them.
+                * Avoid UB caused by double-free memory corruption if flash bank is 'virtual'. */
+
+               if (strcmp(bank->driver->name, "virtual") != 0) {
+                       free(bank->sectors);
+                       free(bank->prot_blocks);
+               }
+
                free(bank->name);
-               free(bank->sectors);
-               free(bank->prot_blocks);
                free(bank);
                bank = next;
        }
@@ -255,7 +270,7 @@ int get_flash_bank_by_num(int num, struct flash_bank **bank)
 /* lookup flash bank by address, bank not found is success, but
  * result_bank is set to NULL. */
 int get_flash_bank_by_addr(struct target *target,
-       uint32_t addr,
+       target_addr_t addr,
        bool check,
        struct flash_bank **result_bank)
 {
@@ -281,7 +296,7 @@ int get_flash_bank_by_addr(struct target *target,
        }
        *result_bank = NULL;
        if (check) {
-               LOG_ERROR("No flash at address 0x%08" PRIx32, addr);
+               LOG_ERROR("No flash at address " TARGET_ADDR_FMT, addr);
                return ERROR_FAIL;
        }
        return ERROR_OK;
@@ -309,8 +324,8 @@ static int default_flash_mem_blank_check(struct flash_bank *bank)
                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);
+                       if (chunk > (bank->sectors[i].size - j))
+                               chunk = (bank->sectors[i].size - j);
 
                        retval = target_read_memory(target,
                                        bank->base + bank->sectors[i].offset + j,
@@ -401,13 +416,13 @@ int default_flash_blank_check(struct flash_bank *bank)
  * warning about those additions.
  */
 static int flash_iterate_address_range_inner(struct target *target,
-       char *pad_reason, uint32_t addr, uint32_t length,
+       char *pad_reason, target_addr_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 */
+       target_addr_t last_addr = addr + length - 1;    /* the last address of range */
        int first = -1;
        int last = -1;
        int i;
@@ -433,7 +448,7 @@ static int flash_iterate_address_range_inner(struct target *target,
        }
 
        /* check whether it all fits in this bank */
-       if (addr + length - 1 > c->base + c->size - 1) {
+       if (last_addr > c->base + c->size - 1) {
                LOG_ERROR("Flash access does not fit into bank.");
                return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
        }
@@ -451,21 +466,19 @@ static int flash_iterate_address_range_inner(struct target *target,
                num_blocks = c->num_sectors;
        }
 
-       addr -= c->base;
-       last_addr -= c->base;
-
        for (i = 0; i < num_blocks; i++) {
                struct flash_sector *f = &block_array[i];
-               uint32_t end = f->offset + f->size;
+               target_addr_t sector_addr = c->base + f->offset;
+               target_addr_t sector_last_addr = sector_addr + f->size - 1;
 
                /* start only on a sector boundary */
                if (first < 0) {
                        /* scanned past the first sector? */
-                       if (addr < f->offset)
+                       if (addr < sector_addr)
                                break;
 
                        /* is this the first sector? */
-                       if (addr == f->offset)
+                       if (addr == sector_addr)
                                first = i;
 
                        /* Does this need head-padding?  If so, pad and warn;
@@ -475,20 +488,20 @@ static int flash_iterate_address_range_inner(struct target *target,
                         * ever know if that data was in use.  The warning
                         * should help users sort out messes later.
                         */
-                       else if (addr < end && pad_reason) {
+                       else if (addr <= sector_last_addr && pad_reason) {
                                /* FIXME say how many bytes (e.g. 80 KB) */
                                LOG_WARNING("Adding extra %s range, "
-                                       "%#8.8x to %#8.8x",
+                                       TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT,
                                        pad_reason,
-                                       (unsigned) f->offset,
-                                       (unsigned) addr - 1);
+                                       sector_addr,
+                                       addr - 1);
                                first = i;
                        } else
                                continue;
                }
 
                /* is this (also?) the last sector? */
-               if (last_addr == end) {
+               if (last_addr == sector_last_addr) {
                        last = i;
                        break;
                }
@@ -496,28 +509,28 @@ static int flash_iterate_address_range_inner(struct target *target,
                /* Does this need tail-padding?  If so, pad and warn;
                 * or else force an error.
                 */
-               if (last_addr < end && pad_reason) {
+               if (last_addr < sector_last_addr && pad_reason) {
                        /* FIXME say how many bytes (e.g. 80 KB) */
                        LOG_WARNING("Adding extra %s range, "
-                               "%#8.8x to %#8.8x",
+                               TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT,
                                pad_reason,
-                               (unsigned) last_addr,
-                               (unsigned) end - 1);
+                               last_addr + 1,
+                               sector_last_addr);
                        last = i;
                        break;
                }
 
                /* MUST finish on a sector boundary */
-               if (last_addr <= f->offset)
+               if (last_addr < sector_addr)
                        break;
        }
 
        /* 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) (c->base + last_addr - 1));
+               LOG_ERROR("address range " TARGET_ADDR_FMT " .. " TARGET_ADDR_FMT
+                       " is not sector-aligned",
+                       addr,
+                       last_addr);
                return ERROR_FLASH_DST_BREAKS_ALIGNMENT;
        }
 
@@ -532,7 +545,7 @@ static int flash_iterate_address_range_inner(struct target *target,
  * multiple chips.
  */
 static int flash_iterate_address_range(struct target *target,
-       char *pad_reason, uint32_t addr, uint32_t length,
+       char *pad_reason, target_addr_t addr, uint32_t length,
        bool iterate_protect_blocks,
        int (*callback)(struct flash_bank *bank, int first, int last))
 {
@@ -566,7 +579,7 @@ static int flash_iterate_address_range(struct target *target,
 }
 
 int flash_erase_address_range(struct target *target,
-       bool pad, uint32_t addr, uint32_t length)
+       bool pad, target_addr_t addr, uint32_t length)
 {
        return flash_iterate_address_range(target, pad ? "erase" : NULL,
                addr, length, false, &flash_driver_erase);
@@ -577,7 +590,8 @@ static int flash_driver_unprotect(struct flash_bank *bank, int first, int last)
        return flash_driver_protect(bank, 0, first, last);
 }
 
-int flash_unlock_address_range(struct target *target, uint32_t addr, uint32_t length)
+int flash_unlock_address_range(struct target *target, target_addr_t addr,
+               uint32_t length)
 {
        /* By default, pad to sector boundaries ... the real issue here
         * is that our (only) caller *permanently* removes protection,