blob: 3aeb40d690f4d4902b19bc844d8c60e9302bdf73 [file] [log] [blame]
Simon Glass2d653f62022-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
9#include <common.h>
10#include <bootdev.h>
11#include <bootflow.h>
Simon Glasscbb607d2023-07-30 11:17:00 -060012#include <bootm.h>
Simon Glass2d653f62022-04-24 23:31:11 -060013#include <bootstd.h>
14#include <command.h>
15#include <console.h>
16#include <dm.h>
17#include <mapmem.h>
18
19/**
20 * report_bootflow_err() - Report where a bootflow failed
21 *
22 * When a bootflow does not make it to the 'loaded' state, something went wrong.
23 * Print a helpful message if there is an error
24 *
25 * @bflow: Bootflow to process
26 * @err: Error code (0 if none)
27 */
28static void report_bootflow_err(struct bootflow *bflow, int err)
29{
30 if (!err)
31 return;
32
33 /* Indent out to 'Method' */
34 printf(" ** ");
35
36 switch (bflow->state) {
37 case BOOTFLOWST_BASE:
38 printf("No media/partition found");
39 break;
40 case BOOTFLOWST_MEDIA:
41 printf("No partition found");
42 break;
43 case BOOTFLOWST_PART:
44 printf("No filesystem found");
45 break;
46 case BOOTFLOWST_FS:
47 printf("File not found");
48 break;
49 case BOOTFLOWST_FILE:
50 printf("File cannot be loaded");
51 break;
52 case BOOTFLOWST_READY:
53 printf("Ready");
54 break;
55 case BOOTFLOWST_COUNT:
56 break;
57 }
58
Simon Glassc8894342023-05-10 16:34:26 -060059 printf(", err=%dE\n", err);
Simon Glass2d653f62022-04-24 23:31:11 -060060}
61
62/**
63 * show_bootflow() - Show the status of a bootflow
64 *
65 * @seq: Bootflow index
66 * @bflow: Bootflow to show
67 * @errors: True to show the error received, if any
68 */
69static void show_bootflow(int index, struct bootflow *bflow, bool errors)
70{
71 printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index,
72 bflow->method->name, bootflow_state_get_name(bflow->state),
Simon Glasseccb25c2022-07-30 15:52:23 -060073 bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
Simon Glassc3867e22023-08-24 13:55:39 -060074 "(none)", bflow->part, bflow->name, bflow->fname ?: "");
Simon Glass2d653f62022-04-24 23:31:11 -060075 if (errors)
76 report_bootflow_err(bflow, bflow->err);
77}
78
79static void show_header(void)
80{
81 printf("Seq Method State Uclass Part Name Filename\n");
82 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
83}
84
85static void show_footer(int count, int num_valid)
86{
87 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
88 printf("(%d bootflow%s, %d valid)\n", count, count != 1 ? "s" : "",
89 num_valid);
90}
91
Simon Glass3fa53b92023-10-01 19:14:38 -060092/**
93 * bootflow_handle_menu() - Handle running the menu and updating cur bootflow
94 *
95 * This shows the menu, allows the user to select something and then prints
96 * what happened
97 *
98 * @std: bootstd information
99 * @text_mode: true to run the menu in text mode
100 * @bflowp: Returns selected bootflow, on success
101 * Return: 0 on success (a bootflow was selected), -EAGAIN if nothing was
102 * chosen, other -ve value on other error
103 */
104__maybe_unused static int bootflow_handle_menu(struct bootstd_priv *std,
105 bool text_mode,
106 struct bootflow **bflowp)
107{
108 struct bootflow *bflow;
109 int ret;
110
111 ret = bootflow_menu_run(std, text_mode, &bflow);
112 if (ret) {
113 if (ret == -EAGAIN) {
114 printf("Nothing chosen\n");
115 std->cur_bootflow = NULL;
116 } else {
117 printf("Menu failed (err=%d)\n", ret);
118 }
119
120 return ret;
121 }
122
123 printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
124 std->cur_bootflow = bflow;
125 *bflowp = bflow;
126
127 return 0;
128}
129
Simon Glass2d653f62022-04-24 23:31:11 -0600130static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
131 char *const argv[])
132{
133 struct bootstd_priv *std;
134 struct bootflow_iter iter;
Simon Glass91943ff2023-01-17 10:48:15 -0700135 struct udevice *dev = NULL;
Simon Glass2d653f62022-04-24 23:31:11 -0600136 struct bootflow bflow;
Simon Glass2b80bc12022-07-30 15:52:25 -0600137 bool all = false, boot = false, errors = false, no_global = false;
Simon Glassd73420e2023-01-17 10:48:06 -0700138 bool list = false, no_hunter = false;
Simon Glass2d653f62022-04-24 23:31:11 -0600139 int num_valid = 0;
Simon Glass91943ff2023-01-17 10:48:15 -0700140 const char *label = NULL;
Simon Glass2d653f62022-04-24 23:31:11 -0600141 bool has_args;
142 int ret, i;
143 int flags;
144
145 ret = bootstd_get_priv(&std);
146 if (ret)
147 return CMD_RET_FAILURE;
Simon Glass2d653f62022-04-24 23:31:11 -0600148
149 has_args = argc > 1 && *argv[1] == '-';
150 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
151 if (has_args) {
152 all = strchr(argv[1], 'a');
153 boot = strchr(argv[1], 'b');
154 errors = strchr(argv[1], 'e');
Simon Glass2b80bc12022-07-30 15:52:25 -0600155 no_global = strchr(argv[1], 'G');
Simon Glass2d653f62022-04-24 23:31:11 -0600156 list = strchr(argv[1], 'l');
Simon Glassd73420e2023-01-17 10:48:06 -0700157 no_hunter = strchr(argv[1], 'H');
Simon Glass2d653f62022-04-24 23:31:11 -0600158 argc--;
159 argv++;
160 }
Simon Glass91943ff2023-01-17 10:48:15 -0700161 if (argc > 1)
162 label = argv[1];
163 if (!label)
164 dev = std->cur_bootdev;
Simon Glass2d653f62022-04-24 23:31:11 -0600165 } else {
166 if (has_args) {
Simon Glassd8d40bc2023-05-06 08:27:09 -0600167 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
Simon Glass2d653f62022-04-24 23:31:11 -0600168 return CMD_RET_USAGE;
169 }
170 boot = true;
171 }
172
173 std->cur_bootflow = NULL;
174
175 flags = 0;
176 if (list)
Simon Glass4f806f32023-02-22 12:17:03 -0700177 flags |= BOOTFLOWIF_SHOW;
Simon Glass2d653f62022-04-24 23:31:11 -0600178 if (all)
Simon Glass4f806f32023-02-22 12:17:03 -0700179 flags |= BOOTFLOWIF_ALL;
Simon Glass2b80bc12022-07-30 15:52:25 -0600180 if (no_global)
Simon Glass4f806f32023-02-22 12:17:03 -0700181 flags |= BOOTFLOWIF_SKIP_GLOBAL;
Simon Glassd73420e2023-01-17 10:48:06 -0700182 if (!no_hunter)
Simon Glass4f806f32023-02-22 12:17:03 -0700183 flags |= BOOTFLOWIF_HUNT;
Simon Glass2d653f62022-04-24 23:31:11 -0600184
185 /*
186 * If we have a device, just scan for bootflows attached to that device
187 */
Simon Glass91943ff2023-01-17 10:48:15 -0700188 if (list) {
189 printf("Scanning for bootflows ");
190 if (dev)
191 printf("in bootdev '%s'\n", dev->name);
192 else if (label)
193 printf("with label '%s'\n", label);
194 else
195 printf("in all bootdevs\n");
196 show_header();
197 }
198 if (dev)
Simon Glass2d653f62022-04-24 23:31:11 -0600199 bootdev_clear_bootflows(dev);
Simon Glass91943ff2023-01-17 10:48:15 -0700200 else
Simon Glass2d653f62022-04-24 23:31:11 -0600201 bootstd_clear_glob();
Simon Glass91943ff2023-01-17 10:48:15 -0700202 for (i = 0,
Simon Glass4b7cb052023-01-17 10:48:16 -0700203 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
Simon Glass91943ff2023-01-17 10:48:15 -0700204 i < 1000 && ret != -ENODEV;
205 i++, ret = bootflow_scan_next(&iter, &bflow)) {
206 bflow.err = ret;
207 if (!ret)
208 num_valid++;
209 ret = bootdev_add_bootflow(&bflow);
210 if (ret) {
211 printf("Out of memory\n");
212 return CMD_RET_FAILURE;
Simon Glass2d653f62022-04-24 23:31:11 -0600213 }
Simon Glass91943ff2023-01-17 10:48:15 -0700214 if (list)
215 show_bootflow(i, &bflow, errors);
216 if (boot && !bflow.err)
217 bootflow_run_boot(&iter, &bflow);
Simon Glass2d653f62022-04-24 23:31:11 -0600218 }
219 bootflow_iter_uninit(&iter);
220 if (list)
221 show_footer(i, num_valid);
222
Simon Glassf9fb57c2023-04-24 13:49:48 +1200223 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && !num_valid && !list)
224 printf("No bootflows found; try again with -l\n");
225
Simon Glass2d653f62022-04-24 23:31:11 -0600226 return 0;
227}
228
229#ifdef CONFIG_CMD_BOOTFLOW_FULL
230static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
231 char *const argv[])
232{
233 struct bootstd_priv *std;
234 struct udevice *dev;
235 struct bootflow *bflow;
236 int num_valid = 0;
237 bool errors = false;
238 int ret, i;
239
240 if (argc > 1 && *argv[1] == '-')
241 errors = strchr(argv[1], 'e');
242
243 ret = bootstd_get_priv(&std);
244 if (ret)
245 return CMD_RET_FAILURE;
246 dev = std->cur_bootdev;
247
248 /* If we have a device, just list bootflows attached to that device */
249 if (dev) {
250 printf("Showing bootflows for bootdev '%s'\n", dev->name);
251 show_header();
252 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
253 !ret;
254 ret = bootdev_next_bootflow(&bflow), i++) {
255 num_valid += bflow->state == BOOTFLOWST_READY;
256 show_bootflow(i, bflow, errors);
257 }
258 } else {
259 printf("Showing all bootflows\n");
260 show_header();
261 for (ret = bootflow_first_glob(&bflow), i = 0;
262 !ret;
263 ret = bootflow_next_glob(&bflow), i++) {
264 num_valid += bflow->state == BOOTFLOWST_READY;
265 show_bootflow(i, bflow, errors);
266 }
267 }
268 show_footer(i, num_valid);
269
270 return 0;
271}
272
273static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
274 char *const argv[])
275{
276 struct bootstd_priv *std;
277 struct bootflow *bflow, *found;
278 struct udevice *dev;
279 const char *name;
280 char *endp;
281 int seq, i;
282 int ret;
283
284 ret = bootstd_get_priv(&std);
285 if (ret)
286 return CMD_RET_FAILURE;
287;
288 if (argc < 2) {
289 std->cur_bootflow = NULL;
290 return 0;
291 }
292 dev = std->cur_bootdev;
293
294 name = argv[1];
295 seq = simple_strtol(name, &endp, 16);
296 found = NULL;
297
298 /*
299 * If we have a bootdev device, only allow selection of bootflows
300 * attached to that device
301 */
302 if (dev) {
303 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
304 !ret;
305 ret = bootdev_next_bootflow(&bflow), i++) {
306 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
307 found = bflow;
308 break;
309 }
310 }
311 } else {
312 for (ret = bootflow_first_glob(&bflow), i = 0;
313 !ret;
314 ret = bootflow_next_glob(&bflow), i++) {
315 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
316 found = bflow;
317 break;
318 }
319 }
320 }
321
322 if (!found) {
323 printf("Cannot find bootflow '%s' ", name);
324 if (dev)
325 printf("in bootdev '%s' ", dev->name);
326 printf("(err=%d)\n", ret);
327 return CMD_RET_FAILURE;
328 }
329 std->cur_bootflow = found;
Simon Glassd42243f2023-07-12 09:04:35 -0600330 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
331 if (env_set("bootargs", found->cmdline)) {
332 printf("Cannot set bootargs\n");
333 return CMD_RET_FAILURE;
334 }
335 }
Simon Glass2d653f62022-04-24 23:31:11 -0600336
337 return 0;
338}
339
340static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
341 char *const argv[])
342{
343 struct bootstd_priv *std;
344 struct bootflow *bflow;
Simon Glasscbb607d2023-07-30 11:17:00 -0600345 bool x86_setup = false;
Simon Glass2d653f62022-04-24 23:31:11 -0600346 bool dump = false;
347 int ret;
348
Simon Glasscbb607d2023-07-30 11:17:00 -0600349 if (argc > 1 && *argv[1] == '-') {
Simon Glass2d653f62022-04-24 23:31:11 -0600350 dump = strchr(argv[1], 'd');
Simon Glasscbb607d2023-07-30 11:17:00 -0600351 x86_setup = strchr(argv[1], 's');
352 }
Simon Glass2d653f62022-04-24 23:31:11 -0600353
354 ret = bootstd_get_priv(&std);
355 if (ret)
356 return CMD_RET_FAILURE;
357
358 if (!std->cur_bootflow) {
359 printf("No bootflow selected\n");
360 return CMD_RET_FAILURE;
361 }
362 bflow = std->cur_bootflow;
363
Simon Glasscbb607d2023-07-30 11:17:00 -0600364 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
365 zimage_dump(bflow->x86_setup, false);
366
367 return 0;
368 }
369
Simon Glass2d653f62022-04-24 23:31:11 -0600370 printf("Name: %s\n", bflow->name);
371 printf("Device: %s\n", bflow->dev->name);
372 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
373 printf("Method: %s\n", bflow->method->name);
374 printf("State: %s\n", bootflow_state_get_name(bflow->state));
375 printf("Partition: %d\n", bflow->part);
376 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
377 printf("Filename: %s\n", bflow->fname);
378 printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf));
379 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
Simon Glass2175e762023-01-06 08:52:33 -0600380 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
Simon Glassf4a91652023-07-12 09:04:34 -0600381 printf("Cmdline: ");
382 if (bflow->cmdline)
383 puts(bflow->cmdline);
384 else
385 puts("(none)");
386 putc('\n');
Simon Glass43b6fa92023-07-12 09:04:36 -0600387 if (bflow->x86_setup)
388 printf("X86 setup: %p\n", bflow->x86_setup);
Simon Glass24d8e1b2023-01-06 08:52:34 -0600389 printf("Logo: %s\n", bflow->logo ?
390 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
391 if (bflow->logo) {
392 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
393 bflow->logo_size);
394 }
Simon Glass7638c852023-01-17 10:47:56 -0700395 printf("FDT: %s\n", bflow->fdt_fname);
396 if (bflow->fdt_fname) {
397 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
398 bflow->fdt_size);
399 printf("FDT addr: %lx\n", bflow->fdt_addr);
400 }
Simon Glass2d653f62022-04-24 23:31:11 -0600401 printf("Error: %d\n", bflow->err);
402 if (dump && bflow->buf) {
403 /* Set some sort of maximum on the size */
404 int size = min(bflow->size, 10 << 10);
405 int i;
406
407 printf("Contents:\n\n");
408 for (i = 0; i < size; i++) {
409 putc(bflow->buf[i]);
410 if (!(i % 128) && ctrlc()) {
411 printf("...interrupted\n");
412 break;
413 }
414 }
415 }
416
417 return 0;
418}
419
Simon Glassc2792242023-08-10 19:33:18 -0600420static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
421 char *const argv[])
422{
423 struct bootstd_priv *std;
424 struct bootflow *bflow;
425 int ret;
426
427 ret = bootstd_get_priv(&std);
428 if (ret)
429 return CMD_RET_FAILURE;
430
431 /*
432 * Require a current bootflow. Users can use 'bootflow scan -b' to
433 * automatically scan and boot, if needed.
434 */
435 if (!std->cur_bootflow) {
436 printf("No bootflow selected\n");
437 return CMD_RET_FAILURE;
438 }
439 bflow = std->cur_bootflow;
440 ret = bootflow_read_all(bflow);
441 if (ret) {
442 printf("Failed: err=%dE\n", ret);
443 return CMD_RET_FAILURE;
444 }
445
446 return 0;
447}
448
Simon Glass2d653f62022-04-24 23:31:11 -0600449static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
450 char *const argv[])
451{
452 struct bootstd_priv *std;
453 struct bootflow *bflow;
454 int ret;
455
456 ret = bootstd_get_priv(&std);
457 if (ret)
458 return CMD_RET_FAILURE;
459
460 /*
461 * Require a current bootflow. Users can use 'bootflow scan -b' to
462 * automatically scan and boot, if needed.
463 */
464 if (!std->cur_bootflow) {
465 printf("No bootflow selected\n");
466 return CMD_RET_FAILURE;
467 }
468 bflow = std->cur_bootflow;
469 ret = bootflow_run_boot(NULL, bflow);
470 if (ret)
471 return CMD_RET_FAILURE;
472
473 return 0;
474}
Simon Glass02d929b2023-01-06 08:52:40 -0600475
476static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
477 char *const argv[])
478{
479 struct bootstd_priv *std;
480 struct bootflow *bflow;
481 bool text_mode = false;
482 int ret;
483
Tom Rinie0dda262023-04-06 10:03:33 -0400484 if (!IS_ENABLED(CONFIG_EXPO)) {
485 printf("Menu not supported\n");
486 return CMD_RET_FAILURE;
487 }
488
Simon Glass02d929b2023-01-06 08:52:40 -0600489 if (argc > 1 && *argv[1] == '-')
490 text_mode = strchr(argv[1], 't');
491
492 ret = bootstd_get_priv(&std);
493 if (ret)
494 return CMD_RET_FAILURE;
495
Simon Glass3fa53b92023-10-01 19:14:38 -0600496 ret = bootflow_handle_menu(std, text_mode, &bflow);
497 if (ret)
498 return CMD_RET_FAILURE;
Simon Glass02d929b2023-01-06 08:52:40 -0600499
500 return 0;
501}
Simon Glass82c09382023-07-12 09:04:39 -0600502
503static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
504 char *const argv[])
505{
506 struct bootstd_priv *std;
507 struct bootflow *bflow;
508 const char *op, *arg, *val = NULL;
509 int ret;
510
511 if (argc < 3)
512 return CMD_RET_USAGE;
513
514 ret = bootstd_get_priv(&std);
515 if (ret)
516 return CMD_RET_FAILURE;
517
518 bflow = std->cur_bootflow;
519 if (!bflow) {
520 printf("No bootflow selected\n");
521 return CMD_RET_FAILURE;
522 }
523
524 op = argv[1];
525 arg = argv[2];
526 if (*op == 's') {
527 if (argc < 4)
528 return CMD_RET_USAGE;
529 val = argv[3];
530 }
531
532 switch (*op) {
533 case 'c': /* clear */
534 val = "";
535 fallthrough;
536 case 's': /* set */
537 case 'd': /* delete */
538 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
539 break;
540 case 'g': /* get */
541 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
542 if (ret >= 0)
543 printf("%.*s\n", ret, val);
544 break;
Simon Glass33ebcb42023-07-12 09:04:42 -0600545 case 'a': /* auto */
546 ret = bootflow_cmdline_auto(bflow, arg);
547 break;
Simon Glass82c09382023-07-12 09:04:39 -0600548 }
549 switch (ret) {
550 case -E2BIG:
551 printf("Argument too long\n");
552 break;
553 case -ENOENT:
554 printf("Argument not found\n");
555 break;
556 case -EINVAL:
557 printf("Mismatched quotes\n");
558 break;
559 case -EBADF:
560 printf("Value must be quoted\n");
561 break;
562 default:
563 if (ret < 0)
564 printf("Unknown error: %dE\n", ret);
565 }
566 if (ret < 0)
567 return CMD_RET_FAILURE;
568
569 return 0;
570}
Simon Glass2d653f62022-04-24 23:31:11 -0600571#endif /* CONFIG_CMD_BOOTFLOW_FULL */
572
Tom Rini36162182023-10-07 15:13:08 -0400573U_BOOT_LONGHELP(bootflow,
Simon Glass2d653f62022-04-24 23:31:11 -0600574#ifdef CONFIG_CMD_BOOTFLOW_FULL
Simon Glass2b80bc12022-07-30 15:52:25 -0600575 "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
Simon Glass2d653f62022-04-24 23:31:11 -0600576 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
577 "bootflow select [<num>|<name>] - select a bootflow\n"
Simon Glasscbb607d2023-07-30 11:17:00 -0600578 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
Simon Glassc2792242023-08-10 19:33:18 -0600579 "bootflow read - read all current-bootflow files\n"
580 "bootflow boot - boot current bootflow\n"
Simon Glass82c09382023-07-12 09:04:39 -0600581 "bootflow menu [-t] - show a menu of available bootflows\n"
Tom Rini36162182023-10-07 15:13:08 -0400582 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
Simon Glass2d653f62022-04-24 23:31:11 -0600583#else
Tom Rini36162182023-10-07 15:13:08 -0400584 "scan - boot first available bootflow\n"
Simon Glass2d653f62022-04-24 23:31:11 -0600585#endif
Tom Rini36162182023-10-07 15:13:08 -0400586 );
Simon Glass2d653f62022-04-24 23:31:11 -0600587
588U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
589 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
590#ifdef CONFIG_CMD_BOOTFLOW_FULL
591 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
592 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
593 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
Simon Glassc2792242023-08-10 19:33:18 -0600594 U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
Simon Glass02d929b2023-01-06 08:52:40 -0600595 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
596 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
Simon Glass82c09382023-07-12 09:04:39 -0600597 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
Simon Glass2d653f62022-04-24 23:31:11 -0600598#endif
599);