#define _GNU_SOURCE
#include <compiler.h>
+#include <env.h>
#include <errno.h>
#include <env_flags.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/ioctl.h>
#include <sys/stat.h>
+#include <u-boot/crc.h>
#include <unistd.h>
#include <dirent.h>
unsigned char *flags;
char *data;
enum flag_scheme flag_scheme;
+ int dirty;
};
static struct environment environment = {
static int have_redund_env;
-static unsigned char active_flag = 1;
-/* obsolete_flag must be 0 to efficiently set it on NOR flash without erasing */
-static unsigned char obsolete_flag = 0;
-
#define DEFAULT_ENV_INSTANCE_STATIC
#include <env_default.h>
if (!opts)
opts = &default_opts;
+ if (!environment.dirty)
+ return 0;
+
/*
* Update CRC
*/
deleting = (oldval && !(value && strlen(value)));
creating = (!oldval && (value && strlen(value)));
- overwriting = (oldval && (value && strlen(value)));
+ overwriting = (oldval && (value && strlen(value) &&
+ strcmp(oldval, value)));
/* check for permission */
if (deleting) {
/* Nothing to do */
return 0;
+ environment.dirty = 1;
if (deleting || overwriting) {
if (*++nxt == '\0') {
*env = '\0';
lseek(fd, blockstart + block_seek, SEEK_SET);
rc = read(fd, buf + processed, readlen);
- if (rc != readlen) {
+ if (rc == -1) {
fprintf(stderr, "Read error on %s: %s\n",
DEVNAME(dev), strerror(errno));
return -1;
}
+ if (rc != readlen) {
+ fprintf(stderr,
+ "Read error on %s: Attempted to read %zd bytes but got %d\n",
+ DEVNAME(dev), readlen, rc);
+ return -1;
+ }
#ifdef DEBUG
fprintf(stderr, "Read 0x%x bytes at 0x%llx on %s\n",
rc, (unsigned long long)blockstart + block_seek,
of the data */
loff_t blockstart; /* running start of the current block -
MEMGETBADBLOCK needs 64 bits */
+ int was_locked = 0; /* flash lock flag */
int rc;
/*
}
erase.length = erasesize;
+ if (DEVTYPE(dev) != MTD_ABSENT) {
+ was_locked = ioctl(fd, MEMISLOCKED, &erase);
+ /* treat any errors as unlocked flash */
+ if (was_locked < 0)
+ was_locked = 0;
+ }
/* This only runs once on NOR flash and SPI-dataflash */
while (processed < write_total) {
if (DEVTYPE(dev) != MTD_ABSENT) {
erase.start = blockstart;
- ioctl(fd, MEMUNLOCK, &erase);
+ if (was_locked)
+ ioctl(fd, MEMUNLOCK, &erase);
/* These do not need an explicit erase cycle */
if (DEVTYPE(dev) != MTD_DATAFLASH)
if (ioctl(fd, MEMERASE, &erase) != 0) {
return -1;
}
- if (DEVTYPE(dev) != MTD_ABSENT)
- ioctl(fd, MEMLOCK, &erase);
+ if (DEVTYPE(dev) != MTD_ABSENT) {
+ if (was_locked)
+ ioctl(fd, MEMLOCK, &erase);
+ }
processed += erasesize;
block_seek = 0;
{
int rc;
struct erase_info_user erase;
+ char tmp = ENV_REDUND_OBSOLETE;
+ int was_locked; /* flash lock flag */
+ was_locked = ioctl(fd, MEMISLOCKED, &erase);
erase.start = DEVOFFSET(dev);
erase.length = DEVESIZE(dev);
- /* This relies on the fact, that obsolete_flag == 0 */
+ /* This relies on the fact, that ENV_REDUND_OBSOLETE == 0 */
rc = lseek(fd, offset, SEEK_SET);
if (rc < 0) {
fprintf(stderr, "Cannot seek to set the flag on %s\n",
DEVNAME(dev));
return rc;
}
- ioctl(fd, MEMUNLOCK, &erase);
- rc = write(fd, &obsolete_flag, sizeof(obsolete_flag));
- ioctl(fd, MEMLOCK, &erase);
+ if (was_locked)
+ ioctl(fd, MEMUNLOCK, &erase);
+ rc = write(fd, &tmp, sizeof(tmp));
+ if (was_locked)
+ ioctl(fd, MEMLOCK, &erase);
if (rc < 0)
perror("Could not set obsolete flag");
(*environment.flags)++;
break;
case FLAG_BOOLEAN:
- *environment.flags = active_flag;
+ *environment.flags = ENV_REDUND_ACTIVE;
break;
default:
fprintf(stderr, "Unimplemented flash scheme %u\n",
rc = -1;
}
- if (target_temp) {
+ if (rc >= 0 && target_temp) {
int dir_fd;
dir_fd = open(dname, O_DIRECTORY | O_RDONLY);
"Warning: Bad CRC, using default environment\n");
memcpy(environment.data, default_environment,
sizeof(default_environment));
+ environment.dirty = 1;
}
} else {
flag0 = *environment.flags;
crc1_ok = (crc1 == redundant->crc);
flag1 = redundant->flags;
+ /*
+ * environment.data still points to ((struct
+ * env_image_redundant *)addr0)->data. If the two
+ * environments differ, or one has bad crc, force a
+ * write-out by marking the environment dirty.
+ */
+ if (memcmp(environment.data, redundant->data, ENV_SIZE) ||
+ !crc0_ok || !crc1_ok)
+ environment.dirty = 1;
+
if (crc0_ok && !crc1_ok) {
dev_current = 0;
} else if (!crc0_ok && crc1_ok) {
"Warning: Bad CRC, using default environment\n");
memcpy(environment.data, default_environment,
sizeof(default_environment));
+ environment.dirty = 1;
dev_current = 0;
} else {
switch (environment.flag_scheme) {
case FLAG_BOOLEAN:
- if (flag0 == active_flag &&
- flag1 == obsolete_flag) {
+ if (flag0 == ENV_REDUND_ACTIVE &&
+ flag1 == ENV_REDUND_OBSOLETE) {
dev_current = 0;
- } else if (flag0 == obsolete_flag &&
- flag1 == active_flag) {
+ } else if (flag0 == ENV_REDUND_OBSOLETE &&
+ flag1 == ENV_REDUND_ACTIVE) {
dev_current = 1;
} else if (flag0 == flag1) {
dev_current = 0;
goto err;
}
DEVTYPE(dev) = mtdinfo.type;
+ if (DEVESIZE(dev) == 0 && ENVSECTORS(dev) == 0 &&
+ mtdinfo.type == MTD_NORFLASH)
+ DEVESIZE(dev) = mtdinfo.erasesize;
if (DEVESIZE(dev) == 0)
/* Assume the erase size is the same as the env-size */
DEVESIZE(dev) = ENVSIZE(dev);