aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>2013-10-05 00:19:08 +0200
committerSpencer Oliver <spen@spen-soft.co.uk>2013-10-15 20:41:08 +0000
commitff5ec942d80a34e20b5a3ca3328f7e6a55fb309b (patch)
tree1d5682ae57f84d16f136b27ee75a6158790fca3f
parent8e6e7948de11e69fa53e7b7f306d35d6d4904b14 (diff)
downloadriscv-openocd-ff5ec942d80a34e20b5a3ca3328f7e6a55fb309b.zip
riscv-openocd-ff5ec942d80a34e20b5a3ca3328f7e6a55fb309b.tar.gz
riscv-openocd-ff5ec942d80a34e20b5a3ca3328f7e6a55fb309b.tar.bz2
arm7_9: Avoid infinite loops in bulk write dispatching
Add a mandatory field in struct arm7_9_common for regular, non-optimized memory writes. Together with the existing bulk_memory_write field, this allows variants to select any combination of implementations for regular and bulk writes, without risking infinite loops from accidentally using bulk writes for implementing bulk writes. ARM 7/9 targets may now select arm7_9_memory_write_opt as their target.write_memory implementation, which will dispatch to arm7_9_common.bulk_write_memory if possible, or fallback to arm7_9_common.write_memory otherwise. To avoid loops, bulk write implementations mustn't call any other functions than arm7_9_write_memory_no_opt() to write memory; it will unconditionally call arm7_9_common.write_memory. If they fail, they should simply return error to allow the caller to fallback to regular writes. Tested on a regular ARM7TDMI only. Change-Id: Iae42a6e093e2df68c4823c927d757ae8f42ef388 Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com> Reviewed-on: http://openocd.zylin.com/1685 Tested-by: jenkins Reviewed-by: Sergey A. Borshch <sb-sf@users.sourceforge.net> Reviewed-by: Spencer Oliver <spen@spen-soft.co.uk>
-rw-r--r--src/target/arm7_9_common.c37
-rw-r--r--src/target/arm7_9_common.h9
-rw-r--r--src/target/arm7tdmi.c1
-rw-r--r--src/target/arm920t.c13
-rw-r--r--src/target/arm920t.h2
-rw-r--r--src/target/arm926ejs.c13
-rw-r--r--src/target/arm926ejs.h2
-rw-r--r--src/target/arm9tdmi.c1
-rw-r--r--src/target/fa526.c3
-rw-r--r--src/target/feroceon.c22
10 files changed, 61 insertions, 42 deletions
diff --git a/src/target/arm7_9_common.c b/src/target/arm7_9_common.c
index 6eade96..7687466 100644
--- a/src/target/arm7_9_common.c
+++ b/src/target/arm7_9_common.c
@@ -2476,11 +2476,28 @@ int arm7_9_write_memory_opt(struct target *target,
const uint8_t *buffer)
{
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
+ int retval;
- if (size == 4 && count > 32 && arm7_9->bulk_write_memory)
- return arm7_9->bulk_write_memory(target, address, count, buffer);
- else
- return arm7_9_write_memory(target, address, size, count, buffer);
+ if (size == 4 && count > 32 && arm7_9->bulk_write_memory) {
+ /* Attempt to do a bulk write */
+ retval = arm7_9->bulk_write_memory(target, address, count, buffer);
+
+ if (retval == ERROR_OK)
+ return ERROR_OK;
+ }
+
+ return arm7_9->write_memory(target, address, size, count, buffer);
+}
+
+int arm7_9_write_memory_no_opt(struct target *target,
+ uint32_t address,
+ uint32_t size,
+ uint32_t count,
+ const uint8_t *buffer)
+{
+ struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
+
+ return arm7_9->write_memory(target, address, size, count, buffer);
}
static int dcc_count;
@@ -2561,8 +2578,11 @@ int arm7_9_bulk_write_memory(struct target *target,
struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
int i;
+ if (address % 4 != 0)
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
if (!arm7_9->dcc_downloads)
- return target_write_memory(target, address, 4, count, buffer);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* regrab previously allocated working_area, or allocate a new one */
if (!arm7_9->dcc_working_area) {
@@ -2571,15 +2591,16 @@ int arm7_9_bulk_write_memory(struct target *target,
/* make sure we have a working area */
if (target_alloc_working_area(target, 24, &arm7_9->dcc_working_area) != ERROR_OK) {
LOG_INFO("no working area available, falling back to memory writes");
- return target_write_memory(target, address, 4, count, buffer);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
/* copy target instructions to target endianness */
for (i = 0; i < 6; i++)
target_buffer_set_u32(target, dcc_code_buf + i*4, dcc_code[i]);
- /* write DCC code to working area */
- retval = target_write_memory(target,
+ /* write DCC code to working area, using the non-optimized
+ * memory write to avoid ending up here again */
+ retval = arm7_9_write_memory_no_opt(target,
arm7_9->dcc_working_area->address, 4, 6, dcc_code_buf);
if (retval != ERROR_OK)
return retval;
diff --git a/src/target/arm7_9_common.h b/src/target/arm7_9_common.h
index 85e5ac0..5821e13 100644
--- a/src/target/arm7_9_common.h
+++ b/src/target/arm7_9_common.h
@@ -120,6 +120,13 @@ struct arm7_9_common {
/**< Callback function called before restoring the processor context */
/**
+ * Variant specific memory write function that does not dispatch to bulk_write_memory.
+ * Used as a fallback when bulk writes are unavailable, or for writing data needed to
+ * do the bulk writes.
+ */
+ int (*write_memory)(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer);
+ /**
* Write target memory in multiples of 4 bytes, optimized for
* writing large quantities of data.
*/
@@ -160,6 +167,8 @@ int arm7_9_write_memory(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer);
int arm7_9_write_memory_opt(struct target *target, uint32_t address,
uint32_t size, uint32_t count, const uint8_t *buffer);
+int arm7_9_write_memory_no_opt(struct target *target, uint32_t address,
+ uint32_t size, uint32_t count, const uint8_t *buffer);
int arm7_9_bulk_write_memory(struct target *target, uint32_t address,
uint32_t count, const uint8_t *buffer);
diff --git a/src/target/arm7tdmi.c b/src/target/arm7tdmi.c
index 4c7cce1..3dc0013 100644
--- a/src/target/arm7tdmi.c
+++ b/src/target/arm7tdmi.c
@@ -648,6 +648,7 @@ int arm7tdmi_init_arch_info(struct target *target,
arm7_9->enable_single_step = arm7_9_enable_eice_step;
arm7_9->disable_single_step = arm7_9_disable_eice_step;
+ arm7_9->write_memory = arm7_9_write_memory;
arm7_9->bulk_write_memory = arm7_9_bulk_write_memory;
arm7_9->post_debug_entry = NULL;
diff --git a/src/target/arm920t.c b/src/target/arm920t.c
index 98bd12f..fbfa170 100644
--- a/src/target/arm920t.c
+++ b/src/target/arm920t.c
@@ -740,17 +740,6 @@ int arm920t_write_memory(struct target *target, uint32_t address,
return ERROR_OK;
}
-int arm920t_write_memory_opt(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, const uint8_t *buffer)
-{
- struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
-
- if (size == 4 && count > 32 && arm7_9->bulk_write_memory)
- return arm7_9->bulk_write_memory(target, address, count, buffer);
- else
- return arm920t_write_memory(target, address, size, count, buffer);
-}
-
/* EXPORTED to FA256 */
int arm920t_soft_reset_halt(struct target *target)
{
@@ -1708,7 +1697,7 @@ struct target_type arm920t_target = {
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm920t_read_memory,
- .write_memory = arm920t_write_memory_opt,
+ .write_memory = arm7_9_write_memory_opt,
.read_phys_memory = arm920t_read_phys_memory,
.write_phys_memory = arm920t_write_phys_memory,
.mmu = arm920_mmu,
diff --git a/src/target/arm920t.h b/src/target/arm920t.h
index 3774513..71876a6 100644
--- a/src/target/arm920t.h
+++ b/src/target/arm920t.h
@@ -60,8 +60,6 @@ int arm920t_read_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
int arm920t_write_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
-int arm920t_write_memory_opt(struct target *target,
- uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
int arm920t_post_debug_entry(struct target *target);
void arm920t_pre_restore_context(struct target *target);
int arm920t_get_ttb(struct target *target, uint32_t *result);
diff --git a/src/target/arm926ejs.c b/src/target/arm926ejs.c
index 1e0a579..af80613 100644
--- a/src/target/arm926ejs.c
+++ b/src/target/arm926ejs.c
@@ -656,17 +656,6 @@ int arm926ejs_write_memory(struct target *target, uint32_t address,
return retval;
}
-int arm926ejs_write_memory_opt(struct target *target, uint32_t address,
- uint32_t size, uint32_t count, const uint8_t *buffer)
-{
- struct arm7_9_common *arm7_9 = target_to_arm7_9(target);
-
- if (size == 4 && count > 32 && arm7_9->bulk_write_memory)
- return arm7_9->bulk_write_memory(target, address, count, buffer);
- else
- return arm926ejs_write_memory(target, address, size, count, buffer);
-}
-
static int arm926ejs_write_phys_memory(struct target *target,
uint32_t address, uint32_t size,
uint32_t count, const uint8_t *buffer)
@@ -819,7 +808,7 @@ struct target_type arm926ejs_target = {
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
- .write_memory = arm926ejs_write_memory_opt,
+ .write_memory = arm7_9_write_memory_opt,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
diff --git a/src/target/arm926ejs.h b/src/target/arm926ejs.h
index 6dde4c6..cc19c9f 100644
--- a/src/target/arm926ejs.h
+++ b/src/target/arm926ejs.h
@@ -50,8 +50,6 @@ int arm926ejs_init_arch_info(struct target *target,
int arm926ejs_arch_state(struct target *target);
int arm926ejs_write_memory(struct target *target,
uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
-int arm926ejs_write_memory_opt(struct target *target,
- uint32_t address, uint32_t size, uint32_t count, const uint8_t *buffer);
int arm926ejs_soft_reset_halt(struct target *target);
extern const struct command_registration arm926ejs_command_handlers[];
diff --git a/src/target/arm9tdmi.c b/src/target/arm9tdmi.c
index d93c15f..ac07534 100644
--- a/src/target/arm9tdmi.c
+++ b/src/target/arm9tdmi.c
@@ -752,6 +752,7 @@ int arm9tdmi_init_arch_info(struct target *target,
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
+ arm7_9->write_memory = arm7_9_write_memory;
arm7_9->bulk_write_memory = arm7_9_bulk_write_memory;
arm7_9->post_debug_entry = NULL;
diff --git a/src/target/fa526.c b/src/target/fa526.c
index a33b4a1..dfb29b8 100644
--- a/src/target/fa526.c
+++ b/src/target/fa526.c
@@ -284,6 +284,7 @@ static int fa526_init_arch_info_2(struct target *target,
arm7_9->enable_single_step = arm9tdmi_enable_single_step;
arm7_9->disable_single_step = arm9tdmi_disable_single_step;
+ arm7_9->write_memory = arm920t_write_memory;
arm7_9->bulk_write_memory = arm7_9_bulk_write_memory;
arm7_9->post_debug_entry = NULL;
@@ -368,7 +369,7 @@ struct target_type fa526_target = {
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm920t_read_memory,
- .write_memory = arm920t_write_memory_opt,
+ .write_memory = arm7_9_write_memory_opt,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,
diff --git a/src/target/feroceon.c b/src/target/feroceon.c
index d3037c5..acaa1b3 100644
--- a/src/target/feroceon.c
+++ b/src/target/feroceon.c
@@ -493,8 +493,11 @@ static int feroceon_bulk_write_memory(struct target *target,
uint32_t dcc_size = sizeof(dcc_code);
+ if (address % 4 != 0)
+ return ERROR_TARGET_UNALIGNED_ACCESS;
+
if (!arm7_9->dcc_downloads)
- return target_write_memory(target, address, 4, count, buffer);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
/* regrab previously allocated working_area, or allocate a new one */
if (!arm7_9->dcc_working_area) {
@@ -503,15 +506,16 @@ static int feroceon_bulk_write_memory(struct target *target,
/* make sure we have a working area */
if (target_alloc_working_area(target, dcc_size, &arm7_9->dcc_working_area) != ERROR_OK) {
LOG_INFO("no working area available, falling back to memory writes");
- return target_write_memory(target, address, 4, count, buffer);
+ return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
}
/* copy target instructions to target endianness */
for (i = 0; i < dcc_size/4; i++)
target_buffer_set_u32(target, dcc_code_buf + i*4, dcc_code[i]);
- /* write DCC code to working area */
- retval = target_write_memory(target,
+ /* write DCC code to working area, using the non-optimized
+ * memory write to avoid ending up here again */
+ retval = arm7_9_write_memory_no_opt(target,
arm7_9->dcc_working_area->address, 4, dcc_size/4, dcc_code_buf);
if (retval != ERROR_OK)
return retval;
@@ -627,6 +631,10 @@ static int feroceon_target_create(struct target *target, Jim_Interp *interp)
arm926ejs_init_arch_info(target, arm926ejs, target->tap);
feroceon_common_setup(target);
+ struct arm *arm = target->arch_info;
+ struct arm7_9_common *arm7_9 = arm->arch_info;
+ arm7_9->write_memory = arm926ejs_write_memory;
+
/* the standard ARM926 methods don't always work (don't ask...) */
arm926ejs->read_cp15 = feroceon_read_cp15;
arm926ejs->write_cp15 = feroceon_write_cp15;
@@ -641,6 +649,10 @@ static int dragonite_target_create(struct target *target, Jim_Interp *interp)
arm966e_init_arch_info(target, arm966e, target->tap);
feroceon_common_setup(target);
+ struct arm *arm = target->arch_info;
+ struct arm7_9_common *arm7_9 = arm->arch_info;
+ arm7_9->write_memory = arm7_9_write_memory;
+
return ERROR_OK;
}
@@ -697,7 +709,7 @@ struct target_type feroceon_target = {
.get_gdb_reg_list = arm_get_gdb_reg_list,
.read_memory = arm7_9_read_memory,
- .write_memory = arm926ejs_write_memory_opt,
+ .write_memory = arm7_9_write_memory_opt,
.checksum_memory = arm_checksum_memory,
.blank_check_memory = arm_blank_check_memory,