[U-Boot] [PATCH 5/6] Support environment anywhere within erase area
Guennadi Liakhovetski
lg at denx.de
Wed Aug 27 17:52:53 CEST 2008
This will become more important with NAND support, in which case the minimum
erase region is a block, which consists of several pages and can be 256KiB
large.
Signed-off-by: Guennadi Liakhovetski <lg at denx.de>
---
tools/env/fw_env.c | 125 +++++++++++++++++++++++++++++++--------------------
1 files changed, 76 insertions(+), 49 deletions(-)
diff --git a/tools/env/fw_env.c b/tools/env/fw_env.c
index 556aa85..931e647 100644
--- a/tools/env/fw_env.c
+++ b/tools/env/fw_env.c
@@ -413,11 +413,37 @@ int fw_setenv (int argc, char *argv[])
return 0;
}
+static int flash_read_buf (int dev, int fd, void *buf, size_t count,
+ off_t offset)
+{
+ int rc;
+
+ rc = lseek (fd, offset, SEEK_SET);
+ if (rc == -1) {
+ fprintf (stderr,
+ "seek error on %s: %s\n",
+ DEVNAME (dev), strerror (errno));
+ return rc;
+ }
+
+ rc = read (fd, buf, count);
+ if (rc != count) {
+ fprintf (stderr,
+ "Read error on %s: %s\n",
+ DEVNAME (dev), strerror (errno));
+ return -1;
+ }
+
+ return rc;
+}
+
static int flash_write (void)
{
- int fd_current, fd_target, rc, dev_target, resid;
+ int fd_current, fd_target, rc, dev_target;
erase_info_t erase_current = {}, erase_target;
char *data = NULL;
+ off_t erase_offset;
+ struct mtd_info_user mtdinfo_target;
/* dev_current: fd_current, erase_current */
if ((fd_current = open (DEVNAME (dev_current), O_RDWR)) < 0) {
@@ -442,6 +468,45 @@ static int flash_write (void)
dev_target = dev_current;
fd_target = fd_current;
}
+
+ /*
+ * Support environment anywhere within erase sectors: read out the
+ * complete area to be erased, replace the environment image, write
+ * the whole block back again.
+ */
+ if (DEVESIZE (dev_target) > CFG_ENV_SIZE) {
+ data = malloc (DEVESIZE (dev_target));
+ if (!data) {
+ fprintf (stderr,
+ "Cannot malloc %lu bytes: %s\n",
+ DEVESIZE (dev_target),
+ strerror (errno));
+ return -1;
+ }
+
+ rc = ioctl (fd_target, MEMGETINFO, &mtdinfo_target);
+ if (rc < 0) {
+ perror ("Cannot get MTD information");
+ return -1;
+ }
+
+ /* Erase sector size is always a power of 2 */
+ erase_offset = DEVOFFSET (dev_target) &
+ ~(mtdinfo_target.erasesize - 1);
+
+ rc = flash_read_buf (dev_target, fd_target, data,
+ DEVESIZE (dev_target), erase_offset);
+ if (rc < 0)
+ return rc;
+
+ /* Overwrite the old environment */
+ memcpy(DEVOFFSET (dev_target) - erase_offset + data,
+ environment.image, CFG_ENV_SIZE);
+ } else {
+ data = (char *)environment.image;
+ erase_offset = DEVOFFSET (dev_target);
+ }
+
printf ("Unlocking flash...\n");
erase_target.length = DEVESIZE (dev_target);
erase_target.start = DEVOFFSET (dev_target);
@@ -455,30 +520,6 @@ static int flash_write (void)
}
printf ("Done\n");
- resid = DEVESIZE (dev_target) - CFG_ENV_SIZE;
- if (resid) {
- if ((data = malloc (resid)) == NULL) {
- fprintf (stderr,
- "Cannot malloc %d bytes: %s\n",
- resid,
- strerror (errno));
- return -1;
- }
- if (lseek (fd_target, DEVOFFSET (dev_target) + CFG_ENV_SIZE,
- SEEK_SET) == -1) {
- fprintf (stderr, "seek error on %s: %s\n",
- DEVNAME (dev_target),
- strerror (errno));
- return -1;
- }
- if ((rc = read (fd_target, data, resid)) != resid) {
- fprintf (stderr,
- "read error on %s: %s\n",
- DEVNAME (dev_target),
- strerror (errno));
- return -1;
- }
- }
printf ("Erasing old environment...\n");
@@ -492,30 +533,24 @@ static int flash_write (void)
printf ("Done\n");
printf ("Writing environment to %s...\n", DEVNAME (dev_target));
- if (lseek (fd_target, DEVOFFSET (dev_target), SEEK_SET) == -1) {
+ if (lseek (fd_target, erase_offset, SEEK_SET) == -1) {
fprintf (stderr,
"seek error on %s: %s\n",
DEVNAME (dev_target), strerror (errno));
return -1;
}
- if (write (fd_target, environment.image, CFG_ENV_SIZE) !=
- CFG_ENV_SIZE) {
+ if (write (fd_target, data, DEVESIZE (dev_target)) !=
+ DEVESIZE (dev_target)) {
fprintf (stderr,
"Write error on %s: %s\n",
DEVNAME (dev_target), strerror (errno));
return -1;
}
- if (resid) {
- if (write (fd_target, data, resid) != resid) {
- fprintf (stderr,
- "write error on %s: %s\n",
- DEVNAME (dev_current), strerror (errno));
- return -1;
- }
+ if (DEVESIZE (dev_target) > CFG_ENV_SIZE)
free (data);
- }
+
if (HaveRedundEnv) {
/* change flag on current active env partition */
if (lseek (fd_current, DEVOFFSET (dev_current) + sizeof (ulong),
@@ -560,7 +595,7 @@ static int flash_write (void)
static int flash_read (void)
{
- int fd;
+ int fd, rc;
if ((fd = open (DEVNAME (dev_current), O_RDONLY)) < 0) {
fprintf (stderr,
@@ -569,18 +604,10 @@ static int flash_read (void)
return -1;
}
- if (lseek (fd, DEVOFFSET (dev_current), SEEK_SET) == -1) {
- fprintf (stderr,
- "seek error on %s: %s\n",
- DEVNAME (dev_current), strerror (errno));
- return -1;
- }
- if (read (fd, environment.image, CFG_ENV_SIZE) != CFG_ENV_SIZE) {
- fprintf (stderr,
- "Read error on %s: %s\n",
- DEVNAME (dev_current), strerror (errno));
- return -1;
- }
+ rc = flash_read_buf (dev_current, fd, environment.image, CFG_ENV_SIZE,
+ DEVOFFSET (dev_current));
+ if (rc < 0)
+ return rc;
if (close (fd)) {
fprintf (stderr,
--
1.5.4
More information about the U-Boot
mailing list