blob: efac27a5d77366aa61a19466b089ee2cf3a255a6 [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 {
119 ret = bootflow_menu_poll(exp, &bflow);
120 } while (ret == -EAGAIN);
Simon Glass6d5083b2023-10-01 19:14:38 -0600121
Simon Glassd7cef832025-05-02 08:46:27 -0600122 if (ret == -EPIPE) {
123 printf("Nothing chosen\n");
124 std->cur_bootflow = NULL;
125 } else if (ret) {
126 printf("Menu failed (err=%d)\n", ret);
127 } else {
128 printf("Selected: %s\n", bflow->os_name ? bflow->os_name :
129 bflow->name);
130 std->cur_bootflow = bflow;
131 *bflowp = bflow;
132 }
133 expo_destroy(exp);
134 if (ret)
135 return ret;
Simon Glass6d5083b2023-10-01 19:14:38 -0600136
137 return 0;
138}
139
Simon Glass7617f492022-04-24 23:31:11 -0600140static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
141 char *const argv[])
142{
143 struct bootstd_priv *std;
144 struct bootflow_iter iter;
Simon Glassba3d5372023-01-17 10:48:15 -0700145 struct udevice *dev = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600146 struct bootflow bflow;
Simon Glass73fcf512022-07-30 15:52:25 -0600147 bool all = false, boot = false, errors = false, no_global = false;
Simon Glass9bf27862023-10-01 19:15:25 -0600148 bool list = false, no_hunter = false, menu = false, text_mode = false;
Simon Glass7617f492022-04-24 23:31:11 -0600149 int num_valid = 0;
Simon Glassba3d5372023-01-17 10:48:15 -0700150 const char *label = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600151 bool has_args;
152 int ret, i;
153 int flags;
154
155 ret = bootstd_get_priv(&std);
156 if (ret)
157 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600158
159 has_args = argc > 1 && *argv[1] == '-';
160 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
161 if (has_args) {
162 all = strchr(argv[1], 'a');
163 boot = strchr(argv[1], 'b');
164 errors = strchr(argv[1], 'e');
Simon Glass73fcf512022-07-30 15:52:25 -0600165 no_global = strchr(argv[1], 'G');
Simon Glass7617f492022-04-24 23:31:11 -0600166 list = strchr(argv[1], 'l');
Simon Glassa21e7752023-01-17 10:48:06 -0700167 no_hunter = strchr(argv[1], 'H');
Simon Glass9bf27862023-10-01 19:15:25 -0600168 menu = strchr(argv[1], 'm');
169 text_mode = strchr(argv[1], 't');
Simon Glass7617f492022-04-24 23:31:11 -0600170 argc--;
171 argv++;
172 }
Simon Glassba3d5372023-01-17 10:48:15 -0700173 if (argc > 1)
174 label = argv[1];
175 if (!label)
176 dev = std->cur_bootdev;
Simon Glass7617f492022-04-24 23:31:11 -0600177 } else {
178 if (has_args) {
Simon Glass2d5a8e12023-05-06 08:27:09 -0600179 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
Simon Glass7617f492022-04-24 23:31:11 -0600180 return CMD_RET_USAGE;
181 }
182 boot = true;
183 }
184
185 std->cur_bootflow = NULL;
186
Simon Glass3c63a872025-03-15 14:25:58 +0000187 flags = BOOTFLOWIF_ONLY_BOOTABLE;
Simon Glass7617f492022-04-24 23:31:11 -0600188 if (list)
Simon Glass99e68182023-02-22 12:17:03 -0700189 flags |= BOOTFLOWIF_SHOW;
Simon Glass7617f492022-04-24 23:31:11 -0600190 if (all)
Simon Glass99e68182023-02-22 12:17:03 -0700191 flags |= BOOTFLOWIF_ALL;
Simon Glass73fcf512022-07-30 15:52:25 -0600192 if (no_global)
Simon Glass99e68182023-02-22 12:17:03 -0700193 flags |= BOOTFLOWIF_SKIP_GLOBAL;
Simon Glassa21e7752023-01-17 10:48:06 -0700194 if (!no_hunter)
Simon Glass99e68182023-02-22 12:17:03 -0700195 flags |= BOOTFLOWIF_HUNT;
Simon Glass7617f492022-04-24 23:31:11 -0600196
197 /*
198 * If we have a device, just scan for bootflows attached to that device
199 */
Simon Glassba3d5372023-01-17 10:48:15 -0700200 if (list) {
201 printf("Scanning for bootflows ");
202 if (dev)
203 printf("in bootdev '%s'\n", dev->name);
204 else if (label)
205 printf("with label '%s'\n", label);
206 else
207 printf("in all bootdevs\n");
208 show_header();
209 }
210 if (dev)
Simon Glass346ab5d2024-11-15 16:19:09 -0700211 bootstd_clear_bootflows_for_bootdev(dev);
Simon Glassba3d5372023-01-17 10:48:15 -0700212 else
Simon Glass7617f492022-04-24 23:31:11 -0600213 bootstd_clear_glob();
Simon Glassba3d5372023-01-17 10:48:15 -0700214 for (i = 0,
Simon Glass5d3d44f2023-01-17 10:48:16 -0700215 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
Simon Glassba3d5372023-01-17 10:48:15 -0700216 i < 1000 && ret != -ENODEV;
217 i++, ret = bootflow_scan_next(&iter, &bflow)) {
218 bflow.err = ret;
219 if (!ret)
220 num_valid++;
Simon Glassc01d83f2024-11-15 16:19:08 -0700221 ret = bootstd_add_bootflow(&bflow);
Simon Glass199f5882024-11-15 16:19:12 -0700222 if (ret < 0) {
Simon Glassba3d5372023-01-17 10:48:15 -0700223 printf("Out of memory\n");
224 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600225 }
Simon Glassba3d5372023-01-17 10:48:15 -0700226 if (list)
227 show_bootflow(i, &bflow, errors);
Simon Glass9bf27862023-10-01 19:15:25 -0600228 if (!menu && boot && !bflow.err)
Simon Glassba3d5372023-01-17 10:48:15 -0700229 bootflow_run_boot(&iter, &bflow);
Simon Glass7617f492022-04-24 23:31:11 -0600230 }
231 bootflow_iter_uninit(&iter);
232 if (list)
233 show_footer(i, num_valid);
234
Simon Glass9bf27862023-10-01 19:15:25 -0600235 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
236 if (!num_valid && !list) {
237 printf("No bootflows found; try again with -l\n");
238 } else if (menu) {
239 struct bootflow *sel_bflow;
240
241 ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
242 if (!ret && boot) {
243 ret = console_clear();
244 if (ret) {
245 log_err("Failed to clear console: %dE\n",
246 ret);
247 return ret;
248 }
249
250 bootflow_run_boot(NULL, sel_bflow);
251 }
252 }
253 }
Simon Glass8f97c672023-04-24 13:49:48 +1200254
Simon Glass7617f492022-04-24 23:31:11 -0600255 return 0;
256}
257
258#ifdef CONFIG_CMD_BOOTFLOW_FULL
259static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
260 char *const argv[])
261{
262 struct bootstd_priv *std;
263 struct udevice *dev;
264 struct bootflow *bflow;
265 int num_valid = 0;
266 bool errors = false;
267 int ret, i;
268
269 if (argc > 1 && *argv[1] == '-')
270 errors = strchr(argv[1], 'e');
271
272 ret = bootstd_get_priv(&std);
273 if (ret)
274 return CMD_RET_FAILURE;
275 dev = std->cur_bootdev;
276
277 /* If we have a device, just list bootflows attached to that device */
278 if (dev) {
279 printf("Showing bootflows for bootdev '%s'\n", dev->name);
280 show_header();
281 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
282 !ret;
283 ret = bootdev_next_bootflow(&bflow), i++) {
284 num_valid += bflow->state == BOOTFLOWST_READY;
285 show_bootflow(i, bflow, errors);
286 }
287 } else {
288 printf("Showing all bootflows\n");
289 show_header();
290 for (ret = bootflow_first_glob(&bflow), i = 0;
291 !ret;
292 ret = bootflow_next_glob(&bflow), i++) {
293 num_valid += bflow->state == BOOTFLOWST_READY;
294 show_bootflow(i, bflow, errors);
295 }
296 }
297 show_footer(i, num_valid);
298
299 return 0;
300}
301
302static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
303 char *const argv[])
304{
305 struct bootstd_priv *std;
306 struct bootflow *bflow, *found;
307 struct udevice *dev;
308 const char *name;
309 char *endp;
310 int seq, i;
311 int ret;
312
313 ret = bootstd_get_priv(&std);
314 if (ret)
315 return CMD_RET_FAILURE;
316;
317 if (argc < 2) {
318 std->cur_bootflow = NULL;
319 return 0;
320 }
321 dev = std->cur_bootdev;
322
323 name = argv[1];
324 seq = simple_strtol(name, &endp, 16);
325 found = NULL;
326
327 /*
328 * If we have a bootdev device, only allow selection of bootflows
329 * attached to that device
330 */
331 if (dev) {
332 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
333 !ret;
334 ret = bootdev_next_bootflow(&bflow), i++) {
335 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
336 found = bflow;
337 break;
338 }
339 }
340 } else {
341 for (ret = bootflow_first_glob(&bflow), i = 0;
342 !ret;
343 ret = bootflow_next_glob(&bflow), i++) {
344 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
345 found = bflow;
346 break;
347 }
348 }
349 }
350
351 if (!found) {
352 printf("Cannot find bootflow '%s' ", name);
353 if (dev)
354 printf("in bootdev '%s' ", dev->name);
355 printf("(err=%d)\n", ret);
356 return CMD_RET_FAILURE;
357 }
358 std->cur_bootflow = found;
Simon Glassb35513a2023-07-12 09:04:35 -0600359 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
360 if (env_set("bootargs", found->cmdline)) {
361 printf("Cannot set bootargs\n");
362 return CMD_RET_FAILURE;
363 }
364 }
Simon Glass7617f492022-04-24 23:31:11 -0600365
366 return 0;
367}
368
369static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
370 char *const argv[])
371{
372 struct bootstd_priv *std;
373 struct bootflow *bflow;
Simon Glass5495aaf2023-07-30 11:17:00 -0600374 bool x86_setup = false;
Simon Glass7617f492022-04-24 23:31:11 -0600375 bool dump = false;
376 int ret;
377
Simon Glass5495aaf2023-07-30 11:17:00 -0600378 if (argc > 1 && *argv[1] == '-') {
Simon Glass7617f492022-04-24 23:31:11 -0600379 dump = strchr(argv[1], 'd');
Simon Glass5495aaf2023-07-30 11:17:00 -0600380 x86_setup = strchr(argv[1], 's');
381 }
Simon Glass7617f492022-04-24 23:31:11 -0600382
383 ret = bootstd_get_priv(&std);
384 if (ret)
385 return CMD_RET_FAILURE;
386
387 if (!std->cur_bootflow) {
388 printf("No bootflow selected\n");
389 return CMD_RET_FAILURE;
390 }
391 bflow = std->cur_bootflow;
392
Simon Glass5495aaf2023-07-30 11:17:00 -0600393 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
Tom Rini6388b6b2025-04-07 12:35:13 -0600394 zimage_dump(bflow->x86_setup, false);
Simon Glass5495aaf2023-07-30 11:17:00 -0600395
396 return 0;
397 }
398
Simon Glass7617f492022-04-24 23:31:11 -0600399 printf("Name: %s\n", bflow->name);
400 printf("Device: %s\n", bflow->dev->name);
401 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
402 printf("Method: %s\n", bflow->method->name);
403 printf("State: %s\n", bootflow_state_get_name(bflow->state));
404 printf("Partition: %d\n", bflow->part);
405 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
406 printf("Filename: %s\n", bflow->fname);
Simon Glasscdf83fd22024-10-19 09:22:09 -0600407 printf("Buffer: ");
408 if (bflow->buf)
409 printf("%lx\n", (ulong)map_to_sysmem(bflow->buf));
410 else
411 printf("(not loaded)\n");
Simon Glass7617f492022-04-24 23:31:11 -0600412 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
Simon Glass72b7b192023-01-06 08:52:33 -0600413 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
Simon Glass33927522023-07-12 09:04:34 -0600414 printf("Cmdline: ");
415 if (bflow->cmdline)
416 puts(bflow->cmdline);
417 else
418 puts("(none)");
419 putc('\n');
Simon Glass63398b02023-07-12 09:04:36 -0600420 if (bflow->x86_setup)
Simon Glass2f0128f2024-10-19 09:21:59 -0600421 printf("X86 setup: %lx\n",
422 (ulong)map_to_sysmem(bflow->x86_setup));
Simon Glass612b9cc2023-01-06 08:52:34 -0600423 printf("Logo: %s\n", bflow->logo ?
424 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
425 if (bflow->logo) {
426 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
427 bflow->logo_size);
428 }
Simon Glass7b8c6342023-01-17 10:47:56 -0700429 printf("FDT: %s\n", bflow->fdt_fname);
430 if (bflow->fdt_fname) {
431 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
432 bflow->fdt_size);
433 printf("FDT addr: %lx\n", bflow->fdt_addr);
434 }
Simon Glass7617f492022-04-24 23:31:11 -0600435 printf("Error: %d\n", bflow->err);
436 if (dump && bflow->buf) {
437 /* Set some sort of maximum on the size */
438 int size = min(bflow->size, 10 << 10);
439 int i;
440
441 printf("Contents:\n\n");
442 for (i = 0; i < size; i++) {
443 putc(bflow->buf[i]);
444 if (!(i % 128) && ctrlc()) {
445 printf("...interrupted\n");
446 break;
447 }
448 }
449 }
450
451 return 0;
452}
453
Simon Glass6d8f95b2023-08-10 19:33:18 -0600454static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
455 char *const argv[])
456{
457 struct bootstd_priv *std;
458 struct bootflow *bflow;
459 int ret;
460
461 ret = bootstd_get_priv(&std);
462 if (ret)
463 return CMD_RET_FAILURE;
464
465 /*
466 * Require a current bootflow. Users can use 'bootflow scan -b' to
467 * automatically scan and boot, if needed.
468 */
469 if (!std->cur_bootflow) {
470 printf("No bootflow selected\n");
471 return CMD_RET_FAILURE;
472 }
473 bflow = std->cur_bootflow;
474 ret = bootflow_read_all(bflow);
475 if (ret) {
476 printf("Failed: err=%dE\n", ret);
477 return CMD_RET_FAILURE;
478 }
479
480 return 0;
481}
482
Simon Glass7617f492022-04-24 23:31:11 -0600483static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
484 char *const argv[])
485{
486 struct bootstd_priv *std;
487 struct bootflow *bflow;
488 int ret;
489
490 ret = bootstd_get_priv(&std);
491 if (ret)
492 return CMD_RET_FAILURE;
493
494 /*
495 * Require a current bootflow. Users can use 'bootflow scan -b' to
496 * automatically scan and boot, if needed.
497 */
498 if (!std->cur_bootflow) {
499 printf("No bootflow selected\n");
500 return CMD_RET_FAILURE;
501 }
502 bflow = std->cur_bootflow;
503 ret = bootflow_run_boot(NULL, bflow);
504 if (ret)
505 return CMD_RET_FAILURE;
506
507 return 0;
508}
Simon Glass0a2f6a32023-01-06 08:52:40 -0600509
510static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
511 char *const argv[])
512{
513 struct bootstd_priv *std;
514 struct bootflow *bflow;
515 bool text_mode = false;
516 int ret;
517
Tom Rinif2d51362023-04-06 10:03:33 -0400518 if (!IS_ENABLED(CONFIG_EXPO)) {
519 printf("Menu not supported\n");
520 return CMD_RET_FAILURE;
521 }
522
Simon Glass0a2f6a32023-01-06 08:52:40 -0600523 if (argc > 1 && *argv[1] == '-')
524 text_mode = strchr(argv[1], 't');
525
526 ret = bootstd_get_priv(&std);
527 if (ret)
528 return CMD_RET_FAILURE;
529
Simon Glass6d5083b2023-10-01 19:14:38 -0600530 ret = bootflow_handle_menu(std, text_mode, &bflow);
531 if (ret)
532 return CMD_RET_FAILURE;
Simon Glass0a2f6a32023-01-06 08:52:40 -0600533
534 return 0;
535}
Simon Glass55a2da32023-07-12 09:04:39 -0600536
537static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
538 char *const argv[])
539{
540 struct bootstd_priv *std;
541 struct bootflow *bflow;
542 const char *op, *arg, *val = NULL;
543 int ret;
544
545 if (argc < 3)
546 return CMD_RET_USAGE;
547
548 ret = bootstd_get_priv(&std);
549 if (ret)
550 return CMD_RET_FAILURE;
551
552 bflow = std->cur_bootflow;
553 if (!bflow) {
554 printf("No bootflow selected\n");
555 return CMD_RET_FAILURE;
556 }
557
558 op = argv[1];
559 arg = argv[2];
560 if (*op == 's') {
Simon Glass7a164f82023-11-29 10:31:19 -0700561 val = argv[3] ?: (const char *)BOOTFLOWCL_EMPTY;
Simon Glass55a2da32023-07-12 09:04:39 -0600562 }
563
564 switch (*op) {
565 case 'c': /* clear */
566 val = "";
567 fallthrough;
568 case 's': /* set */
569 case 'd': /* delete */
570 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
571 break;
572 case 'g': /* get */
573 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
574 if (ret >= 0)
575 printf("%.*s\n", ret, val);
576 break;
Simon Glasscd91e992023-07-12 09:04:42 -0600577 case 'a': /* auto */
578 ret = bootflow_cmdline_auto(bflow, arg);
579 break;
Simon Glass55a2da32023-07-12 09:04:39 -0600580 }
581 switch (ret) {
582 case -E2BIG:
583 printf("Argument too long\n");
584 break;
585 case -ENOENT:
586 printf("Argument not found\n");
587 break;
588 case -EINVAL:
589 printf("Mismatched quotes\n");
590 break;
591 case -EBADF:
592 printf("Value must be quoted\n");
593 break;
594 default:
595 if (ret < 0)
596 printf("Unknown error: %dE\n", ret);
597 }
598 if (ret < 0)
599 return CMD_RET_FAILURE;
600
601 return 0;
602}
Simon Glass7617f492022-04-24 23:31:11 -0600603#endif /* CONFIG_CMD_BOOTFLOW_FULL */
604
Tom Rini03f146c2023-10-07 15:13:08 -0400605U_BOOT_LONGHELP(bootflow,
Simon Glass7617f492022-04-24 23:31:11 -0600606#ifdef CONFIG_CMD_BOOTFLOW_FULL
Simon Glass73fcf512022-07-30 15:52:25 -0600607 "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 -0600608 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
609 "bootflow select [<num>|<name>] - select a bootflow\n"
Simon Glass5495aaf2023-07-30 11:17:00 -0600610 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
Simon Glass6d8f95b2023-08-10 19:33:18 -0600611 "bootflow read - read all current-bootflow files\n"
612 "bootflow boot - boot current bootflow\n"
Simon Glass55a2da32023-07-12 09:04:39 -0600613 "bootflow menu [-t] - show a menu of available bootflows\n"
Tom Rini03f146c2023-10-07 15:13:08 -0400614 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
Simon Glass7617f492022-04-24 23:31:11 -0600615#else
Tom Rini03f146c2023-10-07 15:13:08 -0400616 "scan - boot first available bootflow\n"
Simon Glass7617f492022-04-24 23:31:11 -0600617#endif
Tom Rini03f146c2023-10-07 15:13:08 -0400618 );
Simon Glass7617f492022-04-24 23:31:11 -0600619
620U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
621 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
622#ifdef CONFIG_CMD_BOOTFLOW_FULL
623 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
624 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
625 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
Simon Glass6d8f95b2023-08-10 19:33:18 -0600626 U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
Simon Glass0a2f6a32023-01-06 08:52:40 -0600627 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
628 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
Simon Glass55a2da32023-07-12 09:04:39 -0600629 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
Simon Glass7617f492022-04-24 23:31:11 -0600630#endif
631);