aboutsummaryrefslogtreecommitdiff
path: root/src/target
diff options
context:
space:
mode:
Diffstat (limited to 'src/target')
-rw-r--r--src/target/arm_semihosting.c7
-rw-r--r--src/target/riscv/riscv_semihosting.c4
-rw-r--r--src/target/semihosting_common.c104
-rw-r--r--src/target/semihosting_common.h6
-rw-r--r--src/target/target.c9
-rw-r--r--src/target/target.h9
6 files changed, 135 insertions, 4 deletions
diff --git a/src/target/arm_semihosting.c b/src/target/arm_semihosting.c
index 792474a..507d1cd 100644
--- a/src/target/arm_semihosting.c
+++ b/src/target/arm_semihosting.c
@@ -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 {
diff --git a/src/target/riscv/riscv_semihosting.c b/src/target/riscv/riscv_semihosting.c
index b347212..1dd8e77 100644
--- a/src/target/riscv/riscv_semihosting.c
+++ b/src/target/riscv/riscv_semihosting.c
@@ -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);
diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c
index 8d3f66c..9e60de5 100644
--- a/src/target/semihosting_common.c
+++ b/src/target/semihosting_common.c
@@ -155,6 +155,12 @@ int semihosting_common_init(struct target *target, void *setup,
}
/**
+ * 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
* encoded in target->semihosting.
@@ -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
};
diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h
index b83464e..6eb9ca2 100644
--- a/src/target/semihosting_common.h
+++ b/src/target/semihosting_common.h
@@ -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).
diff --git a/src/target/target.c b/src/target/target.c
index 7cdd8d8..acfbd3d 100644
--- a/src/target/target.c
+++ b/src/target/target.c
@@ -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 }
};
diff --git a/src/target/target.h b/src/target/target.h
index 6ef8f10..974630f 100644
--- a/src/target/target.h
+++ b/src/target/target.h
@@ -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 {