From 9377d47f1a9d3f5cc9872f9e130aa36dec793c1a Mon Sep 17 00:00:00 2001 From: Michael Kubacki Date: Tue, 10 Nov 2020 20:59:07 +0000 Subject: [PATCH] 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 --- .../CapsuleUpdatePolicyDxe.inf | 4 +- FmpDevicePkg/FmpDxe/ReadMe.md | 105 ++++++++++++++ .../CapsuleUpdatePolicyLibNull.inf | 5 +- .../CapsuleUpdatePolicyLibOnProtocol.inf | 12 +- .../FmpDependencyCheckLib.inf | 5 + .../FmpDependencyLib/FmpDependencyLib.inf | 15 +- .../FmpDeviceLibNull/FmpDeviceLibNull.inf | 4 +- FmpDevicePkg/Readme.md | 132 ++++++++++++++++++ 8 files changed, 273 insertions(+), 9 deletions(-) create mode 100644 FmpDevicePkg/FmpDxe/ReadMe.md create mode 100644 FmpDevicePkg/Readme.md diff --git a/FmpDevicePkg/CapsuleUpdatePolicyDxe/CapsuleUpdatePolicyDxe.inf b/FmpDevicePkg/CapsuleUpdatePolicyDxe/CapsuleUpdatePolicyDxe.inf index 5ed7086b91..98981e5847 100644 --- a/FmpDevicePkg/CapsuleUpdatePolicyDxe/CapsuleUpdatePolicyDxe.inf +++ b/FmpDevicePkg/CapsuleUpdatePolicyDxe/CapsuleUpdatePolicyDxe.inf @@ -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.
# diff --git a/FmpDevicePkg/FmpDxe/ReadMe.md b/FmpDevicePkg/FmpDxe/ReadMe.md new file mode 100644 index 0000000000..582dae91b5 --- /dev/null +++ b/FmpDevicePkg/FmpDxe/ReadMe.md @@ -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. diff --git a/FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf b/FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf index db0355ff7c..f0e50ab142 100644 --- a/FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf +++ b/FmpDevicePkg/Library/CapsuleUpdatePolicyLibNull/CapsuleUpdatePolicyLibNull.inf @@ -1,7 +1,10 @@ ## @file # Provides platform policy services used during a capsule update. # -# Copyright (c) 2016, Microsoft Corporation. All rights reserved.
+# This is a NULL instance used for building when an actual instance +# is not needed. +# +# Copyright (c) Microsoft Corporation.
# Copyright (c) 2018, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent diff --git a/FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf b/FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf index 73555e8fd8..f988e0a0cd 100644 --- a/FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf +++ b/FmpDevicePkg/Library/CapsuleUpdatePolicyLibOnProtocol/CapsuleUpdatePolicyLibOnProtocol.inf @@ -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.
+# 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.
# Copyright (c) 2018-2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent diff --git a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf index 0fea2cbe15..f91fc6dddd 100644 --- a/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf +++ b/FmpDevicePkg/Library/FmpDependencyCheckLib/FmpDependencyCheckLib.inf @@ -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.
# # SPDX-License-Identifier: BSD-2-Clause-Patent diff --git a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf index ea403142f2..c9fc0bb15c 100644 --- a/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf +++ b/FmpDevicePkg/Library/FmpDependencyLib/FmpDependencyLib.inf @@ -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.
# diff --git a/FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf b/FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf index 2a0d8891d0..c8294b3066 100644 --- a/FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf +++ b/FmpDevicePkg/Library/FmpDeviceLibNull/FmpDeviceLibNull.inf @@ -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.
+# This is a NULL instance used for building when an actual instance is not needed. +# +# Copyright (c) Microsoft Corporation.
# Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.
# # SPDX-License-Identifier: BSD-2-Clause-Patent diff --git a/FmpDevicePkg/Readme.md b/FmpDevicePkg/Readme.md new file mode 100644 index 0000000000..4cee9b58d9 --- /dev/null +++ b/FmpDevicePkg/Readme.md @@ -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)