mirror of
				https://github.com/smaeul/u-boot.git
				synced 2025-10-31 20:18:18 +00:00 
			
		
		
		
	When the buffer address is not set, say so, rather than showing an address which looks very strange, on sandbox. Signed-off-by: Simon Glass <sjg@chromium.org>
		
			
				
	
	
		
			621 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			621 lines
		
	
	
		
			15 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
| // SPDX-License-Identifier: GPL-2.0+
 | |
| /*
 | |
|  * 'bootflow' command
 | |
|  *
 | |
|  * Copyright 2021 Google LLC
 | |
|  * Written by Simon Glass <sjg@chromium.org>
 | |
|  */
 | |
| 
 | |
| #include <bootdev.h>
 | |
| #include <bootflow.h>
 | |
| #include <bootm.h>
 | |
| #include <bootstd.h>
 | |
| #include <command.h>
 | |
| #include <console.h>
 | |
| #include <dm.h>
 | |
| #include <mapmem.h>
 | |
| 
 | |
| /**
 | |
|  * report_bootflow_err() - Report where a bootflow failed
 | |
|  *
 | |
|  * When a bootflow does not make it to the 'loaded' state, something went wrong.
 | |
|  * Print a helpful message if there is an error
 | |
|  *
 | |
|  * @bflow: Bootflow to process
 | |
|  * @err: Error code (0 if none)
 | |
|  */
 | |
| static void report_bootflow_err(struct bootflow *bflow, int err)
 | |
| {
 | |
| 	if (!err)
 | |
| 		return;
 | |
| 
 | |
| 	/* Indent out to 'Method' */
 | |
| 	printf("     ** ");
 | |
| 
 | |
| 	switch (bflow->state) {
 | |
| 	case BOOTFLOWST_BASE:
 | |
| 		printf("No media/partition found");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_MEDIA:
 | |
| 		printf("No partition found");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_PART:
 | |
| 		printf("No filesystem found");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_FS:
 | |
| 		printf("File not found");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_FILE:
 | |
| 		printf("File cannot be loaded");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_READY:
 | |
| 		printf("Ready");
 | |
| 		break;
 | |
| 	case BOOTFLOWST_COUNT:
 | |
| 		break;
 | |
| 	}
 | |
| 
 | |
| 	printf(", err=%dE\n", err);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * show_bootflow() - Show the status of a bootflow
 | |
|  *
 | |
|  * @seq: Bootflow index
 | |
|  * @bflow: Bootflow to show
 | |
|  * @errors: True to show the error received, if any
 | |
|  */
 | |
| static void show_bootflow(int index, struct bootflow *bflow, bool errors)
 | |
| {
 | |
| 	printf("%3x  %-11s  %-6s  %-9.9s %4x  %-25.25s %s\n", index,
 | |
| 	       bflow->method->name, bootflow_state_get_name(bflow->state),
 | |
| 	       bflow->dev ? dev_get_uclass_name(dev_get_parent(bflow->dev)) :
 | |
| 	       "(none)", bflow->part, bflow->name, bflow->fname ?: "");
 | |
| 	if (errors)
 | |
| 		report_bootflow_err(bflow, bflow->err);
 | |
| }
 | |
| 
 | |
| static void show_header(void)
 | |
| {
 | |
| 	printf("Seq  Method       State   Uclass    Part  Name                      Filename\n");
 | |
| 	printf("---  -----------  ------  --------  ----  ------------------------  ----------------\n");
 | |
| }
 | |
| 
 | |
| static void show_footer(int count, int num_valid)
 | |
| {
 | |
| 	printf("---  -----------  ------  --------  ----  ------------------------  ----------------\n");
 | |
| 	printf("(%d bootflow%s, %d valid)\n", count, count != 1 ? "s" : "",
 | |
| 	       num_valid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * bootflow_handle_menu() - Handle running the menu and updating cur bootflow
 | |
|  *
 | |
|  * This shows the menu, allows the user to select something and then prints
 | |
|  * what happened
 | |
|  *
 | |
|  * @std: bootstd information
 | |
|  * @text_mode: true to run the menu in text mode
 | |
|  * @bflowp: Returns selected bootflow, on success
 | |
|  * Return: 0 on success (a bootflow was selected), -EAGAIN if nothing was
 | |
|  *	chosen, other -ve value on other error
 | |
|  */
 | |
| __maybe_unused static int bootflow_handle_menu(struct bootstd_priv *std,
 | |
| 					       bool text_mode,
 | |
| 					       struct bootflow **bflowp)
 | |
| {
 | |
| 	struct bootflow *bflow;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = bootflow_menu_run(std, text_mode, &bflow);
 | |
| 	if (ret) {
 | |
| 		if (ret == -EAGAIN) {
 | |
| 			printf("Nothing chosen\n");
 | |
| 			std->cur_bootflow = NULL;
 | |
| 		} else {
 | |
| 			printf("Menu failed (err=%d)\n", ret);
 | |
| 		}
 | |
| 
 | |
| 		return ret;
 | |
| 	}
 | |
| 
 | |
| 	printf("Selected: %s\n", bflow->os_name ? bflow->os_name : bflow->name);
 | |
| 	std->cur_bootflow = bflow;
 | |
| 	*bflowp = bflow;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_scan(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow_iter iter;
 | |
| 	struct udevice *dev = NULL;
 | |
| 	struct bootflow bflow;
 | |
| 	bool all = false, boot = false, errors = false, no_global = false;
 | |
| 	bool list = false, no_hunter = false, menu = false, text_mode = false;
 | |
| 	int num_valid = 0;
 | |
| 	const char *label = NULL;
 | |
| 	bool has_args;
 | |
| 	int ret, i;
 | |
| 	int flags;
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	has_args = argc > 1 && *argv[1] == '-';
 | |
| 	if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL)) {
 | |
| 		if (has_args) {
 | |
| 			all = strchr(argv[1], 'a');
 | |
| 			boot = strchr(argv[1], 'b');
 | |
| 			errors = strchr(argv[1], 'e');
 | |
| 			no_global = strchr(argv[1], 'G');
 | |
| 			list = strchr(argv[1], 'l');
 | |
| 			no_hunter = strchr(argv[1], 'H');
 | |
| 			menu = strchr(argv[1], 'm');
 | |
| 			text_mode = strchr(argv[1], 't');
 | |
| 			argc--;
 | |
| 			argv++;
 | |
| 		}
 | |
| 		if (argc > 1)
 | |
| 			label = argv[1];
 | |
| 		if (!label)
 | |
| 			dev = std->cur_bootdev;
 | |
| 	} else {
 | |
| 		if (has_args) {
 | |
| 			printf("Flags not supported: enable CONFIG_BOOTSTD_FULL\n");
 | |
| 			return CMD_RET_USAGE;
 | |
| 		}
 | |
| 		boot = true;
 | |
| 	}
 | |
| 
 | |
| 	std->cur_bootflow = NULL;
 | |
| 
 | |
| 	flags = 0;
 | |
| 	if (list)
 | |
| 		flags |= BOOTFLOWIF_SHOW;
 | |
| 	if (all)
 | |
| 		flags |= BOOTFLOWIF_ALL;
 | |
| 	if (no_global)
 | |
| 		flags |= BOOTFLOWIF_SKIP_GLOBAL;
 | |
| 	if (!no_hunter)
 | |
| 		flags |= BOOTFLOWIF_HUNT;
 | |
| 
 | |
| 	/*
 | |
| 	 * If we have a device, just scan for bootflows attached to that device
 | |
| 	 */
 | |
| 	if (list) {
 | |
| 		printf("Scanning for bootflows ");
 | |
| 		if (dev)
 | |
| 			printf("in bootdev '%s'\n", dev->name);
 | |
| 		else if (label)
 | |
| 			printf("with label '%s'\n", label);
 | |
| 		else
 | |
| 			printf("in all bootdevs\n");
 | |
| 		show_header();
 | |
| 	}
 | |
| 	if (dev)
 | |
| 		bootdev_clear_bootflows(dev);
 | |
| 	else
 | |
| 		bootstd_clear_glob();
 | |
| 	for (i = 0,
 | |
| 	     ret = bootflow_scan_first(dev, label, &iter, flags, &bflow);
 | |
| 	     i < 1000 && ret != -ENODEV;
 | |
| 	     i++, ret = bootflow_scan_next(&iter, &bflow)) {
 | |
| 		bflow.err = ret;
 | |
| 		if (!ret)
 | |
| 			num_valid++;
 | |
| 		ret = bootdev_add_bootflow(&bflow);
 | |
| 		if (ret) {
 | |
| 			printf("Out of memory\n");
 | |
| 			return CMD_RET_FAILURE;
 | |
| 		}
 | |
| 		if (list)
 | |
| 			show_bootflow(i, &bflow, errors);
 | |
| 		if (!menu && boot && !bflow.err)
 | |
| 			bootflow_run_boot(&iter, &bflow);
 | |
| 	}
 | |
| 	bootflow_iter_uninit(&iter);
 | |
| 	if (list)
 | |
| 		show_footer(i, num_valid);
 | |
| 
 | |
| 	if (IS_ENABLED(CONFIG_CMD_BOOTFLOW_FULL) && IS_ENABLED(CONFIG_EXPO)) {
 | |
| 		if (!num_valid && !list) {
 | |
| 			printf("No bootflows found; try again with -l\n");
 | |
| 		} else if (menu) {
 | |
| 			struct bootflow *sel_bflow;
 | |
| 
 | |
| 			ret = bootflow_handle_menu(std, text_mode, &sel_bflow);
 | |
| 			if (!ret && boot) {
 | |
| 				ret = console_clear();
 | |
| 				if (ret) {
 | |
| 					log_err("Failed to clear console: %dE\n",
 | |
| 						ret);
 | |
| 					return ret;
 | |
| 				}
 | |
| 
 | |
| 				bootflow_run_boot(NULL, sel_bflow);
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| #ifdef CONFIG_CMD_BOOTFLOW_FULL
 | |
| static int do_bootflow_list(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct udevice *dev;
 | |
| 	struct bootflow *bflow;
 | |
| 	int num_valid = 0;
 | |
| 	bool errors = false;
 | |
| 	int ret, i;
 | |
| 
 | |
| 	if (argc > 1 && *argv[1] == '-')
 | |
| 		errors = strchr(argv[1], 'e');
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	dev = std->cur_bootdev;
 | |
| 
 | |
| 	/* If we have a device, just list bootflows attached to that device */
 | |
| 	if (dev) {
 | |
| 		printf("Showing bootflows for bootdev '%s'\n", dev->name);
 | |
| 		show_header();
 | |
| 		for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
 | |
| 		     !ret;
 | |
| 		     ret = bootdev_next_bootflow(&bflow), i++) {
 | |
| 			num_valid += bflow->state == BOOTFLOWST_READY;
 | |
| 			show_bootflow(i, bflow, errors);
 | |
| 		}
 | |
| 	} else {
 | |
| 		printf("Showing all bootflows\n");
 | |
| 		show_header();
 | |
| 		for (ret = bootflow_first_glob(&bflow), i = 0;
 | |
| 		     !ret;
 | |
| 		     ret = bootflow_next_glob(&bflow), i++) {
 | |
| 			num_valid += bflow->state == BOOTFLOWST_READY;
 | |
| 			show_bootflow(i, bflow, errors);
 | |
| 		}
 | |
| 	}
 | |
| 	show_footer(i, num_valid);
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_select(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			      char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow, *found;
 | |
| 	struct udevice *dev;
 | |
| 	const char *name;
 | |
| 	char *endp;
 | |
| 	int seq, i;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| ;
 | |
| 	if (argc < 2) {
 | |
| 		std->cur_bootflow = NULL;
 | |
| 		return 0;
 | |
| 	}
 | |
| 	dev = std->cur_bootdev;
 | |
| 
 | |
| 	name = argv[1];
 | |
| 	seq = simple_strtol(name, &endp, 16);
 | |
| 	found = NULL;
 | |
| 
 | |
| 	/*
 | |
| 	 * If we have a bootdev device, only allow selection of bootflows
 | |
| 	 * attached to that device
 | |
| 	 */
 | |
| 	if (dev) {
 | |
| 		for (ret = bootdev_first_bootflow(dev, &bflow), i = 0;
 | |
| 		     !ret;
 | |
| 		     ret = bootdev_next_bootflow(&bflow), i++) {
 | |
| 			if (*endp ? !strcmp(bflow->name, name) : i == seq) {
 | |
| 				found = bflow;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	} else {
 | |
| 		for (ret = bootflow_first_glob(&bflow), i = 0;
 | |
| 		     !ret;
 | |
| 		     ret = bootflow_next_glob(&bflow), i++) {
 | |
| 			if (*endp ? !strcmp(bflow->name, name) : i == seq) {
 | |
| 				found = bflow;
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	if (!found) {
 | |
| 		printf("Cannot find bootflow '%s' ", name);
 | |
| 		if (dev)
 | |
| 			printf("in bootdev '%s' ", dev->name);
 | |
| 		printf("(err=%d)\n", ret);
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 	std->cur_bootflow = found;
 | |
| 	if (IS_ENABLED(CONFIG_BOOTSTD_FULL)) {
 | |
| 		if (env_set("bootargs", found->cmdline)) {
 | |
| 			printf("Cannot set bootargs\n");
 | |
| 			return CMD_RET_FAILURE;
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_info(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow;
 | |
| 	bool x86_setup = false;
 | |
| 	bool dump = false;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (argc > 1 && *argv[1] == '-') {
 | |
| 		dump = strchr(argv[1], 'd');
 | |
| 		x86_setup = strchr(argv[1], 's');
 | |
| 	}
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	if (!std->cur_bootflow) {
 | |
| 		printf("No bootflow selected\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 	bflow = std->cur_bootflow;
 | |
| 
 | |
| 	if (IS_ENABLED(CONFIG_X86) && x86_setup) {
 | |
| 		zimage_dump(bflow->x86_setup, false);
 | |
| 
 | |
| 		return 0;
 | |
| 	}
 | |
| 
 | |
| 	printf("Name:      %s\n", bflow->name);
 | |
| 	printf("Device:    %s\n", bflow->dev->name);
 | |
| 	printf("Block dev: %s\n", bflow->blk ? bflow->blk->name : "(none)");
 | |
| 	printf("Method:    %s\n", bflow->method->name);
 | |
| 	printf("State:     %s\n", bootflow_state_get_name(bflow->state));
 | |
| 	printf("Partition: %d\n", bflow->part);
 | |
| 	printf("Subdir:    %s\n", bflow->subdir ? bflow->subdir : "(none)");
 | |
| 	printf("Filename:  %s\n", bflow->fname);
 | |
| 	printf("Buffer:    ");
 | |
| 	if (bflow->buf)
 | |
| 		printf("%lx\n", (ulong)map_to_sysmem(bflow->buf));
 | |
| 	else
 | |
| 		printf("(not loaded)\n");
 | |
| 	printf("Size:      %x (%d bytes)\n", bflow->size, bflow->size);
 | |
| 	printf("OS:        %s\n", bflow->os_name ? bflow->os_name : "(none)");
 | |
| 	printf("Cmdline:   ");
 | |
| 	if (bflow->cmdline)
 | |
| 		puts(bflow->cmdline);
 | |
| 	else
 | |
| 		puts("(none)");
 | |
| 	putc('\n');
 | |
| 	if (bflow->x86_setup)
 | |
| 		printf("X86 setup: %lx\n",
 | |
| 		       (ulong)map_to_sysmem(bflow->x86_setup));
 | |
| 	printf("Logo:      %s\n", bflow->logo ?
 | |
| 	       simple_xtoa((ulong)map_to_sysmem(bflow->logo)) : "(none)");
 | |
| 	if (bflow->logo) {
 | |
| 		printf("Logo size: %x (%d bytes)\n", bflow->logo_size,
 | |
| 		       bflow->logo_size);
 | |
| 	}
 | |
| 	printf("FDT:       %s\n", bflow->fdt_fname);
 | |
| 	if (bflow->fdt_fname) {
 | |
| 		printf("FDT size:  %x (%d bytes)\n", bflow->fdt_size,
 | |
| 		       bflow->fdt_size);
 | |
| 		printf("FDT addr:  %lx\n", bflow->fdt_addr);
 | |
| 	}
 | |
| 	printf("Error:     %d\n", bflow->err);
 | |
| 	if (dump && bflow->buf) {
 | |
| 		/* Set some sort of maximum on the size */
 | |
| 		int size = min(bflow->size, 10 << 10);
 | |
| 		int i;
 | |
| 
 | |
| 		printf("Contents:\n\n");
 | |
| 		for (i = 0; i < size; i++) {
 | |
| 			putc(bflow->buf[i]);
 | |
| 			if (!(i % 128) && ctrlc()) {
 | |
| 				printf("...interrupted\n");
 | |
| 				break;
 | |
| 			}
 | |
| 		}
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_read(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	/*
 | |
| 	 * Require a current bootflow. Users can use 'bootflow scan -b' to
 | |
| 	 * automatically scan and boot, if needed.
 | |
| 	 */
 | |
| 	if (!std->cur_bootflow) {
 | |
| 		printf("No bootflow selected\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 	bflow = std->cur_bootflow;
 | |
| 	ret = bootflow_read_all(bflow);
 | |
| 	if (ret) {
 | |
| 		printf("Failed: err=%dE\n", ret);
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_boot(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow;
 | |
| 	int ret;
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	/*
 | |
| 	 * Require a current bootflow. Users can use 'bootflow scan -b' to
 | |
| 	 * automatically scan and boot, if needed.
 | |
| 	 */
 | |
| 	if (!std->cur_bootflow) {
 | |
| 		printf("No bootflow selected\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 	bflow = std->cur_bootflow;
 | |
| 	ret = bootflow_run_boot(NULL, bflow);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_menu(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			    char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow;
 | |
| 	bool text_mode = false;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (!IS_ENABLED(CONFIG_EXPO)) {
 | |
| 		printf("Menu not supported\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	if (argc > 1 && *argv[1] == '-')
 | |
| 		text_mode = strchr(argv[1], 't');
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	ret = bootflow_handle_menu(std, text_mode, &bflow);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| 
 | |
| static int do_bootflow_cmdline(struct cmd_tbl *cmdtp, int flag, int argc,
 | |
| 			       char *const argv[])
 | |
| {
 | |
| 	struct bootstd_priv *std;
 | |
| 	struct bootflow *bflow;
 | |
| 	const char *op, *arg, *val = NULL;
 | |
| 	int ret;
 | |
| 
 | |
| 	if (argc < 3)
 | |
| 		return CMD_RET_USAGE;
 | |
| 
 | |
| 	ret = bootstd_get_priv(&std);
 | |
| 	if (ret)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	bflow = std->cur_bootflow;
 | |
| 	if (!bflow) {
 | |
| 		printf("No bootflow selected\n");
 | |
| 		return CMD_RET_FAILURE;
 | |
| 	}
 | |
| 
 | |
| 	op = argv[1];
 | |
| 	arg = argv[2];
 | |
| 	if (*op == 's') {
 | |
| 		val = argv[3] ?: (const char *)BOOTFLOWCL_EMPTY;
 | |
| 	}
 | |
| 
 | |
| 	switch (*op) {
 | |
| 	case 'c':	/* clear */
 | |
| 		val = "";
 | |
| 		fallthrough;
 | |
| 	case 's':	/* set */
 | |
| 	case 'd':	/* delete */
 | |
| 		ret = bootflow_cmdline_set_arg(bflow, arg, val, true);
 | |
| 		break;
 | |
| 	case 'g':	/* get */
 | |
| 		ret = bootflow_cmdline_get_arg(bflow, arg, &val);
 | |
| 		if (ret >= 0)
 | |
| 			printf("%.*s\n", ret, val);
 | |
| 		break;
 | |
| 	case 'a':	/* auto */
 | |
| 		ret = bootflow_cmdline_auto(bflow, arg);
 | |
| 		break;
 | |
| 	}
 | |
| 	switch (ret) {
 | |
| 	case -E2BIG:
 | |
| 		printf("Argument too long\n");
 | |
| 		break;
 | |
| 	case -ENOENT:
 | |
| 		printf("Argument not found\n");
 | |
| 		break;
 | |
| 	case -EINVAL:
 | |
| 		printf("Mismatched quotes\n");
 | |
| 		break;
 | |
| 	case -EBADF:
 | |
| 		printf("Value must be quoted\n");
 | |
| 		break;
 | |
| 	default:
 | |
| 		if (ret < 0)
 | |
| 			printf("Unknown error: %dE\n", ret);
 | |
| 	}
 | |
| 	if (ret < 0)
 | |
| 		return CMD_RET_FAILURE;
 | |
| 
 | |
| 	return 0;
 | |
| }
 | |
| #endif /* CONFIG_CMD_BOOTFLOW_FULL */
 | |
| 
 | |
| U_BOOT_LONGHELP(bootflow,
 | |
| #ifdef CONFIG_CMD_BOOTFLOW_FULL
 | |
| 	"scan [-abeGl] [bdev]  - scan for valid bootflows (-l list, -a all, -e errors, -b boot, -G no global)\n"
 | |
| 	"bootflow list [-e]             - list scanned bootflows (-e errors)\n"
 | |
| 	"bootflow select [<num>|<name>] - select a bootflow\n"
 | |
| 	"bootflow info [-ds]            - show info on current bootflow (-d dump bootflow)\n"
 | |
| 	"bootflow read                  - read all current-bootflow files\n"
 | |
| 	"bootflow boot                  - boot current bootflow\n"
 | |
| 	"bootflow menu [-t]             - show a menu of available bootflows\n"
 | |
| 	"bootflow cmdline [set|get|clear|delete|auto] <param> [<value>] - update cmdline"
 | |
| #else
 | |
| 	"scan - boot first available bootflow\n"
 | |
| #endif
 | |
| 	);
 | |
| 
 | |
| U_BOOT_CMD_WITH_SUBCMDS(bootflow, "Boot flows", bootflow_help_text,
 | |
| 	U_BOOT_SUBCMD_MKENT(scan, 3, 1, do_bootflow_scan),
 | |
| #ifdef CONFIG_CMD_BOOTFLOW_FULL
 | |
| 	U_BOOT_SUBCMD_MKENT(list, 2, 1, do_bootflow_list),
 | |
| 	U_BOOT_SUBCMD_MKENT(select, 2, 1, do_bootflow_select),
 | |
| 	U_BOOT_SUBCMD_MKENT(info, 2, 1, do_bootflow_info),
 | |
| 	U_BOOT_SUBCMD_MKENT(read, 1, 1, do_bootflow_read),
 | |
| 	U_BOOT_SUBCMD_MKENT(boot, 1, 1, do_bootflow_boot),
 | |
| 	U_BOOT_SUBCMD_MKENT(menu, 2, 1, do_bootflow_menu),
 | |
| 	U_BOOT_SUBCMD_MKENT(cmdline, 4, 1, do_bootflow_cmdline),
 | |
| #endif
 | |
| );
 |