From: Simon Glass <sjg@chromium.org>
Some bootmeths can produce multiple bootflows from a single partition.
For example, an extlinux config file may define several labels, each
representing a different kernel to boot.
Add a BOOTMETHF_MULTI flag that bootmeths can set to indicate this
capability. When set, the iterator tries incrementing entry indices
before advancing to the next bootmeth. The read_bootflow() op
receives the entry index via bflow->entry and returns -ENOENT when
no more entries are available.
Add an 'entry' field to both struct bootflow and struct bootflow_iter
to track the entry index. The entry is copied from the iterator to
the bootflow in bootdev_get_bootflow() so the bootmeth can see which
entry is being requested.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
boot/bootdev-uclass.c | 1 +
boot/bootflow.c | 17 +++++++++++++++++
include/bootflow.h | 6 ++++++
include/bootmeth.h | 5 +++++
4 files changed, 29 insertions(+)
@@ -574,6 +574,7 @@ int bootdev_get_bootflow(struct udevice *dev, struct bootflow_iter *iter,
log_debug("->get_bootflow %s,%x=%p\n", dev->name, iter->part,
ops->get_bootflow);
bootflow_init(bflow, dev, iter->method);
+ bflow->entry = iter->entry;
if (!ops->get_bootflow)
return default_get_bootflow(dev, iter, bflow);
@@ -364,6 +364,23 @@ static int iter_incr(struct bootflow_iter *iter)
return BF_NO_MORE_DEVICES;
}
+ /*
+ * If the current method supports multiple entries and the last call
+ * succeeded, try the next entry before advancing the method
+ */
+ if (iter->method && !iter->err) {
+ struct bootmeth_uc_plat *ucp;
+
+ ucp = dev_get_uclass_plat(iter->method);
+ if (ucp->flags & BOOTMETHF_MULTI) {
+ iter->entry++;
+ log_debug("-> next entry %d for method '%s'\n",
+ iter->entry, iter->method->name);
+ return 0;
+ }
+ }
+ iter->entry = 0;
+
/* Get the next boothmethod */
for (iter->cur_method++; iter->cur_method < iter->num_methods;
iter->cur_method++) {
@@ -75,6 +75,9 @@ enum bootflow_flags_t {
* @blk: Block device which contains this bootflow, NULL if this is a network
* device or sandbox 'host' device
* @part: Partition number (0 for whole device)
+ * @entry: Entry index within this (dev, part, method) combination. Used by
+ * bootmeths with BOOTMETHF_MULTI to select which entry to return (e.g.
+ * which label in an extlinux config). Always 0 for non-multi bootmeths.
* @fs_type: Filesystem type (FS_TYPE...) if this is fixed by the media, else 0.
* For example, the sandbox host-filesystem bootdev sets this to
* FS_TYPE_SANDBOX
@@ -110,6 +113,7 @@ struct bootflow {
struct udevice *dev;
struct udevice *blk;
int part;
+ int entry;
int fs_type;
struct udevice *method;
char *name;
@@ -266,6 +270,7 @@ enum {
* @dev: Current bootdev, NULL if none. This is only ever updated in
* bootflow_iter_set_dev()
* @part: Current partition number (0 for whole device)
+ * @entry: Current entry index for BOOTMETHF_MULTI bootmeths, else 0
* @method: Current bootmeth
* @max_part: Maximum hardware partition number in @dev, 0 if there is no
* partition table
@@ -300,6 +305,7 @@ struct bootflow_iter {
int flags;
struct udevice *dev;
int part;
+ int entry;
struct udevice *method;
int max_part;
int first_bootable;
@@ -19,10 +19,15 @@ struct udevice;
* @BOOTMETHF_GLOBAL: bootmeth handles bootdev selection automatically
* @BOOTMETHF_ANY_PART: bootmeth is willing to check any partition, even if it
* has no filesystem
+ * @BOOTMETHF_MULTI: bootmeth can produce multiple bootflows from a single
+ * partition (e.g. extlinux with several labels). The read_bootflow() op should
+ * check bflow->entry to select which entry to return, and return -ENOENT
+ * when the index exceeds available entries.
*/
enum bootmeth_flags {
BOOTMETHF_GLOBAL = BIT(0),
BOOTMETHF_ANY_PART = BIT(1),
+ BOOTMETHF_MULTI = BIT(2),
};
/**