[edk2-devel] [PATCH V2 04/10] FmpDevicePkg/FmpDxe: Use new FmpDeviceLib APIs

Eric Jin eric.jin at intel.com
Mon Aug 12 02:00:23 UTC 2019


REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1525

Update FmpDxe to support multiple controllers and use
new FmpDeviceLib APIs to support Stop/Unload and to
set the context for the worker functions in the
FmpDeviceLib.

Cc: Sean Brogan <sean.brogan at microsoft.com>
Cc: Bret Barkelew <Bret.Barkelew at microsoft.com>
Cc: Liming Gao <liming.gao at intel.com>
Signed-off-by: Michael D Kinney <michael.d.kinney at intel.com>
Reviewed-by: Eric Jin <eric.jin at intel.com>
---
 FmpDevicePkg/FmpDxe/FmpDxe.c      | 586 +++++++++++++++++++-----------
 FmpDevicePkg/FmpDxe/FmpDxe.h      | 341 +++++++++++++++++
 FmpDevicePkg/FmpDxe/FmpDxe.inf    |   4 +-
 FmpDevicePkg/FmpDxe/FmpDxeLib.inf |   4 +-
 4 files changed, 715 insertions(+), 220 deletions(-)
 create mode 100644 FmpDevicePkg/FmpDxe/FmpDxe.h

diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c
index f485f5b939..dab3310834 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxe.c
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.c
@@ -4,46 +4,13 @@
   information provided through PCDs and libraries.
 
   Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
-  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 
   SPDX-License-Identifier: BSD-2-Clause-Patent
 
 **/
 
-#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
-  );
+#include "FmpDxe.h"
 
 ///
 /// FILE_GUID from FmpDxe.inf.  When FmpDxe.inf is used in a platform, the
@@ -56,30 +23,73 @@ 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
+/// TRUE if FmpDeviceLib manages a single firmware storage device.
 ///
-EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc      = NULL;
-BOOLEAN                                        mProgressSupported = FALSE;
+BOOLEAN  mFmpSingleInstance = FALSE;
 
-CHAR16  *mImageIdName = NULL;
-UINT64  mImageId      = 0x1;
-CHAR16  *mVersionName = NULL;
+///
+/// Firmware Management Protocol instance that is initialized in the entry
+/// point from PCD settings.
+///
+EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  mFmpProgress;
 
-EFI_EVENT  mFmpDeviceLockEvent;
 //
-// Indicates if an attempt has been made to lock a
-// FLASH storage device by calling FmpDeviceLock().
-// A FLASH storage device may not support being locked,
-// so this variable is set to TRUE even if FmpDeviceLock()
-// returns an error.
+// Template of the private context structure for the Firmware Management
+// Protocol instance
 //
-BOOLEAN    mFmpDeviceLocked = FALSE;
+const FIRMWARE_MANAGEMENT_PRIVATE_DATA  mFirmwareManagementPrivateDataTemplate = {
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE,  // Signature
+  NULL,                                        // Handle
+  {                                            // Fmp
+    GetTheImageInfo,
+    GetTheImage,
+    SetTheImage,
+    CheckTheImage,
+    GetPackageInfo,
+    SetPackageInfo
+  },
+  FALSE,                                       // DescriptorPopulated
+  {                                            // Desc
+    1,     // ImageIndex
+    //
+    // ImageTypeId
+    //
+    { 0x00000000, 0x0000, 0x0000, {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00} },
+    1,     // ImageId
+    NULL,  // ImageIdName
+    0,     // Version
+    NULL,  // VersionName
+    0,     // Size
+    0,     // AttributesSupported
+    0,     // AttributesSetting
+    0,     // Compatibilities
+    0,     // LowestSupportedImageVersion
+    0,     // LastAttemptVersion
+    0,     // LastAttemptStatus
+    0      // HardwareInstance
+  },
+  NULL,                                        // ImageIdName
+  NULL,                                        // VersionName
+  TRUE,                                        // RuntimeVersionSupported
+  NULL,                                        // FmpDeviceLockEvent
+  FALSE                                        // FmpDeviceLocked
+};
+
+///
+/// GUID that is used to create event used to lock the firmware storage device.
+///
+EFI_GUID  *mLockGuid = NULL;
+
+///
+/// Progress() function pointer passed into SetTheImage()
+///
+EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS  mProgressFunc = NULL;
+
+///
+/// Null-terminated Unicode string retrieved from PcdFmpDeviceImageIdName.
+///
+CHAR16  *mImageIdName = NULL;
 
 /**
   Callback function to report the process of the firmware updating.
@@ -111,10 +121,6 @@ FmpDxeProgress (
 
   Status = EFI_UNSUPPORTED;
 
-  if (!mProgressSupported) {
-    return Status;
-  }
-
   if (mProgressFunc == NULL) {
     return Status;
   }
@@ -125,7 +131,6 @@ FmpDxeProgress (
   Status = mProgressFunc (((Completion * 92) / 100) + 6);
 
   if (Status == EFI_UNSUPPORTED) {
-    mProgressSupported = FALSE;
     mProgressFunc = NULL;
   }
 
@@ -183,7 +188,7 @@ GetImageTypeNameString (
   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
+  @return  The largest value
 
 **/
 UINT32
@@ -237,101 +242,117 @@ GetLowestSupportedVersion (
 }
 
 /**
-  Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the module global
-  variable mDesc.
+  Populates the EFI_FIRMWARE_IMAGE_DESCRIPTOR structure in the private
+  context structure.
+
+  @param[in] Private  Pointer to the private context structure for the
+                      Firmware Management Protocol instance.
 
 **/
 VOID
 PopulateDescriptor (
-  VOID
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
   EFI_STATUS  Status;
 
-  mDesc.ImageIndex = 1;
-  CopyGuid (&mDesc.ImageTypeId, GetImageTypeIdGuid());
-  mDesc.ImageId = mImageId;
-  mDesc.ImageIdName = GetImageTypeNameString();
+  if (Private->DescriptorPopulated) {
+    return;
+  }
+
+  Private->Descriptor.ImageIndex = 1;
+  CopyGuid (&Private->Descriptor.ImageTypeId, GetImageTypeIdGuid());
+  Private->Descriptor.ImageId     = Private->Descriptor.ImageIndex;
+  Private->Descriptor.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);
+  Status = FmpDeviceGetVersion (&Private->Descriptor.Version);
   if (Status == EFI_UNSUPPORTED) {
-    mRuntimeVersionSupported = FALSE;
-    mDesc.Version = GetVersionFromVariable();
+    Private->RuntimeVersionSupported = FALSE;
+    Private->Descriptor.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;
+    Private->Descriptor.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;
+  if (Private->Descriptor.VersionName != NULL) {
+    FreePool (Private->Descriptor.VersionName);
+    Private->Descriptor.VersionName = NULL;
   }
 
   //
   // Attempt to get the version string from the FmpDeviceLib
   //
-  Status = FmpDeviceGetVersionString (&mVersionName);
+  Status = FmpDeviceGetVersionString (&Private->Descriptor.VersionName);
   if (Status == EFI_UNSUPPORTED) {
     DEBUG ((DEBUG_INFO, "FmpDxe: GetVersionString() unsupported in FmpDeviceLib.\n"));
-    mVersionName = AllocateCopyPool (
-                     sizeof (VERSION_STRING_NOT_SUPPORTED),
-                     VERSION_STRING_NOT_SUPPORTED
-                     );
+    Private->Descriptor.VersionName = 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
-                     );
+    Private->Descriptor.VersionName = AllocateCopyPool (
+                                        sizeof (VERSION_STRING_NOT_AVAILABLE),
+                                        VERSION_STRING_NOT_AVAILABLE
+                                        );
   }
 
-  mDesc.VersionName = mVersionName;
-
-  mDesc.LowestSupportedImageVersion = GetLowestSupportedVersion();
+  Private->Descriptor.LowestSupportedImageVersion = GetLowestSupportedVersion();
 
   //
   // Get attributes from the FmpDeviceLib
   //
-  FmpDeviceGetAttributes (&mDesc.AttributesSupported, &mDesc.AttributesSetting);
+  FmpDeviceGetAttributes (
+    &Private->Descriptor.AttributesSupported,
+    &Private->Descriptor.AttributesSetting
+    );
 
   //
   // Force set the updatable bits in the attributes;
   //
-  mDesc.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
-  mDesc.AttributesSetting   |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+  Private->Descriptor.AttributesSupported |= IMAGE_ATTRIBUTE_IMAGE_UPDATABLE;
+  Private->Descriptor.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);
+  Private->Descriptor.AttributesSupported |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
+  Private->Descriptor.AttributesSetting   |= (IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED);
 
-  mDesc.Compatibilities = 0;
+  Private->Descriptor.Compatibilities = 0;
 
   //
   // Get the size of the firmware image from the FmpDeviceLib
   //
-  Status = FmpDeviceGetSize (&mDesc.Size);
+  Status = FmpDeviceGetSize (&Private->Descriptor.Size);
   if (EFI_ERROR (Status)) {
-    mDesc.Size = 0;
+    Private->Descriptor.Size = 0;
   }
 
-  mDesc.LastAttemptVersion = GetLastAttemptVersionFromVariable ();
-  mDesc.LastAttemptStatus  = GetLastAttemptStatusFromVariable ();
+  Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable ();
+  Private->Descriptor.LastAttemptStatus  = GetLastAttemptStatusFromVariable ();
 
-  mDescriptorPopulated = TRUE;
+  //
+  // Get the hardware instance from FmpDeviceLib
+  //
+  Status = FmpDeviceGetHardwareInstance (&Private->Descriptor.HardwareInstance);
+  if (Status == EFI_UNSUPPORTED) {
+    Private->Descriptor.HardwareInstance = 0;
+  }
+
+  Private->DescriptorPopulated = TRUE;
 }
 
 /**
@@ -385,10 +406,17 @@ GetTheImageInfo (
   OUT    CHAR16                            **PackageVersionName
   )
 {
-  EFI_STATUS Status;
+  EFI_STATUS                        Status;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
 
   Status = EFI_SUCCESS;
 
+  //
+  // Retrieve the private context structure
+  //
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
+
   //
   // Check for valid pointer
   //
@@ -424,15 +452,15 @@ GetTheImageInfo (
   //
   *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
 
-
-  if (!mDescriptorPopulated) {
-    PopulateDescriptor();
-  }
+  //
+  // make sure the descriptor has already been loaded
+  //
+  PopulateDescriptor (Private);
 
   //
   // Copy the image descriptor
   //
-  CopyMem (ImageInfo, &mDesc, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));
+  CopyMem (ImageInfo, &Private->Descriptor, sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR));
 
   *DescriptorVersion = EFI_FIRMWARE_IMAGE_DESCRIPTOR_VERSION;
   *DescriptorCount = 1;
@@ -483,11 +511,18 @@ GetTheImage (
   IN OUT UINTN                             *ImageSize
   )
 {
-  EFI_STATUS  Status;
-  UINTN       Size;
+  EFI_STATUS                        Status;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+  UINTN                             Size;
 
   Status = EFI_SUCCESS;
 
+  //
+  // Retrieve the private context structure
+  //
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
+
   //
   // Check to make sure index is 1 (only 1 image for this device)
   //
@@ -632,18 +667,19 @@ CheckTheImage (
   OUT UINT32                            *ImageUpdatable
   )
 {
-  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;
+  EFI_STATUS                        Status;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+  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;
@@ -653,12 +689,16 @@ CheckTheImage (
   FmpHeaderSize    = 0;
   AllHeaderSize    = 0;
 
+  //
+  // Retrieve the private context structure
+  //
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
+
   //
   // make sure the descriptor has already been loaded
   //
-  if (!mDescriptorPopulated) {
-    PopulateDescriptor();
-  }
+  PopulateDescriptor (Private);
 
   if (ImageUpdatable == NULL) {
     DEBUG ((DEBUG_ERROR, "FmpDxe: CheckImage() - ImageUpdatable Pointer Parameter is NULL.\n"));
@@ -776,11 +816,11 @@ CheckTheImage (
   //
   // Check the lowest supported version
   //
-  if (Version < mDesc.LowestSupportedImageVersion) {
+  if (Version < Private->Descriptor.LowestSupportedImageVersion) {
     DEBUG (
       (DEBUG_ERROR,
       "FmpDxe: CheckTheImage() - Version Lower than lowest supported version. 0x%08X < 0x%08X\n",
-      Version, mDesc.LowestSupportedImageVersion)
+      Version, Private->Descriptor.LowestSupportedImageVersion)
       );
     *ImageUpdatable = IMAGE_UPDATABLE_INVALID_OLD;
     Status = EFI_SUCCESS;
@@ -880,17 +920,18 @@ SetTheImage (
   OUT CHAR16                                         **AbortReason
   )
 {
-  EFI_STATUS  Status;
-  UINT32      Updateable;
-  BOOLEAN     BooleanValue;
-  UINT32      FmpHeaderSize;
-  VOID        *FmpHeader;
-  UINTN       FmpPayloadSize;
-  UINT32      AllHeaderSize;
-  UINT32      IncommingFwVersion;
-  UINT32      LastAttemptStatus;
-  UINT32      Version;
-  UINT32      LowestSupportedVersion;
+  EFI_STATUS                        Status;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+  UINT32                            Updateable;
+  BOOLEAN                           BooleanValue;
+  UINT32                            FmpHeaderSize;
+  VOID                              *FmpHeader;
+  UINTN                             FmpPayloadSize;
+  UINT32                            AllHeaderSize;
+  UINT32                            IncommingFwVersion;
+  UINT32                            LastAttemptStatus;
+  UINT32                            Version;
+  UINT32                            LowestSupportedVersion;
 
   Status             = EFI_SUCCESS;
   Updateable         = 0;
@@ -902,6 +943,11 @@ SetTheImage (
   IncommingFwVersion = 0;
   LastAttemptStatus  = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;
 
+  //
+  // Retrieve the private context structure
+  //
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
 
   SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear any previous results.
 
@@ -909,7 +955,7 @@ SetTheImage (
   // 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) {
+  if (Private->FmpDeviceLocked) {
     DEBUG ((DEBUG_ERROR, "FmpDxe: SetTheImage() - Device is already locked.  Can't update.\n"));
     Status = EFI_UNSUPPORTED;
     goto cleanup;
@@ -963,7 +1009,6 @@ SetTheImage (
   }
 
   mProgressFunc = Progress;
-  mProgressSupported = TRUE;
 
   //
   // Checking the image is at least 1%
@@ -1084,7 +1129,7 @@ SetTheImage (
   //
   // Update the version stored in variable
   //
-  if (!mRuntimeVersionSupported) {
+  if (!Private->RuntimeVersionSupported) {
     Version = DEFAULT_VERSION;
     GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version);
     SetVersionInVariable (Version);
@@ -1103,7 +1148,6 @@ SetTheImage (
 
 cleanup:
   mProgressFunc = NULL;
-  mProgressSupported = FALSE;
   SetLastAttemptStatusInVariable (LastAttemptStatus);
 
   if (Progress != NULL) {
@@ -1117,7 +1161,7 @@ cleanup:
   // Need repopulate after SetImage is called to
   // update LastAttemptVersion and LastAttemptStatus.
   //
-  mDescriptorPopulated = FALSE;
+  Private->DescriptorPopulated = FALSE;
 
   return Status;
 }
@@ -1228,12 +1272,16 @@ FmpDxeLockEventNotify (
   IN VOID       *Context
   )
 {
-  EFI_STATUS  Status;
+  EFI_STATUS                        Status;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+
+  Private = (FIRMWARE_MANAGEMENT_PRIVATE_DATA *)Context;
 
-  if (!mFmpDeviceLocked) {
+  if (!Private->FmpDeviceLocked) {
     //
     // Lock the firmware device
     //
+    FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
     Status = FmpDeviceLock();
     if (EFI_ERROR (Status)) {
       if (Status != EFI_UNSUPPORTED) {
@@ -1242,7 +1290,7 @@ FmpDxeLockEventNotify (
         DEBUG ((DEBUG_WARN, "FmpDxe: FmpDeviceLock() returned error.  Status = %r\n", Status));
       }
     }
-    mFmpDeviceLocked = TRUE;
+    Private->FmpDeviceLocked = TRUE;
   }
 }
 
@@ -1262,85 +1310,198 @@ InstallFmpInstance (
   IN EFI_HANDLE  Handle
   )
 {
-  EFI_STATUS                                   Status;
-  EFI_FIRMWARE_MANAGEMENT_PROTOCOL             *Fmp;
-  EDKII_FIRMWARE_MANAGEMENT_PROGRESS_PROTOCOL  *FmpProgress;
+  EFI_STATUS                        Status;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
 
-  Status      = EFI_SUCCESS;
-  Fmp         = NULL;
-  FmpProgress = NULL;
+  DEBUG ((DEBUG_ERROR, "InstallFmpInstance: Entry\n"));
 
   //
   // Only allow a single FMP Protocol instance to be installed
   //
-  if (mFmpInstalled) {
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiFirmwareManagementProtocolGuid,
+                  (VOID **)&Fmp,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (!EFI_ERROR (Status)) {
     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"));
+  Private = AllocateCopyPool (
+              sizeof (mFirmwareManagementPrivateDataTemplate),
+              &mFirmwareManagementPrivateDataTemplate
+              );
+  if (Private == NULL) {
+    DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to allocate memory for private structure.\n"));
     Status = EFI_OUT_OF_RESOURCES;
     goto cleanup;
   }
 
   //
-  // Allocate FMP Progress Protocol instance
+  // Initialize private context data structure
   //
-  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);
+  DEBUG ((DEBUG_ERROR, "InstallFmpInstance: Initialize private context data structure\n"));
+
+  Private->Handle = Handle;
+
+  Private->FmpDeviceContext = NULL;
+  Status = FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
+  if (Status == EFI_UNSUPPORTED) {
+    Private->FmpDeviceContext = NULL;
+  } else if (EFI_ERROR (Status)) {
     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;
+  DEBUG ((DEBUG_ERROR, "InstallFmpInstance: Lock events\n"));
 
-  //
-  // Fill in FMP Progress Protocol fields for Version 1
-  //
-  FmpProgress->Version                        = 1;
-  FmpProgress->ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);
-  FmpProgress->WatchdogSeconds                = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);
+  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", Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\n"));
+    }
+
+    //
+    // Create and register notify function to lock the FMP device.
+    //
+    Status = gBS->CreateEventEx (
+                    EVT_NOTIFY_SIGNAL,
+                    TPL_CALLBACK,
+                    FmpDxeLockEventNotify,
+                    Private,
+                    mLockGuid,
+                    &Private->FmpDeviceLockEvent
+                    );
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register notification.  Status = %r\n", Status));
+    }
+    ASSERT_EFI_ERROR (Status);
+  } else {
+    DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not registering notification to call FmpDeviceLock() because mfg mode\n"));
+  }
 
   //
   // Install FMP Protocol and FMP Progress Protocol
   //
+  DEBUG ((DEBUG_ERROR, "InstallFmpInstance: Install FMP Protocol and FMP Progress Protocol\n"));
+
   Status = gBS->InstallMultipleProtocolInterfaces (
-                  &Handle,
-                  &gEfiFirmwareManagementProtocolGuid,
-                  Fmp,
-                  &gEdkiiFirmwareManagementProgressProtocolGuid,
-                  FmpProgress,
+                  &Private->Handle,
+                  &gEfiFirmwareManagementProtocolGuid, &Private->Fmp,
+                  &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress,
                   NULL
                   );
 
   if (EFI_ERROR (Status)) {
-    DEBUG ((DEBUG_ERROR, "FmpDxe: FMP Protocol install error. Status = %r.\n", Status));
-    FreePool (Fmp);
+    DEBUG ((DEBUG_ERROR, "FmpDxe: Protocol install error. Status = %r.\n", Status));
     goto cleanup;
   }
 
-  DEBUG ((DEBUG_INFO, "FmpDxe: FMP Protocol Installed!\n"));
-  mFmpInstalled = TRUE;
+  DEBUG ((DEBUG_INFO, "FmpDxe: Protocols Installed!\n"));
 
 cleanup:
 
+  if (EFI_ERROR (Status)) {
+    if (Private != NULL) {
+      if (Private->FmpDeviceLockEvent != NULL) {
+        gBS->CloseEvent (Private->FmpDeviceLockEvent);
+      }
+      FreePool (Private);
+    }
+  }
+
   return Status;
 }
 
+/**
+  Function to uninstall 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
+UninstallFmpInstance (
+  IN EFI_HANDLE  Handle
+  )
+{
+  EFI_STATUS                        Status;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL  *Fmp;
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private;
+
+  Status = gBS->OpenProtocol (
+                  Handle,
+                  &gEfiFirmwareManagementProtocolGuid,
+                  (VOID **)&Fmp,
+                  NULL,
+                  NULL,
+                  EFI_OPEN_PROTOCOL_GET_PROTOCOL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (Fmp);
+  FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
+
+  if (Private->FmpDeviceLockEvent != NULL) {
+    gBS->CloseEvent (Private->FmpDeviceLockEvent);
+  }
+
+  Status = gBS->UninstallMultipleProtocolInterfaces (
+                  Private->Handle,
+                  &gEfiFirmwareManagementProtocolGuid, &Private->Fmp,
+                  &gEdkiiFirmwareManagementProgressProtocolGuid, &mFmpProgress,
+                  NULL
+                  );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);
+
+  FreePool (Private);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Unloads the application and its installed protocol.
+
+  @param ImageHandle       Handle that identifies the image to be unloaded.
+  @param  SystemTable      The system table.
+
+  @retval EFI_SUCCESS      The image has been unloaded.
+
+**/
+EFI_STATUS
+EFIAPI
+FmpDxeLibDestructor (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  if (mFmpSingleInstance) {
+    return UninstallFmpInstance (ImageHandle);
+  }
+  return EFI_SUCCESS;
+}
+
 /**
   Main entry for this driver/library.
 
@@ -1356,7 +1517,6 @@ FmpDxeEntryPoint (
   )
 {
   EFI_STATUS  Status;
-  EFI_GUID    *LockGuid;
 
   //
   // Verify that a new FILE_GUID value has been provided in the <Defines>
@@ -1381,49 +1541,28 @@ FmpDxeEntryPoint (
     ASSERT (FALSE);
   }
 
+
   //
   // Detects if PcdFmpDevicePkcs7CertBufferXdr contains a test key.
   //
   DetectTestKey ();
 
-  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", Status));
-    } else {
-      DEBUG ((DEBUG_INFO, "FmpDxe: All variables locked\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));
+  //
+  // Fill in FMP Progress Protocol fields for Version 1
+  //
+  mFmpProgress.Version                        = 1;
+  mFmpProgress.ProgressBarForegroundColor.Raw = PcdGet32 (PcdFmpDeviceProgressColor);
+  mFmpProgress.WatchdogSeconds                = PcdGet8 (PcdFmpDeviceProgressWatchdogTimeInSeconds);
 
-    Status = gBS->CreateEventEx (
-                    EVT_NOTIFY_SIGNAL,
-                    TPL_CALLBACK,
-                    FmpDxeLockEventNotify,
-                    NULL,
-                    LockGuid,
-                    &mFmpDeviceLockEvent
-                    );
-    if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to register notification.  Status = %r\n", Status));
-    }
-    ASSERT_EFI_ERROR (Status);
-  } else {
-    DEBUG ((DEBUG_VERBOSE, "FmpDxe: Not registering notification to call FmpDeviceLock() because mfg mode\n"));
+  // The lock event GUID is retrieved from PcdFmpDeviceLockEventGuid.
+  // If PcdFmpDeviceLockEventGuid is not the size of an EFI_GUID, then
+  // gEfiEndOfDxeEventGroupGuid is used.
+  //
+  mLockGuid = &gEfiEndOfDxeEventGroupGuid;
+  if (PcdGetSize (PcdFmpDeviceLockEventGuid) == sizeof (EFI_GUID)) {
+    mLockGuid = (EFI_GUID *)PcdGetPtr (PcdFmpDeviceLockEventGuid);
   }
+  DEBUG ((DEBUG_INFO, "FmpDxe: Lock GUID: %g\n", mLockGuid));
 
   //
   // Register with library the install function so if the library uses
@@ -1433,8 +1572,15 @@ FmpDxeEntryPoint (
   //
   Status = RegisterFmpInstaller (InstallFmpInstance);
   if (Status == EFI_UNSUPPORTED) {
+    mFmpSingleInstance = TRUE;
     DEBUG ((DEBUG_INFO, "FmpDxe: FmpDeviceLib registration returned EFI_UNSUPPORTED.  Installing single FMP instance.\n"));
-    Status = InstallFmpInstance (ImageHandle);
+    Status = RegisterFmpUninstaller (UninstallFmpInstance);
+    if (Status == EFI_UNSUPPORTED) {
+      Status = InstallFmpInstance (ImageHandle);
+    } else {
+      DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n"));
+      Status = EFI_UNSUPPORTED;
+    }
   } else if (EFI_ERROR (Status)) {
     DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib registration returned %r.  No FMP installed.\n", Status));
   } else {
@@ -1442,6 +1588,10 @@ FmpDxeEntryPoint (
       DEBUG_INFO,
       "FmpDxe: FmpDeviceLib registration returned EFI_SUCCESS.  Expect FMP to be installed during the BDS/Device connection phase.\n"
       ));
+    Status = RegisterFmpUninstaller (UninstallFmpInstance);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "FmpDxe: FmpDeviceLib RegisterFmpInstaller and RegisterFmpUninstaller do not match.\n"));
+    }
   }
 
   return Status;
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.h b/FmpDevicePkg/FmpDxe/FmpDxe.h
new file mode 100644
index 0000000000..c2ffc439d1
--- /dev/null
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.h
@@ -0,0 +1,341 @@
+/** @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 - 2019, Intel Corporation. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _FMP_DXE_H_
+#define _FMP_DXE_H_
+
+#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"
+
+///
+///
+///
+#define FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('f','m','p','p')
+
+typedef struct {
+  UINTN                                        Signature;
+  EFI_HANDLE                                   Handle;
+  EFI_FIRMWARE_MANAGEMENT_PROTOCOL             Fmp;
+  BOOLEAN                                      DescriptorPopulated;
+  EFI_FIRMWARE_IMAGE_DESCRIPTOR                Descriptor;
+  CHAR16                                       *ImageIdName;
+  CHAR16                                       *VersionName;
+  BOOLEAN                                      RuntimeVersionSupported;
+  EFI_EVENT                                    FmpDeviceLockEvent;
+  //
+  // Indicates if an attempt has been made to lock a
+  // FLASH storage device by calling FmpDeviceLock().
+  // A FLASH storage device may not support being locked,
+  // so this variable is set to TRUE even if FmpDeviceLock()
+  // returns an error.
+  //
+  BOOLEAN                                      FmpDeviceLocked;
+  VOID                                         *FmpDeviceContext;
+} FIRMWARE_MANAGEMENT_PRIVATE_DATA;
+
+///
+///
+///
+#define FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS(a) \
+  CR (a, FIRMWARE_MANAGEMENT_PRIVATE_DATA, Fmp, FIRMWARE_MANAGEMENT_PRIVATE_DATA_SIGNATURE)
+
+/**
+  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
+  );
+
+/**
+  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
+  );
+
+/**
+  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[in, out] Image          Points to the buffer where the current image is copied to.
+  @param[in, 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_VIOLATION 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
+  );
+
+
+/**
+  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_ABORTED            The operation is aborted.
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.
+  @retval EFI_UNSUPPORTED        The operation is not supported.
+  @retval EFI_SECURITY_VIOLATION 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                            *ImageUpdatable
+  );
+
+/**
+  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_VIOLATION 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
+  );
+
+/**
+  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
+  );
+
+/**
+  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_VIOLATION 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
+  );
+
+#endif
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.inf b/FmpDevicePkg/FmpDxe/FmpDxe.inf
index cc57de975a..e3f9d174ef 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxe.inf
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.inf
@@ -4,7 +4,7 @@
 #  information provided through PCDs and libraries.
 #
 #  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
-#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
@@ -17,6 +17,7 @@
   MODULE_TYPE                    = DXE_DRIVER
   VERSION_STRING                 = 1.0
   ENTRY_POINT                    = FmpDxeEntryPoint
+  UNLOAD_IMAGE                   = UninstallFmpInstance
 
 #
 # The following information is for reference only and not required by the build tools.
@@ -26,6 +27,7 @@
 
 [Sources]
   FmpDxe.c
+  FmpDxe.h
   DetectTestKey.c
   VariableSupport.h
   VariableSupport.c
diff --git a/FmpDevicePkg/FmpDxe/FmpDxeLib.inf b/FmpDevicePkg/FmpDxe/FmpDxeLib.inf
index 9722918b18..3b639fa74d 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxeLib.inf
+++ b/FmpDevicePkg/FmpDxe/FmpDxeLib.inf
@@ -4,7 +4,7 @@
 #  information provided through PCDs and libraries.
 #
 #  Copyright (c) 2016, Microsoft Corporation. All rights reserved.<BR>
-#  Copyright (c) 2018, Intel Corporation. All rights reserved.<BR>
+#  Copyright (c) 2018 - 2019, Intel Corporation. All rights reserved.<BR>
 #
 #  SPDX-License-Identifier: BSD-2-Clause-Patent
 ##
@@ -18,6 +18,7 @@
   VERSION_STRING                 = 1.0
   LIBRARY_CLASS                  = NULL
   CONSTRUCTOR                    = FmpDxeEntryPoint
+  DESTRUCTOR                     = FmpDxeLibDestructor
 
 #
 # The following information is for reference only and not required by the build tools.
@@ -27,6 +28,7 @@
 
 [Sources]
   FmpDxe.c
+  FmpDxe.h
   DetectTestKey.c
   VariableSupport.h
   VariableSupport.c
-- 
2.20.1.windows.1


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.

View/Reply Online (#45335): https://edk2.groups.io/g/devel/message/45335
Mute This Topic: https://groups.io/mt/32836417/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-




More information about the edk2-devel-archive mailing list