FmpDevicePkg: Improve library documentation

Adds a ReadMe.md to each library instance and updates
FmpDevicePkg_ReadMe.md to reference available library
documentation.

Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
This commit is contained in:
Michael Kubacki 2020-11-10 20:59:07 +00:00
parent 82cfea329c
commit 9377d47f1a
8 changed files with 273 additions and 9 deletions

View file

@ -1,6 +1,6 @@
## @file
# Produce the Capsule Update Policy Protocol using the services of the Capsule
# Update Policy Library.
# Produce the Capsule Update Policy Protocol (EDKII_CAPSULE_UPDATE_POLICY_PROTOCOL) using
# the services of the Capsule Update Policy Library.
#
# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
#

View file

@ -0,0 +1,105 @@
# Firmware Management Protocol (FMP) DXE
For an overview of how FmpDxe fits into the overall FmpDevicePkg architecture, including capsule authentication, capsule
versioning, device-specific dispatch, dependency evaluation, and update policy, see
[FmpDevicePkg/Docs/FmpDevicePkg_ReadMe.md](../Docs/FmpDevicePkg_ReadMe.md).
This document tracks impactful design changes to FmpDxe for the benefit of capsule implementers and platform integrators
to see when and why these changes were made.
---
## Design Changes
- **Date:** 07/20/2026
- **Description/Rationale:** PopulateDescriptor () previously read the FmpControllerState NV variable multiple times
per call through several getters such as GetVersionFromVariable () and GetLowestSupportedVersionFromVariable (),
each independently invoking GetFmpControllerState (). This caused redundant GetVariable () calls and repeated
failed-read debug messages when the variable did not yet exist.
- **Changes:** The getter functions were renamed (for example, to GetVersionFromFmpControllerState ()) and
simplified to pure field extractors that operate on a FMP_CONTROLLER_STATE pointer supplied by the caller instead of
independently reading the variable. PopulateDescriptor () now calls GetFmpControllerState () once, passes the result
to each getter, and frees it after the last use.
- **Impact/Mitigation:**
This is an internal implementation change local to FmpDxe. It does not modify the FmpDeviceLib, FmpDependencyLib,
FmpDependencyCheckLib, FmpDependencyDeviceLib, or CapsuleUpdatePolicyLib APIs, so existing library instances are
unaffected.
---
- **Date:** 09/24/2025
- **Description/Rationale:** XDR-encoded certificate list handling in FmpDxe assumed the PublicKeyDataXdr buffer
(populated from PcdFmpDevicePkcs7CertBufferXdr) is 4-byte aligned, which is not always the case. For example, if
PublicKeyDataXdr = 0x02 and a certificate's length is 0x05, the correct offset to the next certificate is
0x2 + align_up (0x5, 4) = 0xA, but the prior logic computed align_up (0x2 + 0x5, 4) = 0x8.
- **Changes:** The offset calculation used to walk the XDR-encoded certificate list was corrected to align up each
certificate's length independently rather than aligning the running (potentially already unaligned) offset.
- **Impact/Mitigation:**
Platforms that supply a PcdFmpDevicePkcs7CertBufferXdr value containing more than one certificate, where an earlier
certificate's length is not a multiple of 4 bytes, will see corrected certificate parsing behavior.
---
- **Date:** 01/20/2022
- **Description/Rationale:** CheckTheImageInternal () did not force ImageUpdatable to an invalid value when
FmpDeviceCheckImageWithStatus () returned an error but left ImageUpdatable set to IMAGE_UPDATABLE_VALID. In addition,
the FmpDeviceCheckImageWithStatus () LastAttemptStatus parameter description could be misread as meaning the value
is only inspected when the function returns an error.
- **Changes:** CheckTheImageInternal () now forces ImageUpdatable to IMAGE_UPDATABLE_INVALID if
FmpDeviceCheckImageWithStatus () returns an error, and only validates/converts the returned LastAttemptStatus value
when the image is not updatable so a valid LAST_ATTEMPT_STATUS_SUCCESS is not overwritten for an updatable image.
The API documentation for FmpDeviceCheckImageWithStatus () was updated to remove the sentence limiting
LastAttemptStatus inspection to error cases.
- **Impact/Mitigation:**
FmpDeviceLib instances should always set LastAttemptStatus to a value in the designated range (or
LAST_ATTEMPT_STATUS_SUCCESS) whenever FmpDeviceCheckImageWithStatus () is called, not only when it returns an error.
---
- **Date:** 10/26/2021
- **Description/Rationale:** FmpDxe used the deprecated EDKII_VARIABLE_LOCK_PROTOCOL (RequestToLock ()) to lock its
NV variables.
- **Changes:** FmpDxe was updated to lock its NV variables using EDKII_VARIABLE_POLICY_PROTOCOL and
RegisterBasicVariablePolicy () from the new VariablePolicyHelperLib dependency. The module Depex was intended to
change from gEdkiiVariableLockProtocolGuid to gEdkiiVariablePolicyProtocolGuid at the same time. This was missed and
corrected in a follow-up fix on 07/09/2024.
- **Impact/Mitigation:**
Platforms must produce gEdkiiVariablePolicyProtocolGuid for FmpDxe to start. Platforms that only produce the
deprecated gEdkiiVariableLockProtocolGuid protocol will need to update their variable services accordingly.
---
- **Date:** 06/15/2020
- **Description/Rationale:** Extending on the more granular LastAttemptStatus support added in FmpDeviceSetImage (),
FmpDeviceCheckImage () also has a LastAttemptStatus parameter added. An image check is always performed by a set
image operation. A more granular status code from the check image path greatly improves overall error isolation when
applying an image.
- **Changes:** This change allows the FmpDeviceLib implementation to return a last attempt status code in the range
LAST_ATTEMPT_STATUS_LIBRARY_ERROR_MIN_ERROR_CODE to LAST_ATTEMPT_STATUS_LIBRARY_ERROR_MAX_ERROR_CODE. Furthermore,
an internal wrapper for CheckTheImage () in FmpDxe was added called CheckTheImageInternal (). This function can return
a last attempt status code for an error in the driver prior to invoking FmpDeviceCheckImage (). These driver error
codes will be in the range of LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL_VENDOR_RANGE_MIN to
LAST_ATTEMPT_STATUS_DRIVER_ERROR_MAX_ERROR_CODE.
- **Impact/Mitigation:**
The change break the build for all FmpDeviceLib instances due to the API change. Each FmpDeviceLib should change to
the new API definition and implement support to return unique values for LastAttemptStatus when appropriate.
---
- **Date:** 10/07/2019
- **Description/Rationale:** Capsule update is the process where each OEM has a lot of interest. Especially when there
is capsule update failure, it is helpful to gather more information of the failure. With existing implementations, the
SetImage routine from FmpDxe driver, which performs most heavy lifting during capsule update, will only
populate LastAttemptStatus with limited pre-defined error codes which could be consumed/inspected by the OS when it
recovers and boots. Thus our proposal is to update the SetImage routine and leverage the
LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL_VENDOR_RANGE range newly defined in UEFI Spec 2.8 Section 23.4, so that the
error code will provide better granularity when viewing capsule update failure from OS device manager.
- **Changes:** A few error codes (128 total) are reserved from LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL_VENDOR_RANGE
range for FmpDxe driver usage, which ranges from thermal and power API failure to capsule payload header check failure.
Furthermore, *an output pointer of the LastAttemptStatus is added as an input argument for FmpDeviceSetImage function
in FmpDeviceLib to allow platform to provide their own platform specific error codes*.
(SPI write failure, SVN checking failure, and more).
- **Impact/Mitigation:**
The italic text above will cause a breaking change for all the FmpDeviceLib instances due to API being modified. This
is to provide better visibility to OEMs to decode capsule update failures more efficiently. Each FmpDeviceLib should
change to the new API definition and populate proper LastAttemptStatus values when applicable.

View file

@ -1,7 +1,10 @@
## @file
# Provides platform policy services used during a capsule update.
#
# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
# This is a NULL instance used for building when an actual instance
# is not needed.
#
# Copyright (c) Microsoft Corporation.<BR>
# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

View file

@ -1,10 +1,14 @@
## @file
# Provides platform policy services used during a capsule update that uses the
# services of the EDKII_CAPSULE_UPDATE_POLICY_PROTOCOL. If the
# EDKII_CAPSULE_UPDATE_POLICY_PROTOCOL is not available, then assume the
# platform is in a state that supports a firmware update.
# services of the EDKII_CAPSULE_UPDATE_POLICY_PROTOCOL.
#
# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
# If the protocol is not found, CheckSystemPower(), CheckSystemThermal(),
# and CheckSystemEnvironment() assume the platform state supports a
# capsule update, while IsLowestSupportedVersionCheckRequired() and
# IsLockFmpDeviceAtLockEventGuidRequired() default to TRUE so the lowest
# supported version check and FMP device locking are still performed.
#
# Copyright (c) Microsoft Corporation.<BR>
# Copyright (c) 2018-2019, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

View file

@ -2,6 +2,11 @@
# Provides FMP capsule dependency check services when updating the firmware
# image of a FMP device.
#
# This library locates each installed Firmware Management Protocol
# instance, collects its image type and version, and uses
# FmpDependencyLib to evaluate the dependency expression associated with
# the firmware image being updated.
#
# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

View file

@ -1,5 +1,18 @@
## @file
# Provides Fmp Capsule Dependency Expression support.
# Provides FMP Capsule Dependency Expression support.
#
# This library validates a dependency expression, extracts a dependency
# expression from a firmware image, and evaluates a dependency expression
# against the versions of other installed Firmware Management Protocol
# instances.
#
# A dependency expression is a byte stream of opcodes, as defined by the
# FMP capsule dependency format in the UEFI Specification. EvaluateDependency()
# in this library walks this byte stream and, when it encounters a PUSH_GUID
# opcode, requires the caller to have supplied the matching FMP instance's
# ImageTypeId and Version in the FmpVersions array. If a PUSH_GUID opcode refers
# to an FMP instance that is not present in FmpVersions, the dependency expression
# evaluates to FALSE.
#
# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
#

View file

@ -2,7 +2,9 @@
# Provides firmware device specific services to support updates of a firmware
# image stored in a firmware device.
#
# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
# This is a NULL instance used for building when an actual instance is not needed.
#
# Copyright (c) Microsoft Corporation.<BR>
# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
#
# SPDX-License-Identifier: BSD-2-Clause-Patent

132
FmpDevicePkg/Readme.md Normal file
View file

@ -0,0 +1,132 @@
# Firmware Management Protocol (FMP) Device Package
FmpDevicePkg provides the common resources necessary to manage the firmware on a given device. The
[UEFI Specification](https://uefi.org/specifications) defines several elements used in the firmware management process
that are implemented or depended upon in FmpDevicePkg such as:
1. [`EFI_FIRMWARE_MANAGEMENT_PROTOCOL`](https://github.com/tianocore/edk2/blob/HEAD/MdePkg/Include/Protocol/FirmwareManagement.h)
2. Firmware Management Protocol dependency expression support
3. FMP capsule format
4. EFI System Resource Table (ESRT)
## Architecture
`FmpDxe` is the central driver in `FmpDevicePkg`. It produces the Firmware Management Protocol
(`EFI_FIRMWARE_MANAGEMENT_PROTOCOL`) and coordinates with the supporting modules and libraries listed later in this
document to carry out a firmware update. This section describes the high level design of that update flow.
### Capsule Authentication
The firmware update capsule must be signed. FmpDxe verifies the integrity of the capsule contents. The
actual capsule data is preceded by an `EFI_FIRMWARE_IMAGE_AUTHENTICATION` structure. This structure contains a
monotonic count and a `WIN_CERTIFICATE_UEFI_GUID` member that contains a signature that covers both the monotonic
count and the capsule payload data. These two elements ensure replay protection across update operations and
authentication. The certificate type used must be `EFI_CERT_TYPE_PKCS7_GUID`.
An EDK II implementation of signature verification is available in the following `FmpAuthenticationLib` instance:
[SecurityPkg/Library/FmpAuthenticationLibPkcs7](https://github.com/tianocore/edk2/tree/master/SecurityPkg/Library/FmpAuthenticationLibPkcs7).
### Capsule Versioning
The capsule version should only be allowed to increment in value across updates to prevent rollback attacks. The
`EFI_FIRMWARE_IMAGE_DESCRIPTOR` structure contains `Version` and `LowestSupportedImageVersion` fields that are used
to check for compliance during firmware update. `Version` must be greater than or equal to `LowestSupportedImageVersion`
in the current firmware and greater than `Version` of the current firmware.
`FmpDxe` performs this check directly. The value used for `LowestSupportedImageVersion` is the greatest of the
build-time `PcdFmpDeviceBuildTimeLowestSupportedVersion` PCD value, the value returned by the `FmpDeviceLib`
instance's `FmpDeviceGetLowestSupportedVersion()` function, and the lowest supported version most recently saved
from an applied capsule's FMP Payload Header.
### Device-Specific Functionality During Update
A capsule can target firmware update to a diverse set of devices on a system. Each device might bring unique logic
and requirements to the firmware update process. Therefore, a library class called `FmpDeviceLib` exists that allows
for instances written specific to a particular device.
### Dependency Considerations
The UEFI Specification 2.8 version introduced support for expressing dependencies between components involved in a
capsule update. For instance, FW`x` can require FW`y` to be at least version 2.0 to install. This information is
primarily conveyed to `FmpDxe` through the `FmpDependencyCheckLib` and `FmpDependencyLib` library classes.
More information about the overall infrastructure is available in:
- The [UEFI Specification](https://uefi.org/specifications) - "Firmware Update and Reporting" section.
- [TianoCore Wiki: FMP Capsule Dependency Introduction](https://www.tianocore.org/tianocore-wiki.github.io/development/tutorials-howto/fmp_capsule_dependency_introduction.html)
### Update Policy
A library class (`CapsuleUpdatePolicyLib`) is used to make platform-specific policy decisions available to the
firmware update process. This includes information such as whether the system power/thermal state permits firmware
to be updated. A few functions also exist to modify expected behavior such as ignoring the
`LowestSupportedImageVersion` check or not locking the firmware device for update when the FMP lock event is signaled.
It is important to note that the latter functions should only be used in very rare special cases such as during
manufacturing flows.
## Package Organization
This section briefly describes the package modules and libraries.
### Modules
1. **CapsuleUpdatePolicyDxe**
- **Purpose:** Produces the Capsule Update Policy Protocol using the services of the Capsule Update Policy Library.
2. **FmpDxe** [readme](FmpDxe/Readme.md)
- **Purpose:** Produces an instance of the Firmware Management Protocol (`EFI_FIRMWARE_MANAGEMENT_PROTOCOL`) that is
used to support updates to a firmware image stored on a firmware device
### Libraries
1. **CapsuleUpdatePolicyLib**
- **Purpose:** Provides platform policy services used during a capsule update.
- **Instances:**
1. CapsuleUpdatePolicyLibNull
2. CapsuleUpdatePolicyLibOnProtocol
2. **FmpDependencyCheckLib**
- **Purpose:** Provides services to check that capsule dependencies are met during firmware update.
- **Instances:**
1. FmpDependencyCheckLib
2. FmpDependencyCheckLibNull
3. **FmpDependencyDeviceLib**
- **Purpose:** Provides firmware device specific services to support saving dependency expressions to a firmware
device and getting dependency expressions from a firmware device.
- **Instances:**
1. FmpDependencyDeviceLibNull
4. **FmpDependencyLib**
- **Purpose:** Provides functions used to manage dependencies between firmware components during the update of device firmware
images.
- **Instances:**
1. FmpDependencyLib
5. **FmpDeviceLib**
- **Purpose:** Provides firmware device specific services to support firmware updates on a given device.
- **Instances:**
1. FmpDeviceLibNull
6. **FmpPayloadHeaderLib**
- **Purpose:** Provides services to retrieve values from a capsule FMP Payload Header.
- **Instances:**
1. FmpPayloadHeaderLibV1
## Further Reading
Several documents describe important elements involved in understanding `FmpDevicePkg`. Consult the following
resource for more information on a particular topic.
1. `FmpDevicePkg` Overview
1. The Readme documents in this package.
2. [TianoCore Wiki: FmpDevicePkg](https://www.tianocore.org/tianocore-wiki.github.io/platforms-packages/core-packages/fmp_device_pkg.html)
2. UEFI Specification Definitions for Firmware Updating and Reporting
1. [UEFI Specification - Firmware Update and Reporting](https://uefi.org/specifications)
3. Technical Overview of the EDK II Capsule Update and Recovery Flow
1. [A Tour Beyond BIOS - Capsule Update and Recovery in EDK II](https://github.com/tianocore-docs/Docs/blob/master/White_Papers/A_Tour_Beyond_BIOS_Capsule_Update_and_Recovery_in_EDK_II.pdf)
4. Windows UEFI Firmware Update Resources
1. [Windows UEFI Firmware Update Platform](https://docs.microsoft.com/windows-hardware/drivers/bringup/windows-uefi-firmware-update-platform)
2. [Validating Windows UEFI Firmware Update Platform Functionality](https://docs.microsoft.com/windows-hardware/manufacture/desktop/validating-windows-uefi-firmware-update-platform-functionality)
5. NIST Guidelines for Authenticated Firmware Update
1. [SP800-147](https://nvlpubs.nist.gov/nistpubs/Legacy/SP/nistspecialpublication800-147.pdf)
2. [SP800-147B](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-147B.pdf)
3. [SP800-193](https://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-193.pdf)