Intel Top Swap based A and B redundancy
This document describes a simple firmware A and B redundancy scheme based on Intel PCH Top Swap. The scheme maintains two firmware slots and uses the Top Swap control bit to choose which bootblock runs on boot. Each bootblock then continues booting from a matching CBFS region, so switching the Top Swap state switches the active slot.
The Intel Top Swap feature allows the PCH to take two physically topmost chunks of the BIOS flash chip, and decide in which order to map them - effectively allowing to swap the two chunks, and deciding which of them lands at the reset vector.
For background on the hardware mechanism, consult the Intel documentation for your PCH and platform and search for sections named similarly to “Top Swap”, “Top Swap Block Size (TSBS)”, or “Boot Block Update Scheme”. The exact document title and section naming varies between generations. The Alder Lake implementation for example has been developed basing mainly on ADL-P EDS Vol 1&2, sections:
3.2.1 Boot Block Update Scheme,9.70 PCH Descriptor Record 69 (Flash Descriptor Records),31.3.2 Backed Up Control (BUC),2.1.17 BIOS Control (ESPI_BC)
Flash layout and CBFS regions
The implementation assumes four FMAP regions that are CBFS formatted and that use the following names.
The bootblocks live in BOOTBLOCK and TOPSWAP. Each of these is a relatively
small CBFS region that contains a bootblock image and any additional files that
must reside next to it for early boot on a given platform. These regions must
exist in the board’s .fmd file and must be sized with headroom for growth
keeping in mind the FIT table and Boot Guard ACM’s must reside in the same region as the bootblock.
The main firmware CBFS regions are COREBOOT and COREBOOT_TS. COREBOOT is
typically the base slot and is often placed under write protection, along with
BOOTBLOCK. COREBOOT_TS is the alternate slot and is typically left writable
so it can be replaced by an update mechanism, along with TOPSWAP.
The BOOTBLOCK and TOPSWAP regions are expected to be placed in the
flash area covered by the Top Swap configuration. The sizes of the regions
must match and be equal to the corresponding field in the IFD. coreboot
can adjust the The Top Swap size (also called Top Swap Block Size in
Intel’s documentation) field in the descriptor during the build. This
is controlled by CONFIG_INTEL_IFD_SET_TOP_SWAP_BOOTBLOCK_SIZE and uses
CONFIG_INTEL_TOP_SWAP_BOOTBLOCK_SIZE as the requested size.
Kconfig options
The option CONFIG_INTEL_ADD_TOP_SWAP_BOOTBLOCK creates two copies of the
bootblock.
The option CONFIG_INTEL_TOP_SWAP_SEPARATE_REGIONS changes where the bootblocks
are stored. When it is disabled, both are stored in the primary CBFS region as
on existing platforms. When it is enabled, they are placed in the BOOTBLOCK
TOPSWAP FMAP regions. It also places copies of the following stages and
required files from the COREBOOT region in the COREBOOT_TS region.
If CBFS verification is enabled, the image build checks verification status for
all main CBFS regions that are part of the redundancy configuration, not only
for COREBOOT.
The option CONFIG_INTEL_TOP_SWAP_OPTION_CONTROL enables runtime control of the
Top Swap control bit based on a CMOS option. In tree, this option is constrained
to specific Intel SoCs. For a board to use it, the SoC bootblock must apply the
setting early enough for writes to the Top Swap control bit to take effect.
To reduce per board configuration burden, CONFIG_TOP_SWAP_REDUNDANCY exists
as a convenience option that selects the relevant pieces for Top Swap based
redundancy. Even with this convenience option enabled, a board still must
provide an appropriate .fmd layout and a cmos.layout entry as described
below.
Boards that use Top Swap based redundancy must enable CMOS option support
and ensure the option backend can read options at boot time. The symbol
MAINBOARD_NEEDS_CMOS_OPTIONS exists to indicate this dependency. Please
note that not every SoC supports this functionality.
CMOS option and when it is applied
Runtime Top Swap selection is controlled by a CMOS option named
attempt_slot_b. The name is defined as TOP_SWAP_ENABLE_CMOS_OPTION in
src/soc/intel/common/block/include/intelblocks/rtc.h. A board enabling
CONFIG_INTEL_TOP_SWAP_OPTION_CONTROL must provide a CMOS entry with this exact
name in its cmos.layout file.
The function sync_rtc_buc_top_swap() in src/soc/intel/common/block/rtc/rtc.c
implements the synchronization logic. It reads the CMOS option via
get_uint_option(), reads the current Top Swap state from the RTC BUC register,
compares the two, and if they differ it programs the new state and resets the
platform. The reset is intentional and ensures the new Top Swap state is in
effect from the beginning of the subsequent boot.
The SoC bootblock must call sync_rtc_buc_top_swap() early in
bootblock_soc_init() when CONFIG_INTEL_TOP_SWAP_OPTION_CONTROL is enabled.
This must happen before the platform locks down the relevant interfaces such
that Top Swap state changes no longer take effect.
Because the CMOS option is applied in bootblock, a mismatch between the requested slot and the current Top Swap state causes a very early reset. The next boot then starts directly from the selected slot.
CBFS region selection
The choice of the main CBFS region is made in cbfs_get_boot_device() in
src/lib/cbfs.c. Instead of always locating COREBOOT, the code calls
cbfs_fmap_region_hint() to obtain the FMAP region name and then locates that
region.
The default cbfs_fmap_region_hint() implementation is a weak symbol that
returns COREBOOT, so platforms that do not override it retain the existing
behavior.
Intel Top Swap platforms provide a strong definition of
cbfs_fmap_region_hint() in src/soc/intel/common/block/rtc/rtc.c. When
CONFIG_INTEL_TOP_SWAP_OPTION_CONTROL is enabled and the Top Swap control
bit is set, it returns COREBOOT_TS. Otherwise it returns COREBOOT.
cbfs_get_boot_device() logs the selected region and stops with an error if the
region cannot be found in FMAP.
This is deliberately based on the actual hardware Top Swap state rather than on
reading CMOS again. At the point where cbfs_fmap_region_hint() is used, the
option table is not reliably available, because the cmos_layout.bin backing
the option table is itself stored in CBFS.
For the override to apply in a given stage, the RTC block code must be linked into that stage. The common RTC block is built into multiple stages and is also built into postcar to ensure the hint function is available when CBFS is accessed there.
Boot flow summary
A typical update and rollback sequence is as follows.
The platform starts in slot A with Top Swap disabled. The hardware boots from
the BOOTBLOCK and coreboot continues from the COREBOOT CBFS region.
An update writes into the TOPSWAP and COREBOOT_TS regions, then sets the
attempt_slot_b CMOS option.
On the next boot, sync_rtc_buc_top_swap() observes that the CMOS request
differs from the current hardware Top Swap state, programs the new Top Swap
state, and resets the platform.
After the reset, the hardware starts from the bootblock corresponding to
the new Top Swap state. When coreboot later initializes its boot device,
cbfs_fmap_region_hint() sees the Top Swap state and selects COREBOOT_TS, so
the remainder of the boot uses the updated slot.
Clearing CMOS or resetting attempt_slot_b triggers the same sequence in the
opposite direction, returning the platform to COREBOOT without requiring
external flashing.
Troubleshooting notes
If the platform does not switch slots as expected, confirm that the
attempt_slot_b entry exists in cmos.layout and that the option table backend
is in use so get_uint_option() can read it in bootblock.
If the platform resets but still boots from COREBOOT, confirm that the RTC
block implementation providing cbfs_fmap_region_hint() is linked into the
stage that performs CBFS initialization on your platform.
If the build fails to boot after enabling separate regions, confirm that the
.fmd file defines BOOTBLOCK, TOPSWAP, COREBOOT, and COREBOOT_TS as
CBFS regions and that the platform Top Swap configuration matches the reserved
bootblock and Top Swap region placement and sizing.
Serial logs should show the CMOS request and the RTC BUC control bit values during bootblock, followed by a log line indicating which CBFS region is being used.