]> git.ipfire.org Git - thirdparty/u-boot.git/blame - cmd/bootflow.c
bootstd: Allow display of the x86 setup information
[thirdparty/u-boot.git] / cmd / bootflow.c
CommitLineData
2d653f68
SG
1// 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>
cbb607d2 12#include <bootm.h>
2d653f68
SG
13#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
c8894348 59 printf(", err=%dE\n", err);
2d653f68
SG
60}
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),
eccb25cd
SG
73 bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
74 "(none)", bflow->part, bflow->name, bflow->fname);
2d653f68
SG
75 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
92static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
93 char *const argv[])
94{
95 struct bootstd_priv *std;
96 struct bootflow_iter iter;
91943ff7 97 struct udevice *dev = NULL;
2d653f68 98 struct bootflow bflow;
2b80bc1e 99 bool all = false, boot = false, errors = false, no_global = false;
d73420e4 100 bool list = false, no_hunter = false;
2d653f68 101 int num_valid = 0;
91943ff7 102 const char *label = NULL;
2d653f68
SG
103 bool has_args;
104 int ret, i;
105 int flags;
106
107 ret = bootstd_get_priv(&std);
108 if (ret)
109 return CMD_RET_FAILURE;
2d653f68
SG
110
111 has_args = argc > 1 && *argv[1] == '-';
112 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
113 if (has_args) {
114 all = strchr(argv[1], 'a');
115 boot = strchr(argv[1], 'b');
116 errors = strchr(argv[1], 'e');
2b80bc1e 117 no_global = strchr(argv[1], 'G');
2d653f68 118 list = strchr(argv[1], 'l');
d73420e4 119 no_hunter = strchr(argv[1], 'H');
2d653f68
SG
120 argc--;
121 argv++;
122 }
91943ff7
SG
123 if (argc > 1)
124 label = argv[1];
125 if (!label)
126 dev = std->cur_bootdev;
2d653f68
SG
127 } else {
128 if (has_args) {
d8d40bc3 129 printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
2d653f68
SG
130 return CMD_RET_USAGE;
131 }
132 boot = true;
133 }
134
135 std->cur_bootflow = NULL;
136
137 flags = 0;
138 if (list)
4f806f31 139 flags |= BOOTFLOWIF_SHOW;
2d653f68 140 if (all)
4f806f31 141 flags |= BOOTFLOWIF_ALL;
2b80bc1e 142 if (no_global)
4f806f31 143 flags |= BOOTFLOWIF_SKIP_GLOBAL;
d73420e4 144 if (!no_hunter)
4f806f31 145 flags |= BOOTFLOWIF_HUNT;
2d653f68
SG
146
147 /*
148 * If we have a device, just scan for bootflows attached to that device
149 */
91943ff7
SG
150 if (list) {
151 printf("Scanning for bootflows ");
152 if (dev)
153 printf("in bootdev '%s'\n", dev->name);
154 else if (label)
155 printf("with label '%s'\n", label);
156 else
157 printf("in all bootdevs\n");
158 show_header();
159 }
160 if (dev)
2d653f68 161 bootdev_clear_bootflows(dev);
91943ff7 162 else
2d653f68 163 bootstd_clear_glob();
91943ff7 164 for (i = 0,
4b7cb058 165 ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
91943ff7
SG
166 i < 1000 && ret != -ENODEV;
167 i++, ret = bootflow_scan_next(&iter, &bflow)) {
168 bflow.err = ret;
169 if (!ret)
170 num_valid++;
171 ret = bootdev_add_bootflow(&bflow);
172 if (ret) {
173 printf("Out of memory\n");
174 return CMD_RET_FAILURE;
2d653f68 175 }
91943ff7
SG
176 if (list)
177 show_bootflow(i, &bflow, errors);
178 if (boot && !bflow.err)
179 bootflow_run_boot(&iter, &bflow);
2d653f68
SG
180 }
181 bootflow_iter_uninit(&iter);
182 if (list)
183 show_footer(i, num_valid);
184
f9fb57c6
SG
185 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && !num_valid && !list)
186 printf("No bootflows found; try again with -l\n");
187
2d653f68
SG
188 return 0;
189}
190
191#ifdef CONFIG_CMD_BOOTFLOW_FULL
192static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
193 char *const argv[])
194{
195 struct bootstd_priv *std;
196 struct udevice *dev;
197 struct bootflow *bflow;
198 int num_valid = 0;
199 bool errors = false;
200 int ret, i;
201
202 if (argc > 1 && *argv[1] == '-')
203 errors = strchr(argv[1], 'e');
204
205 ret = bootstd_get_priv(&std);
206 if (ret)
207 return CMD_RET_FAILURE;
208 dev = std->cur_bootdev;
209
210 /* If we have a device, just list bootflows attached to that device */
211 if (dev) {
212 printf("Showing bootflows for bootdev '%s'\n", dev->name);
213 show_header();
214 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
215 !ret;
216 ret = bootdev_next_bootflow(&bflow), i++) {
217 num_valid += bflow->state == BOOTFLOWST_READY;
218 show_bootflow(i, bflow, errors);
219 }
220 } else {
221 printf("Showing all bootflows\n");
222 show_header();
223 for (ret = bootflow_first_glob(&bflow), i = 0;
224 !ret;
225 ret = bootflow_next_glob(&bflow), i++) {
226 num_valid += bflow->state == BOOTFLOWST_READY;
227 show_bootflow(i, bflow, errors);
228 }
229 }
230 show_footer(i, num_valid);
231
232 return 0;
233}
234
235static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
236 char *const argv[])
237{
238 struct bootstd_priv *std;
239 struct bootflow *bflow, *found;
240 struct udevice *dev;
241 const char *name;
242 char *endp;
243 int seq, i;
244 int ret;
245
246 ret = bootstd_get_priv(&std);
247 if (ret)
248 return CMD_RET_FAILURE;
249;
250 if (argc < 2) {
251 std->cur_bootflow = NULL;
252 return 0;
253 }
254 dev = std->cur_bootdev;
255
256 name = argv[1];
257 seq = simple_strtol(name, &endp, 16);
258 found = NULL;
259
260 /*
261 * If we have a bootdev device, only allow selection of bootflows
262 * attached to that device
263 */
264 if (dev) {
265 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
266 !ret;
267 ret = bootdev_next_bootflow(&bflow), i++) {
268 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
269 found = bflow;
270 break;
271 }
272 }
273 } else {
274 for (ret = bootflow_first_glob(&bflow), i = 0;
275 !ret;
276 ret = bootflow_next_glob(&bflow), i++) {
277 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
278 found = bflow;
279 break;
280 }
281 }
282 }
283
284 if (!found) {
285 printf("Cannot find bootflow '%s' ", name);
286 if (dev)
287 printf("in bootdev '%s' ", dev->name);
288 printf("(err=%d)\n", ret);
289 return CMD_RET_FAILURE;
290 }
291 std->cur_bootflow = found;
d42243fe
SG
292 if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
293 if (env_set("bootargs", found->cmdline)) {
294 printf("Cannot set bootargs\n");
295 return CMD_RET_FAILURE;
296 }
297 }
2d653f68
SG
298
299 return 0;
300}
301
302static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
303 char *const argv[])
304{
305 struct bootstd_priv *std;
306 struct bootflow *bflow;
cbb607d2 307 bool x86_setup = false;
2d653f68
SG
308 bool dump = false;
309 int ret;
310
cbb607d2 311 if (argc > 1 && *argv[1] == '-') {
2d653f68 312 dump = strchr(argv[1], 'd');
cbb607d2
SG
313 x86_setup = strchr(argv[1], 's');
314 }
2d653f68
SG
315
316 ret = bootstd_get_priv(&std);
317 if (ret)
318 return CMD_RET_FAILURE;
319
320 if (!std->cur_bootflow) {
321 printf("No bootflow selected\n");
322 return CMD_RET_FAILURE;
323 }
324 bflow = std->cur_bootflow;
325
cbb607d2
SG
326 if (IS_ENABLED(CONFIG_X86) && x86_setup) {
327 zimage_dump(bflow->x86_setup, false);
328
329 return 0;
330 }
331
2d653f68
SG
332 printf("Name: %s\n", bflow->name);
333 printf("Device: %s\n", bflow->dev->name);
334 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
335 printf("Method: %s\n", bflow->method->name);
336 printf("State: %s\n", bootflow_state_get_name(bflow->state));
337 printf("Partition: %d\n", bflow->part);
338 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
339 printf("Filename: %s\n", bflow->fname);
340 printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf));
341 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
2175e76a 342 printf("OS: %s\n", bflow->os_name ? bflow->os_name : "(none)");
f4a91655
SG
343 printf("Cmdline: ");
344 if (bflow->cmdline)
345 puts(bflow->cmdline);
346 else
347 puts("(none)");
348 putc('\n');
43b6fa9c
SG
349 if (bflow->x86_setup)
350 printf("X86 setup: %p\n", bflow->x86_setup);
24d8e1b3
SG
351 printf("Logo: %s\n", bflow->logo ?
352 simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
353 if (bflow->logo) {
354 printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
355 bflow->logo_size);
356 }
7638c851
SG
357 printf("FDT: %s\n", bflow->fdt_fname);
358 if (bflow->fdt_fname) {
359 printf("FDT size: %x (%d bytes)\n", bflow->fdt_size,
360 bflow->fdt_size);
361 printf("FDT addr: %lx\n", bflow->fdt_addr);
362 }
2d653f68
SG
363 printf("Error: %d\n", bflow->err);
364 if (dump && bflow->buf) {
365 /* Set some sort of maximum on the size */
366 int size = min(bflow->size, 10 << 10);
367 int i;
368
369 printf("Contents:\n\n");
370 for (i = 0; i < size; i++) {
371 putc(bflow->buf[i]);
372 if (!(i % 128) && ctrlc()) {
373 printf("...interrupted\n");
374 break;
375 }
376 }
377 }
378
379 return 0;
380}
381
382static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
383 char *const argv[])
384{
385 struct bootstd_priv *std;
386 struct bootflow *bflow;
387 int ret;
388
389 ret = bootstd_get_priv(&std);
390 if (ret)
391 return CMD_RET_FAILURE;
392
393 /*
394 * Require a current bootflow. Users can use 'bootflow scan -b' to
395 * automatically scan and boot, if needed.
396 */
397 if (!std->cur_bootflow) {
398 printf("No bootflow selected\n");
399 return CMD_RET_FAILURE;
400 }
401 bflow = std->cur_bootflow;
402 ret = bootflow_run_boot(NULL, bflow);
403 if (ret)
404 return CMD_RET_FAILURE;
405
406 return 0;
407}
02d929bf
SG
408
409static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
410 char *const argv[])
411{
412 struct bootstd_priv *std;
413 struct bootflow *bflow;
414 bool text_mode = false;
415 int ret;
416
e0dda26c
TR
417 if (!IS_ENABLED(CONFIG_EXPO)) {
418 printf("Menu not supported\n");
419 return CMD_RET_FAILURE;
420 }
421
02d929bf
SG
422 if (argc > 1 && *argv[1] == '-')
423 text_mode = strchr(argv[1], 't');
424
425 ret = bootstd_get_priv(&std);
426 if (ret)
427 return CMD_RET_FAILURE;
428
e0dda26c
TR
429 ret = bootflow_menu_run(std, text_mode, &bflow);
430 if (ret) {
431 if (ret == -EAGAIN)
432 printf("Nothing chosen\n");
433 else {
434 printf("Menu failed (err=%d)\n", ret);
435 return CMD_RET_FAILURE;
0041b1c0 436 }
02d929bf
SG
437 }
438
439 printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
440 std->cur_bootflow = bflow;
441
442 return 0;
443}
82c0938f
SG
444
445static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
446 char *const argv[])
447{
448 struct bootstd_priv *std;
449 struct bootflow *bflow;
450 const char *op, *arg, *val = NULL;
451 int ret;
452
453 if (argc < 3)
454 return CMD_RET_USAGE;
455
456 ret = bootstd_get_priv(&std);
457 if (ret)
458 return CMD_RET_FAILURE;
459
460 bflow = std->cur_bootflow;
461 if (!bflow) {
462 printf("No bootflow selected\n");
463 return CMD_RET_FAILURE;
464 }
465
466 op = argv[1];
467 arg = argv[2];
468 if (*op == 's') {
469 if (argc < 4)
470 return CMD_RET_USAGE;
471 val = argv[3];
472 }
473
474 switch (*op) {
475 case 'c': /* clear */
476 val = "";
477 fallthrough;
478 case 's': /* set */
479 case 'd': /* delete */
480 ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
481 break;
482 case 'g': /* get */
483 ret = bootflow_cmdline_get_arg(bflow, arg, &val);
484 if (ret >= 0)
485 printf("%.*s\n", ret, val);
486 break;
33ebcb46
SG
487 case 'a': /* auto */
488 ret = bootflow_cmdline_auto(bflow, arg);
489 break;
82c0938f
SG
490 }
491 switch (ret) {
492 case -E2BIG:
493 printf("Argument too long\n");
494 break;
495 case -ENOENT:
496 printf("Argument not found\n");
497 break;
498 case -EINVAL:
499 printf("Mismatched quotes\n");
500 break;
501 case -EBADF:
502 printf("Value must be quoted\n");
503 break;
504 default:
505 if (ret < 0)
506 printf("Unknown error: %dE\n", ret);
507 }
508 if (ret < 0)
509 return CMD_RET_FAILURE;
510
511 return 0;
512}
2d653f68
SG
513#endif /* CONFIG_CMD_BOOTFLOW_FULL */
514
515#ifdef CONFIG_SYS_LONGHELP
516static char bootflow_help_text[] =
517#ifdef CONFIG_CMD_BOOTFLOW_FULL
2b80bc1e 518 "scan [-abeGl] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
2d653f68
SG
519 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
520 "bootflow select [<num>|<name>] - select a bootflow\n"
cbb607d2 521 "bootflow info [-ds] - show info on current bootflow (-d dump bootflow)\n"
02d929bf 522 "bootflow boot - boot current bootflow (or first available if none selected)\n"
82c0938f 523 "bootflow menu [-t] - show a menu of available bootflows\n"
33ebcb46 524 "bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline";
2d653f68
SG
525#else
526 "scan - boot first available bootflow\n";
527#endif
528#endif /* CONFIG_SYS_LONGHELP */
529
530U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
531 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
532#ifdef CONFIG_CMD_BOOTFLOW_FULL
533 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
534 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
535 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
02d929bf
SG
536 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
537 U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
82c0938f 538 U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
2d653f68
SG
539#endif
540);