]> git.sur5r.net Git - openocd/commitdiff
target, flash: prepare infrastructure for multi-block blank check
authorTomas Vanek <vanekt@fbl.cz>
Thu, 23 Nov 2017 08:18:24 +0000 (09:18 +0100)
committerTomas Vanek <vanekt@fbl.cz>
Tue, 10 Apr 2018 05:16:40 +0000 (06:16 +0100)
'flash erase_check' command runs a check algorithm on a target
if possible. The algorithm is run repeatedly for each flash sector.
Unfortunately every start and stop of the algorithm impose not negligible
overhead.
In practice it means checking is faster than plain read only for
sectors of size approx 4 kByte or bigger. And checking sectors
as short as 512 bytes runs approx 4 times slower than plain read.

The patch changes API call target_blank_check_memory() and related
to take an array of sectors (or arbitrary memory blocks).

Changes in target-specific checking routines are kept minimal.
They use only the first block from the array and process it by
the unchanged algorithm.

default_flash_blank_check() routine repeats target_blank_check_memory()
until all blocks are checked, so it works with both multi-block
and single-block based checkers.

Change-Id: I0e6c60f2d71364c9c07c09416b04de9268807f5e
Signed-off-by: Tomas Vanek <vanekt@fbl.cz>
Reviewed-on: http://openocd.zylin.com/4297
Tested-by: jenkins
Reviewed-by: Andreas Bolsch <hyphen0break@gmail.com>
12 files changed:
src/flash/nor/at91sam7.c
src/flash/nor/core.c
src/target/arm.h
src/target/armv4_5.c
src/target/armv7m.c
src/target/armv7m.h
src/target/mips32.c
src/target/mips32.h
src/target/stm8.c
src/target/target.c
src/target/target.h
src/target/target_type.h

index 03f771c87e2a9a483c8d523f9c3d6d54e5ab8f08..9de829327ac01cea07b4ae2f0016641d7b565079 100644 (file)
@@ -639,14 +639,6 @@ static int at91sam7_read_part_info(struct flash_bank *bank)
 
 static int at91sam7_erase_check(struct flash_bank *bank)
 {
-       struct target *target = bank->target;
-       uint16_t retval;
-       uint32_t blank;
-       uint16_t fast_check;
-       uint8_t *buffer;
-       uint16_t nSector;
-       uint16_t nByte;
-
        if (bank->target->state != TARGET_HALTED) {
                LOG_ERROR("Target not halted");
                return ERROR_TARGET_NOT_HALTED;
@@ -656,45 +648,7 @@ static int at91sam7_erase_check(struct flash_bank *bank)
        at91sam7_read_clock_info(bank);
        at91sam7_set_flash_mode(bank, FMR_TIMING_FLASH);
 
-       fast_check = 1;
-       for (nSector = 0; nSector < bank->num_sectors; nSector++) {
-               retval = target_blank_check_memory(target,
-                               bank->base + bank->sectors[nSector].offset,
-                               bank->sectors[nSector].size,
-                               &blank, bank->erased_value);
-               if (retval != ERROR_OK) {
-                       fast_check = 0;
-                       break;
-               }
-               if (blank == 0xFF)
-                       bank->sectors[nSector].is_erased = 1;
-               else
-                       bank->sectors[nSector].is_erased = 0;
-       }
-
-       if (fast_check)
-               return ERROR_OK;
-
-       LOG_USER("Running slow fallback erase check - add working memory");
-
-       buffer = malloc(bank->sectors[0].size);
-       for (nSector = 0; nSector < bank->num_sectors; nSector++) {
-               bank->sectors[nSector].is_erased = 1;
-               retval = target_read_memory(target, bank->base + bank->sectors[nSector].offset, 4,
-                               bank->sectors[nSector].size/4, buffer);
-               if (retval != ERROR_OK)
-                       return retval;
-
-               for (nByte = 0; nByte < bank->sectors[nSector].size; nByte++) {
-                       if (buffer[nByte] != 0xFF) {
-                               bank->sectors[nSector].is_erased = 0;
-                               break;
-                       }
-               }
-       }
-       free(buffer);
-
-       return ERROR_OK;
+       return default_flash_blank_check(bank);
 }
 
 static int at91sam7_protect_check(struct flash_bank *bank)
index 636d50c517a1463ed52e2b592579887001fd3a36..707dcff181a21e0bfa6a48648cf3480e253a7c4b 100644 (file)
@@ -339,36 +339,49 @@ 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;
        }
 
+       struct target_memory_check_block *block_array;
+       block_array = malloc(bank->num_sectors * sizeof(struct target_memory_check_block));
+       if (block_array == NULL)
+               return default_flash_mem_blank_check(bank);
+
        for (i = 0; i < bank->num_sectors; i++) {
-               uint32_t address = bank->base + bank->sectors[i].offset;
-               uint32_t size = bank->sectors[i].size;
+               block_array[i].address = bank->base + bank->sectors[i].offset;
+               block_array[i].size = bank->sectors[i].size;
+               block_array[i].result = UINT32_MAX; /* erase state unknown */
+       }
 
-               retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value);
-               if (retval != ERROR_OK) {
-                       fast_check = 0;
+       bool fast_check = true;
+       for (i = 0; i < bank->num_sectors; ) {
+               retval = target_blank_check_memory(target,
+                               block_array + i, bank->num_sectors - i,
+                               bank->erased_value);
+               if (retval < 1) {
+                       /* Run slow fallback if the first run gives no result
+                        * otherwise use possibly incomplete results */
+                       if (i == 0)
+                               fast_check = false;
                        break;
                }
-               if (blank == bank->erased_value)
-                       bank->sectors[i].is_erased = 1;
-               else
-                       bank->sectors[i].is_erased = 0;
-               fast_check = 1;
+               i += retval; /* add number of blocks done this round */
        }
 
-       if (!fast_check) {
+       if (fast_check) {
+               for (i = 0; i < bank->num_sectors; i++)
+                       bank->sectors[i].is_erased = block_array[i].result;
+               retval = ERROR_OK;
+       } else {
                LOG_USER("Running slow fallback erase check - add working memory");
-               return default_flash_mem_blank_check(bank);
+               retval = default_flash_mem_blank_check(bank);
        }
+       free(block_array);
 
-       return ERROR_OK;
+       return retval;
 }
 
 /* Manipulate given flash region, selecting the bank according to target
index 62fbb736856352fac42ca646140cf1cd84f390eb..dd25d53be3923d361efb9372fa2b8eebe0cb91cc 100644 (file)
@@ -308,7 +308,7 @@ int armv4_5_run_algorithm_inner(struct target *target,
 int arm_checksum_memory(struct target *target,
                target_addr_t address, uint32_t count, uint32_t *checksum);
 int arm_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
+               struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
 
 void arm_set_cpsr(struct arm *arm, uint32_t cpsr);
 struct reg *arm_reg_current(struct arm *arm, unsigned regnum);
index a6fadaa0b969b6e33599bd8d24612745fde7a6f6..06994ca7b456c8eec18f70af4ae04a1b3f57e427 100644 (file)
@@ -1663,7 +1663,7 @@ cleanup:
  *
  */
 int arm_blank_check_memory(struct target *target,
-       target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
+       struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
 {
        struct working_area *check_algorithm;
        struct reg_param reg_params[3];
@@ -1706,10 +1706,10 @@ int arm_blank_check_memory(struct target *target,
        arm_algo.core_state = ARM_STATE_ARM;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       buf_set_u32(reg_params[0].value, 0, 32, address);
+       buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address);
 
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size);
 
        init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
        buf_set_u32(reg_params[2].value, 0, 32, erased_value);
@@ -1724,7 +1724,7 @@ int arm_blank_check_memory(struct target *target,
                        10000, &arm_algo);
 
        if (retval == ERROR_OK)
-               *blank = buf_get_u32(reg_params[2].value, 0, 32);
+               blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
@@ -1733,7 +1733,10 @@ int arm_blank_check_memory(struct target *target,
 cleanup:
        target_free_working_area(target, check_algorithm);
 
-       return retval;
+       if (retval != ERROR_OK)
+               return retval;
+
+       return 1;       /* only one block has been checked */
 }
 
 static int arm_full_context(struct target *target)
index a8ddfe894a2cba659941df41851f4c02385ec0f1..696f85cb2721b05d677f0c170bf27ac567b9c1b2 100644 (file)
@@ -733,7 +733,7 @@ cleanup:
 
 /** Checks whether a memory region is erased. */
 int armv7m_blank_check_memory(struct target *target,
-       target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
+       struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
 {
        struct working_area *erase_check_algorithm;
        struct reg_param reg_params[3];
@@ -774,10 +774,10 @@ int armv7m_blank_check_memory(struct target *target,
        armv7m_info.core_mode = ARM_MODE_THREAD;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_OUT);
-       buf_set_u32(reg_params[0].value, 0, 32, address);
+       buf_set_u32(reg_params[0].value, 0, 32, blocks->address);
 
        init_reg_param(&reg_params[1], "r1", 32, PARAM_OUT);
-       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, blocks->size);
 
        init_reg_param(&reg_params[2], "r2", 32, PARAM_IN_OUT);
        buf_set_u32(reg_params[2].value, 0, 32, erased_value);
@@ -793,7 +793,7 @@ int armv7m_blank_check_memory(struct target *target,
                        &armv7m_info);
 
        if (retval == ERROR_OK)
-               *blank = buf_get_u32(reg_params[2].value, 0, 32);
+               blocks->result = buf_get_u32(reg_params[2].value, 0, 32);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
@@ -802,7 +802,10 @@ int armv7m_blank_check_memory(struct target *target,
 cleanup:
        target_free_working_area(target, erase_check_algorithm);
 
-       return retval;
+       if (retval != ERROR_OK)
+               return retval;
+
+       return 1;       /* only one block checked */
 }
 
 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)
index 6f5d6f9952bab418b91c574b5ff4476a78347ff3..01bf19e5c1733ff79313afb8fc7e65113759581d 100644 (file)
@@ -225,7 +225,7 @@ int armv7m_restore_context(struct target *target);
 int armv7m_checksum_memory(struct target *target,
                target_addr_t address, uint32_t count, uint32_t *checksum);
 int armv7m_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
+               struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
 
 int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found);
 
index 93fb4e646b2d25e2aa452e8f1240b426b48d71a4..b5dbea312c2c53ec80b57c2461680ad9cc09d904 100644 (file)
@@ -827,7 +827,8 @@ int mips32_checksum_memory(struct target *target, target_addr_t address,
 
 /** Checks whether a memory region is erased. */
 int mips32_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
+               struct target_memory_check_block *blocks, int num_blocks,
+               uint8_t erased_value)
 {
        struct working_area *erase_check_algorithm;
        struct reg_param reg_params[3];
@@ -866,16 +867,16 @@ int mips32_blank_check_memory(struct target *target,
        int retval = target_write_buffer(target, erase_check_algorithm->address,
                                                sizeof(erase_check_code), erase_check_code_8);
        if (retval != ERROR_OK)
-               return retval;
+               goto cleanup;
 
        mips32_info.common_magic = MIPS32_COMMON_MAGIC;
        mips32_info.isa_mode = isa ? MIPS32_ISA_MMIPS32 : MIPS32_ISA_MIPS32;
 
        init_reg_param(&reg_params[0], "r4", 32, PARAM_OUT);
-       buf_set_u32(reg_params[0].value, 0, 32, address);
+       buf_set_u32(reg_params[0].value, 0, 32, blocks[0].address);
 
        init_reg_param(&reg_params[1], "r5", 32, PARAM_OUT);
-       buf_set_u32(reg_params[1].value, 0, 32, count);
+       buf_set_u32(reg_params[1].value, 0, 32, blocks[0].size);
 
        init_reg_param(&reg_params[2], "r6", 32, PARAM_IN_OUT);
        buf_set_u32(reg_params[2].value, 0, 32, erased_value);
@@ -884,15 +885,19 @@ int mips32_blank_check_memory(struct target *target,
                        erase_check_algorithm->address + (sizeof(erase_check_code) - 4), 10000, &mips32_info);
 
        if (retval == ERROR_OK)
-               *blank = buf_get_u32(reg_params[2].value, 0, 32);
+               blocks[0].result = buf_get_u32(reg_params[2].value, 0, 32);
 
        destroy_reg_param(&reg_params[0]);
        destroy_reg_param(&reg_params[1]);
        destroy_reg_param(&reg_params[2]);
 
+cleanup:
        target_free_working_area(target, erase_check_algorithm);
 
-       return retval;
+       if (retval != ERROR_OK)
+               return retval;
+
+       return 1;       /* only one block has been checked */
 }
 
 static int mips32_verify_pointer(struct command_context *cmd_ctx,
index 928598f4c8a56277a14c4f4f70e9e4c4c0cb4d6f..4dc164e1b3f61528414f3d51b4f9dd78e8e6b78b 100644 (file)
@@ -428,6 +428,6 @@ int mips32_get_gdb_reg_list(struct target *target,
 int mips32_checksum_memory(struct target *target, target_addr_t address,
                uint32_t count, uint32_t *checksum);
 int mips32_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value);
+               struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value);
 
 #endif /* OPENOCD_TARGET_MIPS32_H */
index 4556fd987002567cffad6b533053126b8c9eea9e..5a3438a6407b927e6e9e1a4164a8ba11f03004a2 100644 (file)
@@ -1750,7 +1750,7 @@ static int stm8_examine(struct target *target)
 
 /** Checks whether a memory region is erased. */
 static int stm8_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t count, uint32_t *blank, uint8_t erased_value)
+               struct target_memory_check_block *blocks, int num_blocks, uint8_t erased_value)
 {
        struct working_area *erase_check_algorithm;
        struct reg_param reg_params[2];
@@ -1778,10 +1778,10 @@ static int stm8_blank_check_memory(struct target *target,
        stm8_info.common_magic = STM8_COMMON_MAGIC;
 
        init_mem_param(&mem_params[0], 0x0, 3, PARAM_OUT);
-       buf_set_u32(mem_params[0].value, 0, 24, address);
+       buf_set_u32(mem_params[0].value, 0, 24, blocks[0].address);
 
        init_mem_param(&mem_params[1], 0x3, 3, PARAM_OUT);
-       buf_set_u32(mem_params[1].value, 0, 24, count);
+       buf_set_u32(mem_params[1].value, 0, 24, blocks[0].size);
 
        init_reg_param(&reg_params[0], "a", 32, PARAM_IN_OUT);
        buf_set_u32(reg_params[0].value, 0, 32, erased_value);
@@ -1795,7 +1795,7 @@ static int stm8_blank_check_memory(struct target *target,
                        10000, &stm8_info);
 
        if (retval == ERROR_OK)
-               *blank = (*(reg_params[0].value) == 0xff);
+               blocks[0].result = (*(reg_params[0].value) == 0xff);
 
        destroy_mem_param(&mem_params[0]);
        destroy_mem_param(&mem_params[1]);
@@ -1803,7 +1803,10 @@ static int stm8_blank_check_memory(struct target *target,
 
        target_free_working_area(target, erase_check_algorithm);
 
-       return retval;
+       if (retval != ERROR_OK)
+               return retval;
+
+       return 1;       /* only one block has been checked */
 }
 
 static int stm8_checksum_memory(struct target *target, target_addr_t address,
index 729a31bf59b057a41d403c3a2cb365af55a4657f..75555c167a447fc9bd48dfc4394b33357e0e23aa 100644 (file)
@@ -2251,21 +2251,19 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_
        return retval;
 }
 
-int target_blank_check_memory(struct target *target, target_addr_t address, uint32_t size, uint32_t* blank,
+int target_blank_check_memory(struct target *target,
+       struct target_memory_check_block *blocks, int num_blocks,
        uint8_t erased_value)
 {
-       int retval;
        if (!target_was_examined(target)) {
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
 
-       if (target->type->blank_check_memory == 0)
+       if (target->type->blank_check_memory == NULL)
                return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
 
-       retval = target->type->blank_check_memory(target, address, size, blank, erased_value);
-
-       return retval;
+       return target->type->blank_check_memory(target, blocks, num_blocks, erased_value);
 }
 
 int target_read_u64(struct target *target, target_addr_t address, uint64_t *value)
index 7a8a80f30438eaff7cffd81d68b16e3c384fe15c..c5fb55ba7f264a126630f5fea9d18cf8f5460667 100644 (file)
@@ -312,6 +312,12 @@ struct target_timer_callback {
        struct target_timer_callback *next;
 };
 
+struct target_memory_check_block {
+       target_addr_t address;
+       uint32_t size;
+       uint32_t result;
+};
+
 int target_register_commands(struct command_context *cmd_ctx);
 int target_examine(void);
 
@@ -585,7 +591,8 @@ int target_read_buffer(struct target *target,
 int target_checksum_memory(struct target *target,
                target_addr_t address, uint32_t size, uint32_t *crc);
 int target_blank_check_memory(struct target *target,
-               target_addr_t address, uint32_t size, uint32_t *blank, uint8_t erased_value);
+               struct target_memory_check_block *blocks, int num_blocks,
+               uint8_t erased_value);
 int target_wait_state(struct target *target, enum target_state state, int ms);
 
 /**
index 0ab22bd5cf0a4df823c88fec95d3eced32e86fb7..fbbd57d980590e7ec8166cca723ce80098ff17d4 100644 (file)
@@ -130,8 +130,9 @@ struct target_type {
 
        int (*checksum_memory)(struct target *target, target_addr_t address,
                        uint32_t count, uint32_t *checksum);
-       int (*blank_check_memory)(struct target *target, target_addr_t address,
-                       uint32_t count, uint32_t *blank, uint8_t erased_value);
+       int (*blank_check_memory)(struct target *target,
+                       struct target_memory_check_block *blocks, int num_blocks,
+                       uint8_t erased_value);
 
        /*
         * target break-/watchpoint control