diff --git a/src/flash/nor/at91sam7.c b/src/flash/nor/at91sam7.c index 03f771c87..9de829327 100644 --- a/src/flash/nor/at91sam7.c +++ b/src/flash/nor/at91sam7.c @@ -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) diff --git a/src/flash/nor/core.c b/src/flash/nor/core.c index 636d50c51..707dcff18 100644 --- a/src/flash/nor/core.c +++ b/src/flash/nor/core.c @@ -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; } - for (i = 0; i < bank->num_sectors; i++) { - uint32_t address = bank->base + bank->sectors[i].offset; - uint32_t size = bank->sectors[i].size; + 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); - retval = target_blank_check_memory(target, address, size, &blank, bank->erased_value); - if (retval != ERROR_OK) { - fast_check = 0; + for (i = 0; i < bank->num_sectors; i++) { + 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 */ + } + + 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 diff --git a/src/target/arm.h b/src/target/arm.h index 62fbb7368..dd25d53be 100644 --- a/src/target/arm.h +++ b/src/target/arm.h @@ -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); diff --git a/src/target/armv4_5.c b/src/target/armv4_5.c index a6fadaa0b..06994ca7b 100644 --- a/src/target/armv4_5.c +++ b/src/target/armv4_5.c @@ -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(®_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(®_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(®_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(®_params[0]); destroy_reg_param(®_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) diff --git a/src/target/armv7m.c b/src/target/armv7m.c index a8ddfe894..696f85cb2 100644 --- a/src/target/armv7m.c +++ b/src/target/armv7m.c @@ -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(®_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(®_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(®_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(®_params[0]); destroy_reg_param(®_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) diff --git a/src/target/armv7m.h b/src/target/armv7m.h index 6f5d6f995..01bf19e5c 100644 --- a/src/target/armv7m.h +++ b/src/target/armv7m.h @@ -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); diff --git a/src/target/mips32.c b/src/target/mips32.c index 93fb4e646..b5dbea312 100644 --- a/src/target/mips32.c +++ b/src/target/mips32.c @@ -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(®_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(®_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(®_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(®_params[0]); destroy_reg_param(®_params[1]); destroy_reg_param(®_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, diff --git a/src/target/mips32.h b/src/target/mips32.h index 928598f4c..4dc164e1b 100644 --- a/src/target/mips32.h +++ b/src/target/mips32.h @@ -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 */ diff --git a/src/target/stm8.c b/src/target/stm8.c index 4556fd987..5a3438a64 100644 --- a/src/target/stm8.c +++ b/src/target/stm8.c @@ -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(®_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, diff --git a/src/target/target.c b/src/target/target.c index 729a31bf5..75555c167 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -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) diff --git a/src/target/target.h b/src/target/target.h index 7a8a80f30..c5fb55ba7 100644 --- a/src/target/target.h +++ b/src/target/target.h @@ -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); /** diff --git a/src/target/target_type.h b/src/target/target_type.h index 0ab22bd5c..fbbd57d98 100644 --- a/src/target/target_type.h +++ b/src/target/target_type.h @@ -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