aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--contrib/loaders/erase_check/Makefile2
-rw-r--r--contrib/loaders/erase_check/armv7m_0_erase_check.inc2
-rw-r--r--contrib/loaders/erase_check/armv7m_0_erase_check.s45
-rw-r--r--contrib/loaders/erase_check/armv7m_erase_check.inc4
-rw-r--r--contrib/loaders/erase_check/armv7m_erase_check.s48
-rw-r--r--src/target/armv7m.c134
6 files changed, 137 insertions, 98 deletions
diff --git a/contrib/loaders/erase_check/Makefile b/contrib/loaders/erase_check/Makefile
index 427fa0c..1a0fd9e 100644
--- a/contrib/loaders/erase_check/Makefile
+++ b/contrib/loaders/erase_check/Makefile
@@ -12,7 +12,7 @@ STM8_OBJCOPY ?= $(STM8_CROSS_COMPILE)objcopy
STM8_AFLAGS =
-arm: armv4_5_erase_check.inc armv7m_erase_check.inc armv7m_0_erase_check.inc
+arm: armv4_5_erase_check.inc armv7m_erase_check.inc
armv4_5_%.elf: armv4_5_%.s
$(ARM_AS) $(ARM_AFLAGS) $< -o $@
diff --git a/contrib/loaders/erase_check/armv7m_0_erase_check.inc b/contrib/loaders/erase_check/armv7m_0_erase_check.inc
deleted file mode 100644
index 76115ec..0000000
--- a/contrib/loaders/erase_check/armv7m_0_erase_check.inc
+++ /dev/null
@@ -1,2 +0,0 @@
-/* Autogenerated with ../../../src/helper/bin2char.sh */
-0x03,0x78,0x01,0x30,0x1a,0x43,0x01,0x39,0xfa,0xd1,0x00,0xbe,
diff --git a/contrib/loaders/erase_check/armv7m_0_erase_check.s b/contrib/loaders/erase_check/armv7m_0_erase_check.s
deleted file mode 100644
index 6b1e92a..0000000
--- a/contrib/loaders/erase_check/armv7m_0_erase_check.s
+++ /dev/null
@@ -1,45 +0,0 @@
-/***************************************************************************
- * Copyright (C) 2014 by Jeff Ciesielski *
- * jeffciesielski@gmail.com *
- * *
- * Based on the armv7m erase checker by: *
- * Copyright (C) 2010 by Spencer Oliver *
- * spen@spen-soft.co.uk *
- * *
- * This program is free software; you can redistribute it and/or modify *
- * it under the terms of the GNU General Public License as published by *
- * the Free Software Foundation; either version 2 of the License, or *
- * (at your option) any later version. *
- * *
- * This program is distributed in the hope that it will be useful, *
- * but WITHOUT ANY WARRANTY; without even the implied warranty of *
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
- * GNU General Public License for more details. *
- * *
- ***************************************************************************/
-
-/*
- parameters:
- r0 - address in
- r1 - byte count
- r2 - mask - result out
-*/
-
- .text
- .syntax unified
- .cpu cortex-m0
- .thumb
- .thumb_func
-
- .align 2
-
-loop:
- ldrb r3, [r0]
- adds r0, #1
- orrs r2, r2, r3
- subs r1, r1, #1
- bne loop
-end:
- bkpt #0
-
- .end
diff --git a/contrib/loaders/erase_check/armv7m_erase_check.inc b/contrib/loaders/erase_check/armv7m_erase_check.inc
index 1fe25cd..4ee96e1 100644
--- a/contrib/loaders/erase_check/armv7m_erase_check.inc
+++ b/contrib/loaders/erase_check/armv7m_erase_check.inc
@@ -1,2 +1,4 @@
/* Autogenerated with ../../../src/helper/bin2char.sh */
-0x03,0x78,0x01,0x30,0x1a,0x40,0x01,0x39,0xfa,0xd1,0x00,0xbe,
+0x02,0x68,0x12,0x42,0x0d,0xd0,0x43,0x68,0x1c,0x68,0x04,0x33,0x8c,0x42,0x05,0xd1,
+0x01,0x3a,0xf9,0xd1,0x01,0x24,0x04,0x60,0x08,0x30,0xf1,0xe7,0x00,0x24,0xfa,0xe7,
+0x00,0x00,0x00,0xbe,
diff --git a/contrib/loaders/erase_check/armv7m_erase_check.s b/contrib/loaders/erase_check/armv7m_erase_check.s
index 886e3e2..3303c87 100644
--- a/contrib/loaders/erase_check/armv7m_erase_check.s
+++ b/contrib/loaders/erase_check/armv7m_erase_check.s
@@ -20,9 +20,8 @@
/*
parameters:
- r0 - address in
- r1 - byte count
- r2 - mask - result out
+ r0 - pointer to struct { uint32_t size_in_result_out, uint32_t addr }
+ r1 - value to check
*/
.text
@@ -33,13 +32,42 @@
.align 2
-loop:
- ldrb r3, [r0]
- adds r0, #1
- ands r2, r2, r3
- subs r1, r1, #1
- bne loop
-end:
+BLOCK_SIZE_RESULT = 0
+BLOCK_ADDRESS = 4
+SIZEOF_STRUCT_BLOCK = 8
+
+start:
+block_loop:
+ ldr r2, [r0, #BLOCK_SIZE_RESULT] /* get size */
+ tst r2, r2
+ beq done
+
+ ldr r3, [r0, #BLOCK_ADDRESS] /* get address */
+
+word_loop:
+ ldr r4, [r3] /* read word */
+ adds r3, #4
+
+ cmp r4, r1
+ bne not_erased
+
+ subs r2, #1
+ bne word_loop
+
+ movs r4, #1 /* block is erased */
+save_result:
+ str r4, [r0, #BLOCK_SIZE_RESULT]
+ adds r0, #SIZEOF_STRUCT_BLOCK
+ b block_loop
+
+not_erased:
+ movs r4, #0
+ b save_result
+
+/* Avoid padding at .text segment end. Otherwise exit point check fails. */
+ .skip ( . - start + 2) & 2, 0
+
+done:
bkpt #0
.end
diff --git a/src/target/armv7m.c b/src/target/armv7m.c
index 696f85c..7b7893f 100644
--- a/src/target/armv7m.c
+++ b/src/target/armv7m.c
@@ -731,34 +731,23 @@ cleanup:
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,
@@ -766,46 +755,113 @@ int armv7m_blank_check_memory(struct target *target,
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(&reg_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(&reg_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(&reg_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(&reg_params[0]);
destroy_reg_param(&reg_params[1]);
- destroy_reg_param(&reg_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)