diff --git a/drivers/block/Makefile b/drivers/block/Makefile index 7f25912045..f12447d78d 100644 --- a/drivers/block/Makefile +++ b/drivers/block/Makefile @@ -12,7 +12,7 @@ endif ifndef CONFIG_SPL_BUILD obj-$(CONFIG_IDE) += ide.o endif -obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o +obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o host_dev.o obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o diff --git a/drivers/block/host_dev.c b/drivers/block/host_dev.c new file mode 100644 index 0000000000..5885fc358a --- /dev/null +++ b/drivers/block/host_dev.c @@ -0,0 +1,142 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Driver for sandbox host interface, used to access files on the host which + * contain partitions and filesystem + * + * Copyright 2022 Google LLC + * Written by Simon Glass + */ + +#define LOG_CATEGORY UCLASS_HOST + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static int host_sb_attach_file(struct udevice *dev, const char *filename) +{ + struct host_sb_plat *plat = dev_get_plat(dev); + struct blk_desc *desc; + struct udevice *blk; + int ret, fd, size; + char *fname; + + if (!filename) + return -EINVAL; + + if (plat->fd) + return log_msg_ret("fd", -EEXIST); + + /* Sanity check that host_sb_bind() has been used */ + ret = blk_find_from_parent(dev, &blk); + if (ret) + return ret; + + fd = os_open(filename, OS_O_RDWR); + if (fd == -1) { + printf("Failed to access host backing file '%s', trying read-only\n", + filename); + fd = os_open(filename, OS_O_RDONLY); + if (fd == -1) { + printf("- still failed\n"); + return log_msg_ret("open", -ENOENT); + } + } + + fname = strdup(filename); + if (!fname) { + ret = -ENOMEM; + goto err_fname; + } + + size = os_filesize(fd); + desc = dev_get_uclass_plat(blk); + desc->lba = size / desc->blksz; + + /* write this in last, when nothing can go wrong */ + plat = dev_get_plat(dev); + plat->fd = fd; + plat->filename = fname; + + return 0; + +err_fname: + os_close(fd); + + return ret; +} + +int host_sb_detach_file(struct udevice *dev) +{ + struct host_sb_plat *plat = dev_get_plat(dev); + int ret; + + if (!plat->fd) + return log_msg_ret("fd", -ENOENT); + + ret = device_remove(dev, DM_REMOVE_NORMAL); + if (ret) + return log_msg_ret("rem", ret); + + /* Unbind all children */ + ret = device_chld_unbind(dev, NULL); + if (ret) + return log_msg_ret("unb", ret); + + os_close(plat->fd); + plat->fd = 0; + free(plat->filename); + free(plat->label); + + return 0; +} + +static int host_sb_bind(struct udevice *dev) +{ + struct udevice *blk, *bdev; + struct blk_desc *desc; + int ret; + + ret = blk_create_devicef(dev, "sandbox_host_blk", "blk", UCLASS_HOST, + dev_seq(dev), 512, 0, &blk); + if (ret) + return log_msg_ret("blk", ret); + + desc = dev_get_uclass_plat(blk); + snprintf(desc->vendor, BLK_VEN_SIZE, "U-Boot"); + snprintf(desc->product, BLK_PRD_SIZE, "hostfile"); + snprintf(desc->revision, BLK_REV_SIZE, "1.0"); + + if (CONFIG_IS_ENABLED(BOOTSTD)) { + ret = bootdev_bind(dev, "host_bootdev", "bootdev", &bdev); + if (ret) + return log_msg_ret("bd", ret); + } + + return 0; +} + +struct host_ops host_sb_ops = { + .attach_file = host_sb_attach_file, + .detach_file = host_sb_detach_file, +}; + +static const struct udevice_id host_ids[] = { + { .compatible = "sandbox,host" }, + { } +}; + +U_BOOT_DRIVER(host_sb_drv) = { + .name = "host_sb_drv", + .id = UCLASS_HOST, + .of_match = host_ids, + .ops = &host_sb_ops, + .bind = host_sb_bind, + .plat_auto = sizeof(struct host_sb_plat), +};