@@ -170,6 +170,13 @@ config SYS_BOOTCOUNT_EXT_NAME
help
Set the filename and path of the file used to store the boot counter.
+config BOOTCOUNT_FLASH_REDUNDANCY
+ bool "Boot counter on flash device"
+ depends on BOOTCOUNT_FLASH
+ help
+ Store the bootcounter on 2 consecutive flash sectors, and use the backup
+ sector in case the main one gets corrupted.
+
config SYS_BOOTCOUNT_ADDR
hex "RAM address used for reading and writing the boot counter"
default 0x44E3E000 if BOOTCOUNT_AM33XX
@@ -23,8 +23,23 @@
static struct bootcount *bootcount = (void *)CONFIG_SYS_BOOTCOUNT_ADDR;
static ulong bc_flash = CONFIG_SYS_BOOTCOUNT_FLASH_ADDR;
+
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+/*
+ * When using redundant bootcount storage, the backup bootcount resides:
+ * - immediately after the main bootcount in RAM
+ * - on the next sector in flash
+ */
+static struct bootcount *bootcount_backup =
+ (void *)(CONFIG_SYS_BOOTCOUNT_ADDR + sizeof(struct bootcount));
+static ulong bc_flash_backup =
+ CONFIG_SYS_BOOTCOUNT_FLASH_ADDR + CONFIG_SYS_FLASH_SECT_SIZE;
+static ulong bc_flash_end =
+ CONFIG_SYS_BOOTCOUNT_FLASH_ADDR + (2 * CONFIG_SYS_FLASH_SECT_SIZE) - 1;
+#else
static ulong bc_flash_end =
CONFIG_SYS_BOOTCOUNT_FLASH_ADDR + CONFIG_SYS_FLASH_SECT_SIZE - 1;
+#endif
static void bootcount_write(void)
{
@@ -39,6 +54,12 @@ static void bootcount_write(void)
if (flash_write((char *)bootcount, bc_flash, sizeof(*bootcount)))
return;
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+ puts("Writing redundant bootcount to Flash...\n");
+ if (flash_write((char *)bootcount, bc_flash_backup, sizeof(*bootcount)))
+ return;
+#endif
+
flash_sect_protect(1, bc_flash, bc_flash_end);
}
@@ -47,6 +68,9 @@ static void bootcount_init(void)
memset(bootcount, 0, sizeof(*bootcount));
bootcount->magic = CONFIG_SYS_BOOTCOUNT_MAGIC;
bootcount->crc = crc32(0, (uchar *)bootcount, BOOTCOUNT_CRC_SIZE);
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+ memcpy(bootcount_backup, bootcount, sizeof(*bootcount));
+#endif
bootcount_write();
}
@@ -54,6 +78,9 @@ void bootcount_store(ulong a)
{
bootcount->count = a;
bootcount->crc = crc32(0, (uchar *)bootcount, BOOTCOUNT_CRC_SIZE);
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+ memcpy(bootcount_backup, bootcount, sizeof(*bootcount));
+#endif
if (bootcount->flags & BOOTCOUNT_FLAGS_UPDATE)
bootcount_write();
}
@@ -65,13 +92,33 @@ ulong bootcount_load(void)
if (!initialized) {
memcpy(bootcount, (void *)bc_flash, sizeof(*bootcount));
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+ memcpy(bootcount_backup,
+ (void *)bc_flash_backup,
+ sizeof(*bootcount));
+#endif
initialized = 1;
}
crc = crc32(0, (uchar *)bootcount, BOOTCOUNT_CRC_SIZE);
if (bootcount->magic != CONFIG_SYS_BOOTCOUNT_MAGIC ||
bootcount->crc != crc) {
+#ifdef CONFIG_BOOTCOUNT_FLASH_REDUNDANCY
+ puts("Invalid bootcount, checking backup sector...\n");
+ crc = crc32(0, (uchar *)bootcount_backup, BOOTCOUNT_CRC_SIZE);
+ if (bootcount_backup->magic != CONFIG_SYS_BOOTCOUNT_MAGIC ||
+ bootcount_backup->crc != crc) {
+ puts("Invalid backup sector, initializing...\n");
+ bootcount_init();
+ } else {
+ puts("Using backup sector...\n");
+ memcpy(bootcount, bootcount_backup, sizeof(*bootcount));
+ bootcount_write();
+ }
+#else
+ puts("Invalid bootcount, initializing...\n");
bootcount_init();
+#endif
}
return bootcount->count;
In order to deal with possible corruption of the flash memory storing the boot counter, this change adds optional redundancy support to the bootcount flash driver. When enabled, a backup copy of the bootcount structure is stored on the next flash sector, and written each time the main bootcount is saved. In case the primary bootcount is corrupted, the backup sector will be used to restore it to its previous state. Signed-off-by: Arnaud Ferraris <arnaud.ferraris at collabora.com> --- drivers/bootcount/Kconfig | 7 +++++ drivers/bootcount/bootcount_flash.c | 47 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+)