/* * Copyright (c) 2019 Jan Van Winkel * Copyright (c) 2025 Nordic Semiconductor ASA * * SPDX-License-Identifier: Apache-2.0 */ #include #include #include #include "cmdline.h" #include "soc.h" #include "fuse_fs_access_bottom.h" #define NUMBER_OF_OPEN_FILES 128 static struct fs_file_t files[NUMBER_OF_OPEN_FILES]; static uint8_t file_handles[NUMBER_OF_OPEN_FILES]; static const char default_fuse_mountpoint[] = "flash"; static const char *fuse_mountpoint; static ssize_t get_new_file_handle(void) { size_t idx; for (idx = 0; idx < ARRAY_SIZE(file_handles); ++idx) { if (file_handles[idx] == 0) { ++file_handles[idx]; return idx; } } return -ENOMEM; } static void release_file_handle(size_t handle) { if (handle < ARRAY_SIZE(file_handles)) { --file_handles[handle]; } } static int ffa_stat_top(const char *path, struct ffa_dirent *entry_bottom) { struct fs_dirent entry; int err; err = fs_stat(path, &entry); if (err != 0) { return nsi_errno_to_mid(-err); } entry_bottom->size = entry.size; if (entry.type == FS_DIR_ENTRY_DIR) { entry_bottom->is_directory = true; } else { entry_bottom->is_directory = false; } return 0; } static int ffa_readmount_top(int *mnt_nbr, const char **mnt_name) { int err = fs_readmount(mnt_nbr, mnt_name); return nsi_errno_to_mid(-err); } /* Status shared between readdir_* calls */ static struct { struct fs_dir_t dir; struct fs_dirent entry; } readdir_status; static int ffa_readdir_start(const char *path) { int err; fs_dir_t_init(&readdir_status.dir); err = fs_opendir(&readdir_status.dir, path); return nsi_errno_to_mid(-err); } static int ffa_readdir_read_next(struct ffa_dirent *entry_bottom) { int err; err = fs_readdir(&readdir_status.dir, &readdir_status.entry); if (err) { return nsi_errno_to_mid(-err); } entry_bottom->name = readdir_status.entry.name; entry_bottom->size = readdir_status.entry.size; if (readdir_status.entry.type == FS_DIR_ENTRY_DIR) { entry_bottom->is_directory = true; } else { entry_bottom->is_directory = false; } return 0; } static void ffa_readdir_end(void) { (void)fs_closedir(&readdir_status.dir); } static int ffa_create_top(const char *path, uint64_t *fh) { int err; ssize_t handle; handle = get_new_file_handle(); if (handle < 0) { return nsi_errno_to_mid(-handle); } *fh = handle; err = fs_open(&files[handle], path, FS_O_CREATE | FS_O_WRITE); if (err != 0) { release_file_handle(handle); *fh = INVALID_FILE_HANDLE; return nsi_errno_to_mid(-err); } return 0; } static int ffa_release_top(uint64_t fh) { fs_close(&files[fh]); release_file_handle(fh); return 0; } static int ffa_read_top(uint64_t fh, char *buf, size_t size, off_t off) { int err; err = fs_seek(&files[fh], off, FS_SEEK_SET); if (err == 0) { err = fs_read(&files[fh], buf, size); } return nsi_errno_to_mid(-err); } static int ffa_write_top(uint64_t fh, const char *buf, size_t size, off_t off) { int err; err = fs_seek(&files[fh], off, FS_SEEK_SET); if (err == 0) { err = fs_write(&files[fh], buf, size); } return nsi_errno_to_mid(-err); } static int ffa_ftruncate_top(uint64_t fh, off_t size) { int err = fs_truncate(&files[fh], size); return nsi_errno_to_mid(-err); } static int ffa_truncate_top(const char *path, off_t size) { int err; static struct fs_file_t file; err = fs_open(&file, path, FS_O_CREATE | FS_O_WRITE); if (err != 0) { return nsi_errno_to_mid(-err); } err = fs_truncate(&file, size); if (err != 0) { fs_close(&file); } else { err = fs_close(&file); } return nsi_errno_to_mid(-err); } static int ffa_mkdir_top(const char *path) { int err = fs_mkdir(path); return nsi_errno_to_mid(-err); } static int ffa_unlink_top(const char *path) { int err = fs_unlink(path); return nsi_errno_to_mid(-err); } struct ffa_op_callbacks op_callbacks = { .readdir_start = ffa_readdir_start, .readdir_read_next = ffa_readdir_read_next, .readdir_end = ffa_readdir_end, .stat = ffa_stat_top, .readmount = ffa_readmount_top, .mkdir = ffa_mkdir_top, .create = ffa_create_top, .release = ffa_release_top, .read = ffa_read_top, .write = ffa_write_top, .ftruncate = ffa_ftruncate_top, .truncate = ffa_truncate_top, .unlink = ffa_unlink_top, .rmdir = ffa_unlink_top, }; static void fuse_top_dispath_thread(void *arg1, void *arg2, void *arg3) { ARG_UNUSED(arg1); ARG_UNUSED(arg2); ARG_UNUSED(arg3); #define COOLDOWN_TIME 10 int cooldown_count = 0; while (true) { if (ffa_is_op_pended()) { ffa_run_pending_op(); cooldown_count = COOLDOWN_TIME; } else { if (cooldown_count > 0) { k_sleep(K_MSEC(1)); cooldown_count--; } else { k_sleep(K_MSEC(20)); } } } } K_THREAD_DEFINE(fuse_op_handler, CONFIG_ARCH_POSIX_RECOMMENDED_STACK_SIZE, fuse_top_dispath_thread, NULL, NULL, NULL, 100, 0, 0); static void fuse_fs_access_init(void) { size_t i = 0; while (i < ARRAY_SIZE(files)) { fs_file_t_init(&files[i]); ++i; } if (fuse_mountpoint == NULL) { fuse_mountpoint = default_fuse_mountpoint; } ffsa_init_bottom(fuse_mountpoint, &op_callbacks); } static void fuse_fs_access_cleanup(void) { if (fuse_mountpoint == NULL) { return; } ffsa_cleanup_bottom(fuse_mountpoint); } static void fuse_fs_access_options(void) { static struct args_struct_t fuse_fs_access_options[] = { { .manual = false, .is_mandatory = false, .is_switch = false, .option = "flash-mount", .name = "path", .type = 's', .dest = (void *)&fuse_mountpoint, .call_when_found = NULL, .descript = "Path to the directory where to mount flash" }, ARG_TABLE_ENDMARKER }; native_add_command_line_opts(fuse_fs_access_options); } NATIVE_TASK(fuse_fs_access_options, PRE_BOOT_1, 1); NATIVE_TASK(fuse_fs_access_init, PRE_BOOT_2, 1); NATIVE_TASK(fuse_fs_access_cleanup, ON_EXIT, 1);