target: fix clang static analyzer warning
[openocd.git] / src / target / target.c
index 1879430a879119f0c01504eeedca79a90d0b7e62..8a451883ba4ccdedca12408cd655ca2c51e61b6a 100644 (file)
@@ -41,6 +41,7 @@
 #include "config.h"
 #endif
 
+#include <helper/align.h>
 #include <helper/time_support.h>
 #include <jtag/jtag.h>
 #include <flash/nor/core.h>
@@ -55,6 +56,7 @@
 #include "rtos/rtos.h"
 #include "transport/transport.h"
 #include "arm_cti.h"
+#include "smp.h"
 
 /* default halt wait timeout (ms) */
 #define DEFAULT_HALT_TIMEOUT 5000
@@ -154,9 +156,11 @@ static struct target_type *target_types[] = {
 struct target *all_targets;
 static struct target_event_callback *target_event_callbacks;
 static struct target_timer_callback *target_timer_callbacks;
+static int64_t target_timer_next_event_value;
 static LIST_HEAD(target_reset_callback_list);
 static LIST_HEAD(target_trace_callback_list);
-static const int polling_interval = 100;
+static const int polling_interval = TARGET_DEFAULT_POLLING_INTERVAL;
+static LIST_HEAD(empty_smp_targets);
 
 static const struct jim_nvp nvp_assert[] = {
        { .name = "assert", NVP_ASSERT },
@@ -234,6 +238,15 @@ static const struct jim_nvp nvp_target_event[] = {
 
        { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
 
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" },
+
        { .name = NULL, .value = -1 }
 };
 
@@ -484,7 +497,7 @@ struct target *get_target(const char *id)
 
        /* try as tcltarget name */
        for (target = all_targets; target; target = target->next) {
-               if (target_name(target) == NULL)
+               if (!target_name(target))
                        continue;
                if (strcmp(id, target_name(target)) == 0)
                        return target;
@@ -715,6 +728,15 @@ static int no_mmu(struct target *target, int *enabled)
        return ERROR_OK;
 }
 
+/**
+ * Reset the @c examined flag for the given target.
+ * Pure paranoia -- targets are zeroed on allocation.
+ */
+static inline void target_reset_examined(struct target *target)
+{
+       target->examined = false;
+}
+
 static int default_examine(struct target *target)
 {
        target_set_examined(target);
@@ -735,10 +757,12 @@ int target_examine_one(struct target *target)
 
        int retval = target->type->examine(target);
        if (retval != ERROR_OK) {
+               target_reset_examined(target);
                target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_FAIL);
                return retval;
        }
 
+       target_set_examined(target);
        target_call_event_callbacks(target, TARGET_EVENT_EXAMINE_END);
 
        return ERROR_OK;
@@ -826,7 +850,7 @@ static int target_soft_reset_halt(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,
+               target_addr_t entry_point, target_addr_t exit_point,
                int timeout_ms, void *arch_info)
 {
        int retval = ERROR_FAIL;
@@ -867,7 +891,7 @@ done:
 int target_start_algorithm(struct target *target,
                int num_mem_params, struct mem_param *mem_params,
                int num_reg_params, struct reg_param *reg_params,
-               uint32_t entry_point, uint32_t exit_point,
+               target_addr_t entry_point, target_addr_t exit_point,
                void *arch_info)
 {
        int retval = ERROR_FAIL;
@@ -911,7 +935,7 @@ done:
 int target_wait_algorithm(struct target *target,
                int num_mem_params, struct mem_param *mem_params,
                int num_reg_params, struct reg_param *reg_params,
-               uint32_t exit_point, int timeout_ms,
+               target_addr_t exit_point, int timeout_ms,
                void *arch_info)
 {
        int retval = ERROR_FAIL;
@@ -1003,7 +1027,7 @@ int target_run_flash_async_algorithm(struct target *target,
        uint32_t rp = fifo_start_addr;
 
        /* validate block_size is 2^n */
-       assert(!block_size || !(block_size & (block_size - 1)));
+       assert(IS_PWR_OF_2(block_size));
 
        retval = target_write_u32(target, wp_addr, wp);
        if (retval != ERROR_OK)
@@ -1041,7 +1065,7 @@ int target_run_flash_async_algorithm(struct target *target,
                        break;
                }
 
-               if (((rp - fifo_start_addr) & (block_size - 1)) || rp < fifo_start_addr || rp >= fifo_end_addr) {
+               if (!IS_ALIGNED(rp - fifo_start_addr, block_size) || rp < fifo_start_addr || rp >= fifo_end_addr) {
                        LOG_ERROR("corrupted fifo read pointer 0x%" PRIx32, rp);
                        break;
                }
@@ -1156,7 +1180,7 @@ int target_run_read_async_algorithm(struct target *target,
        uint32_t rp = fifo_start_addr;
 
        /* validate block_size is 2^n */
-       assert(!block_size || !(block_size & (block_size - 1)));
+       assert(IS_PWR_OF_2(block_size));
 
        retval = target_write_u32(target, wp_addr, wp);
        if (retval != ERROR_OK)
@@ -1193,7 +1217,7 @@ int target_run_read_async_algorithm(struct target *target,
                        break;
                }
 
-               if (((wp - fifo_start_addr) & (block_size - 1)) || wp < fifo_start_addr || wp >= fifo_end_addr) {
+               if (!IS_ALIGNED(wp - fifo_start_addr, block_size) || wp < fifo_start_addr || wp >= fifo_end_addr) {
                        LOG_ERROR("corrupted fifo write pointer 0x%" PRIx32, wp);
                        break;
                }
@@ -1520,15 +1544,6 @@ static int target_profiling(struct target *target, uint32_t *samples,
                        num_samples, seconds);
 }
 
-/**
- * Reset the @c examined flag for the given target.
- * Pure paranoia -- targets are zeroed on allocation.
- */
-static void target_reset_examined(struct target *target)
-{
-       target->examined = false;
-}
-
 static int handle_target(void *priv);
 
 static int target_init_one(struct command_context *cmd_ctx,
@@ -1733,8 +1748,8 @@ int target_register_timer_callback(int (*callback)(void *priv),
        (*callbacks_p)->time_ms = time_ms;
        (*callbacks_p)->removed = false;
 
-       gettimeofday(&(*callbacks_p)->when, NULL);
-       timeval_add_time(&(*callbacks_p)->when, 0, time_ms * 1000);
+       (*callbacks_p)->when = timeval_ms() + time_ms;
+       target_timer_next_event_value = MIN(target_timer_next_event_value, (*callbacks_p)->when);
 
        (*callbacks_p)->priv = priv;
        (*callbacks_p)->next = NULL;
@@ -1830,7 +1845,7 @@ int target_call_event_callbacks(struct target *target, enum target_event event)
        }
 
        LOG_DEBUG("target event %i (%s) for core %s", event,
-                       jim_nvp_value2name_simple(nvp_target_event, event)->name,
+                       target_event_name(event),
                        target_name(target));
 
        target_handle_event(target, event);
@@ -1868,15 +1883,14 @@ int target_call_trace_callbacks(struct target *target, size_t len, uint8_t *data
 }
 
 static int target_timer_callback_periodic_restart(
-               struct target_timer_callback *cb, struct timeval *now)
+               struct target_timer_callback *cb, int64_t *now)
 {
-       cb->when = *now;
-       timeval_add_time(&cb->when, 0, cb->time_ms * 1000L);
+       cb->when = *now + cb->time_ms;
        return ERROR_OK;
 }
 
 static int target_call_timer_callback(struct target_timer_callback *cb,
-               struct timeval *now)
+               int64_t *now)
 {
        cb->callback(cb->priv);
 
@@ -1898,8 +1912,12 @@ static int target_call_timer_callbacks_check_time(int checktime)
 
        keep_alive();
 
-       struct timeval now;
-       gettimeofday(&now, NULL);
+       int64_t now = timeval_ms();
+
+       /* Initialize to a default value that's a ways into the future.
+        * The loop below will make it closer to now if there are
+        * callbacks that want to be called sooner. */
+       target_timer_next_event_value = now + 1000;
 
        /* Store an address of the place containing a pointer to the
         * next item; initially, that's a standalone "root of the
@@ -1915,11 +1933,14 @@ static int target_call_timer_callbacks_check_time(int checktime)
 
                bool call_it = (*callback)->callback &&
                        ((!checktime && (*callback)->type == TARGET_TIMER_TYPE_PERIODIC) ||
-                        timeval_compare(&now, &(*callback)->when) >= 0);
+                        now >= (*callback)->when);
 
                if (call_it)
                        target_call_timer_callback(*callback, &now);
 
+               if (!(*callback)->removed && (*callback)->when < target_timer_next_event_value)
+                       target_timer_next_event_value = (*callback)->when;
+
                callback = &(*callback)->next;
        }
 
@@ -1927,17 +1948,22 @@ static int target_call_timer_callbacks_check_time(int checktime)
        return ERROR_OK;
 }
 
-int target_call_timer_callbacks(void)
+int target_call_timer_callbacks()
 {
        return target_call_timer_callbacks_check_time(1);
 }
 
 /* invoke periodic callbacks immediately */
-int target_call_timer_callbacks_now(void)
+int target_call_timer_callbacks_now()
 {
        return target_call_timer_callbacks_check_time(0);
 }
 
+int64_t target_timer_next_event(void)
+{
+       return target_timer_next_event_value;
+}
+
 /* Prints the working area layout for debug purposes */
 static void print_wa_layout(struct target *target)
 {
@@ -2133,11 +2159,10 @@ static int target_restore_working_area(struct target *target, struct working_are
 /* Restore the area's backup memory, if any, and return the area to the allocation pool */
 static int target_free_working_area_restore(struct target *target, struct working_area *area, int restore)
 {
-       int retval = ERROR_OK;
-
-       if (area->free)
-               return retval;
+       if (!area || area->free)
+               return ERROR_OK;
 
+       int retval = ERROR_OK;
        if (restore) {
                retval = target_restore_working_area(target, area);
                /* REVISIT: Perhaps the area should be freed even if restoring fails. */
@@ -2249,13 +2274,15 @@ static void target_destroy(struct target *target)
 
        /* release the targets SMP list */
        if (target->smp) {
-               struct target_list *head = target->head;
-               while (head) {
-                       struct target_list *pos = head->next;
+               struct target_list *head, *tmp;
+
+               list_for_each_entry_safe(head, tmp, target->smp_targets, lh) {
+                       list_del(&head->lh);
                        head->target->smp = 0;
                        free(head);
-                       head = pos;
                }
+               if (target->smp_targets != &empty_smp_targets)
+                       free(target->smp_targets);
                target->smp = 0;
        }
 
@@ -2516,6 +2543,10 @@ int target_checksum_memory(struct target *target, target_addr_t address, uint32_
                LOG_ERROR("Target not examined yet");
                return ERROR_FAIL;
        }
+       if (!target->type->checksum_memory) {
+               LOG_ERROR("Target %s doesn't support checksum_memory", target_name(target));
+               return ERROR_FAIL;
+       }
 
        retval = target->type->checksum_memory(target, address, size, &checksum);
        if (retval != ERROR_OK) {
@@ -3042,7 +3073,7 @@ static int handle_target(void *priv)
                                /* Target examination could have failed due to unstable connection,
                                 * but we set the examined flag anyway to repoll it later */
                                if (retval != ERROR_OK) {
-                                       target->examined = true;
+                                       target_set_examined(target);
                                        LOG_USER("Examination failed, GDB will be halted. Polling again in %dms",
                                                 target->backoff.times * polling_interval);
                                        return retval;
@@ -3936,26 +3967,26 @@ static int handle_bp_command_list(struct command_invocation *cmd)
                if (breakpoint->type == BKPT_SOFT) {
                        char *buf = buf_to_hex_str(breakpoint->orig_instr,
                                        breakpoint->length);
-                       command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, %i, 0x%s",
+                       command_print(cmd, "IVA breakpoint: " TARGET_ADDR_FMT ", 0x%x, 0x%s",
                                        breakpoint->address,
                                        breakpoint->length,
-                                       breakpoint->set, buf);
+                                       buf);
                        free(buf);
                } else {
                        if ((breakpoint->address == 0) && (breakpoint->asid != 0))
-                               command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %i",
+                               command_print(cmd, "Context breakpoint: 0x%8.8" PRIx32 ", 0x%x, %u",
                                                        breakpoint->asid,
-                                                       breakpoint->length, breakpoint->set);
+                                                       breakpoint->length, breakpoint->number);
                        else if ((breakpoint->address != 0) && (breakpoint->asid != 0)) {
-                               command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i",
+                               command_print(cmd, "Hybrid breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u",
                                                        breakpoint->address,
-                                                       breakpoint->length, breakpoint->set);
+                                                       breakpoint->length, breakpoint->number);
                                command_print(cmd, "\t|--->linked with ContextID: 0x%8.8" PRIx32,
                                                        breakpoint->asid);
                        } else
-                               command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %i",
+                               command_print(cmd, "Breakpoint(IVA): " TARGET_ADDR_FMT ", 0x%x, %u",
                                                        breakpoint->address,
-                                                       breakpoint->length, breakpoint->set);
+                                                       breakpoint->length, breakpoint->number);
                }
 
                breakpoint = breakpoint->next;
@@ -4400,27 +4431,12 @@ static int new_u64_array_element(Jim_Interp *interp, const char *varname, int id
        return result;
 }
 
-static int jim_mem2array(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-       struct command_context *context;
-       struct target *target;
-
-       context = current_command_context(interp);
-       assert(context);
-
-       target = get_current_target(context);
-       if (!target) {
-               LOG_ERROR("mem2array: no current target");
-               return JIM_ERR;
-       }
-
-       return target_mem2array(interp, target, argc - 1, argv + 1);
-}
-
 static int target_mem2array(Jim_Interp *interp, struct target *target, int argc, Jim_Obj *const *argv)
 {
        int e;
 
+       LOG_WARNING("DEPRECATED! use 'read_memory' not 'mem2array'");
+
        /* argv[0] = name of array to receive the data
         * argv[1] = desired element width in bits
         * argv[2] = memory address
@@ -4573,6 +4589,161 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
        return e;
 }
 
+static int target_jim_read_memory(Jim_Interp *interp, int argc,
+               Jim_Obj * const *argv)
+{
+       /*
+        * argv[1] = memory address
+        * argv[2] = desired element width in bits
+        * argv[3] = number of elements to read
+        * argv[4] = optional "phys"
+        */
+
+       if (argc < 4 || argc > 5) {
+               Jim_WrongNumArgs(interp, 1, argv, "address width count ['phys']");
+               return JIM_ERR;
+       }
+
+       /* Arg 1: Memory address. */
+       jim_wide wide_addr;
+       int e;
+       e = Jim_GetWide(interp, argv[1], &wide_addr);
+
+       if (e != JIM_OK)
+               return e;
+
+       target_addr_t addr = (target_addr_t)wide_addr;
+
+       /* Arg 2: Bit width of one element. */
+       long l;
+       e = Jim_GetLong(interp, argv[2], &l);
+
+       if (e != JIM_OK)
+               return e;
+
+       const unsigned int width_bits = l;
+
+       /* Arg 3: Number of elements to read. */
+       e = Jim_GetLong(interp, argv[3], &l);
+
+       if (e != JIM_OK)
+               return e;
+
+       size_t count = l;
+
+       /* Arg 4: Optional 'phys'. */
+       bool is_phys = false;
+
+       if (argc > 4) {
+               const char *phys = Jim_GetString(argv[4], NULL);
+
+               if (strcmp(phys, "phys")) {
+                       Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys);
+                       return JIM_ERR;
+               }
+
+               is_phys = true;
+       }
+
+       switch (width_bits) {
+       case 8:
+       case 16:
+       case 32:
+       case 64:
+               break;
+       default:
+               Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1);
+               return JIM_ERR;
+       }
+
+       const unsigned int width = width_bits / 8;
+
+       if ((addr + (count * width)) < addr) {
+               Jim_SetResultString(interp, "read_memory: addr + count wraps to zero", -1);
+               return JIM_ERR;
+       }
+
+       if (count > 65536) {
+               Jim_SetResultString(interp, "read_memory: too large read request, exeeds 64K elements", -1);
+               return JIM_ERR;
+       }
+
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert(cmd_ctx != NULL);
+       struct target *target = get_current_target(cmd_ctx);
+
+       const size_t buffersize = 4096;
+       uint8_t *buffer = malloc(buffersize);
+
+       if (!buffer) {
+               LOG_ERROR("Failed to allocate memory");
+               return JIM_ERR;
+       }
+
+       Jim_Obj *result_list = Jim_NewListObj(interp, NULL, 0);
+       Jim_IncrRefCount(result_list);
+
+       while (count > 0) {
+               const unsigned int max_chunk_len = buffersize / width;
+               const size_t chunk_len = MIN(count, max_chunk_len);
+
+               int retval;
+
+               if (is_phys)
+                       retval = target_read_phys_memory(target, addr, width, chunk_len, buffer);
+               else
+                       retval = target_read_memory(target, addr, width, chunk_len, buffer);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("read_memory: read at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
+                               addr, width_bits, chunk_len);
+                       Jim_SetResultString(interp, "read_memory: failed to read memory", -1);
+                       e = JIM_ERR;
+                       break;
+               }
+
+               for (size_t i = 0; i < chunk_len ; i++) {
+                       uint64_t v = 0;
+
+                       switch (width) {
+                       case 8:
+                               v = target_buffer_get_u64(target, &buffer[i * width]);
+                               break;
+                       case 4:
+                               v = target_buffer_get_u32(target, &buffer[i * width]);
+                               break;
+                       case 2:
+                               v = target_buffer_get_u16(target, &buffer[i * width]);
+                               break;
+                       case 1:
+                               v = buffer[i];
+                               break;
+                       }
+
+                       char value_buf[11];
+                       snprintf(value_buf, sizeof(value_buf), "0x%" PRIx64, v);
+
+                       Jim_ListAppendElement(interp, result_list,
+                               Jim_NewStringObj(interp, value_buf, -1));
+               }
+
+               count -= chunk_len;
+               addr += chunk_len * width;
+       }
+
+       free(buffer);
+
+       if (e != JIM_OK) {
+               Jim_DecrRefCount(interp, result_list);
+               return e;
+       }
+
+       Jim_SetResult(interp, result_list);
+       Jim_DecrRefCount(interp, result_list);
+
+       return JIM_OK;
+}
+
 static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t idx, uint64_t *val)
 {
        char *namebuf = alloc_printf("%s(%zu)", varname, idx);
@@ -4598,28 +4769,13 @@ static int get_u64_array_element(Jim_Interp *interp, const char *varname, size_t
        return result;
 }
 
-static int jim_array2mem(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
-{
-       struct command_context *context;
-       struct target *target;
-
-       context = current_command_context(interp);
-       assert(context);
-
-       target = get_current_target(context);
-       if (!target) {
-               LOG_ERROR("array2mem: no current target");
-               return JIM_ERR;
-       }
-
-       return target_array2mem(interp, target, argc-1, argv + 1);
-}
-
 static int target_array2mem(Jim_Interp *interp, struct target *target,
                int argc, Jim_Obj *const *argv)
 {
        int e;
 
+       LOG_WARNING("DEPRECATED! use 'write_memory' not 'array2mem'");
+
        /* argv[0] = name of array from which to read the data
         * argv[1] = desired element width in bits
         * argv[2] = memory address
@@ -4783,6 +4939,144 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
        return e;
 }
 
+static int target_jim_write_memory(Jim_Interp *interp, int argc,
+               Jim_Obj * const *argv)
+{
+       /*
+        * argv[1] = memory address
+        * argv[2] = desired element width in bits
+        * argv[3] = list of data to write
+        * argv[4] = optional "phys"
+        */
+
+       if (argc < 4 || argc > 5) {
+               Jim_WrongNumArgs(interp, 1, argv, "address width data ['phys']");
+               return JIM_ERR;
+       }
+
+       /* Arg 1: Memory address. */
+       int e;
+       jim_wide wide_addr;
+       e = Jim_GetWide(interp, argv[1], &wide_addr);
+
+       if (e != JIM_OK)
+               return e;
+
+       target_addr_t addr = (target_addr_t)wide_addr;
+
+       /* Arg 2: Bit width of one element. */
+       long l;
+       e = Jim_GetLong(interp, argv[2], &l);
+
+       if (e != JIM_OK)
+               return e;
+
+       const unsigned int width_bits = l;
+       size_t count = Jim_ListLength(interp, argv[3]);
+
+       /* Arg 4: Optional 'phys'. */
+       bool is_phys = false;
+
+       if (argc > 4) {
+               const char *phys = Jim_GetString(argv[4], NULL);
+
+               if (strcmp(phys, "phys")) {
+                       Jim_SetResultFormatted(interp, "invalid argument '%s', must be 'phys'", phys);
+                       return JIM_ERR;
+               }
+
+               is_phys = true;
+       }
+
+       switch (width_bits) {
+       case 8:
+       case 16:
+       case 32:
+       case 64:
+               break;
+       default:
+               Jim_SetResultString(interp, "invalid width, must be 8, 16, 32 or 64", -1);
+               return JIM_ERR;
+       }
+
+       const unsigned int width = width_bits / 8;
+
+       if ((addr + (count * width)) < addr) {
+               Jim_SetResultString(interp, "write_memory: addr + len wraps to zero", -1);
+               return JIM_ERR;
+       }
+
+       if (count > 65536) {
+               Jim_SetResultString(interp, "write_memory: too large memory write request, exceeds 64K elements", -1);
+               return JIM_ERR;
+       }
+
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert(cmd_ctx != NULL);
+       struct target *target = get_current_target(cmd_ctx);
+
+       const size_t buffersize = 4096;
+       uint8_t *buffer = malloc(buffersize);
+
+       if (!buffer) {
+               LOG_ERROR("Failed to allocate memory");
+               return JIM_ERR;
+       }
+
+       size_t j = 0;
+
+       while (count > 0) {
+               const unsigned int max_chunk_len = buffersize / width;
+               const size_t chunk_len = MIN(count, max_chunk_len);
+
+               for (size_t i = 0; i < chunk_len; i++, j++) {
+                       Jim_Obj *tmp = Jim_ListGetIndex(interp, argv[3], j);
+                       jim_wide element_wide;
+                       Jim_GetWide(interp, tmp, &element_wide);
+
+                       const uint64_t v = element_wide;
+
+                       switch (width) {
+                       case 8:
+                               target_buffer_set_u64(target, &buffer[i * width], v);
+                               break;
+                       case 4:
+                               target_buffer_set_u32(target, &buffer[i * width], v);
+                               break;
+                       case 2:
+                               target_buffer_set_u16(target, &buffer[i * width], v);
+                               break;
+                       case 1:
+                               buffer[i] = v & 0x0ff;
+                               break;
+                       }
+               }
+
+               count -= chunk_len;
+
+               int retval;
+
+               if (is_phys)
+                       retval = target_write_phys_memory(target, addr, width, chunk_len, buffer);
+               else
+                       retval = target_write_memory(target, addr, width, chunk_len, buffer);
+
+               if (retval != ERROR_OK) {
+                       LOG_ERROR("write_memory: write at " TARGET_ADDR_FMT " with width=%u and count=%zu failed",
+                               addr,  width_bits, chunk_len);
+                       Jim_SetResultString(interp, "write_memory: failed to write memory", -1);
+                       e = JIM_ERR;
+                       break;
+               }
+
+               addr += chunk_len * width;
+       }
+
+       free(buffer);
+
+       return e;
+}
+
 /* FIX? should we propagate errors here rather than printing them
  * and continuing?
  */
@@ -4798,7 +5092,7 @@ void target_handle_event(struct target *target, enum target_event e)
                                           target_name(target),
                                           target_type_name(target),
                                           e,
-                                          jim_nvp_value2name_simple(nvp_target_event, e)->name,
+                                          target_event_name(e),
                                           Jim_GetString(teap->body, NULL));
 
                        /* Override current target by the target an event
@@ -4822,7 +5116,7 @@ void target_handle_event(struct target *target, enum target_event e)
                        if (retval != JIM_OK) {
                                Jim_MakeErrorMessage(teap->interp);
                                LOG_USER("Error executing event %s on target %s:\n%s",
-                                                 jim_nvp_value2name_simple(nvp_target_event, e)->name,
+                                                 target_event_name(e),
                                                  target_name(target),
                                                  Jim_GetString(Jim_GetResult(teap->interp), NULL));
                                /* clean both error code and stacktrace before return */
@@ -4832,6 +5126,152 @@ void target_handle_event(struct target *target, enum target_event e)
        }
 }
 
+static int target_jim_get_reg(Jim_Interp *interp, int argc,
+               Jim_Obj * const *argv)
+{
+       bool force = false;
+
+       if (argc == 3) {
+               const char *option = Jim_GetString(argv[1], NULL);
+
+               if (!strcmp(option, "-force")) {
+                       argc--;
+                       argv++;
+                       force = true;
+               } else {
+                       Jim_SetResultFormatted(interp, "invalid option '%s'", option);
+                       return JIM_ERR;
+               }
+       }
+
+       if (argc != 2) {
+               Jim_WrongNumArgs(interp, 1, argv, "[-force] list");
+               return JIM_ERR;
+       }
+
+       const int length = Jim_ListLength(interp, argv[1]);
+
+       Jim_Obj *result_dict = Jim_NewDictObj(interp, NULL, 0);
+
+       if (!result_dict)
+               return JIM_ERR;
+
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert(cmd_ctx != NULL);
+       const struct target *target = get_current_target(cmd_ctx);
+
+       for (int i = 0; i < length; i++) {
+               Jim_Obj *elem = Jim_ListGetIndex(interp, argv[1], i);
+
+               if (!elem)
+                       return JIM_ERR;
+
+               const char *reg_name = Jim_String(elem);
+
+               struct reg *reg = register_get_by_name(target->reg_cache, reg_name,
+                       false);
+
+               if (!reg || !reg->exist) {
+                       Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name);
+                       return JIM_ERR;
+               }
+
+               if (force) {
+                       int retval = reg->type->get(reg);
+
+                       if (retval != ERROR_OK) {
+                               Jim_SetResultFormatted(interp, "failed to read register '%s'",
+                                       reg_name);
+                               return JIM_ERR;
+                       }
+               }
+
+               char *reg_value = buf_to_hex_str(reg->value, reg->size);
+
+               if (!reg_value) {
+                       LOG_ERROR("Failed to allocate memory");
+                       return JIM_ERR;
+               }
+
+               char *tmp = alloc_printf("0x%s", reg_value);
+
+               free(reg_value);
+
+               if (!tmp) {
+                       LOG_ERROR("Failed to allocate memory");
+                       return JIM_ERR;
+               }
+
+               Jim_DictAddElement(interp, result_dict, elem,
+                       Jim_NewStringObj(interp, tmp, -1));
+
+               free(tmp);
+       }
+
+       Jim_SetResult(interp, result_dict);
+
+       return JIM_OK;
+}
+
+static int target_jim_set_reg(Jim_Interp *interp, int argc,
+               Jim_Obj * const *argv)
+{
+       if (argc != 2) {
+               Jim_WrongNumArgs(interp, 1, argv, "dict");
+               return JIM_ERR;
+       }
+
+       int tmp;
+#if JIM_VERSION >= 80
+       Jim_Obj **dict = Jim_DictPairs(interp, argv[1], &tmp);
+
+       if (!dict)
+               return JIM_ERR;
+#else
+       Jim_Obj **dict;
+       int ret = Jim_DictPairs(interp, argv[1], &dict, &tmp);
+
+       if (ret != JIM_OK)
+               return ret;
+#endif
+
+       const unsigned int length = tmp;
+       struct command_context *cmd_ctx = current_command_context(interp);
+       assert(cmd_ctx);
+       const struct target *target = get_current_target(cmd_ctx);
+
+       for (unsigned int i = 0; i < length; i += 2) {
+               const char *reg_name = Jim_String(dict[i]);
+               const char *reg_value = Jim_String(dict[i + 1]);
+               struct reg *reg = register_get_by_name(target->reg_cache, reg_name,
+                       false);
+
+               if (!reg || !reg->exist) {
+                       Jim_SetResultFormatted(interp, "unknown register '%s'", reg_name);
+                       return JIM_ERR;
+               }
+
+               uint8_t *buf = malloc(DIV_ROUND_UP(reg->size, 8));
+
+               if (!buf) {
+                       LOG_ERROR("Failed to allocate memory");
+                       return JIM_ERR;
+               }
+
+               str_to_buf(reg_value, strlen(reg_value), buf, reg->size, 0);
+               int retval = reg->type->set(reg, buf);
+               free(buf);
+
+               if (retval != ERROR_OK) {
+                       Jim_SetResultFormatted(interp, "failed to set '%s' to register '%s'",
+                               reg_value, reg_name);
+                       return JIM_ERR;
+               }
+       }
+
+       return JIM_OK;
+}
+
 /**
  * Returns true only if the target has a handler for the specified event.
  */
@@ -4970,7 +5410,7 @@ no_params:
                                if (goi->isconfigure) {
                                        /* START_DEPRECATED_TPIU */
                                        if (n->value == TARGET_EVENT_TRACE_CONFIG)
-                                               LOG_INFO("DEPRECATED target event %s", n->name);
+                                               LOG_INFO("DEPRECATED target event %s; use TPIU events {pre,post}-{enable,disable}", n->name);
                                        /* END_DEPRECATED_TPIU */
 
                                        bool replace = true;
@@ -5295,8 +5735,13 @@ static int jim_target_examine(Jim_Interp *interp, int argc, Jim_Obj *const *argv
        }
 
        int e = target->type->examine(target);
-       if (e != ERROR_OK)
+       if (e != ERROR_OK) {
+               target_reset_examined(target);
                return JIM_ERR;
+       }
+
+       target_set_examined(target);
+
        return JIM_OK;
 }
 
@@ -5480,9 +5925,9 @@ COMMAND_HANDLER(handle_target_event_list)
        command_print(CMD, "------------------------- | "
                        "----------------------------------------");
        while (teap) {
-               struct jim_nvp *opt = jim_nvp_value2name_simple(nvp_target_event, teap->event);
                command_print(CMD, "%-25s | %s",
-                               opt->name, Jim_GetString(teap->body, NULL));
+                               target_event_name(teap->event),
+                               Jim_GetString(teap->body, NULL));
                teap = teap->next;
        }
        command_print(CMD, "***END***");
@@ -5609,6 +6054,34 @@ static const struct command_registration target_instance_command_handlers[] = {
                        "from target memory",
                .usage = "arrayname bitwidth address count",
        },
+       {
+               .name = "get_reg",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_get_reg,
+               .help = "Get register values from the target",
+               .usage = "list",
+       },
+       {
+               .name = "set_reg",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_set_reg,
+               .help = "Set target register values",
+               .usage = "dict",
+       },
+       {
+               .name = "read_memory",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_read_memory,
+               .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory",
+               .usage = "address width count ['phys']",
+       },
+       {
+               .name = "write_memory",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_write_memory,
+               .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory",
+               .usage = "address width data ['phys']",
+       },
        {
                .name = "eventlist",
                .handler = handle_target_event_list,
@@ -5702,7 +6175,7 @@ static int target_create(struct jim_getopt_info *goi)
        /* COMMAND */
        jim_getopt_obj(goi, &new_cmd);
        /* does this command exist? */
-       cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_ERRMSG);
+       cmd = Jim_GetCommand(goi->interp, new_cmd, JIM_NONE);
        if (cmd) {
                cp = Jim_GetString(new_cmd, NULL);
                Jim_SetResultFormatted(goi->interp, "Command/target: %s Exists", cp);
@@ -5724,7 +6197,7 @@ static int target_create(struct jim_getopt_info *goi)
        }
        /* now does target type exist */
        for (x = 0 ; target_types[x] ; x++) {
-               if (0 == strcmp(cp, target_types[x]->name)) {
+               if (strcmp(cp, target_types[x]->name) == 0) {
                        /* found */
                        break;
                }
@@ -5754,6 +6227,9 @@ static int target_create(struct jim_getopt_info *goi)
                return JIM_ERR;
        }
 
+       /* set empty smp cluster */
+       target->smp_targets = &empty_smp_targets;
+
        /* set target number */
        target->target_number = new_target_number();
 
@@ -5965,10 +6441,8 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
        int i;
        const char *targetname;
        int retval, len;
-       struct target *target = (struct target *) NULL;
-       struct target_list *head, *curr, *new;
-       curr = (struct target_list *) NULL;
-       head = (struct target_list *) NULL;
+       struct target *target = NULL;
+       struct target_list *head, *new;
 
        retval = 0;
        LOG_DEBUG("%d", argc);
@@ -5977,6 +6451,13 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
         * argv[3] ...
         */
 
+       struct list_head *lh = malloc(sizeof(*lh));
+       if (!lh) {
+               LOG_ERROR("Out of memory");
+               return JIM_ERR;
+       }
+       INIT_LIST_HEAD(lh);
+
        for (i = 1; i < argc; i++) {
 
                targetname = Jim_GetString(argv[i], &len);
@@ -5985,28 +6466,18 @@ static int jim_target_smp(Jim_Interp *interp, int argc, Jim_Obj *const *argv)
                if (target) {
                        new = malloc(sizeof(struct target_list));
                        new->target = target;
-                       new->next = (struct target_list *)NULL;
-                       if (head == (struct target_list *)NULL) {
-                               head = new;
-                               curr = head;
-                       } else {
-                               curr->next = new;
-                               curr = new;
-                       }
+                       list_add_tail(&new->lh, lh);
                }
        }
        /*  now parse the list of cpu and put the target in smp mode*/
-       curr = head;
-
-       while (curr != (struct target_list *)NULL) {
-               target = curr->target;
+       foreach_smp_target(head, lh) {
+               target = head->target;
                target->smp = 1;
-               target->head = head;
-               curr = curr->next;
+               target->smp_targets = lh;
        }
 
        if (target && target->rtos)
-               retval = rtos_smp_init(head->target);
+               retval = rtos_smp_init(target);
 
        return retval;
 }
@@ -6381,8 +6852,7 @@ next:
 out:
        free(test_pattern);
 
-       if (wa)
-               target_free_working_area(target, wa);
+       target_free_working_area(target, wa);
 
        /* Test writes */
        num_bytes = test_size + 4 + 4 + 4;
@@ -6466,8 +6936,7 @@ nextw:
 
        free(test_pattern);
 
-       if (wa)
-               target_free_working_area(target, wa);
+       target_free_working_area(target, wa);
        return retval;
 }
 
@@ -6680,20 +7149,32 @@ static const struct command_registration target_exec_command_handlers[] = {
                .usage = "filename [offset [type]]",
        },
        {
-               .name = "mem2array",
+               .name = "get_reg",
                .mode = COMMAND_EXEC,
-               .jim_handler = jim_mem2array,
-               .help = "read 8/16/32 bit memory and return as a TCL array "
-                       "for script processing",
-               .usage = "arrayname bitwidth address count",
+               .jim_handler = target_jim_get_reg,
+               .help = "Get register values from the target",
+               .usage = "list",
        },
        {
-               .name = "array2mem",
+               .name = "set_reg",
                .mode = COMMAND_EXEC,
-               .jim_handler = jim_array2mem,
-               .help = "convert a TCL array to memory locations "
-                       "and write the 8/16/32 bit values",
-               .usage = "arrayname bitwidth address count",
+               .jim_handler = target_jim_set_reg,
+               .help = "Set target register values",
+               .usage = "dict",
+       },
+       {
+               .name = "read_memory",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_read_memory,
+               .help = "Read Tcl list of 8/16/32/64 bit numbers from target memory",
+               .usage = "address width count ['phys']",
+       },
+       {
+               .name = "write_memory",
+               .mode = COMMAND_EXEC,
+               .jim_handler = target_jim_write_memory,
+               .help = "Write Tcl list of 8/16/32/64 bit numbers to target memory",
+               .usage = "address width data ['phys']",
        },
        {
                .name = "reset_nag",

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)