diff --git a/components/vfs/Kconfig b/components/vfs/Kconfig index 6b914d8ba3..d3954cb378 100644 --- a/components/vfs/Kconfig +++ b/components/vfs/Kconfig @@ -80,15 +80,6 @@ menu "Virtual file system" default 1 help Define maximum number of host filesystem mount points. - - config VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN - int "Host FS: Maximum path length for the host base directory" - default 128 - help - Define maximum path length for the host base directory which is to be mounted. - If host path passed to esp_vfs_semihost_register() is longer than this value - it will be truncated. - endmenu endmenu diff --git a/components/vfs/include/esp_vfs_semihost.h b/components/vfs/include/esp_vfs_semihost.h index 20a0ed5506..c6db970be7 100644 --- a/components/vfs/include/esp_vfs_semihost.h +++ b/components/vfs/include/esp_vfs_semihost.h @@ -1,16 +1,8 @@ -// Copyright 2019 Espressif Systems (Shanghai) PTE LTD -// -// Licensed under the Apache License, Version 2.0 (the "License"); -// you may not use this file except in compliance with the License. -// You may obtain a copy of the License at -// -// http://www.apache.org/licenses/LICENSE-2.0 -// -// Unless required by applicable law or agreed to in writing, software -// distributed under the License is distributed on an "AS IS" BASIS, -// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. -// See the License for the specific language governing permissions and -// limitations under the License. +/* + * SPDX-FileCopyrightText: 2019-2022 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ #pragma once @@ -24,13 +16,12 @@ extern "C" { * @brief add virtual filesystem semihosting driver * * @param base_path VFS path to mount host directory - * @param host_path host path to mount; if NULL default dirctory will be used (see OpenOCD configuration) * @return * - ESP_OK on success * - ESP_ERR_INVALID_ARG if esp_vfs_semihost_register was already called for specified VFS path * - ESP_ERR_NO_MEM if there are no slots to register new mount point */ -esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path); +esp_err_t esp_vfs_semihost_register(const char* base_path); /** * @brief Un-register semihosting driver from VFS diff --git a/components/vfs/openocd_semihosting.h b/components/vfs/openocd_semihosting.h index 319df3bd85..32dfeb75a9 100644 --- a/components/vfs/openocd_semihosting.h +++ b/components/vfs/openocd_semihosting.h @@ -90,9 +90,11 @@ extern "C" { #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 +/* Semihosting version bumped to 2. Changelog; + 1 - Memory based approach with 2 registers implemented as defined in the ARM standard. + 2 - User defined syscall numbers located between 0x100-0x1FF + 3 - The break instruction operands updated to (1, 14) + 4 - Absolute path support is dropped */ #define SEMIHOSTING_DRV_VERSION 2 diff --git a/components/vfs/vfs_semihost.c b/components/vfs/vfs_semihost.c index fac48e6907..2510262225 100644 --- a/components/vfs/vfs_semihost.c +++ b/components/vfs/vfs_semihost.c @@ -28,21 +28,11 @@ #define CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS 1 #endif -#ifndef CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN -#define CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN 128 -#endif - const static char *TAG = "esp_semihost"; /* Additional open flags */ - -/* ESP-specific file open flag. - * Indicates that path passed to open() is absolute host path. - */ -#define ESP_O_SEMIHOST_ABSPATH 0x80000000 - /* There is no O_BINARY flag defined in newlib, as well as on Linux, * but we are leaving it to have the flags table identical to OpenOCD. */ @@ -50,18 +40,18 @@ const static char *TAG = "esp_semihost"; /* The table is identical to the one in OpenOCD semihosting_common.c */ static const int open_modeflags[12] = { - O_RDONLY, - O_RDONLY | O_BINARY, - O_RDWR, - O_RDWR | O_BINARY, - O_WRONLY | O_CREAT | O_TRUNC, - O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, - O_RDWR | O_CREAT | O_TRUNC, - O_RDWR | O_CREAT | O_TRUNC | O_BINARY, - O_WRONLY | O_CREAT | O_APPEND, - O_WRONLY | O_CREAT | O_APPEND | O_BINARY, - O_RDWR | O_CREAT | O_APPEND, - O_RDWR | O_CREAT | O_APPEND | O_BINARY + O_RDONLY, + O_RDONLY | O_BINARY, + O_RDWR, + O_RDWR | O_BINARY, + O_WRONLY | O_CREAT | O_TRUNC, + O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, + O_RDWR | O_CREAT | O_TRUNC, + O_RDWR | O_CREAT | O_TRUNC | O_BINARY, + O_WRONLY | O_CREAT | O_APPEND, + O_WRONLY | O_CREAT | O_APPEND | O_BINARY, + O_RDWR | O_CREAT | O_APPEND, + O_RDWR | O_CREAT | O_APPEND | O_BINARY }; /** @@ -86,7 +76,6 @@ static inline int get_o_mode(int flags) { typedef struct { char base_path[ESP_VFS_PATH_MAX + 1]; /* base path in VFS where host semihosting dir is mounted */ - char host_path[CONFIG_VFS_SEMIHOSTFS_HOST_PATH_MAX_LEN + 1]; /* host path to use as base dir for open files */ } vfs_semihost_ctx_t; static vfs_semihost_ctx_t s_semhost_ctx[CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS]; @@ -96,11 +85,6 @@ static inline bool ctx_is_unused(const vfs_semihost_ctx_t* ctx) return ctx->base_path[0] == 0; } -static inline bool ctx_uses_abspath(const vfs_semihost_ctx_t* ctx) -{ - return ctx->host_path[0]; -} - #define FAIL_IF_NO_DEBUGGER() \ do { \ if (!cpu_hal_is_debugger_attached()) { \ @@ -124,46 +108,21 @@ static esp_err_t vfs_semihost_drvinfo(vfs_semihost_ctx_t *ctx) static int vfs_semihost_open(void* ctx, const char* path, int flags, int mode) { int ret_fd = -1; - char *host_path; - vfs_semihost_ctx_t *semi_ctx = ctx; + FAIL_IF_NO_DEBUGGER(); - ESP_LOGV(TAG, "%s: %p '%s 0x%x 0x%x'", __func__, semi_ctx, path, flags, mode); + if (path == NULL) { + errno = ENOENT; + return ret_fd; + } + + ESP_LOGV(TAG, "%s: '%s 0x%x 0x%x'", __func__, path, flags, mode); int o_mode = get_o_mode(flags); if (o_mode == -1) { /* if wrong flags - error */ errno = EINVAL; } else { - if (ctx_uses_abspath(semi_ctx)) { - /* Create full absolute path on the host by concatenating host base - * path and file path relative to the filesystem root. - */ - host_path = malloc(strlen(semi_ctx->host_path) + strlen(path) + 1); - if (host_path == NULL) { /* if no valid pointer - error and return */ - errno = ENOMEM; - return -1; - } - strcpy(host_path, semi_ctx->host_path); - strcat(host_path, path); -#ifdef __XTENSA__ - /* By default, OpenOCD for Xtensa prepends ESP_SEMIHOST_BASEDIR to - * the path passed from the target. Adding this special flag to o_mode - * inhibits this behavior. - * This is not necessary for RISC-V since standard semihosting - * implementation is used there and paths aren't mangled on OpenOCD side. - */ - if (ctx_uses_abspath(semi_ctx)) { - o_mode |= ESP_O_SEMIHOST_ABSPATH; - } -#endif // __XTENSA__ - } else { - host_path = (char *)path; - } - /* everything is ready: syscall and cleanup */ - ret_fd = semihosting_open(host_path, o_mode, mode); - if (ctx_uses_abspath(semi_ctx)) { - free(host_path); - } + ret_fd = semihosting_open(path, o_mode, mode); } return ret_fd; } @@ -172,6 +131,11 @@ static ssize_t vfs_semihost_write(void* ctx, int fd, const void * data, size_t s { FAIL_IF_NO_DEBUGGER(); + if (data == NULL) { + errno = EINVAL; + return -1; + } + ESP_LOGV(TAG, "%s: %d %u bytes", __func__, fd, size); return semihosting_write(fd, data, size); } @@ -180,11 +144,15 @@ static ssize_t vfs_semihost_read(void* ctx, int fd, void* data, size_t size) { FAIL_IF_NO_DEBUGGER(); + if (data == NULL) { + errno = EINVAL; + return -1; + } + ESP_LOGV(TAG, "%s: %d %u bytes", __func__, fd, size); return semihosting_read(fd, data, size); } - static int vfs_semihost_close(void* ctx, int fd) { FAIL_IF_NO_DEBUGGER(); @@ -200,8 +168,10 @@ static off_t vfs_semihost_lseek(void* ctx, int fd, off_t offset, int mode) return semihosting_seek(fd, offset, mode); } -esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path) +esp_err_t esp_vfs_semihost_register(const char* base_path) { + assert(base_path); + const esp_vfs_t vfs = { .flags = ESP_VFS_FLAG_CONTEXT_PTR, .write_p = &vfs_semihost_write, @@ -210,7 +180,7 @@ esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path .read_p = &vfs_semihost_read, .lseek_p = &vfs_semihost_lseek, }; - ESP_LOGD(TAG, "Register semihosting driver '%s' -> '%s'", base_path, host_path ? host_path : "null"); + ESP_LOGD(TAG, "Register semihosting driver '%s'", base_path); if (!cpu_hal_is_debugger_attached()) { ESP_LOGE(TAG, "OpenOCD is not connected!"); return ESP_ERR_NOT_SUPPORTED; @@ -228,9 +198,7 @@ esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path return ESP_ERR_NO_MEM; } strlcpy(s_semhost_ctx[i].base_path, base_path, sizeof(s_semhost_ctx[i].base_path) - 1); - if (host_path) { - strlcpy(s_semhost_ctx[i].host_path, host_path, sizeof(s_semhost_ctx[i].host_path) - 1); - } + ESP_LOGD(TAG, "Register semihosting driver %d %p", i, &s_semhost_ctx[i]); esp_err_t err; @@ -250,6 +218,8 @@ esp_err_t esp_vfs_semihost_register(const char* base_path, const char* host_path esp_err_t esp_vfs_semihost_unregister(const char* base_path) { + assert(base_path); + ESP_LOGD(TAG, "Unregister semihosting driver @ '%s'", base_path); int i = 0; for (i = 0; i < CONFIG_VFS_SEMIHOSTFS_MAX_MOUNT_POINTS; i++) { @@ -265,7 +235,6 @@ esp_err_t esp_vfs_semihost_unregister(const char* base_path) return ret; } s_semhost_ctx[i].base_path[0] = 0; - s_semhost_ctx[i].host_path[0] = 0; ESP_LOGD(TAG, "Unregistered semihosting driver @ '%s'", base_path); return ESP_OK; } diff --git a/components/xtensa/include/xtensa/semihosting.h b/components/xtensa/include/xtensa/semihosting.h index 8a43605a18..5849827e7c 100644 --- a/components/xtensa/include/xtensa/semihosting.h +++ b/components/xtensa/include/xtensa/semihosting.h @@ -10,6 +10,19 @@ extern "C" { #endif +/** + * @brief Perform semihosting call + * + * See ARM semihosting spec for details. + * https://static.docs.arm.com/100863/0200/semihosting.pdf + * + * @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. + * + * @return return value from the host + */ static inline long semihosting_call_noerrno(long id, long *data) { register long a2 asm ("a2") = id; diff --git a/examples/protocols/http_server/restful_server/main/esp_rest_main.c b/examples/protocols/http_server/restful_server/main/esp_rest_main.c index f0d52ca571..5bf2e3cbe5 100644 --- a/examples/protocols/http_server/restful_server/main/esp_rest_main.c +++ b/examples/protocols/http_server/restful_server/main/esp_rest_main.c @@ -47,7 +47,7 @@ static void initialise_mdns(void) #if CONFIG_EXAMPLE_WEB_DEPLOY_SEMIHOST esp_err_t init_fs(void) { - esp_err_t ret = esp_vfs_semihost_register(CONFIG_EXAMPLE_WEB_MOUNT_POINT, CONFIG_EXAMPLE_HOST_PATH_TO_MOUNT); + esp_err_t ret = esp_vfs_semihost_register(CONFIG_EXAMPLE_WEB_MOUNT_POINT); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to register semihost driver (%s)!", esp_err_to_name(ret)); return ESP_FAIL; diff --git a/examples/storage/semihost_vfs/README.md b/examples/storage/semihost_vfs/README.md index c5c1e2e750..696b9460ab 100644 --- a/examples/storage/semihost_vfs/README.md +++ b/examples/storage/semihost_vfs/README.md @@ -54,7 +54,7 @@ This example also requires [OpenOCD](https://docs.espressif.com/projects/esp-idf ### Overriding the base directory for semihosting -When the example application calls `esp_vfs_semihost_register("/host", NULL)`, the path `/host` on the ESP target is mapped to the semihosting _base directory_. By default, this is the directory where OpenOCD program is started from. In the instructions above, OpenOCD is started in `data` subdirectory of the example project. +When the example application calls `esp_vfs_semihost_register("/host")`, the path `/host` on the ESP target is mapped to the semihosting _base directory_. By default, this is the directory where OpenOCD program is started from. In the instructions above, OpenOCD is started in `data` subdirectory of the example project. When debugging with Xtensa based SoCs (ESP32, ESP32-S2, ESP32-S3) it is possible to override the semihosting base directory using an additional flag of `openocd` command. For example, on Linux and macOS: diff --git a/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c b/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c index b8bba77208..3db7d566b0 100644 --- a/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c +++ b/examples/storage/semihost_vfs/main/semihost_vfs_example_main.c @@ -26,7 +26,7 @@ static uint8_t s_buf[512]; void app_main(void) { // Register host FS at '/host'. On the host file will be written/read in the current semihosting dir of OpenOCD - esp_err_t ret = esp_vfs_semihost_register("/host", NULL); + esp_err_t ret = esp_vfs_semihost_register("/host"); if (ret != ESP_OK) { ESP_LOGE(TAG, "Failed to register semihost driver (%s)!", esp_err_to_name(ret)); return;