[RFC PATCH] env: Export environment config to OS devicetree

Frieder Schrempf frieder at fris.de
Tue Aug 1 16:46:05 CEST 2023


From: Frieder Schrempf <frieder.schrempf at kontron.de>

There are plenty of cases where the OS wants to know where the
persistent environment is stored in order to print or manipulate it.

In most cases a userspace tool like libubootenv [1] is used to handle
the environment. It uses hardcoded settings in a config file in the
rootfs to determine the exact location of the environment.

In order to make systems more flexible and let userspace tools
detect the location of the environment currently in use, let's
add an option to export the runtime configuration to the FDT passed
to the OS.

This is especially useful when your device is able to use multiple
locations for the environment and the rootfs containing the
fw_env.config file should be kept universal.

Currently the general information like location/type, size, offset
and redundancy are exported. Userspace tools might already be able
to guess the correct device to access based on this information.

For further device-specific information two additional properties
'id1' and 'id2' are used. The current implementation uses them for
MMC and SPI FLASH like this:

| Type       | id1                        | id2                        |
| ---------- | -------------------------- | -------------------------- |
| MMC        | MMC device index in U-Boot | MMC hwpart index in U-Boot |
| SPI FLASH  | SPI bus index in U-Boot    | SPI CS index in U-Boot     |

Further extensions for other environment devices are possible.

We add the necessary information to the '/chosen' node. The following
shows two examples:

Redundant environment in MMC:

  /chosen {
    u-boot,env-config {
      location = <5>;              # according to 'enum env_location'
      offset = <0x1E0000>;
      size = <0x100000>;
      sect_size = <0x100000>;
      id1 = <1>;                   # MMC device index
      id2 = <0>;                   # MMC HW partition index
    };
    u-boot,env-redund-config {
      offset = <0x1F0000>;
    };
  };

Redundant environment in SPI NOR:

  /chosen {
    u-boot,env-config {
      location = <10>;             # according to 'enum env_location'
      offset = <0x1E0000>;
      size = <0x100000>;
      sect_size = <0x100000>;
      id1 = <0>;                   # SPI bus
      id2 = <0>;                   # SPI CS
    };
    u-boot,env-redund-config {
      offset = <0x1F0000>;
    };
  };

See [2] for an example parser implementation for libubootenv.

[1] https://github.com/sbabic/libubootenv
[2] https://github.com/fschrempf/libubootenv/commit/726a7ac9b1b1020354ee8fe750f4cad3df01f5e7

Cc: Stefano Babic <sbabic at denx.de>
Cc: Michael Walle <michael at walle.cc>
Signed-off-by: Frieder Schrempf <frieder.schrempf at kontron.de>
---
 boot/Kconfig     |  9 ++++++++
 boot/image-fdt.c |  8 ++++++++
 env/env.c        | 53 ++++++++++++++++++++++++++++++++++++++++++++++++
 include/env.h    |  4 ++++
 4 files changed, 74 insertions(+)

diff --git a/boot/Kconfig b/boot/Kconfig
index e8fb03b801..16a94f9b35 100644
--- a/boot/Kconfig
+++ b/boot/Kconfig
@@ -702,6 +702,15 @@ config OF_BOARD_SETUP
 	  board-specific information in the device tree for use by the OS.
 	  The device tree is then passed to the OS.
 
+config OF_EXPORT_ENV_CONFIG
+	bool "Export environment config to device tree before boot"
+	depends on OF_LIBFDT
+	help
+	  This causes U-Boot to call fdt_environment_config() before booting into
+	  the operating system. This function exports the currently in use
+	  environemnt configuration to the "chosen" node of the fdt. This allows
+	  the OS to determine where the environment is located.
+
 config OF_SYSTEM_SETUP
 	bool "Set up system-specific details in device tree before boot"
 	depends on OF_LIBFDT
diff --git a/boot/image-fdt.c b/boot/image-fdt.c
index f10200f647..c02c8f33ef 100644
--- a/boot/image-fdt.c
+++ b/boot/image-fdt.c
@@ -643,6 +643,14 @@ int image_setup_libfdt(struct bootm_headers *images, void *blob,
 	/* Append PStore configuration */
 	fdt_fixup_pstore(blob);
 #endif
+	if (IS_ENABLED(CONFIG_OF_EXPORT_ENV_CONFIG)) {
+		fdt_ret = fdt_environment_config(blob);
+		if (fdt_ret) {
+			printf("ERROR: environment config fdt fixup failed: %s\n",
+			       fdt_strerror(fdt_ret));
+			goto err;
+		}
+	}
 	if (IS_ENABLED(CONFIG_OF_BOARD_SETUP)) {
 		const char *skip_board_fixup;
 
diff --git a/env/env.c b/env/env.c
index 2aa52c98f8..a640977205 100644
--- a/env/env.c
+++ b/env/env.c
@@ -8,6 +8,7 @@
 #include <env.h>
 #include <env_internal.h>
 #include <log.h>
+#include <mmc.h>
 #include <asm/global_data.h>
 #include <linux/bitops.h>
 #include <linux/bug.h>
@@ -156,6 +157,58 @@ __weak enum env_location env_get_location(enum env_operation op, int prio)
 	return arch_env_get_location(op, prio);
 }
 
+#ifdef CONFIG_OF_EXPORT_ENV_CONFIG
+int fdt_environment_config(void *blob)
+{
+	struct mmc *mmc;
+	u32 location;
+	int chosen_offs, offs;
+	int ret;
+
+	if (CONFIG_IS_ENABLED(ENV_IS_NOWHERE))
+		return 0;
+
+	chosen_offs = fdt_path_offset(blob, "/chosen");
+	if (chosen_offs < 0) {
+		printf("Could not find chosen node.\n");
+		return chosen_offs;
+	}
+
+	offs = fdt_add_subnode(blob, chosen_offs, "u-boot,env-config");
+	if (offs < 0) {
+		printf("Could not create env-config node.\n");
+		return offs;
+	}
+
+	location = env_get_location(0, 0);
+	fdt_setprop_u32(blob, offs, "location", location);
+	fdt_setprop_u32(blob, offs, "offset", CONFIG_ENV_OFFSET);
+	fdt_setprop_u32(blob, offs, "size", CONFIG_ENV_SIZE);
+	fdt_setprop_u32(blob, offs, "sect_size", CONFIG_ENV_SECT_SIZE);
+
+	if (CONFIG_IS_ENABLED(ENV_IS_IN_MMC) && location == ENVL_MMC) {
+		fdt_setprop_u32(blob, offs, "id1", mmc_get_env_dev());
+		mmc = find_mmc_device(mmc_get_env_dev());
+		if (mmc)
+			fdt_setprop_u32(blob, offs, "id2", mmc_get_env_part(mmc));
+	} else if (CONFIG_IS_ENABLED(ENV_IS_IN_SPI_FLASH) && location == ENVL_SPI_FLASH) {
+		fdt_setprop_u32(blob, offs, "id1", CONFIG_ENV_SPI_BUS);
+		fdt_setprop_u32(blob, offs, "id2", CONFIG_ENV_SPI_CS);
+	}
+
+	if (CONFIG_IS_ENABLED(SYS_REDUNDAND_ENVIRONMENT)) {
+		offs = fdt_add_subnode(blob, chosen_offs, "u-boot,env-redund-config");
+		if (offs < 0) {
+			printf("Could not create env-redund-config node.\n");
+			return offs;
+		}
+		fdt_setprop_u32(blob, offs, "offset", CONFIG_ENV_OFFSET_REDUND);
+	}
+
+	return 0;
+}
+#endif
+
 /**
  * env_driver_lookup() - Finds the most suited environment location
  * @op: operations performed on the environment
diff --git a/include/env.h b/include/env.h
index 1480efa59e..f9b45a4925 100644
--- a/include/env.h
+++ b/include/env.h
@@ -377,4 +377,8 @@ void env_import_fdt(void);
 static inline void env_import_fdt(void) {}
 #endif
 
+#ifdef CONFIG_OF_EXPORT_ENV_CONFIG
+int fdt_environment_config(void *blob);
+#endif
+
 #endif
-- 
2.41.0



More information about the U-Boot mailing list