[U-Boot] [PATCH] env: add ENV_IS_ANYWHERE

Rob Clark robdclark at gmail.com
Mon Jul 31 12:42:01 UTC 2017


Useful for devices which would otherwise have to use ENV_IS_NOWHERE.
Tries to find and load uboot.env from any block device (which may be,
for example, hot-pluggable sd-card, SATA or USB disk, so the exact
location is not known at the time u-boot is compiled).

Signed-off-by: Rob Clark <robdclark at gmail.com>
---
 cmd/bootefi.c         |   5 ++
 cmd/nvedit.c          |   6 +-
 cmd/usb.c             |   4 +-
 common/Kconfig        |  11 ++++
 common/Makefile       |   1 +
 common/board_r.c      |  11 ++++
 common/env_anywhere.c | 156 ++++++++++++++++++++++++++++++++++++++++++++++++++
 include/environment.h |   5 ++
 8 files changed, 196 insertions(+), 3 deletions(-)
 create mode 100644 common/env_anywhere.c

diff --git a/cmd/bootefi.c b/cmd/bootefi.c
index 765383bc95..80611e1412 100644
--- a/cmd/bootefi.c
+++ b/cmd/bootefi.c
@@ -10,6 +10,7 @@
 #include <command.h>
 #include <dm.h>
 #include <efi_loader.h>
+#include <environment.h>
 #include <errno.h>
 #include <libfdt.h>
 #include <libfdt_env.h>
@@ -318,6 +319,10 @@ void efi_set_bootdev(const char *dev, const char *devnr, const char *path)
 		part = parse_partnum(devnr);
 
 		bootefi_device_path = efi_dp_from_part(desc, part);
+
+#ifdef CONFIG_ENV_IS_ANYWHERE
+		env_set_location(desc, part);
+#endif
 	} else {
 #ifdef CONFIG_NET
 		bootefi_device_path = efi_dp_from_eth();
diff --git a/cmd/nvedit.c b/cmd/nvedit.c
index cd17db6409..cab7ed2565 100644
--- a/cmd/nvedit.c
+++ b/cmd/nvedit.c
@@ -53,9 +53,11 @@ DECLARE_GLOBAL_DATA_PTR;
 	!defined(CONFIG_ENV_IS_IN_SPI_FLASH)	&& \
 	!defined(CONFIG_ENV_IS_IN_REMOTE)	&& \
 	!defined(CONFIG_ENV_IS_IN_UBI)		&& \
-	!defined(CONFIG_ENV_IS_NOWHERE)
+	!defined(CONFIG_ENV_IS_NOWHERE)		&& \
+	!defined(CONFIG_ENV_IS_ANYWHERE)
 # error Define one of CONFIG_ENV_IS_IN_{EEPROM|FLASH|DATAFLASH|MMC|FAT|EXT4|\
-NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE
+NAND|NVRAM|ONENAND|SATA|SPI_FLASH|REMOTE|UBI} or CONFIG_ENV_IS_NOWHERE or \
+CONFIG_ENV_IS_ANYWHERE
 #endif
 
 /*
diff --git a/cmd/usb.c b/cmd/usb.c
index 4fa456e318..d3347301ca 100644
--- a/cmd/usb.c
+++ b/cmd/usb.c
@@ -23,7 +23,7 @@
 #include <usb.h>
 
 #ifdef CONFIG_USB_STORAGE
-static int usb_stor_curr_dev = -1; /* current device */
+int usb_stor_curr_dev = -1; /* current device */
 #endif
 #if defined(CONFIG_USB_HOST_ETHER) && !defined(CONFIG_DM_ETH)
 static int __maybe_unused usb_ether_curr_dev = -1; /* current ethernet device */
@@ -567,6 +567,7 @@ static void do_usb_start(void)
 {
 	bootstage_mark_name(BOOTSTAGE_ID_USB_START, "usb_start");
 
+#ifndef CONFIG_ENV_IS_ANYWHERE
 	if (usb_init() < 0)
 		return;
 
@@ -575,6 +576,7 @@ static void do_usb_start(void)
 	/* try to recognize storage devices immediately */
 	usb_stor_curr_dev = usb_stor_scan(1);
 # endif
+#endif
 #ifndef CONFIG_DM_USB
 # ifdef CONFIG_USB_KEYBOARD
 	drv_usb_kbd_init();
diff --git a/common/Kconfig b/common/Kconfig
index 361346b092..e5f8b5ed3f 100644
--- a/common/Kconfig
+++ b/common/Kconfig
@@ -210,6 +210,17 @@ config ENV_IS_NOWHERE
 	  Define this if you don't want to or can't have an environment stored
 	  on a storage medium
 
+config ENV_IS_ANYWHERE
+	bool "Environment is on any partition"
+	depends on BLK
+	help
+	  Define this if you want to store the environment on the first
+	  partition found containing /uboot.env.  Environment will be saved
+	  to same partition it was loaded from.  This is suitable for boards
+	  which may be booting from various removable devices (ie. sd-card,
+	  usb-disk, etc) and you don't know at the time u-boot is built what
+	  the boot media will be.
+
 endchoice
 
 config ENV_OFFSET
diff --git a/common/Makefile b/common/Makefile
index 17a92ea2d7..dd5046b78f 100644
--- a/common/Makefile
+++ b/common/Makefile
@@ -51,6 +51,7 @@ obj-$(CONFIG_ENV_IS_IN_SPI_FLASH) += env_sf.o
 obj-$(CONFIG_ENV_IS_IN_REMOTE) += env_remote.o
 obj-$(CONFIG_ENV_IS_IN_UBI) += env_ubi.o
 obj-$(CONFIG_ENV_IS_NOWHERE) += env_nowhere.o
+obj-$(CONFIG_ENV_IS_ANYWHERE) += env_anywhere.o
 
 obj-$(CONFIG_CMD_BEDBUG) += bedbug.o
 obj-$(CONFIG_$(SPL_)OF_LIBFDT) += fdt_support.o
diff --git a/common/board_r.c b/common/board_r.c
index ecca1edb04..1a47f6cf1f 100644
--- a/common/board_r.c
+++ b/common/board_r.c
@@ -693,6 +693,14 @@ static int run_main_loop(void)
 	return 0;
 }
 
+#ifdef CONFIG_ENV_IS_ANYWHERE
+static int env_relocate_late(void)
+{
+	env_relocate_spec_late();
+	return 0;
+}
+#endif
+
 /*
  * Over time we hope to remove these functions with code fragments and
  * stub funtcions, and instead call the relevant function directly.
@@ -898,6 +906,9 @@ static init_fnc_t init_sequence_r[] = {
 #ifdef CONFIG_PS2KBD
 	initr_kbd,
 #endif
+#ifdef CONFIG_ENV_IS_ANYWHERE
+	env_relocate_late,
+#endif
 	run_main_loop,
 };
 
diff --git a/common/env_anywhere.c b/common/env_anywhere.c
new file mode 100644
index 0000000000..dc2fc9e522
--- /dev/null
+++ b/common/env_anywhere.c
@@ -0,0 +1,156 @@
+/*
+ *  Copyright (c) 2017 Rob Clark
+ *
+ *  SPDX-License-Identifier:     GPL-2.0+
+ */
+
+#include <common.h>
+
+#include <command.h>
+#include <environment.h>
+#include <linux/stddef.h>
+#include <malloc.h>
+#include <memalign.h>
+#include <search.h>
+#include <errno.h>
+#include <part.h>
+#include <blk.h>
+#include <usb.h>
+#include <dm.h>
+#include <fs.h>
+
+#define ENV_FILE "uboot.env"
+
+static char env_name[64] = "ANYWHERE";
+char *env_name_spec = env_name;
+
+extern int usb_stor_curr_dev;
+
+env_t *env_ptr;
+
+static struct blk_desc *env_desc;
+static int env_part;
+
+DECLARE_GLOBAL_DATA_PTR;
+
+int env_init(void)
+{
+	/* use default */
+	gd->env_addr = (ulong)&default_environment[0];
+	gd->env_valid = 1;
+
+	return 0;
+}
+
+#ifdef CONFIG_CMD_SAVEENV
+int saveenv(void)
+{
+	env_t env_new;
+	loff_t size;
+	int err;
+
+	if (!env_desc)
+		return 1;
+
+	err = env_export(&env_new);
+	if (err)
+		return err;
+
+	fs_set_blk_dev2(env_desc, env_part);
+
+	err = fs_write(ENV_FILE, (ulong)&env_new, 0, sizeof(env_t), &size);
+	if (err == -1) {
+		printf("\n** Unable to write \"%s\" to %s **\n",
+		       ENV_FILE, env_name_spec);
+		return 1;
+	}
+
+	puts("done\n");
+	return 0;
+}
+#endif /* CONFIG_CMD_SAVEENV */
+
+static int env_find(void)
+{
+	struct udevice *dev;
+
+#if defined(CONFIG_USB_STORAGE) && defined(CONFIG_DM_USB) && defined(CONFIG_CMD_USB)
+	int err;
+
+	err = usb_init();
+	if (!err)
+		usb_stor_curr_dev = usb_stor_scan(1);
+#endif
+
+	for (uclass_first_device_check(UCLASS_BLK, &dev);
+	     dev;
+	     uclass_next_device_check(&dev)) {
+		struct blk_desc *desc = dev_get_uclass_platdata(dev);
+		disk_partition_t info;
+		int part = 1;
+
+		printf("Scanning disk %s for environment...\n", dev->name);
+
+		/* check all partitions: */
+		while (!part_get_info(desc, part, &info)) {
+			fs_set_blk_dev2(desc, part);
+
+			if (fs_exists(ENV_FILE)) {
+				printf("Found %s on %s:%d\n", ENV_FILE,
+				       dev->name, part);
+
+				snprintf(env_name, sizeof(env_name), "%s:%d",
+					 dev->name, part);
+
+				env_desc = desc;
+				env_part = part;
+
+				return 0;
+			}
+
+			part++;
+		}
+	}
+
+	return 1;
+}
+
+void env_set_location(struct blk_desc *desc, int part)
+{
+	/* if we already have an environment location, keep it: */
+	if (env_desc)
+		return;
+
+	env_desc = desc;
+	env_part = part;
+}
+
+void env_relocate_spec(void)
+{
+	set_default_env(NULL);
+}
+
+void env_relocate_spec_late(void)
+{
+	ALLOC_CACHE_ALIGN_BUFFER(char, buf, CONFIG_ENV_SIZE);
+	loff_t size;
+	int err;
+
+	if (env_find())
+		goto err_env_relocate;
+
+	fs_set_blk_dev2(env_desc, env_part);
+
+	err = fs_read(ENV_FILE, (ulong)buf, 0, CONFIG_ENV_SIZE, &size);
+	if (err == -1) {
+		printf("\n** Unable to read \"%s\" from %s **\n",
+		       ENV_FILE, env_name_spec);
+		goto err_env_relocate;
+	}
+
+	env_import(buf, 1);
+	return;
+
+err_env_relocate:
+	set_default_env("!could not find environment");
+}
diff --git a/include/environment.h b/include/environment.h
index 6f94986c6b..57f03fe9ad 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -177,6 +177,11 @@ extern env_t *env_ptr;
 extern void env_relocate_spec(void);
 extern unsigned char env_get_char_spec(int);
 
+#ifdef CONFIG_ENV_IS_ANYWHERE
+void env_relocate_spec_late(void);
+void env_set_location(struct blk_desc *desc, int part);
+#endif
+
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
 extern void env_reloc(void);
 #endif
-- 
2.13.0



More information about the U-Boot mailing list