* [PATCH v4 00/11] boot: Support priority for global bootmeths
@ 2025-10-15 15:44 Simon Glass
2025-10-15 15:44 ` [PATCH v4 01/11] boot: Try all bootmeths on the final partition Simon Glass
` (12 more replies)
0 siblings, 13 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Guillaume La Roque, Jerome Forissier, Martin Schwan, Martyn Welch,
Mattijs Korpershoek, Maximilian Brune, Moritz Fischer,
Sam Protsenko
At present global bootmeths always run first, before all other
bootmeths. Optimisations in the code take advantage of this, putting
them at the end, so they can be used once and then forgotten.
In some cases it is useful to run global bootmeths later in the boot.
For example, the EFI-bootmgr bootmeth may itself scan devices and the
network, so running it first can hold up the boot significantly for
boards not actually relying on EFI-bootmgr to boot.
This series introduces a new field in global bootmeths which indicates
the priority, using the same scheme as is used with bootdev hunters.
Thus it is possible to insert the EFI-bootmgr bootmeth just before the
hunter for network bootdevs is invoked.
Despite the simplicity of the concept and the relatively small series,
this is a fairly significant enhancement. It is also quite tricky to
implement, largely due to the way the original code was written, with
global bootmeths being a small, size-optimised add-on to the original
bootstd implementation.
For now we only allow each global bootmeth to run at most once, but this
implementation is written in a way that we could relax that if needed.
Then the bootmeth itself could decide whether to run at any particular
point in the bootflow iteration.
Size growth is about 390 bytes on Thumb2 (e.g. firefly-rk3288) if
CONFIG_BOOTMETH_GLOBAL is enabled, which it normally is. With that
disabled (which saves about 4K on the same platform), there is no
growth.
Changes in v4:
- Reword the commit message as Tom suggested
- Drop call to bootflow_show()
- Rebase on top of -master
Changes in v3:
- Pull doc changes into this patch
Changes in v2:
- Add a bit more detail suggested by Heinrich
- Update commit message to indicate the bootmeth will always run
- Document how the priority was chosen
Simon Glass (11):
boot: Try all bootmeths on the final partition
boot: Add a new test for global bootmeths
boot: Update first_glob_method when dropping a bootmeth
boot: Add a flag for whether there are global bootmeths
boot: Keep track of which bootmeths have been used
boot: Support rescanning the global bootmeths
boot: Only run global bootmeths once each
boot: Implement a priority for global bootmeths
boot: Don't change the method count after global bootmeths
boot: Run global bootmeths after all bootdevs are exhausted
boot: Run the EFI bootmgr just before network devices
boot/bootflow.c | 181 ++++++++++++++++++++++++++++---
boot/bootmeth-uclass.c | 11 ++
boot/bootmeth_efi_mgr.c | 9 ++
doc/develop/bootstd/overview.rst | 40 ++++++-
include/bootflow.h | 19 +++-
include/bootmeth.h | 4 +
test/boot/bootflow.c | 72 +++++++++++-
7 files changed, 307 insertions(+), 29 deletions(-)
--
2.43.0
base-commit: 996ded5463fd48497b6aa904a5647c2533d73ab3
branch: globa-us4
^ permalink raw reply [flat|nested] 17+ messages in thread
* [PATCH v4 01/11] boot: Try all bootmeths on the final partition
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 19:04 ` Tom Rini
2025-10-15 15:44 ` [PATCH v4 02/11] boot: Add a new test for global bootmeths Simon Glass
` (11 subsequent siblings)
12 siblings, 1 reply; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Maximilian Brune, Moritz Fischer, Sam Protsenko
At present, normally when one bootmeth fails on a partition, we move on
and try the next bootmeth. However, this was not the case for the final
partition due to a bug. Rework the logic so that all partitions are
treated the same.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v4:
- Reword the commit message as Tom suggested
boot/bootflow.c | 34 ++++++++++++++++------------------
1 file changed, 16 insertions(+), 18 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 7ed076c898f..deb5f42ba65 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -221,27 +221,25 @@ static int iter_incr(struct bootflow_iter *iter)
if (iter->err == BF_NO_MORE_DEVICES)
return BF_NO_MORE_DEVICES;
- if (iter->err != BF_NO_MORE_PARTS) {
- /* Get the next boothmethod */
- if (++iter->cur_method < iter->num_methods) {
- iter->method = iter->method_order[iter->cur_method];
- return 0;
- }
+ /* Get the next boothmethod */
+ if (++iter->cur_method < iter->num_methods) {
+ iter->method = iter->method_order[iter->cur_method];
+ return 0;
+ }
+
+ /*
+ * If we have finished scanning the global bootmeths, start the
+ * normal bootdev scan
+ */
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) {
+ iter->num_methods = iter->first_glob_method;
+ iter->doing_global = false;
/*
- * If we have finished scanning the global bootmeths, start the
- * normal bootdev scan
+ * Don't move to the next dev as we haven't tried this
+ * one yet!
*/
- if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) {
- iter->num_methods = iter->first_glob_method;
- iter->doing_global = false;
-
- /*
- * Don't move to the next dev as we haven't tried this
- * one yet!
- */
- inc_dev = false;
- }
+ inc_dev = false;
}
if (iter->flags & BOOTFLOWIF_SINGLE_PARTITION)
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 02/11] boot: Add a new test for global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 01/11] boot: Try all bootmeths on the final partition Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 03/11] boot: Update first_glob_method when dropping a bootmeth Simon Glass
` (10 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Guillaume La Roque,
Jerome Forissier, Mattijs Korpershoek
These have different behaviour from normal bootmeths and we are about to
enhance it. So add a test and also an extra check in bootflow_iter()
Signed-off-by: Simon Glass <sjg@chromium.org>
---
Changes in v4:
- Drop call to bootflow_show()
test/boot/bootflow.c | 44 ++++++++++++++++++++++++++++++++++++++++++++
1 file changed, 44 insertions(+)
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 7cd83dc7443..f3386a1eb31 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -307,6 +307,8 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq(0, iter.max_part);
ut_asserteq_str("extlinux", iter.method->name);
ut_asserteq(0, bflow.err);
+ ut_assert(!iter.doing_global);
+ ut_asserteq(-1, iter.first_glob_method);
/*
* This shows MEDIA even though there is none, since in
@@ -388,6 +390,48 @@ static int bootflow_iter(struct unit_test_state *uts)
BOOTSTD_TEST(bootflow_iter, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
#if defined(CONFIG_SANDBOX) && defined(CONFIG_BOOTMETH_GLOBAL)
+
+/* Check iterating through available bootflows to test global bootmeths */
+static int bootflow_iter_glob(struct unit_test_state *uts)
+{
+ struct bootflow_iter iter;
+ struct bootflow bflow;
+
+ bootstd_clear_glob();
+
+ /* we should get the global bootmeth initially */
+ ut_asserteq(-EINVAL,
+ bootflow_scan_first(NULL, NULL, &iter, BOOTFLOWIF_ALL |
+ BOOTFLOWIF_SHOW, &bflow));
+ ut_asserteq(3, iter.num_methods);
+ ut_assert(iter.doing_global);
+ ut_asserteq(2, iter.first_glob_method);
+
+ ut_asserteq(2, iter.cur_method);
+ ut_asserteq(0, iter.part);
+ ut_asserteq(0, iter.max_part);
+ ut_asserteq_str("firmware0", iter.method->name);
+ ut_asserteq(0, bflow.err);
+ bootflow_free(&bflow);
+
+ /* next we should get the first non-global bootmeth */
+ ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow));
+
+ /* at this point the global bootmeths are stranded above num_methods */
+ ut_asserteq(2, iter.num_methods);
+ ut_asserteq(2, iter.first_glob_method);
+ ut_assert(!iter.doing_global);
+
+ ut_asserteq(0, iter.cur_method);
+ ut_asserteq(0, iter.part);
+ ut_asserteq(0, iter.max_part);
+ ut_asserteq_str("extlinux", iter.method->name);
+ ut_asserteq(0, bflow.err);
+
+ return 0;
+}
+BOOTSTD_TEST(bootflow_iter_glob, UTF_DM | UTF_SCAN_FDT);
+
/* Check using the system bootdev */
static int bootflow_system(struct unit_test_state *uts)
{
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 03/11] boot: Update first_glob_method when dropping a bootmeth
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 01/11] boot: Try all bootmeths on the final partition Simon Glass
2025-10-15 15:44 ` [PATCH v4 02/11] boot: Add a new test for global bootmeths Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 04/11] boot: Add a flag for whether there are global bootmeths Simon Glass
` (9 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Guillaume La Roque, Jerome Forissier, Mattijs Korpershoek,
Maximilian Brune, Moritz Fischer, Sam Protsenko
For now we only support dropping non-global bootmeths from the
iteration. Update first_glob_method in that case and add a few checks
that things are correct.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 6 ++++++
test/boot/bootflow.c | 8 ++++++++
2 files changed, 14 insertions(+)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index deb5f42ba65..62634a59a94 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -109,11 +109,17 @@ int bootflow_iter_drop_bootmeth(struct bootflow_iter *iter,
iter->method_order[iter->cur_method] != bmeth)
return -EINVAL;
+ log_debug("Dropping bootmeth '%s'\n", bmeth->name);
+
memmove(&iter->method_order[iter->cur_method],
&iter->method_order[iter->cur_method + 1],
(iter->num_methods - iter->cur_method - 1) * sizeof(void *));
iter->num_methods--;
+ if (iter->first_glob_method > 0) {
+ iter->first_glob_method--;
+ log_debug("first_glob_method %d\n", iter->first_glob_method);
+ }
return 0;
}
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index f3386a1eb31..07bf239485c 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -482,7 +482,11 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
/* Try to boot the bootmgr flow, which will fail */
console_record_reset_enable();
ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow));
+
+ /* at this point the global bootmeths are stranded above num_methods */
ut_asserteq(3, iter.num_methods);
+ ut_assert(!iter.doing_global);
+ ut_asserteq(3, iter.first_glob_method);
ut_asserteq_str("sandbox", iter.method->name);
ut_assertok(inject_response(uts));
ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow));
@@ -492,9 +496,13 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
/* Check that the sandbox bootmeth has been removed */
ut_asserteq(2, iter.num_methods);
+
for (i = 0; i < iter.num_methods; i++)
ut_assert(strcmp("sandbox", iter.method_order[i]->name));
+ /* the first global bootmeth is now down one place in the list */
+ ut_asserteq(2, iter.first_glob_method);
+
return 0;
}
BOOTSTD_TEST(bootflow_iter_disable, UTF_DM | UTF_SCAN_FDT | UTF_CONSOLE);
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 04/11] boot: Add a flag for whether there are global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (2 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 03/11] boot: Update first_glob_method when dropping a bootmeth Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 05/11] boot: Keep track of which bootmeths have been used Simon Glass
` (8 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Guillaume La Roque,
Jerome Forissier, Martyn Welch, Mattijs Korpershoek,
Sam Protsenko
The current 'doing_global' refers to being in the state of processing
global bootmeths. Since global bootmeths are currently used once at the
start, it becomes false once the last global bootmeth has been used.
In preparation for allowing bootmeths to run at other points in the
bootstd interation, add a new 'have_global' flag which tracks whether
there are any global bootmeths in the method_order[] list. It is set up
when iteration starts. Unlike doing_global which resets back to false
after the global bootmeths have been handled, once have_global is set to
true, it remains true for the entire iteration process. This provides a
quick check as to whether global-bootmeth processing is needed.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootmeth-uclass.c | 1 +
include/bootflow.h | 2 ++
test/boot/bootflow.c | 4 ++++
3 files changed, 7 insertions(+)
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index bb2dd8447cf..a0aa6336c9b 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -209,6 +209,7 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global)
iter->first_glob_method != -1 && iter->first_glob_method != count) {
iter->cur_method = iter->first_glob_method;
iter->doing_global = true;
+ iter->have_global = true;
}
iter->method_order = order;
iter->num_methods = count;
diff --git a/include/bootflow.h b/include/bootflow.h
index 2ef6eb25cf5..b18baebb4ba 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -255,6 +255,7 @@ enum bootflow_meth_flags_t {
* @cur_prio: Current priority being scanned
* @method_order: List of bootmeth devices to use, in order. The normal methods
* appear first, then the global ones, if any
+ * @have_global: true if we have global bootmeths in @method_order[]
* @doing_global: true if we are iterating through the global bootmeths (which
* happens before the normal ones)
* @method_flags: flags controlling which methods should be used for this @dev
@@ -278,6 +279,7 @@ struct bootflow_iter {
int first_glob_method;
enum bootdev_prio_t cur_prio;
struct udevice **method_order;
+ bool have_global;
bool doing_global;
int method_flags;
};
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 07bf239485c..83fb646babf 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -308,6 +308,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq_str("extlinux", iter.method->name);
ut_asserteq(0, bflow.err);
ut_assert(!iter.doing_global);
+ ut_assert(!iter.have_global);
ut_asserteq(-1, iter.first_glob_method);
/*
@@ -405,6 +406,7 @@ static int bootflow_iter_glob(struct unit_test_state *uts)
BOOTFLOWIF_SHOW, &bflow));
ut_asserteq(3, iter.num_methods);
ut_assert(iter.doing_global);
+ ut_assert(iter.have_global);
ut_asserteq(2, iter.first_glob_method);
ut_asserteq(2, iter.cur_method);
@@ -421,6 +423,7 @@ static int bootflow_iter_glob(struct unit_test_state *uts)
ut_asserteq(2, iter.num_methods);
ut_asserteq(2, iter.first_glob_method);
ut_assert(!iter.doing_global);
+ ut_assert(iter.have_global);
ut_asserteq(0, iter.cur_method);
ut_asserteq(0, iter.part);
@@ -486,6 +489,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
/* at this point the global bootmeths are stranded above num_methods */
ut_asserteq(3, iter.num_methods);
ut_assert(!iter.doing_global);
+ ut_assert(iter.have_global);
ut_asserteq(3, iter.first_glob_method);
ut_asserteq_str("sandbox", iter.method->name);
ut_assertok(inject_response(uts));
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 05/11] boot: Keep track of which bootmeths have been used
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (3 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 04/11] boot: Add a flag for whether there are global bootmeths Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 06/11] boot: Support rescanning the global bootmeths Simon Glass
` (7 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Guillaume La Roque, Jerome Forissier, Martyn Welch,
Mattijs Korpershoek, Maximilian Brune, Sam Protsenko
Add a bitfield which tracks when bootmeths have been used. This will be
needed when global bootmeths can be used later in the iteration.
Fix a missing bootflow_free() while here.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 13 +++++++++++++
boot/bootmeth-uclass.c | 10 ++++++++++
include/bootflow.h | 10 +++++++++-
test/boot/bootflow.c | 8 +++++++-
4 files changed, 39 insertions(+), 2 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 62634a59a94..2e4d1a345cd 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -17,6 +17,10 @@
#include <dm/device-internal.h>
#include <dm/uclass-internal.h>
+/* ensure BOOTMETH_MAX_COUNT fits in method_flags field */
+static_assert(BOOTMETH_MAX_COUNT <=
+ (sizeof(((struct bootflow_iter *)NULL)->method_flags) * 8));
+
/* error codes used to signal running out of things */
enum {
BF_NO_MORE_PARTS = -ESHUTDOWN,
@@ -433,6 +437,10 @@ int bootflow_scan_first(struct udevice *dev, const char *label,
bootflow_iter_set_dev(iter, dev, method_flags);
}
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) {
+ iter->methods_done |= BIT(iter->cur_method);
+ log_debug("methods_done now %x\n", iter->cur_method);
+ }
ret = bootflow_check(iter, bflow);
if (ret) {
log_debug("check - ret=%d\n", ret);
@@ -460,6 +468,11 @@ int bootflow_scan_next(struct bootflow_iter *iter, struct bootflow *bflow)
return log_msg_ret("done", ret);
if (!ret) {
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL)) {
+ iter->methods_done |= BIT(iter->cur_method);
+ log_debug("methods_done now %x\n",
+ iter->cur_method);
+ }
ret = bootflow_check(iter, bflow);
log_debug("check - ret=%d\n", ret);
if (!ret)
diff --git a/boot/bootmeth-uclass.c b/boot/bootmeth-uclass.c
index a0aa6336c9b..a9709465f6e 100644
--- a/boot/bootmeth-uclass.c
+++ b/boot/bootmeth-uclass.c
@@ -211,6 +211,16 @@ int bootmeth_setup_iter_order(struct bootflow_iter *iter, bool include_global)
iter->doing_global = true;
iter->have_global = true;
}
+
+ /*
+ * check we don't exceed the maximum bits in methods_done when tracking
+ * which global bootmeths have run
+ */
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && count > BOOTMETH_MAX_COUNT) {
+ free(order);
+ return log_msg_ret("tmb", -ENOSPC);
+ }
+
iter->method_order = order;
iter->num_methods = count;
diff --git a/include/bootflow.h b/include/bootflow.h
index b18baebb4ba..58a4ab9f811 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -11,7 +11,8 @@
#include <bootdev.h>
#include <image.h>
#include <dm/ofnode_decl.h>
-#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/build_bug.h>
struct bootstd_priv;
struct expo;
@@ -213,6 +214,10 @@ enum bootflow_meth_flags_t {
BOOTFLOW_METHF_SINGLE_UCLASS = 1 << 3,
};
+enum {
+ BOOTMETH_MAX_COUNT = 32,
+};
+
/**
* struct bootflow_iter - state for iterating through bootflows
*
@@ -260,6 +265,8 @@ enum bootflow_meth_flags_t {
* happens before the normal ones)
* @method_flags: flags controlling which methods should be used for this @dev
* (enum bootflow_meth_flags_t)
+ * @methods_done: indicates which methods have been processed, one bit for
+ * each method in @method_order[]
*/
struct bootflow_iter {
int flags;
@@ -282,6 +289,7 @@ struct bootflow_iter {
bool have_global;
bool doing_global;
int method_flags;
+ uint methods_done;
};
/**
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 83fb646babf..8317dee1e20 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -310,6 +310,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_assert(!iter.doing_global);
ut_assert(!iter.have_global);
ut_asserteq(-1, iter.first_glob_method);
+ ut_asserteq(BIT(0), iter.methods_done);
/*
* This shows MEDIA even though there is none, since in
@@ -318,6 +319,7 @@ static int bootflow_iter(struct unit_test_state *uts)
* know.
*/
ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+ bootflow_free(&bflow);
ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow));
ut_asserteq(2, iter.num_methods);
@@ -327,6 +329,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq_str("efi", iter.method->name);
ut_asserteq(0, bflow.err);
ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+ ut_asserteq(BIT(0) | BIT(1), iter.methods_done);
bootflow_free(&bflow);
/* The next device is mmc1.bootdev - at first we use the whole device */
@@ -338,6 +341,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq_str("extlinux", iter.method->name);
ut_asserteq(0, bflow.err);
ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+ ut_asserteq(BIT(0) | BIT(1), iter.methods_done);
bootflow_free(&bflow);
ut_asserteq(-ENOENT, bootflow_scan_next(&iter, &bflow));
@@ -348,9 +352,10 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq_str("efi", iter.method->name);
ut_asserteq(0, bflow.err);
ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+ ut_asserteq(BIT(0) | BIT(1), iter.methods_done);
bootflow_free(&bflow);
- /* Then more to partition 1 where we find something */
+ /* Then move to partition 1 where we find something */
ut_assertok(bootflow_scan_next(&iter, &bflow));
ut_asserteq(2, iter.num_methods);
ut_asserteq(0, iter.cur_method);
@@ -380,6 +385,7 @@ static int bootflow_iter(struct unit_test_state *uts)
ut_asserteq_str("extlinux", iter.method->name);
ut_asserteq(0, bflow.err);
ut_asserteq(BOOTFLOWST_MEDIA, bflow.state);
+ ut_asserteq(BIT(0) | BIT(1), iter.methods_done);
bootflow_free(&bflow);
bootflow_iter_uninit(&iter);
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 06/11] boot: Support rescanning the global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (4 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 05/11] boot: Keep track of which bootmeths have been used Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 07/11] boot: Only run global bootmeths once each Simon Glass
` (6 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Mattijs Korpershoek, Maximilian Brune, Moritz Fischer,
Sam Protsenko
Add the logic to scan through the global bootmeths for every new
bootdev, in preparation for allowing global bootmeths to select where in
the hunter ordering they go.
Use a new bootmeth_glob_allowed() function to check if a bootmeth is
allowed, ensuring that each can run at most once.
For now this has no actual effect, since the global bootmeths are
unconditionally processed at the start, with iter->methods_done being
updated to include all of them. Therefore when scanning again, no
unprocessed global bootmeths will be found.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 90 ++++++++++++++++++++++++++++++++++++++++++++--
include/bootflow.h | 5 +++
2 files changed, 93 insertions(+), 2 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 2e4d1a345cd..73deba24d30 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -187,19 +187,81 @@ static void scan_next_in_uclass(struct udevice **devp)
*devp = dev;
}
+/**
+ * bootmeth_glob_allowed() - Check if a global bootmeth is usable at this point
+ *
+ * @iter: Bootflow iterator being used
+ * Return: true if the global bootmeth has not already been used
+ */
+static bool bootmeth_glob_allowed(struct bootflow_iter *iter, int meth_seq)
+{
+ struct udevice *meth = iter->method_order[meth_seq];
+ bool done = iter->methods_done & BIT(meth_seq);
+
+ log_debug("considering glob '%s': done %d\n", meth->name, done);
+
+ /* if this one has already been used, try the next */
+ if (done)
+ return false;
+
+ return true;
+}
+
+/**
+ * next_glob_bootmeth() - Find the next global bootmeth to use
+ *
+ * Scans the global bootmeths to find the first unused one whose priority has
+ * been reached. If found, iter->cur_method and iter->method are set up and
+ * doing_global is set to true
+ *
+ * @iter: Bootflow iterator being used
+ * Return 0 if found, -ENOENT if no more global bootmeths are available
+ */
+static int next_glob_bootmeth(struct bootflow_iter *iter)
+{
+ log_debug("rescan global bootmeths have_global %d\n",
+ iter->have_global);
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->have_global) {
+ int i;
+
+ /* rescan the global bootmeths */
+ log_debug("first_glob_method %d num_methods %d methods_done %x\n",
+ iter->first_glob_method, iter->num_methods,
+ iter->methods_done);
+ for (i = iter->first_glob_method; i < iter->num_methods; i++) {
+ if (bootmeth_glob_allowed(iter, i)) {
+ iter->cur_method = i;
+ iter->method = iter->method_order[i];
+ iter->doing_global = true;
+ iter->dev = NULL;
+ return 0;
+ }
+ }
+ }
+
+ return -ENOENT;
+}
+
/**
* prepare_bootdev() - Get ready to use a bootdev
*
* @iter: Bootflow iterator being used
* @dev: UCLASS_BOOTDEV device to use
* @method_flags: Method flag for the bootdev
+ * @check_global: true to check global bootmeths before processing @dev
* Return 0 if OK, -ve if the bootdev failed to probe
*/
static int prepare_bootdev(struct bootflow_iter *iter, struct udevice *dev,
- int method_flags)
+ int method_flags, bool check_global)
{
int ret;
+ if (check_global && !next_glob_bootmeth(iter)) {
+ iter->pending_bootdev = dev;
+ iter->pending_method_flags = method_flags;
+ return 0;
+ }
+
/*
* Probe the bootdev. This does not probe any attached block device,
* since they are siblings
@@ -245,6 +307,30 @@ static int iter_incr(struct bootflow_iter *iter)
iter->num_methods = iter->first_glob_method;
iter->doing_global = false;
+ /*
+ * we've come to the end, so see if we should use a pending
+ * bootdev from when we decided to rescan the global bootmeths
+ */
+ if (iter->pending_bootdev) {
+ int meth_flags = iter->pending_method_flags;
+
+ dev = iter->pending_bootdev;
+ iter->pending_bootdev = NULL;
+ iter->pending_method_flags = 0;
+
+ ret = prepare_bootdev(iter, dev, meth_flags, false);
+ if (ret)
+ return log_msg_ret("ipb", ret);
+
+ iter->cur_method = 0;
+ iter->method = iter->method_order[iter->cur_method];
+
+ log_debug("-> using pending bootdev '%s' method '%s'\n",
+ dev->name, iter->method->name);
+
+ return 0;
+ }
+
/*
* Don't move to the next dev as we haven't tried this
* one yet!
@@ -347,7 +433,7 @@ static int iter_incr(struct bootflow_iter *iter)
if (ret)
bootflow_iter_set_dev(iter, NULL, 0);
else
- ret = prepare_bootdev(iter, dev, method_flags);
+ ret = prepare_bootdev(iter, dev, method_flags, true);
}
/* if there are no more bootdevs, give up */
diff --git a/include/bootflow.h b/include/bootflow.h
index 58a4ab9f811..059d38251b7 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -267,6 +267,9 @@ enum {
* (enum bootflow_meth_flags_t)
* @methods_done: indicates which methods have been processed, one bit for
* each method in @method_order[]
+ * @pending_bootdev: if non-NULL, bootdev which will be used when the global
+ * bootmeths are done
+ * @pending_method_flags: method flags which will be used with @pending_bootdev
*/
struct bootflow_iter {
int flags;
@@ -290,6 +293,8 @@ struct bootflow_iter {
bool doing_global;
int method_flags;
uint methods_done;
+ struct udevice *pending_bootdev;
+ int pending_method_flags;
};
/**
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 07/11] boot: Only run global bootmeths once each
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (5 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 06/11] boot: Support rescanning the global bootmeths Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 08/11] boot: Implement a priority for global bootmeths Simon Glass
` (5 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Mattijs Korpershoek, Maximilian Brune, Moritz Fischer,
Sam Protsenko
Use the methods_done flags to make sure that each global bootmeth is
only used once. For now this has no effect, since they are all processed
at the start.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 73deba24d30..ca1fe741bab 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -294,7 +294,13 @@ static int iter_incr(struct bootflow_iter *iter)
return BF_NO_MORE_DEVICES;
/* Get the next boothmethod */
- if (++iter->cur_method < iter->num_methods) {
+ for (iter->cur_method++; iter->cur_method < iter->num_methods;
+ iter->cur_method++) {
+ /* loop until we find a global bootmeth we haven't used */
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global &&
+ !bootmeth_glob_allowed(iter, iter->cur_method))
+ continue;
+
iter->method = iter->method_order[iter->cur_method];
return 0;
}
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 08/11] boot: Implement a priority for global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (6 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 07/11] boot: Only run global bootmeths once each Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 09/11] boot: Don't change the method count after " Simon Glass
` (4 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Martyn Welch, Mattijs Korpershoek, Maximilian Brune,
Sam Protsenko
Allow bootmeths to select when they want to run, using the bootdev
priority. Provide a new bootmeth_glob_allowed() function which checks if
a bootmeth is ready to use.
Fix a comment in bootflow_system() which is a test for global bootmeths.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 15 +++++++++++----
include/bootflow.h | 2 +-
include/bootmeth.h | 4 ++++
3 files changed, 16 insertions(+), 5 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index ca1fe741bab..1a4cd0e28e8 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -191,17 +191,24 @@ static void scan_next_in_uclass(struct udevice **devp)
* bootmeth_glob_allowed() - Check if a global bootmeth is usable at this point
*
* @iter: Bootflow iterator being used
- * Return: true if the global bootmeth has not already been used
+ * Return: true if the global bootmeth has a suitable priority and has not
+ * already been used
*/
static bool bootmeth_glob_allowed(struct bootflow_iter *iter, int meth_seq)
{
struct udevice *meth = iter->method_order[meth_seq];
bool done = iter->methods_done & BIT(meth_seq);
+ struct bootmeth_uc_plat *ucp;
- log_debug("considering glob '%s': done %d\n", meth->name, done);
+ ucp = dev_get_uclass_plat(meth);
+ log_debug("considering glob '%s': done %d glob_prio %d\n", meth->name,
+ done, ucp->glob_prio);
- /* if this one has already been used, try the next */
- if (done)
+ /*
+ * if this one has already been used, or its priority is too low, try
+ * the next
+ */
+ if (done || ucp->glob_prio > iter->cur_prio)
return false;
return true;
diff --git a/include/bootflow.h b/include/bootflow.h
index 059d38251b7..1cfdda403ac 100644
--- a/include/bootflow.h
+++ b/include/bootflow.h
@@ -262,7 +262,7 @@ enum {
* appear first, then the global ones, if any
* @have_global: true if we have global bootmeths in @method_order[]
* @doing_global: true if we are iterating through the global bootmeths (which
- * happens before the normal ones)
+ * generally happens before the normal ones)
* @method_flags: flags controlling which methods should be used for this @dev
* (enum bootflow_meth_flags_t)
* @methods_done: indicates which methods have been processed, one bit for
diff --git a/include/bootmeth.h b/include/bootmeth.h
index 26de593a9a4..2a492dfd73a 100644
--- a/include/bootmeth.h
+++ b/include/bootmeth.h
@@ -30,10 +30,14 @@ enum bootmeth_flags {
*
* @desc: A long description of the bootmeth
* @flags: Flags for this bootmeth (enum bootmeth_flags)
+ * @glob_prio: Priority for this bootmeth. If unset (0) the bootmeth is started
+ * before all other bootmeths. Otherwise it is started before the iteration
+ * reaches the given priority.
*/
struct bootmeth_uc_plat {
const char *desc;
int flags;
+ enum bootdev_prio_t glob_prio;
};
/** struct bootmeth_ops - Operations for boot methods */
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 09/11] boot: Don't change the method count after global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (7 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 08/11] boot: Implement a priority for global bootmeths Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 10/11] boot: Run global bootmeths after all bootdevs are exhausted Simon Glass
` (3 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Guillaume La Roque, Jerome Forissier, Mattijs Korpershoek,
Maximilian Brune, Moritz Fischer, Sam Protsenko
At present before scanning global bootmeths, the iterator sets the
method count to the index of the first global bootmeth. Now that we
support scanning the global bootmeths multiple times, we must leave this
count alone.
Check against have_global and first_glob_method instead.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v1)
boot/bootflow.c | 18 ++++++++++++++----
test/boot/bootflow.c | 6 +++---
2 files changed, 17 insertions(+), 7 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 1a4cd0e28e8..38b8af916b2 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -304,9 +304,20 @@ static int iter_incr(struct bootflow_iter *iter)
for (iter->cur_method++; iter->cur_method < iter->num_methods;
iter->cur_method++) {
/* loop until we find a global bootmeth we haven't used */
- if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global &&
- !bootmeth_glob_allowed(iter, iter->cur_method))
- continue;
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->doing_global) {
+ if (!bootmeth_glob_allowed(iter, iter->cur_method))
+ continue;
+
+ iter->method = iter->method_order[iter->cur_method];
+ log_debug("-> next global method '%s'\n",
+ iter->method->name);
+ return 0;
+ }
+
+ /* at this point we are only considering non-global bootmeths */
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && iter->have_global &&
+ iter->cur_method >= iter->first_glob_method)
+ break;
iter->method = iter->method_order[iter->cur_method];
return 0;
@@ -317,7 +328,6 @@ static int iter_incr(struct bootflow_iter *iter)
* normal bootdev scan
*/
if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && global) {
- iter->num_methods = iter->first_glob_method;
iter->doing_global = false;
/*
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 8317dee1e20..20297136e3f 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -426,7 +426,7 @@ static int bootflow_iter_glob(struct unit_test_state *uts)
ut_asserteq(-EPROTONOSUPPORT, bootflow_scan_next(&iter, &bflow));
/* at this point the global bootmeths are stranded above num_methods */
- ut_asserteq(2, iter.num_methods);
+ ut_asserteq(3, iter.num_methods);
ut_asserteq(2, iter.first_glob_method);
ut_assert(!iter.doing_global);
ut_assert(iter.have_global);
@@ -493,7 +493,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
ut_assertok(bootflow_scan_first(NULL, NULL, &iter, 0, &bflow));
/* at this point the global bootmeths are stranded above num_methods */
- ut_asserteq(3, iter.num_methods);
+ ut_asserteq(4, iter.num_methods);
ut_assert(!iter.doing_global);
ut_assert(iter.have_global);
ut_asserteq(3, iter.first_glob_method);
@@ -505,7 +505,7 @@ static int bootflow_iter_disable(struct unit_test_state *uts)
ut_assert_console_end();
/* Check that the sandbox bootmeth has been removed */
- ut_asserteq(2, iter.num_methods);
+ ut_asserteq(3, iter.num_methods);
for (i = 0; i < iter.num_methods; i++)
ut_assert(strcmp("sandbox", iter.method_order[i]->name));
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 10/11] boot: Run global bootmeths after all bootdevs are exhausted
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (8 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 09/11] boot: Don't change the method count after " Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 15:44 ` [PATCH v4 11/11] boot: Run the EFI bootmgr just before network devices Simon Glass
` (2 subsequent siblings)
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Andrew Goodbody,
Martin Schwan, Martyn Welch, Maximilian Brune, Moritz Fischer
When there are no more bootdevs we should still go through the global
bootmeths, since some may not have yet been used, if their priority has
not yet come up.
Add a final check for this at the end of the iterator.
Update the documentation to match the new behaviour of global bootmeths.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v3)
Changes in v3:
- Pull doc changes into this patch
Changes in v2:
- Add a bit more detail suggested by Heinrich
boot/bootflow.c | 23 ++++++++++++++++++
doc/develop/bootstd/overview.rst | 40 +++++++++++++++++++++++++++-----
2 files changed, 57 insertions(+), 6 deletions(-)
diff --git a/boot/bootflow.c b/boot/bootflow.c
index 38b8af916b2..d8a4a81a838 100644
--- a/boot/bootflow.c
+++ b/boot/bootflow.c
@@ -354,6 +354,18 @@ static int iter_incr(struct bootflow_iter *iter)
return 0;
}
+ /* if this was the final global bootmeth check, we are done */
+ if (iter->cur_prio == BOOTDEVP_COUNT) {
+ log_debug("-> done global bootmeths\n");
+
+ /* print the same message as bootflow_iter_set_dev() */
+ if ((iter->flags & (BOOTFLOWIF_SHOW |
+ BOOTFLOWIF_SINGLE_DEV)) ==
+ BOOTFLOWIF_SHOW)
+ printf("No more bootdevs\n");
+ return BF_NO_MORE_DEVICES;
+ }
+
/*
* Don't move to the next dev as we haven't tried this
* one yet!
@@ -459,6 +471,17 @@ static int iter_incr(struct bootflow_iter *iter)
ret = prepare_bootdev(iter, dev, method_flags, true);
}
+ if (IS_ENABLED(CONFIG_BOOTMETH_GLOBAL) && ret) {
+ log_debug("no more bootdevs, trying global\n");
+
+ /* allow global bootmeths with any priority */
+ iter->cur_prio = BOOTDEVP_COUNT;
+ if (!next_glob_bootmeth(iter)) {
+ log_debug("-> next method '%s'\n", iter->method->name);
+ return 0;
+ }
+ }
+
/* if there are no more bootdevs, give up */
if (ret)
return log_msg_ret("incr", BF_NO_MORE_DEVICES);
diff --git a/doc/develop/bootstd/overview.rst b/doc/develop/bootstd/overview.rst
index 0a237359575..e36cde4d360 100644
--- a/doc/develop/bootstd/overview.rst
+++ b/doc/develop/bootstd/overview.rst
@@ -133,7 +133,8 @@ which scans for available bootflows, optionally listing each find it finds (-l)
and trying to boot it (-b).
When global bootmeths are available, these are typically checked before the
-above bootdev scanning.
+above bootdev scanning, but it is possible provide a priority to make them
+run later, by setting the glob_prio field in the driver's bind() method.
Controlling ordering
@@ -612,9 +613,9 @@ simply copied into the iterator. Either way, the `method_order` array it set up,
along with `num_methods`.
Note that global bootmeths are always put at the end of the ordering. If any are
-present, `cur_method` is set to the first one, so that global bootmeths are done
-first. Once all have been used, these bootmeths are dropped from the iteration.
-When there are no global bootmeths, `cur_method` is set to 0.
+present, `cur_method` is set to the first one, so that global bootmeths are
+processed first, so long as their priority allows it. Bootstd keeps track of
+which global bootmeths have been used, to make sure they are only used once.
At this point the iterator is ready to use, with the first bootmeth selected.
Most of the other fields are 0. This means that the current partition
@@ -714,8 +715,35 @@ to the next partition, or bootdev, for example. The special values
`BF_NO_MORE_PARTS` and `BF_NO_MORE_DEVICES` handle this. When `iter_incr` sees
`BF_NO_MORE_PARTS` it knows that it should immediately move to the next bootdev.
When it sees `BF_NO_MORE_DEVICES` it knows that there is nothing more it can do
-so it should immediately return. The caller of `iter_incr()` is responsible for
-updating the `err` field, based on the return value it sees.
+so it should immediately run any unused global bootmeths and then return. The
+caller of `iter_incr()` is responsible for updating the `err` field, based on
+the return value it sees.
+
+Global bootmeths can have a non-zero priority, which indicates where in the
+iteration sequence they should run. Each time a new bootdev is produced by a
+hunter, all of the global bootmeths are first checked to see if they should run
+before this new bootdev. For example, if the bootdev was produced by a hunter
+with priority BOOTDEVP_6_NET_BASE, then a quick check is made for global
+bootmeths with that priority or less. If there are any, they run before the new
+bootdev is processed.
+
+Assuming they are enabled and the iteration sequence runs right to the end, all
+global bootmeths will be used. This is handled by a special case at the end of
+iter_incr(), where it processes amy so-far-unused global bootmeths.
+
+It is important to note the special nature of global bootmeths, with respect to
+priority. If there are two normal bootmeths and a global one, the normal ones
+are run for each bootdev, but the global one is independent of bootdevs. The
+order might be:
+
+ bootdev priority 3: normal-1, normal-3
+ global-2, prio 4
+ bootdev priority 5: normal-1, normal-3
+
+Of course if a specific bootmeth ordering is provided, then this overrides the
+default ordering. Global bootmeths must be listed at the end, reflecting their
+hybrid nature (they are bootmeths but operate on the system as a whole, not on
+a particular bootdev).
The above describes the iteration process at a high level. It is basically a
very simple increment function with a checker called `bootflow_check()` that
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* [PATCH v4 11/11] boot: Run the EFI bootmgr just before network devices
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (9 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 10/11] boot: Run global bootmeths after all bootdevs are exhausted Simon Glass
@ 2025-10-15 15:44 ` Simon Glass
2025-10-15 19:09 ` [PATCH v4 00/11] boot: Support priority for global bootmeths Tom Rini
2025-10-22 22:16 ` Tom Rini
12 siblings, 0 replies; 17+ messages in thread
From: Simon Glass @ 2025-10-15 15:44 UTC (permalink / raw)
To: u-boot
Cc: Heinrich Schuchardt, Tom Rini, Simon Glass, Guillaume La Roque,
Jerome Forissier, Mattijs Korpershoek
At present the EFI bootmgr scans all devices in the system before
deciding which one to boot. Ideally it would use the bootstd iterator
for this, but in the meantime, give it a lower priority, so it runs
just before the network devices.
Note that if there are no hunted network devices hunted, then it will
run at the end, after all bootdevs are exhausted. In other words, it
will always run.
Signed-off-by: Simon Glass <sjg@chromium.org>
---
(no changes since v2)
Changes in v2:
- Update commit message to indicate the bootmeth will always run
- Document how the priority was chosen
boot/bootmeth_efi_mgr.c | 9 +++++++++
test/boot/bootflow.c | 4 ++--
2 files changed, 11 insertions(+), 2 deletions(-)
diff --git a/boot/bootmeth_efi_mgr.c b/boot/bootmeth_efi_mgr.c
index 42b8863815e..05fc35d01a9 100644
--- a/boot/bootmeth_efi_mgr.c
+++ b/boot/bootmeth_efi_mgr.c
@@ -99,6 +99,15 @@ static int bootmeth_efi_mgr_bind(struct udevice *dev)
plat->desc = "EFI bootmgr flow";
plat->flags = BOOTMETHF_GLOBAL;
+ /*
+ * bootmgr scans all available devices which can take a while,
+ * especially for network devices. So choose the priority so that it
+ * comes just before the 'very slow' devices. This allows systems which
+ * don't rely on bootmgr to boot quickly, while allowing bootmgr to run
+ * on systems which need it.
+ */
+ plat->glob_prio = BOOTDEVP_6_NET_BASE;
+
return 0;
}
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 20297136e3f..cc5eed75d83 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -454,11 +454,11 @@ static int bootflow_system(struct unit_test_state *uts)
ut_assertok(device_probe(dev));
sandbox_set_fake_efi_mgr_dev(dev, true);
- /* We should get a single 'bootmgr' method at the start */
+ /* We should get a single 'bootmgr' method at the end */
bootstd_clear_glob();
ut_assertok(run_command("bootflow scan -lH", 0));
ut_assert_skip_to_line(
- " 0 efi_mgr ready (none) 0 <NULL> ");
+ " 1 efi_mgr ready (none) 0 <NULL> ");
ut_assert_skip_to_line("No more bootdevs");
ut_assert_skip_to_line("(2 bootflows, 2 valid)");
ut_assert_console_end();
--
2.43.0
^ permalink raw reply related [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/11] boot: Try all bootmeths on the final partition
2025-10-15 15:44 ` [PATCH v4 01/11] boot: Try all bootmeths on the final partition Simon Glass
@ 2025-10-15 19:04 ` Tom Rini
2025-10-16 12:55 ` Heinrich Schuchardt
0 siblings, 1 reply; 17+ messages in thread
From: Tom Rini @ 2025-10-15 19:04 UTC (permalink / raw)
To: Simon Glass
Cc: u-boot, Heinrich Schuchardt, Andrew Goodbody, Maximilian Brune,
Moritz Fischer, Sam Protsenko
[-- Attachment #1: Type: text/plain, Size: 726 bytes --]
On Wed, Oct 15, 2025 at 04:44:04PM +0100, Simon Glass wrote:
> At present, normally when one bootmeth fails on a partition, we move on
> and try the next bootmeth. However, this was not the case for the final
> partition due to a bug. Rework the logic so that all partitions are
> treated the same.
>
> Signed-off-by: Simon Glass <sjg@chromium.org>
> ---
>
> Changes in v4:
> - Reword the commit message as Tom suggested
>
> boot/bootflow.c | 34 ++++++++++++++++------------------
> 1 file changed, 16 insertions(+), 18 deletions(-)
I'm glad you reworded this, but it's frustrating you didn't also post
this stand alone (and presumably sooner) as was requested as it's a
stand alone fix.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 00/11] boot: Support priority for global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (10 preceding siblings ...)
2025-10-15 15:44 ` [PATCH v4 11/11] boot: Run the EFI bootmgr just before network devices Simon Glass
@ 2025-10-15 19:09 ` Tom Rini
2025-10-22 22:16 ` Tom Rini
12 siblings, 0 replies; 17+ messages in thread
From: Tom Rini @ 2025-10-15 19:09 UTC (permalink / raw)
To: Simon Glass
Cc: u-boot, Heinrich Schuchardt, Andrew Goodbody, Guillaume La Roque,
Jerome Forissier, Martin Schwan, Martyn Welch,
Mattijs Korpershoek, Maximilian Brune, Moritz Fischer,
Sam Protsenko
[-- Attachment #1: Type: text/plain, Size: 1970 bytes --]
On Wed, Oct 15, 2025 at 04:44:03PM +0100, Simon Glass wrote:
> At present global bootmeths always run first, before all other
> bootmeths. Optimisations in the code take advantage of this, putting
> them at the end, so they can be used once and then forgotten.
>
> In some cases it is useful to run global bootmeths later in the boot.
> For example, the EFI-bootmgr bootmeth may itself scan devices and the
> network, so running it first can hold up the boot significantly for
> boards not actually relying on EFI-bootmgr to boot.
>
> This series introduces a new field in global bootmeths which indicates
> the priority, using the same scheme as is used with bootdev hunters.
> Thus it is possible to insert the EFI-bootmgr bootmeth just before the
> hunter for network bootdevs is invoked.
>
> Despite the simplicity of the concept and the relatively small series,
> this is a fairly significant enhancement. It is also quite tricky to
> implement, largely due to the way the original code was written, with
> global bootmeths being a small, size-optimised add-on to the original
> bootstd implementation.
>
> For now we only allow each global bootmeth to run at most once, but this
> implementation is written in a way that we could relax that if needed.
> Then the bootmeth itself could decide whether to run at any particular
> point in the bootflow iteration.
>
> Size growth is about 390 bytes on Thumb2 (e.g. firefly-rk3288) if
> CONFIG_BOOTMETH_GLOBAL is enabled, which it normally is. With that
> disabled (which saves about 4K on the same platform), there is no
> growth.
>
> Changes in v4:
> - Reword the commit message as Tom suggested
> - Drop call to bootflow_show()
> - Rebase on top of -master
Aside from my comment on the first patch, the big thing is if this
addresses the problems Andre reported or not. This is likely the right
step forward regardless, but might not be everything needed.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/11] boot: Try all bootmeths on the final partition
2025-10-15 19:04 ` Tom Rini
@ 2025-10-16 12:55 ` Heinrich Schuchardt
2025-10-16 15:33 ` Tom Rini
0 siblings, 1 reply; 17+ messages in thread
From: Heinrich Schuchardt @ 2025-10-16 12:55 UTC (permalink / raw)
To: Tom Rini
Cc: u-boot, Andrew Goodbody, Maximilian Brune, Moritz Fischer,
Sam Protsenko, Simon Glass
On 10/15/25 21:04, Tom Rini wrote:
> On Wed, Oct 15, 2025 at 04:44:04PM +0100, Simon Glass wrote:
>
>> At present, normally when one bootmeth fails on a partition, we move on
>> and try the next bootmeth. However, this was not the case for the final
>> partition due to a bug. Rework the logic so that all partitions are
>> treated the same.
>>
>> Signed-off-by: Simon Glass <sjg@chromium.org>
>> ---
>>
>> Changes in v4:
>> - Reword the commit message as Tom suggested
>>
>> boot/bootflow.c | 34 ++++++++++++++++------------------
>> 1 file changed, 16 insertions(+), 18 deletions(-)
>
> I'm glad you reworded this, but it's frustrating you didn't also post
> this stand alone (and presumably sooner) as was requested as it's a
> stand alone fix.
>
I guess you could still apply it standalone to origin/master.
Best regards
Heinrich
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 01/11] boot: Try all bootmeths on the final partition
2025-10-16 12:55 ` Heinrich Schuchardt
@ 2025-10-16 15:33 ` Tom Rini
0 siblings, 0 replies; 17+ messages in thread
From: Tom Rini @ 2025-10-16 15:33 UTC (permalink / raw)
To: Heinrich Schuchardt
Cc: u-boot, Andrew Goodbody, Maximilian Brune, Moritz Fischer,
Sam Protsenko, Simon Glass
[-- Attachment #1: Type: text/plain, Size: 1135 bytes --]
On Thu, Oct 16, 2025 at 02:55:27PM +0200, Heinrich Schuchardt wrote:
> On 10/15/25 21:04, Tom Rini wrote:
> > On Wed, Oct 15, 2025 at 04:44:04PM +0100, Simon Glass wrote:
> >
> > > At present, normally when one bootmeth fails on a partition, we move on
> > > and try the next bootmeth. However, this was not the case for the final
> > > partition due to a bug. Rework the logic so that all partitions are
> > > treated the same.
> > >
> > > Signed-off-by: Simon Glass <sjg@chromium.org>
> > > ---
> > >
> > > Changes in v4:
> > > - Reword the commit message as Tom suggested
> > >
> > > boot/bootflow.c | 34 ++++++++++++++++------------------
> > > 1 file changed, 16 insertions(+), 18 deletions(-)
> >
> > I'm glad you reworded this, but it's frustrating you didn't also post
> > this stand alone (and presumably sooner) as was requested as it's a
> > stand alone fix.
> >
>
> I guess you could still apply it standalone to origin/master.
I'll take the whole series at some point soon'ish. But this would
already have been applied if it was standalone as suggested a while ago
now.
--
Tom
[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 228 bytes --]
^ permalink raw reply [flat|nested] 17+ messages in thread
* Re: [PATCH v4 00/11] boot: Support priority for global bootmeths
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
` (11 preceding siblings ...)
2025-10-15 19:09 ` [PATCH v4 00/11] boot: Support priority for global bootmeths Tom Rini
@ 2025-10-22 22:16 ` Tom Rini
12 siblings, 0 replies; 17+ messages in thread
From: Tom Rini @ 2025-10-22 22:16 UTC (permalink / raw)
To: u-boot, Simon Glass
Cc: Heinrich Schuchardt, Andrew Goodbody, Guillaume La Roque,
Jerome Forissier, Martin Schwan, Martyn Welch,
Mattijs Korpershoek, Maximilian Brune, Moritz Fischer,
Sam Protsenko
On Wed, 15 Oct 2025 16:44:03 +0100, Simon Glass wrote:
> At present global bootmeths always run first, before all other
> bootmeths. Optimisations in the code take advantage of this, putting
> them at the end, so they can be used once and then forgotten.
>
> In some cases it is useful to run global bootmeths later in the boot.
> For example, the EFI-bootmgr bootmeth may itself scan devices and the
> network, so running it first can hold up the boot significantly for
> boards not actually relying on EFI-bootmgr to boot.
>
> [...]
Applied to u-boot/master, thanks!
[01/11] boot: Try all bootmeths on the final partition
commit: 396c9b59644081a05a8b078eadc2c4aead37160d
[02/11] boot: Add a new test for global bootmeths
commit: a2301201e36d665c08b51617e1c66133b32d9808
[03/11] boot: Update first_glob_method when dropping a bootmeth
commit: eca985905d7956ca69e1abfe9ef1d3eb5c64c0a9
[04/11] boot: Add a flag for whether there are global bootmeths
commit: 0fe6de0dc5b137a2def3a8cc0baa2fb73a3f8541
[05/11] boot: Keep track of which bootmeths have been used
commit: bef963cb751049cacc86f2754452efadd03ae2f0
[06/11] boot: Support rescanning the global bootmeths
commit: 8e31093dbce4fb233c6f14520149293b92981b50
[07/11] boot: Only run global bootmeths once each
commit: e52053c93c128284ccfae11001d7b211bb081aeb
[08/11] boot: Implement a priority for global bootmeths
commit: 4ce78089b2a615eab466347e8996fbd54a876234
[09/11] boot: Don't change the method count after global bootmeths
commit: eff1dca96330269c8281b17d00f5d2d0e62bd26e
[10/11] boot: Run global bootmeths after all bootdevs are exhausted
commit: 060ce66b83e5ed19180103c26e525d85c2a2aa8b
[11/11] boot: Run the EFI bootmgr just before network devices
commit: 6a56d10fdcf1309d2070b62dc15e80a047da971b
--
Tom
^ permalink raw reply [flat|nested] 17+ messages in thread
end of thread, other threads:[~2025-10-22 22:16 UTC | newest]
Thread overview: 17+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2025-10-15 15:44 [PATCH v4 00/11] boot: Support priority for global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 01/11] boot: Try all bootmeths on the final partition Simon Glass
2025-10-15 19:04 ` Tom Rini
2025-10-16 12:55 ` Heinrich Schuchardt
2025-10-16 15:33 ` Tom Rini
2025-10-15 15:44 ` [PATCH v4 02/11] boot: Add a new test for global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 03/11] boot: Update first_glob_method when dropping a bootmeth Simon Glass
2025-10-15 15:44 ` [PATCH v4 04/11] boot: Add a flag for whether there are global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 05/11] boot: Keep track of which bootmeths have been used Simon Glass
2025-10-15 15:44 ` [PATCH v4 06/11] boot: Support rescanning the global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 07/11] boot: Only run global bootmeths once each Simon Glass
2025-10-15 15:44 ` [PATCH v4 08/11] boot: Implement a priority for global bootmeths Simon Glass
2025-10-15 15:44 ` [PATCH v4 09/11] boot: Don't change the method count after " Simon Glass
2025-10-15 15:44 ` [PATCH v4 10/11] boot: Run global bootmeths after all bootdevs are exhausted Simon Glass
2025-10-15 15:44 ` [PATCH v4 11/11] boot: Run the EFI bootmgr just before network devices Simon Glass
2025-10-15 19:09 ` [PATCH v4 00/11] boot: Support priority for global bootmeths Tom Rini
2025-10-22 22:16 ` Tom Rini
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox