diff --git a/Documentation/soc/intel/index.md b/Documentation/soc/intel/index.md index ef032f5ece..96a23a5572 100644 --- a/Documentation/soc/intel/index.md +++ b/Documentation/soc/intel/index.md @@ -17,4 +17,5 @@ Apollolake CSE FW Update Xeon Scalable processor Skylake/Kaby Lake BootGuard bypass +Intel Top Swap based A/B redundancy ``` diff --git a/Documentation/soc/intel/redundancy.md b/Documentation/soc/intel/redundancy.md new file mode 100644 index 0000000000..bd3a92aaa5 --- /dev/null +++ b/Documentation/soc/intel/redundancy.md @@ -0,0 +1,174 @@ +# 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.