From 4068ba39f8457471219dbbd727735b307a482793 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Filip=20Lewi=C5=84ski?= Date: Fri, 21 Nov 2025 12:19:48 +0100 Subject: [PATCH] soc/intel/common/block/rtc/rtc.c: Top Swap: add Slot B selection mechanism MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit If the Top Swap mechanism is enabled, after running the bootblock from the TOP_SWAP region, boot from an updatable COREBOOT_TS FMAP region. Having flashed the TOP_SWAP bootblock and COREBOOT_TS, this allows the user to boot a newer version of the firmware with the ability to revert to the previous known-good version by performing a CMOS reset. Requires having a read-write COREBOOT_TS region in the FMAP file. This is part of an ongoing implementation of a redundancy feature proposed on the mailing list: https://mail.coreboot.org/archives/list/coreboot@coreboot.org/thread/C6JN2PB7K7D67EG7OIKB6BBERZU5YV35/ TEST=Boot Protectli VP6650, setting the attempt_slot_b flag to different values, observing the "Booting from COREBOOT/COREBOOT_TS region" prints correspondingly. Change-Id: Ieadc9bfbe940cbec79eb84f16a5d622bfbb82ede Signed-off-by: Filip LewiƄski Reviewed-on: https://review.coreboot.org/c/coreboot/+/90147 Tested-by: build bot (Jenkins) Reviewed-by: Sergii Dmytruk --- Makefile.mk | 14 ++++++++------ src/cpu/intel/fit/Makefile.mk | 3 +++ src/include/fmap.h | 4 ++++ src/lib/cbfs.c | 16 ++++++++++++++-- src/soc/intel/common/block/rtc/rtc.c | 13 +++++++++++++ 5 files changed, 42 insertions(+), 8 deletions(-) diff --git a/Makefile.mk b/Makefile.mk index 93a26d0d95..75787b32d4 100644 --- a/Makefile.mk +++ b/Makefile.mk @@ -979,6 +979,14 @@ extract_nth=$(subst *,$(spc),$(patsubst -%-,%,$(word $(1), $(subst |,- -,-$(2)-) # multiple CBFSes in fmap regions, override it. regions-for-file ?= $(if $(value regions-for-file-$(1)), $(regions-for-file-$(1)), COREBOOT) +ifeq ($(CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK),y) +ifneq ($(CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS),y) +TS_OPTIONS := -j $(CONFIG_INTEL_TOP_SWAP_BOOTBLOCK_SIZE) +else +regions-for-file = $(if $(value regions-for-file-$(1)), $(regions-for-file-$(1)), COREBOOT,COREBOOT_TS) +endif +endif + ifeq ($(CONFIG_CBFS_AUTOGEN_ATTRIBUTES),y) cbfs-autogen-attributes=-g endif @@ -1260,12 +1268,6 @@ $(obj)/fmap.fmap: $(obj)/fmap.fmd $(FMAPTOOL) echo " FMAP $(FMAPTOOL) -h $(obj)/fmap_config.h $< $@" $(FMAPTOOL) -h $(obj)/fmap_config.h -R $(obj)/fmap.desc $< $@ -ifeq ($(CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK),y) -ifneq ($(CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS),y) -TS_OPTIONS := -j $(CONFIG_INTEL_TOP_SWAP_BOOTBLOCK_SIZE) -endif -endif - ifneq ($(CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS),y) BB_FIT_REGION = COREBOOT TS_FIT_REGION = COREBOOT diff --git a/src/cpu/intel/fit/Makefile.mk b/src/cpu/intel/fit/Makefile.mk index c8bb5bd26f..2729c0a6ae 100644 --- a/src/cpu/intel/fit/Makefile.mk +++ b/src/cpu/intel/fit/Makefile.mk @@ -66,6 +66,9 @@ pbp.bin-type := raw $(call add_intermediate, add_pbp_fit, set_fit_ptr $(IFITTOOL)) @printf " UPDATE-FIT Platform Boot Policy binary\n" $(IFITTOOL) -f $< -a -n pbp.bin -t 4 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT +ifeq ($(CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS),y) + $(IFITTOOL) -f $< -a -n pbp.bin -t 4 -s $(CONFIG_CPU_INTEL_NUM_FIT_ENTRIES) -r COREBOOT_TS +endif endif # CONFIG_HAVE_PBP_BIN diff --git a/src/include/fmap.h b/src/include/fmap.h index fc49dbdf5e..900bfff542 100644 --- a/src/include/fmap.h +++ b/src/include/fmap.h @@ -13,6 +13,10 @@ #error "FMAP must always start flash address 0" #endif +/* Return the name of the boot region. Falls back to COREBOOT, if not overridden + * by any multi-slot mechanism (e.g Intel Top Swap, vboot). */ +const char *cbfs_fmap_region_hint(void); + /* Locate the named area in the fmap and fill in a region device representing * that area. The region is a sub-region of the readonly boot media. Return * 0 on success, < 0 on error. */ diff --git a/src/lib/cbfs.c b/src/lib/cbfs.c index fab64d3b7b..0c47359260 100644 --- a/src/lib/cbfs.c +++ b/src/lib/cbfs.c @@ -31,6 +31,11 @@ struct mem_pool cbfs_cache = MEM_POOL_INIT(_cbfs_cache, REGION_SIZE(cbfs_cache), CONFIG_CBFS_CACHE_ALIGN); #endif +__weak const char *cbfs_fmap_region_hint(void) +{ + return "COREBOOT"; +} + static void switch_to_postram_cache(int unused) { if (_preram_cbfs_cache != _postram_cbfs_cache) @@ -670,6 +675,7 @@ enum cb_err cbfs_init_boot_device(const struct cbfs_boot_device *cbd, const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) { + printk(BIOS_DEBUG, "Starting cbfs_boot_device\n"); static struct cbfs_boot_device ro; /* Ensure we always init RO mcache, even if the first file is from the RW CBFS. @@ -693,8 +699,14 @@ const struct cbfs_boot_device *cbfs_get_boot_device(bool force_ro) if (region_device_sz(&ro.rdev)) return &ro; - if (fmap_locate_area_as_rdev("COREBOOT", &ro.rdev)) - die("Cannot locate primary CBFS"); + /* Falls back to the default COREBOOT region if no overriding mechanisms are in + place (e.g. Intel Top Swap). */ + const char *region = cbfs_fmap_region_hint(); + + if (fmap_locate_area_as_rdev(region, &ro.rdev)) + die("Cannot locate %s CBFS", region); + + printk(BIOS_INFO, "Booting from %s region\n", region); if (ENV_INITIAL_STAGE) { enum cb_err err = cbfs_init_boot_device(&ro, metadata_hash_get()); diff --git a/src/soc/intel/common/block/rtc/rtc.c b/src/soc/intel/common/block/rtc/rtc.c index fd8dc88755..25c4444511 100644 --- a/src/soc/intel/common/block/rtc/rtc.c +++ b/src/soc/intel/common/block/rtc/rtc.c @@ -1,5 +1,6 @@ /* SPDX-License-Identifier: GPL-2.0-only */ +#include #include #include #include @@ -69,4 +70,16 @@ void sync_rtc_buc_top_swap(void) board_reset(); } } + +/* + * Select the FMAP region to continue booting from, depending on the state of + * Top Swap + */ +const char *cbfs_fmap_region_hint(void) +{ + if (CONFIG(INTEL_TOP_SWAP_OPTION_CONTROL) && get_rtc_buc_top_swap_status()) + return "COREBOOT_TS"; + else + return "COREBOOT"; +} #endif