[PATCH 15/34] bootstd: Add a menu option to bootflow scan
Simon Glass
sjg at chromium.org
Mon Oct 2 03:15:25 CEST 2023
Allow showing a menu and automatically booting, with 'bootflow scan'.
This is more convenient than using a script.
Signed-off-by: Simon Glass <sjg at chromium.org>
---
cmd/bootflow.c | 27 +++++++++++--
doc/usage/cmd/bootflow.rst | 5 +++
test/boot/bootflow.c | 82 ++++++++++++++++++++++++++++++++++++++
3 files changed, 110 insertions(+), 4 deletions(-)
diff --git a/cmd/bootflow.c b/cmd/bootflow.c
index 1516f8a4193b..e4ed4ab83d9d 100644
--- a/cmd/bootflow.c
+++ b/cmd/bootflow.c
@@ -135,7 +135,7 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
struct udevice *dev = NULL;
struct bootflow bflow;
bool all = false, boot = false, errors = false, no_global = false;
- bool list = false, no_hunter = false;
+ bool list = false, no_hunter = false, menu = false, text_mode = false;
int num_valid = 0;
const char *label = NULL;
bool has_args;
@@ -155,6 +155,8 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
no_global = strchr(argv[1], 'G');
list = strchr(argv[1], 'l');
no_hunter = strchr(argv[1], 'H');
+ menu = strchr(argv[1], 'm');
+ text_mode = strchr(argv[1], 't');
argc--;
argv++;
}
@@ -213,15 +215,32 @@ static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
}
if (list)
show_bootflow(i, &bflow, errors);
- if (boot && !bflow.err)
+ if (!menu && boot && !bflow.err)
bootflow_run_boot(&iter, &bflow);
}
bootflow_iter_uninit(&iter);
if (list)
show_footer(i, num_valid);
- if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && !num_valid && !list)
- printf("No bootflows found; try again with -l\n");
+ if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
+ if (!num_valid && !list) {
+ printf("No bootflows found; try again with -l\n");
+ } else if (menu) {
+ struct bootflow *sel_bflow;
+
+ ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
+ if (!ret && boot) {
+ ret = console_clear();
+ if (ret) {
+ log_err("Failed to clear console: %dE\n",
+ ret);
+ return ret;
+ }
+
+ bootflow_run_boot(NULL, sel_bflow);
+ }
+ }
+ }
return 0;
}
diff --git a/doc/usage/cmd/bootflow.rst b/doc/usage/cmd/bootflow.rst
index 6a0645c28d07..795d5990bdc3 100644
--- a/doc/usage/cmd/bootflow.rst
+++ b/doc/usage/cmd/bootflow.rst
@@ -52,6 +52,8 @@ Flags are:
matters, since by then the system boots in the OS and U-Boot is no-longer
running. `bootflow scan -b` is a quick way to boot the first available OS.
A valid bootflow is one that made it all the way to the `loaded` state.
+ Note that if `-m` is provided as well, booting is delayed until the user
+ selects a bootflow.
-e
Used with -l to also show errors for each bootflow. The shows detailed error
@@ -71,6 +73,9 @@ Flags are:
priority or label is tried, to see if more bootdevs can be discovered, but
this flag disables that process.
+-m
+ Show a menu of available bootflows for the user to select. When used with
+ -b it then boots the one that was selected, if any.
The optional argument specifies a particular bootdev to scan. This can either be
the name of a bootdev or its sequence number (both shown with `bootdev list`).
diff --git a/test/boot/bootflow.c b/test/boot/bootflow.c
index 04a5bd5d7a80..a57f5017364a 100644
--- a/test/boot/bootflow.c
+++ b/test/boot/bootflow.c
@@ -637,6 +637,88 @@ static int bootflow_cmd_menu(struct unit_test_state *uts)
}
BOOTSTD_TEST(bootflow_cmd_menu, UT_TESTF_DM | UT_TESTF_SCAN_FDT);
+/* Check 'bootflow scan -m' to select a bootflow using a menu */
+static int bootflow_scan_menu(struct unit_test_state *uts)
+{
+ struct bootstd_priv *std;
+ const char **old_order, **new_order;
+ char prev[3];
+
+ /* get access to the current bootflow */
+ ut_assertok(bootstd_get_priv(&std));
+
+ ut_assertok(prep_mmc_bootdev(uts, "mmc4", false, &old_order));
+
+ /* Add keypresses to move to and select the second one in the list */
+ prev[0] = CTL_CH('n');
+ prev[1] = '\r';
+ prev[2] = '\0';
+ ut_asserteq(2, console_in_puts(prev));
+
+ ut_assertok(run_command("bootflow scan -lm", 0));
+ new_order = std->bootdev_order;
+ std->bootdev_order = old_order;
+
+ ut_assert_skip_to_line("No more bootdevs");
+ ut_assert_nextlinen("--");
+ ut_assert_nextline("(2 bootflows, 2 valid)");
+
+ ut_assert_nextline("Selected: Armbian");
+ ut_assertnonnull(std->cur_bootflow);
+ ut_assert_console_end();
+
+ /* Check not selecting anything */
+ prev[0] = '\e';
+ prev[1] = '\0';
+ ut_asserteq(1, console_in_puts(prev));
+
+ std->bootdev_order = new_order; /* Blue Monday */
+ ut_assertok(run_command("bootflow scan -lm", 0));
+ std->bootdev_order = old_order;
+
+ ut_assertnull(std->cur_bootflow);
+ ut_assert_skip_to_line("(2 bootflows, 2 valid)");
+ ut_assert_nextline("Nothing chosen");
+ ut_assert_console_end();
+
+ return 0;
+}
+BOOTSTD_TEST(bootflow_scan_menu,
+ UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC);
+
+/* Check 'bootflow scan -mb' to select and boot a bootflow using a menu */
+static int bootflow_scan_menu_boot(struct unit_test_state *uts)
+{
+ struct bootstd_priv *std;
+ const char **old_order;
+ char prev[3];
+
+ /* get access to the current bootflow */
+ ut_assertok(bootstd_get_priv(&std));
+
+ ut_assertok(prep_mmc_bootdev(uts, "mmc4", false, &old_order));
+
+ /* Add keypresses to move to and select the second one in the list */
+ prev[0] = CTL_CH('n');
+ prev[1] = '\r';
+ prev[2] = '\0';
+ ut_asserteq(2, console_in_puts(prev));
+
+ ut_assertok(run_command("bootflow scan -lmb", 0));
+ std->bootdev_order = old_order;
+
+ ut_assert_skip_to_line("(2 bootflows, 2 valid)");
+
+ ut_assert_nextline("Selected: Armbian");
+ ut_assert_skip_to_line("Boot failed (err=-14)");
+ ut_assertnonnull(std->cur_bootflow);
+ ut_assert_console_end();
+
+ return 0;
+}
+BOOTSTD_TEST(bootflow_scan_menu_boot,
+ UT_TESTF_DM | UT_TESTF_SCAN_FDT | UT_TESTF_CONSOLE_REC);
+
/* Check searching for a single bootdev using the hunters */
static int bootflow_cmd_hunt_single(struct unit_test_state *uts)
{
--
2.42.0.582.g8ccd20d70d-goog
More information about the U-Boot
mailing list