1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright 2021 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
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
);
398 printf("%lx\n", (ulong
)map_to_sysmem(bflow
->buf
));
400 printf("(not loaded)\n");
401 printf("Size: %x (%d bytes)\n", bflow
->size
, bflow
->size
);
402 printf("OS: %s\n", bflow
->os_name
? bflow
->os_name
: "(none)");
405 puts(bflow
->cmdline
);
409 if (bflow
->x86_setup
)
410 printf("X86 setup: %lx\n",
411 (ulong
)map_to_sysmem(bflow
->x86_setup
));
412 printf("Logo: %s\n", bflow
->logo
?
413 simple_xtoa((ulong
)map_to_sysmem(bflow
->logo
)) : "(none)");
415 printf("Logo size: %x (%d bytes)\n", bflow
->logo_size
,
418 printf("FDT: %s\n", bflow
->fdt_fname
);
419 if (bflow
->fdt_fname
) {
420 printf("FDT size: %x (%d bytes)\n", bflow
->fdt_size
,
422 printf("FDT addr: %lx\n", bflow
->fdt_addr
);
424 printf("Error: %d\n", bflow
->err
);
425 if (dump
&& bflow
->buf
) {
426 /* Set some sort of maximum on the size */
427 int size
= min(bflow
->size
, 10 << 10);
430 printf("Contents:\n\n");
431 for (i
= 0; i
< size
; i
++) {
433 if (!(i
% 128) && ctrlc()) {
434 printf("...interrupted\n");
443 static int do_bootflow_read(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
446 struct bootstd_priv
*std
;
447 struct bootflow
*bflow
;
450 ret
= bootstd_get_priv(&std
);
452 return CMD_RET_FAILURE
;
455 * Require a current bootflow. Users can use 'bootflow scan -b' to
456 * automatically scan and boot, if needed.
458 if (!std
->cur_bootflow
) {
459 printf("No bootflow selected\n");
460 return CMD_RET_FAILURE
;
462 bflow
= std
->cur_bootflow
;
463 ret
= bootflow_read_all(bflow
);
465 printf("Failed: err=%dE\n", ret
);
466 return CMD_RET_FAILURE
;
472 static int do_bootflow_boot(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
475 struct bootstd_priv
*std
;
476 struct bootflow
*bflow
;
479 ret
= bootstd_get_priv(&std
);
481 return CMD_RET_FAILURE
;
484 * Require a current bootflow. Users can use 'bootflow scan -b' to
485 * automatically scan and boot, if needed.
487 if (!std
->cur_bootflow
) {
488 printf("No bootflow selected\n");
489 return CMD_RET_FAILURE
;
491 bflow
= std
->cur_bootflow
;
492 ret
= bootflow_run_boot(NULL
, bflow
);
494 return CMD_RET_FAILURE
;
499 static int do_bootflow_menu(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
502 struct bootstd_priv
*std
;
503 struct bootflow
*bflow
;
504 bool text_mode
= false;
507 if (!IS_ENABLED(CONFIG_EXPO
)) {
508 printf("Menu not supported\n");
509 return CMD_RET_FAILURE
;
512 if (argc
> 1 && *argv
[1] == '-')
513 text_mode
= strchr(argv
[1], 't');
515 ret
= bootstd_get_priv(&std
);
517 return CMD_RET_FAILURE
;
519 ret
= bootflow_handle_menu(std
, text_mode
, &bflow
);
521 return CMD_RET_FAILURE
;
526 static int do_bootflow_cmdline(struct cmd_tbl
*cmdtp
, int flag
, int argc
,
529 struct bootstd_priv
*std
;
530 struct bootflow
*bflow
;
531 const char *op
, *arg
, *val
= NULL
;
535 return CMD_RET_USAGE
;
537 ret
= bootstd_get_priv(&std
);
539 return CMD_RET_FAILURE
;
541 bflow
= std
->cur_bootflow
;
543 printf("No bootflow selected\n");
544 return CMD_RET_FAILURE
;
550 val
= argv
[3] ?: (const char *)BOOTFLOWCL_EMPTY
;
554 case 'c': /* clear */
558 case 'd': /* delete */
559 ret
= bootflow_cmdline_set_arg(bflow
, arg
, val
, true);
562 ret
= bootflow_cmdline_get_arg(bflow
, arg
, &val
);
564 printf("%.*s\n", ret
, val
);
567 ret
= bootflow_cmdline_auto(bflow
, arg
);
572 printf("Argument too long\n");
575 printf("Argument not found\n");
578 printf("Mismatched quotes\n");
581 printf("Value must be quoted\n");
585 printf("Unknown error: %dE\n", ret
);
588 return CMD_RET_FAILURE
;
592 #endif /* CONFIG_CMD_BOOTFLOW_FULL */
594 U_BOOT_LONGHELP(bootflow
,
595 #ifdef CONFIG_CMD_BOOTFLOW_FULL
596 "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
597 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
598 "bootflow select [<num>|<name>] - select a bootflow\n"
599 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
600 "bootflow read - read all current-bootflow files\n"
601 "bootflow boot - boot current bootflow\n"
602 "bootflow menu [-t] - show a menu of available bootflows\n"
603 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
605 "scan - boot first available bootflow\n"
609 U_BOOT_CMD_WITH_SUBCMDS(bootflow
, "Boot flows", bootflow_help_text
,
610 U_BOOT_SUBCMD_MKENT(scan
, 3, 1, do_bootflow_scan
),
611 #ifdef CONFIG_CMD_BOOTFLOW_FULL
612 U_BOOT_SUBCMD_MKENT(list
, 2, 1, do_bootflow_list
),
613 U_BOOT_SUBCMD_MKENT(select
, 2, 1, do_bootflow_select
),
614 U_BOOT_SUBCMD_MKENT(info
, 2, 1, do_bootflow_info
),
615 U_BOOT_SUBCMD_MKENT(read
, 1, 1, do_bootflow_read
),
616 U_BOOT_SUBCMD_MKENT(boot
, 1, 1, do_bootflow_boot
),
617 U_BOOT_SUBCMD_MKENT(menu
, 2, 1, do_bootflow_menu
),
618 U_BOOT_SUBCMD_MKENT(cmdline
, 4, 1, do_bootflow_cmdline
),