dm: sandbox: Create a new HOST uclass
authorSimon Glass <sjg@chromium.org>
Sun, 30 Oct 2022 01:47:15 +0000 (19:47 -0600)
committerSimon Glass <sjg@chromium.org>
Mon, 7 Nov 2022 23:24:30 +0000 (16:24 -0700)
Sandbox supports block devices which can access files on the host machine.
At present there is no uclass for this. The devices are attached to the
root devic. The block-device type is therefore set to UCLASS_ROOT which
is confusing.

Block devices should be attached to a 'media' device instead, something
which handles access to the actual media and provides the block driver
for the block device.

Create a new uclass to handle this. It supports two operations, to attach
and detach a file on the host machine.

For now this is not fully plumbed in.

Signed-off-by: Simon Glass <sjg@chromium.org>
drivers/block/Makefile
drivers/block/host-uclass.c [new file with mode: 0644]
include/dm/uclass-id.h
include/sandbox_host.h [new file with mode: 0644]

index 19d9317c825ae13c5c141727fc62d6b9ff95c90c..7f2591204564c7a676901b26f118bfbb483ca868 100644 (file)
@@ -12,7 +12,7 @@ endif
 ifndef CONFIG_SPL_BUILD
 obj-$(CONFIG_IDE) += ide.o
 endif
-obj-$(CONFIG_SANDBOX) += sandbox.o
+obj-$(CONFIG_SANDBOX) += sandbox.o host-uclass.o
 obj-$(CONFIG_$(SPL_TPL_)BLOCK_CACHE) += blkcache.o
 
 obj-$(CONFIG_EFI_MEDIA) += efi-media-uclass.o
diff --git a/drivers/block/host-uclass.c b/drivers/block/host-uclass.c
new file mode 100644 (file)
index 0000000..6460d96
--- /dev/null
@@ -0,0 +1,176 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Uclass 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 <dm.h>
+#include <malloc.h>
+#include <sandbox_host.h>
+#include <dm/device-internal.h>
+#include <dm/lists.h>
+#include <dm/uclass-internal.h>
+
+DECLARE_GLOBAL_DATA_PTR;
+
+/**
+ * struct host_priv - information kept by the host uclass
+ *
+ * @cur_dev: Currently selected host device, or NULL if none
+ */
+struct host_priv {
+       struct udevice *cur_dev;
+};
+
+int host_create_device(const char *label, bool removable, struct udevice **devp)
+{
+       char dev_name[30], *str, *label_new;
+       struct host_sb_plat *plat;
+       struct udevice *dev, *blk;
+       int ret;
+
+       /* unbind any existing device with this label */
+       dev = host_find_by_label(label);
+       if (dev) {
+               ret = host_detach_file(dev);
+               if (ret)
+                       return log_msg_ret("det", ret);
+
+               ret = device_unbind(dev);
+               if (ret)
+                       return log_msg_ret("unb", ret);
+       }
+
+       snprintf(dev_name, sizeof(dev_name), "host-%s", label);
+       str = strdup(dev_name);
+       if (!str)
+               return -ENOMEM;
+
+       label_new = strdup(label);
+       if (!label_new) {
+               ret = -ENOMEM;
+               goto no_label;
+       }
+
+       ret = device_bind_driver(gd->dm_root, "host_sb_drv", str, &dev);
+       if (ret)
+               goto no_dev;
+       device_set_name_alloced(dev);
+
+       if (!blk_find_from_parent(dev, &blk)) {
+               struct blk_desc *desc = dev_get_uclass_plat(blk);
+
+               desc->removable = removable;
+       }
+
+       plat = dev_get_plat(dev);
+       plat->label = label_new;
+       *devp = dev;
+
+       return 0;
+
+no_dev:
+       free(label_new);
+no_label:
+       free(str);
+
+       return ret;
+}
+
+int host_attach_file(struct udevice *dev, const char *filename)
+{
+       struct host_ops *ops = host_get_ops(dev);
+
+       if (!ops->attach_file)
+               return -ENOSYS;
+
+       return ops->attach_file(dev, filename);
+}
+
+int host_create_attach_file(const char *label, const char *filename,
+                           bool removable, struct udevice **devp)
+{
+       struct udevice *dev;
+       int ret;
+
+       ret = host_create_device(label, removable, &dev);
+       if (ret)
+               return log_msg_ret("cre", ret);
+
+       ret = host_attach_file(dev, filename);
+       if (ret) {
+               device_unbind(dev);
+               return log_msg_ret("att", ret);
+       }
+       *devp = dev;
+
+       return 0;
+}
+
+int host_detach_file(struct udevice *dev)
+{
+       struct host_ops *ops = host_get_ops(dev);
+
+       if (!ops->detach_file)
+               return -ENOSYS;
+
+       if (dev == host_get_cur_dev())
+               host_set_cur_dev(NULL);
+
+       return ops->detach_file(dev);
+}
+
+struct udevice *host_find_by_label(const char *label)
+{
+       struct udevice *dev;
+       struct uclass *uc;
+
+       uclass_id_foreach_dev(UCLASS_HOST, dev, uc) {
+               struct host_sb_plat *plat = dev_get_plat(dev);
+
+               if (plat->label && !strcmp(label, plat->label))
+                       return dev;
+       }
+
+       return NULL;
+}
+
+struct udevice *host_get_cur_dev(void)
+{
+       struct uclass *uc = uclass_find(UCLASS_HOST);
+
+       if (uc) {
+               struct host_priv *priv = uclass_get_priv(uc);
+
+               return priv->cur_dev;
+       }
+
+       return NULL;
+}
+
+void host_set_cur_dev(struct udevice *dev)
+{
+       struct uclass *uc = uclass_find(UCLASS_HOST);
+
+       if (uc) {
+               struct host_priv *priv = uclass_get_priv(uc);
+
+               priv->cur_dev = dev;
+       }
+}
+
+UCLASS_DRIVER(host) = {
+       .id             = UCLASS_HOST,
+       .name           = "host",
+#if CONFIG_IS_ENABLED(OF_REAL)
+       .post_bind      = dm_scan_fdt_dev,
+#endif
+       .priv_auto      = sizeof(struct host_priv),
+};
index 1f3cf8c0853a976bfe99c2d64cb57c331ccf88a6..376f741cc2bba797ff1260b6a238503943dc158a 100644 (file)
@@ -63,6 +63,7 @@ enum uclass_id {
        UCLASS_GPIO,            /* Bank of general-purpose I/O pins */
        UCLASS_HASH,            /* Hash device */
        UCLASS_HWSPINLOCK,      /* Hardware semaphores */
+       UCLASS_HOST,            /* Sandbox host device */
        UCLASS_I2C,             /* I2C bus */
        UCLASS_I2C_EEPROM,      /* I2C EEPROM device */
        UCLASS_I2C_GENERIC,     /* Generic I2C device */
diff --git a/include/sandbox_host.h b/include/sandbox_host.h
new file mode 100644 (file)
index 0000000..2e37ede
--- /dev/null
@@ -0,0 +1,125 @@
+/* SPDX-License-Identifier: GPL-2.0+ */
+/*
+ * sandbox host uclass
+ *
+ * Copyright 2022 Google LLC
+ */
+
+#ifndef __SANDBOX_HOST__
+#define __SANDBOX_HOST__
+
+/**
+ * struct host_sb_plat - platform data for a host device
+ *
+ * @label: Label for this device (allocated)
+ * @filename: Name of file this is attached to, or NULL (allocated)
+ * @fd: File descriptor of file, or 0 for none (file is not open)
+ */
+struct host_sb_plat {
+       char *label;
+       char *filename;
+       int fd;
+};
+
+/**
+ * struct host_ops - operations supported by UCLASS_HOST
+ *
+ * @attach_file: Attach a new file to a device
+ * @detach_file: Detach a file from a device
+ */
+struct host_ops {
+       /*
+        * attach_file() - Attach a new file to the device
+        *
+        * @dev: Device to update
+        * @filename: Name of the file, e.g. "/path/to/disk.img"
+        * Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on
+        * other error
+        */
+       int (*attach_file)(struct udevice *dev, const char *filename);
+
+       /**
+        * detach_file() - Detach a file from the device
+        *
+        * @dev: Device to detach from
+        * Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other
+        * error
+        */
+        int (*detach_file)(struct udevice *dev);
+};
+
+#define host_get_ops(dev)        ((struct host_ops *)(dev)->driver->ops)
+
+/**
+ * host_attach_file() - Attach a new file to the device
+ *
+ * @dev: Device to update
+ * @filename: Name of the file, e.g. "/path/to/disk.img"
+ * Returns: 0 if OK, -EEXIST if a file is already attached, other -ve on
+ * other error
+ */
+int host_attach_file(struct udevice *dev, const char *filename);
+
+/**
+ * host_detach_file() - Detach a file from the device
+ *
+ * @dev: Device to detach from
+ * Returns: 0 if OK, -ENOENT if no file is attached, other -ve on other
+ * error
+ */
+int host_detach_file(struct udevice *dev);
+
+/**
+ * host_create_device() - Create a new host device
+ *
+ * Any existing device with the same label is removed and unbound first
+ *
+ * @label: Label of the attachment, e.g. "test1"
+ * @removable: true if the device should be marked as removable, false
+ *     if it is fixed. See enum blk_flag_t
+ * @devp: Returns the device created, on success
+ * Returns: 0 if OK, -ve on error
+ */
+int host_create_device(const char *label, bool removable,
+                      struct udevice **devp);
+
+/**
+ * host_create_attach_file() - Create a new host device attached to a file
+ *
+ * @label: Label of the attachment, e.g. "test1"
+ * @filename: Name of the file, e.g. "/path/to/disk.img"
+ * @removable: true if the device should be marked as removable, false
+ *     if it is fixed. See enum blk_flag_t
+ * @devp: Returns the device created, on success
+ * Returns: 0 if OK, -ve on error
+ */
+int host_create_attach_file(const char *label, const char *filename,
+                           bool removable, struct udevice **devp);
+
+/**
+ * host_find_by_label() - Find a host by label
+ *
+ * Searches all host devices to find one with the given label
+ *
+ * @label: Label to find
+ * Returns: associated device, or NULL if not found
+ */
+struct udevice *host_find_by_label(const char *label);
+
+/**
+ * host_get_cur_dev() - Get the current device
+ *
+ * Returns current device, or NULL if none
+ */
+struct udevice *host_get_cur_dev(void);
+
+/**
+ * host_set_cur_dev() - Set the current device
+ *
+ * Sets the current device, or clears it if @dev is NULL
+ *
+ * @dev: Device to set as the current one
+ */
+void host_set_cur_dev(struct udevice *dev);
+
+#endif /* __SANDBOX_HOST__ */