From patchwork Wed Apr 22 10:46:27 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Ferraris X-Patchwork-Id: 238276 List-Id: U-Boot discussion From: arnaud.ferraris at collabora.com (Arnaud Ferraris) Date: Wed, 22 Apr 2020 12:46:27 +0200 Subject: [PATCH 1/2] bootcount: add bootcount flash driver Message-ID: <20200422104629.88284-1-arnaud.ferraris@collabora.com> In order to save the bootcounter on raw flash device, this commit introduces a new bootcount driver, enabled using the CONFIG_BOOTCOUNT_FLASH option. The bootcounter is stored at address CONFIG_SYS_BOOTCOUNT_FLASH_ADDR (absolute address, can also be computed from CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET), and it uses a data structure providing several useful enhancements: - a `flags` field, used to check whether the bootcounter should be written to flash (similar to the `upgrade_available` environment variable) - a `crc` field to ensure integrity of the structure, which will be used later on when adding redundancy support - a `data` field, which can be used to store and pass user data between u-boot and the OS (e.g boot partition selection) Signed-off-by: Arnaud Ferraris --- drivers/bootcount/Kconfig | 14 ++++++ drivers/bootcount/Makefile | 1 + drivers/bootcount/bootcount_flash.c | 78 +++++++++++++++++++++++++++++ include/bootcount.h | 12 +++++ scripts/config_whitelist.txt | 2 + 5 files changed, 107 insertions(+) create mode 100644 drivers/bootcount/bootcount_flash.c diff --git a/drivers/bootcount/Kconfig b/drivers/bootcount/Kconfig index 0e506c9ea2..94de3f5ef8 100644 --- a/drivers/bootcount/Kconfig +++ b/drivers/bootcount/Kconfig @@ -66,6 +66,20 @@ config BOOTCOUNT_I2C CONFIG_SYS_BOOTCOUNT_ADDR = i2c addr which is used for the bootcounter. +config BOOTCOUNT_FLASH + bool "Boot counter on flash device" + help + Store the bootcounter on raw flash. The bootcounter will be stored + as a structure using one flash sector, and will only be written when + a specific flag is set in the structure. Additionnally, this driver + relies on one of the following to be defined: + + CONFIG_SYS_BOOTCOUNT_FLASH_ADDR = address used for storing the + bootcounter on flash. + or + CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET = bootcounter offset on flash + (relative to SYS_FLASH_BASE). + config BOOTCOUNT_AT91 bool "Boot counter for Atmel AT91SAM9XE" depends on AT91SAM9XE diff --git a/drivers/bootcount/Makefile b/drivers/bootcount/Makefile index 73ccfb5a08..bddcd136f3 100644 --- a/drivers/bootcount/Makefile +++ b/drivers/bootcount/Makefile @@ -7,6 +7,7 @@ obj-$(CONFIG_BOOTCOUNT_RAM) += bootcount_ram.o obj-$(CONFIG_BOOTCOUNT_ENV) += bootcount_env.o obj-$(CONFIG_BOOTCOUNT_I2C) += bootcount_i2c.o obj-$(CONFIG_BOOTCOUNT_EXT) += bootcount_ext.o +obj-$(CONFIG_BOOTCOUNT_FLASH) += bootcount_flash.o obj-$(CONFIG_DM_BOOTCOUNT) += bootcount-uclass.o obj-$(CONFIG_DM_BOOTCOUNT_RTC) += rtc.o diff --git a/drivers/bootcount/bootcount_flash.c b/drivers/bootcount/bootcount_flash.c new file mode 100644 index 0000000000..1222bb4ae0 --- /dev/null +++ b/drivers/bootcount/bootcount_flash.c @@ -0,0 +1,78 @@ +// SPDX-License-Identifier: GPL-2.0+ +/* + * Copyright (c) 2020 Collabora Ltd. All rights reserved. + */ + +#include +#include +#include +#include +#include + +#ifndef CONFIG_SYS_BOOTCOUNT_FLASH_ADDR +# ifdef CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET +# define CONFIG_SYS_BOOTCOUNT_FLASH_ADDR \ + (CONFIG_SYS_FLASH_BASE + CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET) +# else +# error "Either CONFIG_SYS_BOOTCOUNT_FLASH_ADDR or " \ + "CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET should be defined!" +# endif +#endif + +#define BOOTCOUNT_CRC_SIZE (sizeof(*bootcount) - sizeof(bootcount->crc)) + +static struct bootcount *bootcount = (void *)CONFIG_SYS_BOOTCOUNT_ADDR; +static ulong bc_flash = CONFIG_SYS_BOOTCOUNT_FLASH_ADDR; +static ulong bc_flash_end = + CONFIG_SYS_BOOTCOUNT_FLASH_ADDR + CONFIG_SYS_FLASH_SECT_SIZE - 1; + +static void bootcount_write(void) +{ + if (flash_sect_protect(0, bc_flash, bc_flash_end)) + return; + + puts("Erasing Flash...\n"); + if (flash_sect_erase(bc_flash, bc_flash_end)) + return; + + puts("Writing bootcount to Flash...\n"); + if (flash_write((char *)bootcount, bc_flash, sizeof(*bootcount))) + return; + + flash_sect_protect(1, bc_flash, bc_flash_end); +} + +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); + bootcount_write(); +} + +void bootcount_store(ulong a) +{ + bootcount->count = a; + bootcount->crc = crc32(0, (uchar *)bootcount, BOOTCOUNT_CRC_SIZE); + if (bootcount->flags & BOOTCOUNT_FLAGS_UPDATE) + bootcount_write(); +} + +ulong bootcount_load(void) +{ + static int initialized; + u32 crc; + + if (!initialized) { + memcpy(bootcount, (void *)bc_flash, sizeof(*bootcount)); + initialized = 1; + } + + crc = crc32(0, (uchar *)bootcount, BOOTCOUNT_CRC_SIZE); + if (bootcount->magic != CONFIG_SYS_BOOTCOUNT_MAGIC || + bootcount->crc != crc) { + bootcount_init(); + } + + return bootcount->count; +} diff --git a/include/bootcount.h b/include/bootcount.h index cd30403984..5698bd3239 100644 --- a/include/bootcount.h +++ b/include/bootcount.h @@ -79,6 +79,18 @@ ulong bootcount_load(void); # endif #endif +#ifdef CONFIG_BOOTCOUNT_FLASH +struct bootcount { + u32 magic; + u32 count; + u32 flags; + u32 data; + u32 crc; +}; + +#define BOOTCOUNT_FLAGS_UPDATE 0x1 +#endif + #ifdef CONFIG_SYS_BOOTCOUNT_LE static inline void raw_bootcount_store(volatile u32 *addr, u32 data) { diff --git a/scripts/config_whitelist.txt b/scripts/config_whitelist.txt index 6908431d03..672483f040 100644 --- a/scripts/config_whitelist.txt +++ b/scripts/config_whitelist.txt @@ -1829,6 +1829,8 @@ CONFIG_SYS_BOARD_NAME CONFIG_SYS_BOARD_OMAP3_HA CONFIG_SYS_BOOK3E_HV CONFIG_SYS_BOOTCOUNT_BE +CONFIG_SYS_BOOTCOUNT_FLASH_ADDR +CONFIG_SYS_BOOTCOUNT_FLASH_OFFSET CONFIG_SYS_BOOTCOUNT_LE CONFIG_SYS_BOOTFILE_PREFIX CONFIG_SYS_BOOTMAPSZ From patchwork Wed Apr 22 10:46:28 2020 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Arnaud Ferraris X-Patchwork-Id: 238275 List-Id: U-Boot discussion From: arnaud.ferraris at collabora.com (Arnaud Ferraris) Date: Wed, 22 Apr 2020 12:46:28 +0200 Subject: [PATCH 2/2] bootcount_flash: add redundancy support In-Reply-To: <20200422104629.88284-1-arnaud.ferraris@collabora.com> References: <20200422104629.88284-1-arnaud.ferraris@collabora.com> Message-ID: <20200422104629.88284-2-arnaud.ferraris@collabora.com> 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 --- drivers/bootcount/Kconfig | 7 +++++ drivers/bootcount/bootcount_flash.c | 47 +++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) 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;