From 334a187e64121cb1f8bf6f07f5400e0e5ba8c0ff Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Tue, 5 Apr 2022 14:26:08 +0300 Subject: [PATCH] semihosting: add custom user command handler Custom user syscalls can be handled with target events in the TCL scripts. This patch gives another opportunity to handle custom syscalls in the c files. Besides that some utility functions are also exported for the custom handlers. Signed-off-by: Erhan Kurubas Change-Id: Ice13d527540a0de0b2a8abda912ae3dcff3834b7 Reviewed-on: https://review.openocd.org/c/openocd/+/6889 Tested-by: jenkins Reviewed-by: Ian Thompson Reviewed-by: Antonio Borneo --- src/target/semihosting_common.c | 34 +++++++++++++++------------------ src/target/semihosting_common.h | 18 +++++++++++++++++ 2 files changed, 33 insertions(+), 19 deletions(-) diff --git a/src/target/semihosting_common.c b/src/target/semihosting_common.c index 0a60eb1211..d54c341ac9 100644 --- a/src/target/semihosting_common.c +++ b/src/target/semihosting_common.c @@ -103,16 +103,6 @@ static int semihosting_common_fileio_info(struct target *target, static int semihosting_common_fileio_end(struct target *target, int result, int fileio_errno, bool ctrl_c); -static int semihosting_read_fields(struct target *target, size_t number, - uint8_t *fields); -static int semihosting_write_fields(struct target *target, size_t number, - uint8_t *fields); -static uint64_t semihosting_get_field(struct target *target, size_t index, - uint8_t *fields); -static void semihosting_set_field(struct target *target, uint64_t value, - size_t index, - uint8_t *fields); - /* Attempts to include gdb_server.h failed. */ extern int gdb_actual_connections; @@ -166,6 +156,7 @@ int semihosting_common_init(struct target *target, void *setup, semihosting->setup = setup; semihosting->post_result = post_result; + semihosting->user_command_extension = NULL; target->semihosting = semihosting; @@ -1467,9 +1458,14 @@ int semihosting_common(struct target *target) * Return * On exit, the RETURN REGISTER contains the return status. */ - { - assert(!semihosting_user_op_params); + if (semihosting->user_command_extension) { + retval = semihosting->user_command_extension(target); + if (retval != ERROR_NOT_IMPLEMENTED) + break; + /* If custom user command not handled, we are looking for the TCL handler */ + } + 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" @@ -1507,11 +1503,8 @@ int semihosting_common(struct target *target) 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 */ /* @@ -1670,10 +1663,13 @@ static int semihosting_common_fileio_end(struct target *target, int result, return semihosting->post_result(target); } +/* ------------------------------------------------------------------------- + * Utility functions. */ + /** * Read all fields of a command from target to buffer. */ -static int semihosting_read_fields(struct target *target, size_t number, +int semihosting_read_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1685,7 +1681,7 @@ static int semihosting_read_fields(struct target *target, size_t number, /** * Write all fields of a command from buffer to target. */ -static int semihosting_write_fields(struct target *target, size_t number, +int semihosting_write_fields(struct target *target, size_t number, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1697,7 +1693,7 @@ static int semihosting_write_fields(struct target *target, size_t number, /** * Extract a field from the buffer, considering register size and endianness. */ -static uint64_t semihosting_get_field(struct target *target, size_t index, +uint64_t semihosting_get_field(struct target *target, size_t index, uint8_t *fields) { struct semihosting *semihosting = target->semihosting; @@ -1710,7 +1706,7 @@ static uint64_t semihosting_get_field(struct target *target, size_t index, /** * Store a field in the buffer, considering register size and endianness. */ -static void semihosting_set_field(struct target *target, uint64_t value, +void semihosting_set_field(struct target *target, uint64_t value, size_t index, uint8_t *fields) { diff --git a/src/target/semihosting_common.h b/src/target/semihosting_common.h index 404080f023..1b71690302 100644 --- a/src/target/semihosting_common.h +++ b/src/target/semihosting_common.h @@ -179,6 +179,13 @@ struct semihosting { /** Base directory for semihosting I/O operations. */ char *basedir; + /** + * Target's extension of semihosting user commands. + * @returns ERROR_NOT_IMPLEMENTED when user command is not handled, otherwise + * sets semihosting->result and semihosting->sys_errno and returns ERROR_OK. + */ + int (*user_command_extension)(struct target *target); + int (*setup)(struct target *target, int enable); int (*post_result)(struct target *target); }; @@ -187,4 +194,15 @@ int semihosting_common_init(struct target *target, void *setup, void *post_result); int semihosting_common(struct target *target); +/* utility functions which may also be used by semihosting extensions (custom vendor-defined syscalls) */ +int semihosting_read_fields(struct target *target, size_t number, + uint8_t *fields); +int semihosting_write_fields(struct target *target, size_t number, + uint8_t *fields); +uint64_t semihosting_get_field(struct target *target, size_t index, + uint8_t *fields); +void semihosting_set_field(struct target *target, uint64_t value, + size_t index, + uint8_t *fields); + #endif /* OPENOCD_TARGET_SEMIHOSTING_COMMON_H */ -- 2.30.2