]> git.proxmox.com Git - mirror_edk2.git/blobdiff - SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c
SignedCapsulePkg/SystemFirmwareUpdate: Add SystemFirmwareUpdate.
[mirror_edk2.git] / SignedCapsulePkg / Universal / SystemFirmwareUpdate / SystemFirmwareUpdateDxe.c
diff --git a/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c b/SignedCapsulePkg/Universal/SystemFirmwareUpdate/SystemFirmwareUpdateDxe.c
new file mode 100644 (file)
index 0000000..ae783ff
--- /dev/null
@@ -0,0 +1,526 @@
+/** @file\r
+  SetImage instance to update system firmware.\r
+\r
+  Caution: This module requires additional review when modified.\r
+  This module will have external input - capsule image.\r
+  This external input must be validated carefully to avoid security issue like\r
+  buffer overflow, integer overflow.\r
+\r
+  FmpSetImage() will receive untrusted input and do basic validation.\r
+\r
+  Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>\r
+  This program and the accompanying materials\r
+  are licensed and made available under the terms and conditions of the BSD License\r
+  which accompanies this distribution.  The full text of the license may be found at\r
+  http://opensource.org/licenses/bsd-license.php\r
+\r
+  THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,\r
+  WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.\r
+\r
+**/\r
+\r
+#include "SystemFirmwareDxe.h"\r
+\r
+//\r
+// SystemFmp driver private data\r
+//\r
+SYSTEM_FMP_PRIVATE_DATA *mSystemFmpPrivate = NULL;\r
+\r
+EFI_GUID mCurrentImageTypeId;\r
+\r
+BOOLEAN  mNvRamUpdated = FALSE;\r
+\r
+/**\r
+  Parse Config data file to get the updated data array.\r
+\r
+  @param[in]      DataBuffer      Config raw file buffer.\r
+  @param[in]      BufferSize      Size of raw buffer.\r
+  @param[in, out] ConfigHeader    Pointer to the config header.\r
+  @param[in, out] UpdateArray     Pointer to the config of update data.\r
+\r
+  @retval EFI_NOT_FOUND         No config data is found.\r
+  @retval EFI_OUT_OF_RESOURCES  No enough memory is allocated.\r
+  @retval EFI_SUCCESS           Parse the config file successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+ParseUpdateDataFile (\r
+  IN      UINT8                         *DataBuffer,\r
+  IN      UINTN                         BufferSize,\r
+  IN OUT  CONFIG_HEADER                 *ConfigHeader,\r
+  IN OUT  UPDATE_CONFIG_DATA            **UpdateArray\r
+  );\r
+\r
+/**\r
+  Update System Firmware image component.\r
+\r
+  @param[in]  SystemFirmwareImage     Points to the System Firmware image.\r
+  @param[in]  SystemFirmwareImageSize The length of the System Firmware image in bytes.\r
+  @param[in]  ConfigData              Points to the component configuration structure.\r
+  @param[out] LastAttemptVersion      The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out] LastAttemptStatus       The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS             The System Firmware image is updated.\r
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+PerformUpdate (\r
+  IN VOID                         *SystemFirmwareImage,\r
+  IN UINTN                        SystemFirmwareImageSize,\r
+  IN UPDATE_CONFIG_DATA           *ConfigData,\r
+  OUT UINT32                      *LastAttemptVersion,\r
+  OUT UINT32                      *LastAttemptStatus\r
+  )\r
+{\r
+  EFI_STATUS                   Status;\r
+\r
+  DEBUG((DEBUG_INFO, "PlatformUpdate:"));\r
+  DEBUG((DEBUG_INFO, "  BaseAddress - 0x%lx,", ConfigData->BaseAddress));\r
+  DEBUG((DEBUG_INFO, "  ImageOffset - 0x%x,", ConfigData->ImageOffset));\r
+  DEBUG((DEBUG_INFO, "  Legnth - 0x%x\n", ConfigData->Length));\r
+  Status = PerformFlashWrite (\r
+             ConfigData->FirmwareType,\r
+             ConfigData->BaseAddress,\r
+             ConfigData->AddressType,\r
+             (VOID *)((UINTN)SystemFirmwareImage + (UINTN)ConfigData->ImageOffset),\r
+             ConfigData->Length\r
+             );\r
+  if (!EFI_ERROR(Status)) {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+    if (ConfigData->FirmwareType == PlatformFirmwareTypeNvRam) {\r
+      mNvRamUpdated = TRUE;\r
+    }\r
+  } else {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+  }\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Update System Firmware image.\r
+\r
+  @param[in]  SystemFirmwareImage     Points to the System Firmware image.\r
+  @param[in]  SystemFirmwareImageSize The length of the System Firmware image in bytes.\r
+  @param[in]  ConfigImage             Points to the config file image.\r
+  @param[in]  ConfigImageSize         The length of the config file image in bytes.\r
+  @param[out] LastAttemptVersion      The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out] LastAttemptStatus       The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS             The System Firmware image is updated.\r
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+UpdateImage (\r
+  IN VOID                         *SystemFirmwareImage,\r
+  IN UINTN                        SystemFirmwareImageSize,\r
+  IN VOID                         *ConfigImage,\r
+  IN UINTN                        ConfigImageSize,\r
+  OUT UINT32                      *LastAttemptVersion,\r
+  OUT UINT32                      *LastAttemptStatus\r
+  )\r
+{\r
+  EFI_STATUS                            Status;\r
+  UPDATE_CONFIG_DATA                    *ConfigData;\r
+  UPDATE_CONFIG_DATA                    *UpdateConfigData;\r
+  CONFIG_HEADER                         ConfigHeader;\r
+  UINTN                                 Index;\r
+\r
+  if (ConfigImage == NULL) {\r
+    DEBUG((DEBUG_INFO, "PlatformUpdate (NoConfig):"));\r
+    DEBUG((DEBUG_INFO, "  BaseAddress - 0x%x,", 0));\r
+    DEBUG((DEBUG_INFO, "  Length - 0x%x\n", SystemFirmwareImageSize));\r
+    // ASSUME the whole System Firmware include NVRAM region.\r
+    Status = PerformFlashWrite (\r
+               PlatformFirmwareTypeNvRam,\r
+               0,\r
+               FlashAddressTypeRelativeAddress,\r
+               SystemFirmwareImage,\r
+               SystemFirmwareImageSize\r
+               );\r
+    if (!EFI_ERROR(Status)) {\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_SUCCESS;\r
+      mNvRamUpdated = TRUE;\r
+    } else {\r
+      *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+    }\r
+    return Status;\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "PlatformUpdate (With Config):\n"));\r
+  ConfigData        = NULL;\r
+  ZeroMem (&ConfigHeader, sizeof(ConfigHeader));\r
+  Status            = ParseUpdateDataFile (\r
+                        ConfigImage,\r
+                        ConfigImageSize,\r
+                        &ConfigHeader,\r
+                        &ConfigData\r
+                        );\r
+  DEBUG((DEBUG_INFO, "ParseUpdateDataFile - %r\n", Status));\r
+  if (EFI_ERROR(Status)) {\r
+    *LastAttemptStatus = LAST_ATTEMPT_STATUS_ERROR_UNSUCCESSFUL;\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  DEBUG((DEBUG_INFO, "ConfigHeader.NumOfUpdates - 0x%x\n", ConfigHeader.NumOfUpdates));\r
+  DEBUG((DEBUG_INFO, "PcdEdkiiSystemFirmwareFileGuid - %g\n", PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid)));\r
+\r
+  Index = 0;\r
+  UpdateConfigData = ConfigData;\r
+  while (Index < ConfigHeader.NumOfUpdates) {\r
+    if (CompareGuid(&UpdateConfigData->FileGuid, PcdGetPtr(PcdEdkiiSystemFirmwareFileGuid))) {\r
+      DEBUG((DEBUG_INFO, "FileGuid - %g (processing)\n", &UpdateConfigData->FileGuid));\r
+      Status = PerformUpdate (\r
+                 SystemFirmwareImage,\r
+                 SystemFirmwareImageSize,\r
+                 UpdateConfigData,\r
+                 LastAttemptVersion,\r
+                 LastAttemptStatus\r
+                 );\r
+      //\r
+      // Shall updates be serialized so that if an update is not successfully completed,\r
+      // the remaining updates won't be performed.\r
+      //\r
+      if (EFI_ERROR (Status)) {\r
+        break;\r
+      }\r
+    } else {\r
+      DEBUG((DEBUG_INFO, "FileGuid - %g (ignored)\n", &UpdateConfigData->FileGuid));\r
+    }\r
+\r
+    Index++;\r
+    UpdateConfigData++;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Authenticate and update System Firmware image.\r
+\r
+  Caution: This function may receive untrusted input.\r
+\r
+  @param[in]  Image              The EDKII system FMP capsule image.\r
+  @param[in]  ImageSize          The size of the EDKII system FMP capsule image in bytes.\r
+  @param[out] LastAttemptVersion The last attempt version, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+  @param[out] LastAttemptStatus  The last attempt status, which will be recorded in ESRT and FMP EFI_FIRMWARE_IMAGE_DESCRIPTOR.\r
+\r
+  @retval EFI_SUCCESS             EDKII system FMP capsule passes authentication and the System Firmware image is updated.\r
+  @retval EFI_SECURITY_VIOLATION  EDKII system FMP capsule fails authentication and the System Firmware image is not updated.\r
+  @retval EFI_WRITE_PROTECTED     The flash device is read only.\r
+**/\r
+EFI_STATUS\r
+SystemFirmwareAuthenticatedUpdate (\r
+  IN VOID                         *Image,\r
+  IN UINTN                        ImageSize,\r
+  OUT UINT32                      *LastAttemptVersion,\r
+  OUT UINT32                      *LastAttemptStatus\r
+  )\r
+{\r
+  EFI_STATUS                  Status;\r
+  VOID                        *SystemFirmwareImage;\r
+  UINTN                       SystemFirmwareImageSize;\r
+  VOID                        *ConfigImage;\r
+  UINTN                       ConfigImageSize;\r
+  VOID                        *AuthenticatedImage;\r
+  UINTN                       AuthenticatedImageSize;\r
+\r
+  DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate...\n"));\r
+\r
+  Status = CapsuleAuthenticateSystemFirmware(Image, ImageSize, FALSE, LastAttemptVersion, LastAttemptStatus, &AuthenticatedImage, &AuthenticatedImageSize);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticateImage - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "ExtractSystemFirmwareImage ...\n"));\r
+  ExtractSystemFirmwareImage(AuthenticatedImage, AuthenticatedImageSize, &SystemFirmwareImage, &SystemFirmwareImageSize);\r
+  DEBUG((DEBUG_INFO, "ExtractConfigImage ...\n"));\r
+  ExtractConfigImage(AuthenticatedImage, AuthenticatedImageSize, &ConfigImage, &ConfigImageSize);\r
+\r
+  DEBUG((DEBUG_INFO, "UpdateImage ...\n"));\r
+  Status = UpdateImage(SystemFirmwareImage, SystemFirmwareImageSize, ConfigImage, ConfigImageSize, LastAttemptVersion, LastAttemptStatus);\r
+  if (EFI_ERROR(Status)) {\r
+    DEBUG((DEBUG_INFO, "UpdateImage - %r\n", Status));\r
+    return Status;\r
+  }\r
+\r
+  DEBUG((DEBUG_INFO, "SystemFirmwareAuthenticatedUpdate Done\n"));\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+\r
+  This code finds variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in]      VariableName               Name of Variable to be found.\r
+  @param[in]      VendorGuid                 Variable vendor GUID.\r
+  @param[out]     Attributes                 Attribute value of the variable found.\r
+  @param[in, out] DataSize                   Size of Data found. If size is less than the\r
+                                             data, this value contains the required size.\r
+  @param[out]     Data                       Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetVariableHook (\r
+  IN      CHAR16            *VariableName,\r
+  IN      EFI_GUID          *VendorGuid,\r
+  OUT     UINT32            *Attributes OPTIONAL,\r
+  IN OUT  UINTN             *DataSize,\r
+  OUT     VOID              *Data\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "GetVariableHook - %S, %g\n", VariableName, VendorGuid));\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+  This code Finds the Next available variable.\r
+\r
+  @param[in, out] VariableNameSize           Size of the variable name.\r
+  @param[in, out] VariableName               Pointer to variable name.\r
+  @param[in, out] VendorGuid                 Variable Vendor Guid.\r
+\r
+  @return EFI_INVALID_PARAMETER     Invalid parameter.\r
+  @return EFI_SUCCESS               Find the specified variable.\r
+  @return EFI_NOT_FOUND             Not found.\r
+  @return EFI_BUFFER_TO_SMALL       DataSize is too small for the result.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+GetNextVariableNameHook (\r
+  IN OUT  UINTN             *VariableNameSize,\r
+  IN OUT  CHAR16            *VariableName,\r
+  IN OUT  EFI_GUID          *VendorGuid\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "GetNextVariableNameHook - %S, %g\n", VariableName, VendorGuid));\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+  This code sets variable in storage blocks (Volatile or Non-Volatile).\r
+\r
+  @param[in] VariableName                     Name of Variable to be found.\r
+  @param[in] VendorGuid                       Variable vendor GUID.\r
+  @param[in] Attributes                       Attribute value of the variable found\r
+  @param[in] DataSize                         Size of Data found. If size is less than the\r
+                                              data, this value contains the required size.\r
+  @param[in] Data                             Data pointer.\r
+\r
+  @return EFI_INVALID_PARAMETER           Invalid parameter.\r
+  @return EFI_SUCCESS                     Set successfully.\r
+  @return EFI_OUT_OF_RESOURCES            Resource not enough to set variable.\r
+  @return EFI_NOT_FOUND                   Not found.\r
+  @return EFI_WRITE_PROTECTED             Variable is read-only.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SetVariableHook (\r
+  IN CHAR16                  *VariableName,\r
+  IN EFI_GUID                *VendorGuid,\r
+  IN UINT32                  Attributes,\r
+  IN UINTN                   DataSize,\r
+  IN VOID                    *Data\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "SetVariableHook - %S, %g, 0x%x (0x%x)\n", VariableName, VendorGuid, Attributes, DataSize));\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+\r
+  This code returns information about the EFI variables.\r
+\r
+  @param[in]  Attributes                     Attributes bitmask to specify the type of variables\r
+                                             on which to return information.\r
+  @param[out] MaximumVariableStorageSize     Pointer to the maximum size of the storage space available\r
+                                             for the EFI variables associated with the attributes specified.\r
+  @param[out] RemainingVariableStorageSize   Pointer to the remaining size of the storage space available\r
+                                             for EFI variables associated with the attributes specified.\r
+  @param[out] MaximumVariableSize            Pointer to the maximum size of an individual EFI variables\r
+                                             associated with the attributes specified.\r
+\r
+  @return EFI_SUCCESS                   Query successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+QueryVariableInfoHook (\r
+  IN  UINT32                 Attributes,\r
+  OUT UINT64                 *MaximumVariableStorageSize,\r
+  OUT UINT64                 *RemainingVariableStorageSize,\r
+  OUT UINT64                 *MaximumVariableSize\r
+  )\r
+{\r
+  DEBUG((DEBUG_INFO, "QueryVariableInfoHook - 0x%x\n", Attributes));\r
+  return EFI_NOT_AVAILABLE_YET;\r
+}\r
+\r
+/**\r
+  Updates the firmware image of the device.\r
+\r
+  This function updates the hardware with the new firmware image.\r
+  This function returns EFI_UNSUPPORTED if the firmware image is not updatable.\r
+  If the firmware image is updatable, the function should perform the following minimal validations\r
+  before proceeding to do the firmware image update.\r
+  - Validate the image authentication if image has attribute\r
+    IMAGE_ATTRIBUTE_AUTHENTICATION_REQUIRED. The function returns\r
+    EFI_SECURITY_VIOLATION if the validation fails.\r
+  - Validate the image is a supported image for this device. The function returns EFI_ABORTED if\r
+    the image is unsupported. The function can optionally provide more detailed information on\r
+    why the image is not a supported image.\r
+  - Validate the data from VendorCode if not null. Image validation must be performed before\r
+    VendorCode data validation. VendorCode data is ignored or considered invalid if image\r
+    validation failed. The function returns EFI_ABORTED if the data is invalid.\r
+\r
+  VendorCode enables vendor to implement vendor-specific firmware image update policy. Null if\r
+  the caller did not specify the policy or use the default policy. As an example, vendor can implement\r
+  a policy to allow an option to force a firmware image update when the abort reason is due to the new\r
+  firmware image version is older than the current firmware image version or bad image checksum.\r
+  Sensitive operations such as those wiping the entire firmware image and render the device to be\r
+  non-functional should be encoded in the image itself rather than passed with the VendorCode.\r
+  AbortReason enables vendor to have the option to provide a more detailed description of the abort\r
+  reason to the caller.\r
+\r
+  @param[in]  This               A pointer to the EFI_FIRMWARE_MANAGEMENT_PROTOCOL instance.\r
+  @param[in]  ImageIndex         A unique number identifying the firmware image(s) within the device.\r
+                                 The number is between 1 and DescriptorCount.\r
+  @param[in]  Image              Points to the new image.\r
+  @param[in]  ImageSize          Size of the new image in bytes.\r
+  @param[in]  VendorCode         This enables vendor to implement vendor-specific firmware image update policy.\r
+                                 Null indicates the caller did not specify the policy or use the default policy.\r
+  @param[in]  Progress           A function used by the driver to report the progress of the firmware update.\r
+  @param[out] AbortReason        A pointer to a pointer to a null-terminated string providing more\r
+                                 details for the aborted operation. The buffer is allocated by this function\r
+                                 with AllocatePool(), and it is the caller's responsibility to free it with a\r
+                                 call to FreePool().\r
+\r
+  @retval EFI_SUCCESS            The device was successfully updated with the new image.\r
+  @retval EFI_ABORTED            The operation is aborted.\r
+  @retval EFI_INVALID_PARAMETER  The Image was NULL.\r
+  @retval EFI_UNSUPPORTED        The operation is not supported.\r
+  @retval EFI_SECURITY_VIOLATIO  The operation could not be performed due to an authentication failure.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FmpSetImage (\r
+  IN  EFI_FIRMWARE_MANAGEMENT_PROTOCOL                 *This,\r
+  IN  UINT8                                            ImageIndex,\r
+  IN  CONST VOID                                       *Image,\r
+  IN  UINTN                                            ImageSize,\r
+  IN  CONST VOID                                       *VendorCode,\r
+  IN  EFI_FIRMWARE_MANAGEMENT_UPDATE_IMAGE_PROGRESS    Progress,\r
+  OUT CHAR16                                           **AbortReason\r
+  )\r
+{\r
+  EFI_STATUS              Status;\r
+  EFI_STATUS              VarStatus;\r
+  SYSTEM_FMP_PRIVATE_DATA *SystemFmpPrivate;\r
+\r
+  if (Image == NULL || ImageSize == 0 || AbortReason == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  SystemFmpPrivate = SYSTEM_FMP_PRIVATE_DATA_FROM_FMP(This);\r
+  *AbortReason     = NULL;\r
+\r
+  if (ImageIndex == 0 || ImageIndex > SystemFmpPrivate->DescriptorCount) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = SystemFirmwareAuthenticatedUpdate((VOID *)Image, ImageSize, &SystemFmpPrivate->LastAttempt.LastAttemptVersion, &SystemFmpPrivate->LastAttempt.LastAttemptStatus);\r
+  DEBUG((DEBUG_INFO, "SetImage - LastAttemp Version - 0x%x, State - 0x%x\n", SystemFmpPrivate->LastAttempt.LastAttemptVersion, SystemFmpPrivate->LastAttempt.LastAttemptStatus));\r
+\r
+  //\r
+  // If NVRAM is updated, we should no longer touch variable services, because\r
+  // the current variable driver may not manage the new NVRAM region.\r
+  //\r
+  if (mNvRamUpdated) {\r
+    DEBUG ((DEBUG_INFO, "NvRamUpdated, Update Variable Serivces\n"));\r
+    gRT->GetVariable         = GetVariableHook;\r
+    gRT->GetNextVariableName = GetNextVariableNameHook;\r
+    gRT->SetVariable         = SetVariableHook;\r
+    gRT->QueryVariableInfo   = QueryVariableInfoHook;\r
+\r
+    gRT->Hdr.CRC32 = 0;\r
+    gBS->CalculateCrc32 (\r
+          (UINT8 *) &gRT->Hdr,\r
+          gRT->Hdr.HeaderSize,\r
+          &gRT->Hdr.CRC32\r
+          );\r
+  }\r
+\r
+  VarStatus = gRT->SetVariable(\r
+                     SYSTEM_FMP_LAST_ATTEMPT_VARIABLE_NAME,\r
+                     &gSystemFmpLastAttemptVariableGuid,\r
+                     EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,\r
+                     sizeof(SystemFmpPrivate->LastAttempt),\r
+                     &SystemFmpPrivate->LastAttempt\r
+                     );\r
+  DEBUG((DEBUG_INFO, "SetLastAttemp - %r\n", VarStatus));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  System FMP module entrypoint\r
+\r
+  @param  ImageHandle       The firmware allocated handle for the EFI image.\r
+  @param  SystemTable       A pointer to the EFI System Table.\r
+\r
+  @return EFI_SUCCESS System FMP module is initialized.\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+SystemFirmwareUpdateMainDxe (\r
+  IN EFI_HANDLE                         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE                   *SystemTable\r
+  )\r
+{\r
+  EFI_STATUS                                      Status;\r
+\r
+  //\r
+  // Initialize SystemFmpPrivateData\r
+  //\r
+  mSystemFmpPrivate = AllocateZeroPool (sizeof(SYSTEM_FMP_PRIVATE_DATA));\r
+  if (mSystemFmpPrivate == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  Status = InitializePrivateData(mSystemFmpPrivate);\r
+  if (EFI_ERROR(Status)) {\r
+    FreePool(mSystemFmpPrivate);\r
+    mSystemFmpPrivate = NULL;\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Install FMP protocol.\r
+  //\r
+  Status = gBS->InstallMultipleProtocolInterfaces (\r
+                  &mSystemFmpPrivate->Handle,\r
+                  &gEfiFirmwareManagementProtocolGuid,\r
+                  &mSystemFmpPrivate->Fmp,\r
+                  &gSystemFmpProtocolGuid,\r
+                  &mSystemFmpPrivate->Fmp,\r
+                  NULL\r
+                  );\r
+  if (EFI_ERROR (Status)) {\r
+    FreePool(mSystemFmpPrivate);\r
+    mSystemFmpPrivate = NULL;\r
+    return Status;\r
+  }\r
+\r
+  return Status;\r
+}\r