From f676b45151c33986501e5f8f9bcc64f4a9511089 Mon Sep 17 00:00:00 2001 From: Sean Anderson Date: Tue, 22 Mar 2022 16:59:20 -0400 Subject: [PATCH] fs: Add semihosting filesystem This adds a filesystem which is backed by the host's filesystem. It is modeled off of sandboxfs, which has very similar aims. Semihosting doesn't support listing directories (except with SYS_SYSTEM), so neither do we. it's possible to optimize a bit for the common case of reading a whole file by omitting a call to smh_seek, but this is left as a future optimization. Signed-off-by: Sean Anderson --- disk/part.c | 4 +- fs/Makefile | 1 + fs/fs.c | 20 +++++++ fs/semihostingfs.c | 115 ++++++++++++++++++++++++++++++++++++++++ include/fs.h | 1 + include/semihostingfs.h | 21 ++++++++ 6 files changed, 160 insertions(+), 2 deletions(-) create mode 100644 fs/semihostingfs.c create mode 100644 include/semihostingfs.h diff --git a/disk/part.c b/disk/part.c index 49e39a24e8..b95405bb49 100644 --- a/disk/part.c +++ b/disk/part.c @@ -455,7 +455,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, int part; struct disk_partition tmpinfo; -#ifdef CONFIG_SANDBOX +#if IS_ENABLED(CONFIG_SANDBOX) || IS_ENABLED(CONFIG_SEMIHOSTING) /* * Special-case a pseudo block device "hostfs", to allow access to the * host's own filesystem. @@ -467,7 +467,7 @@ int blk_get_device_part_str(const char *ifname, const char *dev_part_str, info->blksz = 0; info->bootable = 0; strcpy((char *)info->type, BOOT_PART_TYPE); - strcpy((char *)info->name, "Sandbox host"); + strcpy((char *)info->name, "Host filesystem"); #if CONFIG_IS_ENABLED(PARTITION_UUIDS) info->uuid[0] = 0; #endif diff --git a/fs/Makefile b/fs/Makefile index f05a21c9e6..4bed2ff2d9 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -21,6 +21,7 @@ obj-$(CONFIG_FS_FAT) += fat/ obj-$(CONFIG_FS_JFFS2) += jffs2/ obj-$(CONFIG_CMD_REISER) += reiserfs/ obj-$(CONFIG_SANDBOX) += sandbox/ +obj-$(CONFIG_SEMIHOSTING) += semihostingfs.o obj-$(CONFIG_CMD_UBIFS) += ubifs/ obj-$(CONFIG_YAFFS2) += yaffs2/ obj-$(CONFIG_CMD_ZFS) += zfs/ diff --git a/fs/fs.c b/fs/fs.c index 99dac0fd79..c3a2ed9754 100644 --- a/fs/fs.c +++ b/fs/fs.c @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #include @@ -247,6 +248,25 @@ static struct fstype_info fstypes[] = { .ln = fs_ln_unsupported, }, #endif +#ifdef CONFIG_SEMIHOSTING + { + .fstype = FS_TYPE_SEMIHOSTING, + .name = "semihosting", + .null_dev_desc_ok = true, + .probe = smh_fs_set_blk_dev, + .close = fs_close_unsupported, + .ls = fs_ls_unsupported, + .exists = fs_exists_unsupported, + .size = smh_fs_size, + .read = smh_fs_read, + .write = smh_fs_write, + .uuid = fs_uuid_unsupported, + .opendir = fs_opendir_unsupported, + .unlink = fs_unlink_unsupported, + .mkdir = fs_mkdir_unsupported, + .ln = fs_ln_unsupported, + }, +#endif #ifdef CONFIG_CMD_UBIFS { .fstype = FS_TYPE_UBIFS, diff --git a/fs/semihostingfs.c b/fs/semihostingfs.c new file mode 100644 index 0000000000..96eb3349a2 --- /dev/null +++ b/fs/semihostingfs.c @@ -0,0 +1,115 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (C) 2022, Sean Anderson + * Copyright (c) 2012, Google Inc. + */ + +#include +#include +#include +#include +#include +#include + +int smh_fs_set_blk_dev(struct blk_desc *rbdd, struct disk_partition *info) +{ + /* + * Only accept a NULL struct blk_desc for the semihosting, which is when + * hostfs interface is used + */ + return !!rbdd; +} + +static int smh_fs_read_at(const char *filename, loff_t pos, void *buffer, + loff_t maxsize, loff_t *actread) +{ + long fd, size, ret; + + fd = smh_open(filename, MODE_READ | MODE_BINARY); + if (fd < 0) + return fd; + ret = smh_seek(fd, pos); + if (ret < 0) { + smh_close(fd); + return ret; + } + if (!maxsize) { + size = smh_flen(fd); + if (ret < 0) { + smh_close(fd); + return size; + } + + maxsize = size; + } + + size = smh_read(fd, buffer, maxsize); + smh_close(fd); + if (size < 0) + return size; + + *actread = size; + return 0; +} + +static int smh_fs_write_at(const char *filename, loff_t pos, void *buffer, + loff_t towrite, loff_t *actwrite) +{ + long fd, size, ret; + + fd = smh_open(filename, MODE_READ | MODE_BINARY | MODE_PLUS); + if (fd < 0) + return fd; + ret = smh_seek(fd, pos); + if (ret < 0) { + smh_close(fd); + return ret; + } + + ret = smh_write(fd, buffer, towrite, &size); + smh_close(fd); + *actwrite = size; + return ret; +} + +int smh_fs_size(const char *filename, loff_t *result) +{ + long fd, size; + + fd = smh_open(filename, MODE_READ | MODE_BINARY); + if (fd < 0) + return fd; + + size = smh_flen(fd); + smh_close(fd); + + if (size < 0) + return size; + + *result = size; + return 0; +} + +int smh_fs_read(const char *filename, void *buf, loff_t offset, loff_t len, + loff_t *actread) +{ + int ret; + + ret = smh_fs_read_at(filename, offset, buf, len, actread); + if (ret) + printf("** Unable to read file %s **\n", filename); + + return ret; +} + +int smh_fs_write(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actwrite) +{ + int ret; + + ret = smh_fs_write_at(filename, offset, buf, len, actwrite); + if (ret) + printf("** Unable to write file %s **\n", filename); + + return ret; +} diff --git a/include/fs.h b/include/fs.h index b607b0028d..e2beba36b9 100644 --- a/include/fs.h +++ b/include/fs.h @@ -18,6 +18,7 @@ struct cmd_tbl; #define FS_TYPE_BTRFS 5 #define FS_TYPE_SQUASHFS 6 #define FS_TYPE_EROFS 7 +#define FS_TYPE_SEMIHOSTING 8 struct blk_desc; diff --git a/include/semihostingfs.h b/include/semihostingfs.h new file mode 100644 index 0000000000..25ebdbbeff --- /dev/null +++ b/include/semihostingfs.h @@ -0,0 +1,21 @@ +/* SPDX-License-Identifier: GPL-2.0+ */ +/* + * Copyright (C) 2022, Sean Anderson + * Copyright (c) 2012, Google Inc. + */ + +#ifndef __SEMIHOSTING_FS__ +#define __SEMIHOSTING_FS__ + +struct blk_desc; +struct disk_partition; + +int smh_fs_set_blk_dev(struct blk_desc *rbdd, struct disk_partition *info); +void smh_fs_close(void); +int smh_fs_size(const char *filename, loff_t *size); +int smh_fs_read(const char *filename, void *buf, loff_t offset, loff_t len, + loff_t *actread); +int smh_fs_write(const char *filename, void *buf, loff_t offset, + loff_t len, loff_t *actwrite); + +#endif