diff mbox series

[2/2] bootcount_flash: add redundancy support

Message ID 20200422104629.88284-2-arnaud.ferraris@collabora.com
State Changes Requested
Delegated to: Daniel Schwierzeck
Headers show
Series [1/2] bootcount: add bootcount flash driver | expand

Commit Message

Arnaud Ferraris April 22, 2020, 10:46 a.m. UTC
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@collabora.com>
---

 drivers/bootcount/Kconfig           |  7 +++++
 drivers/bootcount/bootcount_flash.c | 47 +++++++++++++++++++++++++++++
 2 files changed, 54 insertions(+)
diff mbox series

Patch

diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig
index 94de3f5ef8..f247988641 100644
--- a/drivers/bootcount/Kconfig
+++ b/drivers/bootcount/Kconfig
@@ -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
diff --git a/drivers/bootcount/bootcount_flash.c b/drivers/bootcount/bootcount_flash.c
index 1222bb4ae0..86ac7e0d03 100644
--- a/drivers/bootcount/bootcount_flash.c
+++ b/drivers/bootcount/bootcount_flash.c
@@ -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;