1 // SPDX-License-Identifier: GPL-2.0+
5 * Copyright 2021 Google LLC
6 * Written by Simon Glass <sjg@chromium.org>
19 * report_bootflow_err() - Report where a bootflow failed
21 * When a bootflow does not make it to the 'loaded' state, something went wrong.
22 * Print a helpful message if there is an error
24 * @bflow: Bootflow to process
25 * @err: Error code (0 if none)
27 static void report_bootflow_err(struct bootflow *bflow, int err)
32 /* Indent out to 'Method' */
35 switch (bflow->state) {
37 printf("No media/partition found");
39 case BOOTFLOWST_MEDIA:
40 printf("No partition found");
43 printf("No filesystem found");
46 printf("File not found");
49 printf("File cannot be loaded");
51 case BOOTFLOWST_READY:
54 case BOOTFLOWST_COUNT:
58 printf(", err=%d\n", err);
62 * show_bootflow() - Show the status of a bootflow
64 * @seq: Bootflow index
65 * @bflow: Bootflow to show
66 * @errors: True to show the error received, if any
68 static void show_bootflow(int index, struct bootflow *bflow, bool errors)
70 printf("%3x %-11s %-6s %-9.9s %4x %-25.25s %s\n", index,
71 bflow->method->name, bootflow_state_get_name(bflow->state),
72 dev_get_uclass_name(dev_get_parent(bflow->dev)), bflow->part,
73 bflow->name, bflow->fname);
75 report_bootflow_err(bflow, bflow->err);
78 static void show_header(void)
80 printf("Seq Method State Uclass Part Name Filename\n");
81 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
84 static void show_footer(int count, int num_valid)
86 printf("--- ----------- ------ -------- ---- ------------------------ ----------------\n");
87 printf("(%d bootflow%s, %d valid)\n", count, count != 1 ? "s" : "",
91 static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
94 struct bootstd_priv *std;
95 struct bootflow_iter iter;
97 struct bootflow bflow;
98 bool all = false, boot = false, errors = false, list = false;
104 ret = bootstd_get_priv(&std);
106 return CMD_RET_FAILURE;
107 dev = std->cur_bootdev;
109 has_args = argc > 1 && *argv[1] == '-';
110 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
112 all = strchr(argv[1], 'a');
113 boot = strchr(argv[1], 'b');
114 errors = strchr(argv[1], 'e');
115 list = strchr(argv[1], 'l');
120 const char *label = argv[1];
122 if (bootdev_find_by_any(label, &dev))
123 return CMD_RET_FAILURE;
127 printf("Flags not supported: enable CONFIG_BOOTFLOW_FULL\n");
128 return CMD_RET_USAGE;
133 std->cur_bootflow = NULL;
137 flags |= BOOTFLOWF_SHOW;
139 flags |= BOOTFLOWF_ALL;
142 * If we have a device, just scan for bootflows attached to that device
144 if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && dev) {
146 printf("Scanning for bootflows in bootdev '%s'\n",
150 bootdev_clear_bootflows(dev);
152 ret = bootflow_scan_bootdev(dev, &iter, flags, &bflow);
153 i < 1000 && ret != -ENODEV;
154 i++, ret = bootflow_scan_next(&iter, &bflow)) {
158 ret = bootdev_add_bootflow(&bflow);
160 printf("Out of memory\n");
161 return CMD_RET_FAILURE;
164 show_bootflow(i, &bflow, errors);
165 if (boot && !bflow.err)
166 bootflow_run_boot(&iter, &bflow);
170 printf("Scanning for bootflows in all bootdevs\n");
173 bootstd_clear_glob();
176 ret = bootflow_scan_first(&iter, flags, &bflow);
177 i < 1000 && ret != -ENODEV;
178 i++, ret = bootflow_scan_next(&iter, &bflow)) {
182 ret = bootdev_add_bootflow(&bflow);
184 printf("Out of memory\n");
185 return CMD_RET_FAILURE;
188 show_bootflow(i, &bflow, errors);
189 if (boot && !bflow.err)
190 bootflow_run_boot(&iter, &bflow);
193 bootflow_iter_uninit(&iter);
195 show_footer(i, num_valid);
200 #ifdef CONFIG_CMD_BOOTFLOW_FULL
201 static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
204 struct bootstd_priv *std;
206 struct bootflow *bflow;
211 if (argc > 1 && *argv[1] == '-')
212 errors = strchr(argv[1], 'e');
214 ret = bootstd_get_priv(&std);
216 return CMD_RET_FAILURE;
217 dev = std->cur_bootdev;
219 /* If we have a device, just list bootflows attached to that device */
221 printf("Showing bootflows for bootdev '%s'\n", dev->name);
223 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
225 ret = bootdev_next_bootflow(&bflow), i++) {
226 num_valid += bflow->state == BOOTFLOWST_READY;
227 show_bootflow(i, bflow, errors);
230 printf("Showing all bootflows\n");
232 for (ret = bootflow_first_glob(&bflow), i = 0;
234 ret = bootflow_next_glob(&bflow), i++) {
235 num_valid += bflow->state == BOOTFLOWST_READY;
236 show_bootflow(i, bflow, errors);
239 show_footer(i, num_valid);
244 static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
247 struct bootstd_priv *std;
248 struct bootflow *bflow, *found;
255 ret = bootstd_get_priv(&std);
257 return CMD_RET_FAILURE;
260 std->cur_bootflow = NULL;
263 dev = std->cur_bootdev;
266 seq = simple_strtol(name, &endp, 16);
270 * If we have a bootdev device, only allow selection of bootflows
271 * attached to that device
274 for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
276 ret = bootdev_next_bootflow(&bflow), i++) {
277 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
283 for (ret = bootflow_first_glob(&bflow), i = 0;
285 ret = bootflow_next_glob(&bflow), i++) {
286 if (*endp ? !strcmp(bflow->name, name) : i == seq) {
294 printf("Cannot find bootflow '%s' ", name);
296 printf("in bootdev '%s' ", dev->name);
297 printf("(err=%d)\n", ret);
298 return CMD_RET_FAILURE;
300 std->cur_bootflow = found;
305 static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
308 struct bootstd_priv *std;
309 struct bootflow *bflow;
313 if (argc > 1 && *argv[1] == '-')
314 dump = strchr(argv[1], 'd');
316 ret = bootstd_get_priv(&std);
318 return CMD_RET_FAILURE;
320 if (!std->cur_bootflow) {
321 printf("No bootflow selected\n");
322 return CMD_RET_FAILURE;
324 bflow = std->cur_bootflow;
326 printf("Name: %s\n", bflow->name);
327 printf("Device: %s\n", bflow->dev->name);
328 printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
329 printf("Method: %s\n", bflow->method->name);
330 printf("State: %s\n", bootflow_state_get_name(bflow->state));
331 printf("Partition: %d\n", bflow->part);
332 printf("Subdir: %s\n", bflow->subdir ? bflow->subdir : "(none)");
333 printf("Filename: %s\n", bflow->fname);
334 printf("Buffer: %lx\n", (ulong)map_to_sysmem(bflow->buf));
335 printf("Size: %x (%d bytes)\n", bflow->size, bflow->size);
336 printf("Error: %d\n", bflow->err);
337 if (dump && bflow->buf) {
338 /* Set some sort of maximum on the size */
339 int size = min(bflow->size, 10 << 10);
342 printf("Contents:\n\n");
343 for (i = 0; i < size; i++) {
345 if (!(i % 128) && ctrlc()) {
346 printf("...interrupted\n");
355 static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
358 struct bootstd_priv *std;
359 struct bootflow *bflow;
362 ret = bootstd_get_priv(&std);
364 return CMD_RET_FAILURE;
367 * Require a current bootflow. Users can use 'bootflow scan -b' to
368 * automatically scan and boot, if needed.
370 if (!std->cur_bootflow) {
371 printf("No bootflow selected\n");
372 return CMD_RET_FAILURE;
374 bflow = std->cur_bootflow;
375 ret = bootflow_run_boot(NULL, bflow);
377 return CMD_RET_FAILURE;
381 #endif /* CONFIG_CMD_BOOTFLOW_FULL */
383 #ifdef CONFIG_SYS_LONGHELP
384 static char bootflow_help_text[] =
385 #ifdef CONFIG_CMD_BOOTFLOW_FULL
386 "scan [-abel] [bdev] - scan for valid bootflows (-l list, -a all, -e errors, -b boot)\n"
387 "bootflow list [-e] - list scanned bootflows (-e errors)\n"
388 "bootflow select [<num>|<name>] - select a bootflow\n"
389 "bootflow info [-d] - show info on current bootflow (-d dump bootflow)\n"
390 "bootflow boot - boot current bootflow (or first available if none selected)";
392 "scan - boot first available bootflow\n";
394 #endif /* CONFIG_SYS_LONGHELP */
396 U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
397 U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
398 #ifdef CONFIG_CMD_BOOTFLOW_FULL
399 U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
400 U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
401 U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
402 U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot)