Our current of global.boot.default expanding to bootsource doesn't work
when booting from boot-only flash. Improve upon this by adding cdev
aliases for removable and builtin storage devices.

Signed-off-by: Ahmad Fatoum <[email protected]>
---
 Documentation/user/booting-linux.rst | 25 ++++++++
 common/cdev-alias.c                  | 86 ++++++++++++++++++++++++++++
 include/driver.h                     |  5 ++
 3 files changed, 116 insertions(+)

diff --git a/Documentation/user/booting-linux.rst 
b/Documentation/user/booting-linux.rst
index b164c538c62a..f1df5ee2bbf0 100644
--- a/Documentation/user/booting-linux.rst
+++ b/Documentation/user/booting-linux.rst
@@ -182,6 +182,31 @@ and configure the overrides as arguments to the ``boot`` 
command:
 
   boot -o bootm.image=/mnt/tftp/oftree mmc
 
+Generic Boot Targets
+^^^^^^^^^^^^^^^^^^^^
+
+A single boot target can yield multiple entries, e.g., one for each
+bootloader spec file detected at runtime as described in the next section.
+
+There is also a number of generic default boot targets available, when
+``CONFIG_BOOT_DEFAULTS`` is enabled. These expands to a single device at most:
+
+* ``bootsource``: expands to the device barebox booted from
+* ``diskuuid.*``: expands to the device with specified ``*`` diskuuid
+
+For these targets that expand to a single device, a partition can also be 
specified,
+e.g., ``bootsource.esp`` to reference the partition with the ``esp`` partition
+label within the bootsource.
+
+Following target can expand to multiple devices:
+
+* ``storage.removable``: expands to built-in storage devices, like USB sticks
+* ``storage.builtin``: expands to built-in storage devices, like eMMC
+* ``storage``: expands to all of the above ``storage.*``
+
+If the bootsource exists within any of these targets, it will be the first
+device in the returned list.
+
 .. _bootloader_spec:
 
 Boot Loader Specification
diff --git a/common/cdev-alias.c b/common/cdev-alias.c
index 3732fd90525f..82b91108c1fc 100644
--- a/common/cdev-alias.c
+++ b/common/cdev-alias.c
@@ -9,7 +9,9 @@
 #include <stringlist.h>
 #include <bootsource.h>
 #include <driver.h>
+#include <block.h>
 #include <init.h>
+#include <linux/bits.h>
 
 struct cdev_alias_res {
        const char *name;
@@ -77,9 +79,93 @@ static int cdev_alias_resolve_diskuuid(struct cdev_alias_res 
*cdev_alias_res,
        return ret;
 }
 
+#define STORAGE_REMOVABLE      BIT(0)
+#define STORAGE_BUILTIN                BIT(1)
+
+/**
+ * call_for_each_storage() - invoke callback for each storage medium
+ *
+ * @fn:                        callback to invoke
+ * @data:              callback-specific data
+ * @filter:            OR-ed types of STORAGE_* to filter for
+ * @only_bootsource:   If true, include only bootsource if available,
+ *                     otherwise omit always
+ * Return:             number of successful callback invocations or a negative 
error
+ */
+static int call_for_each_storage(cdev_alias_processor_t fn,
+                                void *data,
+                                unsigned filter,
+                                bool only_bootsource)
+{
+       struct cdev *cdev, *bootcdev;
+       int ret, nmatches = 0;
+
+       bootcdev = bootsource_of_cdev_find();
+
+       for_each_cdev(cdev) {
+               struct block_device *bdev;
+
+               if (!cdev_is_storage(cdev) || cdev_is_partition(cdev))
+                       continue;
+
+               bdev = cdev_get_block_device(cdev);
+
+               if (((filter & STORAGE_REMOVABLE) && bdev && bdev->removable) ||
+                   ((filter & STORAGE_BUILTIN) && (!bdev || 
!bdev->removable))) {
+                       if (only_bootsource && cdev != bootcdev)
+                               continue;
+                       if (!only_bootsource && cdev == bootcdev)
+                               continue;
+
+                       ret = fn(cdev, data);
+                       if (ret < 0)
+                               return ret;
+                       nmatches++;
+
+                       /* Got our bootsource, no need to continue iteration */
+                       if (only_bootsource)
+                               break;
+               }
+       }
+
+       return nmatches;
+}
+
+static int cdev_alias_resolve_storage(struct cdev_alias_res *cdev_alias_res,
+                                     const char *class,
+                                     cdev_alias_processor_t fn,
+                                     void *data)
+{
+       struct cdev *bootcdev;
+       unsigned filter = 0;
+       int bootsource, nmatches;
+
+       if (!class)
+               filter = ~0;
+       else if (streq_ptr(class, "removable"))
+               filter |= STORAGE_REMOVABLE;
+       else if (streq_ptr(class, "builtin"))
+               filter |= STORAGE_BUILTIN;
+       else
+               return -EINVAL;
+
+       bootcdev = bootsource_of_cdev_find();
+
+       bootsource = call_for_each_storage(fn, data, filter, true);
+       if (bootsource < 0)
+               return bootsource;
+
+       nmatches = call_for_each_storage(fn, data, filter, false);
+       if (nmatches < 0)
+               return nmatches;
+
+       return bootsource + nmatches;
+}
+
 static struct cdev_alias_res cdev_alias_aliases[] = {
        { "bootsource", cdev_alias_resolve_bootsource },
        { "diskuuid", cdev_alias_resolve_diskuuid },
+       { "storage", cdev_alias_resolve_storage },
        { /* sentinel */}
 };
 
diff --git a/include/driver.h b/include/driver.h
index a941ca6127e6..de5a63c379eb 100644
--- a/include/driver.h
+++ b/include/driver.h
@@ -597,6 +597,11 @@ get_inheritable_devfs_flags(const struct cdev *parent_cdev)
        return parent_cdev->flags & DEVFS_INHERITABLE_FLAGS;
 }
 
+static inline bool cdev_is_storage(const struct cdev *cdev)
+{
+       return (cdev->flags & DEVFS_IS_BLOCK_DEV) || cdev->mtd;
+}
+
 struct cdev *
 cdev_find_child_by_gpt_typeuuid(struct cdev *cdev, const guid_t *typeuuid);
 
-- 
2.47.3


Reply via email to