Allow transports to override the selected target (hla configs unification)
[fw/openocd] / src / target / target.c
index 0eb578828e962f99e7d160ff431b2966c14f443d..92411c8c2399cf77681c5013022aff04dae4a554 100644 (file)
@@ -55,6 +55,7 @@
 #include "trace.h"
 #include "image.h"
 #include "rtos/rtos.h"
+#include "transport/transport.h"
 
 /* default halt wait timeout (ms) */
 #define DEFAULT_HALT_TIMEOUT 5000
@@ -87,8 +88,8 @@ extern struct target_type fa526_target;
 extern struct target_type feroceon_target;
 extern struct target_type dragonite_target;
 extern struct target_type xscale_target;
-extern struct target_type cortexm3_target;
-extern struct target_type cortexa8_target;
+extern struct target_type cortexm_target;
+extern struct target_type cortexa_target;
 extern struct target_type cortexr4_target;
 extern struct target_type arm11_target;
 extern struct target_type mips_m4k_target;
@@ -102,6 +103,7 @@ extern struct target_type nds32_v2_target;
 extern struct target_type nds32_v3_target;
 extern struct target_type nds32_v3m_target;
 extern struct target_type or1k_target;
+extern struct target_type quark_x10xx_target;
 
 static struct target_type *target_types[] = {
        &arm7tdmi_target,
@@ -115,8 +117,8 @@ static struct target_type *target_types[] = {
        &feroceon_target,
        &dragonite_target,
        &xscale_target,
-       &cortexm3_target,
-       &cortexa8_target,
+       &cortexm_target,
+       &cortexa_target,
        &cortexr4_target,
        &arm11_target,
        &mips_m4k_target,
@@ -130,6 +132,7 @@ static struct target_type *target_types[] = {
        &nds32_v3_target,
        &nds32_v3m_target,
        &or1k_target,
+       &quark_x10xx_target,
        NULL,
 };
 
@@ -294,6 +297,15 @@ static int new_target_number(void)
        return x + 1;
 }
 
+/* read a uint64_t from a buffer in target memory endianness */
+uint64_t target_buffer_get_u64(struct target *target, const uint8_t *buffer)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               return le_to_h_u64(buffer);
+       else
+               return be_to_h_u64(buffer);
+}
+
 /* read a uint32_t from a buffer in target memory endianness */
 uint32_t target_buffer_get_u32(struct target *target, const uint8_t *buffer)
 {
@@ -327,6 +339,15 @@ static uint8_t target_buffer_get_u8(struct target *target, const uint8_t *buffer
        return *buffer & 0x0ff;
 }
 
+/* write a uint64_t to a buffer in target memory endianness */
+void target_buffer_set_u64(struct target *target, uint8_t *buffer, uint64_t value)
+{
+       if (target->endianness == TARGET_LITTLE_ENDIAN)
+               h_u64_to_le(buffer, value);
+       else
+               h_u64_to_be(buffer, value);
+}
+
 /* write a uint32_t to a buffer in target memory endianness */
 void target_buffer_set_u32(struct target *target, uint8_t *buffer, uint32_t value)
 {
@@ -360,6 +381,14 @@ static void target_buffer_set_u8(struct target *target, uint8_t *buffer, uint8_t
        *buffer = value;
 }
 
+/* write a uint64_t array to a buffer in target memory endianness */
+void target_buffer_get_u64_array(struct target *target, const uint8_t *buffer, uint32_t count, uint64_t *dstbuf)
+{
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               dstbuf[i] = target_buffer_get_u64(target, &buffer[i * 8]);
+}
+
 /* write a uint32_t array to a buffer in target memory endianness */
 void target_buffer_get_u32_array(struct target *target, const uint8_t *buffer, uint32_t count, uint32_t *dstbuf)
 {
@@ -376,8 +405,16 @@ void target_buffer_get_u16_array(struct target *target, const uint8_t *buffer, u
                dstbuf[i] = target_buffer_get_u16(target, &buffer[i * 2]);
 }
 
+/* write a uint64_t array to a buffer in target memory endianness */
+void target_buffer_set_u64_array(struct target *target, uint8_t *buffer, uint32_t count, const uint64_t *srcbuf)
+{
+       uint32_t i;
+       for (i = 0; i < count; i++)
+               target_buffer_set_u64(target, &buffer[i * 8], srcbuf[i]);
+}
+
 /* write a uint32_t array to a buffer in target memory endianness */
-void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, uint32_t *srcbuf)
+void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_t count, const uint32_t *srcbuf)
 {
        uint32_t i;
        for (i = 0; i < count; i++)
@@ -385,7 +422,7 @@ void target_buffer_set_u32_array(struct target *target, uint8_t *buffer, uint32_
 }
 
 /* write a uint16_t array to a buffer in target memory endianness */
-void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, uint16_t *srcbuf)
+void target_buffer_set_u16_array(struct target *target, uint8_t *buffer, uint32_t count, const uint16_t *srcbuf)
 {
        uint32_t i;
        for (i = 0; i < count; i++)
@@ -817,7 +854,7 @@ done:
  */
 
 int target_run_flash_async_algorithm(struct target *target,
-               uint8_t *buffer, uint32_t count, int block_size,
+               const uint8_t *buffer, uint32_t count, int block_size,
                int num_mem_params, struct mem_param *mem_params,
                int num_reg_params, struct reg_param *reg_params,
                uint32_t buffer_start, uint32_t buffer_size,
@@ -1238,6 +1275,10 @@ COMMAND_HANDLER(handle_target_init_command)
        if (ERROR_OK != retval)
                return retval;
 
+       retval = command_run_line(CMD_CTX, "init_target_events");
+       if (ERROR_OK != retval)
+               return retval;
+
        retval = command_run_line(CMD_CTX, "init_board");
        if (ERROR_OK != retval)
                return retval;
@@ -1325,7 +1366,7 @@ int target_unregister_event_callback(int (*callback)(struct target *target,
        return ERROR_OK;
 }
 
-static int target_unregister_timer_callback(int (*callback)(void *priv), void *priv)
+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;
@@ -1796,7 +1837,7 @@ static int target_profiling_default(struct target *target, uint32_t *samples,
                gettimeofday(&now, NULL);
                if ((sample_count >= max_num_samples) ||
                        ((now.tv_sec >= timeout.tv_sec) && (now.tv_usec >= timeout.tv_usec))) {
-                       LOG_INFO("Profiling completed. %d samples.", sample_count);
+                       LOG_INFO("Profiling completed. %" PRIu32 " samples.", sample_count);
                        break;
                }
        }
@@ -1983,6 +2024,30 @@ int target_blank_check_memory(struct target *target, uint32_t address, uint32_t
        return retval;
 }
 
+int target_read_u64(struct target *target, uint64_t address, uint64_t *value)
+{
+       uint8_t value_buf[8];
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       int retval = target_read_memory(target, address, 8, 1, value_buf);
+
+       if (retval == ERROR_OK) {
+               *value = target_buffer_get_u64(target, value_buf);
+               LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "",
+                                 address,
+                                 *value);
+       } else {
+               *value = 0x0;
+               LOG_DEBUG("address: 0x%" PRIx64 " failed",
+                                 address);
+       }
+
+       return retval;
+}
+
 int target_read_u32(struct target *target, uint32_t address, uint32_t *value)
 {
        uint8_t value_buf[4];
@@ -2053,6 +2118,27 @@ int target_read_u8(struct target *target, uint32_t address, uint8_t *value)
        return retval;
 }
 
+int target_write_u64(struct target *target, uint64_t address, uint64_t value)
+{
+       int retval;
+       uint8_t value_buf[8];
+       if (!target_was_examined(target)) {
+               LOG_ERROR("Target not examined yet");
+               return ERROR_FAIL;
+       }
+
+       LOG_DEBUG("address: 0x%" PRIx64 ", value: 0x%16.16" PRIx64 "",
+                         address,
+                         value);
+
+       target_buffer_set_u64(target, value_buf, value);
+       retval = target_write_memory(target, address, 8, 1, value_buf);
+       if (retval != ERROR_OK)
+               LOG_DEBUG("failed: %i", retval);
+
+       return retval;
+}
+
 int target_write_u32(struct target *target, uint32_t address, uint32_t value)
 {
        int retval;
@@ -2298,6 +2384,10 @@ static int handle_target(void *priv)
        for (struct target *target = all_targets;
                        is_jtag_poll_safe() && target;
                        target = target->next) {
+
+               if (!target_was_examined(target))
+                       continue;
+
                if (!target->tap->enabled)
                        continue;
 
@@ -2329,8 +2419,12 @@ static int handle_target(void *priv)
                                return retval;
                        }
                        /* Since we succeeded, we reset backoff count */
-                       if (target->backoff.times > 0)
-                               LOG_USER("Polling target %s succeeded again", target_name(target));
+                       if (target->backoff.times > 0) {
+                               LOG_USER("Polling target %s succeeded again, trying to reexamine", target_name(target));
+                               target_reset_examined(target);
+                               target_examine_one(target);
+                       }
+
                        target->backoff.times = 0;
                }
        }
@@ -3101,7 +3195,7 @@ static COMMAND_HELPER(handle_verify_image_command_internal, int verify)
                                if (diffs == 0)
                                        LOG_ERROR("checksum mismatch - attempting binary compare");
 
-                               data = (uint8_t *)malloc(buf_cnt);
+                               data = malloc(buf_cnt);
 
                                /* Can we use 32bit word accesses? */
                                int size = 1;
@@ -3533,29 +3627,30 @@ COMMAND_HANDLER(handle_profile_command)
 
        const uint32_t MAX_PROFILE_SAMPLE_NUM = 10000;
        uint32_t offset;
-       uint32_t num_of_sampels;
+       uint32_t num_of_samples;
        int retval = ERROR_OK;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], offset);
+
        uint32_t *samples = malloc(sizeof(uint32_t) * MAX_PROFILE_SAMPLE_NUM);
        if (samples == NULL) {
                LOG_ERROR("No memory to store samples.");
                return ERROR_FAIL;
        }
 
-       COMMAND_PARSE_NUMBER(uint, CMD_ARGV[0], offset);
-
        /**
         * Some cores let us sample the PC without the
         * annoying halt/resume step; for example, ARMv7 PCSR.
         * Provide a way to use that more efficient mechanism.
         */
        retval = target_profiling(target, samples, MAX_PROFILE_SAMPLE_NUM,
-                               &num_of_sampels, offset);
+                               &num_of_samples, offset);
        if (retval != ERROR_OK) {
                free(samples);
                return retval;
        }
 
-       assert(num_of_sampels <= MAX_PROFILE_SAMPLE_NUM);
+       assert(num_of_samples <= MAX_PROFILE_SAMPLE_NUM);
 
        retval = target_poll(target);
        if (retval != ERROR_OK) {
@@ -3581,11 +3676,11 @@ COMMAND_HANDLER(handle_profile_command)
        bool with_range = false;
        if (CMD_ARGC == 4) {
                with_range = true;
-               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[2], start_address);
-               COMMAND_PARSE_NUMBER(uint, CMD_ARGV[3], end_address);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[2], start_address);
+               COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address);
        }
 
-       write_gmon(samples, num_of_sampels, CMD_ARGV[1],
+       write_gmon(samples, num_of_samples, CMD_ARGV[1],
                        with_range, start_address, end_address);
        command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
 
@@ -3767,6 +3862,7 @@ static int target_mem2array(Jim_Interp *interp, struct target *target, int argc,
                                new_int_array_element(interp, varname, n, v);
                        }
                        len -= count;
+                       addr += count * width;
                }
        }
 
@@ -3960,6 +4056,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target,
                        e = JIM_ERR;
                        break;
                }
+               addr += count * width;
        }
 
        free(buffer);
@@ -4260,11 +4357,10 @@ no_params:
                                                                                   n->name);
                                        return JIM_ERR;
                                }
-                               if (target->variant)
-                                       free((void *)(target->variant));
                                e = Jim_GetOpt_String(goi, &cp, NULL);
                                if (e != JIM_OK)
                                        return e;
+                               free(target->variant);
                                target->variant = strdup(cp);
                        } else {
                                if (goi->argc != 0)
@@ -4971,6 +5067,15 @@ static int target_create(Jim_GetOptInfo *goi)
        if (e != JIM_OK)
                return e;
        cp = cp2;
+       struct transport *tr = get_current_transport();
+       if (tr->override_target) {
+               e = tr->override_target(&cp);
+               if (e != ERROR_OK) {
+                       LOG_ERROR("The selected transport doesn't support this target");
+                       return JIM_ERR;
+               }
+               LOG_INFO("The selected transport took over low-level target control. The results might differ compared to plain JTAG/SWD");
+       }
        /* now does target type exist */
        for (x = 0 ; target_types[x] ; x++) {
                if (0 == strcmp(cp, target_types[x]->name)) {
@@ -5009,9 +5114,10 @@ static int target_create(Jim_GetOptInfo *goi)
        target = calloc(1, sizeof(struct target));
        /* set target number */
        target->target_number = new_target_number();
+       cmd_ctx->current_target = target->target_number;
 
        /* allocate memory for each unique target type */
-       target->type = (struct target_type *)calloc(1, sizeof(struct target_type));
+       target->type = calloc(1, sizeof(struct target_type));
 
        memcpy(target->type, target_types[x], sizeof(struct target_type));
 
@@ -5397,7 +5503,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
        image_size = 0x0;
        retval = ERROR_OK;
        fastload_num = image.num_sections;
-       fastload = (struct FastLoad *)malloc(sizeof(struct FastLoad)*image.num_sections);
+       fastload = malloc(sizeof(struct FastLoad)*image.num_sections);
        if (fastload == NULL) {
                command_print(CMD_CTX, "out of memory");
                image_close(&image);
@@ -5439,7 +5545,7 @@ COMMAND_HANDLER(handle_fast_load_image_command)
                        fastload[i].data = malloc(length);
                        if (fastload[i].data == NULL) {
                                free(buffer);
-                               command_print(CMD_CTX, "error allocating buffer for section (%d bytes)",
+                               command_print(CMD_CTX, "error allocating buffer for section (%" PRIu32 " bytes)",
                                                          length);
                                retval = ERROR_FAIL;
                                break;
@@ -5562,6 +5668,198 @@ COMMAND_HANDLER(handle_ps_command)
        }
 }
 
+static void binprint(struct command_context *cmd_ctx, const char *text, const uint8_t *buf, int size)
+{
+       if (text != NULL)
+               command_print_sameline(cmd_ctx, "%s", text);
+       for (int i = 0; i < size; i++)
+               command_print_sameline(cmd_ctx, " %02x", buf[i]);
+       command_print(cmd_ctx, " ");
+}
+
+COMMAND_HANDLER(handle_test_mem_access_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       uint32_t test_size;
+       int retval = ERROR_OK;
+
+       if (target->state != TARGET_HALTED) {
+               LOG_INFO("target not halted !!");
+               return ERROR_FAIL;
+       }
+
+       if (CMD_ARGC != 1)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       COMMAND_PARSE_NUMBER(u32, CMD_ARGV[0], test_size);
+
+       /* Test reads */
+       size_t num_bytes = test_size + 4;
+
+       struct working_area *wa = NULL;
+       retval = target_alloc_working_area(target, num_bytes, &wa);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Not enough working area");
+               return ERROR_FAIL;
+       }
+
+       uint8_t *test_pattern = malloc(num_bytes);
+
+       for (size_t i = 0; i < num_bytes; i++)
+               test_pattern[i] = rand();
+
+       retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Test pattern write failed");
+               goto out;
+       }
+
+       for (int host_offset = 0; host_offset <= 1; host_offset++) {
+               for (int size = 1; size <= 4; size *= 2) {
+                       for (int offset = 0; offset < 4; offset++) {
+                               uint32_t count = test_size / size;
+                               size_t host_bufsiz = (count + 2) * size + host_offset;
+                               uint8_t *read_ref = malloc(host_bufsiz);
+                               uint8_t *read_buf = malloc(host_bufsiz);
+
+                               for (size_t i = 0; i < host_bufsiz; i++) {
+                                       read_ref[i] = rand();
+                                       read_buf[i] = read_ref[i];
+                               }
+                               command_print_sameline(CMD_CTX,
+                                               "Test read %" PRIu32 " x %d @ %d to %saligned buffer: ", count,
+                                               size, offset, host_offset ? "un" : "");
+
+                               struct duration bench;
+                               duration_start(&bench);
+
+                               retval = target_read_memory(target, wa->address + offset, size, count,
+                                               read_buf + size + host_offset);
+
+                               duration_measure(&bench);
+
+                               if (retval == ERROR_TARGET_UNALIGNED_ACCESS) {
+                                       command_print(CMD_CTX, "Unsupported alignment");
+                                       goto next;
+                               } else if (retval != ERROR_OK) {
+                                       command_print(CMD_CTX, "Memory read failed");
+                                       goto next;
+                               }
+
+                               /* replay on host */
+                               memcpy(read_ref + size + host_offset, test_pattern + offset, count * size);
+
+                               /* check result */
+                               int result = memcmp(read_ref, read_buf, host_bufsiz);
+                               if (result == 0) {
+                                       command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)",
+                                                       duration_elapsed(&bench),
+                                                       duration_kbps(&bench, count * size));
+                               } else {
+                                       command_print(CMD_CTX, "Compare failed");
+                                       binprint(CMD_CTX, "ref:", read_ref, host_bufsiz);
+                                       binprint(CMD_CTX, "buf:", read_buf, host_bufsiz);
+                               }
+next:
+                               free(read_ref);
+                               free(read_buf);
+                       }
+               }
+       }
+
+out:
+       free(test_pattern);
+
+       if (wa != NULL)
+               target_free_working_area(target, wa);
+
+       /* Test writes */
+       num_bytes = test_size + 4 + 4 + 4;
+
+       retval = target_alloc_working_area(target, num_bytes, &wa);
+       if (retval != ERROR_OK) {
+               LOG_ERROR("Not enough working area");
+               return ERROR_FAIL;
+       }
+
+       test_pattern = malloc(num_bytes);
+
+       for (size_t i = 0; i < num_bytes; i++)
+               test_pattern[i] = rand();
+
+       for (int host_offset = 0; host_offset <= 1; host_offset++) {
+               for (int size = 1; size <= 4; size *= 2) {
+                       for (int offset = 0; offset < 4; offset++) {
+                               uint32_t count = test_size / size;
+                               size_t host_bufsiz = count * size + host_offset;
+                               uint8_t *read_ref = malloc(num_bytes);
+                               uint8_t *read_buf = malloc(num_bytes);
+                               uint8_t *write_buf = malloc(host_bufsiz);
+
+                               for (size_t i = 0; i < host_bufsiz; i++)
+                                       write_buf[i] = rand();
+                               command_print_sameline(CMD_CTX,
+                                               "Test write %" PRIu32 " x %d @ %d from %saligned buffer: ", count,
+                                               size, offset, host_offset ? "un" : "");
+
+                               retval = target_write_memory(target, wa->address, 1, num_bytes, test_pattern);
+                               if (retval != ERROR_OK) {
+                                       command_print(CMD_CTX, "Test pattern write failed");
+                                       goto nextw;
+                               }
+
+                               /* replay on host */
+                               memcpy(read_ref, test_pattern, num_bytes);
+                               memcpy(read_ref + size + offset, write_buf + host_offset, count * size);
+
+                               struct duration bench;
+                               duration_start(&bench);
+
+                               retval = target_write_memory(target, wa->address + size + offset, size, count,
+                                               write_buf + host_offset);
+
+                               duration_measure(&bench);
+
+                               if (retval == ERROR_TARGET_UNALIGNED_ACCESS) {
+                                       command_print(CMD_CTX, "Unsupported alignment");
+                                       goto nextw;
+                               } else if (retval != ERROR_OK) {
+                                       command_print(CMD_CTX, "Memory write failed");
+                                       goto nextw;
+                               }
+
+                               /* read back */
+                               retval = target_read_memory(target, wa->address, 1, num_bytes, read_buf);
+                               if (retval != ERROR_OK) {
+                                       command_print(CMD_CTX, "Test pattern write failed");
+                                       goto nextw;
+                               }
+
+                               /* check result */
+                               int result = memcmp(read_ref, read_buf, num_bytes);
+                               if (result == 0) {
+                                       command_print(CMD_CTX, "Pass in %fs (%0.3f KiB/s)",
+                                                       duration_elapsed(&bench),
+                                                       duration_kbps(&bench, count * size));
+                               } else {
+                                       command_print(CMD_CTX, "Compare failed");
+                                       binprint(CMD_CTX, "ref:", read_ref, num_bytes);
+                                       binprint(CMD_CTX, "buf:", read_buf, num_bytes);
+                               }
+nextw:
+                               free(read_ref);
+                               free(read_buf);
+                       }
+               }
+       }
+
+       free(test_pattern);
+
+       if (wa != NULL)
+               target_free_working_area(target, wa);
+       return retval;
+}
+
 static const struct command_registration target_exec_command_handlers[] = {
        {
                .name = "fast_load_image",
@@ -5599,9 +5897,9 @@ static const struct command_registration target_exec_command_handlers[] = {
                .name = "reg",
                .handler = handle_reg_command,
                .mode = COMMAND_EXEC,
-               .help = "display or set a register; with no arguments, "
-                       "displays all registers and their values",
-               .usage = "[(register_name|register_number) [value]]",
+               .help = "display (reread from target with \"force\") or set a register; "
+                       "with no arguments, displays all registers and their values",
+               .usage = "[(register_number|register_name) [(value|'force')]]",
        },
        {
                .name = "poll",
@@ -5781,6 +6079,13 @@ static const struct command_registration target_exec_command_handlers[] = {
                .help = "list all tasks ",
                .usage = " ",
        },
+       {
+               .name = "test_mem_access",
+               .handler = handle_test_mem_access_command,
+               .mode = COMMAND_EXEC,
+               .help = "Test the target's memory access functions",
+               .usage = "size",
+       },
 
        COMMAND_REGISTRATION_DONE
 };