[edk2-devel] [PATCH v1 09/10] Silicon/Phytium: Added fvb driver for norflash

Ling Jia jialing at phytium.com.cn
Fri Jan 15 08:48:01 UTC 2021


From: Ling <jialing at phytium.com.cn>

The PhytiumFlashFvbDxe provided the fvb protocol,
which requested by the flah operators.

Cc: Leif Lindholm <leif at nuviainc.com>
Signed-off-by: Ling Jia <jialing at phytium.com.cn>
Signed-off-by: Peng Xie <xiepeng at phytium.com.cn>
Reviewed-by: Yiqi Shu <shuyiqi at phytium.com.cn>
---
 Platform/Phytium/Durian/DurianPkg.dsc                                   |    1 +
 Platform/Phytium/Durian/DurianPkg.fdf                                   |    1 +
 Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf |   72 ++
 Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.h   |  106 ++
 Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.c   | 1235 ++++++++++++++++++++
 5 files changed, 1415 insertions(+)

diff --git a/Platform/Phytium/Durian/DurianPkg.dsc b/Platform/Phytium/Durian/DurianPkg.dsc
index d34432e95049..df43c3d5d23a 100644
--- a/Platform/Phytium/Durian/DurianPkg.dsc
+++ b/Platform/Phytium/Durian/DurianPkg.dsc
@@ -265,6 +265,7 @@ [Components.common]
   # NOR Flash driver
   #
   Silicon/Phytium/CommonDrivers/PhytiumSpiNorFlashDxe/PhytiumSpiNorFlashDxe.inf
+  Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf
 
   #
   # Usb Support
diff --git a/Platform/Phytium/Durian/DurianPkg.fdf b/Platform/Phytium/Durian/DurianPkg.fdf
index 703537033944..1a1dde1c64f6 100644
--- a/Platform/Phytium/Durian/DurianPkg.fdf
+++ b/Platform/Phytium/Durian/DurianPkg.fdf
@@ -102,6 +102,7 @@ [FV.FvMain]
 
   INF ArmPkg/Drivers/ArmGic/ArmGicDxe.inf
   INF ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+  INF Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf
   INF ArmPkg/Drivers/TimerDxe/TimerDxe.inf
   INF ArmPkg/Drivers/GenericWatchdogDxe/GenericWatchdogDxe.inf
 
diff --git a/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf
new file mode 100644
index 000000000000..3d177dd92c7e
--- /dev/null
+++ b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.inf
@@ -0,0 +1,72 @@
+#/** @file
+#  Phytium NorFlash Fvb Drivers.
+#
+#  Copyright (C) 2020, Phytium Technology Co,Ltd. All rights reserved.<BR>
+#
+#  SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+  INF_VERSION                    = 0x00010019
+  BASE_NAME                      = PhytiumFlashFvbDxe
+  FILE_GUID                      = b8923820-3e7c-11eb-b12c-17525e90ecc8
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  ENTRY_POINT                    = PhytiumFvbEntryPoint
+
+[Sources]
+  PhytiumFlashFvbDxe.c
+  PhytiumFlashFvbDxe.h
+
+[Packages]
+  EmbeddedPkg/EmbeddedPkg.dec
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  Silicon/Phytium/Phytium.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DevicePathLib
+  MemoryAllocationLib
+  UefiRuntimeServicesTableLib
+  IoLib
+  BaseLib
+  DebugLib
+  HobLib
+  UefiLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  UefiRuntimeLib
+  DxeServicesTableLib
+  PcdLib
+
+[Guids]
+  gEfiSystemNvDataFvGuid
+  gEfiVariableGuid
+  gEfiEventVirtualAddressChangeGuid
+  gEfiAuthenticatedVariableGuid
+
+[Protocols]
+  gEfiDevicePathProtocolGuid
+  gEfiFirmwareVolumeBlockProtocolGuid
+  gPhytiumFlashProtocolGuid
+
+[Pcd.common]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+  gArmPlatformTokenSpaceGuid.PcdNorFlashCheckBlockLocked
+  gPhytiumPlatformTokenSpaceGuid.PcdSpiFlashBase
+  gPhytiumPlatformTokenSpaceGuid.PcdSpiFlashSize
+
+[Depex]
+  #TRUE
+  gPhytiumFlashProtocolGuid
+  #gEfiCpuArchProtocolGuid AND
+  #gPhytiumSpiMasterProtocolGuid AND
+  #gPhytiumFlashProtocolGuid
diff --git a/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.h b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.h
new file mode 100644
index 000000000000..6d7fe18e0137
--- /dev/null
+++ b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.h
@@ -0,0 +1,106 @@
+/** @file
+  Phytium NorFlash Fvb Drivers Header.
+
+  Copyright (C) 2020, Phytium Technology Co Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#ifndef __FVB_FLASH_DXE_H__
+#define __FVB_FLASH_DXE_H__
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/PhytiumSpiNorFlash.h>
+
+#define GET_DATA_OFFSET(BaseAddr, Lba, LbaSize) ((BaseAddr) + (UINTN)((Lba) * (LbaSize)))
+#define FVB_FLASH_SIGNATURE                       SIGNATURE_32('S', 'n', 'o', 'r')
+#define INSTANCE_FROM_FVB_THIS(a)                 CR(a, FT_FVB_DEVICE, FvbProtocol, FVB_FLASH_SIGNATURE)
+
+typedef struct _FT_FVB_DEVICE    FT_FVB_DEVICE;
+
+#define NOR_FLASH_ERASE_RETRY         10
+
+typedef struct {
+  VENDOR_DEVICE_PATH                  Vendor;
+  EFI_DEVICE_PATH_PROTOCOL            End;
+  } FT_FVB_DEVICE_PATH;
+
+struct _FT_FVB_DEVICE {
+  UINT32                              Signature;
+  EFI_HANDLE                          Handle;
+
+  UINTN                               DeviceBaseAddress;
+  UINTN                               RegionBaseAddress;
+  UINTN                               Size;
+  EFI_LBA                             StartLba;
+  EFI_BLOCK_IO_MEDIA                  Media;
+
+  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL FvbProtocol;
+
+  FT_FVB_DEVICE_PATH                  DevicePath;
+  EFI_NORFLASH_DRV_PROTOCOL          *SpiFlashProtocol;
+  VOID                               *ShadowBuffer;
+  UINTN                               FvbSize;
+  };
+
+extern CONST EFI_GUID* CONST          NorFlashVariableGuid;
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetAttributes(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    OUT       EFI_FVB_ATTRIBUTES_2*                    Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbSetAttributes(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    IN OUT    EFI_FVB_ATTRIBUTES_2*                    Attributes
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetPhysicalAddress(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    OUT       EFI_PHYSICAL_ADDRESS*                    Address
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetBlockSize(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    IN        EFI_LBA                                  Lba,
+    OUT       UINTN*                                   BlockSize,
+    OUT       UINTN*                                   NumberOfBlocks
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbRead(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    IN        EFI_LBA                                  Lba,
+    IN        UINTN                                   Offset,
+    IN OUT    UINTN*                                   NumBytes,
+    IN OUT    UINT8*                                   Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbWrite(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    IN        EFI_LBA                                  Lba,
+    IN        UINTN                                    Offset,
+    IN OUT    UINTN*                                   NumBytes,
+    IN        UINT8*                                   Buffer
+  );
+
+EFI_STATUS
+EFIAPI
+PhytiumFvbEraseBlocks(
+    IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL*     This,
+    ...
+  );
+
+#endif /* __FVB_FLASH_DXE_H__ */
diff --git a/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.c b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.c
new file mode 100644
index 000000000000..a2ac7abe09ad
--- /dev/null
+++ b/Silicon/Phytium/CommonDrivers/PhytiumFlashFvbDxe/PhytiumFlashFvbDxe.c
@@ -0,0 +1,1235 @@
+/** @file
+  Phytium NorFlash Fvb Drivers.
+
+  Copyright (c) 2011 - 2014, ARM Ltd. All rights reserved.<BR>
+  Copyright (C) 2020, Phytium Technology Co Ltd. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiRuntimeLib.h>
+
+#include <Guid/NvVarStoreFormatted.h>
+#include <Guid/SystemNvDataGuid.h>
+#include <Guid/VariableFormat.h>
+
+#include "PhytiumFlashFvbDxe.h"
+
+STATIC EFI_EVENT     FvbVirtualAddrChangeEvent;
+STATIC FT_FVB_DEVICE    *PhytiumFvbDevice;
+STATIC UINTN     mFlashNvStorageVariableBase;
+CONST EFI_GUID* CONST NorFlashVariableGuid = &gEfiAuthenticatedVariableGuid;
+
+STATIC CONST FT_FVB_DEVICE PhytiumFvbFlashInstanceTemplate = {
+  FVB_FLASH_SIGNATURE, // Signature
+  NULL,                // Handle ... NEED TO BE FILLED
+  0,                   // DeviceBaseAddress ... NEED TO BE FILLED
+  0,                   // RegionBaseAddress ... NEED TO BE FILLED
+  0,                   // Size ... NEED TO BE FILLED
+  0,                   // StartLba
+  {
+    0,                 // MediaId ... NEED TO BE FILLED
+    FALSE,             // RemovableMedia
+    TRUE,              // MediaPresent
+    FALSE,             // LogicalPartition
+    FALSE,             // ReadOnly
+    FALSE,             // WriteCaching;
+    0,                 // BlockSize ... NEED TO BE FILLED
+    4,                 // IoAlign
+    0,                 // LastBlock ... NEED TO BE FILLED
+    0,                 // LowestAlignedLba
+    1,                 // LogicalBlocksPerPhysicalBlock
+  },                   //Media;
+  {
+    PhytiumFvbGetAttributes, // GetAttributes
+    PhytiumFvbSetAttributes, // SetAttributes
+    PhytiumFvbGetPhysicalAddress,  // GetPhysicalAddress
+    PhytiumFvbGetBlockSize,  // GetBlockSize
+    PhytiumFvbRead,          // Read
+    PhytiumFvbWrite,         // Write
+    PhytiumFvbEraseBlocks,   // EraseBlocks
+    NULL,                 // ParentHandle
+  },                      // FvbProtoccol;
+
+  {
+    {
+      {
+        HARDWARE_DEVICE_PATH,
+        HW_VENDOR_DP,
+        { (UINT8)sizeof(VENDOR_DEVICE_PATH), (UINT8)((sizeof(VENDOR_DEVICE_PATH)) >> 8) }
+      },
+      { 0x0, 0x0, 0x0, { 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0 } }, // GUID ... NEED TO BE FILLED
+    },
+    {
+      END_DEVICE_PATH_TYPE,
+      END_ENTIRE_DEVICE_PATH_SUBTYPE,
+      { sizeof (EFI_DEVICE_PATH_PROTOCOL), 0 }
+    }
+  },     // DevicePath
+
+  NULL,  // SpiFlashProtocol ... NEED TO BE FILLED
+  NULL,  // ShadowBuffer     ... NEED TO BE FILLED
+  0,  // Fvb Size
+};
+
+
+/**
+  Erases a single block of flash.
+
+  @param[in] FlashInstance      The poiter of the fvb device sturct.
+
+  @param[in] BlockAddress       Physical address of Lba to be erased.
+
+  @retval EFI_SUCCESS           The erase single block request successfully completed.
+
+**/
+STATIC
+EFI_STATUS
+FvbFlashEraseSingleBlock (
+  IN FT_FVB_DEVICE     *FlashInstance,
+  IN UINTN             BlockAddress
+  )
+{
+  EFI_STATUS      Status;
+  UINTN           Index;
+  EFI_TPL         OriginalTPL;
+
+  if (!EfiAtRuntime ()) {
+    // Raise TPL to TPL_HIGH to stop anyone from interrupting us.
+    OriginalTPL = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+  } else {
+    // This initialization is only to prevent the compiler to complain about the
+    // use of uninitialized variables
+    OriginalTPL = TPL_HIGH_LEVEL;
+  }
+
+  Index = 0;
+  // The block erase might fail a first time (SW bug ?). Retry it ...
+  do {
+    Status = FlashInstance->SpiFlashProtocol->EraseSingleBlock(BlockAddress);
+    Index++;
+  } while ((Index < NOR_FLASH_ERASE_RETRY) && (Status == EFI_WRITE_PROTECTED));
+
+  if (Index == NOR_FLASH_ERASE_RETRY) {
+    DEBUG((DEBUG_ERROR, "EraseSingleBlock(BlockAddress=0x%08x: Block Locked Error (try to erase %d times)\n", BlockAddress,Index));
+  }
+
+  if (!EfiAtRuntime ()) {
+    // Interruptions can resume.
+    gBS->RestoreTPL (OriginalTPL);
+  }
+
+  return Status;
+}
+
+
+/**
+  Readed the specified number of bytes from the form the block to output buffer.
+
+  @param[in]  FlashInstance        The pointer of FT_FVB_DEVICE instance.
+
+  @param[in]  Lba                  The starting logical block index to write to.
+
+  @param[in]  Offset               Offset into the block at which to begin writing.
+
+  @param[in]  BufferSizeInBytes    The number of bytes to be writed.
+
+  @param[out] Buffer               The pointer to a caller-allocated buffer that
+                                   contains the source for the write.
+
+  @retval EFI_SUCCESS              PhytiumFvbFlashRead() is executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+PhytiumFvbFlashRead (
+  IN FT_FVB_DEVICE   *FlashInstance,
+  IN EFI_LBA          Lba,
+  IN UINTN            Offset,
+  IN UINTN            BufferSizeInBytes,
+  OUT VOID            *Buffer
+  )
+{
+  UINTN Address = GET_DATA_OFFSET(FlashInstance->RegionBaseAddress, Lba, FlashInstance->Media.BlockSize)  + Offset;
+
+  if (BufferSizeInBytes == 0) {
+    return EFI_SUCCESS;
+  }
+
+  // The buffer must be valid
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+  return FlashInstance->SpiFlashProtocol->Read (Address, Buffer, BufferSizeInBytes);
+}
+
+
+/**
+  Write a full or portion of a block. It must not span block boundaries; that is,
+  Offset + *NumBytes <= FlashInstance->Media.BlockSize.
+
+  @param[in]  FlashInstance        The pointer of FT_FVB_DEVICE instance.
+
+  @param[in]  Lba                  The starting logical block index to write to.
+
+  @param[in]  Offset               Offset into the block at which to begin writing.
+
+  @param[in]  BufferSizeInBytes    The number of bytes to be writed.
+
+  @param[out] Buffer               The pointer to a caller-allocated buffer that
+                                   contains the source for the write.
+
+  @retval EFI_SUCCESS              PhytiumFvbWriteBlock() is executed successfully.
+
+  @retval EFI_BAD_BUFFER_SIZE      The write spaned block boundaries.
+
+**/
+STATIC
+EFI_STATUS
+PhytiumFvbWriteBlock (
+  IN FT_FVB_DEVICE   *FlashInstance,
+  IN EFI_LBA          Lba,
+  IN UINTN            Offset,
+  IN UINTN            BufferSizeInBytes,
+  IN UINT8            *Buffer
+  )
+{
+  EFI_STATUS  Status;
+  UINTN       BlockSize;
+  UINTN       BlockAddress;
+
+  // Detect WriteDisabled state
+  if (FlashInstance->Media.ReadOnly == TRUE) {
+    DEBUG ((DEBUG_ERROR, "PhytiumFvbWriteBlock: ERROR - Can not write: Device is in WriteDisabled state.\n"));
+    // It is in WriteDisabled state, return an error right away
+    return EFI_ACCESS_DENIED;
+  }
+
+  // Cache the block size to avoid de-referencing pointers all the time
+  BlockSize = FlashInstance->Media.BlockSize;
+
+  // The write must not span block boundaries.
+  // We need to check each variable individually because adding two large values together overflows.
+  if ((Offset                       >= BlockSize) ||
+      (BufferSizeInBytes            >  BlockSize) ||
+      ((Offset + BufferSizeInBytes) >  BlockSize)) {
+    DEBUG ((DEBUG_ERROR, "PhytiumFvbWriteBlock: ERROR - EFI_BAD_BUFFER_SIZE: (Offset=0x%x + NumBytes=0x%x) > BlockSize=0x%x\n", Offset, BufferSizeInBytes, BlockSize ));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // We must have some bytes to write
+  if (BufferSizeInBytes == 0) {
+    DEBUG ((DEBUG_ERROR, "PhytiumFvbWriteBlock: ERROR - EFI_BAD_BUFFER_SIZE: NumBytes == 0\n"));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // Check we did get some memory. Buffer is BlockSize.
+  if (FlashInstance->ShadowBuffer == NULL) {
+    DEBUG ((DEBUG_ERROR, "PhytiumFvbWriteBlock: ERROR - ShadowBuffer is NULL!\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  //
+  // Write the word to NOR.
+  //
+  BlockAddress = GET_DATA_OFFSET(FlashInstance->RegionBaseAddress, Lba, FlashInstance->Media.BlockSize);
+
+  // Read NOR Flash data into shadow buffer
+  Status = FlashInstance->SpiFlashProtocol->Read (BlockAddress, FlashInstance->ShadowBuffer, BlockSize);
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Put the data at the appropriate location inside the buffer area
+  CopyMem ((VOID*)((UINTN)FlashInstance->ShadowBuffer + Offset), Buffer, BufferSizeInBytes);
+
+  Status = FlashInstance->SpiFlashProtocol->EraseSingleBlock (BlockAddress);
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  // Write the modified buffer back to the NorFlash
+  Status = FlashInstance->SpiFlashProtocol->Write(BlockAddress, FlashInstance->ShadowBuffer, BlockSize);
+  if (EFI_ERROR (Status)) {
+    // Return one of the pre-approved error statuses
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Writes the specified number of bytes from the input buffer to the block.
+
+  @param[in] FlashInstance        The pointer of FT_FVB_DEVICE instance.
+
+  @param[in] Lba                  The starting logical block index to write to.
+
+  @param[in] Offset               Offset into the block at which to begin writing.
+
+  @param[in] BufferSizeInBytes    The number of bytes to be writed.
+
+  @param[in] Buffer               The pointer to a caller-allocated buffer that
+                                  contains the source for the write.
+
+  @retval EFI_SUCCESS             PhytiumFvbFlashWrite() is executed successfully.
+
+  @retval EFI_WRITE_PROTECTED     Flash state is in the WriteDisabled state.
+
+  @retval EFI_INVALID_PARAMETER   The pointer of Buffer is NULL.
+
+**/
+STATIC
+EFI_STATUS
+PhytiumFvbFlashWrite (
+  IN FT_FVB_DEVICE    *FlashInstance,
+  IN EFI_LBA          Lba,
+  IN UINTN            Offset,
+  IN UINTN            BufferSizeInBytes,
+  IN VOID             *Buffer
+  )
+{
+  EFI_STATUS      Status = EFI_SUCCESS;
+  UINT32          BlockSize;
+  UINT32          BlockOffset;
+  UINTN           RemainingBytes;
+  UINTN           WriteSize;
+
+  if (FlashInstance->Media.ReadOnly == TRUE) {
+    return EFI_WRITE_PROTECTED;
+  }
+
+  if (BufferSizeInBytes == 0) {
+    return EFI_SUCCESS;
+  }
+
+  if (Buffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  BlockSize      = FlashInstance->Media.BlockSize;
+  BlockOffset    = Offset;
+  RemainingBytes = BufferSizeInBytes;
+
+  // The write must not span block boundaries.
+  // We need to check each variable individually because adding two large values together overflows.
+  if (Offset >= BlockSize) {
+    DEBUG ((DEBUG_ERROR, "FvbFlashWrite: ERROR - EFI_BAD_BUFFER_SIZE: Offset=0x%x > BlockSize=0x%x\n", Offset, BlockSize));
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // We must have some bytes to read
+  // Write either all the remaining bytes, or the number of bytes that bring
+  // us up to a block boundary, whichever is less.
+  // (DiskOffset | (BlockSize - 1)) + 1) rounds DiskOffset up to the next
+  // block boundary (even if it is already on one).
+  WriteSize = MIN (RemainingBytes, BlockSize - BlockOffset);
+
+  do {
+    Status = PhytiumFvbWriteBlock (FlashInstance, Lba, BlockOffset, WriteSize, Buffer);
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    // Now continue writing either all the remaining bytes or single blocks.
+    RemainingBytes -= WriteSize;
+    Buffer = (UINT8 *) Buffer + WriteSize;
+    Lba++;
+    BlockOffset = 0;
+    WriteSize = MIN (RemainingBytes, BlockSize);
+  } while (RemainingBytes);
+
+  return Status;
+}
+
+
+/**
+  Initialises the FV Header and Variable Store Header
+  to support variable operations.
+
+  @param[in] Ptr       Location to initialise the headers.
+
+  @retval EFI_SUCCESS  PhytiumFvbInitFvAndVariableStoreHeaders()
+                       is executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+PhytiumFvbInitFvAndVariableStoreHeaders (
+  IN FT_FVB_DEVICE *FlashInstance
+  )
+{
+  EFI_STATUS                  Status;
+  VOID*                       Headers;
+  UINTN                       HeadersLength;
+  EFI_FIRMWARE_VOLUME_HEADER  *FirmwareVolumeHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+
+  HeadersLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY) + sizeof(VARIABLE_STORE_HEADER);
+  Headers = AllocateZeroPool (HeadersLength);
+
+  // FirmwareVolumeHeader->FvLength is declared to have the Variable area AND the FTW working area AND the FTW Spare contiguous.
+  ASSERT(PcdGet64 (PcdFlashNvStorageVariableBase64) + PcdGet32 (PcdFlashNvStorageVariableSize) == PcdGet64(PcdFlashNvStorageFtwWorkingBase64));
+  ASSERT(PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) + PcdGet32 (PcdFlashNvStorageFtwWorkingSize) == PcdGet64(PcdFlashNvStorageFtwSpareBase64));
+
+  // Check if the size of the area is at least one block size
+  ASSERT((PcdGet32 (PcdFlashNvStorageVariableSize) > 0) && (PcdGet32 (PcdFlashNvStorageVariableSize) / FlashInstance->Media.BlockSize > 0));
+  ASSERT((PcdGet32 (PcdFlashNvStorageFtwWorkingSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwWorkingSize) / FlashInstance->Media.BlockSize > 0));
+  ASSERT((PcdGet32 (PcdFlashNvStorageFtwSpareSize) > 0) && (PcdGet32 (PcdFlashNvStorageFtwSpareSize) / FlashInstance->Media.BlockSize > 0));
+
+  // Ensure the Variable area Base Addresses are aligned on a block size boundaries
+  ASSERT(PcdGet64 (PcdFlashNvStorageVariableBase64) % FlashInstance->Media.BlockSize == 0);
+  ASSERT(PcdGet64 (PcdFlashNvStorageFtwWorkingBase64) % FlashInstance->Media.BlockSize == 0);
+  ASSERT(PcdGet64 (PcdFlashNvStorageFtwSpareBase64) % FlashInstance->Media.BlockSize == 0);
+
+  //
+  // EFI_FIRMWARE_VOLUME_HEADER
+  //
+  FirmwareVolumeHeader = (EFI_FIRMWARE_VOLUME_HEADER*)Headers;
+  CopyGuid (&FirmwareVolumeHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid);
+  FirmwareVolumeHeader->FvLength = FlashInstance->FvbSize;
+
+  FirmwareVolumeHeader->Signature = EFI_FVH_SIGNATURE;
+  FirmwareVolumeHeader->Attributes = (EFI_FVB_ATTRIBUTES_2) (
+                                          EFI_FVB2_READ_ENABLED_CAP   | // Reads may be enabled
+                                          EFI_FVB2_READ_STATUS        | // Reads are currently enabled
+                                          EFI_FVB2_STICKY_WRITE       | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+                                          EFI_FVB2_MEMORY_MAPPED      | // It is memory mapped
+                                          EFI_FVB2_ERASE_POLARITY     | // After erasure all bits take this value (i.e. '1')
+                                          EFI_FVB2_WRITE_STATUS       | // Writes are currently enabled
+                                          EFI_FVB2_WRITE_ENABLED_CAP    // Writes may be enabled
+                                      );
+
+  FirmwareVolumeHeader->HeaderLength = sizeof(EFI_FIRMWARE_VOLUME_HEADER) + sizeof(EFI_FV_BLOCK_MAP_ENTRY);
+  FirmwareVolumeHeader->Revision = EFI_FVH_REVISION;
+  FirmwareVolumeHeader->BlockMap[0].NumBlocks = FlashInstance->Media.LastBlock + 1;
+  FirmwareVolumeHeader->BlockMap[0].Length    = FlashInstance->Media.BlockSize;
+  FirmwareVolumeHeader->BlockMap[1].NumBlocks = 0;
+  FirmwareVolumeHeader->BlockMap[1].Length    = 0;
+  FirmwareVolumeHeader->Checksum = CalculateCheckSum16 ((UINT16*)FirmwareVolumeHeader, FirmwareVolumeHeader->HeaderLength);
+
+  //
+  // VARIABLE_STORE_HEADER
+  //
+  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)Headers + FirmwareVolumeHeader->HeaderLength);
+  CopyGuid (&VariableStoreHeader->Signature, NorFlashVariableGuid);
+  VariableStoreHeader->Size   = PcdGet32 (PcdFlashNvStorageVariableSize) - FirmwareVolumeHeader->HeaderLength;
+  VariableStoreHeader->Format = VARIABLE_STORE_FORMATTED;
+  VariableStoreHeader->State  = VARIABLE_STORE_HEALTHY;
+
+  // Install the combined super-header in the NorFlash
+  Status = PhytiumFvbWrite (&FlashInstance->FvbProtocol, 0, 0, &HeadersLength, Headers);
+
+  FreePool (Headers);
+
+  return Status;
+}
+
+
+/**
+  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 been corrupted.
+
+**/
+STATIC
+EFI_STATUS
+PhytiumFvbValidateFvHeader (
+  IN  FT_FVB_DEVICE *FlashInstance
+  )
+{
+  UINT16                      Checksum;
+  EFI_FIRMWARE_VOLUME_HEADER  *FwVolHeader;
+  VARIABLE_STORE_HEADER       *VariableStoreHeader;
+  UINTN                       VariableStoreLength;
+  UINTN                       FvLength;
+
+  FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER*)GET_DATA_OFFSET(FlashInstance->RegionBaseAddress, FlashInstance->StartLba, FlashInstance->Media.BlockSize);
+  FvLength = FlashInstance->FvbSize;
+
+  //
+  // 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  != FvLength))
+  {
+    DEBUG ((DEBUG_ERROR, "ValidateFvHeader: No Firmware Volume header present\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  // Check the Firmware Volume Guid
+  if( CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid) == FALSE ) {
+    DEBUG ((DEBUG_ERROR, "ValidateFvHeader: Firmware Volume Guid non-compatible\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  // Verify the header checksum
+  Checksum = CalculateSum16 ((UINT16*)FwVolHeader, FwVolHeader->HeaderLength);
+  if (Checksum != 0) {
+    DEBUG ((DEBUG_ERROR, "ValidateFvHeader: FV checksum is invalid (Checksum:0x%X)\n",Checksum));
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStoreHeader = (VARIABLE_STORE_HEADER*)((UINTN)FwVolHeader + FwVolHeader->HeaderLength);
+
+  // Check the Variable Store Guid
+  if (!CompareGuid (&VariableStoreHeader->Signature, &gEfiVariableGuid) &&
+      !CompareGuid (&VariableStoreHeader->Signature,
+                    &gEfiAuthenticatedVariableGuid)) {
+    DEBUG ((DEBUG_ERROR, "%a: Variable Store Guid non-compatible\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  VariableStoreLength = PcdGet32 (PcdFlashNvStorageVariableSize) - FwVolHeader->HeaderLength;
+  if (VariableStoreHeader->Size != VariableStoreLength) {
+    DEBUG ((DEBUG_ERROR, "ValidateFvHeader: Variable Store Length does not match\n"));
+    return EFI_NOT_FOUND;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The PhytiumFvbGetAttributes() function retrieves the attributes and
+  current settings of the block.
+
+  @param This         Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Attributes   Pointer to EFI_FVB_ATTRIBUTES_2 in which the attributes and
+                      current settings are returned.
+                      Type EFI_FVB_ATTRIBUTES_2 is defined in
+                      EFI_FIRMWARE_VOLUME_HEADER.
+
+  @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL    *This,
+  OUT       EFI_FVB_ATTRIBUTES_2                   *Attributes
+  )
+{
+  EFI_FVB_ATTRIBUTES_2  FlashFvbAttributes;
+  CONST FT_FVB_DEVICE    *FlashInstance;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS(This);
+
+  FlashFvbAttributes = (EFI_FVB_ATTRIBUTES_2) (
+
+      EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
+      EFI_FVB2_READ_STATUS      | // Reads are currently enabled
+      EFI_FVB2_STICKY_WRITE     | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+      EFI_FVB2_MEMORY_MAPPED    | // It is memory mapped
+      EFI_FVB2_ERASE_POLARITY     // After erasure all bits take this value (i.e. '1')
+
+      );
+
+  // Check if it is write protected
+  if (FlashInstance->Media.ReadOnly != TRUE) {
+
+    FlashFvbAttributes = FlashFvbAttributes         |
+                         EFI_FVB2_WRITE_STATUS      | // Writes are currently enabled
+                         EFI_FVB2_WRITE_ENABLED_CAP;  // Writes may be enabled
+  }
+
+  *Attributes = FlashFvbAttributes;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The PhytiumFvbSetAttributes() function sets configurable firmware volume attributes
+  and returns the new settings of the firmware volume.
+
+  @param This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Attributes               On input, Attributes is a pointer to
+                                  EFI_FVB_ATTRIBUTES_2 that contains the desired
+                                  firmware volume settings.
+                                  On successful return, it contains the new
+                                  settings of the firmware volume.
+
+  @retval EFI_SUCCESS             The firmware volume attributes were returned.
+
+  @retval EFI_INVALID_PARAMETER   The attributes requested are in conflict with
+                                  the capabilities as declared in the firmware
+                                  volume header.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbSetAttributes (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN OUT    EFI_FVB_ATTRIBUTES_2                 *Attributes
+  )
+{
+  return EFI_UNSUPPORTED;
+}
+
+
+/**
+  The PhytiumFvbGetPhysicalAddress() function retrieves the base address of
+  a memory-mapped firmware volume. This function should be called
+  only for memory-mapped firmware volumes.
+
+  @param This               EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Address            Pointer to a caller-allocated
+                            EFI_PHYSICAL_ADDRESS that, on successful
+                            return from GetPhysicalAddress(), contains the
+                            base address of the firmware volume.
+
+  @retval EFI_SUCCESS       The firmware volume base address was returned.
+
+  @retval EFI_NOT_SUPPORTED The firmware volume is not memory mapped.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetPhysicalAddress (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  OUT       EFI_PHYSICAL_ADDRESS                 *Address
+  )
+{
+  FT_FVB_DEVICE *FlashInstance;
+
+  ASSERT (Address != NULL);
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  *Address = mFlashNvStorageVariableBase;
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  The PhytiumFvbGetBlockSize() function retrieves the size of the requested
+  block. It also returns the number of additional blocks with
+  the identical size. The PhytiumFvbGetBlockSize() function is used to
+  retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+  @param This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Lba                      Indicates the block whose size to return.
+
+  @param BlockSize                Pointer to a caller-allocated UINTN in which
+                                  the size of the block is returned.
+
+  @param NumberOfBlocks           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 base address was returned.
+
+  @retval EFI_INVALID_PARAMETER   The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbGetBlockSize (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL  *This,
+  IN        EFI_LBA                              Lba,
+  OUT       UINTN                                *BlockSize,
+  OUT       UINTN                                *NumberOfBlocks
+  )
+{
+  EFI_STATUS Status;
+  FT_FVB_DEVICE *FlashInstance;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS(This);
+
+  if (Lba > FlashInstance->Media.LastBlock) {
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    // This is easy because in this platform each NorFlash device has equal sized blocks.
+    *BlockSize = (UINTN) FlashInstance->Media.BlockSize;
+    *NumberOfBlocks = (UINTN) (FlashInstance->Media.LastBlock - Lba + 1);
+    Status = EFI_SUCCESS;
+  }
+
+  return Status;
+}
+
+
+/**
+  Reads the specified number of bytes into a buffer from the specified block.
+
+  The PhytiumFvbRead() function reads the requested number of bytes from the
+  requested block and stores them in the provided buffer.
+  Implementations should be mindful that the firmware volume
+  might be in the ReadDisabled state. If it is in this state,
+  the PhytiumFvbRead() function must return the status code
+  EFI_ACCESS_DENIED without modifying the contents of the
+  buffer. The PhytiumFvbRead() function must also prevent spanning block
+  boundaries. If a read is requested that would span a block
+  boundary, the read must read up to the boundary but not
+  beyond. The output parameter NumBytes must be set to correctly
+  indicate the number of bytes actually read. The caller must be
+  aware that a read may be partially completed.
+
+  @param This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Lba                  The starting logical block index from which to read.
+
+  @param Offset               Offset into the block at which to begin reading.
+
+  @param NumBytes             Pointer to a UINTN.
+                              At entry, *NumBytes contains the total size of the
+                              buffer.
+                              At exit, *NumBytes contains the total number of
+                              bytes read.
+
+  @param Buffer               Pointer to a caller-allocated buffer that will be
+                              used to hold the data that is read.
+
+  @retval EFI_SUCCESS         The firmware volume was read successfully, and
+                              contents are in Buffer.
+
+  @retval EFI_BAD_BUFFER_SIZE Read attempted across an 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.
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbRead (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *This,
+  IN        EFI_LBA                               Lba,
+  IN        UINTN                                 Offset,
+  IN OUT    UINTN                                 *NumBytes,
+  IN OUT    UINT8                                 *Buffer
+  )
+{
+  UINTN              BlockSize;
+  FT_FVB_DEVICE      *FlashInstance;
+  EFI_STATUS         Status;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS(This);
+
+  // Cache the block size to avoid de-referencing pointers all the time
+  BlockSize = FlashInstance->Media.BlockSize;
+
+  // The read must not span block boundaries.
+  // We need to check each variable individually because adding two large values together overflows.
+  if ((Offset               >= BlockSize) ||
+      (*NumBytes            >  BlockSize) ||
+      ((Offset + *NumBytes) >  BlockSize)) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  // We must have some bytes to read
+  if (*NumBytes == 0) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  Status = PhytiumFvbFlashRead (FlashInstance, FlashInstance->StartLba + Lba, Offset, *NumBytes, Buffer);
+  if (EFI_ERROR (Status)) {
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+
+/**
+  Writes the specified number of bytes from the input buffer to the block.
+
+  The PhytiumFvbWrite() function writes the specified number of bytes from
+  the provided buffer to the specified block and offset. If the
+  firmware volume is sticky write, the caller must ensure that
+  all the bits of the specified range to write are in the
+  EFI_FVB_ERASE_POLARITY state before calling the PhytiumFvbWrite()
+  function, or else the result will be unpredictable. This
+  unpredictability arises because, for a sticky-write firmware
+  volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+  state but cannot flip it back again.  Before calling the
+  PhytiumFvbWrite() function,  it is recommended for the caller to
+  first call the PhytiumFvbEraseBlocks() function to erase the specified
+  block to write. A block erase cycle will transition bits from
+  the (NOT)EFI_FVB_ERASE_POLARITY state back to the
+  EFI_FVB_ERASE_POLARITY state. Implementations should be
+  mindful that the firmware volume might be in the WriteDisabled
+  state. If it is in this state, the PhytiumFvbWrite() function must
+  return the status code EFI_ACCESS_DENIED without modifying the
+  contents of the firmware volume. The PhytiumFvbWrite() function must
+  also prevent spanning block boundaries. If a write is
+  requested that spans a block boundary, the write must store up
+  to the boundary but not beyond. The output parameter NumBytes
+  must be set to correctly indicate the number of bytes actually
+  written. The caller must be aware that a write may be
+  partially completed. All writes, partial or otherwise, must be
+  fully flushed to the hardware before the PhytiumFvbWrite() service
+  returns.
+
+  @param This                 EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Lba                  The starting logical block index to write to.
+
+  @param Offset               Offset into the block at which to begin writing.
+
+  @param NumBytes             The pointer to a UINTN.
+                              At entry, *NumBytes contains the total size of the
+                              buffer.
+                              At exit, *NumBytes contains the total number of
+                              bytes actually written.
+
+  @param Buffer               The pointer to a caller-allocated buffer that
+                              contains the source for the write.
+
+  @retval EFI_SUCCESS         The firmware volume was written successfully.
+
+  @retval EFI_BAD_BUFFER_SIZE The write was attempted across an 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 malfunctioning and could not be
+                              written.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbWrite (
+  IN CONST  EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL   *This,
+  IN        EFI_LBA                               Lba,
+  IN        UINTN                                 Offset,
+  IN OUT    UINTN                                 *NumBytes,
+  IN        UINT8                                 *Buffer
+  )
+{
+  FT_FVB_DEVICE *FlashInstance;
+
+  FlashInstance = INSTANCE_FROM_FVB_THIS (This);
+
+  return PhytiumFvbFlashWrite (FlashInstance, FlashInstance->StartLba + Lba, Offset, *NumBytes, Buffer);
+}
+
+
+/**
+  Erases and initialises a firmware volume block.
+
+  The PhytiumFvbEraseBlocks() function erases one or more blocks as denoted
+  by the variable argument list. The entire parameter list of
+  blocks must be verified before 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 PhytiumFvbEraseBlocks() function must return the
+  status code EFI_INVALID_PARAMETER without modifying the contents
+  of the firmware volume. Implementations should be mindful that
+  the firmware volume might be in the WriteDisabled state. If it
+  is in this state, the PhytiumFvbEraseBlocks() function must return the
+  status code EFI_ACCESS_DENIED without modifying the contents of
+  the firmware volume. All calls to PhytiumFvbEraseBlocks() must be fully
+  flushed to the hardware before the PhytiumFvbEraseBlocks() service
+  returns.
+
+  @param This                     EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+                                  instance.
+
+  @param ...                      The variable argument list is a list of tuples.
+                                  Each tuple describes a range of LBAs to erase
+                                  and consists of the following:
+                                  An EFI_LBA that indicates the starting LBA
+                                  A UINTN that indicates the number of blocks
+                                  to erase.
+
+                                  The list is terminated with an
+                                  EFI_LBA_LIST_TERMINATOR.
+
+  @retval EFI_SUCCESS             The erase request 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.
+                                  The firmware device may have been partially
+                                  erased.
+
+  @retval EFI_INVALID_PARAMETER   One or more of the LBAs listed in the variable
+                                  argument list do not exist in the firmware
+                                  volume.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbEraseBlocks (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  ...
+  )
+{
+  EFI_STATUS         Status;
+  VA_LIST            Args;
+  UINTN              BlockAddress; // Physical address of Lba to erase
+  EFI_LBA            StartingLba; // Lba from which we start erasing
+  UINTN              NumOfLba; // Number of Lba blocks to erase
+  FT_FVB_DEVICE      *Instance;
+
+  Instance = INSTANCE_FROM_FVB_THIS(This);
+
+  Status = EFI_SUCCESS;
+
+  // Detect WriteDisabled state
+  if (Instance->Media.ReadOnly == TRUE) {
+    // Firmware volume is in WriteDisabled state
+    DEBUG ((DEBUG_ERROR, "FvbEraseBlocks: ERROR - Device is in WriteDisabled state.\n"));
+    return EFI_ACCESS_DENIED;
+  }
+
+  // Before erasing, check the entire list of parameters to ensure all specified blocks are valid
+
+  VA_START (Args, This);
+  do {
+    // Get the Lba from which we start erasing
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    // Have we reached the end of the list?
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      //Exit the while loop
+      break;
+    }
+
+    // How many Lba blocks are we requested to erase?
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    // All blocks must be within range
+    if ((NumOfLba == 0) || ((Instance->StartLba + StartingLba + NumOfLba - 1) > Instance->Media.LastBlock)) {
+      VA_END (Args);
+      DEBUG ((DEBUG_ERROR, "FvbEraseBlocks: ERROR - Lba range goes past the last Lba.\n"));
+      Status = EFI_INVALID_PARAMETER;
+      goto EXIT;
+    }
+  } while (TRUE);
+  VA_END (Args);
+
+  //
+  // To get here, all must be ok, so start erasing
+  //
+  VA_START (Args, This);
+  do {
+    // Get the Lba from which we start erasing
+    StartingLba = VA_ARG (Args, EFI_LBA);
+
+    // Have we reached the end of the list?
+    if (StartingLba == EFI_LBA_LIST_TERMINATOR) {
+      // Exit the while loop
+      break;
+    }
+
+    // How many Lba blocks are we requested to erase?
+    NumOfLba = VA_ARG (Args, UINT32);
+
+    // Go through each one and erase it
+    while (NumOfLba > 0) {
+
+      // Get the physical address of Lba to erase
+      BlockAddress = GET_DATA_OFFSET (
+                     Instance->RegionBaseAddress,
+                     Instance->StartLba + StartingLba,
+                     Instance->Media.BlockSize
+                     );
+
+      // Erase it
+      Status = FvbFlashEraseSingleBlock (Instance, BlockAddress);
+      if (EFI_ERROR(Status)) {
+        VA_END (Args);
+        Status = EFI_DEVICE_ERROR;
+        goto EXIT;
+      }
+
+      // Move to the next Lba
+      StartingLba++;
+      NumOfLba--;
+    }
+  } while (TRUE);
+
+  VA_END (Args);
+
+EXIT:
+  return Status;
+}
+
+
+//extern const  UINT64  _gPcd_FixedAtBuild_PcdSpiControllerBase;
+//extern const  UINT64  _gPcd_FixedAtBuild_PcdSpiControllerSize;
+//#define SPI_CONTROLLER_BASE     _gPcd_FixedAtBuild_PcdSpiControllerBase
+//#define SPI_CONTROLLER_SIZE     _gPcd_FixedAtBuild_PcdSpiControllerSize
+
+/**
+  This function inited the NorFlash instance.
+
+  @param[in][out] FlashInstance   The pointer of FT_FVB_DEVICE instance.
+
+  @retval EFI_SUCCESS             PhytNorFlashFvbInitialize() is executed successfully.
+
+**/
+STATIC
+EFI_STATUS
+PhytNorFlashFvbInitialize (
+  IN OUT FT_FVB_DEVICE *FlashInstance
+  )
+{
+  EFI_STATUS     Status;
+  UINT32         FvbNumLba;
+  EFI_BOOT_MODE  BootMode;
+  UINTN          TotalFvbSize;
+
+  mFlashNvStorageVariableBase = FixedPcdGet64 (PcdFlashNvStorageVariableBase64);
+
+  // Declare the Non-Volatile storage as EFI_MEMORY_RUNTIME
+
+  // Note: all the NOR Flash region needs to be reserved into the UEFI Runtime memory;
+  //       even if we only use the small block region at the top of the NOR Flash.
+  //       The reason is when the NOR Flash memory is set into program mode, the command
+  //       is written as the base of the flash region (ie: FlashInstance->DeviceBaseAddress)
+  // Todo: SPI control block should be remapped, otherwise ...
+  Status = gDS->AddMemorySpace (
+                  EfiGcdMemoryTypeMemoryMappedIo,
+                  mFlashNvStorageVariableBase, FlashInstance->FvbSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gDS->SetMemorySpaceAttributes (
+                  mFlashNvStorageVariableBase, FlashInstance->FvbSize,
+                  EFI_MEMORY_UC | EFI_MEMORY_RUNTIME
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  TotalFvbSize = FlashInstance->FvbSize;
+
+  // Set the index of the first LBA for the FVB
+  FlashInstance->StartLba = (PcdGet64 (PcdFlashNvStorageVariableBase64) - FlashInstance->RegionBaseAddress) / FlashInstance->Media.BlockSize;
+
+  BootMode = GetBootModeHob ();
+  if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+    Status = EFI_INVALID_PARAMETER;
+  } else {
+    // Determine if there is a valid header at the beginning of the NorFlash
+    Status = PhytiumFvbValidateFvHeader (FlashInstance);
+  }
+
+  // Install the Default FVB header if required
+  if (EFI_ERROR(Status)) {
+    // There is no valid header, so time to install one.
+    DEBUG((DEBUG_ERROR,"NorFlashFvbInitialize: ERROR - The FVB Header is invalid. Installing a correct one for this volume.\n"));
+
+    // Erase all the NorFlash that is reserved for variable storage
+    FvbNumLba = TotalFvbSize / FlashInstance->Media.BlockSize;
+
+    Status = PhytiumFvbEraseBlocks (&FlashInstance->FvbProtocol, (EFI_LBA)0, FvbNumLba, EFI_LBA_LIST_TERMINATOR);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+
+    // Install all appropriate headers
+    Status = PhytiumFvbInitFvAndVariableStoreHeaders (FlashInstance);
+    if (EFI_ERROR(Status)) {
+      return Status;
+    }
+  }
+
+  return Status;
+}
+
+
+/**
+  The CreateInstance() function Create Fvb Instance.
+
+  @retval  EFI_SUCCESS         Create Instance successfully.
+
+  @retval  other               Create Instance failed.
+
+**/
+STATIC
+EFI_STATUS
+CreateInstance (
+  VOID
+  )
+{
+  EFI_STATUS Status;
+  NOR_FLASH_DEVICE_DESCRIPTION   *NorFlashDevice;
+
+  // Locate flash protocols
+  Status = gBS->LocateProtocol (&gPhytiumFlashProtocolGuid,
+                  NULL,
+                  (VOID **)&PhytiumFvbDevice->SpiFlashProtocol);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Cannot locate NorFlash protocol.\n"));
+    return Status;
+  }
+
+  NorFlashDevice = AllocateRuntimePool(sizeof(NOR_FLASH_DEVICE_DESCRIPTION));
+  if (NorFlashDevice == NULL) {
+    DEBUG ((DEBUG_ERROR, "Cannot Allocate NorFlashDevice Pool.\n"));
+    return Status;
+  }
+
+  Status = PhytiumFvbDevice->SpiFlashProtocol->GetDevices (NorFlashDevice);
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  Status = PhytiumFvbDevice->SpiFlashProtocol->Initialization();
+  if (EFI_ERROR(Status)) {
+    return Status;
+  }
+
+  PhytiumFvbDevice->DeviceBaseAddress = NorFlashDevice->DeviceBaseAddress;
+  PhytiumFvbDevice->RegionBaseAddress = NorFlashDevice->RegionBaseAddress;
+  PhytiumFvbDevice->Size = NorFlashDevice->Size;
+
+  PhytiumFvbDevice->Media.MediaId = 0;
+  PhytiumFvbDevice->Media.BlockSize = NorFlashDevice->BlockSize;
+  PhytiumFvbDevice->Media.LastBlock = (PhytiumFvbDevice->Size / PhytiumFvbDevice->Media.BlockSize) - 1;
+  PhytiumFvbDevice->FvbSize = PcdGet32 (PcdFlashNvStorageVariableSize) +
+                              PcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+                              PcdGet32 (PcdFlashNvStorageFtwSpareSize);
+  DEBUG ((DEBUG_INFO, "%a: line at %d, DeviceBaseAddress=%x,PhytiumFvbDevice->Size=%x\n", __FUNCTION__, __LINE__, PhytiumFvbDevice->DeviceBaseAddress, PhytiumFvbDevice->Size));
+
+  CopyGuid (&PhytiumFvbDevice->DevicePath.Vendor.Guid, &NorFlashDevice->Guid);
+
+  PhytiumFvbDevice->ShadowBuffer = AllocateRuntimePool (PhytiumFvbDevice->Media.BlockSize);
+  if (PhytiumFvbDevice->ShadowBuffer == NULL) {
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+              &PhytiumFvbDevice->Handle,
+              &gEfiDevicePathProtocolGuid, &PhytiumFvbDevice->DevicePath,
+              &gEfiFirmwareVolumeBlockProtocolGuid, &PhytiumFvbDevice->FvbProtocol,
+              NULL
+              );
+  if (EFI_ERROR(Status)) {
+    FreePool (PhytiumFvbDevice);
+    return Status;
+  }
+
+  Status = PhytNorFlashFvbInitialize(PhytiumFvbDevice);
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "PhytNorFlashFvbInitialize: Fail to init NorFlash devices\n"));
+    return Status;
+  }
+
+  FreePool(NorFlashDevice);
+
+  return Status;
+}
+
+
+/**
+  Fixup internal data so that EFI can be call in virtual mode.
+  Call the passed in Child Notify event and convert any pointers in lib to virtual mode.
+
+  @param[in]    Event   The Event that is being processed.
+
+  @param[in]    Context Event Context.
+
+  @retval       None.
+
+**/
+STATIC
+VOID
+EFIAPI
+PhytiumFvbVirtualNotifyEvent (
+  IN EFI_EVENT        Event,
+  IN VOID             *Context
+  )
+{
+  // Convert SpiFlashProtocol
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->Erase);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->Write);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->Read);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->GetDevices);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->Initialization);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol->EraseSingleBlock);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice->SpiFlashProtocol);
+
+  EfiConvertPointer (0x0, (VOID**)&mFlashNvStorageVariableBase);
+  EfiConvertPointer (0x0, (VOID**)&PhytiumFvbDevice);
+
+  return;
+}
+
+
+/**
+  This function is the entrypoint of the fvb driver.
+
+  @param[in] ImageHandle    The firmware allocated handle for the EFI image.
+
+  @param[in] SystemTable    A pointer to the EFI System Table.
+
+  @retval EFI_SUCCESS       The entry point is executed successfully.
+
+  @retval other             Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+PhytiumFvbEntryPoint (
+  IN EFI_HANDLE           ImageHandle,
+  IN EFI_SYSTEM_TABLE    *SystemTable
+  )
+{
+  EFI_STATUS                     Status;
+
+  PhytiumFvbDevice = AllocateRuntimeCopyPool (sizeof(PhytiumFvbFlashInstanceTemplate), &PhytiumFvbFlashInstanceTemplate);
+  if (PhytiumFvbDevice == NULL) {
+    DEBUG ((DEBUG_ERROR, "%a: Cannot allocate memory\n", __FUNCTION__));
+    return EFI_OUT_OF_RESOURCES;
+  }
+
+  Status = CreateInstance ();
+  if (EFI_ERROR(Status)) {
+    DEBUG((DEBUG_ERROR, "CreateInstance: Fail to create instance for NorFlash\n"));
+  }
+
+//
+// Register for the virtual address change event
+//
+  Status = gBS->CreateEventEx (
+                EVT_NOTIFY_SIGNAL,
+                TPL_NOTIFY,
+                PhytiumFvbVirtualNotifyEvent,
+                NULL,
+                &gEfiEventVirtualAddressChangeGuid,
+                &FvbVirtualAddrChangeEvent
+                );
+  ASSERT_EFI_ERROR (Status);
+
+  return Status;
+}
-- 
2.25.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#70405): https://edk2.groups.io/g/devel/message/70405
Mute This Topic: https://groups.io/mt/79697762/1813853
Group Owner: devel+owner at edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [edk2-devel-archive at redhat.com]
-=-=-=-=-=-=-=-=-=-=-=-






More information about the edk2-devel-archive mailing list