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
