[PATCH 07/18] km: common: implement field fail-safe u-boot update

Aleksandar Gerasimovski aleksandar.gerasimovski at hitachienergy.com
Tue Nov 16 14:02:03 CET 2021


This patch provides possibility for field fail-safe u-boot updates.
The implementation can be used on all pg-wcom boards that are booting from
parallel NOR flash.

When used in a board design, provided check_for_uboot_update function will
start new u-boot at defined location if updateduboot envvar is set to yes.
With this implementation it is expected that factory programmed u-boot
will always stay as it is, and optionally new u-boot can be safely
programmed by embedded software when the unit is rolled out on the field.

It is expected check_for_uboot_update to be called early in execution
before relocation (*_f) once SoC is basically initialized and environment
can be read, with this possibilities to not be able to fix a u-boot bug by
a u-boot update are reduced to minimum.

Signed-off-by: Aleksandar Gerasimovski <aleksandar.gerasimovski at hitachienergy.com>
---
 board/keymile/Kconfig         | 32 ++++++++++++++++++++++++++
 board/keymile/common/common.c | 53 +++++++++++++++++++++++++++++++++++++++++++
 board/keymile/common/common.h |  1 +
 3 files changed, 86 insertions(+)

diff --git a/board/keymile/Kconfig b/board/keymile/Kconfig
index 7dd8213..863c07d 100644
--- a/board/keymile/Kconfig
+++ b/board/keymile/Kconfig
@@ -130,6 +130,38 @@ config SYS_IVM_EEPROM_PAGE_LEN
 	help
 	  Page size of inventory in EEPROM.
 
+config PG_WCOM_UBOOT_UPDATE_SUPPORTED
+	bool "Enable U-boot Field Fail-Safe Update Functionality"
+	default n
+	help
+	  Indicates that field fail-safe u-boot update is supported.
+	  This functionality works only for designs that are booting
+	  from parallel NOR flash.
+
+config PG_WCOM_UBOOT_BOOTPACKAGE
+	bool "U-boot Is Part Of Factory Boot-Package Image"
+	default n
+	help
+	  Indicates that u-boot will be a part of the factory programmed
+	  boot-package image.
+	  Has to be set for original u-boot programmed at factory.
+
+config PG_WCOM_UBOOT_UPDATE_TEXT_BASE
+	hex "Text Base For U-boot Programmed Outside Factory"
+	default 0xFFFFFFFF
+	help
+	  Text base of an updated u-boot that is not factory programmed but
+	  later when the unit is rolled out on the field.
+	  Has to be set for original u-boot programmed at factory.
+
+config PG_WCOM_UBOOT_UPDATE
+	bool "U-boot Is Part Of Factory Boot-Package Image"
+	default n
+	help
+	  Indicates that u-boot will be a part of the embedded software and
+	  programmed at field.
+	  Has to be set for updated u-boot version programmed at field.
+
 source "board/keymile/km83xx/Kconfig"
 source "board/keymile/kmcent2/Kconfig"
 source "board/keymile/km_arm/Kconfig"
diff --git a/board/keymile/common/common.c b/board/keymile/common/common.c
index ff07260..3999f48 100644
--- a/board/keymile/common/common.c
+++ b/board/keymile/common/common.c
@@ -19,6 +19,8 @@
 #include <asm/io.h>
 #include <linux/ctype.h>
 #include <linux/delay.h>
+#include <linux/bug.h>
+#include <bootcount.h>
 
 #if defined(CONFIG_POST)
 #include "post.h"
@@ -76,6 +78,57 @@ int set_km_env(void)
 	return 0;
 }
 
+#if CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE_SUPPORTED)
+#if   ((!CONFIG_IS_ENABLED(PG_WCOM_UBOOT_BOOTPACKAGE) && \
+	!CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE)) ||     \
+	(CONFIG_IS_ENABLED(PG_WCOM_UBOOT_BOOTPACKAGE) && \
+	CONFIG_IS_ENABLED(PG_WCOM_UBOOT_UPDATE)))
+#error "It has to be either bootpackage or update u-boot image!"
+#endif
+void check_for_uboot_update(void)
+{
+	void (*uboot_update_entry)(void) =
+		(void (*)(void)) CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE;
+	char *isupdated = env_get("updateduboot");
+	ulong bootcount = bootcount_load();
+	ulong ebootcount = 0;
+
+	if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_BOOTPACKAGE)) {
+		/*
+		 * When running in factory burned u-boot move to the updated
+		 * u-boot version only if updateduboot envvar is set to 'yes'
+		 * and bootcount limit is not exceeded.
+		 * Board must be able to start in factory bootloader mode!
+		 */
+		if (isupdated && !strncmp(isupdated, "yes", 3) &&
+		    bootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) {
+			printf("Check update: update detected, ");
+			printf("starting new image @%08x ...\n",
+			       CONFIG_PG_WCOM_UBOOT_UPDATE_TEXT_BASE);
+			ebootcount = early_bootcount_load();
+			if (ebootcount <= CONFIG_BOOTCOUNT_BOOTLIMIT) {
+				early_bootcount_store(++ebootcount);
+				uboot_update_entry();
+			} else {
+				printf("Check update: warning: ");
+				printf("early bootcount exceeded (%lu)\n",
+				       ebootcount);
+			}
+		}
+		printf("Check update: starting factory image @%08x ...\n",
+		       CONFIG_SYS_TEXT_BASE);
+	} else if (IS_ENABLED(CONFIG_PG_WCOM_UBOOT_UPDATE)) {
+		/*
+		 * When running in field updated u-boot, make sure that
+		 * bootcount limit is never exceeded. Must never happen!
+		 */
+		WARN_ON(bootcount > CONFIG_BOOTCOUNT_BOOTLIMIT);
+		printf("Check update: updated u-boot starting @%08x ...\n",
+		       CONFIG_SYS_TEXT_BASE);
+	}
+}
+#endif
+
 #if defined(CONFIG_SYS_I2C_INIT_BOARD)
 static void i2c_write_start_seq(void)
 {
diff --git a/board/keymile/common/common.h b/board/keymile/common/common.h
index fc14728..d16c824 100644
--- a/board/keymile/common/common.h
+++ b/board/keymile/common/common.h
@@ -135,6 +135,7 @@ int set_km_env(void);
 
 ulong early_bootcount_load(void);
 void early_bootcount_store(ulong ebootcount);
+void check_for_uboot_update(void);
 
 #define DELAY_ABORT_SEQ		62  /* @200kHz 9 clocks = 44us, 62us is ok */
 #define DELAY_HALF_PERIOD	(500 / (CONFIG_SYS_I2C_SPEED / 1000))
-- 
1.8.3.1


More information about the U-Boot mailing list