From a2301201e36d665c08b51617e1c66133b32d9808 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:05 +0100 Subject: boot: Add a new test for global bootmeths 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 --- test/boot/bootflow.c | 44 ++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) (limited to 'test') 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) { -- cgit v1.2.3 From eca985905d7956ca69e1abfe9ef1d3eb5c64c0a9 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:06 +0100 Subject: boot: Update first_glob_method when dropping a bootmeth 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 --- test/boot/bootflow.c | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'test') 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); -- cgit v1.2.3 From 0fe6de0dc5b137a2def3a8cc0baa2fb73a3f8541 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:07 +0100 Subject: boot: Add a flag for whether there are global bootmeths 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 --- test/boot/bootflow.c | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'test') 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)); -- cgit v1.2.3 From bef963cb751049cacc86f2754452efadd03ae2f0 Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:08 +0100 Subject: boot: Keep track of which bootmeths have been used 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 --- test/boot/bootflow.c | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) (limited to 'test') 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); -- cgit v1.2.3 From eff1dca96330269c8281b17d00f5d2d0e62bd26e Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:12 +0100 Subject: boot: Don't change the method count after global bootmeths 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 --- test/boot/bootflow.c | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) (limited to 'test') 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)); -- cgit v1.2.3 From 6a56d10fdcf1309d2070b62dc15e80a047da971b Mon Sep 17 00:00:00 2001 From: Simon Glass Date: Wed, 15 Oct 2025 16:44:14 +0100 Subject: boot: Run the EFI bootmgr just before network devices 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 --- test/boot/bootflow.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'test') 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 "); + " 1 efi_mgr ready (none) 0 "); ut_assert_skip_to_line("No more bootdevs"); ut_assert_skip_to_line("(2 bootflows, 2 valid)"); ut_assert_console_end(); -- cgit v1.2.3