semihosting: User defined operation, Tcl command exec on host 48/6748/18
authorZoltán Dudás <zedudi@gmail.com>
Wed, 24 Nov 2021 16:13:50 +0000 (17:13 +0100)
committerAntonio Borneo <borneo.antonio@gmail.com>
Sat, 5 Feb 2022 21:40:17 +0000 (21:40 +0000)
Enabling a portion (0x100 - 0x107) of the user defined semihosting
operation number range (0x100 - 0x1FF) to be processed with the help of
the existing target event mechanism, to implement a general-purpose Tcl
interface for the target available on the host, via semihosting
interface.

Example usage:
- The user configures a Tcl command as a callback for one of the newly
defined events (semihosting-user-cmd-0x10X) in the configuration
file.
- The target can make a semihosting call with <opnum>, passing optional
parameters for the call.

If there is no callback registered to the user defined operation number,
nothing happens.

Example usage: Configure RTT automatically with the exact, linked
control block location from target.

Signed-off-by: Zoltán Dudás <zedudi@gmail.com>
Change-Id: I10e1784b1fecd4e630d78df81cb44bf1aa2fc247
Reviewed-on: https://review.openocd.org/c/openocd/+/6748
Tested-by: jenkins
Reviewed-by: Oleksij Rempel <linux@rempel-privat.de>
Reviewed-by: Antonio Borneo <borneo.antonio@gmail.com>
doc/openocd.texi
src/target/arm_semihosting.c
src/target/riscv/riscv_semihosting.c
src/target/semihosting_common.c
src/target/semihosting_common.h
src/target/target.c
src/target/target.h

index ed92eb4ec5bff5b2ca17e5e8d4d074de82eda9a3..e2c4954733a236a150752533eba18f55a07b898c 100644 (file)
@@ -5185,6 +5185,22 @@ when reset disables PLLs needed to use a fast clock.
 @* After single-step has completed
 @item @b{trace-config}
 @* After target hardware trace configuration was changed
+@item @b{semihosting-user-cmd-0x100}
+@* The target made a semihosting call with user-defined operation number 0x100
+@item @b{semihosting-user-cmd-0x101}
+@* The target made a semihosting call with user-defined operation number 0x101
+@item @b{semihosting-user-cmd-0x102}
+@* The target made a semihosting call with user-defined operation number 0x102
+@item @b{semihosting-user-cmd-0x103}
+@* The target made a semihosting call with user-defined operation number 0x103
+@item @b{semihosting-user-cmd-0x104}
+@* The target made a semihosting call with user-defined operation number 0x104
+@item @b{semihosting-user-cmd-0x105}
+@* The target made a semihosting call with user-defined operation number 0x105
+@item @b{semihosting-user-cmd-0x106}
+@* The target made a semihosting call with user-defined operation number 0x106
+@item @b{semihosting-user-cmd-0x107}
+@* The target made a semihosting call with user-defined operation number 0x107
 @end itemize
 
 @quotation Note
@@ -9241,6 +9257,17 @@ To make the SEMIHOSTING_SYS_EXIT call return normally, enable
 this option (default: disabled).
 @end deffn
 
+@deffn {Command} {arm semihosting_read_user_param}
+@cindex ARM semihosting
+Read parameter of the semihosting call from the target. Usable in
+semihosting-user-cmd-0x10* event handlers, returning a string.
+
+When the target makes semihosting call with operation number from range 0x100-
+0x107, an optional string parameter can be passed to the server. This parameter
+is valid during the run of the event handlers and is accessible with this
+command.
+@end deffn
+
 @section ARMv4 and ARMv5 Architecture
 @cindex ARMv4
 @cindex ARMv5
index 792474acf0de7eb66a5b3cadce4f20ddaf45f2bf..507d1cd2c4580f80687288132326cf5582e39c31 100644 (file)
@@ -367,10 +367,13 @@ 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->op >= 0x100 && semihosting->op <= 0x107)) {
+
                        *retval = semihosting_common(target);
                        if (*retval != ERROR_OK) {
-                               LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
+                               LOG_ERROR("Failed semihosting operation (0x%02X)",
+                                               semihosting->op);
                                return 0;
                        }
                } else {
index b347212d3417f9e2fd336788f2b0c17ced310a86..1dd8e7791a5e5cc66ca75a298559fa9648d66870 100644 (file)
@@ -140,7 +140,9 @@ semihosting_result_t riscv_semihosting(struct target *target, int *retval)
                semihosting->word_size_bytes = riscv_xlen(target) / 8;
 
                /* Check for ARM operation numbers. */
-               if (semihosting->op >= 0 && semihosting->op <= 0x31) {
+               if ((semihosting->op >= 0 && semihosting->op <= 0x31) ||
+                       (semihosting->op >= 0x100 && semihosting->op <= 0x107)) {
+
                        *retval = semihosting_common(target);
                        if (*retval != ERROR_OK) {
                                LOG_ERROR("Failed semihosting operation (0x%02X)", semihosting->op);
index 8d3f66ca530e528b5a5803d1e687d6a7eccdf373..9e60de5722123955c4ac7456adaa2ff15d3c17fa 100644 (file)
@@ -154,6 +154,12 @@ int semihosting_common_init(struct target *target, void *setup,
        return ERROR_OK;
 }
 
+/**
+ * User operation parameter string storage buffer. Contains valid data when the
+ * TARGET_EVENT_SEMIHOSTING_USER_CMD_xxxxx event callbacks are running.
+ */
+static char *semihosting_user_op_params;
+
 /**
  * Portable implementation of ARM semihosting calls.
  * Performs the currently pending semihosting operation
@@ -183,7 +189,7 @@ int semihosting_common(struct target *target)
        /* Enough space to hold 4 long words. */
        uint8_t fields[4*8];
 
-       LOG_DEBUG("op=0x%x, param=0x%" PRIx64, (int)semihosting->op,
+       LOG_DEBUG("op=0x%x, param=0x%" PRIx64, semihosting->op,
                semihosting->param);
 
        switch (semihosting->op) {
@@ -1278,6 +1284,71 @@ int semihosting_common(struct target *target)
                        }
                        break;
 
+               case SEMIHOSTING_USER_CMD_0x100 ... SEMIHOSTING_USER_CMD_0x107:
+                       /**
+                        * This is a user defined operation (while user cmds 0x100-0x1ff
+                        * are possible, only 0x100-0x107 are currently implemented).
+                        *
+                        * Reads the user operation parameters from target, then fires the
+                        * corresponding target event. When the target callbacks returned,
+                        * cleans up the command parameter buffer.
+                        *
+                        * Entry
+                        * On entry, the PARAMETER REGISTER contains a pointer to a
+                        * two-field data block:
+                        * - field 1 Contains a pointer to the bound command parameter
+                        * string
+                        * - field 2 Contains the command parameter string length
+                        *
+                        * Return
+                        * On exit, the RETURN REGISTER contains the return status.
+                        */
+               {
+                       assert(!semihosting_user_op_params);
+
+                       retval = semihosting_read_fields(target, 2, fields);
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Failed to read fields for user defined command"
+                                               " op=0x%x", semihosting->op);
+                               return retval;
+                       }
+
+                       uint64_t addr = semihosting_get_field(target, 0, fields);
+
+                       size_t len = semihosting_get_field(target, 1, fields);
+                       if (len > SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH) {
+                               LOG_ERROR("The maximum length for user defined command "
+                                               "parameter is %u, received length is %zu (op=0x%x)",
+                                               SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH,
+                                               len,
+                                               semihosting->op);
+                               return ERROR_FAIL;
+                       }
+
+                       semihosting_user_op_params = malloc(len + 1);
+                       if (!semihosting_user_op_params)
+                               return ERROR_FAIL;
+                       semihosting_user_op_params[len] = 0;
+
+                       retval = target_read_buffer(target, addr, len,
+                                       (uint8_t *)(semihosting_user_op_params));
+                       if (retval != ERROR_OK) {
+                               LOG_ERROR("Failed to read from target, semihosting op=0x%x",
+                                               semihosting->op);
+                               free(semihosting_user_op_params);
+                               semihosting_user_op_params = NULL;
+                               return retval;
+                       }
+
+                       target_handle_event(target, semihosting->op);
+                       free(semihosting_user_op_params);
+                       semihosting_user_op_params = NULL;
+
+                       semihosting->result = 0;
+                       break;
+               }
+
+
                case SEMIHOSTING_SYS_ELAPSED:   /* 0x30 */
                /*
                 * Returns the number of elapsed target ticks since execution
@@ -1624,6 +1695,30 @@ COMMAND_HANDLER(handle_common_semihosting_resumable_exit_command)
        return ERROR_OK;
 }
 
+COMMAND_HANDLER(handle_common_semihosting_read_user_param_command)
+{
+       struct target *target = get_current_target(CMD_CTX);
+       struct semihosting *semihosting = target->semihosting;
+
+       if (CMD_ARGC)
+               return ERROR_COMMAND_SYNTAX_ERROR;
+
+       if (!semihosting->is_active) {
+               LOG_ERROR("semihosting not yet enabled for current target");
+               return ERROR_FAIL;
+       }
+
+       if (!semihosting_user_op_params) {
+               LOG_ERROR("This command is usable only from a registered user "
+                               "semihosting event callback.");
+               return ERROR_FAIL;
+       }
+
+       command_print_sameline(CMD, "%s", semihosting_user_op_params);
+
+       return ERROR_OK;
+}
+
 const struct command_registration semihosting_common_handlers[] = {
        {
                "semihosting",
@@ -1653,5 +1748,12 @@ const struct command_registration semihosting_common_handlers[] = {
                .usage = "['enable'|'disable']",
                .help = "activate support for semihosting resumable exit",
        },
+       {
+               "semihosting_read_user_param",
+               .handler = handle_common_semihosting_read_user_param_command,
+               .mode = COMMAND_EXEC,
+               .usage = "",
+               .help = "read parameters in semihosting-user-cmd-0x10X callbacks",
+       },
        COMMAND_REGISTRATION_DONE
 };
index b83464ed5a49a19915f49905c1204089fec18e9b..6eb9ca2527aee52d12e3d7ae1f19e9e2377a5f0d 100644 (file)
@@ -75,8 +75,14 @@ enum semihosting_operation_numbers {
        SEMIHOSTING_SYS_WRITE = 0x05,
        SEMIHOSTING_SYS_WRITEC = 0x03,
        SEMIHOSTING_SYS_WRITE0 = 0x04,
+       SEMIHOSTING_USER_CMD_0x100 = 0x100, /* First user cmd op code */
+       SEMIHOSTING_USER_CMD_0x107 = 0x107, /* Last supported user cmd op code */
+       SEMIHOSTING_USER_CMD_0x1FF = 0x1FF, /* Last user cmd op code */
 };
 
+/** Maximum allowed Tcl command segment length in bytes*/
+#define SEMIHOSTING_MAX_TCL_COMMAND_FIELD_LENGTH (1024 * 1024)
+
 /*
  * Codes used by SEMIHOSTING_SYS_EXIT (formerly
  * SEMIHOSTING_REPORT_EXCEPTION).
index 7cdd8d83029c825391303aa0d8f2bddbd9a480a6..acfbd3df5c85a0e1e56e182d9e2e27dcff6e98e4 100644 (file)
@@ -236,6 +236,15 @@ static const struct jim_nvp nvp_target_event[] = {
 
        { .value = TARGET_EVENT_TRACE_CONFIG, .name = "trace-config" },
 
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100, .name = "semihosting-user-cmd-0x100" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101, .name = "semihosting-user-cmd-0x101" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102, .name = "semihosting-user-cmd-0x102" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103, .name = "semihosting-user-cmd-0x103" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104, .name = "semihosting-user-cmd-0x104" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105, .name = "semihosting-user-cmd-0x105" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106, .name = "semihosting-user-cmd-0x106" },
+       { .value = TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107, .name = "semihosting-user-cmd-0x107" },
+
        { .name = NULL, .value = -1 }
 };
 
index 6ef8f10e0719396b027cd2f50edd9e9a0b41c3d0..974630f178555016dbbdf4c683d634f2b08067ae 100644 (file)
@@ -294,6 +294,15 @@ enum target_event {
        TARGET_EVENT_GDB_FLASH_WRITE_END,
 
        TARGET_EVENT_TRACE_CONFIG,
+
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x100 = 0x100, /* semihosting allows user cmds from 0x100 to 0x1ff */
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x101 = 0x101,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x102 = 0x102,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x103 = 0x103,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x104 = 0x104,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x105 = 0x105,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x106 = 0x106,
+       TARGET_EVENT_SEMIHOSTING_USER_CMD_0x107 = 0x107,
 };
 
 struct target_event_action {

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)