From 0fc0254734ae550f977c3d2d73550ee98a568c1c Mon Sep 17 00:00:00 2001 From: Erhan Kurubas Date: Thu, 10 Mar 2022 11:44:42 +0100 Subject: [PATCH] semihosting: version 2 --- components/riscv/include/riscv/semihosting.h | 33 ++--------- components/vfs/openocd_semihosting.h | 56 +++++++++++++++++-- components/vfs/vfs_semihost.c | 18 ------ .../xtensa/include/xtensa/semihosting.h | 47 ++-------------- 4 files changed, 61 insertions(+), 93 deletions(-) diff --git a/components/riscv/include/riscv/semihosting.h b/components/riscv/include/riscv/semihosting.h index d5402964b0..5330161d72 100644 --- a/components/riscv/include/riscv/semihosting.h +++ b/components/riscv/include/riscv/semihosting.h @@ -19,7 +19,7 @@ extern "C" { * @param addr address of apptrace control data block * @return return 0 on sucess or non-zero error code */ -#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x64 +#define ESP_SEMIHOSTING_SYS_APPTRACE_INIT 0x101 /** * @brief Initialize debug stubs table at host side @@ -27,7 +27,7 @@ extern "C" { * @param addr address of debug stubs table * @return return 0 on sucess or non-zero error code */ -#define ESP_SEMIHOSTING_SYS_DBG_STUBS_INIT 0x65 +#define ESP_SEMIHOSTING_SYS_DBG_STUBS_INIT 0x102 /** * @brief Set/clear breakpoint @@ -37,7 +37,7 @@ extern "C" { * @param addr address to set breakpoint at. Ignored if `set` is false. * @return return 0 on sucess or non-zero error code */ -#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x66 +#define ESP_SEMIHOSTING_SYS_BREAKPOINT_SET 0x103 /** * @brief Set/clear watchpoint @@ -49,7 +49,7 @@ extern "C" { * @param flags watchpoint flags, see description below. Ignored if `set` is false. * @return return 0 on sucess or non-zero error code */ -#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x67 +#define ESP_SEMIHOSTING_SYS_WATCHPOINT_SET 0x104 /* bit values for `flags` argument of ESP_SEMIHOSTING_SYS_WATCHPOINT_SET call. Can be ORed. */ /* watch for 'reads' at `addr` */ @@ -85,31 +85,6 @@ static inline long semihosting_call_noerrno(long id, long *data) return a0; } -/** - * @brief Perform semihosting call and retrieve errno - * - * @param id semihosting call number - * @param data data block to pass to the host; number of items and their - * meaning depends on the semihosting call. See the spec for - * details. - * @param[out] out_errno output, errno value from the host. Only set if - * the return value is negative. - * @return return value from the host - */ -static inline long semihosting_call(long id, long *data, int *out_errno) -{ - long ret = semihosting_call_noerrno(id, data); - if (ret < 0) { - /* Constant also defined in openocd_semihosting.h, - * which is common for RISC-V and Xtensa; it is not included here - * to avoid a circular dependency. - */ - const int semihosting_sys_errno = 0x13; - *out_errno = (int) semihosting_call_noerrno(semihosting_sys_errno, NULL); - } - return ret; -} - #ifdef __cplusplus } #endif diff --git a/components/vfs/openocd_semihosting.h b/components/vfs/openocd_semihosting.h index fe829210e8..319df3bd85 100644 --- a/components/vfs/openocd_semihosting.h +++ b/components/vfs/openocd_semihosting.h @@ -66,8 +66,56 @@ extern "C" { * * If the syscall is recognized, the return value is zero. */ -#define SEMIHOSTING_SYS_DRVINFO 0xE0 +#define ESP_SEMIHOSTING_SYS_DRV_INFO 0x100 +/* 0x101...0x104 used by RiscV for custom semihosting calls */ + +/* Other Espressif extension sys calls */ +#define ESP_SEMIHOSTING_SYS_SEEK 0x105 /* custom lseek with whence */ +/* not implemented yet */ +#define ESP_SEMIHOSTING_SYS_MKDIR 0x106 +#define ESP_SEMIHOSTING_SYS_OPENDIR 0x107 +#define ESP_SEMIHOSTING_SYS_READDIR 0x108 +#define ESP_SEMIHOSTING_SYS_READDIR_R 0x109 +#define ESP_SEMIHOSTING_SYS_SEEKDIR 0x10A +#define ESP_SEMIHOSTING_SYS_TELLDIR 0x10B +#define ESP_SEMIHOSTING_SYS_CLOSEDIR 0x10C +#define ESP_SEMIHOSTING_SYS_RMDIR 0x10D +#define ESP_SEMIHOSTING_SYS_ACCESS 0x10E +#define ESP_SEMIHOSTING_SYS_TRUNCATE 0x10F +#define ESP_SEMIHOSTING_SYS_UTIME 0x110 +#define ESP_SEMIHOSTING_SYS_FSTAT 0x111 +#define ESP_SEMIHOSTING_SYS_STAT 0x112 +#define ESP_SEMIHOSTING_SYS_FSYNC 0x113 +#define ESP_SEMIHOSTING_SYS_LINK 0x114 +#define ESP_SEMIHOSTING_SYS_UNLINK 0x115 + +/* Semihosting version bumped to 2. + In this version, memory based approach implemented as defined in the ARM standard. + Also user defined syscall numbers enumerated between 0x100-0x1FF +*/ +#define SEMIHOSTING_DRV_VERSION 2 + +/** + * @brief Perform semihosting call and retrieve errno + * + * @param id semihosting call number + * @param data data block to pass to the host; number of items and their + * meaning depends on the semihosting call. See the spec for + * details. + * @param[out] out_errno output, errno value from the host. Only set if + * the return value is negative. + * @return return value from the host + */ +static inline long semihosting_call(long id, long *data, int *out_errno) +{ + long ret = semihosting_call_noerrno(id, data); + if (ret < 0) { + const int semihosting_sys_errno = SEMIHOSTING_SYS_ERRNO; + *out_errno = (int) semihosting_call_noerrno(semihosting_sys_errno, NULL); + } + return ret; +} static inline int semihosting_open(const char *path, int open_mode, int mode) { @@ -126,7 +174,7 @@ static inline off_t semihosting_seek(int fd, off_t offset, int mode) { int host_errno = 0; long args[] = {fd, offset, mode, 0}; - off_t ret = (off_t) semihosting_call(SEMIHOSTING_SYS_SEEK, args, &host_errno); + off_t ret = (off_t) semihosting_call(ESP_SEMIHOSTING_SYS_SEEK, args, &host_errno); if (ret == -1) { errno = host_errno; } @@ -138,9 +186,9 @@ static inline int semihosting_ver_info(void) int host_errno = 0; struct { int version; - } ver_info = { 1 }; + } ver_info = { SEMIHOSTING_DRV_VERSION }; long args[] = {(long) &ver_info, sizeof(ver_info), 0, 0}; - int ret = (int) semihosting_call(SEMIHOSTING_SYS_DRVINFO, args, &host_errno); + int ret = (int) semihosting_call(ESP_SEMIHOSTING_SYS_DRV_INFO, args, &host_errno); (void) host_errno; /* errno not set by this call */ return ret; } diff --git a/components/vfs/vfs_semihost.c b/components/vfs/vfs_semihost.c index d9cd4bf65f..9ab4b4239f 100644 --- a/components/vfs/vfs_semihost.c +++ b/components/vfs/vfs_semihost.c @@ -100,7 +100,6 @@ static inline bool ctx_uses_abspath(const vfs_semihost_ctx_t* ctx) } \ } while(0) -#if __XTENSA__ static esp_err_t vfs_semihost_drvinfo(vfs_semihost_ctx_t *ctx) { FAIL_IF_NO_DEBUGGER(); @@ -112,7 +111,6 @@ static esp_err_t vfs_semihost_drvinfo(vfs_semihost_ctx_t *ctx) } return ESP_OK; } -#endif // __XTENSA__ static int vfs_semihost_open(void* ctx, const char* path, int flags, int mode) { @@ -151,20 +149,6 @@ static int vfs_semihost_open(void* ctx, const char* path, int flags, int mode) #endif // __XTENSA__ } else { host_path = (char *)path; - /* For Xtensa targets in OpenOCD there is additional logic related to - * semihosting paths handling that isn't there for other targets. - * When ESP_SEMIHOST_BASEDIR OpenOCD variable is not set, OpenOCD will - * by default prepend '.' to the path passed from the target. - * By contrast, for RISC-V there is no such logic and the path will be - * used as is, no matter whether it is absolute or relative. - * See esp_xtensa_semihosting_get_file_name in esp_xtensa_semihosting.c - * for details. - */ -#ifndef __XTENSA__ - if (*host_path == '/') { - ++host_path; - } -#endif // !__XTENSA__ } /* everything is ready: syscall and cleanup */ ret_fd = semihosting_open(host_path, o_mode, mode); @@ -241,13 +225,11 @@ esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path ESP_LOGD(TAG, "Register semihosting driver %d %p", i, &s_semhost_ctx[i]); esp_err_t err; -#if __XTENSA__ /* Check for older OpenOCD versions */ err = vfs_semihost_drvinfo(&s_semhost_ctx[i]); // define semihosting version if (err != ESP_OK) { ESP_LOGE(TAG, "Incompatible OpenOCD version detected. Please follow the getting started guides to install the required version."); } -#endif // __XTENSA__ err = esp_vfs_register(base_path, &vfs, &s_semhost_ctx[i]); if (err != ESP_OK) { diff --git a/components/xtensa/include/xtensa/semihosting.h b/components/xtensa/include/xtensa/semihosting.h index 71a23bb563..8a43605a18 100644 --- a/components/xtensa/include/xtensa/semihosting.h +++ b/components/xtensa/include/xtensa/semihosting.h @@ -10,53 +10,16 @@ extern "C" { #endif -/** - * @brief Perform semihosting call and retrieve errno - * - * @param id semihosting call number - * @param data data block to pass to the host; number of items and their - * meaning depends on the semihosting call. See the spec for - * details. - * On Xtensa, this function assumes that the array contains at - * least 4 elements, but no effort is made to guarantee that. - * Passing a shorter array will still work, as long as it contains - * sufficient values for the corresponding semihosting call. - * @param[out] out_errno output, errno value from the host. Only set if - * the return value is negative. - * @return return value from the host - */ -static inline long semihosting_call(long id, long *data, int *out_errno) // NOLINT(readability-non-const-parameter) +static inline long semihosting_call_noerrno(long id, long *data) { - /* GCC doesn't allow using specific register names in constraints for Xtensa. - * For this case, GCC extended inline assembly manual says the following: - * If you must use a specific register, but your Machine Constraints do not provide - * sufficient control to select the specific register you want, local register variables - * may provide a solution. - * Using local register variables results in simpler generated code than - * the previous implementation which listed a2-a6 as clobbered registers. - */ register long a2 asm ("a2") = id; - register long a3 asm ("a3") = (long) data[0]; - register long a4 asm ("a4") = (long) data[1]; - register long a5 asm ("a5") = (long) data[2]; - register long a6 asm ("a6") = (long) data[3]; + register long a3 asm ("a3") = (long)data; - /* The break instruction operands should be (1, 14) according to the ISA manual. - * We keep (1, 1) for compatibility, until OpenOCD is updated to support both - * conventions. - */ __asm__ __volatile__ ( - "break 1, 1\n" - : "+r"(a2), "+r"(a3) - : "r"(a4), "r"(a5), "r"(a6) + "break 1, 14\n" + : "+r"(a2) : "r"(a3) : "memory"); - - long host_ret = a2; - long host_errno = a3; - if (host_ret < 0) { - *out_errno = host_errno; - } - return host_ret; + return a2; } #ifdef __cplusplus