summaryrefslogtreecommitdiff
path: root/test
diff options
context:
space:
mode:
authorTom Rini <[email protected]>2025-10-22 14:17:16 -0600
committerTom Rini <[email protected]>2025-10-22 16:16:31 -0600
commitb10c055d4e1b5153a331a61ef82a5b01b5bb4c45 (patch)
tree71eed5c423cb81260e92ac32d37e5395d62c9393 /test
parent8bc918ed97b4c79eecd56969a2898a8c75886c5a (diff)
parent6a56d10fdcf1309d2070b62dc15e80a047da971b (diff)
Merge patch series "boot: Support priority for global bootmeths"
Simon Glass <[email protected]> says: 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. Link: https://lore.kernel.org/r/[email protected]
Diffstat (limited to 'test')
-rw-r--r--test/boot/bootflow.c72
1 files changed, 67 insertions, 5 deletions
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 7cd83dc7443..cc5eed75d83 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -307,6 +307,10 @@ 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_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
@@ -315,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);
@@ -324,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 */
@@ -335,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));
@@ -345,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);
@@ -377,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);
@@ -388,6 +397,50 @@ 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_assert(iter.have_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(3, 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);
+ 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)
{
@@ -401,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();
@@ -438,7 +491,12 @@ 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));
- ut_asserteq(3, iter.num_methods);
+
+ /* at this point the global bootmeths are stranded above 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);
ut_asserteq_str("sandbox", iter.method->name);
ut_assertok(inject_response(uts));
ut_asserteq(-ENOTSUPP, bootflow_run_boot(&iter, &bflow));
@@ -447,10 +505,14 @@ 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));
+ /* 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);