return retval;
}
-/** Checks whether a memory region is erased. */
+/** Checks an array of memory regions whether they are erased. */
int armv7m_blank_check_memory(struct target *target,
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];
+ struct working_area *erase_check_params;
+ struct reg_param reg_params[2];
struct armv7m_algorithm armv7m_info;
- const uint8_t *code;
- uint32_t code_size;
int retval;
+ static bool timed_out;
+
static const uint8_t erase_check_code[] = {
#include "../../contrib/loaders/erase_check/armv7m_erase_check.inc"
};
- static const uint8_t zero_erase_check_code[] = {
-#include "../../contrib/loaders/erase_check/armv7m_0_erase_check.inc"
- };
- switch (erased_value) {
- case 0x00:
- code = zero_erase_check_code;
- code_size = sizeof(zero_erase_check_code);
- break;
- case 0xff:
- default:
- code = erase_check_code;
- code_size = sizeof(erase_check_code);
- }
+ const uint32_t code_size = sizeof(erase_check_code);
/* make sure we have a working area */
if (target_alloc_working_area(target, code_size,
return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
retval = target_write_buffer(target, erase_check_algorithm->address,
- code_size, code);
+ code_size, erase_check_code);
if (retval != ERROR_OK)
- goto cleanup;
+ goto cleanup1;
+
+ /* prepare blocks array for algo */
+ struct algo_block {
+ union {
+ uint32_t size;
+ uint32_t result;
+ };
+ uint32_t address;
+ };
+
+ uint32_t avail = target_get_working_area_avail(target);
+ int blocks_to_check = avail / sizeof(struct algo_block) - 1;
+ if (num_blocks < blocks_to_check)
+ blocks_to_check = num_blocks;
+
+ struct algo_block *params = malloc((blocks_to_check+1)*sizeof(struct algo_block));
+ if (params == NULL) {
+ retval = ERROR_FAIL;
+ goto cleanup1;
+ }
+
+ int i;
+ uint32_t total_size = 0;
+ for (i = 0; i < blocks_to_check; i++) {
+ total_size += blocks[i].size;
+ target_buffer_set_u32(target, (uint8_t *)&(params[i].size),
+ blocks[i].size / sizeof(uint32_t));
+ target_buffer_set_u32(target, (uint8_t *)&(params[i].address),
+ blocks[i].address);
+ }
+ target_buffer_set_u32(target, (uint8_t *)&(params[blocks_to_check].size), 0);
+
+ uint32_t param_size = (blocks_to_check + 1) * sizeof(struct algo_block);
+ if (target_alloc_working_area(target, param_size,
+ &erase_check_params) != ERROR_OK) {
+ retval = ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
+ goto cleanup2;
+ }
+
+ retval = target_write_buffer(target, erase_check_params->address,
+ param_size, (uint8_t *)params);
+ if (retval != ERROR_OK)
+ goto cleanup3;
+
+ uint32_t erased_word = erased_value | (erased_value << 8)
+ | (erased_value << 16) | (erased_value << 24);
+
+ LOG_DEBUG("Starting erase check of %d blocks, parameters@"
+ TARGET_ADDR_FMT, blocks_to_check, erase_check_params->address);
armv7m_info.common_magic = ARMV7M_COMMON_MAGIC;
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, blocks->address);
+ buf_set_u32(reg_params[0].value, 0, 32, erase_check_params->address);
init_reg_param(®_params[1], "r1", 32, PARAM_OUT);
- buf_set_u32(reg_params[1].value, 0, 32, blocks->size);
+ buf_set_u32(reg_params[1].value, 0, 32, erased_word);
- init_reg_param(®_params[2], "r2", 32, PARAM_IN_OUT);
- buf_set_u32(reg_params[2].value, 0, 32, erased_value);
+ /* assume CPU clk at least 1 MHz */
+ int timeout = (timed_out ? 30000 : 2000) + total_size * 3 / 1000;
retval = target_run_algorithm(target,
- 0,
- NULL,
- 3,
- reg_params,
- erase_check_algorithm->address,
- erase_check_algorithm->address + (code_size - 2),
- 10000,
- &armv7m_info);
+ 0, NULL,
+ ARRAY_SIZE(reg_params), reg_params,
+ erase_check_algorithm->address,
+ erase_check_algorithm->address + (code_size - 2),
+ timeout,
+ &armv7m_info);
+
+ timed_out = retval == ERROR_TARGET_TIMEOUT;
+ if (retval != ERROR_OK && !timed_out)
+ goto cleanup4;
+
+ retval = target_read_buffer(target, erase_check_params->address,
+ param_size, (uint8_t *)params);
+ if (retval != ERROR_OK)
+ goto cleanup4;
- if (retval == ERROR_OK)
- blocks->result = buf_get_u32(reg_params[2].value, 0, 32);
+ for (i = 0; i < blocks_to_check; i++) {
+ uint32_t result = target_buffer_get_u32(target,
+ (uint8_t *)&(params[i].result));
+ if (result != 0 && result != 1)
+ break;
+
+ blocks[i].result = result;
+ }
+ if (i && timed_out)
+ LOG_INFO("Slow CPU clock: %d blocks checked, %d remain. Continuing...", i, num_blocks-i);
+
+ retval = i; /* return number of blocks really checked */
+cleanup4:
destroy_reg_param(®_params[0]);
destroy_reg_param(®_params[1]);
- destroy_reg_param(®_params[2]);
-cleanup:
+cleanup3:
+ target_free_working_area(target, erase_check_params);
+cleanup2:
+ free(params);
+cleanup1:
target_free_working_area(target, erase_check_algorithm);
- if (retval != ERROR_OK)
- return retval;
-
- return 1; /* only one block checked */
+ return retval;
}
int armv7m_maybe_skip_bkpt_inst(struct target *target, bool *inst_found)