public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Zhai, MingXin (Duke) via groups.io" <duke.zhai=amd.com@groups.io>
To: <devel@edk2.groups.io>
Cc: Eric Xing <eric.xing@amd.com>, Ken Yao <ken.yao@amd.com>,
	Igniculus Fu <igniculus.fu@amd.com>,
	Abner Chang <abner.chang@amd.com>
Subject: [edk2-devel] [PATCH V2 11/32] AMD/VanGoghBoard: Check in FvbServices
Date: Fri, 26 Jan 2024 14:00:29 +0800	[thread overview]
Message-ID: <20240126060050.1725-12-duke.zhai@amd.com> (raw)
In-Reply-To: <20240126060050.1725-1-duke.zhai@amd.com>

From: Duke Zhai <Duke.Zhai@amd.com>

BZ #:4640
In V2: Improve coding style.
  1.Remove the leading underscore and use double underscore at trailing in C header files.
  2.Remove old tianocore licenses and redundant license description.
  3.Improve coding style. For example: remove space between @param.

In V1:
  Initial FvbServices module. It describes platform flash IC information
  for FlashUpdate module to send command correctly.
  Different flash ICs may use the different Opcodes.

Signed-off-by: Duke Zhai <duke.zhai@amd.com>
Cc: Eric Xing <eric.xing@amd.com>
Cc: Ken Yao <ken.yao@amd.com>
Cc: Igniculus Fu <igniculus.fu@amd.com>
Cc: Abner Chang <abner.chang@amd.com>
---
 .../VanGoghCommonPkg/FvbServices/FvbInfo.c    |  120 ++
 .../FvbServices/FwBlockService.c              | 1285 +++++++++++++++++
 .../FvbServices/FwBlockService.h              |  515 +++++++
 .../FvbServices/PlatformSmmSpi.inf            |   68 +
 4 files changed, 1988 insertions(+)
 create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FvbInfo.c
 create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.c
 create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.h
 create mode 100644 Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/PlatformSmmSpi.inf

diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FvbInfo.c b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FvbInfo.c
new file mode 100644
index 0000000000..c0be635864
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FvbInfo.c
@@ -0,0 +1,120 @@
+/** @file
+Defines data structure that is the volume header found.These data is intent
+to decouple FVB driver with FV header.
+
+Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+Copyright (c) 2013 Intel Corporation. All rights reserved.<BR>
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+
+**/
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Guid/EventGroup.h>
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/DevicePath.h>
+//
+// The Library classes this module consumes
+//
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+#define FVB_MEDIA_BLOCK_SIZE  (0x00010000)
+
+#define SYSTEM_NV_BLOCK_NUM  ((FixedPcdGet32(PcdFlashNvStorageVariableSize)+ FixedPcdGet32(PcdFlashNvStorageFtwWorkingSize) + FixedPcdGet32(PcdFlashNvStorageFtwSpareSize))/ FVB_MEDIA_BLOCK_SIZE)
+
+typedef struct {
+  EFI_PHYSICAL_ADDRESS          BaseAddress;
+  EFI_FIRMWARE_VOLUME_HEADER    FvbInfo;
+  //
+  // EFI_FV_BLOCK_MAP_ENTRY    ExtraBlockMap[n];//n=0
+  //
+  EFI_FV_BLOCK_MAP_ENTRY        End[1];
+} EFI_FVB2_MEDIA_INFO;
+
+EFI_FVB2_MEDIA_INFO  mPlatformFvbMediaInfo =
+  //
+  // Systen NvStorage FVB
+  //
+{
+  0,
+  {
+    {
+      0,
+    },    // ZeroVector[16]
+    EFI_SYSTEM_NV_DATA_FV_GUID,
+    FVB_MEDIA_BLOCK_SIZE *SYSTEM_NV_BLOCK_NUM,
+    EFI_FVH_SIGNATURE,
+    EFI_FVB2_MEMORY_MAPPED |
+    EFI_FVB2_READ_ENABLED_CAP |
+    EFI_FVB2_READ_STATUS |
+    EFI_FVB2_WRITE_ENABLED_CAP |
+    EFI_FVB2_WRITE_STATUS |
+    EFI_FVB2_ERASE_POLARITY |
+    EFI_FVB2_ALIGNMENT_16,
+    sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY),
+    0xFBFF,    // CheckSum
+    0,         // ExtHeaderOffset
+    {
+      0,
+    },    // Reserved[1]
+    2,    // Revision
+    {
+      {
+        SYSTEM_NV_BLOCK_NUM,
+        FVB_MEDIA_BLOCK_SIZE,
+      }
+    }
+  },
+  {
+    {
+      0,
+      0
+    }
+  }
+};
+
+/**
+  Get Fvb information.
+
+  @param[in] BaseAddress    The base address compare with NvStorageVariable base address.
+  @param[out] FvbInfo        Fvb information.
+
+  @retval EFI_SUCCESS       Get Fvb information successfully.
+  @retval EFI_NOT_FOUND     Not find Fvb information.
+
+**/
+EFI_STATUS
+EFIAPI
+GetFvbInfo (
+  IN  UINT64                      BaseAddress,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **FvbInfo
+  )
+{
+  mPlatformFvbMediaInfo.BaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
+
+  if (mPlatformFvbMediaInfo.BaseAddress == BaseAddress) {
+    *FvbInfo = &mPlatformFvbMediaInfo.FvbInfo;
+    return EFI_SUCCESS;
+  }
+
+  return EFI_NOT_FOUND;
+}
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.c b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.c
new file mode 100644
index 0000000000..f514ad772a
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.c
@@ -0,0 +1,1285 @@
+/** @file
+  Implements FvbServicesSmm
+
+  Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+  Copyright (c) 2013-2016 Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifdef _MSC_VER
+  #pragma optimize( "", off )
+#endif
+
+#ifdef __GNUC__
+  #ifndef __clang__
+    #pragma GCC push_options
+    #pragma GCC optimize ("O0")
+  #else
+    #pragma clang optimize off
+  #endif
+#endif
+
+#include "FwBlockService.h"
+
+#define EFI_FVB2_STATUS  (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
+
+ESAL_FWB_GLOBAL  *mFvbModuleGlobal;
+
+FV_MEMMAP_DEVICE_PATH  mFvMemmapDevicePathTemplate = {
+  {
+    {
+      HARDWARE_DEVICE_PATH,
+      HW_MEMMAP_DP,
+      {
+        (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),
+        (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)
+      }
+    },
+    EfiMemoryMappedIO,
+    (EFI_PHYSICAL_ADDRESS)0,
+    (EFI_PHYSICAL_ADDRESS)0,
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+FV_PIWG_DEVICE_PATH  mFvPIWGDevicePathTemplate = {
+  {
+    {
+      MEDIA_DEVICE_PATH,
+      MEDIA_PIWG_FW_VOL_DP,
+      {
+        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),
+        (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)
+      }
+    },
+    { 0 }
+  },
+  {
+    END_DEVICE_PATH_TYPE,
+    END_ENTIRE_DEVICE_PATH_SUBTYPE,
+    {
+      END_DEVICE_PATH_LENGTH,
+      0
+    }
+  }
+};
+
+EFI_FW_VOL_BLOCK_DEVICE  mFvbDeviceTemplate = {
+  FVB_DEVICE_SIGNATURE,
+  NULL,
+  0,
+  {
+    FvbProtocolGetAttributes,
+    FvbProtocolSetAttributes,
+    FvbProtocolGetPhysicalAddress,
+    FvbProtocolGetBlockSize,
+    FvbProtocolRead,
+    FvbProtocolWrite,
+    FvbProtocolEraseBlocks,
+    NULL
+  }
+};
+
+/**
+  Retrieves the physical address of a memory mapped FV
+
+  @param[in]  Instance    The FV instance whose base address is going to be returned.
+
+  @param[in]  Global      Pointer to ESAL_FWB_GLOBAL that contains all instance data.
+
+  @param[out] FwhInstance The EFI_FW_VOL_INSTANCE fimrware instance structure
+  @param[in]  Virtual     Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS            Successfully returns
+  @retval  EFI_INVALID_PARAMETER  Instance not found           -
+
+**/
+EFI_STATUS
+GetFvbInstance (
+  IN  UINTN                Instance,
+  IN  ESAL_FWB_GLOBAL      *Global,
+  OUT EFI_FW_VOL_INSTANCE  **FwhInstance,
+  IN BOOLEAN               Virtual
+  )
+{
+  EFI_FW_VOL_INSTANCE  *FwhRecord;
+
+  if (Instance >= Global->NumFv) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // Find the right instance of the FVB private data
+  //
+  FwhRecord = Global->FvInstance[Virtual];
+  while (Instance > 0) {
+    FwhRecord = (EFI_FW_VOL_INSTANCE *)
+                (
+                 (UINTN)((UINT8 *)FwhRecord) + FwhRecord->VolumeHeader.HeaderLength +
+                 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
+                );
+    Instance--;
+  }
+
+  *FwhInstance = FwhRecord;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves the physical address of a memory mapped FV
+
+  @param[in]  Instance  The FV instance whose base address is going to be returned.
+
+  @param[out]  Address  Pointer to a caller allocated EFI_PHYSICAL_ADDRESS
+                        that on successful return, contains the base address
+                        of the firmware volume.
+  @param[in]  Global    Pointer to ESAL_FWB_GLOBAL that contains all
+                        instance data
+  @param[in]  Virtual   Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS            Successfully returns
+  @retval  EFI_INVALID_PARAMETER  Instance not found            -
+   -
+
+**/
+EFI_STATUS
+FvbGetPhysicalAddress (
+  IN UINTN                  Instance,
+  OUT EFI_PHYSICAL_ADDRESS  *Address,
+  IN ESAL_FWB_GLOBAL        *Global,
+  IN BOOLEAN                Virtual
+  )
+{
+  EFI_FW_VOL_INSTANCE  *FwhInstance;
+  EFI_STATUS           Status;
+
+  FwhInstance = NULL;
+
+  //
+  // Find the right instance of the FVB private data
+  //
+  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
+  ASSERT_EFI_ERROR (Status);
+  *Address = FwhInstance->FvBase[Virtual];
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves attributes, insures positive polarity of attribute bits, returns
+  resulting attributes in output parameter
+
+  @param[in]  Instance   The FV instance whose attributes is going to be
+                         returned
+  @param[out] Attributes Output buffer which contains attributes
+  @param[in]  Global     Pointer to ESAL_FWB_GLOBAL that contains all
+                         instance data
+  @param[in]  Virtual    Whether CPU is in virtual or physical mode
+
+  @retval    EFI_SUCCESS            Successfully returns
+  @retval    EFI_INVALID_PARAMETER  Instance not found
+
+**/
+EFI_STATUS
+FvbGetVolumeAttributes (
+  IN UINTN                  Instance,
+  OUT EFI_FVB_ATTRIBUTES_2  *Attributes,
+  IN ESAL_FWB_GLOBAL        *Global,
+  IN BOOLEAN                Virtual
+  )
+{
+  EFI_FW_VOL_INSTANCE  *FwhInstance;
+  EFI_STATUS           Status;
+
+  FwhInstance = NULL;
+
+  //
+  // Find the right instance of the FVB private data
+  //
+  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
+  ASSERT_EFI_ERROR (Status);
+  *Attributes = FwhInstance->VolumeHeader.Attributes;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves the starting address of an LBA in an FV
+
+  @param[in]   Instance               The FV instance which the Lba belongs to
+  @param[in]   Lba                    The logical block address
+  @param[out]  LbaAddress             On output, contains the physical starting address
+                          of the Lba
+  @param[out]  LbaLength              On output, contains the length of the block
+  @param[out]  NumOfBlocks            A pointer to a caller allocated UINTN in which the
+                                      number of consecutive blocks starting with Lba is
+                                      returned. All blocks in this range have a size of
+                                      BlockSize
+  @param[in]  Global                  Pointer to ESAL_FWB_GLOBAL that contains all
+                                      instance data
+  @param[in]  Virtual                 Whether CPU is in virtual or physical mode
+  @retval  EFI_SUCCESS             Successfully returns
+  @retval  EFI_INVALID_PARAMETER   Instance not found
+
+**/
+EFI_STATUS
+FvbGetLbaAddress (
+  IN  UINTN            Instance,
+  IN  EFI_LBA          Lba,
+  OUT UINTN            *LbaAddress,
+  OUT UINTN            *LbaLength,
+  OUT UINTN            *NumOfBlocks,
+  IN  ESAL_FWB_GLOBAL  *Global,
+  IN  BOOLEAN          Virtual
+  )
+{
+  UINT32                  NumBlocks;
+  UINT32                  BlockLength;
+  UINTN                   Offset;
+  EFI_LBA                 StartLba;
+  EFI_LBA                 NextLba;
+  EFI_FW_VOL_INSTANCE     *FwhInstance;
+  EFI_FV_BLOCK_MAP_ENTRY  *BlockMap;
+  EFI_STATUS              Status;
+
+  FwhInstance = NULL;
+
+  //
+  // Find the right instance of the FVB private data
+  //
+  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
+  ASSERT_EFI_ERROR (Status);
+
+  StartLba = 0;
+  Offset   = 0;
+  BlockMap = &(FwhInstance->VolumeHeader.BlockMap[0]);
+
+  //
+  // Parse the blockmap of the FV to find which map entry the Lba belongs to
+  //
+  while (TRUE) {
+    NumBlocks   = BlockMap->NumBlocks;
+    BlockLength = BlockMap->Length;
+
+    if ((NumBlocks == 0) || (BlockLength == 0)) {
+      return EFI_INVALID_PARAMETER;
+    }
+
+    NextLba = StartLba + NumBlocks;
+
+    //
+    // The map entry found
+    //
+    if ((Lba >= StartLba) && (Lba < NextLba)) {
+      Offset = Offset + (UINTN)MultU64x32 ((Lba - StartLba), BlockLength);
+      if (LbaAddress) {
+        *LbaAddress = FwhInstance->FvBase[Virtual] + Offset;
+      }
+
+      if (LbaLength) {
+        *LbaLength = BlockLength;
+      }
+
+      if (NumOfBlocks) {
+        *NumOfBlocks = (UINTN)(NextLba - Lba);
+      }
+
+      return EFI_SUCCESS;
+    }
+
+    StartLba = NextLba;
+    Offset   = Offset + NumBlocks * BlockLength;
+    BlockMap++;
+  }
+}
+
+/**
+  Reads specified number of bytes into a buffer from the specified block
+
+  @param[in]       Instance      The FV instance to be read from
+  @param[in]       Lba           The logical block address to be read from
+  @param[in]       BlockOffset   Offset into the block at which to begin reading
+  @param[in, out]  NumBytes      Pointer that on input contains the total size of
+                                 the buffer. On output, it contains the total number
+                                 of bytes read
+  @param[in]       Buffer        Pointer to a caller allocated buffer that will be
+                                 used to hold the data read
+  @param[in]       Global        Pointer to ESAL_FWB_GLOBAL that contains all
+                                 instance data
+  @param[in]       Virtual       Whether CPU is in virtual or physical mode
+
+  @retval   EFI_SUCCESS            The firmware volume was read successfully and
+                                   contents are in Buffer
+  @retval   EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes returned
+                                   in Buffer
+  @retval   EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
+  @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
+                                   could not be read
+  @retval   EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL
+
+**/
+EFI_STATUS
+FvbReadBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN UINTN            BlockOffset,
+  IN OUT UINTN        *NumBytes,
+  IN UINT8            *Buffer,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  )
+
+{
+  EFI_FVB_ATTRIBUTES_2  Attributes;
+  UINTN                 LbaAddress;
+  UINTN                 LbaLength;
+  EFI_STATUS            Status;
+
+  DEBUG ((DEBUG_INFO, "Smm %a() enter\n", __FUNCTION__));
+
+  //
+  // Check for invalid conditions
+  //
+  if ((NumBytes == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*NumBytes == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Check if the FV is read enabled
+  //
+  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
+
+  if ((Attributes & EFI_FVB2_READ_STATUS) == 0) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Perform boundary checks and adjust NumBytes
+  //
+  if (BlockOffset > LbaLength) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (LbaLength < (*NumBytes + BlockOffset)) {
+    *NumBytes = (UINT32)(LbaLength - BlockOffset);
+    Status    = EFI_BAD_BUFFER_SIZE;
+  }
+
+  // DEBUG ((DEBUG_INFO, "ReadAddress: 0x%x, NumBytes: 0x%x\n", (UINT8 *) (LbaAddress + BlockOffset), *NumBytes));
+  CopyMem (Buffer, (UINT8 *)(LbaAddress + BlockOffset), (UINTN)(*NumBytes));
+
+  return Status;
+}
+
+/**
+  Writes specified number of bytes from the input buffer to the block
+
+  @param[in]       Instance      The FV instance to be written to
+  @param[in]       Lba           The starting logical block index to write to
+  @param[in]       BlockOffset   Offset into the block at which to begin writing
+  @param[in, out]  NumBytes      Pointer that on input contains the total size of
+                                 the buffer. On output, it contains the total number
+                                 of bytes actually written
+  @param[in]       Buffer        Pointer to a caller allocated buffer that contains
+                                 the source for the write
+  @param[in]       Global        Pointer to ESAL_FWB_GLOBAL that contains all
+                                 instance data
+  @param[in]       Virtual       Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             The firmware volume was written successfully
+  @retval  EFI_BAD_BUFFER_SIZE     Write attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes
+                                   actually written
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written
+  @retval  EFI_INVALID_PARAMETER   Instance not found, or NumBytes, Buffer are NULL
+
+**/
+EFI_STATUS
+FvbWriteBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN UINTN            BlockOffset,
+  IN OUT UINTN        *NumBytes,
+  IN UINT8            *Buffer,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  Attributes;
+  UINTN                 LbaAddress;
+  UINTN                 LbaLength;
+  EFI_STATUS            Status;
+
+  //
+  // Check for invalid conditions
+  //
+  if ((NumBytes == NULL) || (Buffer == NULL)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (*NumBytes == 0) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  //
+  // Check if the FV is write enabled
+  //
+  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
+
+  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Perform boundary checks and adjust NumBytes
+  //
+  if (BlockOffset > LbaLength) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  if (LbaLength < (*NumBytes + BlockOffset)) {
+    *NumBytes = (UINT32)(LbaLength - BlockOffset);
+    Status    = EFI_BAD_BUFFER_SIZE;
+  }
+
+  //
+  // Write data
+  //
+  Status = FlashFdWrite (
+             LbaAddress + BlockOffset,
+             LbaAddress,
+             NumBytes,
+             Buffer,
+             LbaLength
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  return Status;
+}
+
+/**
+  Erases and initializes a firmware volume block
+
+  @param[in]  Instance    The FV instance to be erased
+  @param[in]  Lba         The logical block index to be erased
+  @param[in]  Global      Pointer to ESAL_FWB_GLOBAL that contains all
+                          instance data
+  @param[in]  Virtual     Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             The erase request was successfully completed
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written. Firmware device may have been
+                                   partially erased
+  @retval  EFI_INVALID_PARAMETER   Instance not found
+
+**/
+EFI_STATUS
+FvbEraseBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  Attributes;
+  UINTN                 LbaAddress;
+  UINTN                 LbaLength;
+  EFI_STATUS            Status;
+
+  //
+  // Check if the FV is write enabled
+  //
+  FvbGetVolumeAttributes (Instance, &Attributes, Global, Virtual);
+
+  if ((Attributes & EFI_FVB2_WRITE_STATUS) == 0) {
+    return EFI_ACCESS_DENIED;
+  }
+
+  //
+  // Get the starting address of the block for erase.
+  //
+  Status = FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NULL, Global, Virtual);
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Status = FlashFdErase (LbaAddress, LbaLength);
+
+  return Status;
+}
+
+/**
+  Modifies the current settings of the firmware volume according to the
+  input parameter, and returns the new setting of the volume
+
+  @param[in]       Instance          The FV instance whose attributes is going to be
+                                     modified
+  @param[in, out]  Attributes        On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
+                                     containing the desired firmware volume settings.
+                                     On successful return, it contains the new settings
+                                     of the firmware volume
+  @param[in]       Global            Pointer to ESAL_FWB_GLOBAL that contains all
+                                     instance data
+  @param[in]       Virtual           Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             Successfully returns
+  @retval  EFI_ACCESS_DENIED       The volume setting is locked and cannot be modified
+  @retval  EFI_INVALID_PARAMETER   Instance not found, or The attributes requested are
+                                   in conflict with the capabilities as declared in the
+                                   firmware volume header
+
+**/
+EFI_STATUS
+FvbSetVolumeAttributes (
+  IN UINTN                     Instance,
+  IN OUT EFI_FVB_ATTRIBUTES_2  *Attributes,
+  IN ESAL_FWB_GLOBAL           *Global,
+  IN BOOLEAN                   Virtual
+  )
+{
+  EFI_FW_VOL_INSTANCE   *FwhInstance;
+  EFI_FVB_ATTRIBUTES_2  OldAttributes;
+  EFI_FVB_ATTRIBUTES_2  *AttribPtr;
+  UINT32                Capabilities;
+  UINT32                OldStatus;
+  UINT32                NewStatus;
+  EFI_STATUS            Status;
+  EFI_FVB_ATTRIBUTES_2  UnchangedAttributes;
+
+  FwhInstance = NULL;
+  //
+  // Find the right instance of the FVB private data
+  //
+  Status = GetFvbInstance (Instance, Global, &FwhInstance, Virtual);
+  ASSERT_EFI_ERROR (Status);
+
+  AttribPtr     = (EFI_FVB_ATTRIBUTES_2 *)&(FwhInstance->VolumeHeader.Attributes);
+  OldAttributes = *AttribPtr;
+  Capabilities  = OldAttributes & (EFI_FVB2_READ_DISABLED_CAP | \
+                                   EFI_FVB2_READ_ENABLED_CAP | \
+                                   EFI_FVB2_WRITE_DISABLED_CAP | \
+                                   EFI_FVB2_WRITE_ENABLED_CAP | \
+                                   EFI_FVB2_LOCK_CAP \
+                                   );
+  OldStatus = OldAttributes & EFI_FVB2_STATUS;
+  NewStatus = *Attributes & EFI_FVB2_STATUS;
+
+  UnchangedAttributes = EFI_FVB2_READ_DISABLED_CAP  | \
+                        EFI_FVB2_READ_ENABLED_CAP   | \
+                        EFI_FVB2_WRITE_DISABLED_CAP | \
+                        EFI_FVB2_WRITE_ENABLED_CAP  | \
+                        EFI_FVB2_LOCK_CAP           | \
+                        EFI_FVB2_STICKY_WRITE       | \
+                        EFI_FVB2_MEMORY_MAPPED      | \
+                        EFI_FVB2_ERASE_POLARITY     | \
+                        EFI_FVB2_READ_LOCK_CAP      | \
+                        EFI_FVB2_WRITE_LOCK_CAP     | \
+                        EFI_FVB2_ALIGNMENT;
+
+  //
+  // Some attributes of FV is read only can *not* be set
+  //
+  if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttributes)) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  //
+  // If firmware volume is locked, no status bit can be updated
+  //
+  if (OldAttributes & EFI_FVB2_LOCK_STATUS) {
+    if (OldStatus ^ NewStatus) {
+      return EFI_ACCESS_DENIED;
+    }
+  }
+
+  //
+  // Test read disable
+  //
+  if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+    if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Test read enable
+  //
+  if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_READ_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Test write disable
+  //
+  if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+    if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Test write enable
+  //
+  if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_WRITE_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  //
+  // Test lock
+  //
+  if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+    if (NewStatus & EFI_FVB2_LOCK_STATUS) {
+      return EFI_INVALID_PARAMETER;
+    }
+  }
+
+  *AttribPtr  = (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+  *AttribPtr  = (*AttribPtr) | NewStatus;
+  *Attributes = *AttribPtr;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Retrieves the physical address of the device.
+
+  @param[in]   This        Calling context
+  @param[out]  Address     Output buffer containing the address.
+
+  @retval EFI_SUCCESS  Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  OUT EFI_PHYSICAL_ADDRESS                     *Address
+  )
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+  return FvbGetPhysicalAddress (FvbDevice->Instance, Address, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+}
+
+/**
+  Retrieve the size of a logical block
+
+  @param[in]   This           alling context
+  @param[in]   Lba            Indicates which block to return the size for.
+  @param[out]  BlockSize      A pointer to a caller allocated UINTN in which
+                              the size of the block is returned
+  @param[out]  NumOfBlocks    a pointer to a caller allocated UINTN in which the
+                              number of consecutive blocks starting with Lba is
+                              returned. All blocks in this range have a size of
+                              BlockSize
+
+  @retval  EFI_SUCCESS        The firmware volume was read successfully and
+                              contents are in Buffer
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN CONST EFI_LBA                             Lba,
+  OUT UINTN                                    *BlockSize,
+  OUT UINTN                                    *NumOfBlocks
+  )
+
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+  return FvbGetLbaAddress (
+           FvbDevice->Instance,
+           Lba,
+           NULL,
+           BlockSize,
+           NumOfBlocks,
+           mFvbModuleGlobal,
+                 // EfiGoneVirtual ()
+           FALSE // Hard coded to FALSE for SMM driver.
+           );
+}
+
+/**
+    Retrieves Volume attributes.  No polarity translations are done.
+
+  @param[in]     This                 Calling context
+  @param[out]    Attributes           output buffer which contains attributes
+
+  @retval  EFI_SUCCESS            Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  OUT EFI_FVB_ATTRIBUTES_2                     *Attributes
+  )
+
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+  return FvbGetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+}
+
+/**
+  Sets Volume attributes. No polarity translations are done.
+
+  @param[in]   This                   Calling context
+  @param[out]  Attributes             output buffer which contains attributes
+
+  @retval  EFI_SUCCESS                Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN OUT EFI_FVB_ATTRIBUTES_2                  *Attributes
+  )
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+  // return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, EfiGoneVirtual ());
+  return FvbSetVolumeAttributes (FvbDevice->Instance, Attributes, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+}
+
+/**
+  The EraseBlock() function erases one or more blocks as denoted by the
+  variable argument list. The entire parameter list of blocks must be verified
+  prior to erasing any blocks.  If a block is requested that does not exist
+  within the associated firmware volume (it has a larger index than the last
+  block of the firmware volume), the EraseBlock() function must return
+  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+  @param[in]  This                    Calling context
+  @param[in]  ...                     Starting LBA followed by Number of Lba to erase.
+                                      a -1 to terminate the list.
+
+  @retval  EFI_SUCCESS             The erase request was successfully completed
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written. Firmware device may have been
+                                   partially erased.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  ...
+  )
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+  EFI_FW_VOL_INSTANCE      *FwhInstance;
+  UINTN                    NumOfBlocks;
+  VA_LIST                  args;
+  EFI_LBA                  StartingLba;
+  UINTN                    NumOfLba;
+  EFI_STATUS               Status;
+
+  FwhInstance = NULL;
+  FvbDevice   = FVB_DEVICE_FROM_THIS (This);
+
+  // Status    = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, EfiGoneVirtual ());
+  Status = GetFvbInstance (FvbDevice->Instance, mFvbModuleGlobal, &FwhInstance, FALSE);    // Hard coded to FALSE for SMM driver.
+  ASSERT_EFI_ERROR (Status);
+
+  NumOfBlocks = FwhInstance->NumOfBlocks;
+
+  VA_START (args, This);
+
+  do {
+    StartingLba = VA_ARG (args, EFI_LBA);
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      break;
+    }
+
+    NumOfLba = VA_ARG (args, UINTN);
+
+    //
+    // Check input parameters
+    //
+    if ((NumOfLba == 0) || ((StartingLba + NumOfLba) > NumOfBlocks)) {
+      VA_END (args);
+      return EFI_INVALID_PARAMETER;
+    }
+  } while (TRUE);
+
+  VA_END (args);
+
+  VA_START (args, This);
+  do {
+    StartingLba = VA_ARG (args, EFI_LBA);
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      break;
+    }
+
+    NumOfLba = VA_ARG (args, UINTN);
+
+    while (NumOfLba > 0) {
+      // Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, EfiGoneVirtual ());
+      Status = FvbEraseBlock (FvbDevice->Instance, StartingLba, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+      if (EFI_ERROR (Status)) {
+        VA_END (args);
+        return Status;
+      }
+
+      StartingLba++;
+      NumOfLba--;
+    }
+  } while (TRUE);
+
+  VA_END (args);
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Writes data beginning at Lba:Offset from FV. The write terminates either
+  when *NumBytes of data have been written, or when a block boundary is
+  reached.  *NumBytes is updated to reflect the actual number of bytes
+  written. The write opertion does not include erase. This routine will
+  attempt to write only the specified bytes. If the writes do not stick,
+  it will return an error.
+
+  @param[in]       This                   Calling context
+  @param[in]       Lba                    Block in which to begin write
+  @param[in]       Offset                 Offset in the block at which to begin write
+  @param[in, out]  NumBytes               On input, indicates the requested write size. On
+                                          output, indicates the actual number of bytes written
+  @param[in]       Buffer                 Buffer containing source data for the write.
+
+  @retval  EFI_SUCCESS            The firmware volume was written successfully
+  @retval  EFI_BAD_BUFFER_SIZE    Write attempted across a LBA boundary. On output,
+                                  NumBytes contains the total number of bytes
+                                  actually written
+  @retval  EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR       The block device is not functioning correctly and
+                                  could not be written
+  @retval  EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolWrite (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN       EFI_LBA                             Lba,
+  IN       UINTN                               Offset,
+  IN OUT   UINTN                               *NumBytes,
+  IN       UINT8                               *Buffer
+  )
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+  return FvbWriteBlock (FvbDevice->Instance, (EFI_LBA)Lba, (UINTN)Offset, NumBytes, (UINT8 *)Buffer, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+}
+
+/**
+  Reads data beginning at Lba:Offset from FV. The Read terminates either
+  when *NumBytes of data have been read, or when a block boundary is
+  reached.  *NumBytes is updated to reflect the actual number of bytes
+  written. The write opertion does not include erase. This routine will
+  attempt to write only the specified bytes. If the writes do not stick,
+  it will return an error.
+
+  @param[in]   This       Calling context
+  @param[in]   Lba        Block in which to begin Read
+  @param[in]   Offset     Offset in the block at which to begin Read
+  @param[out]  NumBytes   On input, indicates the requested write size. On
+                          output, indicates the actual number of bytes Read
+  @param[in]  Buffer      Buffer containing source data for the Read.
+
+  @retval  EFI_SUCCESS             The firmware volume was read successfully and
+                                   contents are in Buffer
+  @retval  EFI_BAD_BUFFER_SIZE     Read attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes returned
+                                   in Buffer
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the ReadDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be read
+  @retval  EFI_INVALID_PARAMETER   NumBytes or Buffer are NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolRead (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN CONST EFI_LBA                             Lba,
+  IN CONST UINTN                               Offset,
+  IN OUT UINTN                                 *NumBytes,
+  IN UINT8                                     *Buffer
+  )
+{
+  EFI_FW_VOL_BLOCK_DEVICE  *FvbDevice;
+
+  FvbDevice = FVB_DEVICE_FROM_THIS (This);
+
+  // return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, EfiGoneVirtual ());
+  return FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, Buffer, mFvbModuleGlobal, FALSE); // Hard coded to FALSE for SMM driver.
+}
+
+/**
+  Check the integrity of firmware volume header
+
+  @param[in]  FwVolHeader            A pointer to a firmware volume header
+
+  @retval  EFI_SUCCESS            The firmware volume is consistent
+  @retval  EFI_NOT_FOUND          The firmware volume has corrupted. So it is not an FV
+
+**/
+EFI_STATUS
+ValidateFvHeader (
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader
+  )
+{
+  //
+  // Verify the header revision, header signature, length
+  // Length of FvBlock cannot be 2**64-1
+  // HeaderLength cannot be an odd number
+  //
+  if ((FwVolHeader->Revision != EFI_FVH_REVISION) ||
+      (FwVolHeader->Signature != EFI_FVH_SIGNATURE) ||
+      (FwVolHeader->FvLength == ((UINTN)-1)) ||
+      ((FwVolHeader->HeaderLength & 0x01) != 0)
+      )
+  {
+    return EFI_NOT_FOUND;
+  }
+
+  //
+  // Verify the header checksum
+  //
+  if (CalculateCheckSum16 ((UINT16 *)FwVolHeader, FwVolHeader->HeaderLength) != 0) {
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+
+  This function does common initialization for FVB services
+
+  @param[in]  ImageHandle            A pointer to a image volume header
+  @param[in]  SystemTable            Pointer to the System Table
+
+  @retval  EFI_SUCCESS               initialization for FVB services successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  )
+{
+  EFI_STATUS                       Status;
+  EFI_FW_VOL_INSTANCE              *FwhInstance;
+  EFI_FIRMWARE_VOLUME_HEADER       *FwVolHeader;
+  EFI_DXE_SERVICES                 *DxeServices;
+  EFI_GCD_MEMORY_SPACE_DESCRIPTOR  Descriptor;
+  UINT32                           BufferSize;
+  EFI_FV_BLOCK_MAP_ENTRY           *PtrBlockMapEntry;
+  EFI_HANDLE                       FwbHandle;
+  EFI_FW_VOL_BLOCK_DEVICE          *FvbDevice;
+  UINT32                           MaxLbaSize;
+  EFI_PHYSICAL_ADDRESS             BaseAddress;
+  UINTN                            NumOfBlocks;
+  UINT32                           PlatformFvBaseAddress;
+
+  //
+  // Get the DXE services table
+  //
+  DxeServices = gDS;
+
+  //
+  // Allocate runtime services data for global variable, which contains
+  // the private data of all firmware volume block instances
+  //
+  mFvbModuleGlobal = AllocateRuntimePool (sizeof (ESAL_FWB_GLOBAL));
+  ASSERT (mFvbModuleGlobal);
+
+  Status = gSmst->SmmLocateProtocol (&gEfiSmmSpiProtocolGuid, NULL, (VOID **)&mFvbModuleGlobal->SpiProtocol);
+  ASSERT_EFI_ERROR (Status);
+
+  //
+  // Calculate the total size for all firmware volume block instances
+  //
+  BufferSize            = 0;
+  PlatformFvBaseAddress = PcdGet32 (PcdFlashNvStorageVariableBase);
+  FwVolHeader           = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PlatformFvBaseAddress;
+  BufferSize           += (FwVolHeader->HeaderLength +
+                           sizeof (EFI_FW_VOL_INSTANCE) -
+                           sizeof (EFI_FIRMWARE_VOLUME_HEADER)
+                           );
+
+  //
+  // Only need to allocate once. There is only one copy of physical memory for
+  // the private data of each FV instance. But in virtual mode or in physical
+  // mode, the address of the the physical memory may be different.
+  //
+  mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] = AllocateRuntimePool (BufferSize);
+  ASSERT (mFvbModuleGlobal->FvInstance[FVB_PHYSICAL] != NULL);
+
+  //
+  // Make a virtual copy of the FvInstance pointer.
+  //
+  FwhInstance                               = mFvbModuleGlobal->FvInstance[FVB_PHYSICAL];
+  mFvbModuleGlobal->FvInstance[FVB_VIRTUAL] = FwhInstance;
+
+  mFvbModuleGlobal->NumFv = 0;
+  MaxLbaSize              = 0;
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)PlatformFvBaseAddress;
+  BaseAddress = (UINTN)FwVolHeader;
+
+  //
+  // Check if it is a "real" flash
+  //
+  Status = DxeServices->GetMemorySpaceDescriptor (
+                          BaseAddress,
+                          &Descriptor
+                          );
+  if (EFI_ERROR (Status)) {
+    return EFI_SUCCESS;
+  }
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
+  Status      = ValidateFvHeader (FwVolHeader);
+  if (EFI_ERROR (Status)) {
+    //
+    // Get FvbInfo to provide in FwhInstance.
+    //
+    Status = GetFvbInfo (BaseAddress, &FwVolHeader);
+    //
+    //  Write healthy FV header back.
+    //
+    CopyMem (
+      (VOID *)(UINTN)BaseAddress,
+      (VOID *)FwVolHeader,
+      FwVolHeader->HeaderLength
+      );
+  }
+
+  FwhInstance->FvBase[FVB_PHYSICAL] = (UINTN)BaseAddress;
+  FwhInstance->FvBase[FVB_VIRTUAL]  = (UINTN)BaseAddress;
+
+  CopyMem ((UINTN *)&(FwhInstance->VolumeHeader), (UINTN *)FwVolHeader, FwVolHeader->HeaderLength);
+  FwVolHeader = &(FwhInstance->VolumeHeader);
+  EfiInitializeLock (&(FwhInstance->FvbDevLock), TPL_HIGH_LEVEL);
+
+  NumOfBlocks = 0;
+
+  for (PtrBlockMapEntry = FwVolHeader->BlockMap; PtrBlockMapEntry->NumBlocks != 0; PtrBlockMapEntry++) {
+    //
+    // Get the maximum size of a block.
+    //
+    if (MaxLbaSize < PtrBlockMapEntry->Length) {
+      MaxLbaSize = PtrBlockMapEntry->Length;
+    }
+
+    NumOfBlocks = NumOfBlocks + PtrBlockMapEntry->NumBlocks;
+  }
+
+  //
+  // The total number of blocks in the FV.
+  //
+  FwhInstance->NumOfBlocks = NumOfBlocks;
+
+  //
+  // Add a FVB Protocol Instance
+  //
+  FvbDevice = AllocateRuntimePool (sizeof (EFI_FW_VOL_BLOCK_DEVICE));
+  ASSERT (FvbDevice != NULL);
+
+  CopyMem (FvbDevice, &mFvbDeviceTemplate, sizeof (EFI_FW_VOL_BLOCK_DEVICE));
+
+  FvbDevice->Instance = mFvbModuleGlobal->NumFv;
+  mFvbModuleGlobal->NumFv++;
+
+  //
+  // Set up the devicepath
+  //
+  if (FwVolHeader->ExtHeaderOffset == 0) {
+    //
+    // FV does not contains extension header, then produce MEMMAP_DEVICE_PATH
+    //
+    FvbDevice->DevicePath                                                           = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &mFvMemmapDevicePathTemplate);
+    ((FV_MEMMAP_DEVICE_PATH *)FvbDevice->DevicePath)->MemMapDevPath.StartingAddress = BaseAddress;
+    ((FV_MEMMAP_DEVICE_PATH *)FvbDevice->DevicePath)->MemMapDevPath.EndingAddress   = BaseAddress + FwVolHeader->FvLength - 1;
+  } else {
+    FvbDevice->DevicePath = (EFI_DEVICE_PATH_PROTOCOL *)AllocateCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mFvPIWGDevicePathTemplate);
+    CopyGuid (
+      &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,
+      (GUID *)(UINTN)(BaseAddress + FwVolHeader->ExtHeaderOffset)
+      );
+  }
+
+  FwbHandle = NULL;
+  Status    = gSmst->SmmInstallProtocolInterface (
+                       &FwbHandle,
+                       &gEfiSmmFirmwareVolumeBlockProtocolGuid,
+                       EFI_NATIVE_INTERFACE,
+                       &FvbDevice->FwVolBlockInstance
+                       );
+  ASSERT_EFI_ERROR (Status);
+  FwhInstance = (EFI_FW_VOL_INSTANCE *)
+                (
+                 (UINTN)((UINT8 *)FwhInstance) + FwVolHeader->HeaderLength +
+                 (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUME_HEADER))
+                );
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Writes specified number of bytes from the input buffer to the address
+
+  @param[in]       WriteAddress      The FV address to be written to
+  @param[in]       Address           The FV address to be written to
+  @param[in, out]  NumBytes          Pointer that on input contains the total size of
+                                     the buffer. On output, it contains the total number
+                                     of bytes actually written
+  @param[in]       Buffer            Pointer to a caller allocated buffer that contains
+                                     the source for the write
+  @param[in]       LbaLength         contains the length of the Buffer.
+
+  @return The status returned from SpiProtocol().
+
+**/
+EFI_STATUS
+FlashFdWrite (
+  IN  UINTN     WriteAddress,
+  IN  UINTN     Address,
+  IN OUT UINTN  *NumBytes,
+  IN  UINT8     *Buffer,
+  IN  UINTN     LbaLength
+  )
+{
+  EFI_STATUS  Status;
+
+  Status = EFI_SUCCESS;
+
+  //
+  // TODO:  Suggested that this code be "critical section"
+  //
+  WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));
+  Status        = mFvbModuleGlobal->SpiProtocol->Execute (
+                                                   mFvbModuleGlobal->SpiProtocol,
+                                                   SPI_OPCODE_WRITE_INDEX, // OpcodeIndex
+                                                   0,                      // PrefixOpcodeIndex
+                                                   TRUE,                   // DataCycle
+                                                   TRUE,                   // Atomic
+                                                   TRUE,                   // ShiftOut
+                                                   WriteAddress,           // Address
+                                                   (UINT32)(*NumBytes),    // Data Number
+                                                   Buffer,
+                                                   EnumSpiRegionBios
+                                                   );
+
+  AsmWbinvd ();
+
+  return Status;
+}
+
+/**
+  Erase specified FV address
+
+  @param[in]       WriteAddress      The FV address to be written to
+  @param[in]       LbaLength         contains the length of the Buffer.
+
+  @return The status returned from SpiProtocol().
+
+**/
+EFI_STATUS
+FlashFdErase (
+  IN UINTN  WriteAddress,
+  IN UINTN  LbaLength
+  )
+{
+  EFI_STATUS    Status;
+  SPI_INSTANCE  *SpiInstance;
+
+  Status        = EFI_SUCCESS;
+  SpiInstance   = SPI_INSTANCE_FROM_SPIPROTOCOL (mFvbModuleGlobal->SpiProtocol);
+  WriteAddress -= (PcdGet32 (PcdFlashAreaBaseAddress));
+  while ((INTN)LbaLength > 0) {
+    if ((WriteAddress >= 0) && (WriteAddress + LbaLength <= SpiInstance->SpiInitTable.BiosSize)) {
+      Status = mFvbModuleGlobal->SpiProtocol->Execute (
+                                                mFvbModuleGlobal->SpiProtocol,
+                                                SPI_OPCODE_ERASE_INDEX, // OpcodeIndex
+                                                0,                      // PrefixOpcodeIndex
+                                                FALSE,                  // DataCycle
+                                                TRUE,                   // Atomic
+                                                TRUE,                   // ShiftOut
+                                                WriteAddress,           // Address
+                                                0,                      // Data Number
+                                                NULL,
+                                                EnumSpiRegionBios     // SPI_REGION_TYPE
+                                                );
+
+      if (Status != EFI_SUCCESS) {
+        return Status;
+      }
+    }
+
+    WriteAddress += SpiInstance->SpiInitTable.OpcodeMenu[SPI_OPCODE_ERASE_INDEX].Operation;
+    LbaLength    -= SpiInstance->SpiInitTable.OpcodeMenu[SPI_OPCODE_ERASE_INDEX].Operation;
+  }
+
+  AsmWbinvd ();
+
+  return Status;
+}
+
+#ifdef _MSC_VER
+  #pragma optimize( "", on )
+#endif
+#ifdef __GNUC__
+  #ifndef __clang__
+    #pragma GCC pop_options
+  #endif
+#endif
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.h b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.h
new file mode 100644
index 0000000000..a604f3be4b
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/FwBlockService.h
@@ -0,0 +1,515 @@
+/** @file
+  Implements FvbServicesSmm
+  Firmware volume block driver for SPI device
+
+  Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+  Copyright (c) 2013-2015 Intel Corporation. All rights reserved.<BR>
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FW_BLOCK_SERVICE_SMM_H_
+#define FW_BLOCK_SERVICE_SMM_H_
+
+//
+// The Library classes this module consumes
+//
+#include <Library/UefiLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+
+#include <Protocol/Spi.h>
+#include <Protocol/SpiCommon.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Pi/PiFirmwareVolume.h>
+
+#define FVB_PHYSICAL  0
+#define FVB_VIRTUAL   1
+
+typedef struct {
+  EFI_LOCK                      FvbDevLock;
+  UINTN                         FvBase[2];
+  UINTN                         NumOfBlocks;
+  EFI_FIRMWARE_VOLUME_HEADER    VolumeHeader;
+} EFI_FW_VOL_INSTANCE;
+
+typedef struct {
+  UINT32                 NumFv;
+  EFI_FW_VOL_INSTANCE    *FvInstance[2];
+  UINT8                  *FvbScratchSpace[2];
+  EFI_SPI_PROTOCOL       *SpiProtocol;
+} ESAL_FWB_GLOBAL;
+
+//
+// Fvb Protocol instance data
+//
+#define FVB_DEVICE_FROM_THIS(a)         CR (a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockInstance, FVB_DEVICE_SIGNATURE)
+#define FVB_EXTEND_DEVICE_FROM_THIS(a)  CR (a, EFI_FW_VOL_BLOCK_DEVICE, FvbExtension, FVB_DEVICE_SIGNATURE)
+#define FVB_DEVICE_SIGNATURE  SIGNATURE_32 ('F', 'V', 'B', 'N')
+
+typedef struct {
+  MEDIA_FW_VOL_DEVICE_PATH    FvDevPath;
+  EFI_DEVICE_PATH_PROTOCOL    EndDevPath;
+} FV_PIWG_DEVICE_PATH;
+
+typedef struct {
+  MEMMAP_DEVICE_PATH          MemMapDevPath;
+  EFI_DEVICE_PATH_PROTOCOL    EndDevPath;
+} FV_MEMMAP_DEVICE_PATH;
+
+typedef struct {
+  UINTN                                 Signature;
+  EFI_DEVICE_PATH_PROTOCOL              *DevicePath;
+  UINTN                                 Instance;
+  EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL    FwVolBlockInstance;
+} EFI_FW_VOL_BLOCK_DEVICE;
+
+/**
+  Get Fvb information.
+
+  @param[in] BaseAddress    The base address compare with NvStorageVariable base address.
+  @param[out] FvbInfo        Fvb information.
+
+  @retval EFI_SUCCESS       Get Fvb information successfully.
+  @retval EFI_NOT_FOUND     Not find Fvb information.
+
+**/
+EFI_STATUS
+GetFvbInfo (
+  IN  UINT64                      FvLength,
+  OUT EFI_FIRMWARE_VOLUME_HEADER  **FvbInfo
+  );
+
+/**
+  Reads specified number of bytes into a buffer from the specified block
+
+  @param[in]       Instance      The FV instance to be read from
+  @param[in]       Lba           The logical block address to be read from
+  @param[in]       BlockOffset   Offset into the block at which to begin reading
+  @param[in, out]  NumBytes      Pointer that on input contains the total size of
+                                 the buffer. On output, it contains the total number
+                                 of bytes read
+  @param[in]       Buffer        Pointer to a caller allocated buffer that will be
+                                 used to hold the data read
+  @param[in]       Global        Pointer to ESAL_FWB_GLOBAL that contains all
+                                 instance data
+  @param[in]       Virtual       Whether CPU is in virtual or physical mode
+
+  @retval   EFI_SUCCESS            The firmware volume was read successfully and
+                                   contents are in Buffer
+  @retval   EFI_BAD_BUFFER_SIZE    Read attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes returned
+                                   in Buffer
+  @retval   EFI_ACCESS_DENIED      The firmware volume is in the ReadDisabled state
+  @retval   EFI_DEVICE_ERROR       The block device is not functioning correctly and
+                                   could not be read
+  @retval   EFI_INVALID_PARAMETER  Instance not found, or NumBytes, Buffer are NULL
+
+**/
+EFI_STATUS
+FvbReadBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN UINTN            BlockOffset,
+  IN OUT UINTN        *NumBytes,
+  IN UINT8            *Buffer,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  );
+
+/**
+  Writes specified number of bytes from the input buffer to the block
+
+  @param[in]       Instance      The FV instance to be written to
+  @param[in]       Lba           The starting logical block index to write to
+  @param[in]       BlockOffset   Offset into the block at which to begin writing
+  @param[in, out]  NumBytes      Pointer that on input contains the total size of
+                                 the buffer. On output, it contains the total number
+                                 of bytes actually written
+  @param[in]       Buffer        Pointer to a caller allocated buffer that contains
+                                 the source for the write
+  @param[in]       Global        Pointer to ESAL_FWB_GLOBAL that contains all
+                                 instance data
+  @param[in]       Virtual       Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             The firmware volume was written successfully
+  @retval  EFI_BAD_BUFFER_SIZE     Write attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes
+                                   actually written
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written
+  @retval  EFI_INVALID_PARAMETER   Instance not found, or NumBytes, Buffer are NULL
+
+**/
+EFI_STATUS
+FvbWriteBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN UINTN            BlockOffset,
+  IN OUT UINTN        *NumBytes,
+  IN UINT8            *Buffer,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  );
+
+/**
+  Erases and initializes a firmware volume block
+
+  @param[in]  Instance    The FV instance to be erased
+  @param[in]  Lba         The logical block index to be erased
+  @param[in]  Global      Pointer to ESAL_FWB_GLOBAL that contains all
+                          instance data
+  @param[in]  Virtual     Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             The erase request was successfully completed
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written. Firmware device may have been
+                                   partially erased
+  @retval  EFI_INVALID_PARAMETER   Instance not found
+
+**/
+EFI_STATUS
+FvbEraseBlock (
+  IN UINTN            Instance,
+  IN EFI_LBA          Lba,
+  IN ESAL_FWB_GLOBAL  *Global,
+  IN BOOLEAN          Virtual
+  );
+
+/**
+  Modifies the current settings of the firmware volume according to the
+  input parameter, and returns the new setting of the volume
+
+  @param[in]       Instance          The FV instance whose attributes is going to be
+                                     modified
+  @param[in, out]  Attributes        On input, it is a pointer to EFI_FVB_ATTRIBUTES_2
+                                     containing the desired firmware volume settings.
+                                     On successful return, it contains the new settings
+                                     of the firmware volume
+  @param[in]       Global            Pointer to ESAL_FWB_GLOBAL that contains all
+                                     instance data
+  @param[in]       Virtual           Whether CPU is in virtual or physical mode
+
+  @retval  EFI_SUCCESS             Successfully returns
+  @retval  EFI_ACCESS_DENIED       The volume setting is locked and cannot be modified
+  @retval  EFI_INVALID_PARAMETER   Instance not found, or The attributes requested are
+                                   in conflict with the capabilities as declared in the
+                                   firmware volume header
+
+**/
+EFI_STATUS
+FvbSetVolumeAttributes (
+  IN UINTN                     Instance,
+  IN OUT EFI_FVB_ATTRIBUTES_2  *Attributes,
+  IN ESAL_FWB_GLOBAL           *Global,
+  IN BOOLEAN                   Virtual
+  );
+
+/**
+  Retrieves attributes, insures positive polarity of attribute bits, returns
+  resulting attributes in output parameter
+
+  @param[in]  Instance   The FV instance whose attributes is going to be
+                         returned
+  @param[out] Attributes Output buffer which contains attributes
+  @param[in]  Global     Pointer to ESAL_FWB_GLOBAL that contains all
+                         instance data
+  @param[in]  Virtual    Whether CPU is in virtual or physical mode
+
+  @retval    EFI_SUCCESS            Successfully returns
+  @retval    EFI_INVALID_PARAMETER  Instance not found
+
+**/
+EFI_STATUS
+FvbGetVolumeAttributes (
+  IN UINTN                  Instance,
+  OUT EFI_FVB_ATTRIBUTES_2  *Attributes,
+  IN ESAL_FWB_GLOBAL        *Global,
+  IN BOOLEAN                Virtual
+  );
+
+/**
+  Retrieves the physical address of the device.
+
+  @param[in]   This        Calling context
+  @param[out]  Address     Output buffer containing the address.
+
+  @retval EFI_SUCCESS  Successfully returns
+
+**/
+EFI_STATUS
+FvbGetPhysicalAddress (
+  IN UINTN                  Instance,
+  OUT EFI_PHYSICAL_ADDRESS  *Address,
+  IN ESAL_FWB_GLOBAL        *Global,
+  IN BOOLEAN                Virtual
+  );
+
+/**
+
+  This function does common initialization for FVB services
+
+  @param[in]  ImageHandle            A pointer to a image volume header
+  @param[in]  SystemTable            Pointer to the System Table
+
+  @retval  EFI_SUCCESS               initialization for FVB services successfully
+
+**/
+EFI_STATUS
+EFIAPI
+FvbInitialize (
+  IN EFI_HANDLE        ImageHandle,
+  IN EFI_SYSTEM_TABLE  *SystemTable
+  );
+
+/**
+  Retrieves the starting address of an LBA in an FV
+
+  @param[in]   Instance               The FV instance which the Lba belongs to
+  @param[in]   Lba                    The logical block address
+  @param[out]  LbaAddress             On output, contains the physical starting address
+                                      of the Lba
+  @param[out]  LbaLength              On output, contains the length of the block
+  @param[out]  NumOfBlocks            A pointer to a caller allocated UINTN in which the
+                                      number of consecutive blocks starting with Lba is
+                                      returned. All blocks in this range have a size of
+                                      BlockSize
+  @param[in]  Global                  Pointer to ESAL_FWB_GLOBAL that contains all
+                                      instance data
+  @param[in]  Virtual                 Whether CPU is in virtual or physical mode
+  @retval  EFI_SUCCESS             Successfully returns
+  @retval  EFI_INVALID_PARAMETER   Instance not found
+
+**/
+EFI_STATUS
+FvbGetLbaAddress (
+  IN  UINTN            Instance,
+  IN  EFI_LBA          Lba,
+  OUT UINTN            *LbaAddress,
+  OUT UINTN            *LbaLength,
+  OUT UINTN            *NumOfBlocks,
+  IN  ESAL_FWB_GLOBAL  *Global,
+  IN  BOOLEAN          Virtual
+  );
+
+/**
+  Retrieves Volume attributes.  No polarity translations are done.
+
+  @param[in]     This                 Calling context
+  @param[out]    Attributes           Output buffer which contains attributes
+
+  @retval  EFI_SUCCESS            Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  OUT EFI_FVB_ATTRIBUTES_2                     *Attributes
+  );
+
+/**
+  Sets Volume attributes. No polarity translations are done.
+
+  @param[in]   This                   Calling context
+  @param[out]  Attributes             output buffer which contains attributes
+
+  @retval  EFI_SUCCESS                Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolSetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN OUT EFI_FVB_ATTRIBUTES_2                  *Attributes
+  );
+
+/**
+  Retrieves the physical address of the device.
+
+  @param[in]   This        Calling context
+  @param[out]  Address     Output buffer containing the address.
+
+  @retval EFI_SUCCESS  Successfully returns
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetPhysicalAddress (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  OUT EFI_PHYSICAL_ADDRESS                     *Address
+  );
+
+/**
+  Retrieve the size of a logical block
+
+  @param[in]   This           alling context
+  @param[in]   Lba            Indicates which block to return the size for.
+  @param[out]  BlockSize      A pointer to a caller allocated UINTN in which
+                              the size of the block is returned
+  @param[out]  NumOfBlocks    a pointer to a caller allocated UINTN in which the
+                              number of consecutive blocks starting with Lba is
+                              returned. All blocks in this range have a size of
+                              BlockSize
+
+  @retval  EFI_SUCCESS        The firmware volume was read successfully and
+                              contents are in Buffer
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolGetBlockSize (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN CONST EFI_LBA                             Lba,
+  OUT UINTN                                    *BlockSize,
+  OUT UINTN                                    *NumOfBlocks
+  );
+
+/**
+  Reads data beginning at Lba:Offset from FV. The Read terminates either
+  when *NumBytes of data have been read, or when a block boundary is
+  reached.  *NumBytes is updated to reflect the actual number of bytes
+  written. The write opertion does not include erase. This routine will
+  attempt to write only the specified bytes. If the writes do not stick,
+  it will return an error.
+
+  @param[in]   This       Calling context
+  @param[in]   Lba        Block in which to begin Read
+  @param[in]   Offset     Offset in the block at which to begin Read
+  @param[out]  NumBytes   On input, indicates the requested write size. On
+                          output, indicates the actual number of bytes Read
+  @param[in]  Buffer      Buffer containing source data for the Read.
+
+  @retval  EFI_SUCCESS             The firmware volume was read successfully and
+                                   contents are in Buffer
+  @retval  EFI_BAD_BUFFER_SIZE     Read attempted across a LBA boundary. On output,
+                                   NumBytes contains the total number of bytes returned
+                                   in Buffer
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the ReadDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be read
+  @retval  EFI_INVALID_PARAMETER   NumBytes or Buffer are NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolRead (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN CONST EFI_LBA                             Lba,
+  IN CONST UINTN                               Offset,
+  IN OUT UINTN                                 *NumBytes,
+  IN UINT8                                     *Buffer
+  );
+
+/**
+  Writes data beginning at Lba:Offset from FV. The write terminates either
+  when *NumBytes of data have been written, or when a block boundary is
+  reached.  *NumBytes is updated to reflect the actual number of bytes
+  written. The write opertion does not include erase. This routine will
+  attempt to write only the specified bytes. If the writes do not stick,
+  it will return an error.
+
+  @param[in]       This                   Calling context
+  @param[in]       Lba                    Block in which to begin write
+  @param[in]       Offset                 Offset in the block at which to begin write
+  @param[in, out]  NumBytes               On input, indicates the requested write size. On
+                                          output, indicates the actual number of bytes written
+  @param[in]       Buffer                 Buffer containing source data for the write.
+
+  @retval  EFI_SUCCESS            The firmware volume was written successfully
+  @retval  EFI_BAD_BUFFER_SIZE    Write attempted across a LBA boundary. On output,
+                                  NumBytes contains the total number of bytes
+                                  actually written
+  @retval  EFI_ACCESS_DENIED      The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR       The block device is not functioning correctly and
+                                  could not be written
+  @retval  EFI_INVALID_PARAMETER  NumBytes or Buffer are NULL
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolWrite (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  IN       EFI_LBA                             Lba,
+  IN       UINTN                               Offset,
+  IN OUT   UINTN                               *NumBytes,
+  IN       UINT8                               *Buffer
+  );
+
+/**
+  The EraseBlock() function erases one or more blocks as denoted by the
+  variable argument list. The entire parameter list of blocks must be verified
+  prior to erasing any blocks.  If a block is requested that does not exist
+  within the associated firmware volume (it has a larger index than the last
+  block of the firmware volume), the EraseBlock() function must return
+  EFI_INVALID_PARAMETER without modifying the contents of the firmware volume.
+
+  @param[in]  This                    Calling context
+  @param[in]  ...                     Starting LBA followed by Number of Lba to erase.
+                                      a -1 to terminate the list.
+
+  @retval  EFI_SUCCESS             The erase request was successfully completed
+  @retval  EFI_ACCESS_DENIED       The firmware volume is in the WriteDisabled state
+  @retval  EFI_DEVICE_ERROR        The block device is not functioning correctly and
+                                   could not be written. Firmware device may have been
+                                   partially erased.
+
+**/
+EFI_STATUS
+EFIAPI
+FvbProtocolEraseBlocks (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL  *This,
+  ...
+  );
+
+/**
+  Writes specified number of bytes from the input buffer to the address
+
+  @param[in]       WriteAddress      The FV address to be written to
+  @param[in]       Address           The FV address to be written to
+  @param[in, out]  NumBytes          Pointer that on input contains the total size of
+                                     the buffer. On output, it contains the total number
+                                     of bytes actually written
+  @param[in]       Buffer            Pointer to a caller allocated buffer that contains
+                                     the source for the write
+  @param[in]       LbaLength         contains the length of the Buffer.
+
+  @return The status returned from SpiProtocol().
+
+**/
+EFI_STATUS
+FlashFdWrite (
+  IN  UINTN     WriteAddress,
+  IN  UINTN     Address,
+  IN OUT UINTN  *NumBytes,
+  IN  UINT8     *Buffer,
+  IN  UINTN     LbaLength
+  );
+
+/**
+  Erase specified FV address
+
+  @param[in]       WriteAddress      The FV address to be written to
+  @param[in]       LbaLength         contains the length of the Buffer.
+
+  @return The status returned from SpiProtocol().
+
+**/
+EFI_STATUS
+FlashFdErase (
+  IN UINTN  WriteAddress,
+  IN UINTN  LbaLength
+  );
+
+#endif
diff --git a/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/PlatformSmmSpi.inf b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/PlatformSmmSpi.inf
new file mode 100644
index 0000000000..0a620662d2
--- /dev/null
+++ b/Platform/AMD/VanGoghBoard/VanGoghCommonPkg/FvbServices/PlatformSmmSpi.inf
@@ -0,0 +1,68 @@
+## @file
+#  FvbServicesSmm
+#  Component description file for SpiFvbServices Module
+#
+# Copyright (C) 2024 Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2013-2015 Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x00010005
+  BASE_NAME                      = FvbServicesSmm
+  FILE_GUID                      = 72A87810-D3A3-36BE-4788-49AA4003DFD3
+  MODULE_TYPE                    = DXE_SMM_DRIVER
+  VERSION_STRING                 = 1.0
+  PI_SPECIFICATION_VERSION       = 0x0001000A
+  ENTRY_POINT                    = FvbInitialize
+
+[Sources]
+  FwBlockService.c
+  FwBlockService.h
+  FvbInfo.c
+
+[Packages]
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  VanGoghCommonPkg/AmdCommonPkg.dec
+  ChachaniBoardPkg/Project.dec
+
+[LibraryClasses]
+  UefiLib
+  UefiDriverEntryPoint
+  BaseLib
+  DebugLib
+  BaseMemoryLib
+  MemoryAllocationLib
+  DxeServicesTableLib
+  UefiBootServicesTableLib
+  SmmServicesTableLib
+  DevicePathLib
+  HobLib
+  PcdLib
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid             # ALWAYS_CONSUMED  Create Event: EVENT_GROUP_GUID
+  gEfiSystemNvDataFvGuid
+
+[Protocols]
+  gEfiSmmFirmwareVolumeBlockProtocolGuid
+  gEfiSmmSpiProtocolGuid
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gPlatformPkgTokenSpaceGuid.PcdFlashAreaSize
+  gPlatformPkgTokenSpaceGuid.PcdFlashAreaBaseAddress
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase
+
+
+[Depex]
+  gEfiSmmBase2ProtocolGuid AND
+  gEfiSmmSpiProtocolGuid
--
2.31.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#114504): https://edk2.groups.io/g/devel/message/114504
Mute This Topic: https://groups.io/mt/103971401/7686176
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [rebecca@openfw.io]
-=-=-=-=-=-=-=-=-=-=-=-



  parent reply	other threads:[~2024-01-26  6:02 UTC|newest]

Thread overview: 39+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-26  6:00 [edk2-devel] [PATCH V2 00/32] Introduce AMD Vangogh platform reference code Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 01/32] AMD/AmdPlatformPkg: Check in AMD S3 logo Zhai, MingXin (Duke) via groups.io
2024-01-26  9:19   ` Chang, Abner via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 02/32] AMD/VanGoghBoard: Check in ACPI tables Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 03/32] AMD/VanGoghBoard: Check in Capsule update Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 04/32] AMD/VanGoghBoard: Check in AgesaPublic pkg Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 05/32]AMD/VanGoghBoard: Check in PlatformSecLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 06/32] AMD/VanGoghBoard: Check in AmdIdsExtLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 07/32] AMD/VanGoghBoard: Check in PciPlatform Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 08/32] AMD/VanGoghBoard: Check in UDKFlashUpdate Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 09/32] AMD/VanGoghBoard: Check in Flash_AB Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 10/32] AMD/VanGoghBoard: Check in FlashUpdate Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` Zhai, MingXin (Duke) via groups.io [this message]
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 12/32] AMD/VanGoghBoard: Check in AMD BaseSerialPortLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 13/32] AMD/VanGoghBoard: Check in PlatformFlashAccessLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 14/32] AMD/VanGoghBoard: Check in SmbiosLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 15/32] AMD/VanGoghBoard: Check in SpiFlashDeviceLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 16/32] AMD/VanGoghBoard: Check in BaseTscTimerLib Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 17/32] AMD/VanGoghBoard: Check in Smm access module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 18/32] AMD/VanGoghBoard: Check in PciHostBridge module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 19/32] AMD/VanGoghBoard: Check in PcatRealTimeClockRuntimeDxe module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 20/32] AMD/VanGoghBoard: Check in FTPM module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 21/32] AMD/VanGoghBoard: Check in SignedCapsule Zhai, MingXin (Duke) via groups.io
2024-01-26  9:28   ` Chang, Abner via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 22/32] AMD/VanGoghBoard: Check in Vtf0 Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 23/32] AMD/VanGoghBoard: Check in AcpiPlatform Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 24/32] AMD/VanGoghBoard: Check in FchSpi module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 25/32] AMD/VanGoghBoard: Check in PlatformInitPei module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 26/32] AMD/VanGoghBoard: Check in Smbios platform dxe drivers Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 27/32] AMD/VanGoghBoard: Check in Fsp2WrapperPkg Zhai, MingXin (Duke) via groups.io
2024-01-26  9:34   ` Chang, Abner via groups.io
2024-01-26  9:36     ` Chang, Abner via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 28/32] AMD/VanGoghBoard: Check in SmmCpuFeaturesLibCommon module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 29/32] AMD/VanGoghBoard: Check in SmramSaveState module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 30/32] AMD/VanGoghBoard: Check in EDK2 override files Zhai, MingXin (Duke) via groups.io
2024-01-26  9:37   ` Chang, Abner via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 31/32] AMD/VanGoghBoard: Check in AMD SmmControlPei module Zhai, MingXin (Duke) via groups.io
2024-01-26  6:00 ` [edk2-devel] [PATCH V2 32/32] AMD/VanGoghBoard: Check in Chachani board project files and build script Zhai, MingXin (Duke) via groups.io
2024-01-26  9:48 ` [edk2-devel] [PATCH V2 00/32] Introduce AMD Vangogh platform reference code Chang, Abner via groups.io

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-list from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20240126060050.1725-12-duke.zhai@amd.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox