verify: display up to 128 diff's
[fw/openocd] / src / target / target.c
index b6813fd3facf00806ed509d2b9d414408918be3f..01d94416b27540163ad76f8778a4e59ec11d21ec 100644 (file)
@@ -2,7 +2,7 @@
  *   Copyright (C) 2005 by Dominic Rath                                    *
  *   Dominic.Rath@gmx.de                                                   *
  *                                                                         *
- *   Copyright (C) 2007-2009 Øyvind Harboe                                 *
+ *   Copyright (C) 2007-2010 Øyvind Harboe                                 *
  *   oyvind.harboe@zylin.com                                               *
  *                                                                         *
  *   Copyright (C) 2008, Duane Ellis                                       *
@@ -50,6 +50,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj *const *argv);
 static int target_mem2array(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj *const *argv);
+static int target_register_user_commands(struct command_context *cmd_ctx);
 
 /* targets */
 extern struct target_type arm7tdmi_target;
@@ -70,7 +71,7 @@ extern struct target_type avr_target;
 extern struct target_type dsp563xx_target;
 extern struct target_type testee_target;
 
-struct target_type *target_types[] =
+static struct target_type *target_types[] =
 {
        &arm7tdmi_target,
        &arm9tdmi_target,
@@ -93,8 +94,8 @@ struct target_type *target_types[] =
 };
 
 struct target *all_targets = NULL;
-struct target_event_callback *target_event_callbacks = NULL;
-struct target_timer_callback *target_timer_callbacks = NULL;
+static struct target_event_callback *target_event_callbacks = NULL;
+static struct target_timer_callback *target_timer_callbacks = NULL;
 
 static const Jim_Nvp nvp_assert[] = {
        { .name = "assert", NVP_ASSERT },
@@ -121,7 +122,7 @@ static const Jim_Nvp nvp_error_target[] = {
        { .value = -1, .name = NULL }
 };
 
-const char *target_strerror_safe(int err)
+static const char *target_strerror_safe(int err)
 {
        const Jim_Nvp *n;
 
@@ -282,7 +283,7 @@ uint16_t target_buffer_get_u16(struct target *target, const uint8_t *buffer)
 }
 
 /* read a uint8_t from a buffer in target memory endianness */
-uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer)
+static uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer)
 {
        return *buffer & 0x0ff;
 }
@@ -306,7 +307,7 @@ void target_buffer_set_u16(struct target *target, uint8_t *buffer, uint16_t valu
 }
 
 /* write a uint8_t to a buffer in target memory endianness */
-void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t value)
+static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t value)
 {
        *buffer = value;
 }
@@ -473,18 +474,10 @@ int target_resume(struct target *target, int current, uint32_t address, int hand
        if ((retval = target->type->resume(target, current, address, handle_breakpoints, debug_execution)) != ERROR_OK)
                return retval;
 
-       /* Invalidate any cached protect/erase/... flash status, since
-        * almost all targets will now be able modify the flash by
-        * themselves.  We want flash drivers and infrastructure to
-        * be able to rely on (non-invalidated) cached state.
-        *
-        * REVISIT do the same for NAND ; maybe other flash flavors too...
-        */
-       nor_resume(target);
        return retval;
 }
 
-int target_process_reset(struct command_context *cmd_ctx, enum target_reset_mode reset_mode)
+static int target_process_reset(struct command_context *cmd_ctx, enum target_reset_mode reset_mode)
 {
        char buf[100];
        int retval;
@@ -629,23 +622,55 @@ static int target_soft_reset_halt_imp(struct target *target)
        return target->type->soft_reset_halt_imp(target);
 }
 
-static int target_run_algorithm_imp(struct target *target, int num_mem_params, struct mem_param *mem_params, int num_reg_params, struct reg_param *reg_param, uint32_t entry_point, uint32_t exit_point, int timeout_ms, void *arch_info)
+/**
+ * Downloads a target-specific native code algorithm to the target,
+ * and executes it.  * Note that some targets may need to set up, enable,
+ * and tear down a breakpoint (hard or * soft) to detect algorithm
+ * termination, while others may support  lower overhead schemes where
+ * soft breakpoints embedded in the algorithm automatically terminate the
+ * algorithm.
+ *
+ * @param target used to run the algorithm
+ * @param arch_info target-specific description of the algorithm.
+ */
+int target_run_algorithm(struct target *target,
+               int num_mem_params, struct mem_param *mem_params,
+               int num_reg_params, struct reg_param *reg_param,
+               uint32_t entry_point, uint32_t exit_point,
+               int timeout_ms, void *arch_info)
 {
+       int retval = ERROR_FAIL;
+
        if (!target_was_examined(target))
        {
                LOG_ERROR("Target not examined yet");
-               return ERROR_FAIL;
+               goto done;
        }
-       return target->type->run_algorithm_imp(target, num_mem_params, mem_params, num_reg_params, reg_param, entry_point, exit_point, timeout_ms, arch_info);
+       if (!target->type->run_algorithm) {
+               LOG_ERROR("Target type '%s' does not support %s",
+                               target_type_name(target), __func__);
+               goto done;
+       }
+
+       target->running_alg = true;
+       retval = target->type->run_algorithm(target,
+                       num_mem_params, mem_params,
+                       num_reg_params, reg_param,
+                       entry_point, exit_point, timeout_ms, arch_info);
+       target->running_alg = false;
+
+done:
+       return retval;
 }
 
+
 int target_read_memory(struct target *target,
                uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
 {
        return target->type->read_memory(target, address, size, count, buffer);
 }
 
-int target_read_phys_memory(struct target *target,
+static int target_read_phys_memory(struct target *target,
                uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
 {
        return target->type->read_phys_memory(target, address, size, count, buffer);
@@ -657,7 +682,7 @@ int target_write_memory(struct target *target,
        return target->type->write_memory(target, address, size, count, buffer);
 }
 
-int target_write_phys_memory(struct target *target,
+static int target_write_phys_memory(struct target *target,
                uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
 {
        return target->type->write_phys_memory(target, address, size, count, buffer);
@@ -711,17 +736,6 @@ int target_step(struct target *target,
 }
 
 
-int target_run_algorithm(struct target *target,
-               int num_mem_params, struct mem_param *mem_params,
-               int num_reg_params, struct reg_param *reg_param,
-               uint32_t entry_point, uint32_t exit_point,
-               int timeout_ms, void *arch_info)
-{
-       return target->type->run_algorithm(target,
-                       num_mem_params, mem_params, num_reg_params, reg_param,
-                       entry_point, exit_point, timeout_ms, arch_info);
-}
-
 /**
  * Reset the @c examined flag for the given target.
  * Pure paranoia -- targets are zeroed on allocation.
@@ -785,9 +799,6 @@ static int target_init_one(struct command_context *cmd_ctx,
        type->soft_reset_halt_imp = target->type->soft_reset_halt;
        type->soft_reset_halt = target_soft_reset_halt_imp;
 
-       type->run_algorithm_imp = target->type->run_algorithm;
-       type->run_algorithm = target_run_algorithm_imp;
-
        /* Sanity-check MMU support ... stub in what we must, to help
         * implement it in stages, but warn if we need to do so.
         */
@@ -831,7 +842,7 @@ static int target_init_one(struct command_context *cmd_ctx,
        return ERROR_OK;
 }
 
-int target_init(struct command_context *cmd_ctx)
+static int target_init(struct command_context *cmd_ctx)
 {
        struct target *target;
        int retval;
@@ -964,7 +975,7 @@ int target_unregister_event_callback(int (*callback)(struct target *target, enum
        return ERROR_OK;
 }
 
-int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
 {
        struct target_timer_callback **p = &target_timer_callbacks;
        struct target_timer_callback *c = target_timer_callbacks;
@@ -1087,7 +1098,7 @@ int target_call_timer_callbacks_now(void)
        return target_call_timer_callbacks_check_time(0);
 }
 
-int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area)
+int target_alloc_working_area_try(struct target *target, uint32_t size, struct working_area **area)
 {
        struct working_area *c = target->working_areas;
        struct working_area *new_wa = NULL;
@@ -1165,8 +1176,6 @@ int target_alloc_working_area(struct target *target, uint32_t size, struct worki
 
                if (free_size < size)
                {
-                       LOG_WARNING("not enough working area available(requested %u, free %u)",
-                                   (unsigned)(size), (unsigned)(free_size));
                        return ERROR_TARGET_RESOURCE_NOT_AVAILABLE;
                }
 
@@ -1207,7 +1216,20 @@ int target_alloc_working_area(struct target *target, uint32_t size, struct worki
        return ERROR_OK;
 }
 
-int target_free_working_area_restore(struct target *target, struct working_area *area, int restore)
+int target_alloc_working_area(struct target *target, uint32_t size, struct working_area **area)
+{
+       int retval;
+
+       retval = target_alloc_working_area_try(target, size, area);
+       if (retval == ERROR_TARGET_RESOURCE_NOT_AVAILABLE)
+       {
+               LOG_WARNING("not enough working area available(requested %u)", (unsigned)(size));
+       }
+       return retval;
+
+}
+
+static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore)
 {
        if (area->free)
                return ERROR_OK;
@@ -1236,7 +1258,7 @@ int target_free_working_area(struct target *target, struct working_area *area)
 /* free resources and restore memory, if restoring memory fails,
  * free up resources anyway
  */
-void target_free_all_working_areas_restore(struct target *target, int restore)
+static void target_free_all_working_areas_restore(struct target *target, int restore)
 {
        struct working_area *c = target->working_areas;
 
@@ -1784,6 +1806,12 @@ static int handle_target(void *priv)
        Jim_Interp *interp = (Jim_Interp *)priv;
        int retval = ERROR_OK;
 
+       if (!is_jtag_poll_safe())
+       {
+               /* polling is disabled currently */
+               return ERROR_OK;
+       }
+
        /* we do not want to recurse here... */
        static int recursive = 0;
        if (! recursive)
@@ -2294,6 +2322,76 @@ COMMAND_HANDLER(handle_md_command)
        return retval;
 }
 
+typedef int (*target_write_fn)(struct target *target,
+               uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
+
+static int target_write_memory_fast(struct target *target,
+               uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer)
+{
+       return target_write_buffer(target, address, size * count, buffer);
+}
+
+static int target_fill_mem(struct target *target,
+               uint32_t address,
+               target_write_fn fn,
+               unsigned data_size,
+               /* value */
+               uint32_t b,
+               /* count */
+               unsigned c)
+{
+       /* We have to write in reasonably large chunks to be able
+        * to fill large memory areas with any sane speed */
+       const unsigned chunk_size = 16384;
+       uint8_t *target_buf = malloc(chunk_size * data_size);
+       if (target_buf == NULL)
+       {
+               LOG_ERROR("Out of memory");
+               return ERROR_FAIL;
+       }
+
+       for (unsigned i = 0; i < chunk_size; i ++)
+       {
+               switch (data_size)
+               {
+               case 4:
+                       target_buffer_set_u32(target, target_buf + i*data_size, b);
+                       break;
+               case 2:
+                       target_buffer_set_u16(target, target_buf + i*data_size, b);
+                       break;
+               case 1:
+                       target_buffer_set_u8(target, target_buf + i*data_size, b);
+                       break;
+               default:
+                       exit(-1);
+               }
+       }
+
+       int retval = ERROR_OK;
+
+       for (unsigned x = 0; x < c; x += chunk_size)
+       {
+               unsigned current;
+               current = c - x;
+               if (current > chunk_size)
+               {
+                       current = chunk_size;
+               }
+               int retval = fn(target, address + x * data_size, data_size, current, target_buf);
+               if (retval != ERROR_OK)
+               {
+                       break;
+               }
+               /* avoid GDB timeouts */
+               keep_alive();
+       }
+       free(target_buf);
+
+       return retval;
+}
+
+
 COMMAND_HANDLER(handle_mw_command)
 {
        if (CMD_ARGC < 2)
@@ -2301,8 +2399,7 @@ COMMAND_HANDLER(handle_mw_command)
                return ERROR_COMMAND_SYNTAX_ERROR;
        }
        bool physical=strcmp(CMD_ARGV[0], "phys")==0;
-       int (*fn)(struct target *target,
-                       uint32_t address, uint32_t size, uint32_t count, uint8_t *buffer);
+       target_write_fn fn;
        if (physical)
        {
                CMD_ARGC--;
@@ -2310,7 +2407,7 @@ COMMAND_HANDLER(handle_mw_command)
                fn=target_write_phys_memory;
        } else
        {
-               fn=target_write_memory;
+               fn = target_write_memory_fast;
        }
        if ((CMD_ARGC < 2) || (CMD_ARGC > 3))
                return ERROR_COMMAND_SYNTAX_ERROR;
@@ -2327,35 +2424,22 @@ COMMAND_HANDLER(handle_mw_command)
 
        struct target *target = get_current_target(CMD_CTX);
        unsigned wordsize;
-       uint8_t value_buf[4];
        switch (CMD_NAME[2])
        {
                case 'w':
                        wordsize = 4;
-                       target_buffer_set_u32(target, value_buf, value);
                        break;
                case 'h':
                        wordsize = 2;
-                       target_buffer_set_u16(target, value_buf, value);
                        break;
                case 'b':
                        wordsize = 1;
-                       value_buf[0] = value;
                        break;
                default:
                        return ERROR_COMMAND_SYNTAX_ERROR;
        }
-       for (unsigned i = 0; i < count; i++)
-       {
-               int retval = fn(target,
-                               address + i * wordsize, wordsize, 1, value_buf);
-               if (ERROR_OK != retval)
-                       return retval;
-               keep_alive();
-       }
-
-       return ERROR_OK;
 
+       return target_fill_mem(target, address, fn, wordsize, value, count);
 }
 
 static COMMAND_HELPER(parse_load_image_command_CMD_ARGV, struct image *image,
@@ -2476,7 +2560,7 @@ COMMAND_HANDLER(handle_load_image_command)
        if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
                command_print(CMD_CTX, "downloaded %" PRIu32 " bytes "
-                               "in %fs (%0.3f kb/s)", image_size,
+                               "in %fs (%0.3f KiB/s)", image_size,
                                duration_elapsed(&bench), duration_kbps(&bench, image_size));
        }
 
@@ -2542,7 +2626,7 @@ COMMAND_HANDLER(handle_dump_image_command)
        if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
                command_print(CMD_CTX,
-                               "dumped %ld bytes in %fs (%0.3f kb/s)", (long)fileio.size,
+                               "dumped %ld bytes in %fs (%0.3f KiB/s)", (long)fileio.size,
                                duration_elapsed(&bench), duration_kbps(&bench, fileio.size));
        }
 
@@ -2598,6 +2682,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
        }
 
        image_size = 0x0;
+       int diffs = 0;
        retval = ERROR_OK;
        for (i = 0; i < image.num_sections; i++)
        {
@@ -2632,7 +2717,10 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
                                /* failed crc checksum, fall back to a binary compare */
                                uint8_t *data;
 
-                               command_print(CMD_CTX, "checksum mismatch - attempting binary compare");
+                               if (diffs == 0)
+                               {
+                                       LOG_ERROR("checksum mismatch - attempting binary compare");
+                               }
 
                                data = (uint8_t*)malloc(buf_cnt);
 
@@ -2653,22 +2741,22 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
                                                if (data[t] != buffer[t])
                                                {
                                                        command_print(CMD_CTX,
-                                                                                 "Verify operation failed address 0x%08x. Was 0x%02x instead of 0x%02x\n",
+                                                                                 "diff %d address 0x%08x. Was 0x%02x instead of 0x%02x",
+                                                                                 diffs,
                                                                                  (unsigned)(t + image.sections[i].base_address),
                                                                                  data[t],
                                                                                  buffer[t]);
-                                                       free(data);
-                                                       free(buffer);
-                                                       retval = ERROR_FAIL;
-                                                       goto done;
-                                               }
-                                               if ((t%16384) == 0)
-                                               {
-                                                       keep_alive();
+                                                       if (diffs++ >= 127)
+                                                       {
+                                                               command_print(CMD_CTX, "More than 128 errors, the rest are not printed.");
+                                                               free(data);
+                                                               free(buffer);
+                                                               goto done;
+                                                       }
                                                }
+                                               keep_alive();
                                        }
                                }
-
                                free(data);
                        }
                } else
@@ -2682,10 +2770,14 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
                image_size += buf_cnt;
        }
 done:
+       if (diffs > 0)
+       {
+               retval = ERROR_FAIL;
+       }
        if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
                command_print(CMD_CTX, "verified %" PRIu32 " bytes "
-                               "in %fs (%0.3f kb/s)", image_size,
+                               "in %fs (%0.3f KiB/s)", image_size,
                                duration_elapsed(&bench), duration_kbps(&bench, image_size));
        }
 
@@ -3139,12 +3231,9 @@ static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        struct command_context *context;
        struct target *target;
 
-       context = Jim_GetAssocData(interp, "context");
-       if (context == NULL)
-       {
-               LOG_ERROR("mem2array: no command context");
-               return JIM_ERR;
-       }
+       context = current_command_context(interp);
+       assert (context != NULL);
+
        target = get_current_target(context);
        if (target == NULL)
        {
@@ -3335,11 +3424,9 @@ static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        struct command_context *context;
        struct target *target;
 
-       context = Jim_GetAssocData(interp, "context");
-       if (context == NULL) {
-               LOG_ERROR("array2mem: no command context");
-               return JIM_ERR;
-       }
+       context = current_command_context(interp);
+       assert (context != NULL);
+
        target = get_current_target(context);
        if (target == NULL) {
                LOG_ERROR("array2mem: no current target");
@@ -3494,22 +3581,6 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
        return JIM_OK;
 }
 
-void target_all_handle_event(enum target_event e)
-{
-       struct target *target;
-
-       LOG_DEBUG("**all*targets: event: %d, %s",
-                          (int)e,
-                          Jim_Nvp_value2name_simple(nvp_target_event, e)->name);
-
-       target = all_targets;
-       while (target) {
-               target_handle_event(target, e);
-               target = target->next;
-       }
-}
-
-
 /* FIX? should we propagate errors here rather than printing them
  * and continuing?
  */
@@ -3909,36 +3980,21 @@ static int jim_target_mw(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        }
 
        struct target *target = Jim_CmdPrivData(goi.interp);
-       uint8_t  target_buf[32];
+       unsigned data_size;
        if (strcasecmp(cmd_name, "mww") == 0) {
-               target_buffer_set_u32(target, target_buf, b);
-               b = 4;
+               data_size = 4;
        }
        else if (strcasecmp(cmd_name, "mwh") == 0) {
-               target_buffer_set_u16(target, target_buf, b);
-               b = 2;
+               data_size = 2;
        }
        else if (strcasecmp(cmd_name, "mwb") == 0) {
-               target_buffer_set_u8(target, target_buf, b);
-               b = 1;
+               data_size = 1;
        } else {
                LOG_ERROR("command '%s' unknown: ", cmd_name);
                return JIM_ERR;
        }
 
-       for (jim_wide x = 0; x < c; x++)
-       {
-               e = target_write_memory(target, a, b, 1, target_buf);
-               if (e != ERROR_OK)
-               {
-                       Jim_SetResult_sprintf(interp,
-                                       "Error writing @ 0x%08x: %d\n", (int)(a), e);
-                       return JIM_ERR;
-               }
-               /* b = width */
-               a = a + b;
-       }
-       return JIM_OK;
+       return (target_fill_mem(target, a, target_write_memory_fast, data_size, b, c) == ERROR_OK) ? JIM_OK : JIM_ERR;
 }
 
 static int jim_target_md(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
@@ -4252,7 +4308,9 @@ static int jim_target_wait_state(Jim_Interp *interp, int argc, Jim_Obj *const *a
  */
 static int jim_target_event_list(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
 {
-       struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert (cmd_ctx != NULL);
+
        struct target *target = Jim_CmdPrivData(interp);
        struct target_event_action *teap = target->event_action;
        command_print(cmd_ctx, "Event actions for target (%d) %s\n",
@@ -4446,7 +4504,9 @@ static int target_create(Jim_GetOptInfo *goi)
        struct target *target;
        struct command_context *cmd_ctx;
 
-       cmd_ctx = Jim_GetAssocData(goi->interp, "context");
+       cmd_ctx = current_command_context(goi->interp);
+       assert (cmd_ctx != NULL);
+
        if (goi->argc < 3) {
                Jim_WrongNumArgs(goi->interp, 1, goi->argv, "?name? ?type? ..options...");
                return JIM_ERR;
@@ -4620,7 +4680,9 @@ static int jim_target_current(Jim_Interp *interp, int argc, Jim_Obj *const *argv
                Jim_WrongNumArgs(interp, 1, argv, "Too many parameters");
                return JIM_ERR;
        }
-       struct command_context *cmd_ctx = Jim_GetAssocData(interp, "context");
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert (cmd_ctx != NULL);
+
        Jim_SetResultString(interp, get_current_target(cmd_ctx)->cmd_name, -1);
        return JIM_OK;
 }
@@ -4895,7 +4957,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
        if ((ERROR_OK == retval) && (duration_measure(&bench) == ERROR_OK))
        {
                command_print(CMD_CTX, "Loaded %" PRIu32 " bytes "
-                               "in %fs (%0.3f kb/s)", image_size, 
+                               "in %fs (%0.3f KiB/s)", image_size,
                                duration_elapsed(&bench), duration_kbps(&bench, image_size));
 
                command_print(CMD_CTX,
@@ -5192,7 +5254,7 @@ static const struct command_registration target_exec_command_handlers[] = {
        },
        COMMAND_REGISTRATION_DONE
 };
-int target_register_user_commands(struct command_context *cmd_ctx)
+static int target_register_user_commands(struct command_context *cmd_ctx)
 {
        int retval = ERROR_OK;
        if ((retval = target_request_register_commands(cmd_ctx)) != ERROR_OK)