[Concept,02/12] bootstd: Add BOOTMETHF_MULTI for multi-entry bootmeths

Message ID 20260324221911.3678307-3-sjg@u-boot.org
State New
Headers
Series bootstd: Support multiple bootflows per partition |

Commit Message

Simon Glass March 24, 2026, 10:18 p.m. UTC
  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(+)
  

Patch

diff --git a/boot/bootdev-uclass.c b/boot/bootdev-uclass.c
index f0f5912b582..72f9a315c04 100644
--- a/boot/bootdev-uclass.c
+++ b/boot/bootdev-uclass.c
@@ -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);
 
diff --git a/boot/bootflow.c b/boot/bootflow.c
index dbda50b8231..d44ba65c1a9 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -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++) {
diff --git a/include/bootflow.h b/include/bootflow.h
index dbdbca96596..2a4a96c1031 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -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;
diff --git a/include/bootmeth.h b/include/bootmeth.h
index 2cc8b690bbf..997dc762370 100644
--- a/include/bootmeth.h
+++ b/include/bootmeth.h
@@ -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),
 };
 
 /**