--- /dev/null
+// 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 <sjg@chromium.org>
+ */
+
+#define LOG_CATEGORY UCLASS_HOST
+
+#include <common.h>
+#include <blk.h>
+#include <bootdev.h>
+#include <dm.h>
+#include <log.h>
+#include <malloc.h>
+#include <os.h>
+#include <sandbox_host.h>
+#include <dm/device-internal.h>
+
+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),
+};