summaryrefslogtreecommitdiffstats
path: root/FmpDevicePkg/FmpDxe
diff options
context:
space:
mode:
Diffstat (limited to 'FmpDevicePkg/FmpDxe')
-rw-r--r--FmpDevicePkg/FmpDxe/DetectTestKey.c166
-rw-r--r--FmpDevicePkg/FmpDxe/FmpDxe.c1452
-rw-r--r--FmpDevicePkg/FmpDxe/FmpDxe.inf93
-rw-r--r--FmpDevicePkg/FmpDxe/FmpDxe.uni20
-rw-r--r--FmpDevicePkg/FmpDxe/FmpDxeExtra.uni18
-rw-r--r--FmpDevicePkg/FmpDxe/FmpDxeLib.inf90
-rw-r--r--FmpDevicePkg/FmpDxe/VariableSupport.c461
-rw-r--r--FmpDevicePkg/FmpDxe/VariableSupport.h180
8 files changed, 2480 insertions, 0 deletions
diff --git a/FmpDevicePkg/FmpDxe/DetectTestKey.c b/FmpDevicePkg/FmpDxe/DetectTestKey.c
new file mode 100644
index 0000000000..0a6e37eded
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/DetectTestKey.c
@@ -0,0 +1,166 @@
+/** @file
+ Detects if PcdFmpDevicePkcs7CertBufferXdr contains a test key.
+
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseCryptLib.h>
+
+/**
+ Check to see if any of the keys in PcdFmpDevicePkcs7CertBufferXdr matches
+ the test key. PcdFmpDeviceTestKeySha256Digest contains the SHA256 hash of
+ the test key. For each key in PcdFmpDevicePkcs7CertBufferXdr, compute the
+ SHA256 hash and compare it to PcdFmpDeviceTestKeySha256Digest. If the
+ SHA256 hash matches or there is then error computing the SHA256 hash, then
+ set PcdTestKeyUsed to TRUE. Skip this check if PcdTestKeyUsed is already
+ TRUE or PcdFmpDeviceTestKeySha256Digest is not exactly SHA256_DIGEST_SIZE
+ bytes.
+**/
+VOID
+DetectTestKey (
+ VOID
+ )
+{
+ BOOLEAN TestKeyUsed;
+ UINTN PublicKeyDataLength;
+ UINT8 *PublicKeyDataXdr;
+ UINT8 *PublicKeyDataXdrEnd;
+ VOID *HashContext;
+ UINT8 Digest[SHA256_DIGEST_SIZE];
+
+ //
+ // If PcdFmpDeviceTestKeySha256Digest is not exacty SHA256_DIGEST_SIZE bytes,
+ // then skip the test key detection.
+ //
+ if (PcdGetSize (PcdFmpDeviceTestKeySha256Digest) != SHA256_DIGEST_SIZE) {
+ return;
+ }
+
+ //
+ // If PcdTestKeyUsed is already TRUE, then skip test key detection
+ //
+ TestKeyUsed = PcdGetBool (PcdTestKeyUsed);
+ if (TestKeyUsed) {
+ return;
+ }
+
+ //
+ // If PcdFmpDevicePkcs7CertBufferXdr is invalid, then skip test key detection
+ //
+ PublicKeyDataXdr = PcdGetPtr (PcdFmpDevicePkcs7CertBufferXdr);
+ PublicKeyDataXdrEnd = PublicKeyDataXdr + PcdGetSize (PcdFmpDevicePkcs7CertBufferXdr);
+ if (PublicKeyDataXdr == NULL || PublicKeyDataXdr == PublicKeyDataXdrEnd) {
+ return;
+ }
+
+ //
+ // Allocate hash context buffer required for SHA 256
+ //
+ HashContext = AllocatePool (Sha256GetContextSize ());
+ if (HashContext == NULL) {
+ TestKeyUsed = TRUE;
+ }
+
+ //
+ // Loop through all keys in PcdFmpDevicePkcs7CertBufferXdr
+ //
+ while (!TestKeyUsed && PublicKeyDataXdr < PublicKeyDataXdrEnd) {
+ if (PublicKeyDataXdr + sizeof (UINT32) > PublicKeyDataXdrEnd) {
+ //
+ // Key data extends beyond end of PCD
+ //
+ break;
+ }
+ //
+ // Read key length stored in big endian format
+ //
+ PublicKeyDataLength = SwapBytes32 (*(UINT32 *)(PublicKeyDataXdr));
+ //
+ // Point to the start of the key data
+ //
+ PublicKeyDataXdr += sizeof (UINT32);
+ if (PublicKeyDataXdr + PublicKeyDataLength > PublicKeyDataXdrEnd) {
+ //
+ // Key data extends beyond end of PCD
+ //
+ break;
+ }
+
+ //
+ // Hash public key from PcdFmpDevicePkcs7CertBufferXdr using SHA256.
+ // If error occurs computing SHA256, then assume test key is in use.
+ //
+ ZeroMem (Digest, SHA256_DIGEST_SIZE);
+ if (!Sha256Init (HashContext)) {
+ TestKeyUsed = TRUE;
+ break;
+ }
+ if (!Sha256Update (HashContext, PublicKeyDataXdr, PublicKeyDataLength)) {
+ TestKeyUsed = TRUE;
+ break;
+ }
+ if (!Sha256Final (HashContext, Digest)) {
+ TestKeyUsed = TRUE;
+ break;
+ }
+
+ //
+ // Check if SHA256 hash of public key matches SHA256 hash of test key
+ //
+ if (CompareMem (Digest, PcdGetPtr (PcdFmpDeviceTestKeySha256Digest), SHA256_DIGEST_SIZE) == 0) {
+ TestKeyUsed = TRUE;
+ break;
+ }
+
+ //
+ // Point to start of next key
+ //
+ PublicKeyDataXdr += PublicKeyDataLength;
+ PublicKeyDataXdr = (UINT8 *)ALIGN_POINTER (PublicKeyDataXdr, sizeof (UINT32));
+ }
+
+ //
+ // Free hash context buffer required for SHA 256
+ //
+ if (HashContext != NULL) {
+ FreePool (HashContext);
+ HashContext = NULL;
+ }
+
+ //
+ // If test key detected or an error occured checking for the test key, then
+ // set PcdTestKeyUsed to TRUE.
+ //
+ if (TestKeyUsed) {
+ DEBUG ((DEBUG_INFO, "FmpDxe: Test key detected in PcdFmpDevicePkcs7CertBufferXdr.\n"));
+ PcdSetBoolS (PcdTestKeyUsed, TRUE);
+ } else {
+ DEBUG ((DEBUG_INFO, "FmpDxe: No test key detected in PcdFmpDevicePkcs7CertBufferXdr.\n"));
+ }
+}
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c
new file mode 100644
index 0000000000..b709bc282a
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.c
@@ -0,0 +1,1452 @@
+/** @file
+ Produces a Firmware Management Protocol that supports updates to a firmware
+ image stored in a firmware device with platform and firmware device specific
+ information provided through PCDs and libraries.
+
+ Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/FmpAuthenticationLib.h>
+#include <Library/FmpDeviceLib.h>
+#include <Library/FmpPayloadHeaderLib.h>
+#include <Library/CapsuleUpdatePolicyLib.h>
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/FirmwareManagementProgress.h>
+#include <Guid/SystemResourceTable.h>
+#include <Guid/EventGroup.h>
+#include "VariableSupport.h"
+
+#define VERSION_STRING_NOT_SUPPORTED L"VERSION STRING NOT SUPPORTED"
+#define VERSION_STRING_NOT_AVAILABLE L"VERSION STRING NOT AVAILABLE"
+
+/**
+ Check to see if any of the keys in PcdFmpDevicePkcs7CertBufferXdr matches
+ the test key. PcdFmpDeviceTestKeySha256Digest contains the SHA256 hash of
+ the test key. For each key in PcdFmpDevicePkcs7CertBufferXdr, compute the
+ SHA256 hash and compare it to PcdFmpDeviceTestKeySha256Digest. If the
+ SHA256 hash matches or there is then error computing the SHA256 hash, then
+ set PcdTestKeyUsed to TRUE. Skip this check if PcdTestKeyUsed is already
+ TRUE or PcdFmpDeviceTestKeySha256Digest is not exactly SHA256_DIGEST_SIZE
+ bytes.
+**/
+VOID
+DetectTestKey (
+ VOID
+ );
+
+///
+/// FILE_GUID from FmpDxe.inf. When FmpDxe.inf is used in a platform, the
+/// FILE_GUID must always be overridden in the <Defines> section to provide
+/// the ESRT GUID value associated with the updatable firmware image. A
+/// check is made in this module's driver entry point to verify that a
+/// new FILE_GUID value has been defined.
+///
+const EFI_GUID mDefaultModuleFileGuid = {
+ 0x78ef0a56, 0x1cf0, 0x4535, { 0xb5, 0xda, 0xf6, 0xfd, 0x2f, 0x40, 0x5a, 0x11 }
+};
+
+EFI_FIRMWARE_IMAGE_DESCRIPTOR mDesc;
+BOOLEAN mDescriptorPopulated = FALSE;
+BOOLEAN mRuntimeVersionSupported = TRUE;
+BOOLEAN mFmpInstalled = FALSE;
+
+///
+/// Function pointer to progress function
+///
+EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS mProgressFunc = NULL;
+BOOLEAN mProgressSupported = FALSE;
+
+CHAR16 *mImageIdName = NULL;
+UINT64 mImageId = 0x1;
+CHAR16 *mVersionName = NULL;
+
+EFI_EVENT mFmpDeviceLockEvent;
+BOOLEAN mFmpDeviceLocked = FALSE;
+
+/**
+ Callback function to report the process of the firmware updating.
+
+ Wrap the caller's version in this so that progress from the device lib is
+ within the expected range. Convert device lib 0% - 100% to 6% - 98%.
+
+ FmpDxe 1% - 5% for validation
+ FmpDeviceLib 6% - 98% for flashing/update
+ FmpDxe 99% - 100% finish
+
+ @param[in] Completion A value between 1 and 100 indicating the current
+ completion progress of the firmware update. Completion
+ progress is reported as from 1 to 100 percent. A value
+ of 0 is used by the driver to indicate that progress
+ reporting is not supported.
+
+ @retval EFI_SUCCESS The progress was updated.
+ @retval EFI_UNSUPPORTED Updating progress is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDxeProgress (
+ IN UINTN Completion
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_UNSUPPORTED;
+
+ if (!mProgressSupported) {
+ return Status;
+ }
+
+ if (mProgressFunc == NULL) {
+ return Status;
+ }
+
+ //
+ // Reserve 6% - 98% for the FmpDeviceLib. Call the real progress function.
+ //
+ Status = mProgressFunc (((Completion * 92) / 100) + 6);
+
+ if (Status == EFI_UNSUPPORTED) {
+ mProgressSupported = FALSE;
+ mProgressFunc = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Returns a pointer to the ImageTypeId GUID value. An attempt is made to get
+ the GUID value from the FmpDeviceLib. If the FmpDeviceLib does not provide
+ a GUID value, then gEfiCallerIdGuid is returned.
+
+ @return The ImageTypeId GUID
+
+**/
+EFI_GUID *
+GetImageTypeIdGuid (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *FmpDeviceLibGuid;
+
+ FmpDeviceLibGuid = NULL;
+ Status = FmpDeviceGetImageTypeIdGuidPtr (&FmpDeviceLibGuid);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_UNSUPPORTED) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid error %r\n", Status));
+ }
+ return &gEfiCallerIdGuid;
+ }
+ if (FmpDeviceLibGuid == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib GetImageTypeIdGuidPtr() returned invalid GUID\n"));
+ return &gEfiCallerIdGuid;
+ }
+ return FmpDeviceLibGuid;
+}
+
+/**
+ Returns a pointer to the Null-terminated Unicode ImageIdName string.
+
+ @return Null-terminated Unicode ImageIdName string.
+
+**/
+CHAR16 *
+GetImageTypeNameString (
+ VOID
+ )
+{
+ return mImageIdName;
+}
+
+/**
+ Lowest supported version is a combo of three parts.
+ 1. Check if the device lib has a lowest supported version
+ 2. Check if we have a variable for lowest supported version (this will be updated with each capsule applied)
+ 3. Check Fixed at build PCD
+
+ Take the largest value
+
+**/
+UINT32
+GetLowestSupportedVersion (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 DeviceLibLowestSupportedVersion;
+ UINT32 VariableLowestSupportedVersion;
+ UINT32 ReturnLsv;
+
+ //
+ // Get the LowestSupportedVersion.
+ //
+
+ DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
+ ReturnLsv = PcdGet32 (PcdFmpDeviceBuildTimeLowestSupportedVersion);
+ if (!IsLowestSupportedVersionCheckRequired ()) {
+ return 1;
+ }
+
+ //
+ // Check the FmpDeviceLib
+ //
+ Status = FmpDeviceGetLowestSupportedVersion (&DeviceLibLowestSupportedVersion);
+ if (EFI_ERROR (Status)) {
+ DeviceLibLowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
+ }
+
+ if (DeviceLibLowestSupportedVersion > ReturnLsv) {
+ ReturnLsv = DeviceLibLowestSupportedVersion;
+ }
+
+ //
+ // Check the lowest supported version UEFI variable for this device
+ //
+ VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable();
+ if (VariableLowestSupportedVersion > ReturnLsv) {
+ ReturnLsv = VariableLowestSupportedVersion;
+ }
+
+ //
+ // Return the largest value
+ //
+ return ReturnLsv;
+}
+
+/**
+ Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the module global
+ variable mDesc.
+
+**/
+VOID
+PopulateDescriptor (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ mDesc.ImageIndex = 1;
+ CopyGuid (&mDesc.ImageTypeId, GetImageTypeIdGuid());
+ mDesc.ImageId = mImageId;
+ mDesc.ImageIdName = GetImageTypeNameString();
+
+ //
+ // Get the version. Some devices don't support getting the firmware version
+ // at runtime. If FmpDeviceLib does not support returning a version, then
+ // it is stored in a UEFI variable.
+ //
+ Status = FmpDeviceGetVersion (&mDesc.Version);
+ if (Status == EFI_UNSUPPORTED) {
+ mRuntimeVersionSupported = FALSE;
+ mDesc.Version = GetVersionFromVariable();
+ } else if (EFI_ERROR (Status)) {
+ //
+ // Unexpected error. Use default version.
+ //
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetVersion() from FmpDeviceLib (%s) returned %r\n", GetImageTypeNameString(), Status));
+ mDesc.Version = DEFAULT_VERSION;
+ }
+
+ //
+ // Free the current version name. Shouldn't really happen but this populate
+ // function could be called multiple times (to refresh).
+ //
+ if (mVersionName != NULL) {
+ FreePool (mVersionName);
+ mVersionName = NULL;
+ }
+
+ //
+ // Attempt to get the version string from the FmpDeviceLib
+ //
+ Status = FmpDeviceGetVersionString (&mVersionName);
+ if (Status == EFI_UNSUPPORTED) {
+ DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() unsupported in FmpDeviceLib.\n"));
+ mVersionName = AllocateCopyPool (
+ sizeof (VERSION_STRING_NOT_SUPPORTED),
+ VERSION_STRING_NOT_SUPPORTED
+ );
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() not available in FmpDeviceLib.\n"));
+ mVersionName = AllocateCopyPool (
+ sizeof (VERSION_STRING_NOT_AVAILABLE),
+ VERSION_STRING_NOT_AVAILABLE
+ );
+ }
+
+ mDesc.VersionName = mVersionName;
+
+ mDesc.LowestSupportedImageVersion = GetLowestSupportedVersion();
+
+ //
+ // Get attributes from the FmpDeviceLib
+ //
+ FmpDeviceGetAttributes (&mDesc.AttributesSupported, &mDesc.AttributesSetting);
+
+ //
+ // Force set the updatable bits in the attributes;
+ //
+ mDesc.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+ mDesc.AttributesSetting |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+
+ //
+ // Force set the authentication bits in the attributes;
+ //
+ mDesc.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+ mDesc.AttributesSetting |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+
+ mDesc.Compatibilities = 0;
+
+ //
+ // Get the size of the firmware image from the FmpDeviceLib
+ //
+ Status = FmpDeviceGetSize (&mDesc.Size);
+ if (EFI_ERROR (Status)) {
+ mDesc.Size = 0;
+ }
+
+ mDesc.LastAttemptVersion = GetLastAttemptVersionFromVariable ();
+ mDesc.LastAttemptStatus = GetLastAttemptStatusFromVariable ();
+
+ mDescriptorPopulated = TRUE;
+}
+
+/**
+ Returns information about the current firmware image(s) of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in, out] ImageInfoSize A pointer to the size, in bytes, of the ImageInfo buffer.
+ On input, this is the size of the buffer allocated by the caller.
+ On output, it is the size of the buffer returned by the firmware
+ if the buffer was large enough, or the size of the buffer needed
+ to contain the image(s) information if the buffer was too small.
+ @param[in, out] ImageInfo A pointer to the buffer in which firmware places the current image(s)
+ information. The information is an array of EFI_FIRMWARE_IMAGE_DESCRIPTORs.
+ @param[out] DescriptorVersion A pointer to the location in which firmware returns the version number
+ associated with the EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] DescriptorCount A pointer to the location in which firmware returns the number of
+ descriptors or firmware images within this device.
+ @param[out] DescriptorSize A pointer to the location in which firmware returns the size, in bytes,
+ of an individual EFI_FIRMWARE_IMAGE_DESCRIPTOR.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version comparison
+ is to be performed using PackageVersionName. A value of 0xFFFFFFFD indicates
+ that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing the
+ package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a call
+ to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The ImageInfo buffer was too small. The current buffer size
+ needed to hold the image(s) information is returned in ImageInfoSize.
+ @retval EFI_INVALID_PARAMETER ImageInfoSize is NULL.
+ @retval EFI_DEVICE_ERROR Valid information could not be returned. Possible corrupted image.
+
+**/
+EFI_STATUS
+EFIAPI
+GetTheImageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN OUT UINTN *ImageInfoSize,
+ IN OUT EFI_FIRMWARE_IMAGE_DESCRIPTOR *ImageInfo,
+ OUT UINT32 *DescriptorVersion,
+ OUT UINT8 *DescriptorCount,
+ OUT UINTN *DescriptorSize,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Check for valid pointer
+ //
+ if (ImageInfoSize == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - ImageInfoSize is NULL.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ //
+ // Check the buffer size
+ // NOTE: Check this first so caller can get the necessary memory size it must allocate.
+ //
+ if (*ImageInfoSize < (sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR))) {
+ *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+ DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImageInfo() - ImageInfoSize is to small.\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+
+ //
+ // Confirm that buffer isn't null
+ //
+ if ( (ImageInfo == NULL) || (DescriptorVersion == NULL) || (DescriptorCount == NULL) || (DescriptorSize == NULL)
+ || (PackageVersion == NULL)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetImageInfo() - Pointer Parameter is NULL.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ //
+ // Set the size to whatever we need
+ //
+ *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+
+
+ if (!mDescriptorPopulated) {
+ PopulateDescriptor();
+ }
+
+ //
+ // Copy the image descriptor
+ //
+ CopyMem (ImageInfo, &mDesc, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+
+ *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
+ *DescriptorCount = 1;
+ *DescriptorSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
+ //
+ // means unsupported
+ //
+ *PackageVersion = 0xFFFFFFFF;
+
+ //
+ // Do not update PackageVersionName since it is not supported in this instance.
+ //
+
+cleanup:
+
+ return Status;
+}
+
+/**
+ Retrieves a copy of the current firmware image of the device.
+
+ This function allows a copy of the current firmware image to be created and saved.
+ The saved copy could later been used, for example, in firmware image recovery or rollback.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[out] Image Points to the buffer where the current image is copied to.
+ @param[out] ImageSize On entry, points to the size of the buffer pointed to by Image, in bytes.
+ On return, points to the length of the image, in bytes.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_BUFFER_TOO_SMALL The buffer specified by ImageSize is too small to hold the
+ image. The current buffer size needed to hold the image is returned
+ in ImageSize.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_NOT_FOUND The current image is not copied to the buffer.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+GetTheImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN OUT VOID *Image,
+ IN OUT UINTN *ImageSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ Status = EFI_SUCCESS;
+
+ if ((ImageSize == NULL)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - ImageSize Pointer Parameter is NULL.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ //
+ // Check the buffer size
+ //
+ Status = FmpDeviceGetSize (&Size);
+ if (EFI_ERROR (Status)) {
+ Size = 0;
+ }
+ if (*ImageSize < Size) {
+ *ImageSize = Size;
+ DEBUG ((DEBUG_VERBOSE, "FmpDxe: GetImage() - ImageSize is to small.\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ goto cleanup;
+ }
+
+ if (Image == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Pointer Parameter is NULL.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ //
+ // Check to make sure index is 1 (only 1 image for this device)
+ //
+ if (ImageIndex != 1) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: GetImage() - Image Index Invalid.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+
+ Status = FmpDeviceGetImage (Image, ImageSize);
+cleanup:
+
+ return Status;
+}
+
+/**
+ Helper function to safely retrieve the FMP header from
+ within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.
+
+ @param[in] Image Pointer to the image.
+ @param[in] ImageSize Size of the image.
+ @param[out] PayloadSize
+
+ @retval !NULL Valid pointer to the header.
+ @retval NULL Structure is bad and pointer cannot be found.
+
+**/
+VOID *
+GetFmpHeader (
+ IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN CONST UINTN ImageSize,
+ OUT UINTN *PayloadSize
+ )
+{
+ //
+ // Check to make sure that operation can be safely performed.
+ //
+ if (((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) < (UINTN)Image || \
+ ((UINTN)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength) >= (UINTN)Image + ImageSize) {
+ //
+ // Pointer overflow. Invalid image.
+ //
+ return NULL;
+ }
+
+ *PayloadSize = ImageSize - (sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
+ return (VOID *)((UINT8 *)Image + sizeof (Image->MonotonicCount) + Image->AuthInfo.Hdr.dwLength);
+}
+
+/**
+ Helper function to safely calculate the size of all headers
+ within an EFI_FIRMWARE_IMAGE_AUTHENTICATION structure.
+
+ @param[in] Image Pointer to the image.
+ @param[in] AdditionalHeaderSize Size of any headers that cannot be calculated by this function.
+
+ @retval UINT32>0 Valid size of all the headers.
+ @retval 0 Structure is bad and size cannot be found.
+
+**/
+UINT32
+GetAllHeaderSize (
+ IN CONST EFI_FIRMWARE_IMAGE_AUTHENTICATION *Image,
+ IN UINT32 AdditionalHeaderSize
+ )
+{
+ UINT32 CalculatedSize;
+
+ CalculatedSize = sizeof (Image->MonotonicCount) +
+ AdditionalHeaderSize +
+ Image->AuthInfo.Hdr.dwLength;
+
+ //
+ // Check to make sure that operation can be safely performed.
+ //
+ if (CalculatedSize < sizeof (Image->MonotonicCount) ||
+ CalculatedSize < AdditionalHeaderSize ||
+ CalculatedSize < Image->AuthInfo.Hdr.dwLength ) {
+ //
+ // Integer overflow. Invalid image.
+ //
+ return 0;
+ }
+
+ return CalculatedSize;
+}
+
+/**
+ Checks if the firmware image is valid for the device.
+
+ This function allows firmware update application to validate the firmware image without
+ invoking the SetImage() first.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[out] ImageUpdatable Indicates if the new image is valid for update. It also provides,
+ if available, additional information if the image is invalid.
+
+ @retval EFI_SUCCESS The image was successfully checked.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+CheckTheImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ OUT UINT32 *ImageUpdateable
+ )
+{
+ EFI_STATUS Status;
+ UINTN RawSize;
+ VOID *FmpPayloadHeader;
+ UINTN FmpPayloadSize;
+ UINT32 Version;
+ UINT32 FmpHeaderSize;
+ UINTN AllHeaderSize;
+ UINT32 Index;
+ VOID *PublicKeyData;
+ UINTN PublicKeyDataLength;
+ UINT8 *PublicKeyDataXdr;
+ UINT8 *PublicKeyDataXdrEnd;
+
+ Status = EFI_SUCCESS;
+ RawSize = 0;
+ FmpPayloadHeader = NULL;
+ FmpPayloadSize = 0;
+ Version = 0;
+ FmpHeaderSize = 0;
+ AllHeaderSize = 0;
+
+ //
+ // make sure the descriptor has already been loaded
+ //
+ if (!mDescriptorPopulated) {
+ PopulateDescriptor();
+ }
+
+ if (ImageUpdateable == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - ImageUpdateable Pointer Parameter is NULL.\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ //
+ //Set to valid and then if any tests fail it will update this flag.
+ //
+ *ImageUpdateable = IMAGE_UPDATABLE_VALID;
+
+ if (Image == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Pointer Parameter is NULL.\n"));
+ //
+ // not sure if this is needed
+ //
+ *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ PublicKeyDataXdr = PcdGetPtr (PcdFmpDevicePkcs7CertBufferXdr);
+ PublicKeyDataXdrEnd = PublicKeyDataXdr + PcdGetSize (PcdFmpDevicePkcs7CertBufferXdr);
+
+ if (PublicKeyDataXdr == NULL || (PublicKeyDataXdr == PublicKeyDataXdrEnd)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Invalid certificate, skipping it.\n"));
+ Status = EFI_ABORTED;
+ } else {
+ //
+ // Try each key from PcdFmpDevicePkcs7CertBufferXdr
+ //
+ for (Index = 1; PublicKeyDataXdr < PublicKeyDataXdrEnd; Index++) {
+ Index++;
+ DEBUG (
+ (DEBUG_INFO,
+ "FmpDxe: Certificate #%d [%p..%p].\n",
+ Index,
+ PublicKeyDataXdr,
+ PublicKeyDataXdrEnd
+ )
+ );
+
+ if ((PublicKeyDataXdr + sizeof (UINT32)) > PublicKeyDataXdrEnd) {
+ //
+ // Key data extends beyond end of PCD
+ //
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate size extends beyond end of PCD, skipping it.\n"));
+ Status = EFI_ABORTED;
+ break;
+ }
+ //
+ // Read key length stored in big-endian format
+ //
+ PublicKeyDataLength = SwapBytes32 (*(UINT32 *)(PublicKeyDataXdr));
+ //
+ // Point to the start of the key data
+ //
+ PublicKeyDataXdr += sizeof (UINT32);
+ if (PublicKeyDataXdr + PublicKeyDataLength > PublicKeyDataXdrEnd) {
+ //
+ // Key data extends beyond end of PCD
+ //
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Certificate extends beyond end of PCD, skipping it.\n"));
+ Status = EFI_ABORTED;
+ break;
+ }
+ PublicKeyData = PublicKeyDataXdr;
+ Status = AuthenticateFmpImage (
+ (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image,
+ ImageSize,
+ PublicKeyData,
+ PublicKeyDataLength
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ PublicKeyDataXdr += PublicKeyDataLength;
+ PublicKeyDataXdr = (UINT8 *)ALIGN_POINTER (PublicKeyDataXdr, sizeof (UINT32));
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - Authentication Failed %r.\n", Status));
+ goto cleanup;
+ }
+
+ //
+ // Check to make sure index is 1
+ //
+ if (ImageIndex != 1) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - Image Index Invalid.\n"));
+ *ImageUpdateable = IMAGE_UPDATABLE_INVALID_TYPE;
+ Status = EFI_SUCCESS;
+ goto cleanup;
+ }
+
+
+ //
+ // Check the FmpPayloadHeader
+ //
+ FmpPayloadHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
+ if (FmpPayloadHeader == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpHeader failed.\n"));
+ Status = EFI_ABORTED;
+ goto cleanup;
+ }
+ Status = GetFmpPayloadHeaderVersion (FmpPayloadHeader, FmpPayloadSize, &Version);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderVersion failed %r.\n", Status));
+ *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
+ Status = EFI_SUCCESS;
+ goto cleanup;
+ }
+
+ //
+ // Check the lowest supported version
+ //
+ if (Version < mDesc.LowestSupportedImageVersion) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "FmpDxe: CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",
+ Version, mDesc.LowestSupportedImageVersion)
+ );
+ *ImageUpdateable = IMAGE_UPDATABLE_INVALID_OLD;
+ Status = EFI_SUCCESS;
+ goto cleanup;
+ }
+
+ //
+ // Get the FmpHeaderSize so we can determine the real payload size
+ //
+ Status = GetFmpPayloadHeaderSize (FmpPayloadHeader, FmpPayloadSize, &FmpHeaderSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));
+ *ImageUpdateable = IMAGE_UPDATABLE_INVALID;
+ Status = EFI_SUCCESS;
+ goto cleanup;
+ }
+
+ //
+ // Call FmpDevice Lib Check Image on the
+ // Raw payload. So all headers need stripped off
+ //
+ AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );
+ if (AllHeaderSize == 0) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - GetAllHeaderSize failed.\n"));
+ Status = EFI_ABORTED;
+ goto cleanup;
+ }
+ RawSize = ImageSize - AllHeaderSize;
+
+ //
+ // FmpDeviceLib CheckImage function to do any specific checks
+ //
+ Status = FmpDeviceCheckImage ((((UINT8 *)Image) + AllHeaderSize), RawSize, ImageUpdateable);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: CheckTheImage() - FmpDeviceLib CheckImage failed. Status = %r\n", Status));
+ }
+
+cleanup:
+ return Status;
+}
+
+/**
+ Updates the firmware image of the device.
+
+ This function updates the hardware with the new firmware image.
+ This function returns EFI_UNSUPPORTED if the firmware image is not updatable.
+ If the firmware image is updatable, the function should perform the following minimal validations
+ before proceeding to do the firmware image update.
+ - Validate the image authentication if image has attribute
+ IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns
+ EFI_SECURITY_VIOLATION if the validation fails.
+ - Validate the image is a supported image for this device. The function returns EFI_ABORTED if
+ the image is unsupported. The function can optionally provide more detailed information on
+ why the image is not a supported image.
+ - Validate the data from VendorCode if not null. Image validation must be performed before
+ VendorCode data validation. VendorCode data is ignored or considered invalid if image
+ validation failed. The function returns EFI_ABORTED if the data is invalid.
+
+ VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if
+ the caller did not specify the policy or use the default policy. As an example, vendor can implement
+ a policy to allow an option to force a firmware image update when the abort reason is due to the new
+ firmware image version is older than the current firmware image version or bad image checksum.
+ Sensitive operations such as those wiping the entire firmware image and render the device to be
+ non-functional should be encoded in the image itself rather than passed with the VendorCode.
+ AbortReason enables vendor to have the option to provide a more detailed description of the abort
+ reason to the caller.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] ImageIndex A unique number identifying the firmware image(s) within the device.
+ The number is between 1 and DescriptorCount.
+ @param[in] Image Points to the new image.
+ @param[in] ImageSize Size of the new image in bytes.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware image update policy.
+ Null indicates the caller did not specify the policy or use the default policy.
+ @param[in] Progress A function used by the driver to report the progress of the firmware update.
+ @param[out] AbortReason A pointer to a pointer to a null-terminated string providing more
+ details for the aborted operation. The buffer is allocated by this function
+ with AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+
+ @retval EFI_SUCCESS The device was successfully updated with the new image.
+ @retval EFI_ABORTED The operation is aborted.
+ @retval EFI_INVALID_PARAMETER The Image was NULL.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+SetTheImage (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN UINT8 ImageIndex,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS Progress,
+ OUT CHAR16 **AbortReason
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Updateable;
+ BOOLEAN BooleanValue;
+ UINT32 FmpHeaderSize;
+ VOID *FmpHeader;
+ UINTN FmpPayloadSize;
+ UINT32 AllHeaderSize;
+ UINT32 IncommingFwVersion;
+ UINT32 LastAttemptStatus;
+
+ Status = EFI_SUCCESS;
+ Updateable = 0;
+ BooleanValue = FALSE;
+ FmpHeaderSize = 0;
+ FmpHeader = NULL;
+ FmpPayloadSize = 0;
+ AllHeaderSize = 0;
+ IncommingFwVersion = 0;
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
+
+
+ SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear any previous results.
+
+ //
+ // if we have locked the device, then skip the set operation.
+ // it should be blocked by hardware too but we can catch here even faster
+ //
+ if (mFmpDeviceLocked) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Device is already locked. Can't update.\n"));
+ Status = EFI_ACCESS_DENIED;
+ goto cleanup;
+ }
+
+ //
+ // Call check image to verify the image
+ //
+ Status = CheckTheImage (This, ImageIndex, Image, ImageSize, &Updateable);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Check The Image failed with %r.\n", Status));
+ if (Status == EFI_SECURITY_VIOLATION) {
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_AUTH_ERROR;
+ }
+ goto cleanup;
+ }
+
+ //
+ // No functional error in CheckTheImage. Attempt to get the Version to
+ // support better error reporting.
+ //
+ FmpHeader = GetFmpHeader ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, ImageSize, &FmpPayloadSize );
+ if (FmpHeader == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpHeader failed.\n"));
+ Status = EFI_ABORTED;
+ goto cleanup;
+ }
+ Status = GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &IncommingFwVersion);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set to actual value
+ //
+ SetLastAttemptVersionInVariable (IncommingFwVersion);
+ }
+
+
+ if (Updateable != IMAGE_UPDATABLE_VALID) {
+ DEBUG (
+ (DEBUG_ERROR,
+ "FmpDxed: SetTheImage() - Check The Image returned that the Image was not valid for update. Updatable value = 0x%X.\n",
+ Updateable)
+ );
+ Status = EFI_ABORTED;
+ goto cleanup;
+ }
+
+ if (Progress == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Invalid progress callback\n"));
+ Status = EFI_INVALID_PARAMETER;
+ goto cleanup;
+ }
+
+ mProgressFunc = Progress;
+ mProgressSupported = TRUE;
+
+ //
+ // Checking the image is at least 1%
+ //
+ Status = Progress (1);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Progress Callback failed with Status %r.\n", Status));
+ }
+
+ //
+ //Check System Power
+ //
+ Status = CheckSystemPower (&BooleanValue);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemPower - API call failed %r.\n", Status));
+ goto cleanup;
+ }
+ if (!BooleanValue) {
+ Status = EFI_ABORTED;
+ DEBUG (
+ (DEBUG_ERROR,
+ "FmpDxe: SetTheImage() - CheckSystemPower - returned False. Update not allowed due to System Power.\n")
+ );
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_PWR_EVT_BATT;
+ goto cleanup;
+ }
+
+ Progress (2);
+
+ //
+ //Check System Thermal
+ //
+ Status = CheckSystemThermal (&BooleanValue);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemThermal - API call failed %r.\n", Status));
+ goto cleanup;
+ }
+ if (!BooleanValue) {
+ Status = EFI_ABORTED;
+ DEBUG (
+ (DEBUG_ERROR,
+ "FmpDxe: SetTheImage() - CheckSystemThermal - returned False. Update not allowed due to System Thermal.\n")
+ );
+ goto cleanup;
+ }
+
+ Progress (3);
+
+ //
+ //Check System Environment
+ //
+ Status = CheckSystemEnvironment (&BooleanValue);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - CheckSystemEnvironment - API call failed %r.\n", Status));
+ goto cleanup;
+ }
+ if (!BooleanValue) {
+ Status = EFI_ABORTED;
+ DEBUG (
+ (DEBUG_ERROR,
+ "FmpDxe: SetTheImage() - CheckSystemEnvironment - returned False. Update not allowed due to System Environment.\n")
+ );
+ goto cleanup;
+ }
+
+ Progress (4);
+
+ //
+ // Save LastAttemptStatus as error so that if SetImage never returns the error
+ // state is recorded.
+ //
+ SetLastAttemptStatusInVariable (LastAttemptStatus);
+
+ //
+ // Strip off all the headers so the device can process its firmware
+ //
+ Status = GetFmpPayloadHeaderSize (FmpHeader, FmpPayloadSize, &FmpHeaderSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetFmpPayloadHeaderSize failed %r.\n", Status));
+ goto cleanup;
+ }
+
+ AllHeaderSize = GetAllHeaderSize ( (EFI_FIRMWARE_IMAGE_AUTHENTICATION *)Image, FmpHeaderSize );
+ if (AllHeaderSize == 0) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - GetAllHeaderSize failed.\n"));
+ Status = EFI_ABORTED;
+ goto cleanup;
+ }
+
+ //
+ // Indicate that control is handed off to FmpDeviceLib
+ //
+ Progress (5);
+
+ //
+ //Copy the requested image to the firmware using the FmpDeviceLib
+ //
+ Status = FmpDeviceSetImage (
+ (((UINT8 *)Image) + AllHeaderSize),
+ ImageSize - AllHeaderSize,
+ VendorCode,
+ FmpDxeProgress,
+ IncommingFwVersion,
+ AbortReason
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() SetImage from FmpDeviceLib failed. Status = %r.\n", Status));
+ goto cleanup;
+ }
+
+
+ //
+ // Finished the update without error
+ // Indicate that control has been returned from FmpDeviceLib
+ //
+ Progress (99);
+
+ //
+ // Update the version stored in variable
+ //
+ if (!mRuntimeVersionSupported) {
+ UINT32 Version = DEFAULT_VERSION;
+ GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version);
+ SetVersionInVariable (Version);
+ }
+
+ //
+ // Update lowest supported variable
+ //
+ {
+ UINT32 Version = DEFAULT_LOWESTSUPPORTEDVERSION;
+ GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, &Version);
+ SetLowestSupportedVersionInVariable (Version);
+ }
+
+ LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
+
+ //
+ // Set flag so the descriptor is repopulated
+ // This only applied to devices that do not require system reboot
+ //
+ if (!PcdGetBool (PcdFmpDeviceSystemResetRequired)) {
+ mDescriptorPopulated = FALSE;
+ }
+
+cleanup:
+ mProgressFunc = NULL;
+ mProgressSupported = FALSE;
+ SetLastAttemptStatusInVariable (LastAttemptStatus);
+
+ //
+ // Set progress to 100 after everything is done including recording Status.
+ //
+ Progress (100);
+
+ return Status;
+}
+
+/**
+ Returns information about the firmware package.
+
+ This function returns package information.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[out] PackageVersion A version number that represents all the firmware images in the device.
+ The format is vendor specific and new version must have a greater value
+ than the old version. If PackageVersion is not supported, the value is
+ 0xFFFFFFFF. A value of 0xFFFFFFFE indicates that package version
+ comparison is to be performed using PackageVersionName. A value of
+ 0xFFFFFFFD indicates that package version update is in progress.
+ @param[out] PackageVersionName A pointer to a pointer to a null-terminated string representing
+ the package version name. The buffer is allocated by this function with
+ AllocatePool(), and it is the caller's responsibility to free it with a
+ call to FreePool().
+ @param[out] PackageVersionNameMaxLen The maximum length of package version name if device supports update of
+ package version name. A value of 0 indicates the device does not support
+ update of package version name. Length is the number of Unicode characters,
+ including the terminating null character.
+ @param[out] AttributesSupported Package attributes that are supported by this device. See 'Package Attribute
+ Definitions' for possible returned values of this parameter. A value of 1
+ indicates the attribute is supported and the current setting value is
+ indicated in AttributesSetting. A value of 0 indicates the attribute is not
+ supported and the current setting value in AttributesSetting is meaningless.
+ @param[out] AttributesSetting Package attributes. See 'Package Attribute Definitions' for possible returned
+ values of this parameter
+
+ @retval EFI_SUCCESS The package information was successfully returned.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ OUT UINT32 *PackageVersion,
+ OUT CHAR16 **PackageVersionName,
+ OUT UINT32 *PackageVersionNameMaxLen,
+ OUT UINT64 *AttributesSupported,
+ OUT UINT64 *AttributesSetting
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Updates information about the firmware package.
+
+ This function updates package information.
+ This function returns EFI_UNSUPPORTED if the package information is not updatable.
+ VendorCode enables vendor to implement vendor-specific package information update policy.
+ Null if the caller did not specify this policy or use the default policy.
+
+ @param[in] This A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.
+ @param[in] Image Points to the authentication image.
+ Null if authentication is not required.
+ @param[in] ImageSize Size of the authentication image in bytes.
+ 0 if authentication is not required.
+ @param[in] VendorCode This enables vendor to implement vendor-specific firmware
+ image update policy.
+ Null indicates the caller did not specify this policy or use
+ the default policy.
+ @param[in] PackageVersion The new package version.
+ @param[in] PackageVersionName A pointer to the new null-terminated Unicode string representing
+ the package version name.
+ The string length is equal to or less than the value returned in
+ PackageVersionNameMaxLen.
+
+ @retval EFI_SUCCESS The device was successfully updated with the new package
+ information.
+ @retval EFI_INVALID_PARAMETER The PackageVersionName length is longer than the value
+ returned in PackageVersionNameMaxLen.
+ @retval EFI_UNSUPPORTED The operation is not supported.
+ @retval EFI_SECURITY_VIOLATIO The operation could not be performed due to an authentication failure.
+
+**/
+EFI_STATUS
+EFIAPI
+SetPackageInfo (
+ IN EFI_FIRMWARE_MANAGEMENT_PROTOCOL *This,
+ IN CONST VOID *Image,
+ IN UINTN ImageSize,
+ IN CONST VOID *VendorCode,
+ IN UINT32 PackageVersion,
+ IN CONST CHAR16 *PackageVersionName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Event notification function that is invoked when the event GUID specified by
+ PcdFmpDeviceLockEventGuid is signaled.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+**/
+VOID
+EFIAPI
+FmpDxeLockEventNotify (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+
+ if (!mFmpDeviceLocked) {
+ if (IsLockFmpDeviceAtLockEventGuidRequired ()) {
+ //
+ // Lock all UEFI Variables used by this module.
+ //
+ Status = LockAllFmpVariables ();
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variables. Status = %r.\n"));
+ } else {
+ DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\n"));
+ }
+
+ //
+ // Lock the firmware device
+ //
+ Status = FmpDeviceLock();
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_UNSUPPORTED) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLock() returned error. Status = %r\n", Status));
+ } else {
+ DEBUG ((DEBUG_WARN, "FmpDxe: FmpDeviceLock() returned error. Status = %r\n", Status));
+ }
+ }
+ mFmpDeviceLocked = TRUE;
+ } else {
+ DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not calling FmpDeviceLock() because mfg mode\n"));
+ }
+ }
+}
+
+/**
+ Function to install FMP instance.
+
+ @param[in] Handle The device handle to install a FMP instance on.
+
+ @retval EFI_SUCCESS FMP Installed
+ @retval EFI_INVALID_PARAMETER Handle was invalid
+ @retval other Error installing FMP
+
+**/
+EFI_STATUS
+EFIAPI
+InstallFmpInstance (
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL *FmpProgress;
+
+ Status = EFI_SUCCESS;
+ Fmp = NULL;
+ FmpProgress = NULL;
+
+ //
+ // Only allow a single FMP Protocol instance to be installed
+ //
+ if (mFmpInstalled) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ //
+ // Allocate FMP Protocol instance
+ //
+ Fmp = AllocateZeroPool (sizeof (EFI_FIRMWARE_MANAGEMENT_PROTOCOL));
+ if (Fmp == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Protocol instance.\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto cleanup;
+ }
+
+ //
+ // Allocate FMP Progress Protocol instance
+ //
+ FmpProgress = AllocateZeroPool (sizeof (EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL));
+ if (FmpProgress == NULL) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for FMP Progress Protocol instance.\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ FreePool (Fmp);
+ goto cleanup;
+ }
+
+ //
+ // Set up FMP Protocol function pointers
+ //
+ Fmp->GetImageInfo = GetTheImageInfo;
+ Fmp->GetImage = GetTheImage;
+ Fmp->SetImage = SetTheImage;
+ Fmp->CheckImage = CheckTheImage;
+ Fmp->GetPackageInfo = GetPackageInfo;
+ Fmp->SetPackageInfo = SetPackageInfo;
+
+ //
+ // Fill in FMP Progress Protocol fields for Version 1
+ //
+ FmpProgress->Version = 1;
+ FmpProgress->ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);
+ FmpProgress->WatchdogSeconds = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);
+
+ //
+ // Install FMP Protocol and FMP Progress Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiFirmwareManagementProtocolGuid,
+ Fmp,
+ &gEdkiiFirmwareManagementProgressProtocolGuid,
+ FmpProgress,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FMP Protocol install error. Status = %r.\n", Status));
+ FreePool (Fmp);
+ goto cleanup;
+ }
+
+ DEBUG ((DEBUG_INFO, "FmpDxe: FMP Protocol Installed!\n"));
+ mFmpInstalled = TRUE;
+
+cleanup:
+
+ return Status;
+}
+
+/**
+ Main entry for this library.
+
+ @param[in] ImageHandle Image handle this driver.
+ @param[in] SystemTable Pointer to SystemTable.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDxeEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID *LockGuid;
+
+ //
+ // Verify that a new FILE_GUID value has been provided in the <Defines>
+ // section of this module. The FILE_GUID is the ESRT GUID that must be
+ // unique for each updatable firmware image.
+ //
+ if (CompareGuid (&mDefaultModuleFileGuid, &gEfiCallerIdGuid)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Use of default FILE_GUID detected. FILE_GUID must be set to a unique value.\n"));
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Get the ImageIdName value for the EFI_FIRMWARE_IMAGE_DESCRIPTOR from a PCD.
+ //
+ mImageIdName = (CHAR16 *) PcdGetPtr (PcdFmpDeviceImageIdName);
+ if (PcdGetSize (PcdFmpDeviceImageIdName) <= 2 || mImageIdName[0] == 0) {
+ //
+ // PcdFmpDeviceImageIdName must be set to a non-empty Unicode string
+ //
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib PcdFmpDeviceImageIdName is an empty string.\n"));
+ ASSERT (FALSE);
+ }
+
+ //
+ // Detects if PcdFmpDevicePkcs7CertBufferXdr contains a test key.
+ //
+ DetectTestKey ();
+
+ //
+ // Register with library the install function so if the library uses
+ // UEFI driver model/driver binding protocol it can install FMP on its device handle
+ // If library is simple lib that does not use driver binding then it should return
+ // unsupported and this will install the FMP instance on the ImageHandle
+ //
+ Status = RegisterFmpInstaller (InstallFmpInstance);
+ if (Status == EFI_UNSUPPORTED) {
+ DEBUG ((DEBUG_INFO, "FmpDxe: FmpDeviceLib registration returned EFI_UNSUPPORTED. Installing single FMP instance.\n"));
+ Status = InstallFmpInstance (ImageHandle);
+ } else if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib registration returned %r. No FMP installed.\n", Status));
+ } else {
+ DEBUG ((
+ DEBUG_INFO,
+ "FmpDxe: FmpDeviceLib registration returned EFI_SUCCESS. Expect FMP to be installed during the BDS/Device connection phase.\n"
+ ));
+ }
+
+ //
+ // Register notify function to lock the FMP device.
+ // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid.
+ // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then
+ // gEfiEndOfDxeEventGroupGuid is used.
+ //
+ LockGuid = &gEfiEndOfDxeEventGroupGuid;
+ if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) {
+ LockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid);
+ }
+ DEBUG ((DEBUG_INFO, "FmpDxe: Lock GUID: %g\n", LockGuid));
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ FmpDxeLockEventNotify,
+ NULL,
+ LockGuid,
+ &mFmpDeviceLockEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register for ready to boot. Status = %r\n", Status));
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.inf b/FmpDevicePkg/FmpDxe/FmpDxe.inf
new file mode 100644
index 0000000000..256c50bf03
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.inf
@@ -0,0 +1,93 @@
+## @file
+# Produces a Firmware Management Protocol that supports updates to a firmware
+# image stored in a firmware device with platform and firmware device specific
+# information provided through PCDs and libraries.
+#
+# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpDxe
+ MODULE_UNI_FILE = FmpDxe.uni
+ FILE_GUID = 78EF0A56-1CF0-4535-B5DA-F6FD2F405A11
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FmpDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF ARM AARCH64
+#
+
+[Sources]
+ FmpDxe.c
+ DetectTestKey.c
+ VariableSupport.h
+ VariableSupport.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ BaseLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ BaseCryptLib
+ FmpAuthenticationLib
+ FmpDeviceLib
+ FmpPayloadHeaderLib
+ CapsuleUpdatePolicyLib
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+
+[Protocols]
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## PRODUCES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## PRODUCES
+
+[Pcd]
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceSystemResetRequired ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageIdName ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceBuildTimeLowestSupportedVersion ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceLockEventGuid ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressWatchdogTimeInSeconds ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressColor ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceTestKeySha256Digest ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## SOMETIMES_PRODUCES
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid AND gEdkiiVariableLockProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FmpDxeExtra.uni
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.uni b/FmpDevicePkg/FmpDxe/FmpDxe.uni
new file mode 100644
index 0000000000..502ec0660d
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Produces a Firmware Management Protocol that supports updates to a firmware
+// image stored in a firmware device with platform and firmware device specific
+// information provided through PCDs and libraries.
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Produces a Firmware Management Protocol to support firmware updates"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Produces a Firmware Management Protocol that supports updates to a firmware image stored in a firmware device with platform and firmware device specific information provided through PCDs and libraries."
diff --git a/FmpDevicePkg/FmpDxe/FmpDxeExtra.uni b/FmpDevicePkg/FmpDxe/FmpDxeExtra.uni
new file mode 100644
index 0000000000..8f3cc4367c
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxeExtra.uni
@@ -0,0 +1,18 @@
+// /** @file
+// FmpDxe Localized Strings and Content
+//
+// Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+// **/
+
+#string STR_PROPERTIES_MODULE_NAME
+#language en-US
+"Firmware Management Protocol DXE DXE Driver"
diff --git a/FmpDevicePkg/FmpDxe/FmpDxeLib.inf b/FmpDevicePkg/FmpDxe/FmpDxeLib.inf
new file mode 100644
index 0000000000..c8fe49e0c0
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxeLib.inf
@@ -0,0 +1,90 @@
+## @file
+# Produces a Firmware Management Protocol that supports updates to a firmware
+# image stored in a firmware device with platform and firmware device specific
+# information provided through PCDs and libraries.
+#
+# Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+# Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are met:
+# 1. Redistributions of source code must retain the above copyright notice,
+# this list of conditions and the following disclaimer.
+# 2. Redistributions in binary form must reproduce the above copyright notice,
+# this list of conditions and the following disclaimer in the documentation
+# and/or other materials provided with the distribution.
+#
+# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+# ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+# WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+# IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+# INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+# BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+# DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+# OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+# ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FmpDxeLib
+ MODULE_UNI_FILE = FmpDxe.uni
+ FILE_GUID = 4B11717A-30B3-4122-8C69-8E0D5E141C32
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = FmpDxeEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF ARM AARCH64
+#
+
+[Sources]
+ FmpDxe.c
+ DetectTestKey.c
+ VariableSupport.h
+ VariableSupport.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ CryptoPkg/CryptoPkg.dec
+ FmpDevicePkg/FmpDevicePkg.dec
+
+[LibraryClasses]
+ DebugLib
+ BaseLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ BaseCryptLib
+ FmpAuthenticationLib
+ FmpDeviceLib
+ FmpPayloadHeaderLib
+ CapsuleUpdatePolicyLib
+
+[Guids]
+ gEfiEndOfDxeEventGroupGuid
+
+[Protocols]
+ gEdkiiVariableLockProtocolGuid ## CONSUMES
+ gEfiFirmwareManagementProtocolGuid ## PRODUCES
+ gEdkiiFirmwareManagementProgressProtocolGuid ## PRODUCES
+
+[Pcd]
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceSystemResetRequired ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceImageIdName ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceBuildTimeLowestSupportedVersion ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceLockEventGuid ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressWatchdogTimeInSeconds ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceProgressColor ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDevicePkcs7CertBufferXdr ## CONSUMES
+ gFmpDevicePkgTokenSpaceGuid.PcdFmpDeviceTestKeySha256Digest ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdTestKeyUsed ## SOMETIMES_PRODUCES
+
+[Depex]
+ gEfiVariableWriteArchProtocolGuid AND gEdkiiVariableLockProtocolGuid
diff --git a/FmpDevicePkg/FmpDxe/VariableSupport.c b/FmpDevicePkg/FmpDxe/VariableSupport.c
new file mode 100644
index 0000000000..c15178d099
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/VariableSupport.c
@@ -0,0 +1,461 @@
+/** @file
+ UEFI variable support functions for Firmware Management Protocol based
+ firmware updates.
+
+ Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Protocol/VariableLock.h>
+#include "VariableSupport.h"
+
+///
+/// Array of UEFI variable names that are locked in LockAllFmpVariables().
+///
+const CHAR16 *mFmpVariableLockList[] = {
+ VARNAME_VERSION,
+ VARNAME_LSV,
+ VARNAME_LASTATTEMPTSTATUS,
+ VARNAME_LASTATTEMPTVERSION
+};
+
+/**
+ Returns the value used to fill in the Version field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default version value
+ is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+
+ @return The version of the firmware image in the firmware device.
+
+**/
+UINT32
+GetVersionFromVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *Value;
+ UINTN Size;
+ UINT32 Version;
+
+ Value = NULL;
+ Size = 0;
+ Version = DEFAULT_VERSION;
+
+ Status = GetVariable2 (VARNAME_VERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to get the Version from variable. Status = %r\n", Status));
+ return Version;
+ }
+
+ //
+ // No error from call
+ //
+ if (Size == sizeof (*Value)) {
+ //
+ // Successful read
+ //
+ Version = *Value;
+ } else {
+ //
+ // Return default since size was unknown
+ //
+ DEBUG ((DEBUG_ERROR, "Getting version Variable returned a size different than expected. Size = 0x%x\n", Size));
+ }
+
+ FreePool (Value);
+
+ return Version;
+}
+
+/**
+ Returns the value used to fill in the LowestSupportedVersion field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default lowest
+ supported version value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
+
+ @return The lowest supported version of the firmware image in the firmware
+ device.
+
+**/
+UINT32
+GetLowestSupportedVersionFromVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *Value;
+ UINTN Size;
+ UINT32 Version;
+
+ Value = NULL;
+ Size = 0;
+ Version = DEFAULT_LOWESTSUPPORTEDVERSION;
+
+ Status = GetVariable2 (VARNAME_LSV, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Warning: Failed to get the Lowest Supported Version from variable. Status = %r\n", Status));
+ return Version;
+ }
+
+ //
+ // No error from call
+ //
+ if (Size == sizeof (*Value)) {
+ //
+ // Successful read
+ //
+ Version = *Value;
+ } else {
+ //
+ // Return default since size was unknown
+ //
+ DEBUG ((DEBUG_ERROR, "Getting LSV Variable returned a size different than expected. Size = 0x%x\n", Size));
+ }
+
+ FreePool (Value);
+
+ return Version;
+}
+
+/**
+ Returns the value used to fill in the LastAttemptStatus field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default last attempt
+ status value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
+
+ @return The last attempt status value for the most recent capsule update.
+
+**/
+UINT32
+GetLastAttemptStatusFromVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *Value;
+ UINTN Size;
+ UINT32 LastAttemptStatus;
+
+ Value = NULL;
+ Size = 0;
+ LastAttemptStatus = DEFAULT_LASTATTEMPT;
+
+ Status = GetVariable2 (VARNAME_LASTATTEMPTSTATUS, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Status from variable. Status = %r\n", Status));
+ return LastAttemptStatus;
+ }
+
+ //
+ // No error from call
+ //
+ if (Size == sizeof (*Value)) {
+ //
+ // Successful read
+ //
+ LastAttemptStatus = *Value;
+ } else {
+ //
+ // Return default since size was unknown
+ //
+ DEBUG (
+ (DEBUG_ERROR,
+ "Getting Last Attempt Status Variable returned a size different than expected. Size = 0x%x\n",
+ Size)
+ );
+ }
+
+ FreePool (Value);
+
+ return LastAttemptStatus;
+}
+
+/**
+ Returns the value used to fill in the LastAttemptVersion field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default last attempt
+ version value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
+
+ @return The last attempt version value for the most recent capsule update.
+
+**/
+UINT32
+GetLastAttemptVersionFromVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 *Value;
+ UINTN Size;
+ UINT32 Version;
+
+ Value = NULL;
+ Size = 0;
+ Version = DEFAULT_LASTATTEMPT;
+
+ Status = GetVariable2 (VARNAME_LASTATTEMPTVERSION, &gEfiCallerIdGuid, (VOID **)&Value, &Size);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_WARN, "Warning: Failed to get the Last Attempt Version from variable. Status = %r\n", Status));
+ return Version;
+ }
+
+ //
+ // No error from call
+ //
+ if (Size == sizeof (*Value)) {
+ //
+ // Successful read
+ //
+ Version = *Value;
+ } else {
+ //
+ // Return default since size was unknown
+ //
+ DEBUG (
+ (DEBUG_ERROR,
+ "Getting Last Attempt Version variable returned a size different than expected. Size = 0x%x\n",
+ Size)
+ );
+ }
+
+ FreePool (Value);
+
+ return Version;
+}
+
+
+/**
+ Saves the version current of the firmware image in the firmware device to a
+ UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+
+ @param[in] Version The version of the firmware image in the firmware device.
+
+**/
+VOID
+SetVersionInVariable (
+ UINT32 Version
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Current;
+
+ Status = EFI_SUCCESS;
+
+ Current = GetVersionFromVariable();
+ if (Current != Version) {
+ Status = gRT->SetVariable (
+ VARNAME_VERSION,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Version),
+ &Version
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set the Version into a variable. Status = %r\n", Status));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "Version variable doesn't need to update. Same value as before.\n"));
+ }
+}
+
+/**
+ Saves the lowest supported version current of the firmware image in the
+ firmware device to a UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
+
+ @param[in] LowestSupported The lowest supported version of the firmware image
+ in the firmware device.
+
+**/
+VOID
+SetLowestSupportedVersionInVariable (
+ UINT32 LowestSupportedVersion
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Current;
+
+ Status = EFI_SUCCESS;
+
+ Current = GetLowestSupportedVersionFromVariable();
+ if (LowestSupportedVersion > Current) {
+ Status = gRT->SetVariable (
+ VARNAME_LSV,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (LowestSupportedVersion), &LowestSupportedVersion
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set the LSV into a variable. Status = %r\n", Status));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "LSV variable doesn't need to update. Same value as before.\n"));
+ }
+}
+
+/**
+ Saves the last attempt status value of the most recent FMP capsule update to a
+ UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
+
+ @param[in] LastAttemptStatus The last attempt status of the most recent FMP
+ capsule update.
+
+**/
+VOID
+SetLastAttemptStatusInVariable (
+ UINT32 LastAttemptStatus
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Current;
+
+ Status = EFI_SUCCESS;
+
+ Current = GetLastAttemptStatusFromVariable();
+ if (Current != LastAttemptStatus) {
+ Status = gRT->SetVariable (
+ VARNAME_LASTATTEMPTSTATUS,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (LastAttemptStatus),
+ &LastAttemptStatus
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptStatus into a variable. Status = %r\n", Status));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "LastAttemptStatus variable doesn't need to update. Same value as before.\n"));
+ }
+}
+
+/**
+ Saves the last attempt version value of the most recent FMP capsule update to
+ a UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
+
+ @param[in] LastAttemptVersion The last attempt version value of the most
+ recent FMP capsule update.
+
+**/
+VOID
+SetLastAttemptVersionInVariable (
+ UINT32 LastAttemptVersion
+ )
+{
+ EFI_STATUS Status;
+ UINT32 Current;
+
+ Status = EFI_SUCCESS;
+
+ Current = GetLastAttemptVersionFromVariable();
+ if (Current != LastAttemptVersion) {
+ Status = gRT->SetVariable (
+ VARNAME_LASTATTEMPTVERSION,
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (LastAttemptVersion),
+ &LastAttemptVersion
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptVersion into a variable. Status = %r\n", Status));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "LastAttemptVersion variable doesn't need to update. Same value as before.\n"));
+ }
+}
+
+/**
+ Locks all the UEFI Variables used by this module.
+
+ @retval EFI_SUCCESS All UEFI variables are locked.
+ @retval EFI_UNSUPPORTED Variable Lock Protocol not found.
+ @retval Other One of the UEFI variables could not be locked.
+
+**/
+EFI_STATUS
+LockAllFmpVariables (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ EFI_STATUS ReturnStatus;
+ UINTN Index;
+
+ VariableLock = NULL;
+ Status = gBS->LocateProtocol (
+ &gEdkiiVariableLockProtocolGuid,
+ NULL,
+ (VOID **)&VariableLock
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to locate Variable Lock Protocol (%r).\n", Status));
+ return EFI_UNSUPPORTED;
+ }
+
+ ReturnStatus = EFI_SUCCESS;
+ for (Index = 0; Index < ARRAY_SIZE (mFmpVariableLockList); Index++) {
+ Status = VariableLock->RequestToLock (
+ VariableLock,
+ (CHAR16 *)mFmpVariableLockList[Index],
+ &gEfiCallerIdGuid
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variable %g %s. Status = %r\n",
+ &gEfiCallerIdGuid,
+ mFmpVariableLockList[Index],
+ Status
+ ));
+ if (!EFI_ERROR (ReturnStatus)) {
+ ReturnStatus = Status;
+ }
+ }
+ }
+
+ return ReturnStatus;
+}
diff --git a/FmpDevicePkg/FmpDxe/VariableSupport.h b/FmpDevicePkg/FmpDxe/VariableSupport.h
new file mode 100644
index 0000000000..e7e34f5d8f
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/VariableSupport.h
@@ -0,0 +1,180 @@
+/** @file
+ UEFI variable support functions for Firmware Management Protocol based
+ firmware updates.
+
+ Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
+ Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are met:
+ 1. Redistributions of source code must retain the above copyright notice,
+ this list of conditions and the following disclaimer.
+ 2. Redistributions in binary form must reproduce the above copyright notice,
+ this list of conditions and the following disclaimer in the documentation
+ and/or other materials provided with the distribution.
+
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
+ ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+ BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+ OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+**/
+
+#ifndef __VARIABLE_SUPPORT_H__
+#define __VARIABLE_SUPPORT_H__
+
+#define DEFAULT_VERSION 0x1
+#define DEFAULT_LOWESTSUPPORTEDVERSION 0x0
+#define DEFAULT_LASTATTEMPT 0x0
+
+#define VARNAME_VERSION L"FmpVersion"
+#define VARNAME_LSV L"FmpLsv"
+
+#define VARNAME_LASTATTEMPTSTATUS L"LastAttemptStatus"
+#define VARNAME_LASTATTEMPTVERSION L"LastAttemptVersion"
+
+/**
+ Returns the value used to fill in the Version field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default version value
+ is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+
+ @return The version of the firmware image in the firmware device.
+
+**/
+UINT32
+GetVersionFromVariable (
+ VOID
+ );
+
+/**
+ Returns the value used to fill in the LowestSupportedVersion field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default lowest
+ supported version value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
+
+ @return The lowest supported version of the firmware image in the firmware
+ device.
+
+**/
+UINT32
+GetLowestSupportedVersionFromVariable (
+ VOID
+ );
+
+/**
+ Returns the value used to fill in the LastAttemptStatus field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default last attempt
+ status value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
+
+ @return The last attempt status value for the most recent capsule update.
+
+**/
+UINT32
+GetLastAttemptStatusFromVariable (
+ VOID
+ );
+
+/**
+ Returns the value used to fill in the LastAttemptVersion field of the
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the GetImageInfo()
+ service of the Firmware Management Protocol. The value is read from a UEFI
+ variable. If the UEFI variables does not exist, then a default last attempt
+ version value is returned.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
+
+ @return The last attempt version value for the most recent capsule update.
+
+**/
+UINT32
+GetLastAttemptVersionFromVariable (
+ VOID
+ );
+
+/**
+ Saves the version current of the firmware image in the firmware device to a
+ UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+
+ @param[in] Version The version of the firmware image in the firmware device.
+
+**/
+VOID
+SetVersionInVariable (
+ UINT32 Version
+ );
+
+/**
+ Saves the lowest supported version current of the firmware image in the
+ firmware device to a UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpLsv"
+
+ @param[in] LowestSupported The lowest supported version of the firmware image
+ in the firmware device.
+
+**/
+VOID
+SetLowestSupportedVersionInVariable (
+ UINT32 LowestSupportedVersion
+ );
+
+/**
+ Saves the last attempt status value of the most recent FMP capsule update to a
+ UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptStatus"
+
+ @param[in] LastAttemptStatus The last attempt status of the most recent FMP
+ capsule update.
+
+**/
+VOID
+SetLastAttemptStatusInVariable (
+ UINT32 LastAttemptStatus
+ );
+
+/**
+ Saves the last attempt version value of the most recent FMP capsule update to
+ a UEFI variable.
+
+ UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"LastAttemptVersion"
+
+ @param[in] LastAttemptVersion The last attempt version value of the most
+ recent FMP capsule update.
+
+**/
+VOID
+SetLastAttemptVersionInVariable (
+ UINT32 LastAttemptVersion
+ );
+
+/**
+ Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently
+ executing module.
+
+**/
+EFI_STATUS
+LockAllFmpVariables (
+ VOID
+ );
+
+#endif