Use a union to cover both with and without redundant environment cases.

Signed-off-by: Guennadi Liakhovetski <[EMAIL PROTECTED]>
---
 tools/env/fw_env.c |  148 +++++++++++++++++++++++++++++-----------------------
 1 files changed, 82 insertions(+), 66 deletions(-)

diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index b8bca91..35783c5 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -63,16 +63,30 @@ static int curdev;
 
 #define ENV_SIZE      getenvsize()
 
-typedef struct environment_s {
-       ulong crc;                      /* CRC32 over data bytes    */
-       unsigned char flags;            /* active or obsolete */
-       char *data;
-} env_t;
+/* This union will occupy exactly CFG_ENV_SIZE bytes. */
+union env_image {
+       struct {
+               uint32_t        crc;    /* CRC32 over data bytes    */
+               char            data[];
+       } single;
+       struct {
+               uint32_t        crc;    /* CRC32 over data bytes    */
+               unsigned char   flags;  /* active or obsolete */
+               char            data[];
+       } redund;
+};
+
+struct environment {
+       union env_image *image;
+       char            *data;  /* shortcut to data */
+};
 
-static env_t environment;
+static struct environment environment;
 
 static int HaveRedundEnv = 0;
 
+#define ENV_FLAGS(e) e.image->redund.flags
+
 static unsigned char active_flag = 1;
 static unsigned char obsolete_flag = 0;
 
@@ -156,7 +170,7 @@ static char default_environment[] = {
 #ifdef  CONFIG_EXTRA_ENV_SETTINGS
        CONFIG_EXTRA_ENV_SETTINGS
 #endif
-       "\0"                    /* Termimate env_t data with 2 NULs */
+       "\0"                    /* Termimate struct environment data with 2 
NULs */
 };
 
 static int flash_io (int mode);
@@ -382,8 +396,12 @@ int fw_setenv (int argc, char *argv[])
 
   WRITE_FLASH:
 
-       /* Update CRC */
-       environment.crc = crc32 (0, (uint8_t*) environment.data, ENV_SIZE);
+       /*
+        * Update CRC: it is at the same location with and without the
+        * redundant environment
+        */
+       environment.image->single.crc = crc32 (0, (uint8_t *) environment.data,
+                                              ENV_SIZE);
 
        /* write environment back to flash */
        if (flash_io (O_RDWR)) {
@@ -396,7 +414,7 @@ int fw_setenv (int argc, char *argv[])
 
 static int flash_io (int mode)
 {
-       int fd, fdr, rc, otherdev, len, resid;
+       int fd, fdr, rc, otherdev, resid;
        erase_info_t erase;
        char *data = NULL;
 
@@ -407,11 +425,6 @@ static int flash_io (int mode)
                return (-1);
        }
 
-       len = sizeof (environment.crc);
-       if (HaveRedundEnv) {
-               len += sizeof (environment.flags);
-       }
-
        if (mode == O_RDWR) {
                if (HaveRedundEnv) {
                        /* switch to next partition for writing */
@@ -436,7 +449,7 @@ static int flash_io (int mode)
                        erase.length = DEVESIZE (curdev);
                        erase.start = DEVOFFSET (curdev);
                        ioctl (fd, MEMUNLOCK, &erase);
-                       environment.flags = active_flag;
+                       ENV_FLAGS(environment) = active_flag;
                }
 
                printf ("Done\n");
@@ -485,18 +498,15 @@ static int flash_io (int mode)
                                DEVNAME (otherdev), strerror (errno));
                        return (-1);
                }
-               if (write (fdr, &environment, len) != len) {
-                       fprintf (stderr,
-                               "CRC write error on %s: %s\n",
-                               DEVNAME (otherdev), strerror (errno));
-                       return (-1);
-               }
-               if (write (fdr, environment.data, ENV_SIZE) != ENV_SIZE) {
+
+               if (write (fdr, environment.image, CFG_ENV_SIZE) !=
+                   CFG_ENV_SIZE) {
                        fprintf (stderr,
                                "Write error on %s: %s\n",
                                DEVNAME (otherdev), strerror (errno));
                        return (-1);
                }
+
                if (resid) {
                        if (write (fdr, data, resid) != resid) {
                                fprintf (stderr,
@@ -548,13 +558,8 @@ static int flash_io (int mode)
                                DEVNAME (curdev), strerror (errno));
                        return (-1);
                }
-               if (read (fd, &environment, len) != len) {
-                       fprintf (stderr,
-                               "CRC read error on %s: %s\n",
-                               DEVNAME (curdev), strerror (errno));
-                       return (-1);
-               }
-               if ((rc = read (fd, environment.data, ENV_SIZE)) != ENV_SIZE) {
+               if (read (fd, environment.image, CFG_ENV_SIZE) !=
+                   CFG_ENV_SIZE) {
                        fprintf (stderr,
                                "Read error on %s: %s\n",
                                DEVNAME (curdev), strerror (errno));
@@ -604,22 +609,24 @@ static int env_init (void)
        if (parse_config ())            /* should fill envdevices */
                return 1;
 
-       if ((addr1 = calloc (1, ENV_SIZE)) == NULL) {
+       if ((addr1 = calloc (1, CFG_ENV_SIZE)) == NULL) {
                fprintf (stderr,
                        "Not enough memory for environment (%ld bytes)\n",
-                       ENV_SIZE);
+                       CFG_ENV_SIZE);
                return (errno);
        }
 
        /* read environment from FLASH to local buffer */
-       environment.data = addr1;
+       environment.image = (union env_image *)addr1;
+       environment.data = HaveRedundEnv ? environment.image->redund.data :
+               environment.image->single.data;
        curdev = 0;
        if (flash_io (O_RDONLY)) {
                return (errno);
        }
 
-       crc1_ok = ((crc1 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE))
-                          == environment.crc);
+       crc1 = crc32 (0, (uint8_t *) environment.data, ENV_SIZE);
+       crc1_ok = (crc1 == environment.image->single.crc);
        if (!HaveRedundEnv) {
                if (!crc1_ok) {
                        fprintf (stderr,
@@ -627,74 +634,83 @@ static int env_init (void)
                        memcpy(environment.data, default_environment, sizeof 
default_environment);
                }
        } else {
-               flag1 = environment.flags;
+               flag1 = ENV_FLAGS(environment);
 
                curdev = 1;
-               if ((addr2 = calloc (1, ENV_SIZE)) == NULL) {
+               if ((addr2 = calloc (1, CFG_ENV_SIZE)) == NULL) {
                        fprintf (stderr,
                                "Not enough memory for environment (%ld 
bytes)\n",
-                               ENV_SIZE);
+                               CFG_ENV_SIZE);
                        return (errno);
                }
-               environment.data = addr2;
+               environment.image = (union env_image *)addr2;
 
                if (flash_io (O_RDONLY)) {
                        return (errno);
                }
 
-               crc2_ok = ((crc2 = crc32 (0, (uint8_t *) environment.data, 
ENV_SIZE))
-                                  == environment.crc);
-               flag2 = environment.flags;
+               crc2 = crc32 (0, (uint8_t *) environment.image->redund.data,
+                             ENV_SIZE);
+               crc2_ok = (crc2 == environment.image->redund.crc);
+               flag2 = ENV_FLAGS(environment);
 
                if (crc1_ok && !crc2_ok) {
-                       environment.data = addr1;
-                       environment.flags = flag1;
-                       environment.crc = crc1;
+                       environment.image = (union env_image *)addr1;
+                       ENV_FLAGS(environment) = flag1;
+                       environment.image->redund.crc = crc1;
                        curdev = 0;
                        free (addr2);
                } else if (!crc1_ok && crc2_ok) {
-                       environment.data = addr2;
-                       environment.flags = flag2;
-                       environment.crc = crc2;
+                       environment.image = (union env_image *)addr2;
+                       ENV_FLAGS(environment) = flag2;
+                       environment.image->redund.crc = crc2;
                        curdev = 1;
                        free (addr1);
                } else if (!crc1_ok && !crc2_ok) {
                        fprintf (stderr,
                                "Warning: Bad CRC, using default 
environment\n");
-                       memcpy(environment.data, default_environment, sizeof 
default_environment);
+                       memcpy(environment.image->redund.data,
+                              default_environment, sizeof default_environment);
                        curdev = 0;
                        free (addr1);
+               /* From here: both CRCs correct */
                } else if (flag1 == active_flag && flag2 == obsolete_flag) {
-                       environment.data = addr1;
-                       environment.flags = flag1;
-                       environment.crc = crc1;
+                       environment.image = (union env_image *)addr1;
+                       ENV_FLAGS(environment) = flag1;
+                       environment.image->redund.crc = crc1;
                        curdev = 0;
                        free (addr2);
                } else if (flag1 == obsolete_flag && flag2 == active_flag) {
-                       environment.data = addr2;
-                       environment.flags = flag2;
-                       environment.crc = crc2;
+                       environment.image = (union env_image *)addr2;
+                       ENV_FLAGS(environment) = flag2;
+                       environment.image->redund.crc = crc2;
                        curdev = 1;
                        free (addr1);
+               /* From here: invalid flag configuration */
                } else if (flag1 == flag2) {
-                       environment.data = addr1;
-                       environment.flags = flag1;
-                       environment.crc = crc1;
+                       environment.image = (union env_image *)addr1;
+                       ENV_FLAGS(environment) = flag1;
+                       environment.image->redund.crc = crc1;
                        curdev = 0;
                        free (addr2);
-               } else if (flag1 == 0xFF) {
-                       environment.data = addr1;
-                       environment.flags = flag1;
-                       environment.crc = crc1;
+               } else if (flag1 == obsolete_flag || flag1 == active_flag) {
+                       /* flag1 valid, update flag2 */
+                       environment.image = (union env_image *)addr1;
+                       ENV_FLAGS(environment) = flag1;
+                       environment.image->redund.crc = crc1;
                        curdev = 0;
                        free (addr2);
-               } else if (flag2 == 0xFF) {
-                       environment.data = addr2;
-                       environment.flags = flag2;
-                       environment.crc = crc2;
+               } else {
+                       if (flag2 != obsolete_flag && flag2 != active_flag)
+                               fprintf (stderr, "Both CRCs valid, but both "
+                                       "flags invalid, will use the 1st\n");
+                       environment.image = (union env_image *)addr2;
+                       ENV_FLAGS(environment) = flag2;
+                       environment.image->redund.crc = crc2;
                        curdev = 1;
                        free (addr1);
                }
+               environment.data = environment.image->redund.data;
        }
        return (0);
 }
-- 
1.5.4

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

Reply via email to