X-Git-Url: https://review.openocd.org/gitweb?p=openocd.git;a=blobdiff_plain;f=src%2Ftarget%2Ftarget.c;h=c09dfd865e5b087a40c41d34f89e349aa5bf0e49;hp=d78f3b1607e3d9a85975a34a4579bf9d95eeb07a;hb=565f8481c7b71614a05d79ab79af8610d2535a81;hpb=f132fcf636361009b4125827351ef01556d49b31 diff --git a/src/target/target.c b/src/target/target.c index d78f3b1607..c09dfd865e 100644 --- a/src/target/target.c +++ b/src/target/target.c @@ -102,6 +102,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, @@ -130,6 +131,7 @@ static struct target_type *target_types[] = { &nds32_v3_target, &nds32_v3m_target, &or1k_target, + &quark_x10xx_target, NULL, }; @@ -294,6 +296,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 +338,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 +380,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 +404,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 +421,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 +853,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, @@ -1325,7 +1361,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; @@ -1983,6 +2019,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 +2113,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 +2379,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; @@ -3767,6 +3852,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 +4046,7 @@ static int target_array2mem(Jim_Interp *interp, struct target *target, e = JIM_ERR; break; } + addr += count * width; } free(buffer); @@ -4260,11 +4347,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) @@ -5562,6 +5648,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 %d 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 %d 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 +5877,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 +6059,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 };