1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright 2021 Google LLC
19 * report_bootflow_err() - Report where a bootflow failed
21 * When a bootflow does not make it to the 'loaded' state, something went wrong.
22 * Print a helpful message if there is an error
24 * @bflow: Bootflow to process
25 * @err: Error code (0 if none)
27 static void report_bootflow_err(struct bootflow *bflow, int err)
32 /* Indent out to 'Method' */
35 switch (bflow->state) {
37 printf("No media/partition found");
39 case BOOTFLOWST_MEDIA:
40 printf("No partition found");
43 printf("No filesystem found");
46 printf("File not found");
49 printf("File cannot be loaded");
51 case BOOTFLOWST_READY:
54 case BOOTFLOWST_COUNT:
58 printf(", err=%dE\n", err);
62 * show_bootflow() - Show the status of a bootflow
64 * @seq: Bootflow index
65 * @bflow: Bootflow to show
66 * @errors: True to show the error received, if any
68 static void show_bootflow(int index, struct bootflow *bflow, bool errors)
70 printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index,
71 bflow->method->name, bootflow_state_get_name(bflow->state),
72 bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
73 "(none)", bflow->part, bflow->name, bflow->fname ?: "");
75 report_bootflow_err(bflow, bflow->err);
78 static void show_header(void)
80 printf("Seq Method State Uclass Part Name Filename\n");
81 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
84 static void show_footer(int count, int num_valid)
86 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
87 printf("(%d bootflow%s, %d valid)\n", count, count != 1 ? "s" : "",
92 * bootflow_handle_menu() - Handle running the menu and updating cur bootflow
94 * This shows the menu, allows the user to select something and then prints
97 * @std: bootstd information
98 * @text_mode: true to run the menu in text mode
99 * @bflowp: Returns selected bootflow, on success
100 * Return: 0 on success (a bootflow was selected), -EAGAIN if nothing was
101 * chosen, other -ve value on other error
103 __maybe_unused static int bootflow_handle_menu(struct bootstd_priv *std,
105 struct bootflow **bflowp)
107 struct bootflow *bflow;
110 ret = bootflow_menu_run(std, text_mode, &bflow);
112 if (ret == -EAGAIN) {
113 printf("Nothing chosen\n");
114 std->cur_bootflow = NULL;
116 printf("Menu failed (err=%d)\n", ret);
122 printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
123 std->cur_bootflow = bflow;
129 static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
132 struct bootstd_priv *std;
133 struct bootflow_iter iter;
134 struct udevice *dev = NULL;
135 struct bootflow bflow;
136 bool all = false, boot = false, errors = false, no_global = false;
137 bool list = false, no_hunter = false, menu = false, text_mode = false;
139 const char *label = NULL;
144 ret = bootstd_get_priv(&std);
146 return CMD_RET_FAILURE;
148 has_args = argc > 1 && *argv[1] == '-';
149 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
151 all = strchr(argv[1], 'a');
152 boot = strchr(argv[1], 'b');
153 errors = strchr(argv[1], 'e');
154 no_global = strchr(argv[1], 'G');
155 list = strchr(argv[1], 'l');
156 no_hunter = strchr(argv[1], 'H');
157 menu = strchr(argv[1], 'm');
158 text_mode = strchr(argv[1], 't');
165 dev = std->cur_bootdev;
168 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
169 return CMD_RET_USAGE;
174 std->cur_bootflow = NULL;
178 flags |= BOOTFLOWIF_SHOW;
180 flags |= BOOTFLOWIF_ALL;
182 flags |= BOOTFLOWIF_SKIP_GLOBAL;
184 flags |= BOOTFLOWIF_HUNT;
187 * If we have a device, just scan for bootflows attached to that device
190 printf("Scanning for bootflows ");
192 printf("in bootdev '%s'\n", dev->name);
194 printf("with label '%s'\n", label);
196 printf("in all bootdevs\n");
200 bootdev_clear_bootflows(dev);
202 bootstd_clear_glob();
204 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
205 i < 1000 && ret != -ENODEV;
206 i++, ret = bootflow_scan_next(&iter, &bflow)) {
210 ret = bootdev_add_bootflow(&bflow);
212 printf("Out of memory\n");
213 return CMD_RET_FAILURE;
216 show_bootflow(i, &bflow, errors);
217 if (!menu && boot && !bflow.err)
218 bootflow_run_boot(&iter, &bflow);
220 bootflow_iter_uninit(&iter);
222 show_footer(i, num_valid);
224 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
225 if (!num_valid && !list) {
226 printf("No bootflows found; try again with -l\n");
228 struct bootflow *sel_bflow;
230 ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
232 ret = console_clear();
234 log_err("Failed to clear console: %dE\n",
239 bootflow_run_boot(NULL, sel_bflow);
247 #ifdef CONFIG_CMD_BOOTFLOW_FULL
248 static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
251 struct bootstd_priv *std;
253 struct bootflow *bflow;
258 if (argc > 1 && *argv[1] == '-')
259 errors = strchr(argv[1], 'e');
261 ret = bootstd_get_priv(&std);
263 return CMD_RET_FAILURE;
264 dev = std->cur_bootdev;
266 /* If we have a device, just list bootflows attached to that device */
268 printf("Showing bootflows for bootdev '%s'\n", dev->name);
270 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
272 ret = bootdev_next_bootflow(&bflow), i++) {
273 num_valid += bflow->state == BOOTFLOWST_READY;
274 show_bootflow(i, bflow, errors);
277 printf("Showing all bootflows\n");
279 for (ret = bootflow_first_glob(&bflow), i = 0;
281 ret = bootflow_next_glob(&bflow), i++) {
282 num_valid += bflow->state == BOOTFLOWST_READY;
283 show_bootflow(i, bflow, errors);
286 show_footer(i, num_valid);
291 static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
294 struct bootstd_priv *std;
295 struct bootflow *bflow, *found;
302 ret = bootstd_get_priv(&std);
304 return CMD_RET_FAILURE;
307 std->cur_bootflow = NULL;
310 dev = std->cur_bootdev;
313 seq = simple_strtol(name, &endp, 16);
317 * If we have a bootdev device, only allow selection of bootflows
318 * attached to that device
321 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
323 ret = bootdev_next_bootflow(&bflow), i++) {
324 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
330 for (ret = bootflow_first_glob(&bflow), i = 0;
332 ret = bootflow_next_glob(&bflow), i++) {
333 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
341 printf("Cannot find bootflow '%s' ", name);
343 printf("in bootdev '%s' ", dev->name);
344 printf("(err=%d)\n", ret);
345 return CMD_RET_FAILURE;
347 std->cur_bootflow = found;
348 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
349 if (env_set("bootargs", found->cmdline)) {
350 printf("Cannot set bootargs\n");
351 return CMD_RET_FAILURE;
358 static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
361 struct bootstd_priv *std;
362 struct bootflow *bflow;
363 bool x86_setup = false;
367 if (argc > 1 && *argv[1] == '-') {
368 dump = strchr(argv[1], 'd');
369 x86_setup = strchr(argv[1], 's');
372 ret = bootstd_get_priv(&std);
374 return CMD_RET_FAILURE;
376 if (!std->cur_bootflow) {
377 printf("No bootflow selected\n");
378 return CMD_RET_FAILURE;
380 bflow = std->cur_bootflow;
382 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
383 zimage_dump(bflow->x86_setup, false);
388 printf("Name: %s\n", bflow->name);
389 printf("Device: %s\n", bflow->dev->name);
390 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
391 printf("Method: %s\n", bflow->method->name);
392 printf("State: %s\n", bootflow_state_get_name(bflow->state));
393 printf("Partition: %d\n", bflow->part);
394 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
395 printf("Filename: %s\n", bflow->fname);
396 printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf));
397 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
398 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
401 puts(bflow->cmdline);
405 if (bflow->x86_setup)
406 printf("X86 setup: %p\n", bflow->x86_setup);
407 printf("Logo: %s\n", bflow->logo ?
408 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
410 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
413 printf("FDT: %s\n", bflow->fdt_fname);
414 if (bflow->fdt_fname) {
415 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
417 printf("FDT addr: %lx\n", bflow->fdt_addr);
419 printf("Error: %d\n", bflow->err);
420 if (dump && bflow->buf) {
421 /* Set some sort of maximum on the size */
422 int size = min(bflow->size, 10 << 10);
425 printf("Contents:\n\n");
426 for (i = 0; i < size; i++) {
428 if (!(i % 128) && ctrlc()) {
429 printf("...interrupted\n");
438 static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
441 struct bootstd_priv *std;
442 struct bootflow *bflow;
445 ret = bootstd_get_priv(&std);
447 return CMD_RET_FAILURE;
450 * Require a current bootflow. Users can use 'bootflow scan -b' to
451 * automatically scan and boot, if needed.
453 if (!std->cur_bootflow) {
454 printf("No bootflow selected\n");
455 return CMD_RET_FAILURE;
457 bflow = std->cur_bootflow;
458 ret = bootflow_read_all(bflow);
460 printf("Failed: err=%dE\n", ret);
461 return CMD_RET_FAILURE;
467 static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
470 struct bootstd_priv *std;
471 struct bootflow *bflow;
474 ret = bootstd_get_priv(&std);
476 return CMD_RET_FAILURE;
479 * Require a current bootflow. Users can use 'bootflow scan -b' to
480 * automatically scan and boot, if needed.
482 if (!std->cur_bootflow) {
483 printf("No bootflow selected\n");
484 return CMD_RET_FAILURE;
486 bflow = std->cur_bootflow;
487 ret = bootflow_run_boot(NULL, bflow);
489 return CMD_RET_FAILURE;
494 static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
497 struct bootstd_priv *std;
498 struct bootflow *bflow;
499 bool text_mode = false;
502 if (!IS_ENABLED(CONFIG_EXPO)) {
503 printf("Menu not supported\n");
504 return CMD_RET_FAILURE;
507 if (argc > 1 && *argv[1] == '-')
508 text_mode = strchr(argv[1], 't');
510 ret = bootstd_get_priv(&std);
512 return CMD_RET_FAILURE;
514 ret = bootflow_handle_menu(std, text_mode, &bflow);
516 return CMD_RET_FAILURE;
521 static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
524 struct bootstd_priv *std;
525 struct bootflow *bflow;
526 const char *op, *arg, *val = NULL;
530 return CMD_RET_USAGE;
532 ret = bootstd_get_priv(&std);
534 return CMD_RET_FAILURE;
536 bflow = std->cur_bootflow;
538 printf("No bootflow selected\n");
539 return CMD_RET_FAILURE;
545 val = argv[3] ?: (const char *)BOOTFLOWCL_EMPTY;
549 case 'c': /* clear */
553 case 'd': /* delete */
554 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
557 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
559 printf("%.*s\n", ret, val);
562 ret = bootflow_cmdline_auto(bflow, arg);
567 printf("Argument too long\n");
570 printf("Argument not found\n");
573 printf("Mismatched quotes\n");
576 printf("Value must be quoted\n");
580 printf("Unknown error: %dE\n", ret);
583 return CMD_RET_FAILURE;
587 #endif /* CONFIG_CMD_BOOTFLOW_FULL */
589 U_BOOT_LONGHELP(bootflow,
590 #ifdef CONFIG_CMD_BOOTFLOW_FULL
591 "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
592 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
593 "bootflow select [<num>|<name>] - select a bootflow\n"
594 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
595 "bootflow read - read all current-bootflow files\n"
596 "bootflow boot - boot current bootflow\n"
597 "bootflow menu [-t] - show a menu of available bootflows\n"
598 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
600 "scan - boot first available bootflow\n"
604 U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
605 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
606 #ifdef CONFIG_CMD_BOOTFLOW_FULL
607 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
608 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
609 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
610 U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
611 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
612 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
613 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),