+ .chain = target_subcommand_handlers,
+ },
+ COMMAND_REGISTRATION_DONE
+};
+
+int target_register_commands(struct command_context *cmd_ctx)
+{
+ return register_commands(cmd_ctx, NULL, target_command_handlers);
+}
+
+static bool target_reset_nag = true;
+
+bool get_target_reset_nag(void)
+{
+ return target_reset_nag;
+}
+
+COMMAND_HANDLER(handle_target_reset_nag)
+{
+ return CALL_COMMAND_HANDLER(handle_command_parse_bool,
+ &target_reset_nag, "Nag after each reset about options to improve "
+ "performance");
+}
+
+COMMAND_HANDLER(handle_ps_command)
+{
+ struct target *target = get_current_target(CMD_CTX);
+ char *display;
+ if (target->state != TARGET_HALTED) {
+ LOG_INFO("target not halted !!");
+ return ERROR_OK;
+ }
+
+ if ((target->rtos) && (target->rtos->type)
+ && (target->rtos->type->ps_command)) {
+ display = target->rtos->type->ps_command(target);
+ command_print(CMD_CTX, "%s", display);
+ free(display);
+ return ERROR_OK;
+ } else {
+ LOG_INFO("failed");
+ return ERROR_TARGET_FAILURE;
+ }
+}
+
+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",
+ .handler = handle_fast_load_image_command,
+ .mode = COMMAND_ANY,
+ .help = "Load image into server memory for later use by "
+ "fast_load; primarily for profiling",
+ .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] "
+ "[min_address [max_length]]",
+ },
+ {
+ .name = "fast_load",
+ .handler = handle_fast_load_command,
+ .mode = COMMAND_EXEC,
+ .help = "loads active fast load image to current target "
+ "- mainly for profiling purposes",
+ .usage = "",
+ },
+ {
+ .name = "profile",
+ .handler = handle_profile_command,
+ .mode = COMMAND_EXEC,
+ .usage = "seconds filename [start end]",
+ .help = "profiling samples the CPU PC",
+ },
+ /** @todo don't register virt2phys() unless target supports it */
+ {
+ .name = "virt2phys",
+ .handler = handle_virt2phys_command,
+ .mode = COMMAND_ANY,
+ .help = "translate a virtual address into a physical address",
+ .usage = "virtual_address",
+ },
+ {
+ .name = "reg",
+ .handler = handle_reg_command,
+ .mode = COMMAND_EXEC,
+ .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",
+ .handler = handle_poll_command,
+ .mode = COMMAND_EXEC,
+ .help = "poll target state; or reconfigure background polling",
+ .usage = "['on'|'off']",
+ },
+ {
+ .name = "wait_halt",
+ .handler = handle_wait_halt_command,
+ .mode = COMMAND_EXEC,
+ .help = "wait up to the specified number of milliseconds "
+ "(default 5000) for a previously requested halt",
+ .usage = "[milliseconds]",
+ },
+ {
+ .name = "halt",
+ .handler = handle_halt_command,
+ .mode = COMMAND_EXEC,
+ .help = "request target to halt, then wait up to the specified"
+ "number of milliseconds (default 5000) for it to complete",
+ .usage = "[milliseconds]",
+ },
+ {
+ .name = "resume",
+ .handler = handle_resume_command,
+ .mode = COMMAND_EXEC,
+ .help = "resume target execution from current PC or address",
+ .usage = "[address]",
+ },
+ {
+ .name = "reset",
+ .handler = handle_reset_command,
+ .mode = COMMAND_EXEC,
+ .usage = "[run|halt|init]",
+ .help = "Reset all targets into the specified mode."
+ "Default reset mode is run, if not given.",
+ },
+ {
+ .name = "soft_reset_halt",
+ .handler = handle_soft_reset_halt_command,
+ .mode = COMMAND_EXEC,
+ .usage = "",
+ .help = "halt the target and do a soft reset",
+ },
+ {
+ .name = "step",
+ .handler = handle_step_command,
+ .mode = COMMAND_EXEC,
+ .help = "step one instruction from current PC or address",
+ .usage = "[address]",
+ },
+ {
+ .name = "mdd",
+ .handler = handle_md_command,
+ .mode = COMMAND_EXEC,
+ .help = "display memory words",
+ .usage = "['phys'] address [count]",
+ },
+ {
+ .name = "mdw",
+ .handler = handle_md_command,
+ .mode = COMMAND_EXEC,
+ .help = "display memory words",
+ .usage = "['phys'] address [count]",
+ },
+ {
+ .name = "mdh",
+ .handler = handle_md_command,
+ .mode = COMMAND_EXEC,
+ .help = "display memory half-words",
+ .usage = "['phys'] address [count]",
+ },
+ {
+ .name = "mdb",
+ .handler = handle_md_command,
+ .mode = COMMAND_EXEC,
+ .help = "display memory bytes",
+ .usage = "['phys'] address [count]",
+ },
+ {
+ .name = "mwd",
+ .handler = handle_mw_command,
+ .mode = COMMAND_EXEC,
+ .help = "write memory word",
+ .usage = "['phys'] address value [count]",
+ },
+ {
+ .name = "mww",
+ .handler = handle_mw_command,
+ .mode = COMMAND_EXEC,
+ .help = "write memory word",
+ .usage = "['phys'] address value [count]",
+ },
+ {
+ .name = "mwh",
+ .handler = handle_mw_command,
+ .mode = COMMAND_EXEC,
+ .help = "write memory half-word",
+ .usage = "['phys'] address value [count]",
+ },
+ {
+ .name = "mwb",
+ .handler = handle_mw_command,
+ .mode = COMMAND_EXEC,
+ .help = "write memory byte",
+ .usage = "['phys'] address value [count]",
+ },
+ {
+ .name = "bp",
+ .handler = handle_bp_command,
+ .mode = COMMAND_EXEC,
+ .help = "list or set hardware or software breakpoint",
+ .usage = "<address> [<asid>] <length> ['hw'|'hw_ctx']",
+ },
+ {
+ .name = "rbp",
+ .handler = handle_rbp_command,
+ .mode = COMMAND_EXEC,
+ .help = "remove breakpoint",
+ .usage = "address",
+ },
+ {
+ .name = "wp",
+ .handler = handle_wp_command,
+ .mode = COMMAND_EXEC,
+ .help = "list (no params) or create watchpoints",
+ .usage = "[address length [('r'|'w'|'a') value [mask]]]",
+ },
+ {
+ .name = "rwp",
+ .handler = handle_rwp_command,
+ .mode = COMMAND_EXEC,
+ .help = "remove watchpoint",
+ .usage = "address",
+ },
+ {
+ .name = "load_image",
+ .handler = handle_load_image_command,
+ .mode = COMMAND_EXEC,
+ .usage = "filename address ['bin'|'ihex'|'elf'|'s19'] "
+ "[min_address] [max_length]",
+ },
+ {
+ .name = "dump_image",
+ .handler = handle_dump_image_command,
+ .mode = COMMAND_EXEC,
+ .usage = "filename address size",
+ },
+ {
+ .name = "verify_image_checksum",
+ .handler = handle_verify_image_checksum_command,
+ .mode = COMMAND_EXEC,
+ .usage = "filename [offset [type]]",
+ },
+ {
+ .name = "verify_image",
+ .handler = handle_verify_image_command,
+ .mode = COMMAND_EXEC,
+ .usage = "filename [offset [type]]",
+ },
+ {
+ .name = "test_image",
+ .handler = handle_test_image_command,
+ .mode = COMMAND_EXEC,
+ .usage = "filename [offset [type]]",
+ },
+ {
+ .name = "mem2array",
+ .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",
+ },
+ {
+ .name = "array2mem",
+ .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",
+ },
+ {
+ .name = "reset_nag",
+ .handler = handle_target_reset_nag,
+ .mode = COMMAND_ANY,
+ .help = "Nag after each reset about options that could have been "
+ "enabled to improve performance. ",
+ .usage = "['enable'|'disable']",
+ },
+ {
+ .name = "ps",
+ .handler = handle_ps_command,
+ .mode = COMMAND_EXEC,
+ .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
+};
+static int target_register_user_commands(struct command_context *cmd_ctx)
+{
+ int retval = ERROR_OK;
+ retval = target_request_register_commands(cmd_ctx);
+ if (retval != ERROR_OK)
+ return retval;
+
+ retval = trace_register_commands(cmd_ctx);
+ if (retval != ERROR_OK)
+ return retval;
+
+
+ return register_commands(cmd_ctx, NULL, target_exec_command_handlers);
+}