]> git.proxmox.com Git - mirror_edk2.git/commitdiff
UefiPayloadPkg: Add a common FVB SMM module
authorGuo Dong <guo.dong@intel.com>
Wed, 22 Sep 2021 21:42:50 +0000 (14:42 -0700)
committermergify[bot] <37929162+mergify[bot]@users.noreply.github.com>
Mon, 25 Oct 2021 17:28:21 +0000 (17:28 +0000)
This FVB module is used to initialize NV variable region
and provide SMM FVB protocol to read/write SPI variable region.

This module consume HOB gNvVariableInfoGuid and depends on
FlashDeviceLib for the actual SPI device operate.

During FVB initialization, it will initialize the variable region
if the variable region is not valid. And it support to write initial
variable data from FFS file if it is found.

Signed-off-by: Guo Dong <guo.dong@intel.com>
Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Reviewed-by: Ray Ni <ray.ni@intel.com>
Reviewed-by: Benjamin You <benjamin.you@intel.com>
UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c [new file with mode: 0644]
UefiPayloadPkg/FvbRuntimeDxe/FvbService.c [new file with mode: 0644]
UefiPayloadPkg/FvbRuntimeDxe/FvbService.h [new file with mode: 0644]
UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c [new file with mode: 0644]
UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf [new file with mode: 0644]
UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h [new file with mode: 0644]
UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h [new file with mode: 0644]
UefiPayloadPkg/UefiPayloadPkg.dec

diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c b/UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c
new file mode 100644 (file)
index 0000000..78b6b81
--- /dev/null
@@ -0,0 +1,151 @@
+/** @file\r
+\r
+  Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiDxe.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Guid/FirmwareFileSystem2.h>\r
+#include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/NvVariableInfoGuid.h>\r
+#include <Library/HobLib.h>\r
+\r
+#define FVB_MEDIA_BLOCK_SIZE        0x1000\r
+\r
+typedef struct {\r
+  EFI_FIRMWARE_VOLUME_HEADER        FvInfo;\r
+  EFI_FV_BLOCK_MAP_ENTRY            End[1];\r
+} EFI_FVB2_MEDIA_INFO;\r
+\r
+//\r
+// This data structure contains a template of FV header which is used to restore\r
+// Fv header if it's corrupted.\r
+//\r
+EFI_FVB2_MEDIA_INFO mFvbMediaInfo = {\r
+  {\r
+    {0,},           // ZeroVector[16]\r
+    EFI_SYSTEM_NV_DATA_FV_GUID,\r
+    0,\r
+    EFI_FVH_SIGNATURE,\r
+    0x0004feff,     // check PiFirmwareVolume.h for details on EFI_FVB_ATTRIBUTES_2\r
+    sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY),\r
+    0,              // CheckSum which will be calucated dynamically.\r
+    0,              // ExtHeaderOffset\r
+    {0,},\r
+    EFI_FVH_REVISION,\r
+    {\r
+      {\r
+        0,\r
+        FVB_MEDIA_BLOCK_SIZE,\r
+      }\r
+    }\r
+  },\r
+  {\r
+    {\r
+      0,\r
+      0\r
+    }\r
+  }\r
+};\r
+\r
+/**\r
+  Initialize the variable store\r
+\r
+  @retval     EFI_SUCCESS if initialize the store success.\r
+\r
+**/\r
+EFI_STATUS\r
+InitVariableStore (\r
+  VOID\r
+  )\r
+{\r
+  EFI_STATUS          Status;\r
+  UINT32              NvStorageBase;\r
+  UINT32              NvStorageSize;\r
+  UINT32              NvVariableSize;\r
+  UINT32              FtwWorkingSize;\r
+  UINT32              FtwSpareSize;\r
+  EFI_HOB_GUID_TYPE   *GuidHob;\r
+  NV_VARIABLE_INFO    *NvVariableInfo;\r
+\r
+  //\r
+  // Find SPI flash variable hob\r
+  //\r
+  GuidHob = GetFirstGuidHob (&gNvVariableInfoGuid);\r
+  if (GuidHob == NULL) {\r
+    ASSERT (FALSE);\r
+    return EFI_NOT_FOUND;\r
+  }\r
+  NvVariableInfo = (NV_VARIABLE_INFO *) GET_GUID_HOB_DATA (GuidHob);\r
+\r
+  //\r
+  // Get variable region base and size.\r
+  //\r
+  NvStorageSize = NvVariableInfo->VariableStoreSize;\r
+  NvStorageBase = NvVariableInfo->VariableStoreBase;\r
+\r
+  //\r
+  // NvStorageBase needs to be 4KB aligned, NvStorageSize needs to be 8KB * n\r
+  //\r
+  if (((NvStorageBase & (SIZE_4KB - 1)) != 0) || ((NvStorageSize & (SIZE_8KB - 1)) != 0)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  FtwSpareSize   = NvStorageSize / 2;\r
+  FtwWorkingSize = 0x2000;\r
+  NvVariableSize = NvStorageSize / 2 - FtwWorkingSize;\r
+  DEBUG ((DEBUG_INFO, "NvStorageBase:0x%x, NvStorageSize:0x%x\n", NvStorageBase, NvStorageSize));\r
+\r
+  if (NvVariableSize >= 0x80000000) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+  Status = PcdSet32S(PcdFlashNvStorageVariableSize,   NvVariableSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = PcdSet32S(PcdFlashNvStorageVariableBase,   NvStorageBase);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = PcdSet64S(PcdFlashNvStorageVariableBase64, NvStorageBase);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = PcdSet32S(PcdFlashNvStorageFtwWorkingSize, FtwWorkingSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = PcdSet32S(PcdFlashNvStorageFtwWorkingBase, NvStorageBase + NvVariableSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = PcdSet32S(PcdFlashNvStorageFtwSpareSize,   FtwSpareSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+  Status = PcdSet32S(PcdFlashNvStorageFtwSpareBase,   NvStorageBase + FtwSpareSize);\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Get a heathy FV header used for variable store recovery\r
+\r
+  @retval     The FV header.\r
+\r
+**/\r
+EFI_FIRMWARE_VOLUME_HEADER *\r
+GetFvHeaderTemplate (\r
+  VOID\r
+  )\r
+{\r
+  EFI_FIRMWARE_VOLUME_HEADER        *FvHeader;\r
+  UINTN                             FvSize;\r
+\r
+  FvSize = PcdGet32(PcdFlashNvStorageFtwSpareSize) * 2;\r
+  FvHeader                        = &mFvbMediaInfo.FvInfo;\r
+  FvHeader->FvLength              = FvSize;\r
+  FvHeader->BlockMap[0].NumBlocks = (UINT32) (FvSize / FvHeader->BlockMap[0].Length);\r
+  FvHeader->Checksum = 0;\r
+  FvHeader->Checksum = CalculateCheckSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);\r
+\r
+  return FvHeader;\r
+}\r
+\r
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
new file mode 100644 (file)
index 0000000..d90a39b
--- /dev/null
@@ -0,0 +1,1088 @@
+/** @file\r
+Firmware Volume Block Driver to provide FVB service.\r
+\r
+  Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include "FvbService.h"\r
+\r
+//\r
+// Global variable for this FVB driver  which contains\r
+// the private data of all firmware volume block instances\r
+//\r
+FWB_GLOBAL               mFvbModuleGlobal;\r
+\r
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate = {\r
+  {\r
+    {\r
+      HARDWARE_DEVICE_PATH,\r
+      HW_MEMMAP_DP,\r
+      {\r
+        (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),\r
+        (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)\r
+      }\r
+    },\r
+    EfiMemoryMappedIO,\r
+    (EFI_PHYSICAL_ADDRESS) 0,\r
+    (EFI_PHYSICAL_ADDRESS) 0,\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      END_DEVICE_PATH_LENGTH,\r
+      0\r
+    }\r
+  }\r
+};\r
+\r
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate = {\r
+  {\r
+    {\r
+      MEDIA_DEVICE_PATH,\r
+      MEDIA_PIWG_FW_VOL_DP,\r
+      {\r
+        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),\r
+        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)\r
+      }\r
+    },\r
+    { 0 }\r
+  },\r
+  {\r
+    END_DEVICE_PATH_TYPE,\r
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,\r
+    {\r
+      END_DEVICE_PATH_LENGTH,\r
+      0\r
+    }\r
+  }\r
+};\r
+\r
+\r
+EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate = {\r
+  FVB_DEVICE_SIGNATURE,\r
+  NULL,\r
+  0, // Instance\r
+  {\r
+    FvbProtocolGetAttributes,\r
+    FvbProtocolSetAttributes,\r
+    FvbProtocolGetPhysicalAddress,\r
+    FvbProtocolGetBlockSize,\r
+    FvbProtocolRead,\r
+    FvbProtocolWrite,\r
+    FvbProtocolEraseBlocks,\r
+    NULL\r
+  } // FwVolBlockInstance\r
+};\r
+\r
+\r
+/**\r
+  Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed\r
+  by mFvbModuleGlobal.FvInstance based on a index.\r
+  Each EFI_FW_VOL_INSTANCE is  with variable length as\r
+  we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.\r
+\r
+  @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.\r
+\r
+  @return A pointer to EFI_FW_VOL_INSTANCE.\r
+\r
+**/\r
+EFI_FW_VOL_INSTANCE *\r
+GetFvbInstance (\r
+  IN  UINTN             Instance\r
+  )\r
+{\r
+  EFI_FW_VOL_INSTANCE   *FwhRecord;\r
+\r
+  if ( Instance >= mFvbModuleGlobal.NumFv ) {\r
+    ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);\r
+    return NULL;\r
+  }\r
+\r
+  //\r
+  // Find the right instance of the FVB private data\r
+  //\r
+  FwhRecord = mFvbModuleGlobal.FvInstance;\r
+  while ( Instance > 0 ) {\r
+    FwhRecord = (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) +\r
+                FwhRecord->VolumeHeader.HeaderLength +\r
+                (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER)));\r
+    Instance--;\r
+  }\r
+\r
+  return FwhRecord;\r
+\r
+}\r
+\r
+\r
+/**\r
+  Get the EFI_FVB_ATTRIBUTES_2 of a FV.\r
+\r
+  @param[in]  Instance    The index of the EFI_FW_VOL_INSTANCE.\r
+\r
+  @retval     EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.\r
+\r
+**/\r
+STATIC\r
+EFI_FVB_ATTRIBUTES_2\r
+FvbGetVolumeAttributes (\r
+  IN UINTN                                Instance\r
+  )\r
+{\r
+  EFI_FW_VOL_INSTANCE *    FwInstance;\r
+  FwInstance = GetFvbInstance(Instance);\r
+  ASSERT (FwInstance != NULL);\r
+\r
+  if (FwInstance == NULL) {\r
+    return 0;\r
+  }\r
+\r
+  return FwInstance->VolumeHeader.Attributes;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Retrieves the starting address of an LBA in an FV. It also\r
+  return a few other attribut of the FV.\r
+\r
+  @param[in]  Instance        The index of the EFI_FW_VOL_INSTANCE.\r
+  @param[in]  Lba             The logical block address\r
+  @param[out] LbaAddress      On output, contains the physical starting address\r
+                              of the Lba\r
+  @param[out] LbaLength       On output, contains the length of the block\r
+  @param[out] NumOfBlocks     A pointer to a caller allocated UINTN in which the\r
+                              number of consecutive blocks starting with Lba is\r
+                              returned. All blocks in this range have a size of\r
+                              BlockSize\r
+\r
+  @retval   EFI_SUCCESS Successfully returns\r
+  @retval   EFI_INVALID_PARAMETER Instance not found\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FvbGetLbaAddress (\r
+  IN  UINTN                               Instance,\r
+  IN  EFI_LBA                             Lba,\r
+  OUT UINTN                               *LbaAddress,\r
+  OUT UINTN                               *LbaLength,\r
+  OUT UINTN                               *NumOfBlocks\r
+  )\r
+{\r
+  UINT32                                  NumBlocks;\r
+  UINT32                                  BlockLength;\r
+  UINTN                                   Offset;\r
+  EFI_LBA                                 StartLba;\r
+  EFI_LBA                                 NextLba;\r
+  EFI_FW_VOL_INSTANCE                     *FwhInstance;\r
+  EFI_FV_BLOCK_MAP_ENTRY                  *BlockMap;\r
+\r
+  //\r
+  // Find the right instance of the FVB private data\r
+  //\r
+  FwhInstance = GetFvbInstance (Instance);\r
+  if (FwhInstance == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  StartLba  = 0;\r
+  Offset    = 0;\r
+  BlockMap  = &FwhInstance->VolumeHeader.BlockMap[0];\r
+  ASSERT (BlockMap != NULL);\r
+\r
+  //\r
+  // Parse the blockmap of the FV to find which map entry the Lba belongs to\r
+  //\r
+  while (TRUE) {\r
+    if ( BlockMap != NULL) {\r
+      NumBlocks   = BlockMap->NumBlocks;\r
+      BlockLength = BlockMap->Length;\r
+    }\r
+\r
+    if ( NumBlocks == 0 || BlockLength == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    NextLba = StartLba + NumBlocks;\r
+\r
+    //\r
+    // The map entry found\r
+    //\r
+    if (Lba >= StartLba && Lba < NextLba) {\r
+      Offset = Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength);\r
+      if (LbaAddress != NULL) {\r
+        *LbaAddress = FwhInstance->FvBase + Offset;\r
+      }\r
+\r
+      if (LbaLength != NULL) {\r
+        *LbaLength = BlockLength;\r
+      }\r
+\r
+      if (NumOfBlocks != NULL) {\r
+        *NumOfBlocks = (UINTN)(NextLba - Lba);\r
+      }\r
+      return EFI_SUCCESS;\r
+    }\r
+\r
+    StartLba  = NextLba;\r
+    Offset    = Offset + NumBlocks * BlockLength;\r
+    BlockMap++;\r
+  }\r
+}\r
+\r
+\r
+/**\r
+  Reads specified number of bytes into a buffer from the specified block\r
+\r
+  @param[in]      Instance        The FV instance to be read from\r
+  @param[in]      Lba             The logical block address to be read from\r
+  @param[in]      BlockOffset     Offset into the block at which to begin reading\r
+  @param[in, out] NumBytes        Pointer that on input contains the total size of\r
+                                  the buffer. On output, it contains the total number\r
+                                  of bytes read\r
+  @param[in]      Buffer          Pointer to a caller allocated buffer that will be\r
+                                  used to hold the data read\r
+\r
+\r
+  @retval         EFI_SUCCESS         The firmware volume was read successfully and\r
+                                      contents are in Buffer\r
+  @retval         EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On output,\r
+                                      NumBytes contains the total number of bytes returned\r
+                                      in Buffer\r
+  @retval         EFI_ACCESS_DENIED   The firmware volume is in the ReadDisabled state\r
+  @retval         EFI_DEVICE_ERROR    The block device is not functioning correctly and\r
+                                      could not be read\r
+  @retval         EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FvbReadBlock (\r
+  IN UINTN                                Instance,\r
+  IN EFI_LBA                              Lba,\r
+  IN UINTN                                BlockOffset,\r
+  IN OUT UINTN                            *NumBytes,\r
+  IN UINT8                                *Buffer\r
+  )\r
+{\r
+  EFI_FVB_ATTRIBUTES_2                    Attributes;\r
+  UINTN                                   LbaAddress;\r
+  UINTN                                   LbaLength;\r
+  EFI_STATUS                              Status;\r
+  EFI_STATUS                              ReadStatus;\r
+\r
+  if ( (NumBytes == NULL) || (Buffer == NULL)) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+  if (*NumBytes == 0) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  Attributes = FvbGetVolumeAttributes (Instance);\r
+\r
+  if ( (Attributes & EFI_FVB2_READ_STATUS) == 0) {\r
+    return (EFI_ACCESS_DENIED);\r
+  }\r
+\r
+  if (BlockOffset > LbaLength) {\r
+   return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  if (LbaLength < ( *NumBytes + BlockOffset ) ) {\r
+    *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
+    Status = EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  ReadStatus = LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Buffer);\r
+  if (EFI_ERROR(ReadStatus)) {\r
+    return ReadStatus;\r
+  }\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Writes specified number of bytes from the input buffer to the block\r
+\r
+  @param[in]  Instance          The FV instance to be written to\r
+  @param[in]  Lba               The starting logical block index to write to\r
+  @param[in]  BlockOffset       Offset into the block at which to begin writing\r
+  @param[in, out]  NumBytes     Pointer that on input contains the total size of\r
+                                 the buffer. On output, it contains the total number\r
+                                 of bytes actually written\r
+  @param[in]  Buffer            Pointer to a caller allocated buffer that contains\r
+                                 the source for the write\r
+  @retval     EFI_SUCCESS         The firmware volume was written successfully\r
+  @retval     EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On output,\r
+                                  NumBytes contains the total number of bytes\r
+                                  actually written\r
+  @retval     EFI_ACCESS_DENIED   The firmware volume is in the WriteDisabled state\r
+  @retval     EFI_DEVICE_ERROR    The block device is not functioning correctly and\r
+                                  could not be written\r
+  @retval     EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffer are NULL\r
+\r
+**/\r
+EFI_STATUS\r
+FvbWriteBlock (\r
+  IN UINTN                                Instance,\r
+  IN EFI_LBA                              Lba,\r
+  IN UINTN                                BlockOffset,\r
+  IN OUT UINTN                            *NumBytes,\r
+  IN UINT8                                *Buffer\r
+  )\r
+{\r
+  EFI_FVB_ATTRIBUTES_2                    Attributes;\r
+  UINTN                                   LbaAddress;\r
+  UINTN                                   LbaLength;\r
+  EFI_STATUS                              Status;\r
+\r
+  if ( (NumBytes == NULL) || (Buffer == NULL)) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+  if (*NumBytes == 0) {\r
+    return (EFI_INVALID_PARAMETER);\r
+  }\r
+\r
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  //\r
+  // Check if the FV is write enabled\r
+  //\r
+  Attributes = FvbGetVolumeAttributes (Instance);\r
+  if ( (Attributes & EFI_FVB2_WRITE_STATUS) == 0) {\r
+    return EFI_ACCESS_DENIED;\r
+  }\r
+\r
+  //\r
+  // Perform boundary checks and adjust NumBytes\r
+  //\r
+  if (BlockOffset > LbaLength) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  if ( LbaLength < ( *NumBytes + BlockOffset ) ) {\r
+    DEBUG ((DEBUG_ERROR,\r
+      "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",\r
+      *NumBytes, (UINT32)(LbaLength - BlockOffset)));\r
+    *NumBytes = (UINT32) (LbaLength - BlockOffset);\r
+    return EFI_BAD_BUFFER_SIZE;\r
+  }\r
+\r
+  LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
+  Status = LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, Buffer);\r
+\r
+  LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
+  WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), *NumBytes);\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Erases and initializes a firmware volume block\r
+\r
+  @param[in]    Instance    The FV instance to be erased\r
+  @param[in]    Lba         The logical block index to be erased\r
+\r
+  @retval   EFI_SUCCESS       The erase request was successfully completed\r
+  @retval   EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
+  @retval   EFI_DEVICE_ERROR  The block device is not functioning correctly and\r
+                              could not be written. Firmware device may have been\r
+                              partially erased\r
+  @retval   EFI_INVALID_PARAMETER Instance not found\r
+\r
+**/\r
+EFI_STATUS\r
+FvbEraseBlock (\r
+  IN UINTN                                Instance,\r
+  IN EFI_LBA                              Lba\r
+  )\r
+{\r
+\r
+  EFI_FVB_ATTRIBUTES_2                    Attributes;\r
+  UINTN                                   LbaAddress;\r
+  UINTN                                   LbaLength;\r
+  EFI_STATUS                              Status;\r
+\r
+  //\r
+  // Check if the FV is write enabled\r
+  //\r
+  Attributes = FvbGetVolumeAttributes (Instance);\r
+\r
+  if( (Attributes & EFI_FVB2_WRITE_STATUS) == 0)  {\r
+    return (EFI_ACCESS_DENIED);\r
+  }\r
+\r
+  //\r
+  // Get the starting address of the block for erase.\r
+  //\r
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL);\r
+  if (EFI_ERROR(Status)) {\r
+    return Status;\r
+  }\r
+\r
+  LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);\r
+\r
+  Status = LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);\r
+\r
+  LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);\r
+\r
+  WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Modifies the current settings of the firmware volume according to the\r
+  input parameter, and returns the new setting of the volume\r
+\r
+  @param[in]  Instance              The FV instance whose attributes is going to be\r
+                                    modified\r
+  @param[in, out]  Attributes       On input, it is a pointer to EFI_FVB_ATTRIBUTES_2\r
+                                    containing the desired firmware volume settings.\r
+                                    On successful return, it contains the new settings\r
+                                    of the firmware volume\r
+\r
+  @retval     EFI_SUCCESS           Successfully returns\r
+  @retval     EFI_ACCESS_DENIED     The volume setting is locked and cannot be modified\r
+  @retval     EFI_INVALID_PARAMETER Instance not found, or The attributes requested are\r
+                                    in conflict with the capabilities as declared in the\r
+                                    firmware volume header\r
+\r
+**/\r
+STATIC\r
+EFI_STATUS\r
+FvbSetVolumeAttributes (\r
+  IN UINTN                                Instance,\r
+  IN OUT EFI_FVB_ATTRIBUTES_2             *Attributes\r
+  )\r
+{\r
+  EFI_FW_VOL_INSTANCE                       *FwhInstance;\r
+  EFI_FVB_ATTRIBUTES_2                      OldAttributes;\r
+  EFI_FVB_ATTRIBUTES_2                      *AttribPtr;\r
+  EFI_FVB_ATTRIBUTES_2                      UnchangedAttributes;\r
+  UINT32                                    Capabilities;\r
+  UINT32                                    OldStatus;\r
+  UINT32                                    NewStatus;\r
+\r
+  //\r
+  // Find the right instance of the FVB private data\r
+  //\r
+  FwhInstance = GetFvbInstance (Instance);\r
+  if (FwhInstance == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  AttribPtr = (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attributes);\r
+  ASSERT (AttribPtr != NULL);\r
+  if ( AttribPtr == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  OldAttributes = *AttribPtr;\r
+  Capabilities  = OldAttributes & EFI_FVB2_CAPABILITIES;\r
+  OldStatus     = OldAttributes & EFI_FVB2_STATUS;\r
+  NewStatus     = *Attributes   & EFI_FVB2_STATUS;\r
+\r
+  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \\r
+                        EFI_FVB2_READ_ENABLED_CAP   | \\r
+                        EFI_FVB2_WRITE_DISABLED_CAP | \\r
+                        EFI_FVB2_WRITE_ENABLED_CAP  | \\r
+                        EFI_FVB2_LOCK_CAP           | \\r
+                        EFI_FVB2_STICKY_WRITE       | \\r
+                        EFI_FVB2_MEMORY_MAPPED      | \\r
+                        EFI_FVB2_ERASE_POLARITY     | \\r
+                        EFI_FVB2_READ_LOCK_CAP      | \\r
+                        EFI_FVB2_WRITE_LOCK_CAP     | \\r
+                        EFI_FVB2_ALIGNMENT;\r
+\r
+  //\r
+  // Some attributes of FV is read only can *not* be set\r
+  //\r
+  if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  //\r
+  // If firmware volume is locked, no status bit can be updated\r
+  //\r
+  if ((OldAttributes & EFI_FVB2_LOCK_STATUS) != 0) {\r
+    if ((OldStatus ^ NewStatus) != 0) {\r
+      return EFI_ACCESS_DENIED;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Test read disable\r
+  //\r
+  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {\r
+    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Test read enable\r
+  //\r
+  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {\r
+    if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Test write disable\r
+  //\r
+  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {\r
+    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Test write enable\r
+  //\r
+  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {\r
+    if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  //\r
+  // Test lock\r
+  //\r
+  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {\r
+    if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  }\r
+\r
+  *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));\r
+  *AttribPtr  = (*AttribPtr) | NewStatus;\r
+  *Attributes = *AttribPtr;\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Retrieves the physical address of the device.\r
+\r
+  @param[in]  This    A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.\r
+  @param[out] Address Output buffer containing the address.\r
+\r
+  @retval     EFI_SUCCESS The function always return successfully.\r
+  @retval     EFI_INVALID_PARAMETER Instance not found.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetPhysicalAddress (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  OUT EFI_PHYSICAL_ADDRESS                      *Address\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+  EFI_FW_VOL_INSTANCE                           *FwhInstance;\r
+\r
+  FvbDevice   = FVB_DEVICE_FROM_THIS (This);\r
+  FwhInstance = GetFvbInstance(FvbDevice->Instance);\r
+  if (FwhInstance == NULL) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  *Address = FwhInstance->FvBase;\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Retrieve the size of a logical block\r
+\r
+  @param[in]  This        Calling context\r
+  @param[in]  Lba         Indicates which block to return the size for.\r
+  @param[out] BlockSize   A pointer to a caller allocated UINTN in which\r
+                          the size of the block is returned\r
+  @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which the\r
+                          number of consecutive blocks starting with Lba is\r
+                          returned. All blocks in this range have a size of\r
+                          BlockSize\r
+\r
+  @retval     EFI_SUCCESS The function always return successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetBlockSize (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN  EFI_LBA                                   Lba,\r
+  OUT UINTN                                     *BlockSize,\r
+  OUT UINTN                                     *NumOfBlocks\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+\r
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
+  return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumOfBlocks);\r
+}\r
+\r
+\r
+/**\r
+  Retrieves Volume attributes.  No polarity translations are done.\r
+\r
+  @param[in]    This        Calling context\r
+  @param[out]   Attributes  Output buffer which contains attributes\r
+\r
+  @retval       EFI_SUCCESS The function always return successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetAttributes (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  OUT EFI_FVB_ATTRIBUTES_2                      *Attributes\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+\r
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
+  *Attributes = FvbGetVolumeAttributes (FvbDevice->Instance);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+/**\r
+  Sets Volume attributes. No polarity translations are done.\r
+\r
+  @param[in]      This        Calling context\r
+  @param[in, out] Attributes  Output buffer which contains attributes\r
+\r
+  @retval     EFI_SUCCESS The function always return successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolSetAttributes (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN OUT EFI_FVB_ATTRIBUTES_2                   *Attributes\r
+  )\r
+{\r
+  EFI_STATUS                                    Status;\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+\r
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
+  Status    = FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);\r
+  return Status;\r
+}\r
+\r
+\r
+\r
+/**\r
+  This function erases one or more blocks as denoted by the\r
+  variable argument list. The entire parameter list of blocks must be verified\r
+  prior to erasing any blocks.  If a block is requested that does not exist\r
+  within the associated firmware volume (it has a larger index than the last\r
+  block of the firmware volume), the EraseBlock() function must return\r
+  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.\r
+\r
+  @param[in] This         Calling context\r
+  @param[in] ...          Starting LBA followed by Number of Lba to erase.\r
+                          a -1 to terminate the list.\r
+\r
+  @retval EFI_SUCCESS       The erase request was successfully completed\r
+  @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled state\r
+  @retval EFI_DEVICE_ERROR  The block device is not functioning correctly and\r
+                            could not be written. Firmware device may have been\r
+                            partially erased\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolEraseBlocks (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  ...\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+  EFI_FW_VOL_INSTANCE                           *FwhInstance;\r
+  UINTN                                         NumOfBlocks;\r
+  VA_LIST                                       args;\r
+  EFI_LBA                                       StartingLba;\r
+  UINTN                                         NumOfLba;\r
+  EFI_STATUS                                    Status;\r
+\r
+  FvbDevice    = FVB_DEVICE_FROM_THIS (This);\r
+  FwhInstance  = GetFvbInstance (FvbDevice->Instance);\r
+  if (FwhInstance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  NumOfBlocks = FwhInstance->NumOfBlocks;\r
+  VA_START (args, This);\r
+\r
+  do {\r
+    StartingLba = VA_ARG (args, EFI_LBA);\r
+    if ( StartingLba == EFI_LBA_LIST_TERMINATOR ) {\r
+      break;\r
+    }\r
+\r
+    NumOfLba = VA_ARG (args, UINT32);\r
+\r
+    //\r
+    // Check input parameters\r
+    //\r
+    if (NumOfLba == 0) {\r
+      VA_END (args);\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+\r
+    if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {\r
+      return EFI_INVALID_PARAMETER;\r
+    }\r
+  } while ( 1 );\r
+\r
+  VA_END (args);\r
+\r
+  VA_START (args, This);\r
+  do {\r
+    StartingLba = VA_ARG (args, EFI_LBA);\r
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {\r
+      break;\r
+    }\r
+\r
+    NumOfLba = VA_ARG (args, UINT32);\r
+\r
+    while ( NumOfLba > 0 ) {\r
+      Status = FvbEraseBlock (FvbDevice->Instance, StartingLba);\r
+      if ( EFI_ERROR(Status)) {\r
+        VA_END (args);\r
+        return Status;\r
+      }\r
+      StartingLba++;\r
+      NumOfLba--;\r
+    }\r
+  } while ( 1 );\r
+\r
+  VA_END (args);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+\r
+\r
+/**\r
+  Writes data beginning at Lba:Offset from FV. The write terminates either\r
+  when *NumBytes of data have been written, or when a block boundary is\r
+  reached.  *NumBytes is updated to reflect the actual number of bytes\r
+  written. The write opertion does not include erase. This routine will\r
+  attempt to write only the specified bytes. If the writes do not stick,\r
+  it will return an error.\r
+\r
+  @param[in]      This      Calling context\r
+  @param[in]      Lba       Block in which to begin write\r
+  @param[in]      Offset    Offset in the block at which to begin write\r
+  @param[in,out]  NumBytes  On input, indicates the requested write size. On\r
+                            output, indicates the actual number of bytes written\r
+  @param[in]      Buffer    Buffer containing source data for the write.\r
+\r
+  @retval EFI_SUCCESS           The firmware volume was written successfully\r
+  @retval EFI_BAD_BUFFER_SIZE   Write attempted across a LBA boundary. On output,\r
+                                NumBytes contains the total number of bytes\r
+                                actually written\r
+  @retval EFI_ACCESS_DENIED     The firmware volume is in the WriteDisabled state\r
+  @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and\r
+                                could not be written\r
+  @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolWrite (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN EFI_LBA                                    Lba,\r
+  IN UINTN                                      Offset,\r
+  IN OUT UINTN                                  *NumBytes,\r
+  IN UINT8                                      *Buffer\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE                       *FvbDevice;\r
+  EFI_STATUS                                    Status;\r
+\r
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
+  Status    = FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
+  DEBUG((DEBUG_VERBOSE,\r
+    "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status:%r\n",\r
+    Lba, Offset, *NumBytes, Buffer, Status));\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  Reads data beginning at Lba:Offset from FV. The Read terminates either\r
+  when *NumBytes of data have been read, or when a block boundary is\r
+  reached.  *NumBytes is updated to reflect the actual number of bytes\r
+  written. The write opertion does not include erase. This routine will\r
+  attempt to write only the specified bytes. If the writes do not stick,\r
+  it will return an error.\r
+\r
+  @param[in]      This      Calling context\r
+  @param[in]      Lba       Block in which to begin write\r
+  @param[in]      Offset    Offset in the block at which to begin write\r
+  @param[in,out]  NumBytes  On input, indicates the requested write size. On\r
+                            output, indicates the actual number of bytes written\r
+  @param[out]     Buffer    Buffer containing source data for the write.\r
+\r
+\r
+Returns:\r
+  @retval EFI_SUCCESS           The firmware volume was read successfully and\r
+                                contents are in Buffer\r
+  @retval EFI_BAD_BUFFER_SIZE   Read attempted across a LBA boundary. On output,\r
+                                NumBytes contains the total number of bytes returned\r
+                                in Buffer\r
+  @retval EFI_ACCESS_DENIED     The firmware volume is in the ReadDisabled state\r
+  @retval EFI_DEVICE_ERROR      The block device is not functioning correctly and\r
+                                could not be read\r
+  @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolRead (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN EFI_LBA                                    Lba,\r
+  IN UINTN                                      Offset,\r
+  IN OUT UINTN                                  *NumBytes,\r
+  OUT UINT8                                     *Buffer\r
+  )\r
+{\r
+\r
+  EFI_FW_VOL_BLOCK_DEVICE     *FvbDevice;\r
+  EFI_STATUS                  Status;\r
+\r
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);\r
+  Status    = FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer);\r
+  DEBUG((DEBUG_VERBOSE,\r
+    "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status:%r\n",\r
+    Lba, Offset, *NumBytes, Buffer, Status));\r
+\r
+  return Status;\r
+}\r
+\r
+/**\r
+  Check the integrity of firmware volume header in FvBase\r
+\r
+  @param[in]  FvBase        A pointer to firmware volume base address.\r
+\r
+  @retval     TRUE          The firmware volume is consistent\r
+  @retval     FALSE         The firmware volume has corrupted.\r
+\r
+**/\r
+BOOLEAN\r
+IsFvHeaderValid (\r
+  IN       EFI_PHYSICAL_ADDRESS          FvBase\r
+  )\r
+{\r
+  UINT16                                 Sum;\r
+  EFI_FIRMWARE_VOLUME_HEADER             *FwVolHeader;\r
+\r
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvBase;\r
+  if (FvBase == PcdGet32(PcdFlashNvStorageVariableBase)) {\r
+    if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid, sizeof(EFI_GUID)) != 0 ) {\r
+      DEBUG((DEBUG_INFO, "  --FileSystemGuid not match: %g\n", &FwVolHeader->FileSystemGuid));\r
+      return FALSE;\r
+    }\r
+  } else {\r
+    if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2Guid, sizeof(EFI_GUID)) != 0 ) {\r
+      DEBUG((DEBUG_INFO, "  --not expected guid.\n"));\r
+      return FALSE;\r
+    }\r
+  }\r
+\r
+  if ( (FwVolHeader->Revision != EFI_FVH_REVISION)   ||\r
+       (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||\r
+       (FwVolHeader->FvLength == ((UINTN) -1))       ||\r
+       ((FwVolHeader->HeaderLength & 0x01 ) !=0) )  {\r
+    DEBUG((DEBUG_INFO, "  -- >Revision = 0x%x, Signature = 0x%x\n", FwVolHeader->Revision, FwVolHeader->Signature ));\r
+    DEBUG((DEBUG_INFO, "  -- >FvLength = 0x%lx, HeaderLength = 0x%x\n", FwVolHeader->FvLength, FwVolHeader->HeaderLength ));\r
+    return FALSE;\r
+  }\r
+\r
+  Sum = CalculateSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLength);\r
+  if (Sum != 0) {\r
+    DEBUG((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum));\r
+    return FALSE;\r
+  }\r
+\r
+  return TRUE;\r
+}\r
+\r
+\r
+/**\r
+  Get intial variable data.\r
+\r
+  @param[out]  VarData          Valid variable data.\r
+  @param[out]  VarSize          Valid variable size.\r
+\r
+  @retval RETURN_SUCCESS        Successfully found initial variable data.\r
+  @retval RETURN_NOT_FOUND      Failed to find the variable data file from FV.\r
+  @retval EFI_INVALID_PARAMETER VarData or VarSize is null.\r
+\r
+**/\r
+EFI_STATUS\r
+GetInitialVariableData (\r
+  OUT VOID                       **VarData,\r
+  OUT UINTN                      *VarSize\r
+  )\r
+{\r
+  EFI_STATUS                     Status;\r
+  VOID                           *ImageData;\r
+  UINTN                          ImageSize;\r
+  EFI_FIRMWARE_VOLUME_HEADER     *FvHeader;\r
+  VARIABLE_STORE_HEADER          *VariableStore;\r
+  AUTHENTICATED_VARIABLE_HEADER  *Variable;\r
+  UINTN                          VariableSize;\r
+  UINTN                          VarEndAddr;\r
+\r
+  if ((VarData == NULL) || (VarSize == NULL)) {\r
+    return EFI_INVALID_PARAMETER;\r
+  }\r
+\r
+  Status = GetSectionFromAnyFv (PcdGetPtr(PcdNvsDataFile), EFI_SECTION_RAW, 0, &ImageData, &ImageSize);\r
+  if (EFI_ERROR (Status)) {\r
+    return Status;\r
+  }\r
+\r
+  FvHeader      = (EFI_FIRMWARE_VOLUME_HEADER *) ImageData;\r
+  VariableStore = (VARIABLE_STORE_HEADER *) ((UINT8 *)ImageData + FvHeader->HeaderLength);\r
+  VarEndAddr    = (UINTN)VariableStore + VariableStore->Size;\r
+  Variable      = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (VariableStore + 1);\r
+  *VarData      = (VOID *)Variable;\r
+  while (((UINTN)Variable < VarEndAddr)) {\r
+    if (Variable->StartId != VARIABLE_DATA) {\r
+      break;\r
+    }\r
+    VariableSize = sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->DataSize + Variable->NameSize;\r
+    Variable     = (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINTN) Variable + VariableSize);\r
+  }\r
+\r
+  *VarSize = (UINTN)Variable - HEADER_ALIGN (VariableStore + 1);\r
+\r
+  return EFI_SUCCESS;\r
+}\r
+\r
+/**\r
+  The function does the necessary initialization work for\r
+  Firmware Volume Block Driver.\r
+\r
+  @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.\r
+                                It will ASSERT on errors.\r
+\r
+**/\r
+EFI_STATUS\r
+FvbInitialize (\r
+  VOID\r
+  )\r
+{\r
+  EFI_FW_VOL_INSTANCE                   *FwVolInstance;\r
+  EFI_FIRMWARE_VOLUME_HEADER            *FvHeader;\r
+  EFI_FV_BLOCK_MAP_ENTRY                *BlockMap;\r
+  EFI_PHYSICAL_ADDRESS                  BaseAddress;\r
+  UINTN                                 WriteAddr;\r
+  EFI_STATUS                            Status;\r
+  UINTN                                 BufferSize;\r
+  UINTN                                 Length;\r
+  VARIABLE_STORE_HEADER                 VariableStore;\r
+  VOID                                  *VarData;\r
+\r
+  InitVariableStore ();\r
+  BaseAddress = PcdGet32(PcdFlashNvStorageVariableBase);\r
+  FvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;\r
+\r
+  //\r
+  // Check FV header and variable store header\r
+  //\r
+  if (!IsFvHeaderValid (BaseAddress)) {\r
+    //\r
+    //  Write back a healthy FV header\r
+    //\r
+    DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n", BaseAddress));\r
+    FvHeader = GetFvHeaderTemplate ();\r
+    LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, FALSE);\r
+\r
+    Status = LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->BlockMap->Length);\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+    Length    = FvHeader->HeaderLength;\r
+    WriteAddr = (UINTN)BaseAddress;\r
+    Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) FvHeader);\r
+    WriteAddr += Length;\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+    //\r
+    // Write back variable store header\r
+    //\r
+    VariableStore.Size   = PcdGet32(PcdFlashNvStorageVariableSize) - FvHeader->HeaderLength;\r
+    VariableStore.Format = VARIABLE_STORE_FORMATTED;\r
+    VariableStore.State  = VARIABLE_STORE_HEALTHY;\r
+    CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid);\r
+    BufferSize = sizeof (VARIABLE_STORE_HEADER);\r
+    Status = LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *) &VariableStore);\r
+    WriteAddr += BufferSize;\r
+    ASSERT_EFI_ERROR(Status);\r
+\r
+    //\r
+    // Write initial variable data if found\r
+    //\r
+    Status = GetInitialVariableData (&VarData, &Length);\r
+    if (!EFI_ERROR (Status)) {\r
+      Status = LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) VarData);\r
+      ASSERT_EFI_ERROR(Status);\r
+    }\r
+\r
+    LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Length, TRUE);\r
+    WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, FvHeader->BlockMap->Length);\r
+  }\r
+\r
+  //\r
+  // Create a new FW volume instance for NVS variable\r
+  //\r
+  BufferSize    = FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER);\r
+  FwVolInstance = (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (BufferSize);\r
+  if (FwVolInstance == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+  FwVolInstance->FvBase = (UINTN)BaseAddress;\r
+  CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength);\r
+\r
+  //\r
+  // Process the block map for each FV. Assume it has same block size.\r
+  //\r
+  FwVolInstance->NumOfBlocks = 0;\r
+  FvHeader = &FwVolInstance->VolumeHeader;\r
+  for (BlockMap = FvHeader->BlockMap; BlockMap->NumBlocks != 0; BlockMap++) {\r
+    FwVolInstance->NumOfBlocks += BlockMap->NumBlocks;\r
+  }\r
+\r
+  //\r
+  // Add a FVB Protocol Instance\r
+  //\r
+  Status = InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv);\r
+  mFvbModuleGlobal.NumFv++;\r
+  mFvbModuleGlobal.FvInstance = FwVolInstance;\r
+\r
+  return Status;\r
+}\r
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h
new file mode 100644 (file)
index 0000000..c07562c
--- /dev/null
@@ -0,0 +1,187 @@
+/** @file\r
+The header file for Firmware volume block driver.\r
+\r
+Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef FW_BLOCK_SERVICE_H_\r
+#define FW_BLOCK_SERVICE_H_\r
+\r
+#include <Guid/EventGroup.h>\r
+#include <Guid/FirmwareFileSystem2.h>\r
+#include <Guid/SystemNvDataGuid.h>\r
+#include <Guid/VariableFormat.h>\r
+#include <Protocol/DevicePath.h>\r
+#include <Protocol/FirmwareVolumeBlock.h>\r
+#include <Library/UefiDriverEntryPoint.h>\r
+#include <Library/UefiBootServicesTableLib.h>\r
+#include <Library/UefiLib.h>\r
+#include <Library/BaseLib.h>\r
+#include <Library/DebugLib.h>\r
+#include <Library/BaseMemoryLib.h>\r
+#include <Library/IoLib.h>\r
+#include <Library/CacheMaintenanceLib.h>\r
+#include <Library/MemoryAllocationLib.h>\r
+#include <Library/PcdLib.h>\r
+#include <Library/FlashDeviceLib.h>\r
+#include <Library/DevicePathLib.h>\r
+#include <Library/HobLib.h>\r
+#include <Library/DxeServicesLib.h>\r
+#include <Guid/NvVariableInfoGuid.h>\r
+#include <Register/ArchitecturalMsr.h>\r
+\r
+//\r
+// Define two helper macro to extract the Capability field or Status field in FVB\r
+// bit fields\r
+//\r
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \\r
+                              EFI_FVB2_READ_ENABLED_CAP | \\r
+                              EFI_FVB2_WRITE_DISABLED_CAP | \\r
+                              EFI_FVB2_WRITE_ENABLED_CAP | \\r
+                              EFI_FVB2_LOCK_CAP \\r
+                              )\r
+\r
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)\r
+\r
+\r
+typedef struct {\r
+  UINTN                       FvBase;\r
+  UINTN                       NumOfBlocks;\r
+  //\r
+  // Note!!!: VolumeHeader must be the last element\r
+  // of the structure.\r
+  //\r
+  EFI_FIRMWARE_VOLUME_HEADER  VolumeHeader;\r
+} EFI_FW_VOL_INSTANCE;\r
+\r
+\r
+typedef struct {\r
+  EFI_FW_VOL_INSTANCE         *FvInstance;\r
+  UINT32                      NumFv;\r
+  UINT32                      Flags;\r
+} FWB_GLOBAL;\r
+\r
+//\r
+// Fvb Protocol instance data\r
+//\r
+#define FVB_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)\r
+#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE)\r
+#define FVB_DEVICE_SIGNATURE       SIGNATURE_32('F','V','B','C')\r
+\r
+typedef struct {\r
+  MEDIA_FW_VOL_DEVICE_PATH  FvDevPath;\r
+  EFI_DEVICE_PATH_PROTOCOL  EndDevPath;\r
+} FV_PIWG_DEVICE_PATH;\r
+\r
+typedef struct {\r
+  MEMMAP_DEVICE_PATH          MemMapDevPath;\r
+  EFI_DEVICE_PATH_PROTOCOL    EndDevPath;\r
+} FV_MEMMAP_DEVICE_PATH;\r
+\r
+typedef struct {\r
+  UINT32                                Signature;\r
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;\r
+  UINTN                                 Instance;\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    FwVolBlockInstance;\r
+} EFI_FW_VOL_BLOCK_DEVICE;\r
+\r
+/**\r
+  Get a heathy FV header used for variable store recovery\r
+\r
+  @retval     The FV header.\r
+\r
+**/\r
+EFI_FIRMWARE_VOLUME_HEADER *\r
+GetFvHeaderTemplate (\r
+  VOID\r
+  );\r
+\r
+EFI_STATUS\r
+InitVariableStore (\r
+  VOID\r
+  );\r
+\r
+//\r
+// Protocol APIs\r
+//\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetAttributes (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  OUT EFI_FVB_ATTRIBUTES_2                      *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolSetAttributes (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN OUT EFI_FVB_ATTRIBUTES_2                   *Attributes\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetPhysicalAddress (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,\r
+       OUT EFI_PHYSICAL_ADDRESS                *Address\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolGetBlockSize (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,\r
+  IN  EFI_LBA                            Lba,\r
+  OUT UINTN                              *BlockSize,\r
+  OUT UINTN                              *NumOfBlocks\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolRead (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN EFI_LBA                              Lba,\r
+  IN UINTN                                Offset,\r
+  IN OUT UINTN                            *NumBytes,\r
+  OUT UINT8                                *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolWrite (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL   *This,\r
+  IN EFI_LBA                              Lba,\r
+  IN UINTN                                Offset,\r
+  IN OUT UINTN                            *NumBytes,\r
+  IN UINT8                                *Buffer\r
+  );\r
+\r
+EFI_STATUS\r
+EFIAPI\r
+FvbProtocolEraseBlocks (\r
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    *This,\r
+  ...\r
+  );\r
+\r
+EFI_FW_VOL_INSTANCE *\r
+GetFvbInstance (\r
+  IN  UINTN                              Instance\r
+  );\r
+\r
+EFI_STATUS\r
+InstallFvbProtocol (\r
+  IN  EFI_FW_VOL_INSTANCE               *FwhInstance,\r
+  IN  UINTN                             InstanceNum\r
+  );\r
+\r
+EFI_STATUS\r
+FvbInitialize (\r
+  VOID\r
+  );\r
+\r
+extern FWB_GLOBAL              mFvbModuleGlobal;\r
+extern EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate;\r
+extern FV_MEMMAP_DEVICE_PATH   mFvMemmapDevicePathTemplate;\r
+extern FV_PIWG_DEVICE_PATH     mFvPIWGDevicePathTemplate;\r
+\r
+#endif\r
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c b/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c
new file mode 100644 (file)
index 0000000..0f1f4b3
--- /dev/null
@@ -0,0 +1,139 @@
+/** @file\r
+  SMM Firmware Volume Block Driver.\r
+\r
+  Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#include <PiSmm.h>\r
+#include <Library/SmmServicesTableLib.h>\r
+#include "FvbSmmCommon.h"\r
+#include "FvbService.h"\r
+\r
+/**\r
+  The function installs EFI_SMM_FIRMWARE_VOLUME_BLOCK protocol\r
+  for each FV in the system.\r
+\r
+  @param[in]  FwhInstance   The pointer to a FW volume instance structure,\r
+                            which contains the information about one FV.\r
+  @param[in]  InstanceNum   The instance number which can be used as a ID\r
+                            to locate this FwhInstance in other functions.\r
+\r
+  @retval     EFI_SUCESS    Installed successfully.\r
+  @retval     Else          Did not install successfully.\r
+\r
+**/\r
+EFI_STATUS\r
+InstallFvbProtocol (\r
+  IN  EFI_FW_VOL_INSTANCE               *FwhInstance,\r
+  IN  UINTN                             InstanceNum\r
+  )\r
+{\r
+  EFI_FW_VOL_BLOCK_DEVICE               *FvbDevice;\r
+  EFI_FIRMWARE_VOLUME_HEADER            *FwVolHeader;\r
+  EFI_STATUS                            Status;\r
+  EFI_HANDLE                            FvbHandle;\r
+  FV_MEMMAP_DEVICE_PATH                 *FvDevicePath;\r
+  VOID                                  *TempPtr;\r
+\r
+  FvbDevice = (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool (\r
+                                            sizeof (EFI_FW_VOL_BLOCK_DEVICE),\r
+                                            &mFvbDeviceTemplate\r
+                                            );\r
+  if (FvbDevice == NULL) {\r
+    return EFI_OUT_OF_RESOURCES;\r
+  }\r
+\r
+  FvbDevice->Instance = InstanceNum;\r
+  FwVolHeader         = &FwhInstance->VolumeHeader;\r
+\r
+  //\r
+  // Set up the devicepath\r
+  //\r
+  if (FwVolHeader->ExtHeaderOffset == 0) {\r
+    //\r
+    // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH\r
+    //\r
+    TempPtr = AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);\r
+    FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
+    if (FvbDevice->DevicePath == NULL) {\r
+      ASSERT (FALSE);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+    FvDevicePath = (FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath;\r
+    FvDevicePath->MemMapDevPath.StartingAddress = FwhInstance->FvBase;\r
+    FvDevicePath->MemMapDevPath.EndingAddress   = FwhInstance->FvBase + FwVolHeader->FvLength - 1;\r
+  } else {\r
+    TempPtr = AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);\r
+    FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;\r
+    if (FvbDevice->DevicePath == NULL) {\r
+      ASSERT (FALSE);\r
+      return EFI_OUT_OF_RESOURCES;\r
+    }\r
+\r
+    CopyGuid (\r
+      &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,\r
+      (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset)\r
+      );\r
+  }\r
+\r
+  //\r
+  // Install the SMM Firmware Volume Block Protocol and Device Path Protocol\r
+  //\r
+  FvbHandle = NULL;\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &FvbHandle,\r
+                    &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    &FvbDevice->FwVolBlockInstance\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  Status = gSmst->SmmInstallProtocolInterface (\r
+                    &FvbHandle,\r
+                    &gEfiDevicePathProtocolGuid,\r
+                    EFI_NATIVE_INTERFACE,\r
+                    FvbDevice->DevicePath\r
+                    );\r
+  ASSERT_EFI_ERROR (Status);\r
+\r
+  //\r
+  // Notify the Fvb wrapper driver SMM fvb is ready\r
+  //\r
+  FvbHandle = NULL;\r
+  Status = gBS->InstallProtocolInterface (\r
+                  &FvbHandle,\r
+                  &gEfiSmmFirmwareVolumeBlockProtocolGuid,\r
+                  EFI_NATIVE_INTERFACE,\r
+                  &FvbDevice->FwVolBlockInstance\r
+                  );\r
+\r
+  return Status;\r
+}\r
+\r
+\r
+/**\r
+  The driver entry point for SMM Firmware Volume Block Driver.\r
+\r
+  The function does the necessary initialization work\r
+  Firmware Volume Block Driver.\r
+\r
+  @param[in]  ImageHandle       The firmware allocated handle for the UEFI image.\r
+  @param[in]  SystemTable       A pointer to the EFI system table.\r
+\r
+  @retval     EFI_SUCCESS       This funtion always return EFI_SUCCESS.\r
+                                It will ASSERT on errors.\r
+\r
+**/\r
+EFI_STATUS\r
+EFIAPI\r
+FvbSmmInitialize (\r
+  IN EFI_HANDLE         ImageHandle,\r
+  IN EFI_SYSTEM_TABLE   *SystemTable\r
+  )\r
+{\r
+  FvbInitialize ();\r
+\r
+  return EFI_SUCCESS;\r
+}\r
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf
new file mode 100644 (file)
index 0000000..2a26207
--- /dev/null
@@ -0,0 +1,71 @@
+## @file\r
+# This driver installs the EFI_SMM_FIRMWARE_VOLUMEN_PROTOCOL.\r
+#\r
+#\r
+#  Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+#\r
+#  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+#\r
+##\r
+\r
+[Defines]\r
+  INF_VERSION                    = 0x00010005\r
+  BASE_NAME                      = FvbSmm\r
+  FILE_GUID                      = A4EC8ADB-B7A8-47d1-8E52-EC820D0ACF6F\r
+  MODULE_TYPE                    = DXE_SMM_DRIVER\r
+  VERSION_STRING                 = 1.0\r
+  PI_SPECIFICATION_VERSION       = 0x0001000A\r
+  ENTRY_POINT                    = FvbSmmInitialize\r
+\r
+[Sources]\r
+  FvbInfo.c\r
+  FvbService.h\r
+  FvbService.c\r
+  FvbServiceSmm.c\r
+  FvbSmmCommon.h\r
+\r
+[Packages]\r
+  MdePkg/MdePkg.dec\r
+  MdeModulePkg/MdeModulePkg.dec\r
+  UefiCpuPkg/UefiCpuPkg.dec\r
+  UefiPayloadPkg/UefiPayloadPkg.dec\r
+\r
+[LibraryClasses]\r
+  FlashDeviceLib\r
+  PcdLib\r
+  MemoryAllocationLib\r
+  CacheMaintenanceLib\r
+  IoLib\r
+  BaseMemoryLib\r
+  DebugLib\r
+  BaseLib\r
+  UefiLib\r
+  SmmServicesTableLib\r
+  UefiBootServicesTableLib\r
+  UefiDriverEntryPoint\r
+  HobLib\r
+  DxeServicesLib\r
+\r
+[Guids]\r
+  gEfiFirmwareFileSystem2Guid                   # ALWAYS_CONSUMED\r
+  gEfiSystemNvDataFvGuid                        # ALWAYS_CONSUMED\r
+  gEfiAuthenticatedVariableGuid\r
+  gNvVariableInfoGuid\r
+\r
+  [Protocols]\r
+  gEfiDevicePathProtocolGuid                    # PROTOCOL ALWAYS_PRODUCED\r
+  gEfiSmmFirmwareVolumeBlockProtocolGuid        # PROTOCOL ALWAYS_PRODUCED\r
+\r
+[Pcd]\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize\r
+\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase\r
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase\r
+  gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile\r
+\r
+[Depex]\r
+  TRUE\r
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h
new file mode 100644 (file)
index 0000000..5886996
--- /dev/null
@@ -0,0 +1,69 @@
+/** @file\r
+  The common header file for SMM FVB module.\r
+\r
+Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>\r
+SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef SMM_FVB_COMMON_H_\r
+#define SMM_FVB_COMMON_H_\r
+\r
+#include <Protocol/SmmFirmwareVolumeBlock.h>\r
+\r
+#define EFI_FUNCTION_GET_ATTRIBUTES           1\r
+#define EFI_FUNCTION_SET_ATTRIBUTES           2\r
+#define EFI_FUNCTION_GET_PHYSICAL_ADDRESS     3\r
+#define EFI_FUNCTION_GET_BLOCK_SIZE           4\r
+#define EFI_FUNCTION_READ                     5\r
+#define EFI_FUNCTION_WRITE                    6\r
+#define EFI_FUNCTION_ERASE_BLOCKS             7\r
+\r
+typedef struct {\r
+  UINTN       Function;\r
+  EFI_STATUS  ReturnStatus;\r
+  UINT8       Data[1];\r
+} SMM_FVB_COMMUNICATE_FUNCTION_HEADER;\r
+\r
+\r
+///\r
+/// Size of SMM communicate header, without including the payload.\r
+///\r
+#define SMM_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADER, Data))\r
+\r
+///\r
+/// Size of SMM FVB communicate function header, without including the payload.\r
+///\r
+#define SMM_FVB_COMMUNICATE_HEADER_SIZE  (OFFSET_OF (SMM_FVB_COMMUNICATE_FUNCTION_HEADER, Data))\r
+\r
+typedef struct {\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *SmmFvb;\r
+  EFI_FVB_ATTRIBUTES_2                       Attributes;\r
+} SMM_FVB_ATTRIBUTES_HEADER;\r
+\r
+typedef struct {\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *SmmFvb;\r
+  EFI_PHYSICAL_ADDRESS                       Address;\r
+} SMM_FVB_PHYSICAL_ADDRESS_HEADER;\r
+\r
+typedef struct {\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *SmmFvb;\r
+  EFI_LBA                                    Lba;\r
+  UINTN                                      BlockSize;\r
+  UINTN                                      NumOfBlocks;\r
+} SMM_FVB_BLOCK_SIZE_HEADER;\r
+\r
+typedef struct {\r
+  EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL     *SmmFvb;\r
+  EFI_LBA                                    Lba;\r
+  UINTN                                      Offset;\r
+  UINTN                                      NumBytes;\r
+} SMM_FVB_READ_WRITE_HEADER;\r
+\r
+typedef struct {\r
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL         *SmmFvb;\r
+  EFI_LBA                                    StartLba;\r
+  UINTN                                      NumOfLba;\r
+} SMM_FVB_BLOCKS_HEADER;\r
+\r
+#endif\r
diff --git a/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h b/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h
new file mode 100644 (file)
index 0000000..f22e4e6
--- /dev/null
@@ -0,0 +1,24 @@
+/** @file\r
+  This file defines the hob structure for the SPI flash variable info.\r
+\r
+  Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>\r
+  SPDX-License-Identifier: BSD-2-Clause-Patent\r
+\r
+**/\r
+\r
+#ifndef NV_VARIABLE_INFO_GUID_H_\r
+#define NV_VARIABLE_INFO_GUID_H_\r
+\r
+//\r
+// NV variable hob info GUID\r
+//\r
+extern EFI_GUID gNvVariableInfoGuid;\r
+\r
+typedef struct {\r
+  UINT8                  Revision;\r
+  UINT8                  Reserved[3];\r
+  UINT32                 VariableStoreBase;\r
+  UINT32                 VariableStoreSize;\r
+} NV_VARIABLE_INFO;\r
+\r
+#endif\r
index 3ffdce550d11367cb7358e2b11976d01c0599431..e385dc7219e11036c0e2743a1281ab0a82a1d4b5 100644 (file)
@@ -37,6 +37,8 @@
   gUefiSerialPortInfoGuid  = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }\r
   gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }\r
 \r
   gUefiSerialPortInfoGuid  = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }\r
   gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }\r
 \r
+  # SMM variable support\r
+  gNvVariableInfoGuid      = { 0x7a345dca, 0xc26, 0x4f2a,  { 0xa8, 0x9a, 0x57, 0xc0, 0x8d, 0xdd, 0x22, 0xee } }\r
   gSpiFlashInfoGuid        = { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c, 0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } }\r
   gSmmRegisterInfoGuid     = { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9, 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }\r
   gS3CommunicationGuid     = { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf, 0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } }\r
   gSpiFlashInfoGuid        = { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c, 0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } }\r
   gSmmRegisterInfoGuid     = { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9, 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }\r
   gS3CommunicationGuid     = { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf, 0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } }\r
@@ -81,3 +83,7 @@ gUefiPayloadPkgTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServicesCode|0x80|UINT32|0x
 gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x02000000|UINT32|0x00000017\r
 \r
 gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile|{ 0x57, 0x72, 0xcf, 0x80, 0xab, 0x87, 0xf9, 0x47, 0xa3, 0xfe, 0xD5, 0x0B, 0x76, 0xd8, 0x95, 0x41 }|VOID*|0x00000018\r
 gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x02000000|UINT32|0x00000017\r
 \r
 gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile|{ 0x57, 0x72, 0xcf, 0x80, 0xab, 0x87, 0xf9, 0x47, 0xa3, 0xfe, 0xD5, 0x0B, 0x76, 0xd8, 0x95, 0x41 }|VOID*|0x00000018\r
+\r
+## FFS filename to find the default variable initial data file.\r
+# @Prompt FFS Name of variable initial data file\r
+ gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile |{ 0x1a, 0xf1, 0xb1, 0xae, 0x42, 0xcc, 0xcf, 0x4e, 0xac, 0x60, 0xdb, 0xab, 0xf6, 0xca, 0x69, 0xe6 }|VOID*|0x00000025\r