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

Cc: Sean Brogan <sean.bro...@microsoft.com>
Cc: Bret Barkelew <bret.barke...@microsoft.com>
Cc: Liming Gao <liming....@intel.com>
Signed-off-by: Michael D Kinney <michael.d.kin...@intel.com>
Signed-off-by: Eric Jin <eric....@intel.com>
---
 FmpDevicePkg/FmpDxe/FmpDxe.c          | 124 +++-
 FmpDevicePkg/FmpDxe/FmpDxe.h          |   8 +-
 FmpDevicePkg/FmpDxe/VariableSupport.c | 824 ++++++++++++++++++--------
 FmpDevicePkg/FmpDxe/VariableSupport.h | 135 ++++-
 4 files changed, 786 insertions(+), 305 deletions(-)

diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.c b/FmpDevicePkg/FmpDxe/FmpDxe.c
index dab3310834..1574425fd6 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxe.c
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.c
@@ -11,6 +11,7 @@
 **/
 
 #include "FmpDxe.h"
+#include "VariableSupport.h"
 
 ///
 /// FILE_GUID from FmpDxe.inf.  When FmpDxe.inf is used in a platform, the
@@ -73,7 +74,13 @@ const FIRMWARE_MANAGEMENT_PRIVATE_DATA  
mFirmwareManagementPrivateDataTemplate =
   NULL,                                        // VersionName
   TRUE,                                        // RuntimeVersionSupported
   NULL,                                        // FmpDeviceLockEvent
-  FALSE                                        // FmpDeviceLocked
+  FALSE,                                       // FmpDeviceLocked
+  NULL,                                        // FmpDeviceContext
+  NULL,                                        // VersionVariableName
+  NULL,                                        // LsvVariableName
+  NULL,                                        // LastAttemptStatusVariableName
+  NULL,                                        // 
LastAttemptVersionVariableName
+  NULL                                         // FmpStateVariableName
 };
 
 ///
@@ -193,7 +200,7 @@ GetImageTypeNameString (
 **/
 UINT32
 GetLowestSupportedVersion (
-  VOID
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
   EFI_STATUS  Status;
@@ -230,7 +237,7 @@ GetLowestSupportedVersion (
   //
   // Check the lowest supported version UEFI variable for this device
   //
-  VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable();
+  VariableLowestSupportedVersion = GetLowestSupportedVersionFromVariable 
(Private);
   if (VariableLowestSupportedVersion > ReturnLsv) {
     ReturnLsv = VariableLowestSupportedVersion;
   }
@@ -265,6 +272,20 @@ PopulateDescriptor (
   Private->Descriptor.ImageId     = Private->Descriptor.ImageIndex;
   Private->Descriptor.ImageIdName = GetImageTypeNameString();
 
+  //
+  // Get the hardware instance from FmpDeviceLib
+  //
+  Status = FmpDeviceGetHardwareInstance 
(&Private->Descriptor.HardwareInstance);
+  if (Status == EFI_UNSUPPORTED) {
+    Private->Descriptor.HardwareInstance = 0;
+  }
+
+  //
+  // Generate UEFI Variable names used to store status information for this
+  // FMP instance.
+  //
+  GenerateFmpVariableNames (Private);
+
   //
   // Get the version.  Some devices don't support getting the firmware version
   // at runtime.  If FmpDeviceLib does not support returning a version, then
@@ -273,7 +294,7 @@ PopulateDescriptor (
   Status = FmpDeviceGetVersion (&Private->Descriptor.Version);
   if (Status == EFI_UNSUPPORTED) {
     Private->RuntimeVersionSupported = FALSE;
-    Private->Descriptor.Version = GetVersionFromVariable();
+    Private->Descriptor.Version = GetVersionFromVariable (Private);
   } else if (EFI_ERROR (Status)) {
     //
     // Unexpected error.   Use default version.
@@ -309,7 +330,7 @@ PopulateDescriptor (
                                         );
   }
 
-  Private->Descriptor.LowestSupportedImageVersion = 
GetLowestSupportedVersion();
+  Private->Descriptor.LowestSupportedImageVersion = GetLowestSupportedVersion 
(Private);
 
   //
   // Get attributes from the FmpDeviceLib
@@ -341,16 +362,8 @@ PopulateDescriptor (
     Private->Descriptor.Size = 0;
   }
 
-  Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable 
();
-  Private->Descriptor.LastAttemptStatus  = GetLastAttemptStatusFromVariable ();
-
-  //
-  // Get the hardware instance from FmpDeviceLib
-  //
-  Status = FmpDeviceGetHardwareInstance 
(&Private->Descriptor.HardwareInstance);
-  if (Status == EFI_UNSUPPORTED) {
-    Private->Descriptor.HardwareInstance = 0;
-  }
+  Private->Descriptor.LastAttemptVersion = GetLastAttemptVersionFromVariable 
(Private);
+  Private->Descriptor.LastAttemptStatus  = GetLastAttemptStatusFromVariable 
(Private);
 
   Private->DescriptorPopulated = TRUE;
 }
@@ -453,7 +466,7 @@ GetTheImageInfo (
   *ImageInfoSize = sizeof (EFI_FIRMWARE_IMAGE_DESCRIPTOR);
 
   //
-  // make sure the descriptor has already been loaded
+  // Make sure the descriptor has already been loaded or refreshed
   //
   PopulateDescriptor (Private);
 
@@ -696,7 +709,7 @@ CheckTheImage (
   FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
 
   //
-  // make sure the descriptor has already been loaded
+  // Make sure the descriptor has already been loaded or refreshed
   //
   PopulateDescriptor (Private);
 
@@ -949,7 +962,15 @@ SetTheImage (
   Private = FIRMWARE_MANAGEMENT_PRIVATE_DATA_FROM_THIS (This);
   FmpDeviceSetContext (Private->Handle, &Private->FmpDeviceContext);
 
-  SetLastAttemptVersionInVariable (IncommingFwVersion); //set to 0 to clear 
any previous results.
+  //
+  // Make sure the descriptor has already been loaded or refreshed
+  //
+  PopulateDescriptor (Private);
+
+  //
+  // Set to 0 to clear any previous results.
+  //
+  SetLastAttemptVersionInVariable (Private, IncommingFwVersion);
 
   //
   // if we have locked the device, then skip the set operation.
@@ -988,7 +1009,7 @@ SetTheImage (
     //
     // Set to actual value
     //
-    SetLastAttemptVersionInVariable (IncommingFwVersion);
+    SetLastAttemptVersionInVariable (Private, IncommingFwVersion);
   }
 
 
@@ -1080,7 +1101,7 @@ SetTheImage (
   // Save LastAttemptStatus as error so that if SetImage never returns the 
error
   // state is recorded.
   //
-  SetLastAttemptStatusInVariable (LastAttemptStatus);
+  SetLastAttemptStatusInVariable (Private, LastAttemptStatus);
 
   //
   // Strip off all the headers so the device can process its firmware
@@ -1132,23 +1153,21 @@ SetTheImage (
   if (!Private->RuntimeVersionSupported) {
     Version = DEFAULT_VERSION;
     GetFmpPayloadHeaderVersion (FmpHeader, FmpPayloadSize, &Version);
-    SetVersionInVariable (Version);
+    SetVersionInVariable (Private, Version);
   }
 
   //
   // Update lowest supported variable
   //
-  {
-    LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
-    GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, 
&LowestSupportedVersion);
-    SetLowestSupportedVersionInVariable (LowestSupportedVersion);
-  }
+  LowestSupportedVersion = DEFAULT_LOWESTSUPPORTEDVERSION;
+  GetFmpPayloadHeaderLowestSupportedVersion (FmpHeader, FmpPayloadSize, 
&LowestSupportedVersion);
+  SetLowestSupportedVersionInVariable (Private, LowestSupportedVersion);
 
   LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;
 
 cleanup:
   mProgressFunc = NULL;
-  SetLastAttemptStatusInVariable (LastAttemptStatus);
+  SetLastAttemptStatusInVariable (Private, LastAttemptStatus);
 
   if (Progress != NULL) {
     //
@@ -1359,13 +1378,18 @@ InstallFmpInstance (
     goto cleanup;
   }
 
+  //
+  // Make sure the descriptor has already been loaded or refreshed
+  //
+  PopulateDescriptor (Private);
+
   DEBUG ((DEBUG_ERROR, "InstallFmpInstance: Lock events\n"));
 
   if (IsLockFmpDeviceAtLockEventGuidRequired ()) {
     //
     // Lock all UEFI Variables used by this module.
     //
-    Status = LockAllFmpVariables ();
+    Status = LockAllFmpVariables (Private);
     if (EFI_ERROR (Status)) {
       DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variables.  Status = 
%r.\n", Status));
     } else {
@@ -1417,6 +1441,27 @@ cleanup:
       if (Private->FmpDeviceLockEvent != NULL) {
         gBS->CloseEvent (Private->FmpDeviceLockEvent);
       }
+      if (Private->Descriptor.VersionName != NULL) {
+        FreePool (Private->Descriptor.VersionName);
+      }
+      if (Private->FmpDeviceContext != NULL) {
+        FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);
+      }
+      if (Private->VersionVariableName != NULL) {
+        FreePool (Private->VersionVariableName);
+      }
+      if (Private->LsvVariableName != NULL) {
+        FreePool (Private->LsvVariableName);
+      }
+      if (Private->LastAttemptStatusVariableName != NULL) {
+        FreePool (Private->LastAttemptStatusVariableName);
+      }
+      if (Private->LastAttemptVersionVariableName != NULL) {
+        FreePool (Private->LastAttemptVersionVariableName);
+      }
+      if (Private->FmpStateVariableName != NULL) {
+        FreePool (Private->FmpStateVariableName);
+      }
       FreePool (Private);
     }
   }
@@ -1473,8 +1518,27 @@ UninstallFmpInstance (
     return Status;
   }
 
-  FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);
-
+  if (Private->Descriptor.VersionName != NULL) {
+    FreePool (Private->Descriptor.VersionName);
+  }
+  if (Private->FmpDeviceContext != NULL) {
+    FmpDeviceSetContext (NULL, &Private->FmpDeviceContext);
+  }
+  if (Private->VersionVariableName != NULL) {
+    FreePool (Private->VersionVariableName);
+  }
+  if (Private->LsvVariableName != NULL) {
+    FreePool (Private->LsvVariableName);
+  }
+  if (Private->LastAttemptStatusVariableName != NULL) {
+    FreePool (Private->LastAttemptStatusVariableName);
+  }
+  if (Private->LastAttemptVersionVariableName != NULL) {
+    FreePool (Private->LastAttemptVersionVariableName);
+  }
+  if (Private->FmpStateVariableName != NULL) {
+    FreePool (Private->FmpStateVariableName);
+  }
   FreePool (Private);
 
   return EFI_SUCCESS;
diff --git a/FmpDevicePkg/FmpDxe/FmpDxe.h b/FmpDevicePkg/FmpDxe/FmpDxe.h
index c2ffc439d1..06514c67c8 100644
--- a/FmpDevicePkg/FmpDxe/FmpDxe.h
+++ b/FmpDevicePkg/FmpDxe/FmpDxe.h
@@ -18,6 +18,7 @@
 #include <Library/BaseLib.h>
 #include <Library/BaseMemoryLib.h>
 #include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
 #include <Library/MemoryAllocationLib.h>
 #include <Library/UefiLib.h>
 #include <Library/FmpAuthenticationLib.h>
@@ -26,9 +27,9 @@
 #include <Library/CapsuleUpdatePolicyLib.h>
 #include <Protocol/FirmwareManagement.h>
 #include <Protocol/FirmwareManagementProgress.h>
+#include <Protocol/VariableLock.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"
@@ -57,6 +58,11 @@ typedef struct {
   //
   BOOLEAN                                      FmpDeviceLocked;
   VOID                                         *FmpDeviceContext;
+  CHAR16                                       *VersionVariableName;
+  CHAR16                                       *LsvVariableName;
+  CHAR16                                       *LastAttemptStatusVariableName;
+  CHAR16                                       *LastAttemptVersionVariableName;
+  CHAR16                                       *FmpStateVariableName;
 } FIRMWARE_MANAGEMENT_PRIVATE_DATA;
 
 ///
diff --git a/FmpDevicePkg/FmpDxe/VariableSupport.c 
b/FmpDevicePkg/FmpDxe/VariableSupport.c
index 57f4388df2..d06d6b36c7 100644
--- a/FmpDevicePkg/FmpDxe/VariableSupport.c
+++ b/FmpDevicePkg/FmpDxe/VariableSupport.c
@@ -3,81 +3,339 @@
   firmware updates.
 
   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/UefiBootServicesTableLib.h>
-#include <Library/UefiRuntimeServicesTableLib.h>
-#include <Library/UefiLib.h>
-#include <Library/MemoryAllocationLib.h>
-#include <Protocol/VariableLock.h>
+#include "FmpDxe.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
-};
+/**
+  Retrieve the value of a 32-bit UEFI Variable specified by VariableName and
+  a GUID of gEfiCallerIdGuid.
+
+  @param[in]  VariableName  Pointer to the UEFI Variable name to retrieve.
+  @param[out] Valid         Set to TRUE if UEFI Variable is present and the 
size
+                            of the UEFI Variable value is 32-bits.  Otherwise
+                            FALSE.
+  @param[out] Value         If Valid is set to TRUE, then the 32-bit value of
+                            the UEFI Variable.  Otherwise 0.
+**/
+static
+VOID
+GetFmpVariable (
+  IN  CHAR16   *VariableName,
+  OUT BOOLEAN  *Valid,
+  OUT UINT32   *Value
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       Size;
+  UINT32      *Buffer;
+
+  *Valid = FALSE;
+  *Value = 0;
+  Size   = 0;
+  Buffer = NULL;
+  Status = GetVariable2 (
+             VariableName,
+             &gEfiCallerIdGuid,
+             (VOID **)&Buffer,
+             &Size
+             );
+  if (!EFI_ERROR (Status) && Size == sizeof (*Value) && Buffer != NULL) {
+    *Valid = TRUE;
+    *Value = *Buffer;
+  }
+  if (Buffer != NULL) {
+    FreePool (Buffer);
+  }
+}
 
 /**
-  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.
+  Delete the UEFI Variable with name specified by VariableName and GUID of
+  gEfiCallerIdGuid.  If the variable can not be deleted, then print a
+  DEBUG_ERROR message.
 
-  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+  @param[in] VariableName  Pointer to the UEFI Variable name to delete.
+**/
+static
+VOID
+DeleteFmpVariable (
+  IN CHAR16  *VariableName
+  )
+{
+  EFI_STATUS  Status;
+  BOOLEAN     Valid;
+  UINT32      Value;
 
-  @return  The version of the firmware image in the firmware device.
+  GetFmpVariable (VariableName, &Valid, &Value);
+  if (Valid) {
+    Status = gRT->SetVariable (VariableName, &gEfiCallerIdGuid, 0, 0, NULL);
+    if (EFI_ERROR (Status)) {
+      DEBUG ((DEBUG_ERROR, "Failed to delete FMP Variable %s.  Status = %r\n", 
VariableName, Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "Deleted FMP Variable %s\n", VariableName));
+    }
+  }
+}
+
+/**
+  Retrieve the FMP Controller State UEFI Variable value.  Return NULL if
+  the variable does not exist or if the size of the UEFI Variable is not the
+  size of FMP_CONTROLLER_STATE.  The buffer for the UEFI Variable value
+  if allocated using the UEFI Boot Service AllocatePool().
 
+  @param[in] Private  Private context structure for the managed controller.
+
+  @return  Pointer to the allocated FMP Controller State.  Returns NULL
+           if the variable does not exist or is a different size than expected.
 **/
-UINT32
-GetVersionFromVariable (
-  VOID
+static
+FMP_CONTROLLER_STATE *
+GetFmpControllerState (
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
-  EFI_STATUS  Status;
-  UINT32      *Value;
-  UINTN       Size;
-  UINT32      Version;
+  EFI_STATUS            Status;
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  UINTN                 Size;
+
+  FmpControllerState = NULL;
+  Size               = 0;
+  Status = GetVariable2 (
+             Private->FmpStateVariableName,
+             &gEfiCallerIdGuid,
+             (VOID **)&FmpControllerState,
+             &Size
+             );
+  if (EFI_ERROR (Status) || FmpControllerState == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to get the FMP Controller State.  Status = 
%r\n", Status));
+  } else {
+    if (Size == sizeof (*FmpControllerState)) {
+      return FmpControllerState;
+    }
+    DEBUG ((DEBUG_ERROR, "Getting FMP Controller State returned a size 
different than expected. Size = 0x%x\n", Size));
+  }
+  if (FmpControllerState != NULL) {
+    FreePool (FmpControllerState);
+  }
+  return NULL;
+}
 
-  Value = NULL;
-  Size = 0;
-  Version = DEFAULT_VERSION;
+/**
+  Generates a Null-terminated Unicode string UEFI Variable name from a base 
name
+  and a hardware instance.  If the hardware instance value is 0, then the base
+  name is returned.  If the hardware instance value is non-zero, then the 
64-bit
+  hardware instance value is converted to a 16 character hex string and 
appended
+  to base name.  The UEFI Variable name returned is allocated using the UEFI
+  Boot Service AllocatePool().
+
+  @param[in] HardwareInstance  64-bit hardware instance value.
+  @param[in] BaseVariableName  Null-terminated Unicode string that is the base
+                               name of the UEFI Variable.
+
+  @return  Pointer to the allocated UEFI Variable name.  Returns NULL if the
+           UEFI Variable can not be allocated.
+**/
+static
+CHAR16 *
+GenerateFmpVariableName (
+  IN  UINT64  HardwareInstance,
+  IN  CHAR16  *BaseVariableName
+  )
+{
+  CHAR16  *VariableName;
+
+  VariableName = CatSPrint (NULL, BaseVariableName);
+  if (VariableName == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to generate FMP variable name %s.\n", 
BaseVariableName));
+    return VariableName;
+  }
+  if (HardwareInstance == 0) {
+    return VariableName;
+  }
+  VariableName = CatSPrint (VariableName, L"%016lx", HardwareInstance);
+  if (VariableName == NULL) {
+    DEBUG ((DEBUG_ERROR, "Failed to generate FMP variable name %s.\n", 
BaseVariableName));
+  }
+  return VariableName;
+}
+
+/**
+  Generate the names of the UEFI Variables used to store state information for
+  a managed controller.  The UEFI Variables names are a combination of a base
+  name and an optional hardware instance value as a 16 character hex value.  If
+  the hardware instance value is 0, then the 16 character hex value is not
+  included.  These storage for the UEFI Variable names are allocated using the
+  UEFI Boot Service AllocatePool() and the pointers are stored in the Private.
+  The following are examples of variable names produces for hardware instance
+  value 0 and value 0x1234567812345678.
+
+    FmpVersion
+    FmpLsv
+    LastAttemptStatus
+    LastAttemptVersion
+    FmpState
+
+    FmpVersion1234567812345678
+    FmpLsv1234567812345678
+    LastAttemptStatus1234567812345678
+    LastAttemptVersion1234567812345678
+    FmpState1234567812345678
+
+  @param[in,out] Private  Private context structure for the managed controller.
+**/
+VOID
+GenerateFmpVariableNames (
+  IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
+  )
+{
+  EFI_STATUS                   Status;
+  VOID                         *Buffer;
+  FMP_CONTROLLER_STATE  FmpControllerState;
+
+  if (Private->VersionVariableName != NULL) {
+    FreePool (Private->VersionVariableName);
+  }
+  if (Private->LsvVariableName != NULL) {
+    FreePool (Private->LsvVariableName);
+  }
+  if (Private->LastAttemptStatusVariableName != NULL) {
+    FreePool (Private->LastAttemptStatusVariableName);
+  }
+  if (Private->LastAttemptVersionVariableName != NULL) {
+    FreePool (Private->LastAttemptVersionVariableName);
+  }
+  if (Private->FmpStateVariableName != NULL) {
+    FreePool (Private->FmpStateVariableName);
+  }
 
-  Status = GetVariable2 (VARNAME_VERSION, &gEfiCallerIdGuid, (VOID **)&Value, 
&Size);
-  if (EFI_ERROR (Status) || (Value == NULL)) {
-    DEBUG ((DEBUG_ERROR, "Failed to get the Version from variable.  Status = 
%r\n", Status));
-    return Version;
+  Private->VersionVariableName = GenerateFmpVariableName (
+                                   Private->Descriptor.HardwareInstance,
+                                   VARNAME_VERSION
+                                   );
+  Private->LsvVariableName = GenerateFmpVariableName (
+                               Private->Descriptor.HardwareInstance,
+                               VARNAME_LSV
+                               );
+  Private->LastAttemptStatusVariableName = GenerateFmpVariableName (
+                                             
Private->Descriptor.HardwareInstance,
+                                             VARNAME_LASTATTEMPTSTATUS
+                                             );
+  Private->LastAttemptVersionVariableName = GenerateFmpVariableName (
+                                              
Private->Descriptor.HardwareInstance,
+                                              VARNAME_LASTATTEMPTVERSION
+                                              );
+  Private->FmpStateVariableName = GenerateFmpVariableName (
+                                    Private->Descriptor.HardwareInstance,
+                                    VARNAME_FMPSTATE
+                                    );
+
+  DEBUG ((DEBUG_INFO, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid, 
Private->VersionVariableName));
+  DEBUG ((DEBUG_INFO, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid, 
Private->LsvVariableName));
+  DEBUG ((DEBUG_INFO, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid, 
Private->LastAttemptStatusVariableName));
+  DEBUG ((DEBUG_INFO, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid, 
Private->LastAttemptVersionVariableName));
+  DEBUG ((DEBUG_INFO, "FmpDxe Variable %g %s\n", &gEfiCallerIdGuid, 
Private->FmpStateVariableName));
+
+  Buffer = GetFmpControllerState (Private);
+  if (Buffer != NULL) {
+    //
+    // FMP Controller State was found with correct size.
+    // Delete old variables if they exist.
+    //
+    FreePool (Buffer);
+    DeleteFmpVariable (Private->VersionVariableName);
+    DeleteFmpVariable (Private->LsvVariableName);
+    DeleteFmpVariable (Private->LastAttemptStatusVariableName);
+    DeleteFmpVariable (Private->LastAttemptVersionVariableName);
+    return;
   }
 
   //
-  // No error from call
+  // FMP Controller State was either not found or is wrong size.
+  // Create a new FMP Controller State variable with the correct size.
   //
-  if (Size == sizeof (*Value)) {
+  DEBUG ((DEBUG_INFO, "Create FMP Controller State\n"));
+  GetFmpVariable (
+    Private->VersionVariableName,
+    &FmpControllerState.VersionValid,
+    &FmpControllerState.Version
+    );
+  GetFmpVariable (
+    Private->LsvVariableName,
+    &FmpControllerState.LsvValid,
+    &FmpControllerState.Lsv
+    );
+  GetFmpVariable (
+    Private->LastAttemptStatusVariableName,
+    &FmpControllerState.LastAttemptStatusValid,
+    &FmpControllerState.LastAttemptStatus
+    );
+  GetFmpVariable (
+    Private->LastAttemptVersionVariableName,
+    &FmpControllerState.LastAttemptVersionValid,
+    &FmpControllerState.LastAttemptVersion
+    );
+  Status = gRT->SetVariable (
+                  Private->FmpStateVariableName,
+                  &gEfiCallerIdGuid,
+                  EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+                  sizeof (FmpControllerState),
+                  &FmpControllerState
+                  );
+  if (EFI_ERROR (Status)) {
     //
-    // Successful read
+    // Failed to create FMP Controller State.  In this case, do not
+    // delete the individual variables.  They can be used again on next boot
+    // to create the FMP Controller State.
     //
-    Version = *Value;
+    DEBUG ((DEBUG_ERROR, "Failed to create FMP Controller State.  Status = 
%r\n", Status));
   } else {
-    //
-    // Return default since size was unknown
-    //
-    DEBUG ((DEBUG_ERROR, "Getting version Variable returned a size different 
than expected. Size = 0x%x\n", Size));
+    DeleteFmpVariable (Private->VersionVariableName);
+    DeleteFmpVariable (Private->LsvVariableName);
+    DeleteFmpVariable (Private->LastAttemptStatusVariableName);
+    DeleteFmpVariable (Private->LastAttemptVersionVariableName);
   }
+}
 
-  FreePool (Value);
+/**
+  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"FmpState"
 
-  return Version;
+  @param[in] Private  Private context structure for the managed controller.
+
+  @return  The version of the firmware image in the firmware device.
+**/
+UINT32
+GetVersionFromVariable (
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
+  )
+{
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  UINT32                Value;
+
+  Value = DEFAULT_VERSION;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState != NULL) {
+    if (FmpControllerState->VersionValid) {
+      Value = FmpControllerState->Version;
+      DEBUG ((DEBUG_INFO, "Get FMP Variable %g %s Version %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        Value
+        ));
+    }
+    FreePool (FmpControllerState);
+  }
+  return Value;
 }
 
 /**
@@ -87,50 +345,35 @@ GetVersionFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
+
+  @param[in] Private  Private context structure for the managed controller.
 
   @return  The lowest supported version of the firmware image in the firmware
            device.
-
 **/
 UINT32
 GetLowestSupportedVersionFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
-  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) || (Value == NULL)) {
-    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));
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  UINT32                Value;
+
+  Value = DEFAULT_LOWESTSUPPORTEDVERSION;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState != NULL) {
+    if (FmpControllerState->LsvValid) {
+      Value = FmpControllerState->Lsv;
+      DEBUG ((DEBUG_INFO, "Get FMP Variable %g %s LowestSupportedVersion 
%08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        Value
+        ));
+    }
+    FreePool (FmpControllerState);
   }
-
-  FreePool (Value);
-
-  return Version;
+  return Value;
 }
 
 /**
@@ -140,53 +383,34 @@ GetLowestSupportedVersionFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
-  @return  The last attempt status value for the most recent capsule update.
+  @param[in] Private  Private context structure for the managed controller.
 
+  @return  The last attempt status value for the most recent capsule update.
 **/
 UINT32
 GetLastAttemptStatusFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
-  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) || (Value == NULL)) {
-    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)
-      );
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  UINT32                Value;
+
+  Value = DEFAULT_LASTATTEMPTSTATUS;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState != NULL) {
+    if (FmpControllerState->LastAttemptStatusValid) {
+      Value = FmpControllerState->LastAttemptStatus;
+      DEBUG ((DEBUG_INFO, "Get FMP Variable %g %s LastAttemptStatus %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        Value
+        ));
+    }
+    FreePool (FmpControllerState);
   }
-
-  FreePool (Value);
-
-  return LastAttemptStatus;
+  return Value;
 }
 
 /**
@@ -196,219 +420,343 @@ GetLastAttemptStatusFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
-  @return  The last attempt version value for the most recent capsule update.
+  @param[in] Private  Private context structure for the managed controller.
 
+  @return  The last attempt version value for the most recent capsule update.
 **/
 UINT32
 GetLastAttemptVersionFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
-  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) || (Value == NULL)) {
-    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)
-      );
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  UINT32                Value;
+
+  Value = DEFAULT_LASTATTEMPTVERSION;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState != NULL) {
+    if (FmpControllerState->LastAttemptVersionValid) {
+      Value = FmpControllerState->LastAttemptVersion;
+      DEBUG ((DEBUG_INFO, "Get FMP Variable %g %s LastAttemptVersion %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        Value
+        ));
+    }
+    FreePool (FmpControllerState);
   }
-
-  FreePool (Value);
-
-  return Version;
+  return Value;
 }
 
-
 /**
   Saves the version current of the firmware image in the firmware device to a
   UEFI variable.
 
-  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
+  @param[in] Private  Private context structure for the managed controller.
   @param[in] Version  The version of the firmware image in the firmware device.
-
 **/
 VOID
 SetVersionInVariable (
-   UINT32  Version
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN UINT32                            Version
   )
 {
-  EFI_STATUS  Status;
-  UINT32      Current;
+  EFI_STATUS            Status;
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  BOOLEAN               Update;
 
-  Status = EFI_SUCCESS;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState == NULL) {
+    //
+    // Can not update value if FMP Controller State does not exist.
+    // This variable is guaranteed to be created by GenerateFmpVariableNames().
+    //
+    return;
+  }
 
-  Current = GetVersionFromVariable();
-  if (Current != Version) {
+  Update = FALSE;
+  if (!FmpControllerState->VersionValid) {
+    Update = TRUE;
+  }
+  if (FmpControllerState->Version != Version) {
+    Update = TRUE;
+  }
+  if (!Update) {
+    DEBUG ((DEBUG_INFO, "No need to update FMP Controller State.  Same value 
as before.\n"));
+  } else {
+    FmpControllerState->VersionValid = TRUE;
+    FmpControllerState->Version      = Version;
     Status = gRT->SetVariable (
-                    VARNAME_VERSION,
+                    Private->FmpStateVariableName,
                     &gEfiCallerIdGuid,
                     EFI_VARIABLE_NON_VOLATILE | 
EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                    sizeof (Version),
-                    &Version
+                    sizeof (*FmpControllerState),
+                    FmpControllerState
                     );
     if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_ERROR, "Failed to set the Version into a variable.  Status 
= %r\n", Status));
+      DEBUG ((DEBUG_ERROR, "Failed to update FMP Controller State.  Status = 
%r\n", Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "Set FMP Variable %g %s Version %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        Version
+        ));
     }
-  } else {
-    DEBUG ((DEBUG_INFO, "Version variable doesn't need to update.  Same value 
as before.\n"));
   }
+  FreePool (FmpControllerState);
 }
 
 /**
   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] LowestSupportedVersion The lowest supported version of the 
firmware image
-                                    in the firmware device.
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
+  @param[in] Private                 Private context structure for the managed
+                                     controller.
+  @param[in] LowestSupportedVersion  The lowest supported version of the
+                                     firmware image in the firmware device.
 **/
 VOID
 SetLowestSupportedVersionInVariable (
-   UINT32  LowestSupportedVersion
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN UINT32                            LowestSupportedVersion
   )
 {
-  EFI_STATUS  Status;
-  UINT32      Current;
+  EFI_STATUS            Status;
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  BOOLEAN               Update;
 
-  Status = EFI_SUCCESS;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState == NULL) {
+    //
+    // Can not update value if FMP Controller State does not exist.
+    // This variable is guaranteed to be created by GenerateFmpVariableNames().
+    //
+    return;
+  }
 
-  Current = GetLowestSupportedVersionFromVariable();
-  if (LowestSupportedVersion > Current) {
+  Update = FALSE;
+  if (!FmpControllerState->LsvValid) {
+    Update = TRUE;
+  }
+  if (FmpControllerState->Lsv < LowestSupportedVersion) {
+    Update = TRUE;
+  }
+  if (!Update) {
+    DEBUG ((DEBUG_INFO, "No need to update FMP Controller State.  Same value 
as before.\n"));
+  } else {
+    FmpControllerState->LsvValid = TRUE;
+    FmpControllerState->Lsv      = LowestSupportedVersion;
     Status = gRT->SetVariable (
-                    VARNAME_LSV,
+                    Private->FmpStateVariableName,
                     &gEfiCallerIdGuid,
                     EFI_VARIABLE_NON_VOLATILE | 
EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                    sizeof (LowestSupportedVersion), &LowestSupportedVersion
+                    sizeof (*FmpControllerState),
+                    FmpControllerState
                     );
     if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_ERROR, "Failed to set the LSV into a variable.  Status = 
%r\n", Status));
+      DEBUG ((DEBUG_ERROR, "Failed to update FMP Controller State.  Status = 
%r\n", Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "Set FMP Variable %g %s LowestSupportedVersion 
%08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        LowestSupportedVersion
+        ));
     }
-  } else {
-    DEBUG ((DEBUG_INFO, "LSV variable doesn't need to update.  Same value as 
before.\n"));
   }
+  FreePool (FmpControllerState);
 }
 
 /**
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
+  @param[in] Private            Private context structure for the managed
+                                controller.
   @param[in] LastAttemptStatus  The last attempt status of the most recent FMP
                                 capsule update.
-
 **/
 VOID
 SetLastAttemptStatusInVariable (
-   UINT32  LastAttemptStatus
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN UINT32                            LastAttemptStatus
   )
 {
-  EFI_STATUS  Status;
-  UINT32      Current;
+  EFI_STATUS            Status;
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  BOOLEAN               Update;
 
-  Status = EFI_SUCCESS;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState == NULL) {
+    //
+    // Can not update value if FMP Controller State does not exist.
+    // This variable is guaranteed to be created by GenerateFmpVariableNames().
+    //
+    return;
+  }
 
-  Current = GetLastAttemptStatusFromVariable();
-  if (Current != LastAttemptStatus) {
+  Update = FALSE;
+  if (!FmpControllerState->LastAttemptStatusValid) {
+    Update = TRUE;
+  }
+  if (FmpControllerState->LastAttemptStatus != LastAttemptStatus) {
+    Update = TRUE;
+  }
+  if (!Update) {
+    DEBUG ((DEBUG_INFO, "No need to update FMP Controller State.  Same value 
as before.\n"));
+  } else {
+    FmpControllerState->LastAttemptStatusValid = TRUE;
+    FmpControllerState->LastAttemptStatus      = LastAttemptStatus;
     Status = gRT->SetVariable (
-                    VARNAME_LASTATTEMPTSTATUS,
+                    Private->FmpStateVariableName,
                     &gEfiCallerIdGuid,
                     EFI_VARIABLE_NON_VOLATILE | 
EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                    sizeof (LastAttemptStatus),
-                    &LastAttemptStatus
+                    sizeof (*FmpControllerState),
+                    FmpControllerState
                     );
     if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptStatus into a 
variable.  Status = %r\n", Status));
+      DEBUG ((DEBUG_ERROR, "Failed to update FMP Controller State.  Status = 
%r\n", Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "Set FMP Variable %g %s LastAttemptStatus %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        LastAttemptStatus
+        ));
     }
-  } else {
-    DEBUG ((DEBUG_INFO, "LastAttemptStatus variable doesn't need to update.  
Same value as before.\n"));
   }
+  FreePool (FmpControllerState);
 }
 
 /**
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpState"
 
+  @param[in] Private             Private context structure for the managed
+                                 controller.
   @param[in] LastAttemptVersion  The last attempt version value of the most
                                  recent FMP capsule update.
-
 **/
 VOID
 SetLastAttemptVersionInVariable (
-   UINT32  LastAttemptVersion
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN UINT32                            LastAttemptVersion
   )
 {
-  EFI_STATUS  Status;
-  UINT32      Current;
+  EFI_STATUS            Status;
+  FMP_CONTROLLER_STATE  *FmpControllerState;
+  BOOLEAN               Update;
 
-  Status = EFI_SUCCESS;
+  FmpControllerState = GetFmpControllerState (Private);
+  if (FmpControllerState == NULL) {
+    //
+    // Can not update value if FMP Controller State does not exist.
+    // This variable is guaranteed to be created by GenerateFmpVariableNames().
+    //
+    return;
+  }
 
-  Current = GetLastAttemptVersionFromVariable();
-  if (Current != LastAttemptVersion) {
+  Update = FALSE;
+  if (!FmpControllerState->LastAttemptVersionValid) {
+    Update = TRUE;
+  }
+  if (FmpControllerState->LastAttemptVersion != LastAttemptVersion) {
+    Update = TRUE;
+  }
+  if (!Update) {
+    DEBUG ((DEBUG_INFO, "No need to update FMP Controller State.  Same value 
as before.\n"));
+  } else {
+    FmpControllerState->LastAttemptVersionValid = TRUE;
+    FmpControllerState->LastAttemptVersion      = LastAttemptVersion;
     Status = gRT->SetVariable (
-                    VARNAME_LASTATTEMPTVERSION,
+                    Private->FmpStateVariableName,
                     &gEfiCallerIdGuid,
                     EFI_VARIABLE_NON_VOLATILE | 
EFI_VARIABLE_BOOTSERVICE_ACCESS,
-                    sizeof (LastAttemptVersion),
-                    &LastAttemptVersion
+                    sizeof (*FmpControllerState),
+                    FmpControllerState
                     );
     if (EFI_ERROR (Status)) {
-      DEBUG ((DEBUG_ERROR, "Failed to set the LastAttemptVersion into a 
variable.  Status = %r\n", Status));
+      DEBUG ((DEBUG_ERROR, "Failed to update FMP Controller State.  Status = 
%r\n", Status));
+    } else {
+      DEBUG ((DEBUG_INFO, "Set FMP Variable %g %s LastAttemptVersion %08x\n",
+        &gEfiCallerIdGuid,
+        Private->FmpStateVariableName,
+        LastAttemptVersion
+        ));
     }
-  } else {
-    DEBUG ((DEBUG_INFO, "LastAttemptVersion variable doesn't need to update.  
Same value as before.\n"));
   }
+  FreePool (FmpControllerState);
 }
 
 /**
-  Locks all the UEFI Variables used by this module.
+  Attempts to lock a single UEFI Variable propagating the error state of the
+  first lock attempt that fails.  Uses gEfiCallerIdGuid as the variable GUID.
+
+  @param[in] PreviousStatus  The previous UEFI Variable lock attempt status.
+  @param[in] VariableLock    The EDK II Variable Lock Protocol instance.
+  @param[in] VariableName    The name of the UEFI Variable to lock.
+
+  @retval  EFI_SUCCESS  The UEFI Variable was locked and the previous variable
+                        lock attempt also succeeded.
+  @retval  Other        The UEFI Variable could not be locked or the previous
+                        variable lock attempt failed.
+**/
+static
+EFI_STATUS
+LockFmpVariable (
+  IN EFI_STATUS                    PreviousStatus,
+  IN EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock,
+  IN CHAR16                        *VariableName
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = VariableLock->RequestToLock (
+                           VariableLock,
+                           VariableName,
+                           &gEfiCallerIdGuid
+                           );
+  if (!EFI_ERROR (Status)) {
+    return PreviousStatus;
+  }
+
+  DEBUG ((DEBUG_ERROR, "FmpDxe: Failed to lock variable %g %s.  Status = %r\n",
+    &gEfiCallerIdGuid,
+    VariableName,
+    Status
+    ));
+
+  if (EFI_ERROR (PreviousStatus)) {
+    return PreviousStatus;
+  }
+  return Status;
+}
+
+/**
+  Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently
+  executing module.
+
+  @param[in] Private  Private context structure for the managed controller.
 
   @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
+  FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   )
 {
   EFI_STATUS                    Status;
   EDKII_VARIABLE_LOCK_PROTOCOL  *VariableLock;
-  EFI_STATUS                    ReturnStatus;
-  UINTN                         Index;
 
   VariableLock = NULL;
   Status = gBS->LocateProtocol (
@@ -416,29 +764,17 @@ LockAllFmpVariables (
                   NULL,
                   (VOID **)&VariableLock
                   );
-  if (EFI_ERROR (Status)) {
+  if (EFI_ERROR (Status) || VariableLock == NULL) {
     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;
-      }
-    }
-  }
+  Status = EFI_SUCCESS;
+  Status = LockFmpVariable (Status, VariableLock, 
Private->VersionVariableName);
+  Status = LockFmpVariable (Status, VariableLock, Private->LsvVariableName);
+  Status = LockFmpVariable (Status, VariableLock, 
Private->LastAttemptStatusVariableName);
+  Status = LockFmpVariable (Status, VariableLock, 
Private->LastAttemptVersionVariableName);
+  Status = LockFmpVariable (Status, VariableLock, 
Private->FmpStateVariableName);
 
-  return ReturnStatus;
+  return Status;
 }
diff --git a/FmpDevicePkg/FmpDxe/VariableSupport.h 
b/FmpDevicePkg/FmpDxe/VariableSupport.h
index b5079a9900..23f24f2a13 100644
--- a/FmpDevicePkg/FmpDxe/VariableSupport.h
+++ b/FmpDevicePkg/FmpDxe/VariableSupport.h
@@ -3,7 +3,7 @@
   firmware updates.
 
   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
 
@@ -12,16 +12,75 @@
 #ifndef __VARIABLE_SUPPORT_H__
 #define __VARIABLE_SUPPORT_H__
 
+///
+/// Default values for FMP Controller State information
+///
 #define DEFAULT_VERSION                 0x1
 #define DEFAULT_LOWESTSUPPORTEDVERSION  0x0
-#define DEFAULT_LASTATTEMPT             0x0
+#define DEFAULT_LASTATTEMPTSTATUS       0x0
+#define DEFAULT_LASTATTEMPTVERSION      0x0
 
+///
+/// Base UEFI Variable names for FMP Controller State information stored in
+/// separate variables.
+///
 #define VARNAME_VERSION                 L"FmpVersion"
 #define VARNAME_LSV                     L"FmpLsv"
-
 #define VARNAME_LASTATTEMPTSTATUS       L"LastAttemptStatus"
 #define VARNAME_LASTATTEMPTVERSION      L"LastAttemptVersion"
 
+///
+/// Base UEFI Variable name for FMP Controller State information stored in a
+/// merged UEFI Variable.  If the separate UEFI Variables above are detected,
+/// then they are merged into a single variable and the separate variables are
+/// deleted.
+///
+#define VARNAME_FMPSTATE                L"FmpState"
+
+///
+/// FMP Controller State structure that is used to store the state of
+/// a controller in one combined UEFI Variable.
+///
+typedef struct {
+  BOOLEAN  VersionValid;
+  BOOLEAN  LsvValid;
+  BOOLEAN  LastAttemptStatusValid;
+  BOOLEAN  LastAttemptVersionValid;
+  UINT32   Version;
+  UINT32   Lsv;
+  UINT32   LastAttemptStatus;
+  UINT32   LastAttemptVersion;
+} FMP_CONTROLLER_STATE;
+
+/**
+  Generate the names of the UEFI Variables used to store state information for
+  a managed controller.  The UEFI Variables names are a combination of a base
+  name and an optional hardware instance value as a 16 character hex value.  If
+  the hardware instance value is 0, then the 16 character hex value is not
+  included.  These storage for the UEFI Variable names are allocated using the
+  UEFI Boot Service AllocatePool() and the pointers are stored in the Private.
+  The following are examples of variable names produces for hardware instance
+  value 0 and value 0x1234567812345678.
+
+    FmpVersion
+    FmpLsv
+    LastAttemptStatus
+    LastAttemptVersion
+    FmpDxe
+
+    FmpVersion1234567812345678
+    FmpLsv1234567812345678
+    LastAttemptStatus1234567812345678
+    LastAttemptVersion1234567812345678
+    FmpDxe1234567812345678
+
+  @param[in,out] Private  Private context structure for the managed controller.
+**/
+VOID
+GenerateFmpVariableNames (
+  IN OUT FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
+  );
+
 /**
   Returns the value used to fill in the Version field of the
   EFI_FIRMWARE_IMAGE_DESCRIPTOR structure that is returned by the 
GetImageInfo()
@@ -29,14 +88,15 @@
   variable.  If the UEFI variables does not exist, then a default version value
   is returned.
 
-  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
-  @return  The version of the firmware image in the firmware device.
+  @param[in] Private  Private context structure for the managed controller.
 
+  @return  The version of the firmware image in the firmware device.
 **/
 UINT32
 GetVersionFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   );
 
 /**
@@ -46,15 +106,16 @@ GetVersionFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
+
+  @param[in] Private  Private context structure for the managed controller.
 
   @return  The lowest supported version of the firmware image in the firmware
            device.
-
 **/
 UINT32
 GetLowestSupportedVersionFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   );
 
 /**
@@ -64,14 +125,15 @@ GetLowestSupportedVersionFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
-  @return  The last attempt status value for the most recent capsule update.
+  @param[in] Private  Private context structure for the managed controller.
 
+  @return  The last attempt status value for the most recent capsule update.
 **/
 UINT32
 GetLastAttemptStatusFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   );
 
 /**
@@ -81,83 +143,96 @@ GetLastAttemptStatusFromVariable (
   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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
-  @return  The last attempt version value for the most recent capsule update.
+  @param[in] Private  Private context structure for the managed controller.
 
+  @return  The last attempt version value for the most recent capsule update.
 **/
 UINT32
 GetLastAttemptVersionFromVariable (
-  VOID
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   );
 
 /**
   Saves the version current of the firmware image in the firmware device to a
   UEFI variable.
 
-  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpVersion"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
+  @param[in] Private  Private context structure for the managed controller.
   @param[in] Version  The version of the firmware image in the firmware device.
-
 **/
 VOID
 SetVersionInVariable (
-   UINT32  Version
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN 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] LowestSupportedVersion The lowest supported version of the 
firmware image
-                                    in the firmware device.
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
+  @param[in] Private                 Private context structure for the managed
+                                     controller.
+  @param[in] LowestSupportedVersion  The lowest supported version of the
+                                     firmware image in the firmware device.
 **/
 VOID
 SetLowestSupportedVersionInVariable (
-   UINT32  LowestSupportedVersion
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN 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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
+  @param[in] Private            Private context structure for the managed
+                                controller.
   @param[in] LastAttemptStatus  The last attempt status of the most recent FMP
                                 capsule update.
-
 **/
 VOID
 SetLastAttemptStatusInVariable (
-   UINT32  LastAttemptStatus
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN 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"
+  UEFI Variable accessed: GUID = gEfiCallerIdGuid, Name = L"FmpDxe"
 
+  @param[in] Private             Private context structure for the managed
+                                 controller.
   @param[in] LastAttemptVersion  The last attempt version value of the most
                                  recent FMP capsule update.
-
 **/
 VOID
 SetLastAttemptVersionInVariable (
-   UINT32  LastAttemptVersion
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private,
+  IN UINT32                            LastAttemptVersion
   );
 
 /**
   Locks all the UEFI Variables that use gEfiCallerIdGuid of the currently
   executing module.
 
+  @param[in] Private  Private context structure for the managed controller.
+
+  @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
+  IN FIRMWARE_MANAGEMENT_PRIVATE_DATA  *Private
   );
 
 #endif
-- 
2.20.1.windows.1


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

View/Reply Online (#45336): https://edk2.groups.io/g/devel/message/45336
Mute This Topic: https://groups.io/mt/32836423/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub  [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-

Reply via email to