blob: 55643a6876f0c7a273fc4e57f3cec577bad2ae74 [file] [log] [blame]
Simon Glass7617f492022-04-24 23:31:11 -06001// SPDX-License-Identifier: GPL-2.0+
2/*
3 * 'bootflow' command
4 *
5 * Copyright 2021 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
7 */
8
Simon Glass7617f492022-04-24 23:31:11 -06009#include <bootdev.h>
10#include <bootflow.h>
Simon Glass5495aaf2023-07-30 11:17:00 -060011#include <bootm.h>
Simon Glass7617f492022-04-24 23:31:11 -060012#include <bootstd.h>
13#include <command.h>
14#include <console.h>
15#include <dm.h>
Tom Rini22856382025-05-14 16:46:03 -060016#include <env.h>
Simon Glassd7cef832025-05-02 08:46:27 -060017#include <expo.h>
18#include <log.h>
Simon Glass7617f492022-04-24 23:31:11 -060019#include <mapmem.h>
20
21/**
22 * report_bootflow_err() - Report where a bootflow failed
23 *
24 * When a bootflow does not make it to the 'loaded' state, something went wrong.
25 * Print a helpful message if there is an error
26 *
27 * @bflow: Bootflow to process
28 * @err: Error code (0 if none)
29 */
30static void report_bootflow_err(struct bootflow *bflow, int err)
31{
32 if (!err)
33 return;
34
35 /* Indent out to 'Method' */
36 printf(" ** ");
37
38 switch (bflow->state) {
39 case BOOTFLOWST_BASE:
40 printf("No media/partition found");
41 break;
42 case BOOTFLOWST_MEDIA:
43 printf("No partition found");
44 break;
45 case BOOTFLOWST_PART:
46 printf("No filesystem found");
47 break;
48 case BOOTFLOWST_FS:
49 printf("File not found");
50 break;
51 case BOOTFLOWST_FILE:
52 printf("File cannot be loaded");
53 break;
54 case BOOTFLOWST_READY:
55 printf("Ready");
56 break;
57 case BOOTFLOWST_COUNT:
58 break;
59 }
60
Simon Glass9482fdf2023-05-10 16:34:26 -060061 printf(", err=%dE\n", err);
Simon Glass7617f492022-04-24 23:31:11 -060062}
63
64/**
65 * show_bootflow() - Show the status of a bootflow
66 *
67 * @seq: Bootflow index
68 * @bflow: Bootflow to show
69 * @errors: True to show the error received, if any
70 */
71static void show_bootflow(int index, struct bootflow *bflow, bool errors)
72{
73 printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index,
74 bflow->method->name, bootflow_state_get_name(bflow->state),
Simon Glassdee4d642022-07-30 15:52:23 -060075 bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
Simon Glassd465ad52023-08-24 13:55:39 -060076 "(none)", bflow->part, bflow->name, bflow->fname ?: "");
Simon Glass7617f492022-04-24 23:31:11 -060077 if (errors)
78 report_bootflow_err(bflow, bflow->err);
79}
80
81static void show_header(void)
82{
83 printf("Seq Method State Uclass Part Name Filename\n");
84 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
85}
86
87static void show_footer(int count, int num_valid)
88{
89 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
90 printf("(%d bootflow%s, %d valid)\n", count, count != 1 ? "s" : "",
91 num_valid);
92}
93
Simon Glass6d5083b2023-10-01 19:14:38 -060094/**
95 * bootflow_handle_menu() - Handle running the menu and updating cur bootflow
96 *
97 * This shows the menu, allows the user to select something and then prints
98 * what happened
99 *
100 * @std: bootstd information
101 * @text_mode: true to run the menu in text mode
102 * @bflowp: Returns selected bootflow, on success
103 * Return: 0 on success (a bootflow was selected), -EAGAIN if nothing was
104 * chosen, other -ve value on other error
105 */
106__maybe_unused static int bootflow_handle_menu(struct bootstd_priv *std,
107 bool text_mode,
108 struct bootflow **bflowp)
109{
Simon Glassd7cef832025-05-02 08:46:27 -0600110 struct expo *exp;
Simon Glass6d5083b2023-10-01 19:14:38 -0600111 struct bootflow *bflow;
112 int ret;
113
Simon Glassd7cef832025-05-02 08:46:27 -0600114 ret = bootflow_menu_start(std, text_mode, &exp);
115 if (ret)
116 return log_msg_ret("bhs", ret);
Simon Glass6d5083b2023-10-01 19:14:38 -0600117
Simon Glassd7cef832025-05-02 08:46:27 -0600118 do {
Simon Glass02708f52025-05-02 08:46:52 -0600119 ret = expo_render(exp);
120 if (ret)
121 return log_msg_ret("bhr", ret);
Simon Glassd7cef832025-05-02 08:46:27 -0600122 ret = bootflow_menu_poll(exp, &bflow);
123 } while (ret == -EAGAIN);
Simon Glass6d5083b2023-10-01 19:14:38 -0600124
Simon Glassd7cef832025-05-02 08:46:27 -0600125 if (ret == -EPIPE) {
126 printf("Nothing chosen\n");
127 std->cur_bootflow = NULL;
128 } else if (ret) {
129 printf("Menu failed (err=%d)\n", ret);
130 } else {
131 printf("Selected: %s\n", bflow->os_name ? bflow->os_name :
132 bflow->name);
133 std->cur_bootflow = bflow;
134 *bflowp = bflow;
135 }
136 expo_destroy(exp);
137 if (ret)
138 return ret;
Simon Glass6d5083b2023-10-01 19:14:38 -0600139
140 return 0;
141}
142
Simon Glass7617f492022-04-24 23:31:11 -0600143static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
144 char *const argv[])
145{
146 struct bootstd_priv *std;
147 struct bootflow_iter iter;
Simon Glassba3d5372023-01-17 10:48:15 -0700148 struct udevice *dev = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600149 struct bootflow bflow;
Simon Glass73fcf512022-07-30 15:52:25 -0600150 bool all = false, boot = false, errors = false, no_global = false;
Simon Glass9bf27862023-10-01 19:15:25 -0600151 bool list = false, no_hunter = false, menu = false, text_mode = false;
Simon Glass7617f492022-04-24 23:31:11 -0600152 int num_valid = 0;
Simon Glassba3d5372023-01-17 10:48:15 -0700153 const char *label = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600154 bool has_args;
155 int ret, i;
156 int flags;
157
158 ret = bootstd_get_priv(&std);
159 if (ret)
160 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600161
162 has_args = argc > 1 && *argv[1] == '-';
163 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
164 if (has_args) {
165 all = strchr(argv[1], 'a');
166 boot = strchr(argv[1], 'b');
167 errors = strchr(argv[1], 'e');
Simon Glass73fcf512022-07-30 15:52:25 -0600168 no_global = strchr(argv[1], 'G');
Simon Glass7617f492022-04-24 23:31:11 -0600169 list = strchr(argv[1], 'l');
Simon Glassa21e7752023-01-17 10:48:06 -0700170 no_hunter = strchr(argv[1], 'H');
Simon Glass9bf27862023-10-01 19:15:25 -0600171 menu = strchr(argv[1], 'm');
172 text_mode = strchr(argv[1], 't');
Simon Glass7617f492022-04-24 23:31:11 -0600173 argc--;
174 argv++;
175 }
Simon Glassba3d5372023-01-17 10:48:15 -0700176 if (argc > 1)
177 label = argv[1];
178 if (!label)
179 dev = std->cur_bootdev;
Simon Glass7617f492022-04-24 23:31:11 -0600180 } else {
181 if (has_args) {
Simon Glass2d5a8e12023-05-06 08:27:09 -0600182 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
Simon Glass7617f492022-04-24 23:31:11 -0600183 return CMD_RET_USAGE;
184 }
185 boot = true;
186 }
187
188 std->cur_bootflow = NULL;
189
Simon Glass3c63a872025-03-15 14:25:58 +0000190 flags = BOOTFLOWIF_ONLY_BOOTABLE;
Simon Glass7617f492022-04-24 23:31:11 -0600191 if (list)
Simon Glass99e68182023-02-22 12:17:03 -0700192 flags |= BOOTFLOWIF_SHOW;
Simon Glass7617f492022-04-24 23:31:11 -0600193 if (all)
Simon Glass99e68182023-02-22 12:17:03 -0700194 flags |= BOOTFLOWIF_ALL;
Simon Glass73fcf512022-07-30 15:52:25 -0600195 if (no_global)
Simon Glass99e68182023-02-22 12:17:03 -0700196 flags |= BOOTFLOWIF_SKIP_GLOBAL;
Simon Glassa21e7752023-01-17 10:48:06 -0700197 if (!no_hunter)
Simon Glass99e68182023-02-22 12:17:03 -0700198 flags |= BOOTFLOWIF_HUNT;
Simon Glass7617f492022-04-24 23:31:11 -0600199
200 /*
201 * If we have a device, just scan for bootflows attached to that device
202 */
Simon Glassba3d5372023-01-17 10:48:15 -0700203 if (list) {
204 printf("Scanning for bootflows ");
205 if (dev)
206 printf("in bootdev '%s'\n", dev->name);
207 else if (label)
208 printf("with label '%s'\n", label);
209 else
210 printf("in all bootdevs\n");
211 show_header();
212 }
213 if (dev)
Simon Glass346ab5d2024-11-15 16:19:09 -0700214 bootstd_clear_bootflows_for_bootdev(dev);
Simon Glassba3d5372023-01-17 10:48:15 -0700215 else
Simon Glass7617f492022-04-24 23:31:11 -0600216 bootstd_clear_glob();
Simon Glassba3d5372023-01-17 10:48:15 -0700217 for (i = 0,
Simon Glass5d3d44f2023-01-17 10:48:16 -0700218 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
Simon Glassba3d5372023-01-17 10:48:15 -0700219 i < 1000 && ret != -ENODEV;
220 i++, ret = bootflow_scan_next(&iter, &bflow)) {
221 bflow.err = ret;
222 if (!ret)
223 num_valid++;
Simon Glassc01d83f2024-11-15 16:19:08 -0700224 ret = bootstd_add_bootflow(&bflow);
Simon Glass199f5882024-11-15 16:19:12 -0700225 if (ret < 0) {
Simon Glassba3d5372023-01-17 10:48:15 -0700226 printf("Out of memory\n");
227 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600228 }
Simon Glassba3d5372023-01-17 10:48:15 -0700229 if (list)
230 show_bootflow(i, &bflow, errors);
Simon Glass9bf27862023-10-01 19:15:25 -0600231 if (!menu && boot && !bflow.err)
Simon Glassba3d5372023-01-17 10:48:15 -0700232 bootflow_run_boot(&iter, &bflow);
Simon Glass7617f492022-04-24 23:31:11 -0600233 }
234 bootflow_iter_uninit(&iter);
235 if (list)
236 show_footer(i, num_valid);
237
Simon Glass9bf27862023-10-01 19:15:25 -0600238 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
239 if (!num_valid && !list) {
240 printf("No bootflows found; try again with -l\n");
241 } else if (menu) {
242 struct bootflow *sel_bflow;
243
244 ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
245 if (!ret && boot) {
246 ret = console_clear();
247 if (ret) {
248 log_err("Failed to clear console: %dE\n",
249 ret);
250 return ret;
251 }
252
253 bootflow_run_boot(NULL, sel_bflow);
254 }
255 }
256 }
Simon Glass8f97c672023-04-24 13:49:48 +1200257
Simon Glass7617f492022-04-24 23:31:11 -0600258 return 0;
259}
260
261#ifdef CONFIG_CMD_BOOTFLOW_FULL
262static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
263 char *const argv[])
264{
265 struct bootstd_priv *std;
266 struct udevice *dev;
267 struct bootflow *bflow;
268 int num_valid = 0;
269 bool errors = false;
270 int ret, i;
271
272 if (argc > 1 && *argv[1] == '-')
273 errors = strchr(argv[1], 'e');
274
275 ret = bootstd_get_priv(&std);
276 if (ret)
277 return CMD_RET_FAILURE;
278 dev = std->cur_bootdev;
279
280 /* If we have a device, just list bootflows attached to that device */
281 if (dev) {
282 printf("Showing bootflows for bootdev '%s'\n", dev->name);
283 show_header();
284 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
285 !ret;
286 ret = bootdev_next_bootflow(&bflow), i++) {
287 num_valid += bflow->state == BOOTFLOWST_READY;
288 show_bootflow(i, bflow, errors);
289 }
290 } else {
291 printf("Showing all bootflows\n");
292 show_header();
293 for (ret = bootflow_first_glob(&bflow), i = 0;
294 !ret;
295 ret = bootflow_next_glob(&bflow), i++) {
296 num_valid += bflow->state == BOOTFLOWST_READY;
297 show_bootflow(i, bflow, errors);
298 }
299 }
300 show_footer(i, num_valid);
301
302 return 0;
303}
304
305static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
306 char *const argv[])
307{
308 struct bootstd_priv *std;
309 struct bootflow *bflow, *found;
310 struct udevice *dev;
311 const char *name;
312 char *endp;
313 int seq, i;
314 int ret;
315
316 ret = bootstd_get_priv(&std);
317 if (ret)
318 return CMD_RET_FAILURE;
319;
320 if (argc < 2) {
321 std->cur_bootflow = NULL;
322 return 0;
323 }
324 dev = std->cur_bootdev;
325
326 name = argv[1];
327 seq = simple_strtol(name, &endp, 16);
328 found = NULL;
329
330 /*
331 * If we have a bootdev device, only allow selection of bootflows
332 * attached to that device
333 */
334 if (dev) {
335 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
336 !ret;
337 ret = bootdev_next_bootflow(&bflow), i++) {
338 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
339 found = bflow;
340 break;
341 }
342 }
343 } else {
344 for (ret = bootflow_first_glob(&bflow), i = 0;
345 !ret;
346 ret = bootflow_next_glob(&bflow), i++) {
347 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
348 found = bflow;
349 break;
350 }
351 }
352 }
353
354 if (!found) {
355 printf("Cannot find bootflow '%s' ", name);
356 if (dev)
357 printf("in bootdev '%s' ", dev->name);
358 printf("(err=%d)\n", ret);
359 return CMD_RET_FAILURE;
360 }
361 std->cur_bootflow = found;
Simon Glassb35513a2023-07-12 09:04:35 -0600362 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
363 if (env_set("bootargs", found->cmdline)) {
364 printf("Cannot set bootargs\n");
365 return CMD_RET_FAILURE;
366 }
367 }
Simon Glass7617f492022-04-24 23:31:11 -0600368
369 return 0;
370}
371
372static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
373 char *const argv[])
374{
375 struct bootstd_priv *std;
376 struct bootflow *bflow;
Simon Glass5495aaf2023-07-30 11:17:00 -0600377 bool x86_setup = false;
Simon Glass7617f492022-04-24 23:31:11 -0600378 bool dump = false;
379 int ret;
380
Simon Glass5495aaf2023-07-30 11:17:00 -0600381 if (argc > 1 && *argv[1] == '-') {
Simon Glass7617f492022-04-24 23:31:11 -0600382 dump = strchr(argv[1], 'd');
Simon Glass5495aaf2023-07-30 11:17:00 -0600383 x86_setup = strchr(argv[1], 's');
384 }
Simon Glass7617f492022-04-24 23:31:11 -0600385
386 ret = bootstd_get_priv(&std);
387 if (ret)
388 return CMD_RET_FAILURE;
389
390 if (!std->cur_bootflow) {
391 printf("No bootflow selected\n");
392 return CMD_RET_FAILURE;
393 }
394 bflow = std->cur_bootflow;
395
Simon Glass5495aaf2023-07-30 11:17:00 -0600396 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
Tom Rini6388b6b2025-04-07 12:35:13 -0600397 zimage_dump(bflow->x86_setup, false);
Simon Glass5495aaf2023-07-30 11:17:00 -0600398
399 return 0;
400 }
401
Simon Glass7617f492022-04-24 23:31:11 -0600402 printf("Name: %s\n", bflow->name);
403 printf("Device: %s\n", bflow->dev->name);
404 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
405 printf("Method: %s\n", bflow->method->name);
406 printf("State: %s\n", bootflow_state_get_name(bflow->state));
407 printf("Partition: %d\n", bflow->part);
408 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
409 printf("Filename: %s\n", bflow->fname);
Simon Glasscdf83fd22024-10-19 09:22:09 -0600410 printf("Buffer: ");
411 if (bflow->buf)
412 printf("%lx\n", (ulong)map_to_sysmem(bflow->buf));
413 else
414 printf("(not loaded)\n");
Simon Glass7617f492022-04-24 23:31:11 -0600415 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
Simon Glass72b7b192023-01-06 08:52:33 -0600416 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
Simon Glass33927522023-07-12 09:04:34 -0600417 printf("Cmdline: ");
418 if (bflow->cmdline)
419 puts(bflow->cmdline);
420 else
421 puts("(none)");
422 putc('\n');
Simon Glass63398b02023-07-12 09:04:36 -0600423 if (bflow->x86_setup)
Simon Glass2f0128f2024-10-19 09:21:59 -0600424 printf("X86 setup: %lx\n",
425 (ulong)map_to_sysmem(bflow->x86_setup));
Simon Glass612b9cc2023-01-06 08:52:34 -0600426 printf("Logo: %s\n", bflow->logo ?
427 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
428 if (bflow->logo) {
429 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
430 bflow->logo_size);
431 }
Simon Glass7b8c6342023-01-17 10:47:56 -0700432 printf("FDT: %s\n", bflow->fdt_fname);
433 if (bflow->fdt_fname) {
434 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
435 bflow->fdt_size);
436 printf("FDT addr: %lx\n", bflow->fdt_addr);
437 }
Simon Glass7617f492022-04-24 23:31:11 -0600438 printf("Error: %d\n", bflow->err);
439 if (dump && bflow->buf) {
440 /* Set some sort of maximum on the size */
441 int size = min(bflow->size, 10 << 10);
442 int i;
443
444 printf("Contents:\n\n");
445 for (i = 0; i < size; i++) {
446 putc(bflow->buf[i]);
447 if (!(i % 128) && ctrlc()) {
448 printf("...interrupted\n");
449 break;
450 }
451 }
452 }
453
454 return 0;
455}
456
Simon Glass6d8f95b2023-08-10 19:33:18 -0600457static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
458 char *const argv[])
459{
460 struct bootstd_priv *std;
461 struct bootflow *bflow;
462 int ret;
463
464 ret = bootstd_get_priv(&std);
465 if (ret)
466 return CMD_RET_FAILURE;
467
468 /*
469 * Require a current bootflow. Users can use 'bootflow scan -b' to
470 * automatically scan and boot, if needed.
471 */
472 if (!std->cur_bootflow) {
473 printf("No bootflow selected\n");
474 return CMD_RET_FAILURE;
475 }
476 bflow = std->cur_bootflow;
477 ret = bootflow_read_all(bflow);
478 if (ret) {
479 printf("Failed: err=%dE\n", ret);
480 return CMD_RET_FAILURE;
481 }
482
483 return 0;
484}
485
Simon Glass7617f492022-04-24 23:31:11 -0600486static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
487 char *const argv[])
488{
489 struct bootstd_priv *std;
490 struct bootflow *bflow;
491 int ret;
492
493 ret = bootstd_get_priv(&std);
494 if (ret)
495 return CMD_RET_FAILURE;
496
497 /*
498 * Require a current bootflow. Users can use 'bootflow scan -b' to
499 * automatically scan and boot, if needed.
500 */
501 if (!std->cur_bootflow) {
502 printf("No bootflow selected\n");
503 return CMD_RET_FAILURE;
504 }
505 bflow = std->cur_bootflow;
506 ret = bootflow_run_boot(NULL, bflow);
507 if (ret)
508 return CMD_RET_FAILURE;
509
510 return 0;
511}
Simon Glass0a2f6a32023-01-06 08:52:40 -0600512
513static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
514 char *const argv[])
515{
516 struct bootstd_priv *std;
517 struct bootflow *bflow;
518 bool text_mode = false;
519 int ret;
520
Tom Rinif2d51362023-04-06 10:03:33 -0400521 if (!IS_ENABLED(CONFIG_EXPO)) {
522 printf("Menu not supported\n");
523 return CMD_RET_FAILURE;
524 }
525
Simon Glass0a2f6a32023-01-06 08:52:40 -0600526 if (argc > 1 && *argv[1] == '-')
527 text_mode = strchr(argv[1], 't');
528
529 ret = bootstd_get_priv(&std);
530 if (ret)
531 return CMD_RET_FAILURE;
532
Simon Glass6d5083b2023-10-01 19:14:38 -0600533 ret = bootflow_handle_menu(std, text_mode, &bflow);
534 if (ret)
535 return CMD_RET_FAILURE;
Simon Glass0a2f6a32023-01-06 08:52:40 -0600536
537 return 0;
538}
Simon Glass55a2da32023-07-12 09:04:39 -0600539
540static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
541 char *const argv[])
542{
543 struct bootstd_priv *std;
544 struct bootflow *bflow;
545 const char *op, *arg, *val = NULL;
546 int ret;
547
548 if (argc < 3)
549 return CMD_RET_USAGE;
550
551 ret = bootstd_get_priv(&std);
552 if (ret)
553 return CMD_RET_FAILURE;
554
555 bflow = std->cur_bootflow;
556 if (!bflow) {
557 printf("No bootflow selected\n");
558 return CMD_RET_FAILURE;
559 }
560
561 op = argv[1];
562 arg = argv[2];
563 if (*op == 's') {
Simon Glass7a164f82023-11-29 10:31:19 -0700564 val = argv[3] ?: (const char *)BOOTFLOWCL_EMPTY;
Simon Glass55a2da32023-07-12 09:04:39 -0600565 }
566
567 switch (*op) {
568 case 'c': /* clear */
569 val = "";
570 fallthrough;
571 case 's': /* set */
572 case 'd': /* delete */
573 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
574 break;
575 case 'g': /* get */
576 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
577 if (ret >= 0)
578 printf("%.*s\n", ret, val);
579 break;
Simon Glasscd91e992023-07-12 09:04:42 -0600580 case 'a': /* auto */
581 ret = bootflow_cmdline_auto(bflow, arg);
582 break;
Simon Glass55a2da32023-07-12 09:04:39 -0600583 }
584 switch (ret) {
585 case -E2BIG:
586 printf("Argument too long\n");
587 break;
588 case -ENOENT:
589 printf("Argument not found\n");
590 break;
591 case -EINVAL:
592 printf("Mismatched quotes\n");
593 break;
594 case -EBADF:
595 printf("Value must be quoted\n");
596 break;
597 default:
598 if (ret < 0)
599 printf("Unknown error: %dE\n", ret);
600 }
601 if (ret < 0)
602 return CMD_RET_FAILURE;
603
604 return 0;
605}
Simon Glass7617f492022-04-24 23:31:11 -0600606#endif /* CONFIG_CMD_BOOTFLOW_FULL */
607
Tom Rini03f146c2023-10-07 15:13:08 -0400608U_BOOT_LONGHELP(bootflow,
Simon Glass7617f492022-04-24 23:31:11 -0600609#ifdef CONFIG_CMD_BOOTFLOW_FULL
Simon Glass73fcf512022-07-30 15:52:25 -0600610 "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
Simon Glass7617f492022-04-24 23:31:11 -0600611 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
612 "bootflow select [<num>|<name>] - select a bootflow\n"
Simon Glass5495aaf2023-07-30 11:17:00 -0600613 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
Simon Glass6d8f95b2023-08-10 19:33:18 -0600614 "bootflow read - read all current-bootflow files\n"
615 "bootflow boot - boot current bootflow\n"
Simon Glass55a2da32023-07-12 09:04:39 -0600616 "bootflow menu [-t] - show a menu of available bootflows\n"
Tom Rini03f146c2023-10-07 15:13:08 -0400617 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
Simon Glass7617f492022-04-24 23:31:11 -0600618#else
Tom Rini03f146c2023-10-07 15:13:08 -0400619 "scan - boot first available bootflow\n"
Simon Glass7617f492022-04-24 23:31:11 -0600620#endif
Tom Rini03f146c2023-10-07 15:13:08 -0400621 );
Simon Glass7617f492022-04-24 23:31:11 -0600622
623U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
624 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
625#ifdef CONFIG_CMD_BOOTFLOW_FULL
626 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
627 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
628 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
Simon Glass6d8f95b2023-08-10 19:33:18 -0600629 U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
Simon Glass0a2f6a32023-01-06 08:52:40 -0600630 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
631 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
Simon Glass55a2da32023-07-12 09:04:39 -0600632 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
Simon Glass7617f492022-04-24 23:31:11 -0600633#endif
634);