
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@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_ */