]> git.proxmox.com Git - mirror_edk2.git/commitdiff
FmpDevicePkg/FmpDxe: Different variable for each FMP Descriptor
authorEric Jin <eric.jin@intel.com>
Mon, 12 Aug 2019 05:00:59 +0000 (13:00 +0800)
committerLiming Gao <liming.gao@intel.com>
Thu, 15 Aug 2019 09:22:23 +0000 (17:22 +0800)
REF: https://bugzilla.tianocore.org/show_bug.cgi?id=1525

Cc: Sean Brogan <sean.brogan@microsoft.com>
Cc: Bret Barkelew <Bret.Barkelew@microsoft.com>
Cc: Liming Gao <liming.gao@intel.com>
Signed-off-by: Michael D Kinney <michael.d.kinney@intel.com>
Signed-off-by: Eric Jin <eric.jin@intel.com>
Reviewed-by: Liming Gao <liming.gao@intel.com>
FmpDevicePkg/FmpDxe/FmpDxe.c
FmpDevicePkg/FmpDxe/FmpDxe.h
FmpDevicePkg/FmpDxe/VariableSupport.c
FmpDevicePkg/FmpDxe/VariableSupport.h

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