
From: Simon Glass <sjg@chromium.org> The existing filesystem support is fairly basic. It supports access to only one filesystem at a time, does not allow caching, does not have an equivalent of Linux's VFS and uses global variables to keep track of which one is in use. As a starting point to improving this, provide a filesystem uclass. For now it only includes operations to mount and unmount. Provide a bootdev so that it is possible to locate bootflows on a filesystem. Signed-off-by: Simon Glass <sjg@chromium.org> --- MAINTAINERS | 6 ++ fs/Kconfig | 8 +++ fs/Makefile | 1 + fs/fs-uclass.c | 113 +++++++++++++++++++++++++++++++++++++ include/dm/uclass-id.h | 1 + include/fs.h | 78 +++++++++++++++++++++++++ test/boot/bootdev.c | 3 + test/boot/bootstd_common.h | 9 +-- 8 files changed, 215 insertions(+), 4 deletions(-) create mode 100644 fs/fs-uclass.c create mode 100644 include/fs.h diff --git a/MAINTAINERS b/MAINTAINERS index b3875718bce..08b57e5306e 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1182,6 +1182,12 @@ F: net/fastboot_tcp.c F: net/fastboot_udp.c F: test/dm/fastboot.c +FILESYSTEM LAYER +M: Simon Glass <sjg@chromium.org> +S: Maintained +F: fs/fs-uclass.c +F: include/fs.h + FPGA M: Michal Simek <michal.simek@amd.com> S: Maintained diff --git a/fs/Kconfig b/fs/Kconfig index 490f9755016..f7951b483aa 100644 --- a/fs/Kconfig +++ b/fs/Kconfig @@ -4,6 +4,14 @@ menu "File systems" +config FS + bool "Support for filesystems" + default y if SANDBOX || VENDOR_EMULATION || ARCH_QEMU + depends on EXPERT + help + Provides an interface for filesystems, allowing them to be + persistently mounted. Filesystem can contain files and directory. + config FS_LEGACY def_bool y help diff --git a/fs/Makefile b/fs/Makefile index 02c32aa8287..75959d06f12 100644 --- a/fs/Makefile +++ b/fs/Makefile @@ -5,6 +5,7 @@ # Copyright (c) 2012, NVIDIA CORPORATION. All rights reserved. obj-$(CONFIG_$(PHASE_)FS_LEGACY) += fs_legacy.o fs_internal.o +obj-$(CONFIG_$(PHASE_)FS) += fs-uclass.o ifdef CONFIG_XPL_BUILD obj-$(CONFIG_SPL_FS_FAT) += fat/ diff --git a/fs/fs-uclass.c b/fs/fs-uclass.c new file mode 100644 index 00000000000..9e698972df8 --- /dev/null +++ b/fs/fs-uclass.c @@ -0,0 +1,113 @@ +// SPDX-License-Identifier: GPL-2.0 +/* + * Implementation of a filesystem, e.g. on a partition + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#define LOG_DEBUG +#define LOG_CATEGORY UCLASS_FS + +#include <bootdev.h> +#include <bootmeth.h> +#include <dm.h> +#include <fs.h> +#include <dm/device-internal.h> + +int fs_mount(struct udevice *dev) +{ + struct fs_ops *ops = fs_get_ops(dev); + int ret; + + ret = ops->mount(dev); + if (ret) + return log_msg_ret("fsm", ret); + + ret = bootdev_setup_for_dev(dev, "fs_bootdev"); + if (ret) + return log_msg_ret("fss", ret); + + return 0; +} + +int fs_unmount(struct udevice *dev) +{ + struct fs_ops *ops = fs_get_ops(dev); + + return ops->unmount(dev); +} + +static int fs_get_bootflow(struct udevice *dev, struct bootflow_iter *iter, + struct bootflow *bflow) +{ + struct udevice *fsdev = dev_get_parent(dev); + int ret; + + log_debug("get_bootflow fs '%s'\n", fsdev->name); + + ret = bootmeth_check(bflow->method, iter); + if (ret) + return log_msg_ret("check", ret); + + return 0; +} + +static int fs_bootdev_bind(struct udevice *dev) +{ + struct bootdev_uc_plat *ucp = dev_get_uclass_plat(dev); + + /* + * we don't know what priority to give this, so pick something a little + * slow for now + */ + ucp->prio = BOOTDEVP_3_INTERNAL_SLOW; + + return 0; +} + +static int fs_bootdev_hunt(struct bootdev_hunter *info, bool show) +{ + struct udevice *dev; + int ret; + + /* mount all filesystems, which will create bootdevs for each */ + uclass_foreach_dev_probe(UCLASS_FS, dev) { + ret = fs_mount(dev); + if (ret) + log_warning("Failed to mount filesystem '%s'\n", + dev->name); + } + + return 0; +} + +struct bootdev_ops fs_bootdev_ops = { + .get_bootflow = fs_get_bootflow, +}; + +static const struct udevice_id fs_bootdev_ids[] = { + { .compatible = "u-boot,bootdev-fs" }, + { } +}; + +U_BOOT_DRIVER(fs_bootdev) = { + .name = "fs_bootdev", + .id = UCLASS_BOOTDEV, + .ops = &fs_bootdev_ops, + .bind = fs_bootdev_bind, + .of_match = fs_bootdev_ids, +}; + +BOOTDEV_HUNTER(fs_bootdev_hunter) = { + .prio = BOOTDEVP_3_INTERNAL_SLOW, + .uclass = UCLASS_FS, + .hunt = fs_bootdev_hunt, + .drv = DM_DRIVER_REF(fs_bootdev), +}; + +UCLASS_DRIVER(fs) = { + .name = "fs", + .id = UCLASS_FS, + .per_device_auto = sizeof(struct fs_priv), + .per_device_plat_auto = sizeof(struct fs_plat), +}; diff --git a/include/dm/uclass-id.h b/include/dm/uclass-id.h index 4818d9bd272..45e9abfce32 100644 --- a/include/dm/uclass-id.h +++ b/include/dm/uclass-id.h @@ -68,6 +68,7 @@ enum uclass_id { UCLASS_FIRMWARE, /* Firmware */ UCLASS_FPGA, /* FPGA device */ UCLASS_FUZZING_ENGINE, /* Fuzzing engine */ + UCLASS_FS, /* Filesystem */ UCLASS_FS_FIRMWARE_LOADER, /* Generic loader */ UCLASS_FWU_MDATA, /* FWU Metadata Access */ UCLASS_GPIO, /* Bank of general-purpose I/O pins */ diff --git a/include/fs.h b/include/fs.h new file mode 100644 index 00000000000..05a2ac844b8 --- /dev/null +++ b/include/fs.h @@ -0,0 +1,78 @@ +/* SPDX-License-Identifier: GPL-2.0 */ +/* + * U-Boot Filesystem layer + * + * Models a filesystem which can be mounted and unmounted. It also allows a + * directory to be looked up. + * + * Copyright 2025 Simon Glass <sjg@chromium.org> + */ + +#ifndef __FS_H +#define __FS_H + +#include <fs_common.h> + +struct udevice; + +enum { + /* Maximum length of the filesystem name */ + FS_MAX_NAME_LEN = 128, +}; + +/** + * struct fs_plat - Filesystem information + * + * @name: Name of the filesystem, or empty if not available + */ +struct fs_plat { + char name[FS_MAX_NAME_LEN]; +}; + +/** + * struct fs_priv - Private information for the FS devices + * + * @mounted: true if mounted + */ +struct fs_priv { + bool mounted; +}; + +struct fs_ops { + /** + * mount() - Mount the filesystem + * + * @dev: Filesystem device + * Return 0 if OK, -EISCONN if already mounted, other -ve on error + */ + int (*mount)(struct udevice *dev); + + /** + * unmount() - Unmount the filesystem + * + * @dev: Filesystem device + * Return 0 if OK, -ENOTCONN if not mounted, other -ve on error + */ + int (*unmount)(struct udevice *dev); +}; + +/* Get access to a filesystem's operations */ +#define fs_get_ops(dev) ((struct fs_ops *)(dev)->driver->ops) + +/** + * fs_mount() - Mount the filesystem + * + * @dev: Filesystem device + * Return 0 if OK, -EISCONN if already mounted, other -ve on error + */ +int fs_mount(struct udevice *dev); + +/** + * fs_unmount() - Unmount the filesystem + * + * @dev: Filesystem device + * Return 0 if OK, -ENOTCONN if not mounted, other -ve on error + */ +int fs_unmount(struct udevice *dev); + +#endif diff --git a/test/boot/bootdev.c b/test/boot/bootdev.c index cd1d00bfbe0..a578af5ccf0 100644 --- a/test/boot/bootdev.c +++ b/test/boot/bootdev.c @@ -390,6 +390,7 @@ static int bootdev_test_hunter(struct unit_test_state *uts) ut_assert_nextlinen("----"); ut_assert_nextline(" 6 ethernet eth_bootdev"); ut_assert_nextline(" 1 simple_bus (none)"); + ut_assert_nextline(" 3 fs fs_bootdev"); ut_assert_nextline(" 5 ide ide_bootdev"); ut_assert_nextline(" 2 mmc mmc_bootdev"); ut_assert_nextline(" 4 nvme nvme_bootdev"); @@ -447,6 +448,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) /* This is the extension feature which has no uclass at present */ ut_assert_nextline("Hunting with: simple_bus"); ut_assert_nextline("Found 2 extension board(s)."); + ut_assert_nextline("Hunting with: fs"); ut_assert_nextline("Hunting with: ide"); /* mmc hunter has already been used so should not run again */ @@ -468,6 +470,7 @@ static int bootdev_test_cmd_hunt(struct unit_test_state *uts) ut_assert_nextlinen("----"); ut_assert_nextline(" 6 * ethernet eth_bootdev"); ut_assert_nextline(" 1 * simple_bus (none)"); + ut_assert_nextline(" 3 * fs fs_bootdev"); ut_assert_nextline(" 5 * ide ide_bootdev"); ut_assert_nextline(" 2 * mmc mmc_bootdev"); ut_assert_nextline(" 4 * nvme nvme_bootdev"); diff --git a/test/boot/bootstd_common.h b/test/boot/bootstd_common.h index 945515f7da8..ce049ad8bd1 100644 --- a/test/boot/bootstd_common.h +++ b/test/boot/bootstd_common.h @@ -24,10 +24,11 @@ enum { HUNTER_ETH = 0, HUNTER_SIMPLE_BUS, - HUNTER_MMC = 3, - HUNTER_SCSI = 6, - HUNTER_USB = 8, - HUNTER_COUNT = 10, + HUNTER_FS = 3, + HUNTER_MMC, /* ID of MMC hunter */ + HUNTER_SCSI = 7, /* ID of SCSI hunter */ + HUNTER_USB = 9, /* ID of USB hunter */ + HUNTER_COUNT = 11, HUNTER_MAX = HUNTER_COUNT - 1, }; -- 2.43.0