Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Capsule updates for coreboot+UefiPkgPayload #6026

Open
wants to merge 14 commits into
base: master
Choose a base branch
from

Conversation

SergiiDmytruk
Copy link
Contributor

@SergiiDmytruk SergiiDmytruk commented Aug 1, 2024

Description

The proposed changes are part of UEFI Capsule Update for coreboot with EDK II project (funded by NLnet foundation), whose goal is to make updates of open source firmware easier for end users while also increasing update's security by limiting full flash access to the firmware itself.

Because capsules require persistent EFI variables, this also adds SMMSTOREv2 to EDK.

  • Breaking change?
    • Breaking change - Does this PR cause a break in build or boot behavior?
    • There is a possibility that building with CAPSULE_SUPPORT might require some changes. Maybe some new changes in DSC file need to not apply if CAPSULE_MAIN_FW_GUID is empty.
  • Impacts security?
    • Security - Does this PR have a direct security impact?
    • SMMSTORE and flash access in general might be considered related to security, but it's really dealt with by coreboot.
  • Includes tests?
    • Tests - Does this PR include any explicit test code?
    • No tests.

How This Was Tested

A combination of coreboot changes from here and here (for QEMU Q35) were combined with changes from this branch while update capsules were built as specified in this overview. Then CapsuleApp.efi and produced capsule file were made available in the VM and used to perform a successful firmware update.

Essentially the same changes but in forks of coreboot (Dasharo/coreboot#509) and EDK2 (Dasharo/edk2#147) were verified both on QEMU Q35 and MSI PRO Z690-A DDR4 hardware.

How to test for yourself

For convenience, I combined coreboot's capsule and Q35 changes in a single branch here (also fixes an issue with QEMU addressed by now abandoned Q35 patch) and this branch contains all needed EDK changes. After building coreboot with the following defconfig:

CONFIG_OPTION_BACKEND_NONE=y
CONFIG_BOARD_EMULATION_QEMU_X86_Q35=y
CONFIG_EDK2_BOOT_TIMEOUT=5
CONFIG_CPU_QEMU_X86_TSEG_SMM=y
CONFIG_USE_UDK_202005_BINDING=y
CONFIG_VGA_TEXT_FRAMEBUFFER=y
CONFIG_RESOURCE_ALLOCATION_TOP_DOWN=y
CONFIG_DRIVERS_EFI_VARIABLE_STORE=y
CONFIG_DRIVERS_EFI_FW_INFO=y
CONFIG_PAYLOAD_EDK2=y
CONFIG_EDK2_REPO_CUSTOM=y
CONFIG_EDK2_REPOSITORY="https://github.com/Dasharo/edk2-upstream.git"
CONFIG_EDK2_TAG_OR_REV="origin/up/enable-capsule-updates"
CONFIG_EDK2_SERIAL_SUPPORT=y
cp defconfig .config
make olddefconfig
make -j$(nproc)

One should be able to run the image in QEMU:

qemu-system-x86_64 -M q35,smm=on -enable-kvm -m 512 \
    -drive if=pflash,format=raw,unit=0,file=build/coreboot.rom \
    -drive file=disk.qcow2,format=qcow2 \
    -serial stdio -nographic

Here disk.qcow2 is supposed to contain a capsule and CapsuleApp.efi (see https://docs.dasharo.com/kb/edk2-capsule-updates/ for how to produce those). I deliberately didn't go into every little detail here but can do if anyone will face issues testing this.

Integration Instructions

Those willing to make use of the changes from coreboot apart from pulling in relevant commits should have these options on:

CONFIG_USE_UDK_202005_BINDING=y
CONFIG_DRIVERS_EFI_VARIABLE_STORE=y
CONFIG_DRIVERS_EFI_FW_INFO=y

On EDK side this translates into -D CAPSULE_SUPPORT=TRUE and -D CAPSULE_MAIN_FW_GUID=<firmware guid>, plus building CapsuleApp.efi and capsules as mentioned above with proper key management for signing the capsules.

Copy link

github-actions bot commented Oct 3, 2024

This PR has been automatically marked as stale because it has not had activity in 60 days. It will be closed if no further activity occurs within 7 days. Thank you for your contributions.

@github-actions github-actions bot added the stale Due to lack of updates, this item is pending deletion. label Oct 3, 2024
Copy link

mergify bot commented Oct 3, 2024

PR can not be merged due to conflict. Please rebase and resubmit

@github-actions github-actions bot removed the stale Due to lack of updates, this item is pending deletion. label Oct 4, 2024
SergiiDmytruk and others added 14 commits October 6, 2024 18:22
The implementation is for CbParseLib, SblParseLib returns an error.

coreboot's CB_TAG_FW_INFO is a machine-friendly version of a system
firmware component.  A component is identified by a GUID.  This is meant
to be a source of information for ESRT.

Signed-off-by: Sergii Dmytruk <[email protected]>
…rmware

Use firmware information passed by bootloader to make a single-element
ESRT.

BlParseLib is always built now because it became a dependency of
UefiPayloadPkg/BlSupportDxe.

Signed-off-by: Sergii Dmytruk <[email protected]>
The HOBs created by BuildCvHob() will get picked up and processed by
MdeModulePkg/Library/DxeCapsuleLibFmp/DxeCapsuleProcessLib.c in DXE.

Signed-off-by: Sergii Dmytruk <[email protected]>
When set to TRUE, bit EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED of
OsIndications is set.

At the moment EDK never sets this bit (there is only definition with no
uses), maybe nothing actually checks its value.  Whatever the reason is,
it seems like a good idea to make setting it possible.

Signed-off-by: Sergii Dmytruk <[email protected]>
Make UefiPayloadPkg.dsc add required libraries/DXEs/PCDs when
CAPSULE_SUPPORT define is set to TRUE.

UefiPayloadEntry now switches boot mode to BOOT_ON_FLASH_UPDATE if there
are any capsules.  It's not guarded by any PCD under the assumption that
bootloader won't pass capsules if EDK shouldn't be handling them.

EsrtDxe is enabled to manage ESRT entries.  ProcessCapsules() internally
looks up EsrtManagementProtocol and calls SyncEsrtFmp() to import data
from available FMP instances.

PlatformBootManagerLib was made to call ProcessCapsules() twice: before
and after end-of-DXE.

Signed-off-by: Sergii Dmytruk <[email protected]>
This is using test certificate stored in this repository.  Building
additionally requires setting CAPSULE_FIRMWARE_GUID to firmware GUID in
string form.

FDF file is not updated because FMP driver is to be embedded into update
capsule.

Signed-off-by: Sergii Dmytruk <[email protected]>
Since commit bc744f5893fc4d53275ed26dd8d968011c6a09c1 coreboot supports
the SMMSTORE v2 feature. It implements an SMI handler that is able to
write, read and erase pages in the boot media (SPI flash).
The existence of this optional feature is advertised by a coreboot table.

Add the tag and headers to parse the table.

Signed-off-by: Patrick Rudolph <[email protected]>
Add a new InfoHob that contains the SmmStore information passed from
coreboot tables when the SMMSTOREV2 feature is enabled.

This will be used to implement the FVB on top of the SMI installed by
coreboot.

Signed-off-by: Patrick Rudolph <[email protected]>
Implement all of the FVB protocol functions on top of the SmmStore
as a library. The library consumes the introduced
gEfiSmmStoreInfoHobGuid.

The SMI handler uses a fixed communication buffer in reserved DRAM.
To initiate a transaction you must write to the I/O APM_CNT port.

Tests on Intel(R) Xeon(R) E-2288G CPU @ 3.70G showed that the SMI isn't
triggered with a probability of 1:40 of all cases when called in a tight
loop. The CPU continues running and the SMI is triggeres asynchronously
a few clock cycles later. coreboot only handels synchronous APM request
and does nothing on asynchronous APM triggers.

As there's no livesign from SMM it's impossible to tell if the handler
has run. Just wait a bit and try again to trigger a synchronous SMI.

Tests confirmed that out of 5 million tries the SMI is now always
handled.

When a synchronous SMI happens with the correct write to the APM_CNT
port, the ebx register is checked first that it doesn't point to SMRAM.
If it doesn't it's used to read in the arguments that define a SmmStore
transaction.

The SMI handler will only operate on a predefined and memory mapped
region in the boot media.

Signed-off-by: Patrick Rudolph <[email protected]>
Signed-off-by: Sergii Dmytruk <[email protected]>
This adds support for FVB in order to support a platform independent
and non-volatile variable store on UefiPayloadPkg. The variable store
makes use of the SmmStoreLib to provide an unauthenticated variable
store.

Since commit bc744f5893fc4d53275ed26dd8d968011c6a09c1 coreboot supports
the SMMSTORE v2 feature. It implements an SMI handler that is able to
write, read and erase pages in the boot media (SPI flash).
The communication is done using a fixed communication buffer that is
allocated in CBMEM. The existence of this optional feature is advertised
by a coreboot table.
When the SMMSTORE feature is not available, the variable emulation is used
by setting PcdEmuVariableNvModeEnable to TRUE.

The DXE component provides runtime services and takes care of virtual to
physical mapping the communication buffers between SMM and OS.

The contents of the variable store can be accessed and modified by any
privileged application. As authentication is done by runtime services
only the store shouldn't be used to store authenticated variables.

Tested on Linux and Windows 10 on real hardware.
Currently this cannot be tested on upstream coreboot in qemu due to the
lack of support for SMMSTORE in qemu boards.

Signed-off-by: Patrick Rudolph <[email protected]>
Signed-off-by: Sean Rhodes <[email protected]>
Signed-off-by: Matt DeVillier <[email protected]>
Signed-off-by: Sergii Dmytruk <[email protected]>
This allows reusing SMMSTORE protocol for the purpose of firmware
updates.

Signed-off-by: Sergii Dmytruk <[email protected]>
Such strings can include, for example, version information about the
bootloader.

Signed-off-by: Sergii Dmytruk <[email protected]>
Part of functions of the library are left unimplemented (return
EFI_UNSUPPORTED) the rest use information about current firmware
obtained from CBMEM and SMMSTOREv2 to perform flashing.

Flashing is slightly optimized: FmpDeviceSetImageWithStatus() first
reads a block and checks that it differs from the new contents before
initiating erase and write.

Signed-off-by: Sergii Dmytruk <[email protected]>
They are used by the code but weren't declared as such.

Signed-off-by: Sergii Dmytruk <[email protected]>
@tianocore-assign-reviewers
Copy link

WARNING: Cannot add some reviewers: A user specified as a reviewer for this PR is not a collaborator of the repository. Please add them as a collaborator to the repository so they can be requested in the future.

Non-collaborators requested:

Attn Admins:


Admin Instructions:

  • Add the non-collaborators as collaborators to the appropriate team(s) listed in teams
  • If they are no longer needed as reviewers, remove them from Maintainers.txt

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants