arm7_9: Avoid infinite loops in bulk write dispatching
[fw/openocd] / src / target / arm7_9_common.c
index 07beef51d4dd46d1c9405f501ae83be04e60e8fa..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,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;