blob: 551dffbb8b89534c75d0bd67600ed6d720cb6ab2 [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;
Simon Glass7bbbcbf2025-05-02 08:46:55 -0600112 int ret, seq;
Simon Glass6d5083b2023-10-01 19:14:38 -0600113
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 Glass7bbbcbf2025-05-02 08:46:55 -0600118 ret = -ERESTART;
Simon Glassd7cef832025-05-02 08:46:27 -0600119 do {
Simon Glass7bbbcbf2025-05-02 08:46:55 -0600120 if (ret == -ERESTART) {
121 ret = expo_render(exp);
122 if (ret)
123 return log_msg_ret("bhr", ret);
124 }
125 ret = bootflow_menu_poll(exp, &seq);
126 } while (ret == -EAGAIN || ret == -ERESTART);
Simon Glass6d5083b2023-10-01 19:14:38 -0600127
Simon Glassd7cef832025-05-02 08:46:27 -0600128 if (ret == -EPIPE) {
129 printf("Nothing chosen\n");
130 std->cur_bootflow = NULL;
131 } else if (ret) {
132 printf("Menu failed (err=%d)\n", ret);
133 } else {
Simon Glass7bbbcbf2025-05-02 08:46:55 -0600134 bflow = alist_getw(&std->bootflows, seq, struct bootflow);
Simon Glassd7cef832025-05-02 08:46:27 -0600135 printf("Selected: %s\n", bflow->os_name ? bflow->os_name :
136 bflow->name);
137 std->cur_bootflow = bflow;
138 *bflowp = bflow;
139 }
140 expo_destroy(exp);
141 if (ret)
142 return ret;
Simon Glass6d5083b2023-10-01 19:14:38 -0600143
144 return 0;
145}
146
Simon Glass7617f492022-04-24 23:31:11 -0600147static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
148 char *const argv[])
149{
150 struct bootstd_priv *std;
151 struct bootflow_iter iter;
Simon Glassba3d5372023-01-17 10:48:15 -0700152 struct udevice *dev = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600153 struct bootflow bflow;
Simon Glass73fcf512022-07-30 15:52:25 -0600154 bool all = false, boot = false, errors = false, no_global = false;
Simon Glass9bf27862023-10-01 19:15:25 -0600155 bool list = false, no_hunter = false, menu = false, text_mode = false;
Simon Glass7617f492022-04-24 23:31:11 -0600156 int num_valid = 0;
Simon Glassba3d5372023-01-17 10:48:15 -0700157 const char *label = NULL;
Simon Glass7617f492022-04-24 23:31:11 -0600158 bool has_args;
159 int ret, i;
160 int flags;
161
162 ret = bootstd_get_priv(&std);
163 if (ret)
164 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600165
166 has_args = argc > 1 && *argv[1] == '-';
167 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
168 if (has_args) {
169 all = strchr(argv[1], 'a');
170 boot = strchr(argv[1], 'b');
171 errors = strchr(argv[1], 'e');
Simon Glass73fcf512022-07-30 15:52:25 -0600172 no_global = strchr(argv[1], 'G');
Simon Glass7617f492022-04-24 23:31:11 -0600173 list = strchr(argv[1], 'l');
Simon Glassa21e7752023-01-17 10:48:06 -0700174 no_hunter = strchr(argv[1], 'H');
Simon Glass9bf27862023-10-01 19:15:25 -0600175 menu = strchr(argv[1], 'm');
176 text_mode = strchr(argv[1], 't');
Simon Glass7617f492022-04-24 23:31:11 -0600177 argc--;
178 argv++;
179 }
Simon Glassba3d5372023-01-17 10:48:15 -0700180 if (argc > 1)
181 label = argv[1];
182 if (!label)
183 dev = std->cur_bootdev;
Simon Glass7617f492022-04-24 23:31:11 -0600184 } else {
185 if (has_args) {
Simon Glass2d5a8e12023-05-06 08:27:09 -0600186 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
Simon Glass7617f492022-04-24 23:31:11 -0600187 return CMD_RET_USAGE;
188 }
189 boot = true;
190 }
191
192 std->cur_bootflow = NULL;
193
Simon Glass3c63a872025-03-15 14:25:58 +0000194 flags = BOOTFLOWIF_ONLY_BOOTABLE;
Simon Glass7617f492022-04-24 23:31:11 -0600195 if (list)
Simon Glass99e68182023-02-22 12:17:03 -0700196 flags |= BOOTFLOWIF_SHOW;
Simon Glass7617f492022-04-24 23:31:11 -0600197 if (all)
Simon Glass99e68182023-02-22 12:17:03 -0700198 flags |= BOOTFLOWIF_ALL;
Simon Glass73fcf512022-07-30 15:52:25 -0600199 if (no_global)
Simon Glass99e68182023-02-22 12:17:03 -0700200 flags |= BOOTFLOWIF_SKIP_GLOBAL;
Simon Glassa21e7752023-01-17 10:48:06 -0700201 if (!no_hunter)
Simon Glass99e68182023-02-22 12:17:03 -0700202 flags |= BOOTFLOWIF_HUNT;
Simon Glass7617f492022-04-24 23:31:11 -0600203
204 /*
205 * If we have a device, just scan for bootflows attached to that device
206 */
Simon Glassba3d5372023-01-17 10:48:15 -0700207 if (list) {
208 printf("Scanning for bootflows ");
209 if (dev)
210 printf("in bootdev '%s'\n", dev->name);
211 else if (label)
212 printf("with label '%s'\n", label);
213 else
214 printf("in all bootdevs\n");
215 show_header();
216 }
217 if (dev)
Simon Glass346ab5d2024-11-15 16:19:09 -0700218 bootstd_clear_bootflows_for_bootdev(dev);
Simon Glassba3d5372023-01-17 10:48:15 -0700219 else
Simon Glass7617f492022-04-24 23:31:11 -0600220 bootstd_clear_glob();
Simon Glassba3d5372023-01-17 10:48:15 -0700221 for (i = 0,
Simon Glass5d3d44f2023-01-17 10:48:16 -0700222 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
Simon Glassba3d5372023-01-17 10:48:15 -0700223 i < 1000 && ret != -ENODEV;
224 i++, ret = bootflow_scan_next(&iter, &bflow)) {
225 bflow.err = ret;
226 if (!ret)
227 num_valid++;
Simon Glassc01d83f2024-11-15 16:19:08 -0700228 ret = bootstd_add_bootflow(&bflow);
Simon Glass199f5882024-11-15 16:19:12 -0700229 if (ret < 0) {
Simon Glassba3d5372023-01-17 10:48:15 -0700230 printf("Out of memory\n");
231 return CMD_RET_FAILURE;
Simon Glass7617f492022-04-24 23:31:11 -0600232 }
Simon Glassba3d5372023-01-17 10:48:15 -0700233 if (list)
234 show_bootflow(i, &bflow, errors);
Simon Glass9bf27862023-10-01 19:15:25 -0600235 if (!menu && boot && !bflow.err)
Simon Glassba3d5372023-01-17 10:48:15 -0700236 bootflow_run_boot(&iter, &bflow);
Simon Glass7617f492022-04-24 23:31:11 -0600237 }
238 bootflow_iter_uninit(&iter);
239 if (list)
240 show_footer(i, num_valid);
241
Simon Glass9bf27862023-10-01 19:15:25 -0600242 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
243 if (!num_valid && !list) {
244 printf("No bootflows found; try again with -l\n");
245 } else if (menu) {
246 struct bootflow *sel_bflow;
247
248 ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
249 if (!ret && boot) {
250 ret = console_clear();
251 if (ret) {
252 log_err("Failed to clear console: %dE\n",
253 ret);
254 return ret;
255 }
256
257 bootflow_run_boot(NULL, sel_bflow);
258 }
259 }
260 }
Simon Glass8f97c672023-04-24 13:49:48 +1200261
Simon Glass7617f492022-04-24 23:31:11 -0600262 return 0;
263}
264
265#ifdef CONFIG_CMD_BOOTFLOW_FULL
266static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
267 char *const argv[])
268{
269 struct bootstd_priv *std;
270 struct udevice *dev;
271 struct bootflow *bflow;
272 int num_valid = 0;
273 bool errors = false;
274 int ret, i;
275
276 if (argc > 1 && *argv[1] == '-')
277 errors = strchr(argv[1], 'e');
278
279 ret = bootstd_get_priv(&std);
280 if (ret)
281 return CMD_RET_FAILURE;
282 dev = std->cur_bootdev;
283
284 /* If we have a device, just list bootflows attached to that device */
285 if (dev) {
286 printf("Showing bootflows for bootdev '%s'\n", dev->name);
287 show_header();
288 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
289 !ret;
290 ret = bootdev_next_bootflow(&bflow), i++) {
291 num_valid += bflow->state == BOOTFLOWST_READY;
292 show_bootflow(i, bflow, errors);
293 }
294 } else {
295 printf("Showing all bootflows\n");
296 show_header();
297 for (ret = bootflow_first_glob(&bflow), i = 0;
298 !ret;
299 ret = bootflow_next_glob(&bflow), i++) {
300 num_valid += bflow->state == BOOTFLOWST_READY;
301 show_bootflow(i, bflow, errors);
302 }
303 }
304 show_footer(i, num_valid);
305
306 return 0;
307}
308
309static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
310 char *const argv[])
311{
312 struct bootstd_priv *std;
313 struct bootflow *bflow, *found;
314 struct udevice *dev;
315 const char *name;
316 char *endp;
317 int seq, i;
318 int ret;
319
320 ret = bootstd_get_priv(&std);
321 if (ret)
322 return CMD_RET_FAILURE;
323;
324 if (argc < 2) {
325 std->cur_bootflow = NULL;
326 return 0;
327 }
328 dev = std->cur_bootdev;
329
330 name = argv[1];
331 seq = simple_strtol(name, &endp, 16);
332 found = NULL;
333
334 /*
335 * If we have a bootdev device, only allow selection of bootflows
336 * attached to that device
337 */
338 if (dev) {
339 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
340 !ret;
341 ret = bootdev_next_bootflow(&bflow), i++) {
342 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
343 found = bflow;
344 break;
345 }
346 }
347 } else {
348 for (ret = bootflow_first_glob(&bflow), i = 0;
349 !ret;
350 ret = bootflow_next_glob(&bflow), i++) {
351 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
352 found = bflow;
353 break;
354 }
355 }
356 }
357
358 if (!found) {
359 printf("Cannot find bootflow '%s' ", name);
360 if (dev)
361 printf("in bootdev '%s' ", dev->name);
362 printf("(err=%d)\n", ret);
363 return CMD_RET_FAILURE;
364 }
365 std->cur_bootflow = found;
Simon Glassb35513a2023-07-12 09:04:35 -0600366 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
367 if (env_set("bootargs", found->cmdline)) {
368 printf("Cannot set bootargs\n");
369 return CMD_RET_FAILURE;
370 }
371 }
Simon Glass7617f492022-04-24 23:31:11 -0600372
373 return 0;
374}
375
376static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
377 char *const argv[])
378{
379 struct bootstd_priv *std;
380 struct bootflow *bflow;
Simon Glass5495aaf2023-07-30 11:17:00 -0600381 bool x86_setup = false;
Simon Glass7617f492022-04-24 23:31:11 -0600382 bool dump = false;
383 int ret;
384
Simon Glass5495aaf2023-07-30 11:17:00 -0600385 if (argc > 1 && *argv[1] == '-') {
Simon Glass7617f492022-04-24 23:31:11 -0600386 dump = strchr(argv[1], 'd');
Simon Glass5495aaf2023-07-30 11:17:00 -0600387 x86_setup = strchr(argv[1], 's');
388 }
Simon Glass7617f492022-04-24 23:31:11 -0600389
390 ret = bootstd_get_priv(&std);
391 if (ret)
392 return CMD_RET_FAILURE;
393
394 if (!std->cur_bootflow) {
395 printf("No bootflow selected\n");
396 return CMD_RET_FAILURE;
397 }
398 bflow = std->cur_bootflow;
399
Simon Glass5495aaf2023-07-30 11:17:00 -0600400 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
Tom Rini6388b6b2025-04-07 12:35:13 -0600401 zimage_dump(bflow->x86_setup, false);
Simon Glass5495aaf2023-07-30 11:17:00 -0600402
403 return 0;
404 }
405
Simon Glass7617f492022-04-24 23:31:11 -0600406 printf("Name: %s\n", bflow->name);
407 printf("Device: %s\n", bflow->dev->name);
408 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
409 printf("Method: %s\n", bflow->method->name);
410 printf("State: %s\n", bootflow_state_get_name(bflow->state));
411 printf("Partition: %d\n", bflow->part);
412 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
413 printf("Filename: %s\n", bflow->fname);
Simon Glasscdf83fd22024-10-19 09:22:09 -0600414 printf("Buffer: ");
415 if (bflow->buf)
416 printf("%lx\n", (ulong)map_to_sysmem(bflow->buf));
417 else
418 printf("(not loaded)\n");
Simon Glass7617f492022-04-24 23:31:11 -0600419 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
Simon Glass72b7b192023-01-06 08:52:33 -0600420 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
Simon Glass33927522023-07-12 09:04:34 -0600421 printf("Cmdline: ");
422 if (bflow->cmdline)
423 puts(bflow->cmdline);
424 else
425 puts("(none)");
426 putc('\n');
Simon Glass63398b02023-07-12 09:04:36 -0600427 if (bflow->x86_setup)
Simon Glass2f0128f2024-10-19 09:21:59 -0600428 printf("X86 setup: %lx\n",
429 (ulong)map_to_sysmem(bflow->x86_setup));
Simon Glass612b9cc2023-01-06 08:52:34 -0600430 printf("Logo: %s\n", bflow->logo ?
431 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
432 if (bflow->logo) {
433 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
434 bflow->logo_size);
435 }
Simon Glass7b8c6342023-01-17 10:47:56 -0700436 printf("FDT: %s\n", bflow->fdt_fname);
437 if (bflow->fdt_fname) {
438 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
439 bflow->fdt_size);
440 printf("FDT addr: %lx\n", bflow->fdt_addr);
441 }
Simon Glass7617f492022-04-24 23:31:11 -0600442 printf("Error: %d\n", bflow->err);
443 if (dump && bflow->buf) {
444 /* Set some sort of maximum on the size */
445 int size = min(bflow->size, 10 << 10);
446 int i;
447
448 printf("Contents:\n\n");
449 for (i = 0; i < size; i++) {
450 putc(bflow->buf[i]);
451 if (!(i % 128) && ctrlc()) {
452 printf("...interrupted\n");
453 break;
454 }
455 }
456 }
457
458 return 0;
459}
460
Simon Glass6d8f95b2023-08-10 19:33:18 -0600461static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
462 char *const argv[])
463{
464 struct bootstd_priv *std;
465 struct bootflow *bflow;
466 int ret;
467
468 ret = bootstd_get_priv(&std);
469 if (ret)
470 return CMD_RET_FAILURE;
471
472 /*
473 * Require a current bootflow. Users can use 'bootflow scan -b' to
474 * automatically scan and boot, if needed.
475 */
476 if (!std->cur_bootflow) {
477 printf("No bootflow selected\n");
478 return CMD_RET_FAILURE;
479 }
480 bflow = std->cur_bootflow;
481 ret = bootflow_read_all(bflow);
482 if (ret) {
483 printf("Failed: err=%dE\n", ret);
484 return CMD_RET_FAILURE;
485 }
486
487 return 0;
488}
489
Simon Glass7617f492022-04-24 23:31:11 -0600490static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
491 char *const argv[])
492{
493 struct bootstd_priv *std;
494 struct bootflow *bflow;
495 int ret;
496
497 ret = bootstd_get_priv(&std);
498 if (ret)
499 return CMD_RET_FAILURE;
500
501 /*
502 * Require a current bootflow. Users can use 'bootflow scan -b' to
503 * automatically scan and boot, if needed.
504 */
505 if (!std->cur_bootflow) {
506 printf("No bootflow selected\n");
507 return CMD_RET_FAILURE;
508 }
509 bflow = std->cur_bootflow;
510 ret = bootflow_run_boot(NULL, bflow);
511 if (ret)
512 return CMD_RET_FAILURE;
513
514 return 0;
515}
Simon Glass0a2f6a32023-01-06 08:52:40 -0600516
517static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
518 char *const argv[])
519{
520 struct bootstd_priv *std;
521 struct bootflow *bflow;
522 bool text_mode = false;
523 int ret;
524
Tom Rinif2d51362023-04-06 10:03:33 -0400525 if (!IS_ENABLED(CONFIG_EXPO)) {
526 printf("Menu not supported\n");
527 return CMD_RET_FAILURE;
528 }
529
Simon Glass0a2f6a32023-01-06 08:52:40 -0600530 if (argc > 1 && *argv[1] == '-')
531 text_mode = strchr(argv[1], 't');
532
533 ret = bootstd_get_priv(&std);
534 if (ret)
535 return CMD_RET_FAILURE;
536
Simon Glass6d5083b2023-10-01 19:14:38 -0600537 ret = bootflow_handle_menu(std, text_mode, &bflow);
538 if (ret)
539 return CMD_RET_FAILURE;
Simon Glass0a2f6a32023-01-06 08:52:40 -0600540
541 return 0;
542}
Simon Glass55a2da32023-07-12 09:04:39 -0600543
544static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
545 char *const argv[])
546{
547 struct bootstd_priv *std;
548 struct bootflow *bflow;
549 const char *op, *arg, *val = NULL;
550 int ret;
551
552 if (argc < 3)
553 return CMD_RET_USAGE;
554
555 ret = bootstd_get_priv(&std);
556 if (ret)
557 return CMD_RET_FAILURE;
558
559 bflow = std->cur_bootflow;
560 if (!bflow) {
561 printf("No bootflow selected\n");
562 return CMD_RET_FAILURE;
563 }
564
565 op = argv[1];
566 arg = argv[2];
567 if (*op == 's') {
Simon Glass7a164f82023-11-29 10:31:19 -0700568 val = argv[3] ?: (const char *)BOOTFLOWCL_EMPTY;
Simon Glass55a2da32023-07-12 09:04:39 -0600569 }
570
571 switch (*op) {
572 case 'c': /* clear */
573 val = "";
574 fallthrough;
575 case 's': /* set */
576 case 'd': /* delete */
577 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
578 break;
579 case 'g': /* get */
580 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
581 if (ret >= 0)
582 printf("%.*s\n", ret, val);
583 break;
Simon Glasscd91e992023-07-12 09:04:42 -0600584 case 'a': /* auto */
585 ret = bootflow_cmdline_auto(bflow, arg);
586 break;
Simon Glass55a2da32023-07-12 09:04:39 -0600587 }
588 switch (ret) {
589 case -E2BIG:
590 printf("Argument too long\n");
591 break;
592 case -ENOENT:
593 printf("Argument not found\n");
594 break;
595 case -EINVAL:
596 printf("Mismatched quotes\n");
597 break;
598 case -EBADF:
599 printf("Value must be quoted\n");
600 break;
601 default:
602 if (ret < 0)
603 printf("Unknown error: %dE\n", ret);
604 }
605 if (ret < 0)
606 return CMD_RET_FAILURE;
607
608 return 0;
609}
Simon Glass7617f492022-04-24 23:31:11 -0600610#endif /* CONFIG_CMD_BOOTFLOW_FULL */
611
Tom Rini03f146c2023-10-07 15:13:08 -0400612U_BOOT_LONGHELP(bootflow,
Simon Glass7617f492022-04-24 23:31:11 -0600613#ifdef CONFIG_CMD_BOOTFLOW_FULL
Simon Glass73fcf512022-07-30 15:52:25 -0600614 "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 -0600615 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
616 "bootflow select [<num>|<name>] - select a bootflow\n"
Simon Glass5495aaf2023-07-30 11:17:00 -0600617 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
Simon Glass6d8f95b2023-08-10 19:33:18 -0600618 "bootflow read - read all current-bootflow files\n"
619 "bootflow boot - boot current bootflow\n"
Simon Glass55a2da32023-07-12 09:04:39 -0600620 "bootflow menu [-t] - show a menu of available bootflows\n"
Tom Rini03f146c2023-10-07 15:13:08 -0400621 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
Simon Glass7617f492022-04-24 23:31:11 -0600622#else
Tom Rini03f146c2023-10-07 15:13:08 -0400623 "scan - boot first available bootflow\n"
Simon Glass7617f492022-04-24 23:31:11 -0600624#endif
Tom Rini03f146c2023-10-07 15:13:08 -0400625 );
Simon Glass7617f492022-04-24 23:31:11 -0600626
627U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
628 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
629#ifdef CONFIG_CMD_BOOTFLOW_FULL
630 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
631 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
632 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
Simon Glass6d8f95b2023-08-10 19:33:18 -0600633 U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
Simon Glass0a2f6a32023-01-06 08:52:40 -0600634 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
635 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
Simon Glass55a2da32023-07-12 09:04:39 -0600636 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
Simon Glass7617f492022-04-24 23:31:11 -0600637#endif
638);