[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