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.aka...@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

_______________________________________________
U-Boot mailing list
U-Boot@lists.denx.de
https://lists.denx.de/listinfo/u-boot

Reply via email to