#include "trace.h"
#include "image.h"
#include "rtos/rtos.h"
+#include "transport/transport.h"
/* default halt wait timeout (ms) */
#define DEFAULT_HALT_TIMEOUT 5000
extern struct target_type dragonite_target;
extern struct target_type xscale_target;
extern struct target_type cortexm_target;
-extern struct target_type cortexa8_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;
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,
&dragonite_target,
&xscale_target,
&cortexm_target,
- &cortexa8_target,
+ &cortexa_target,
&cortexr4_target,
&arm11_target,
&mips_m4k_target,
&nds32_v3_target,
&nds32_v3m_target,
&or1k_target,
+ &quark_x10xx_target,
NULL,
};
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)
{
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)
{
*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)
{
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, const uint32_t *srcbuf)
{
*/
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,
int retval;
int timeout = 0;
+ const uint8_t *buffer_orig = buffer;
+
/* Set up working area. First word is write pointer, second word is read pointer,
* rest is fifo data area. */
uint32_t wp_addr = buffer_start;
break;
}
- LOG_DEBUG("count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32, count, wp, rp);
+ LOG_DEBUG("offs 0x%zx count 0x%" PRIx32 " wp 0x%" PRIx32 " rp 0x%" PRIx32,
+ (size_t) (buffer - buffer_orig), count, wp, rp);
if (rp == 0) {
LOG_ERROR("flash write algorithm aborted by target");
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;
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;
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];
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;
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;
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);
+ retval = target_examine_one(target);
+ /* 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;
+ return retval;
+ }
+ }
+
target->backoff.times = 0;
}
}
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;
uint32_t addr, uint32_t asid, uint32_t length, int hw)
{
struct target *target = get_current_target(cmd_ctx);
+ int retval;
if (asid == 0) {
- int retval = breakpoint_add(target, addr, length, hw);
+ retval = breakpoint_add(target, addr, length, hw);
if (ERROR_OK == retval)
command_print(cmd_ctx, "breakpoint set at 0x%8.8" PRIx32 "", addr);
else {
return retval;
}
} else if (addr == 0) {
- int retval = context_breakpoint_add(target, asid, length, hw);
+ if (target->type->add_context_breakpoint == NULL) {
+ LOG_WARNING("Context breakpoint not available");
+ return ERROR_OK;
+ }
+ retval = context_breakpoint_add(target, asid, length, hw);
if (ERROR_OK == retval)
command_print(cmd_ctx, "Context breakpoint set at 0x%8.8" PRIx32 "", asid);
else {
return retval;
}
} else {
- int retval = hybrid_breakpoint_add(target, addr, asid, length, hw);
+ if (target->type->add_hybrid_breakpoint == NULL) {
+ LOG_WARNING("Hybrid breakpoint not available");
+ return ERROR_OK;
+ }
+ retval = hybrid_breakpoint_add(target, addr, asid, length, hw);
if (ERROR_OK == retval)
command_print(cmd_ctx, "Hybrid breakpoint set at 0x%8.8" PRIx32 "", asid);
else {
LOG_ERROR("failed to write %zu bytes: %s", len, strerror(errno));
}
-static void writeLong(FILE *f, int l)
+static void writeLong(FILE *f, int l, struct target *target)
{
- int i;
- for (i = 0; i < 4; i++) {
- char c = (l >> (i*8))&0xff;
- writeData(f, &c, 1);
- }
+ uint8_t val[4];
+ target_buffer_set_u32(target, val, l);
+ writeData(f, val, 4);
}
static void writeString(FILE *f, char *s)
typedef unsigned char UNIT[2]; /* unit of profiling */
/* Dump a gmon.out histogram file. */
-static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename,
- bool with_range, uint32_t start_address, uint32_t end_address)
+static void write_gmon(uint32_t *samples, uint32_t sampleNum, const char *filename, bool with_range,
+ uint32_t start_address, uint32_t end_address, struct target *target)
{
uint32_t i;
FILE *f = fopen(filename, "w");
if (f == NULL)
return;
writeString(f, "gmon");
- writeLong(f, 0x00000001); /* Version */
- writeLong(f, 0); /* padding */
- writeLong(f, 0); /* padding */
- writeLong(f, 0); /* padding */
+ writeLong(f, 0x00000001, target); /* Version */
+ writeLong(f, 0, target); /* padding */
+ writeLong(f, 0, target); /* padding */
+ writeLong(f, 0, target); /* padding */
uint8_t zero = 0; /* GMON_TAG_TIME_HIST */
writeData(f, &zero, 1);
}
/* append binary memory gmon.out &profile_hist_hdr ((char*)&profile_hist_hdr + sizeof(struct gmon_hist_hdr)) */
- writeLong(f, min); /* low_pc */
- writeLong(f, max); /* high_pc */
- writeLong(f, numBuckets); /* # of buckets */
- writeLong(f, 100); /* KLUDGE! We lie, ca. 100Hz best case. */
+ writeLong(f, min, target); /* low_pc */
+ writeLong(f, max, target); /* high_pc */
+ writeLong(f, numBuckets, target); /* # of buckets */
+ writeLong(f, 100, target); /* KLUDGE! We lie, ca. 100Hz best case. */
writeString(f, "seconds");
for (i = 0; i < (15-strlen("seconds")); i++)
writeData(f, &zero, 1);
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(u32, 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) {
COMMAND_PARSE_NUMBER(u32, CMD_ARGV[3], end_address);
}
- write_gmon(samples, num_of_sampels, CMD_ARGV[1],
- with_range, start_address, end_address);
+ write_gmon(samples, num_of_samples, CMD_ARGV[1],
+ with_range, start_address, end_address, target);
command_print(CMD_CTX, "Wrote %s", CMD_ARGV[1]);
free(samples);
new_int_array_element(interp, varname, n, v);
}
len -= count;
+ addr += count * width;
}
}
e = JIM_ERR;
break;
}
+ addr += count * width;
}
free(buffer);
TCFG_WORK_AREA_SIZE,
TCFG_WORK_AREA_BACKUP,
TCFG_ENDIAN,
- TCFG_VARIANT,
TCFG_COREID,
TCFG_CHAIN_POSITION,
TCFG_DBGBASE,
{ .name = "-work-area-size", .value = TCFG_WORK_AREA_SIZE },
{ .name = "-work-area-backup", .value = TCFG_WORK_AREA_BACKUP },
{ .name = "-endian" , .value = TCFG_ENDIAN },
- { .name = "-variant", .value = TCFG_VARIANT },
{ .name = "-coreid", .value = TCFG_COREID },
{ .name = "-chain-position", .value = TCFG_CHAIN_POSITION },
{ .name = "-dbgbase", .value = TCFG_DBGBASE },
Jim_Nvp *n;
Jim_Obj *o;
jim_wide w;
- char *cp;
int e;
/* parse config or cget options ... */
/* loop for more */
break;
- case TCFG_VARIANT:
- if (goi->isconfigure) {
- if (goi->argc < 1) {
- Jim_SetResultFormatted(goi->interp,
- "%s ?STRING?",
- n->name);
- return JIM_ERR;
- }
- 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)
- goto no_params;
- }
- Jim_SetResultString(goi->interp, target->variant, -1);
- /* loop for more */
- break;
-
case TCFG_COREID:
if (goi->isconfigure) {
e = Jim_GetOpt_Wide(goi, &w);
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)) {
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));
target->endianness = TARGET_LITTLE_ENDIAN;
}
- /* incase variant is not set */
- if (!target->variant)
- target->variant = strdup("");
-
cp = Jim_GetString(new_cmd, NULL);
target->cmd_name = strdup(cp);
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);
}
}
+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",
.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",
.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
};