arm7_9: Avoid infinite loops in bulk write dispatching 85/1685/2
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>
Fri, 4 Oct 2013 22:19:08 +0000 (00:19 +0200)
committerSpencer Oliver <spen@spen-soft.co.uk>
Tue, 15 Oct 2013 20:41:08 +0000 (20:41 +0000)
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>
src/target/arm7_9_common.c
src/target/arm7_9_common.h
src/target/arm7tdmi.c
src/target/arm920t.c
src/target/arm920t.h
src/target/arm926ejs.c
src/target/arm926ejs.h
src/target/arm9tdmi.c
src/target/fa526.c
src/target/feroceon.c

index 6eade96a16a66f9bfbc8cc2809e7cd9579ac4958..7687466f823d51284943e1420954870bda956fb6 100644 (file)
@@ -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;
index 85e5ac045657b2c824c6a89c789bee5daa011f8c..5821e132bdc2f5f1f03d0861da0d42e76759a9af 100644 (file)
@@ -119,6 +119,13 @@ struct arm7_9_common {
        void (*pre_restore_context)(struct target *target);
        /**< 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);
 
index 4c7cce19ebd707990c3bb5a4e540a9a725017305..3dc001343734da5fe5a33cd006fb02dbb28bcfb8 100644 (file)
@@ -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;
index 98bd12f56b07b4e4d7f9f89a8a847b4756760c84..fbfa170369e7514bf3d4ae7dd1365a4b810ad84f 100644 (file)
@@ -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,
index 37745130fefc555caf73b7745741cb2b01aa9708..71876a69bc126245e82cd5b5afc887a5d4c93dd0 100644 (file)
@@ -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);
index 1e0a579028fe6e1c0baf35d7f06df1e59e9f04af..af806139c21d43c6ad6d82b32c1b1e47e0cf3f53 100644 (file)
@@ -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,
index 6dde4c6ff2a9952de62f6f5cc0a2effff3adfaf3..cc19c9fc5181d154c757f8489a99900c0a68f092 100644 (file)
@@ -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[];
index d93c15f7cb3521a02dc69ea0600fc040b6f85ecc..ac07534f38f7bbfeaa6ec3b0768ae92373056500 100644 (file)
@@ -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;
index a33b4a1c678fd4265c136d70ce1a97d7b8d1f13b..dfb29b8ee4dd729c1ce65448ab83943534489432 100644 (file)
@@ -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,
index d3037c5433ade42e126698da5b57ca31bb8da282..acaa1b3b4846cab63523783a1871cae2c75909c3 100644 (file)
@@ -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,

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)