soc/intel/common/block/rtc/rtc.c: Top Swap: add Slot B selection mechanism

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 <filip.lewinski@3mdeb.com>
Reviewed-on: https://review.coreboot.org/c/coreboot/+/90147
Tested-by: build bot (Jenkins) <no-reply@coreboot.org>
Reviewed-by: Sergii Dmytruk <sergii.dmytruk@3mdeb.com>
This commit is contained in:
Filip Lewiński 2025-11-21 12:19:48 +01:00 committed by Matt DeVillier
commit 4068ba39f8
5 changed files with 42 additions and 8 deletions

View file

@ -979,6 +979,14 @@ extract_nth=$(subst *,$(spc),$(patsubst -%-,%,$(word $(1), $(subst |,- -,-$(2)-)
# multiple CBFSes in fmap regions, override it. # multiple CBFSes in fmap regions, override it.
regions-for-file ?= $(if $(value regions-for-file-$(1)), $(regions-for-file-$(1)), COREBOOT) 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) ifeq ($(CONFIG_CBFS_AUTOGEN_ATTRIBUTES),y)
cbfs-autogen-attributes=-g cbfs-autogen-attributes=-g
endif endif
@ -1260,12 +1268,6 @@ $(obj)/fmap.fmap: $(obj)/fmap.fmd $(FMAPTOOL)
echo " FMAP $(FMAPTOOL) -h $(obj)/fmap_config.h $< $@" echo " FMAP $(FMAPTOOL) -h $(obj)/fmap_config.h $< $@"
$(FMAPTOOL) -h $(obj)/fmap_config.h -R $(obj)/fmap.desc $< $@ $(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) ifneq ($(CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS),y)
BB_FIT_REGION = COREBOOT BB_FIT_REGION = COREBOOT
TS_FIT_REGION = COREBOOT TS_FIT_REGION = COREBOOT

View file

@ -66,6 +66,9 @@ pbp.bin-type := raw
$(call add_intermediate, add_pbp_fit, set_fit_ptr $(IFITTOOL)) $(call add_intermediate, add_pbp_fit, set_fit_ptr $(IFITTOOL))
@printf " UPDATE-FIT Platform Boot Policy binary\n" @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 $(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 endif # CONFIG_HAVE_PBP_BIN

View file

@ -13,6 +13,10 @@
#error "FMAP must always start flash address 0" #error "FMAP must always start flash address 0"
#endif #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 /* 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 * that area. The region is a sub-region of the readonly boot media. Return
* 0 on success, < 0 on error. */ * 0 on success, < 0 on error. */

View file

@ -31,6 +31,11 @@ struct mem_pool cbfs_cache =
MEM_POOL_INIT(_cbfs_cache, REGION_SIZE(cbfs_cache), CONFIG_CBFS_CACHE_ALIGN); MEM_POOL_INIT(_cbfs_cache, REGION_SIZE(cbfs_cache), CONFIG_CBFS_CACHE_ALIGN);
#endif #endif
__weak const char *cbfs_fmap_region_hint(void)
{
return "COREBOOT";
}
static void switch_to_postram_cache(int unused) static void switch_to_postram_cache(int unused)
{ {
if (_preram_cbfs_cache != _postram_cbfs_cache) 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) 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; static struct cbfs_boot_device ro;
/* Ensure we always init RO mcache, even if the first file is from the RW CBFS. /* 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)) if (region_device_sz(&ro.rdev))
return &ro; return &ro;
if (fmap_locate_area_as_rdev("COREBOOT", &ro.rdev)) /* Falls back to the default COREBOOT region if no overriding mechanisms are in
die("Cannot locate primary CBFS"); 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) { if (ENV_INITIAL_STAGE) {
enum cb_err err = cbfs_init_boot_device(&ro, metadata_hash_get()); enum cb_err err = cbfs_init_boot_device(&ro, metadata_hash_get());

View file

@ -1,5 +1,6 @@
/* SPDX-License-Identifier: GPL-2.0-only */ /* SPDX-License-Identifier: GPL-2.0-only */
#include <fmap.h>
#include <intelblocks/pcr.h> #include <intelblocks/pcr.h>
#include <intelblocks/rtc.h> #include <intelblocks/rtc.h>
#include <option.h> #include <option.h>
@ -69,4 +70,16 @@ void sync_rtc_buc_top_swap(void)
board_reset(); 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 #endif