arm7_9: Avoid infinite loops in bulk write dispatching
[fw/openocd] / src / target / arm7_9_common.c
index bf081946efea28825667b76aba05f404a87b4d15..7687466f823d51284943e1420954870bda956fb6 100644 (file)
@@ -26,7 +26,7 @@
  *   You should have received a copy of the GNU General Public License     *
  *   along with this program; if not, write to the                         *
  *   Free Software Foundation, Inc.,                                       *
- *   59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.             *
+ *   51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.           *
  ***************************************************************************/
 
 #ifdef HAVE_CONFIG_H
@@ -2469,6 +2469,37 @@ int arm7_9_write_memory(struct target *target,
        return ERROR_OK;
 }
 
+int arm7_9_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);
+       int retval;
+
+       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;
 static const uint8_t *dcc_buffer;
 
@@ -2547,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) {
@@ -2557,26 +2591,27 @@ 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;
        }
 
-       struct arm_algorithm armv4_5_info;
+       struct arm_algorithm arm_algo;
        struct reg_param reg_params[1];
 
-       armv4_5_info.common_magic = ARM_COMMON_MAGIC;
-       armv4_5_info.core_mode = ARM_MODE_SVC;
-       armv4_5_info.core_state = ARM_STATE_ARM;
+       arm_algo.common_magic = ARM_COMMON_MAGIC;
+       arm_algo.core_mode = ARM_MODE_SVC;
+       arm_algo.core_state = ARM_STATE_ARM;
 
        init_reg_param(&reg_params[0], "r0", 32, PARAM_IN_OUT);
 
@@ -2587,7 +2622,7 @@ int arm7_9_bulk_write_memory(struct target *target,
        retval = armv4_5_run_algorithm_inner(target, 0, NULL, 1, reg_params,
                        arm7_9->dcc_working_area->address,
                        arm7_9->dcc_working_area->address + 6*4,
-                       20*1000, &armv4_5_info, arm7_9_dcc_completion);
+                       20*1000, &arm_algo, arm7_9_dcc_completion);
 
        if (retval == ERROR_OK) {
                uint32_t endaddress = buf_get_u32(reg_params[0].value, 0, 32);
@@ -2659,6 +2694,46 @@ int arm7_9_check_reset(struct target *target)
        return ERROR_OK;
 }
 
+int arm7_9_endianness_callback(jtag_callback_data_t pu8_in,
+               jtag_callback_data_t i_size, jtag_callback_data_t i_be,
+               jtag_callback_data_t i_flip)
+{
+       uint8_t *in = (uint8_t *)pu8_in;
+       int size = (int)i_size;
+       int be = (int)i_be;
+       int flip = (int)i_flip;
+       uint32_t readback;
+
+       switch (size) {
+       case 4:
+               readback = le_to_h_u32(in);
+               if (flip)
+                       readback = flip_u32(readback, 32);
+               if (be)
+                       h_u32_to_be(in, readback);
+               else
+                       h_u32_to_le(in, readback);
+               break;
+       case 2:
+               readback = le_to_h_u16(in);
+               if (flip)
+                       readback = flip_u32(readback, 16);
+               if (be)
+                       h_u16_to_be(in, readback & 0xffff);
+               else
+                       h_u16_to_le(in, readback & 0xffff);
+               break;
+       case 1:
+               readback = *in;
+               if (flip)
+                       readback = flip_u32(readback, 8);
+               *in = readback & 0xff;
+               break;
+       }
+
+       return ERROR_OK;
+}
+
 COMMAND_HANDLER(handle_arm7_9_dbgrq_command)
 {
        struct target *target = get_current_target(CMD_CTX);
@@ -2766,6 +2841,7 @@ int arm7_9_init_arch_info(struct target *target, struct arm7_9_common *arm7_9)
        arm7_9->dcc_downloads = false;
 
        arm->arch_info = arm7_9;
+       arm->core_type = ARM_MODE_ANY;
        arm->read_core_reg = arm7_9_read_core_reg;
        arm->write_core_reg = arm7_9_write_core_reg;
        arm->full_context = arm7_9_full_context;