This is an automated email from Gerrit. "Name of user not set <zed...@gmail.com>" just uploaded a new patch set to Gerrit, which you can find at https://review.openocd.org/c/openocd/+/6748
-- gerrit commit 2c5a6911dbf676115b520d1869da2d483e033d3c Author: Zoltán Dudás <zed...@gmail.com> Date: Wed Nov 24 17:13:50 2021 +0100 semihosting: Extended operation, Tcl command exec on host Enabling user defined semihosting operation number range to be processed with a new semihosting command. Defining a new semihosting operation from the forementioned range: Execute a Tcl command on the host defined by the target. For example, this method can be used to automatically configure RTT with actual control block location from target. Signed-off-by: Zoltán Dudás <zed...@gmail.com> Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247 diff --git a/doc/openocd.texi b/doc/openocd.texi index 0ab4b36ac..7eb70a7eb 100644 --- a/doc/openocd.texi +++ b/doc/openocd.texi @@ -9170,6 +9170,15 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable this option (default: disabled). @end deffn +@deffn {Command} {arm semihosting_extended} [@option{enable}|@option{disable}] +@cindex ARM semihosting +Display status of semihosting extended functionality, after optionally +changing that status. + +This option enables the user-defined semihosting operation number +range (0x0100 - 0x01ff) to be processed. +@end deffn + @section ARMv4 and ARMv5 Architecture @cindex ARMv4 @cindex ARMv5 diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c index 792474acf..2a613c586 100644 --- a/src/target/arm_semihosting.c +++ b/src/target/arm_semihosting.c @@ -367,7 +367,8 @@ int arm_semihosting(struct target *target, int *retval) } /* Check for ARM operation numbers. */ - if (semihosting->op >= 0 && semihosting->op <= 0x31) { + if ((semihosting->op >= 0 && semihosting->op <= 0x31) || + ((semihosting->is_extended) && (semihosting->op >= 0x100 && semihosting->op <= 0x1FF))) { *retval = semihosting_common(target); if (*retval != ERROR_OK) { LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op); diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 5c96e1cd6..0a3ff005f 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -117,6 +117,8 @@ int semihosting_common_init(struct target *target, void *setup, semihosting->hit_fileio = false; semihosting->is_resumable = false; semihosting->has_resumable_exit = false; + semihosting->is_extended = false; + semihosting->extended_ctx = NULL; semihosting->word_size_bytes = 0; semihosting->op = -1; semihosting->param = 0; @@ -1262,6 +1264,48 @@ int semihosting_common(struct target *target) } break; + case SEMIHOSTING_EXT_TCL_CMD: /* 0x169 */ + /* + * Runs a Tcl command in the context obtained from the + * extended functionality enable command handler. + * + * Entry + * On entry, the PARAMETER REGISTER contains a pointer to a + * two-field data block: + * - field 1 Contains a pointer to the command string + * - field 2 Contains the command length + * + * Return + * On exit, the RETURN REGISTER contains the return status. + */ + retval = semihosting_read_fields(target, 2, fields); + if (retval != ERROR_OK) { + return retval; + } else { + uint64_t addr = semihosting_get_field(target, 0, fields); + size_t len = semihosting_get_field(target, 1, fields); + + if (len > 0 && len < SEMIHOSTING_MAX_TCL_COMMAND_LENGTH) { + char command[len]; + + retval = target_read_buffer(target, addr, len, (uint8_t*)command); + + if (retval != ERROR_OK) + return retval; + + if(target->semihosting->extended_ctx) { + command_run_line(target->semihosting->extended_ctx, command); + LOG_DEBUG("Runnning tcl command from semihosting (length=%u): %s", + (unsigned int)len, command); + } else { + semihosting->result = -1; + return -1; + } + } + semihosting->result = 0; + } + break; + case SEMIHOSTING_SYS_ELAPSED: /* 0x30 */ /* * Returns the number of elapsed target ticks since execution @@ -1608,6 +1652,38 @@ static __COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command) return ERROR_OK; } +static __COMMAND_HANDLER(handle_common_semihosting_extended_command) +{ + struct target *target = get_current_target(CMD_CTX); + + if (!target) { + LOG_ERROR("No target selected"); + return ERROR_FAIL; + } + + struct semihosting *semihosting = target->semihosting; + if (!semihosting) { + command_print(CMD, "semihosting not supported for current target"); + return ERROR_FAIL; + } + + if (!semihosting->is_active) { + command_print(CMD, "semihosting not yet enabled for current target"); + return ERROR_FAIL; + } + + if (CMD_ARGC > 0) + COMMAND_PARSE_ENABLE(CMD_ARGV[0], semihosting->is_extended); + + command_print(CMD, "semihosting extended functionality is %s", + semihosting->is_extended + ? "enabled" : "disabled"); + + semihosting->extended_ctx = copy_command_context(CMD_CTX); + + return ERROR_OK; +} + const struct command_registration semihosting_common_handlers[] = { { "semihosting", @@ -1637,5 +1713,12 @@ const struct command_registration semihosting_common_handlers[] = { .usage = "['enable'|'disable']", .help = "activate support for semihosting resumable exit", }, + { + "semihosting_extended", + .handler = handle_common_semihosting_extended_command, + .mode = COMMAND_EXEC, + .usage = "['enable'|'disable']", + .help = "activate support for extended semihosting operations", + }, COMMAND_REGISTRATION_DONE }; diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index b83464ed5..4098afecc 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -75,8 +75,16 @@ enum semihosting_operation_numbers { SEMIHOSTING_SYS_WRITE = 0x05, SEMIHOSTING_SYS_WRITEC = 0x03, SEMIHOSTING_SYS_WRITE0 = 0x04, + /* + * Semihosting extension, Tcl command run. Operation number + * obtained from user defined area (0x100-0x1FF). + */ + SEMIHOSTING_EXT_TCL_CMD = 0x169, }; +/** Maxmium allowed Tcl command length in bytes*/ +#define SEMIHOSTING_MAX_TCL_COMMAND_LENGTH 256 + /* * Codes used by SEMIHOSTING_SYS_EXIT (formerly * SEMIHOSTING_REPORT_EXCEPTION). @@ -108,6 +116,9 @@ struct semihosting { /** Most are resumable, except the two exit calls. */ bool is_resumable; + /** A flag reporting whether extended semihosting functionality is active. */ + bool is_extended; + /** * When SEMIHOSTING_SYS_EXIT is called outside a debug session, * things are simple, the openocd process calls exit() and passes @@ -153,6 +164,9 @@ struct semihosting { /** The current time when 'execution starts' */ clock_t setup_time; + /** Command context to be used in extended semihosting functionality. */ + struct command_context * extended_ctx; + int (*setup)(struct target *target, int enable); int (*post_result)(struct target *target); }; --