[U-Boot] [RFC, PATCH v4 02/16] env: extend interfaces to import/export U-Boot environment per context

AKASHI Takahiro takahiro.akashi at linaro.org
Wed Jul 17 08:25:11 UTC 2019


The following interfaces are extended to accept an additional argument,
context:
    env_import() -> env_import_ext()
    env_export() -> env_export_ext()
    env_load() -> env_load_ext()
    env_save() -> env_save_ext()

With this patch applied, we will be able to have different U-Boot
environments each of which has its own "context," or dedicated
backing storage.

Currently, there are two contexts defined:
  ENVCTX_UBOOT: the legacy U-Boot environment variables
  ENVCTX_UEFI: UEFI variables which will be utilized in
	       successive commits.

Along with those changes, "env_t" structure is also modified so that
we will be able to load/save environment data of arbitrary size,
instead of fixed size of ENV_SIZE.

Signed-off-by: AKASHI Takahiro <takahiro.akashi at linaro.org>
---
 env/common.c                      | 80 ++++++++++++++++++++++-----
 env/env.c                         | 92 +++++++++++++++++++++++--------
 include/asm-generic/global_data.h |  7 ++-
 include/env_default.h             |  1 +
 include/environment.h             | 85 +++++++++++++++++++++++++---
 5 files changed, 220 insertions(+), 45 deletions(-)

diff --git a/env/common.c b/env/common.c
index bd340fe9d52d..c2a2d9f22feb 100644
--- a/env/common.c
+++ b/env/common.c
@@ -107,34 +107,48 @@ int set_default_vars(int nvars, char * const vars[], int flags)
  * Check if CRC is valid and (if yes) import the environment.
  * Note that "buf" may or may not be aligned.
  */
-int env_import(const char *buf, int check)
+int env_import_ext(const char *buf, enum env_context ctx, int check)
 {
-	env_t *ep = (env_t *)buf;
+	env_hdr_t *ep = (env_hdr_t *)buf;
 
 	if (check) {
 		uint32_t crc;
 
 		memcpy(&crc, &ep->crc, sizeof(crc));
 
-		if (crc32(0, ep->data, ENV_SIZE) != crc) {
-			set_default_env("bad CRC", 0);
+		if (crc32(0, ep->data, ep->data_size) != crc) {
+			if (ctx == ENVCTX_UBOOT)
+				set_default_env("bad CRC", 0);
+
 			return -ENOMSG; /* needed for env_load() */
 		}
 	}
 
-	if (himport_r(&env_htab, (char *)ep->data, ENV_SIZE, '\0', 0, 0,
-			0, NULL)) {
+	if (himport_ext(&env_htab, ctx, (char *)ep->data, ep->data_size,
+			/*
+			 * FIXME:
+			 * H_NOCLEAR is necessary here to handle
+			 * multiple contexts simultaneously.
+			 * This, however, breaks backward compatibility.
+			 */
+			'\0', H_NOCLEAR, 0, 0, NULL)) {
 		gd->flags |= GD_FLG_ENV_READY;
 		return 0;
 	}
 
 	pr_err("Cannot import environment: errno = %d\n", errno);
 
-	set_default_env("import failed", 0);
+	if (ctx == ENVCTX_UBOOT)
+		set_default_env("import failed", 0);
 
 	return -EIO;
 }
 
+int env_import(const char *buf, int check)
+{
+	return env_import_ext(buf, ENVCTX_UBOOT, check);
+}
+
 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
 static unsigned char env_flags;
 
@@ -199,30 +213,68 @@ int env_import_redund(const char *buf1, int buf1_read_fail,
 	env_flags = ep->flags;
 	return env_import((char *)ep, 0);
 }
+
+int env_import_redund_ext(const char *buf1, int buf1_read_fail,
+			  const char *buf2, int buf2_read_fail,
+			  enum env_context ctx)
+{
+	/* TODO */
+	return 0;
+}
 #endif /* CONFIG_SYS_REDUNDAND_ENVIRONMENT */
 
 /* Export the environment and generate CRC for it. */
-int env_export(env_t *env_out)
+int env_export_ext(env_hdr_t **env_out, enum env_context ctx)
 {
-	char *res;
+	unsigned char *data;
+	size_t size;
 	ssize_t	len;
+	env_hdr_t *envp;
 
-	res = (char *)env_out->data;
-	len = hexport_r(&env_htab, '\0', 0, &res, ENV_SIZE, 0, NULL);
+	if (*env_out) {
+		data = (*env_out)->data;
+		size = (*env_out)->data_size;
+	} else {
+		data = NULL;
+		size = 0;
+	}
+	len = hexport_ext(&env_htab, ctx, '\0', 0, (char **)&data, size,
+			  0, NULL);
 	if (len < 0) {
-		pr_err("Cannot export environment: errno = %d\n", errno);
+		pr_err("Cannot export environment: errno = %d\n",
+		       errno);
 		return 1;
 	}
 
-	env_out->crc = crc32(0, env_out->data, ENV_SIZE);
+	if (*env_out) {
+		envp = *env_out;
+	} else {
+		envp = malloc(sizeof(*envp) + len);
+		if (!envp) {
+			pr_err("Out of memory\n");
+			free(data);
+			return 1;
+		}
+		*env_out = envp;
+
+		envp->data_size = len;
+		memcpy(envp->data, data, len);
+		free(data);
+	}
 
+	envp->crc = crc32(0, envp->data, envp->data_size);
 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-	env_out->flags = ++env_flags; /* increase the serial */
+	envp->flags = ++env_flags; /* increase the serial */
 #endif
 
 	return 0;
 }
 
+int env_export(env_t *env_out)
+{
+	return env_export_ext((env_hdr_t **)&env_out, ENVCTX_UBOOT);
+}
+
 void env_relocate(void)
 {
 #if defined(CONFIG_NEEDS_MANUAL_RELOC)
diff --git a/env/env.c b/env/env.c
index 4b417b90a291..e4c9f1d779a0 100644
--- a/env/env.c
+++ b/env/env.c
@@ -85,12 +85,12 @@ static enum env_location env_locations[] = {
 #endif
 };
 
-static bool env_has_inited(enum env_location location)
+static bool env_has_inited(enum env_context ctx, enum env_location location)
 {
-	return gd->env_has_init & BIT(location);
+	return gd->env_has_init[ctx] & BIT(location);
 }
 
-static void env_set_inited(enum env_location location)
+static void env_set_inited(enum env_context ctx, enum env_location location)
 {
 	/*
 	 * We're using a 32-bits bitmask stored in gd (env_has_init)
@@ -99,7 +99,7 @@ static void env_set_inited(enum env_location location)
 	 */
 	BUILD_BUG_ON(ARRAY_SIZE(env_locations) > BITS_PER_LONG);
 
-	gd->env_has_init |= BIT(location);
+	gd->env_has_init[ctx] |= BIT(location);
 }
 
 /**
@@ -120,16 +120,21 @@ static void env_set_inited(enum env_location location)
  * Returns:
  * an enum env_location value on success, a negative error code otherwise
  */
-__weak enum env_location env_get_location(enum env_operation op, int prio)
+__weak enum env_location env_get_location_ext(enum env_context ctx,
+					      enum env_operation op, int prio)
 {
 	if (prio >= ARRAY_SIZE(env_locations))
 		return ENVL_UNKNOWN;
 
-	gd->env_load_prio = prio;
+	gd->env_load_prio[ctx] = prio;
 
 	return env_locations[prio];
 }
 
+__weak enum env_location env_get_location(enum env_operation op, int prio)
+{
+	return env_get_location_ext(ENVCTX_UBOOT, op, prio);
+}
 
 /**
  * env_driver_lookup() - Finds the most suited environment location
@@ -143,11 +148,16 @@ __weak enum env_location env_get_location(enum env_operation op, int prio)
  * Returns:
  * NULL on error, a pointer to a struct env_driver otherwise
  */
-static struct env_driver *env_driver_lookup(enum env_operation op, int prio)
+static struct env_driver *env_driver_lookup(enum env_context ctx,
+					    enum env_operation op, int prio)
 {
-	enum env_location loc = env_get_location(op, prio);
+	enum env_location loc;
 	struct env_driver *drv;
 
+	if (ctx == ENVCTX_UBOOT)
+		loc = env_get_location(op, prio);
+	else
+		loc = env_get_location_ext(ctx, op, prio);
 	if (loc == ENVL_UNKNOWN)
 		return NULL;
 
@@ -174,19 +184,21 @@ int env_get_char(int index)
 		return env_get_char_spec(index);
 }
 
-int env_load(void)
+int env_load_ext(enum env_context ctx)
 {
 	struct env_driver *drv;
 	int best_prio = -1;
 	int prio;
 
-	for (prio = 0; (drv = env_driver_lookup(ENVOP_LOAD, prio)); prio++) {
+	for (prio = 0; (drv = env_driver_lookup(ctx, ENVOP_LOAD, prio));
+	     prio++) {
 		int ret;
 
-		if (!drv->load)
+		if ((ctx == ENVCTX_UBOOT && !drv->load) ||
+		    (ctx != ENVCTX_UBOOT && !drv->load_ext))
 			continue;
 
-		if (!env_has_inited(drv->location))
+		if (!env_has_inited(ctx, drv->location))
 			continue;
 
 		printf("Loading Environment from %s... ", drv->name);
@@ -195,7 +207,10 @@ int env_load(void)
 		 * drv->load() in some underlying API, and it must be exactly
 		 * one message.
 		 */
-		ret = drv->load();
+		if (ctx == ENVCTX_UBOOT)
+			ret = drv->load();
+		else
+			ret = drv->load_ext(ctx);
 		if (!ret) {
 			printf("OK\n");
 			return 0;
@@ -221,27 +236,39 @@ int env_load(void)
 		debug("Selecting environment with bad CRC\n");
 	else
 		best_prio = 0;
-	env_get_location(ENVOP_LOAD, best_prio);
+	if (ctx == ENVCTX_UBOOT)
+		env_get_location(ENVOP_LOAD, best_prio);
+	else
+		env_get_location_ext(ctx, ENVOP_LOAD, best_prio);
 
 	return -ENODEV;
 }
 
-int env_save(void)
+int env_load(void)
+{
+	return env_load_ext(ENVCTX_UBOOT);
+}
+
+int env_save_ext(enum env_context ctx)
 {
 	struct env_driver *drv;
 
-	drv = env_driver_lookup(ENVOP_SAVE, gd->env_load_prio);
+	drv = env_driver_lookup(ctx, ENVOP_SAVE, gd->env_load_prio[ctx]);
 	if (drv) {
 		int ret;
 
-		if (!drv->save)
+		if ((ctx == ENVCTX_UBOOT && !drv->save) ||
+		    (ctx != ENVCTX_UBOOT && !drv->save_ext))
 			return -ENODEV;
 
-		if (!env_has_inited(drv->location))
+		if (!env_has_inited(ctx, drv->location))
 			return -ENODEV;
 
 		printf("Saving Environment to %s... ", drv->name);
-		ret = drv->save();
+		if (ctx == ENVCTX_UBOOT)
+			ret = drv->save();
+		else
+			ret = drv->save_ext(ctx);
 		if (ret)
 			printf("Failed (%d)\n", ret);
 		else
@@ -254,15 +281,36 @@ int env_save(void)
 	return -ENODEV;
 }
 
+int env_save(void)
+{
+	return env_save_ext(ENVCTX_UBOOT);
+}
+
 int env_init(void)
 {
 	struct env_driver *drv;
 	int ret = -ENOENT;
-	int prio;
+	int ctx, prio;
+
+	/* other than ENVCTX_UBOOT */
+	for (ctx = 1;  ctx < ENVCTX_COUNT; ctx++) {
+		for (prio = 0; (drv = env_driver_lookup(ctx, ENVOP_INIT, prio));
+		     prio++) {
+			if (!drv->init_ext || !(ret = drv->init_ext(ctx)))
+				env_set_inited(ctx, drv->location);
+
+			debug("%s: Environment %s(%d) init done (ret=%d)\n",
+			      __func__, drv->name, ctx, ret);
+		}
+	}
 
-	for (prio = 0; (drv = env_driver_lookup(ENVOP_INIT, prio)); prio++) {
+	/* ENVCTX_UBOOT */
+	ret = -ENOENT;
+	for (prio = 0; (drv = env_driver_lookup(ENVCTX_UBOOT, ENVOP_INIT,
+						prio));
+	     prio++) {
 		if (!drv->init || !(ret = drv->init()))
-			env_set_inited(drv->location);
+			env_set_inited(ENVCTX_UBOOT, drv->location);
 
 		debug("%s: Environment %s init done (ret=%d)\n", __func__,
 		      drv->name, ret);
diff --git a/include/asm-generic/global_data.h b/include/asm-generic/global_data.h
index 02a3ed683821..cc2debfd2deb 100644
--- a/include/asm-generic/global_data.h
+++ b/include/asm-generic/global_data.h
@@ -20,6 +20,7 @@
  */
 
 #ifndef __ASSEMBLY__
+#include <environment.h>
 #include <fdtdec.h>
 #include <membuff.h>
 #include <linux/list.h>
@@ -50,8 +51,10 @@ typedef struct global_data {
 #endif
 	unsigned long env_addr;		/* Address  of Environment struct */
 	unsigned long env_valid;	/* Environment valid? enum env_valid */
-	unsigned long env_has_init;	/* Bitmask of boolean of struct env_location offsets */
-	int env_load_prio;		/* Priority of the loaded environment */
+	unsigned long env_has_init[ENVCTX_COUNT_MAX];
+			/* Bitmask of boolean of struct env_location offsets */
+	int env_load_prio[ENVCTX_COUNT_MAX];
+					/* Priority of the loaded environment */
 
 	unsigned long ram_base;		/* Base address of RAM used by U-Boot */
 	unsigned long ram_top;		/* Top address of RAM used by U-Boot */
diff --git a/include/env_default.h b/include/env_default.h
index 86b639d3e283..dcf1523293f5 100644
--- a/include/env_default.h
+++ b/include/env_default.h
@@ -15,6 +15,7 @@ env_t environment __UBOOT_ENV_SECTION__(environment) = {
 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
 	1,		/* Flags: valid */
 #endif
+	ENV_SIZE,
 	{
 #elif defined(DEFAULT_ENV_INSTANCE_STATIC)
 static char default_environment[] = {
diff --git a/include/environment.h b/include/environment.h
index cd966761416e..9fa085a9b728 100644
--- a/include/environment.h
+++ b/include/environment.h
@@ -134,21 +134,31 @@ extern unsigned long nand_env_oob_offset;
 #include "compiler.h"
 
 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-# define ENV_HEADER_SIZE	(sizeof(uint32_t) + 1)
-
 # define ACTIVE_FLAG   1
 # define OBSOLETE_FLAG 0
+
+#define ENVIRONMENT_HEADER \
+	uint32_t	crc;		/* CRC32 over data bytes	*/ \
+	uint32_t	data_size;	/* Environment data size	*/ \
+	unsigned char	flags;		/* active/obsolete flags	*/
 #else
-# define ENV_HEADER_SIZE	(sizeof(uint32_t))
+#define ENVIRONMENT_HEADER \
+	uint32_t	crc;		/* CRC32 over data bytes	*/ \
+	uint32_t	data_size;	/* Environment data size	*/
 #endif
 
+typedef struct environment_hdr {
+	ENVIRONMENT_HEADER
+	unsigned char	data[];		/* Environment data		*/
+} env_hdr_t;
+
+# define ENV_HEADER_SIZE	(sizeof(env_hdr_t))
+
+/* For compatibility */
 #define ENV_SIZE (CONFIG_ENV_SIZE - ENV_HEADER_SIZE)
 
 typedef struct environment_s {
-	uint32_t	crc;		/* CRC32 over data bytes	*/
-#ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
-	unsigned char	flags;		/* active/obsolete flags	*/
-#endif
+	ENVIRONMENT_HEADER
 	unsigned char	data[ENV_SIZE]; /* Environment data		*/
 } env_t;
 
@@ -202,6 +212,11 @@ enum env_operation {
 	ENVOP_SAVE,	/* we want to call the save function */
 };
 
+enum env_context {
+	ENVCTX_UBOOT,
+	ENVCTX_COUNT,
+};
+
 struct env_driver {
 	const char *name;
 	enum env_location location;
@@ -216,6 +231,17 @@ struct env_driver {
 	 */
 	int (*load)(void);
 
+	/**
+	 * load_ext() - Load given environment context from storage
+	 *
+	 * This method is optional. If not provided, no environment will be
+	 * loaded.
+	 *
+	 * @ctx:	context to be loaded
+	 * Return:	0 if OK, -ve on error
+	 */
+	int (*load_ext)(enum env_context ctx);
+
 	/**
 	 * save() - Save the environment to storage
 	 *
@@ -225,6 +251,16 @@ struct env_driver {
 	 */
 	int (*save)(void);
 
+	/**
+	 * save_ext() - Save given environment context to storage
+	 *
+	 * This method is required for 'saveenv' to work.
+	 *
+	 * @ctx:	context to be saved
+	 * Return:	0 if OK, -ve on error
+	 */
+	int (*save_ext)(enum env_context ctx);
+
 	/**
 	 * init() - Set up the initial pre-relocation environment
 	 *
@@ -234,6 +270,17 @@ struct env_driver {
 	 * other -ve on error
 	 */
 	int (*init)(void);
+
+	/**
+	 * init() - Set up the initial pre-relocation environment
+	 *
+	 * This method is optional.
+	 *
+	 * @ctx:	context to be saved
+	 * @return 0 if OK, -ENOENT if no initial environment could be found,
+	 * other -ve on error
+	 */
+	int (*init_ext)(enum env_context ctx);
 };
 
 /* Declare a new environment location driver */
@@ -269,14 +316,19 @@ int set_default_vars(int nvars, char * const vars[], int flags);
 
 /* Import from binary representation into hash table */
 int env_import(const char *buf, int check);
+int env_import_ext(const char *buf, enum env_context ctx, int check);
 
 /* Export from hash table into binary representation */
 int env_export(env_t *env_out);
+int env_export_ext(env_hdr_t **env_out, enum env_context ctx);
 
 #ifdef CONFIG_SYS_REDUNDAND_ENVIRONMENT
 /* Select and import one of two redundant environments */
 int env_import_redund(const char *buf1, int buf1_status,
 		      const char *buf2, int buf2_status);
+int env_import_redund_ext(const char *buf1, int buf1_status,
+			  const char *buf2, int buf2_status,
+			  enum env_context ctx);
 #endif
 
 /**
@@ -296,6 +348,14 @@ int env_get_char(int index);
  */
 int env_load(void);
 
+/**
+ * env_load_ext() - Load given environment context from storage
+ *
+ * @ctx: context to be loaded
+ * @return 0 if OK, -ve on error
+ */
+int env_load_ext(enum env_context ctx);
+
 /**
  * env_save() - Save the environment to storage
  *
@@ -303,6 +363,14 @@ int env_load(void);
  */
 int env_save(void);
 
+/**
+ * env_save_ext() - Save given environment context to storage
+ *
+ * @ctx: context to be saved
+ * @return 0 if OK, -ve on error
+ */
+int env_save_ext(enum env_context ctx);
+
 /**
  * env_fix_drivers() - Updates envdriver as per relocation
  */
@@ -314,4 +382,7 @@ int eth_env_set_enetaddr(const char *name, const uint8_t *enetaddr);
 
 #endif /* DO_DEPS_ONLY */
 
+/* FIXME: ENVCTX_COUNT is protected by DO_DEPS_ONLY */
+#define ENVCTX_COUNT_MAX 2
+
 #endif /* _ENVIRONMENT_H_ */
-- 
2.21.0



More information about the U-Boot mailing list