[edk2-devel] [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables

Nhi Pham via groups.io posted 32 patches 4 years, 8 months ago
There is a newer version of this series
[edk2-devel] [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables
Posted by Nhi Pham via groups.io 4 years, 8 months ago
From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Non-volatile variables now can be stored on flash. MM communication
protocol is used to access storage on flash.

Included in this change are:
* FlashPei module is used to compare saved UUID with firmware's
  UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
  Otherwise fill the storage with default value from NVRAM FV.
* FlashLib provide APIs to access flash through MM Communication
  protocol
* FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
  used by the variable services to get/set variables.

Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                  |   3 +
 Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec              |   3 +
 Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc              |  11 +-
 Platform/Ampere/JadePkg/Jade.dsc                                  |   1 +
 Platform/Ampere/JadePkg/Jade.fdf                                  |  62 ++-
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf |  54 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf       |  51 ++
 Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf       |  36 ++
 Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h          |  42 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c   | 525 ++++++++++++++++++++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c         | 283 +++++++++++
 Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c         | 358 +++++++++++++
 12 files changed, 1425 insertions(+), 4 deletions(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index be827dd19a96..d5b12a81e9bf 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -37,6 +37,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to communicate with secure parition over MM interface.
   MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
 
+  ##  @libraryclass  Defines a set of methods to access flash memory.
+  FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
+
   ##  @libraryclass  Defines a set of methods to generate random numbers by using Hardware RNG.
   TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
 
diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
index 6ebdf7db0a57..26e020715290 100755
--- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
@@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
   # Firmware Volume Pcds
   #
   gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
+
+  # NVRam Pcds
+  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index 9f75da6f05ad..65973569a41d 100755
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
 
 [BuildOptions]
   GCC:RELEASE_*_*_CC_FLAGS  = -DMDEPKG_NDEBUG
+  GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)
 
 [LibraryClasses.common]
 !if $(TARGET) == RELEASE
@@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
   SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
   PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
   MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
 
 [LibraryClasses.common.UEFI_APPLICATION]
   UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
@@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
 
   EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
   ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
+  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
 
 [LibraryClasses.ARM,LibraryClasses.AARCH64]
   #
@@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
   gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
 
+  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
+
 ################################################################################
 #
 # Component Section - list of all EDK II Component Entries defined by this Platform
@@ -520,8 +525,10 @@ [Components.common]
   Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
   Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
   Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
+  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
   ArmPkg/Drivers/CpuPei/CpuPei.inf
   UefiCpuPkg/CpuIoPei/CpuIoPei.inf
+  MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
   MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
   MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
     <LibraryClasses>
@@ -575,9 +582,9 @@ [Components.common]
   #
   # Environment Variables Protocol
   #
+  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
+  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
   MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
-    <PcdsFixedAtBuild>
-      gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
     <LibraryClasses>
       BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
       TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index f37ab1a92e44..9b9a5d0bad0f 100755
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -52,6 +52,7 @@ [Defines]
   DEFINE EDK2_SKIP_PEICORE       = TRUE
   DEFINE SECURE_BOOT_ENABLE      = FALSE
   DEFINE INCLUDE_TFTP_COMMAND    = TRUE
+  DEFINE UEFI_UUID               = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
 
   #
   # Network definition
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 1857296a8ea5..375455086d0b 100755
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
 ErasePolarity = 1
 
 # This one is tricky, it must be: BlockSize * NumBlocks = Size
-BlockSize     = 0x10000
+BlockSize     = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
 NumBlocks     = 0x7C
 
 ################################################################################
@@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
 
 #
 # NV Variables
-# T.B.D
+# Offset: 0x00740000
+# Size:   0x00080000
 #
+0x00740000|0x00030000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+DATA = {
+  ## This is the EFI_FIRMWARE_VOLUME_HEADER
+  # ZeroVector []
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  # FileSystemGuid: gEfiSystemNvDataFvGuid         =
+  #   { 0xFFF12B8D, 0x7696, 0x4C8B,
+  #     { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+  0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
+  0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
+  # FvLength: 0x80000
+  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+  # Signature "_FVH"       # Attributes
+  0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
+  # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
+  0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
+  # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
+  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+  # Blockmap[1]: End
+  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+  ## This is the VARIABLE_STORE_HEADER
+  # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
+  # Signature: gEfiAuthenticatedVariableGuid =
+  #   { 0xaaf32c78, 0x947b, 0x439a,
+  #     { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
+  0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
+  0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
+  # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
+  #         0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
+  # This can speed up the Variable Dispatch a bit.
+  0xB8, 0xFF, 0x02, 0x00,
+  # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
+  0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00770000|0x00010000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+DATA = {
+  # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
+  #  { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
+  0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
+  0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95,
+  # Crc:UINT32            #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
+  0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
+  # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
+  0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00780000|0x00040000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
 
 ################################################################################
 #
@@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
   INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
   INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
   INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
+  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
   INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
   INF ArmPkg/Drivers/CpuPei/CpuPei.inf
   INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+  INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
   INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
   INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
   INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
@@ -144,6 +199,7 @@ [FV.FvMain]
   INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
   INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
   INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
+  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
 }
 
   INF MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -173,6 +229,8 @@ [FV.FvMain]
   # Environment Variables Protocol
   #
   INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
 
   #
   # Multiple Console IO support
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
new file mode 100644
index 000000000000..782278615094
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
@@ -0,0 +1,54 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = FlashFvbDxe
+  FILE_GUID                      = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
+  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
+  VERSION_STRING                 = 0.1
+  ENTRY_POINT                    = FlashFvbDxeInitialize
+
+[Sources]
+  FlashFvbDxe.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+  DebugLib
+  FlashLib
+  PcdLib
+  UefiBootServicesTableLib
+  UefiDriverEntryPoint
+  UefiRuntimeLib
+
+[FixedPcd]
+  gAmpereTokenSpaceGuid.PcdFvBlockSize
+
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+
+[Guids]
+  gEfiEventVirtualAddressChangeGuid
+  gSpiNorMmGuid
+
+[Protocols]
+  gEfiFirmwareVolumeBlockProtocolGuid             ## PRODUCES
+  gEfiMmCommunicationProtocolGuid                 ## CONSUMES
+
+[Depex]
+  gEfiMmCommunicationProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
new file mode 100644
index 000000000000..a4eaf5039bb0
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
@@ -0,0 +1,51 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                    = 0x0001001B
+  BASE_NAME                      = FlashPei
+  FILE_GUID                      = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
+  MODULE_TYPE                    = PEIM
+  VERSION_STRING                 = 1.0
+  ENTRY_POINT                    = FlashPeiEntryPoint
+
+[Sources]
+  FlashPei.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+  ArmSmcLib
+  BaseMemoryLib
+  DebugLib
+  MmCommunicationLib
+  PcdLib
+  PeimEntryPoint
+
+[Guids]
+  gSpiNorMmGuid
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+
+  gAmpereTokenSpaceGuid.PcdNvramErased
+
+[Depex]
+  TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
new file mode 100644
index 000000000000..2d5003d1af17
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
@@ -0,0 +1,36 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+  INF_VERSION                   = 0x0001001B
+  BASE_NAME                     = FlashLib
+  FILE_GUID                     = 9E9D093D-6484-45AE-BA49-0745AA0BB481
+  MODULE_TYPE                   = DXE_DRIVER
+  VERSION_STRING                = 0.1
+  LIBRARY_CLASS                 = FlashLib
+  CONSTRUCTOR                   = FlashLibConstructor
+
+[Sources.common]
+  FlashLib.c
+
+[Packages]
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  MdePkg/MdePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+  BaseMemoryLib
+  DebugLib
+  MemoryAllocationLib
+
+[Guids]
+  gSpiNorMmGuid
+
+[Protocols]
+  gEfiMmCommunicationProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
new file mode 100644
index 000000000000..9207dee643a5
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
@@ -0,0 +1,42 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FLASH_LIB_H_
+#define FLASH_LIB_H_
+
+EFI_STATUS
+EFIAPI
+FlashGetNvRamInfo (
+  OUT UINT64 *NvRamBase,
+  OUT UINT32 *NvRamSize
+  );
+
+EFI_STATUS
+EFIAPI
+FlashEraseCommand (
+  IN UINT8  *pBlockAddress,
+  IN UINT32 Length
+  );
+
+EFI_STATUS
+EFIAPI
+FlashProgramCommand (
+  IN     UINT8 *pByteAddress,
+  IN     UINT8 *Byte,
+  IN OUT UINTN *Length
+  );
+
+EFI_STATUS
+EFIAPI
+FlashReadCommand (
+  IN     UINT8 *pByteAddress,
+  OUT    UINT8 *Byte,
+  IN OUT UINTN *Length
+  );
+
+#endif /* FLASH_LIB_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
new file mode 100644
index 000000000000..dcd92151b7d2
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
@@ -0,0 +1,525 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/FlashLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+//
+// These temporary buffers are used to calculate and convert linear virtual
+// to physical address
+//
+STATIC UINT64 mNvFlashBase;
+STATIC UINT32 mNvFlashSize;
+STATIC UINT32 mFlashBlockSize;
+STATIC UINT64 mNvStorageBase;
+STATIC UINT64 mNvStorageSize;
+
+/**
+  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
+**/
+VOID
+EFIAPI
+FlashFvbAddressChangeEvent (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
+}
+
+/**
+  The GetAttributes() 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
+FlashFvbDxeGetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  OUT      EFI_FVB_ATTRIBUTES_2                *Attributes
+  )
+{
+  ASSERT (Attributes != NULL);
+
+  *Attributes = EFI_FVB2_READ_ENABLED_CAP   | // Reads may be enabled
+                EFI_FVB2_READ_STATUS        | // Reads are currently enabled
+                EFI_FVB2_WRITE_STATUS       | // Writes are currently enabled
+                EFI_FVB2_WRITE_ENABLED_CAP  | // Writes may be 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_ALIGNMENT          |
+                EFI_FVB2_ERASE_POLARITY;      // After erasure all bits take this value (i.e. '1')
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The SetAttributes() function sets configurable firmware volume
+  attributes and returns the new settings of the firmware volume.
+
+  @param This         Indicates the 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. Type
+                      EFI_FVB_ATTRIBUTES_2 is defined in
+                      EFI_FIRMWARE_VOLUME_HEADER.
+
+  @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
+FlashFvbDxeSetAttributes (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  IN OUT   EFI_FVB_ATTRIBUTES_2                *Attributes
+  )
+{
+  return EFI_SUCCESS;  // ignore for now
+}
+
+/**
+  The GetPhysicalAddress() function retrieves the base address of
+  a memory-mapped firmware volume. This function should be called
+  only for memory-mapped firmware volumes.
+
+  @param This     Indicates the 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_UNSUPPORTED   The firmware volume is not memory mapped.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeGetPhysicalAddress (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  OUT      EFI_PHYSICAL_ADDRESS                *Address
+  )
+{
+  ASSERT (Address != NULL);
+
+  *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  The GetBlockSize() function retrieves the size of the requested
+  block. It also returns the number of additional blocks with
+  the identical size. The GetBlockSize() function is used to
+  retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+  @param This           Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+  @param Lba            Indicates the block for which to return the size.
+
+  @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
+FlashFvbDxeGetBlockSize (
+  IN  CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  IN        EFI_LBA                             Lba,
+  OUT       UINTN                               *BlockSize,
+  OUT       UINTN                               *NumberOfBlocks
+  )
+{
+  UINTN TotalNvStorageBlocks;
+
+  ASSERT (BlockSize != NULL);
+  ASSERT (NumberOfBlocks != NULL);
+
+  TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
+
+  if (TotalNvStorageBlocks <= (UINTN)Lba) {
+    DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
+    return EFI_INVALID_PARAMETER;
+  }
+
+  *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
+  *BlockSize = mFlashBlockSize;
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Reads the specified number of bytes into a buffer from the specified block.
+
+  The Read() 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 Read() function must return the status code
+  EFI_ACCESS_DENIED without modifying the contents of the
+  buffer. The Read() 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     Indicates the 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
+FlashFvbDxeRead (
+  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 Status;
+
+  ASSERT (NumBytes != NULL);
+  ASSERT (Buffer != NULL);
+
+  if (Offset + *NumBytes > mFlashBlockSize) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  Status = FlashReadCommand (
+             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
+             Buffer,
+             NumBytes
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Writes the specified number of bytes from the input buffer to the block.
+
+  The Write() 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 Write()
+  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
+  Write() function,  it is recommended for the caller to first call
+  the EraseBlocks() 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 Write() function must
+  return the status code EFI_ACCESS_DENIED without modifying the
+  contents of the firmware volume. The Write() 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 Write() service
+  returns.
+
+  @param This     Indicates the 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
+FlashFvbDxeWrite (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  IN       EFI_LBA                             Lba,
+  IN       UINTN                               Offset,
+  IN OUT   UINTN                               *NumBytes,
+  IN       UINT8                               *Buffer
+  )
+{
+  EFI_STATUS Status;
+
+  ASSERT (NumBytes != NULL);
+  ASSERT (Buffer != NULL);
+
+  if (Offset + *NumBytes > mFlashBlockSize) {
+    return EFI_BAD_BUFFER_SIZE;
+  }
+
+  Status = FlashProgramCommand (
+             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
+             Buffer,
+             NumBytes
+             );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return Status;
+}
+
+/**
+  Erases and initializes a firmware volume block.
+
+  The EraseBlocks() 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 EraseBlocks() 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 EraseBlocks() function must return the
+  status code EFI_ACCESS_DENIED without modifying the contents of
+  the firmware volume. All calls to EraseBlocks() must be fully
+  flushed to the hardware before the EraseBlocks() service
+  returns.
+
+  @param This   Indicates the 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. For example, the
+                following indicates that two ranges of blocks
+                (5-7 and 10-11) are to be erased: EraseBlocks
+                (This, 5, 3, 10, 2, 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
+FlashFvbDxeErase (
+  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+  ...
+  )
+{
+  VA_LIST    Args;
+  EFI_LBA    Start;
+  UINTN      Length;
+  EFI_STATUS Status;
+
+  Status = EFI_SUCCESS;
+
+  VA_START (Args, This);
+
+  for (Start = VA_ARG (Args, EFI_LBA);
+       Start != EFI_LBA_LIST_TERMINATOR;
+       Start = VA_ARG (Args, EFI_LBA))
+  {
+    Length = VA_ARG (Args, UINTN);
+    Status = FlashEraseCommand (
+               (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
+               Length * mFlashBlockSize
+               );
+  }
+
+  VA_END (Args);
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
+  FlashFvbDxeGetAttributes,
+  FlashFvbDxeSetAttributes,
+  FlashFvbDxeGetPhysicalAddress,
+  FlashFvbDxeGetBlockSize,
+  FlashFvbDxeRead,
+  FlashFvbDxeWrite,
+  FlashFvbDxeErase
+};
+
+EFI_STATUS
+EFIAPI
+FlashFvbDxeInitialize (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_STATUS Status;
+  EFI_HANDLE FvbHandle = NULL;
+  EFI_EVENT  VirtualAddressChangeEvent;
+
+  // Get NV store FV info
+  mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
+  mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
+  mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+                   FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+                   FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  DEBUG ((
+    DEBUG_INFO,
+    "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
+    __FUNCTION__,
+    mNvStorageBase,
+    mNvStorageSize
+    ));
+
+  // Get NV Flash information
+  Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  if (mNvFlashSize >= (mNvStorageSize * 2)) {
+    DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
+  } else {
+    DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
+    return EFI_DEVICE_ERROR;
+  }
+
+  Status = gBS->CreateEventEx (
+                  EVT_NOTIFY_SIGNAL,
+                  TPL_NOTIFY,
+                  FlashFvbAddressChangeEvent,
+                  NULL,
+                  &gEfiEventVirtualAddressChangeGuid,
+                  &VirtualAddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->InstallMultipleProtocolInterfaces (
+                  &FvbHandle,
+                  &gEfiFirmwareVolumeBlockProtocolGuid,
+                  &mFlashFvbProtocol,
+                  NULL
+                  );
+
+  if (EFI_ERROR (Status)) {
+    DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
+    return Status;
+  }
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
new file mode 100644
index 000000000000..6bfbbbebaa85
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
@@ -0,0 +1,283 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Uefi.h>
+
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MmCommunicationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <MmLib.h>
+
+// Convert to string
+#define _STR(x)          #x
+
+// Make sure the argument is expanded before converting to string
+#define STR(x)          _STR(x)
+
+// Use dynamic UEFI_UUID of each build time
+#define UEFI_UUID_BUILD      STR(UEFI_UUID)
+
+EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
+
+STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
+STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
+
+STATIC
+EFI_STATUS
+UefiMmCreateSpiNorReq (
+  VOID   *Data,
+  UINT64 Size
+  )
+{
+  CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
+  mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
+
+  if (Size != 0) {
+    ASSERT (Data);
+    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
+
+    CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Entry point function for the PEIM
+
+  @param FileHandle      Handle of the file being invoked.
+  @param PeiServices     Describes the list of possible PEI Services.
+
+  @return EFI_SUCCESS    If we installed our PPI
+
+**/
+EFI_STATUS
+EFIAPI
+FlashPeiEntryPoint (
+  IN       EFI_PEI_FILE_HANDLE FileHandle,
+  IN CONST EFI_PEI_SERVICES    **PeiServices
+  )
+{
+  UINT64                               FWNvRamStartOffset;
+  EFI_STATUS                           Status;
+  EFI_MM_COMMUNICATE_SPINOR_RES        *MmSpiNorRes;
+  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
+  UINT64                               MmData[5];
+  UINTN                                Size;
+  VOID                                 *NvRamAddress;
+  UINTN                                NvRamSize;
+
+#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
+  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
+  UINT64                               NV2Base, NV2Size;
+#endif
+
+  NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
+  NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+              FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+              FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+  /* Find out about the start offset of NVRAM to be passed to SMC */
+  ZeroMem ((VOID *)MmData, sizeof (MmData));
+  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
+  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+  Status = MmCommunicationCommunicate (
+             (VOID *)&mEfiMmSpiNorReq,
+             &Size
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
+  if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
+    /* Old FW so just exit */
+    return EFI_SUCCESS;
+  }
+  FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
+
+  CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
+  if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
+    /* NVRAM size provided by FW is not enough */
+    return EFI_INVALID_PARAMETER;
+  }
+
+  /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
+  ZeroMem ((VOID *)MmData, sizeof (MmData));
+  MmData[0] = MM_SPINOR_FUNC_READ;
+  MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+  MmData[2] = (UINT64)sizeof (mStoredUuid);
+  MmData[3] = (UINT64)mStoredUuid;
+  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+  Status = MmCommunicationCommunicate (
+             (VOID *)&mEfiMmSpiNorReq,
+             &Size
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+    return Status;
+  }
+
+  if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
+    ZeroMem ((VOID *)MmData, sizeof (MmData));
+    MmData[0] = MM_SPINOR_FUNC_ERASE;
+    MmData[1] = (UINT64)FWNvRamStartOffset;
+    MmData[2] = (UINT64)(NvRamSize * 2);
+    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = MmCommunicationCommunicate (
+               (VOID *)&mEfiMmSpiNorReq,
+               &Size
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      return Status;
+    }
+
+    ZeroMem ((VOID *)MmData, sizeof (MmData));
+    MmData[0] = MM_SPINOR_FUNC_WRITE;
+    MmData[1] = (UINT64)FWNvRamStartOffset;
+    MmData[2] = (UINT64)(NvRamSize * 2);
+    MmData[3] = (UINT64)NvRamAddress;
+    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = MmCommunicationCommunicate (
+               (VOID *)&mEfiMmSpiNorReq,
+               &Size
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      return Status;
+    }
+
+    /* Update UUID */
+    ZeroMem ((VOID *)MmData, sizeof (MmData));
+    MmData[0] = MM_SPINOR_FUNC_ERASE;
+    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+    MmData[2] = (UINT64)sizeof (mBuildUuid);
+    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = MmCommunicationCommunicate (
+               (VOID *)&mEfiMmSpiNorReq,
+               &Size
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      return Status;
+    }
+
+    ZeroMem ((VOID *)MmData, sizeof (MmData));
+    MmData[0] = MM_SPINOR_FUNC_WRITE;
+    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+    MmData[2] = (UINT64)sizeof (mBuildUuid);
+    MmData[3] = (UINT64)mBuildUuid;
+    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = MmCommunicationCommunicate (
+               (VOID *)&mEfiMmSpiNorReq,
+               &Size
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      return Status;
+    }
+    DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
+
+    /* Indicate that NVRAM was cleared */
+    PcdSetBoolS (PcdNvramErased, TRUE);
+  } else {
+    /* Copy the stored NVRAM to RAM */
+    ZeroMem ((VOID *)MmData, sizeof (MmData));
+    MmData[0] = MM_SPINOR_FUNC_READ;
+    MmData[1] = (UINT64)FWNvRamStartOffset;
+    MmData[2] = (UINT64)(NvRamSize * 2);
+    MmData[3] = (UINT64)NvRamAddress;
+    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = MmCommunicationCommunicate (
+               (VOID *)&mEfiMmSpiNorReq,
+               &Size
+               );
+    ASSERT_EFI_ERROR (Status);
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      return Status;
+    }
+    DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
+  }
+
+#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
+  /* Find out about the start offset of NVRAM2 to be passed to SMC */
+  ZeroMem ((VOID *)MmData, sizeof (MmData));
+  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
+  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+  Status = MmCommunicationCommunicate (
+             (VOID *)&mEfiMmSpiNorReq,
+             &Size
+             );
+  ASSERT_EFI_ERROR (Status);
+
+  MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
+  if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
+    NV2Base = MmSpiNorNV2InfoRes->NVBase;
+    NV2Size = MmSpiNorNV2InfoRes->NVSize;
+    /* Make sure the requested size is smaller than allocated */
+    if (RAM_BLOCKIO_SIZE <= NV2Size) {
+      /* Copy the ramdisk image to RAM */
+      ZeroMem ((VOID *)MmData, sizeof (MmData));
+      MmData[0] = MM_SPINOR_FUNC_READ;
+      MmData[1] = (UINT64)NV2Base; /* Start virtual address */
+      MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
+      MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
+      UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+      Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+      Status = MmCommunicationCommunicate (
+                 (VOID *)&mEfiMmSpiNorReq,
+                 &Size
+                 );
+      ASSERT_EFI_ERROR (Status);
+
+      MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+      ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
+    }
+
+    BuildMemoryAllocationHob (
+      (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
+      EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
+      EfiLoaderData
+      );
+  }
+#endif
+
+  return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
new file mode 100644
index 000000000000..cd77aed3cfe1
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
@@ -0,0 +1,358 @@
+/** @file
+
+  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FlashLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <MmLib.h>
+#include <Protocol/MmCommunication.h>
+
+STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
+STATIC EFI_MM_COMM_REQUEST           *mCommBuffer              = NULL;
+
+BOOLEAN mIsEfiRuntime;
+UINT8   *mTmpBufVirt;
+UINT8   *mTmpBufPhy;
+
+/**
+  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+  event. It converts a pointer to a new virtual address.
+
+  @param  Event        Event whose notification function is being invoked.
+  @param  Context      Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+FlashLibAddressChangeEvent (
+  IN EFI_EVENT Event,
+  IN VOID      *Context
+  )
+{
+  gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
+  gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
+  gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
+
+  mIsEfiRuntime = TRUE;
+}
+
+EFI_STATUS
+EFIAPI
+FlashLibConstructor (
+  IN EFI_HANDLE       ImageHandle,
+  IN EFI_SYSTEM_TABLE *SystemTable
+  )
+{
+  EFI_EVENT  VirtualAddressChangeEvent = NULL;
+  EFI_STATUS Status = EFI_SUCCESS;
+
+  mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
+  ASSERT (mCommBuffer != NULL);
+
+  mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
+  mTmpBufVirt = mTmpBufPhy;
+  ASSERT (mTmpBufPhy != NULL);
+
+  Status = gBS->LocateProtocol (
+                  &gEfiMmCommunicationProtocolGuid,
+                  NULL,
+                  (VOID **)&mMmCommunicationProtocol
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  Status = gBS->CreateEvent (
+                  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+                  TPL_CALLBACK,
+                  FlashLibAddressChangeEvent,
+                  NULL,
+                  &VirtualAddressChangeEvent
+                  );
+  ASSERT_EFI_ERROR (Status);
+
+  return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FlashMmCommunicate (
+  IN OUT VOID  *CommBuffer,
+  IN OUT UINTN *CommSize
+  )
+{
+  if (mMmCommunicationProtocol == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  return mMmCommunicationProtocol->Communicate (
+                                     mMmCommunicationProtocol,
+                                     CommBuffer,
+                                     CommSize
+                                     );
+}
+
+STATIC
+EFI_STATUS
+UefiMmCreateSpiNorReq (
+  IN VOID   *Data,
+  IN UINT64 Size
+  )
+{
+  if (mCommBuffer == NULL) {
+    return EFI_INVALID_PARAMETER;
+  }
+
+  CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
+  mCommBuffer->EfiMmHdr.MsgLength = Size;
+
+  if (Size != 0) {
+    ASSERT (Data);
+    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
+
+    CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
+  }
+
+  return EFI_SUCCESS;
+}
+
+/**
+  Convert Virtual Address to Physical Address at Runtime Services
+
+  @param  VirtualPtr          Virtual Address Pointer
+  @param  Size                Total bytes of the buffer
+
+  @retval Ptr                 Return the pointer of the converted address
+
+**/
+STATIC
+UINT8 *
+ConvertVirtualToPhysical (
+  IN UINT8 *VirtualPtr,
+  IN UINTN Size
+  )
+{
+  if (mIsEfiRuntime) {
+    ASSERT (VirtualPtr != NULL);
+    CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
+    return (UINT8 *)mTmpBufPhy;
+  }
+
+  return (UINT8 *)VirtualPtr;
+}
+
+/**
+  Convert Physical Address to Virtual Address at Runtime Services
+
+  @param  VirtualPtr          Physical Address Pointer
+  @param  Size                Total bytes of the buffer
+
+**/
+STATIC
+VOID
+ConvertPhysicaltoVirtual (
+  IN UINT8 *PhysicalPtr,
+  IN UINTN Size
+  )
+{
+  if (mIsEfiRuntime) {
+    ASSERT (PhysicalPtr != NULL);
+    CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
+  }
+}
+
+EFI_STATUS
+EFIAPI
+FlashGetNvRamInfo (
+  OUT UINT64 *NvRamBase,
+  OUT UINT32 *NvRamSize
+  )
+{
+  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
+  EFI_STATUS                           Status;
+  UINT64                               MmData[5];
+  UINTN                                Size;
+
+  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
+
+  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+  Status = FlashMmCommunicate (
+             mCommBuffer,
+             &Size
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
+  if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
+    *NvRamBase = MmSpiNorNVInfoRes->NVBase;
+    *NvRamSize = MmSpiNorNVInfoRes->NVSize;
+    DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashEraseCommand (
+  IN UINT8  *pBlockAddress,
+  IN UINT32 Length
+  )
+{
+  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+  EFI_STATUS                    Status;
+  UINT64                        MmData[5];
+  UINTN                         Size;
+
+  ASSERT (pBlockAddress != NULL);
+
+  MmData[0] = MM_SPINOR_FUNC_ERASE;
+  MmData[1] = (UINT64)pBlockAddress;
+  MmData[2] = Length;
+
+  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+  Status = FlashMmCommunicate (
+             mCommBuffer,
+             &Size
+             );
+  if (EFI_ERROR (Status)) {
+    return Status;
+  }
+
+  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+    DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
+    return EFI_DEVICE_ERROR;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashProgramCommand (
+  IN     UINT8 *pByteAddress,
+  IN     UINT8 *Byte,
+  IN OUT UINTN *Length
+  )
+{
+  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+  EFI_STATUS                    Status;
+  UINT64                        MmData[5];
+  UINTN                         Remain, Size, NumWrite;
+  UINTN                         Count = 0;
+
+  ASSERT (pByteAddress != NULL);
+  ASSERT (Byte != NULL);
+  ASSERT (Length != NULL);
+
+  Remain = *Length;
+  while (Remain > 0) {
+    NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
+
+    MmData[0] = MM_SPINOR_FUNC_WRITE;
+    MmData[1] = (UINT64)pByteAddress;
+    MmData[2] = NumWrite;
+    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
+
+    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = FlashMmCommunicate (
+               mCommBuffer,
+               &Size
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
+      return EFI_DEVICE_ERROR;
+    }
+
+    Remain -= NumWrite;
+    Count += NumWrite;
+  }
+
+  return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashReadCommand (
+  IN     UINT8 *pByteAddress,
+  OUT    UINT8 *Byte,
+  IN OUT UINTN *Length
+  )
+{
+  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+  EFI_STATUS                    Status;
+  UINT64                        MmData[5];
+  UINTN                         Remain, Size, NumRead;
+  UINTN                         Count = 0;
+
+  ASSERT (pByteAddress != NULL);
+  ASSERT (Byte != NULL);
+  ASSERT (Length != NULL);
+
+  Remain = *Length;
+  while (Remain > 0) {
+    NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
+
+    MmData[0] = MM_SPINOR_FUNC_READ;
+    MmData[1] = (UINT64)pByteAddress;
+    MmData[2] = NumRead;
+    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
+
+    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+    Status = FlashMmCommunicate (
+               mCommBuffer,
+               &Size
+               );
+    if (EFI_ERROR (Status)) {
+      return Status;
+    }
+
+    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+      DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
+      return EFI_DEVICE_ERROR;
+    }
+
+    ConvertPhysicaltoVirtual (Byte + Count, NumRead);
+    Remain -= NumRead;
+    Count += NumRead;
+  }
+
+  return EFI_SUCCESS;
+}
-- 
2.17.1



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#75617): https://edk2.groups.io/g/devel/message/75617
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables
Posted by Leif Lindholm 4 years, 8 months ago
On Wed, May 26, 2021 at 17:07:01 +0700, Nhi Pham wrote:
> From: Vu Nguyen <vunguyen@os.amperecomputing.com>
> 
> Non-volatile variables now can be stored on flash. MM communication
> protocol is used to access storage on flash.
> 
> Included in this change are:
> * FlashPei module is used to compare saved UUID with firmware's
>   UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
>   Otherwise fill the storage with default value from NVRAM FV.
> * FlashLib provide APIs to access flash through MM Communication
>   protocol
> * FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
>   used by the variable services to get/set variables.
> 
> Cc: Thang Nguyen <thang@os.amperecomputing.com>
> Cc: Chuong Tran <chuong@os.amperecomputing.com>
> Cc: Phong Vo <phong@os.amperecomputing.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
> 
> Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
> ---
>  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                  |   3 +
>  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec              |   3 +
>  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc              |  11 +-
>  Platform/Ampere/JadePkg/Jade.dsc                                  |   1 +
>  Platform/Ampere/JadePkg/Jade.fdf                                  |  62 ++-
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf |  54 ++
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf       |  51 ++
>  Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf       |  36 ++
>  Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h          |  42 ++
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c   | 525 ++++++++++++++++++++
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c         | 283 +++++++++++
>  Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c         | 358 +++++++++++++
>  12 files changed, 1425 insertions(+), 4 deletions(-)
> 
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> index be827dd19a96..d5b12a81e9bf 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> @@ -37,6 +37,9 @@ [LibraryClasses]
>    ##  @libraryclass  Defines a set of methods to communicate with secure parition over MM interface.
>    MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
>  
> +  ##  @libraryclass  Defines a set of methods to access flash memory.
> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> +
>    ##  @libraryclass  Defines a set of methods to generate random numbers by using Hardware RNG.
>    TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
>  
> diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> index 6ebdf7db0a57..26e020715290 100755
> --- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> @@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
>    # Firmware Volume Pcds
>    #
>    gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
> +
> +  # NVRam Pcds
> +  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> index 9f75da6f05ad..65973569a41d 100755
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> @@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
>  
>  [BuildOptions]
>    GCC:RELEASE_*_*_CC_FLAGS  = -DMDEPKG_NDEBUG
> +  GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)

This isn't obvious enough. I'm a bear of very little brain, and I
could possibly figure out what's happening here, given time, but
please put a proper description in commit message (and possibly here?
whatever makes sense).

>  
>  [LibraryClasses.common]
>  !if $(TARGET) == RELEASE
> @@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
>    SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
>    PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
>    MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>  
>  [LibraryClasses.common.UEFI_APPLICATION]
>    UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
> @@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>  
>    EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
>    ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>  
>  [LibraryClasses.ARM,LibraryClasses.AARCH64]
>    #
> @@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
>    gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
>  
> +  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
> +
>  ################################################################################
>  #
>  # Component Section - list of all EDK II Component Entries defined by this Platform
> @@ -520,8 +525,10 @@ [Components.common]
>    Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>    Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>    Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
> +  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>    ArmPkg/Drivers/CpuPei/CpuPei.inf
>    UefiCpuPkg/CpuIoPei/CpuIoPei.inf
> +  MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>    MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>    MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
>      <LibraryClasses>
> @@ -575,9 +582,9 @@ [Components.common]
>    #
>    # Environment Variables Protocol
>    #
> +  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> +  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>    MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
> -    <PcdsFixedAtBuild>
> -      gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
>      <LibraryClasses>
>        BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
>        TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
> index f37ab1a92e44..9b9a5d0bad0f 100755
> --- a/Platform/Ampere/JadePkg/Jade.dsc
> +++ b/Platform/Ampere/JadePkg/Jade.dsc
> @@ -52,6 +52,7 @@ [Defines]
>    DEFINE EDK2_SKIP_PEICORE       = TRUE
>    DEFINE SECURE_BOOT_ENABLE      = FALSE
>    DEFINE INCLUDE_TFTP_COMMAND    = TRUE
> +  DEFINE UEFI_UUID               = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5

This is a horrible name for a UUID. What is it meant to identify?

>    #
>    # Network definition
> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
> index 1857296a8ea5..375455086d0b 100755
> --- a/Platform/Ampere/JadePkg/Jade.fdf
> +++ b/Platform/Ampere/JadePkg/Jade.fdf
> @@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
>  ErasePolarity = 1
>  
>  # This one is tricky, it must be: BlockSize * NumBlocks = Size
> -BlockSize     = 0x10000
> +BlockSize     = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
>  NumBlocks     = 0x7C
>  
>  ################################################################################
> @@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
>  
>  #
>  # NV Variables
> -# T.B.D

Ah. If I can make a retroactive comment - could this be introduced as
"Placeholder" rather than "T.B.D."?

/
    Leif

> +# Offset: 0x00740000
> +# Size:   0x00080000
>  #
> +0x00740000|0x00030000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +DATA = {
> +  ## This is the EFI_FIRMWARE_VOLUME_HEADER
> +  # ZeroVector []
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  # FileSystemGuid: gEfiSystemNvDataFvGuid         =
> +  #   { 0xFFF12B8D, 0x7696, 0x4C8B,
> +  #     { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
> +  0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
> +  0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
> +  # FvLength: 0x80000
> +  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  # Signature "_FVH"       # Attributes
> +  0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
> +  # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
> +  0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
> +  # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
> +  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
> +  # Blockmap[1]: End
> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> +  ## This is the VARIABLE_STORE_HEADER
> +  # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
> +  # Signature: gEfiAuthenticatedVariableGuid =
> +  #   { 0xaaf32c78, 0x947b, 0x439a,
> +  #     { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
> +  0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
> +  0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
> +  # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
> +  #         0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
> +  # This can speed up the Variable Dispatch a bit.
> +  0xB8, 0xFF, 0x02, 0x00,
> +  # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
> +  0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +}
> +
> +0x00770000|0x00010000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +DATA = {
> +  # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
> +  #  { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
> +  0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
> +  0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95,
> +  # Crc:UINT32            #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
> +  0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
> +  # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
> +  0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +}
> +
> +0x00780000|0x00040000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>  
>  ################################################################################
>  #
> @@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
>    INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>    INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>    INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>    INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
>    INF ArmPkg/Drivers/CpuPei/CpuPei.inf
>    INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
> +  INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>    INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>    INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
>    INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
> @@ -144,6 +199,7 @@ [FV.FvMain]
>    INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
>    INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
>    INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>  }
>  
>    INF MdeModulePkg/Core/Dxe/DxeMain.inf
> @@ -173,6 +229,8 @@ [FV.FvMain]
>    # Environment Variables Protocol
>    #
>    INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> +  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>  
>    #
>    # Multiple Console IO support
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> new file mode 100644
> index 000000000000..782278615094
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> @@ -0,0 +1,54 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = FlashFvbDxe
> +  FILE_GUID                      = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
> +  VERSION_STRING                 = 0.1
> +  ENTRY_POINT                    = FlashFvbDxeInitialize
> +
> +[Sources]
> +  FlashFvbDxe.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> +  DebugLib
> +  FlashLib
> +  PcdLib
> +  UefiBootServicesTableLib
> +  UefiDriverEntryPoint
> +  UefiRuntimeLib
> +
> +[FixedPcd]
> +  gAmpereTokenSpaceGuid.PcdFvBlockSize
> +
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
> +
> +[Guids]
> +  gEfiEventVirtualAddressChangeGuid
> +  gSpiNorMmGuid
> +
> +[Protocols]
> +  gEfiFirmwareVolumeBlockProtocolGuid             ## PRODUCES
> +  gEfiMmCommunicationProtocolGuid                 ## CONSUMES
> +
> +[Depex]
> +  gEfiMmCommunicationProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> new file mode 100644
> index 000000000000..a4eaf5039bb0
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> @@ -0,0 +1,51 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                    = 0x0001001B
> +  BASE_NAME                      = FlashPei
> +  FILE_GUID                      = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
> +  MODULE_TYPE                    = PEIM
> +  VERSION_STRING                 = 1.0
> +  ENTRY_POINT                    = FlashPeiEntryPoint
> +
> +[Sources]
> +  FlashPei.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  MdeModulePkg/MdeModulePkg.dec
> +  MdePkg/MdePkg.dec
> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> +  ArmSmcLib
> +  BaseMemoryLib
> +  DebugLib
> +  MmCommunicationLib
> +  PcdLib
> +  PeimEntryPoint
> +
> +[Guids]
> +  gSpiNorMmGuid
> +
> +[FixedPcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +[Pcd]
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
> +
> +  gAmpereTokenSpaceGuid.PcdNvramErased
> +
> +[Depex]
> +  TRUE
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
> new file mode 100644
> index 000000000000..2d5003d1af17
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
> @@ -0,0 +1,36 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> +  INF_VERSION                   = 0x0001001B
> +  BASE_NAME                     = FlashLib
> +  FILE_GUID                     = 9E9D093D-6484-45AE-BA49-0745AA0BB481
> +  MODULE_TYPE                   = DXE_DRIVER
> +  VERSION_STRING                = 0.1
> +  LIBRARY_CLASS                 = FlashLib
> +  CONSTRUCTOR                   = FlashLibConstructor
> +
> +[Sources.common]
> +  FlashLib.c
> +
> +[Packages]
> +  ArmPkg/ArmPkg.dec
> +  ArmPlatformPkg/ArmPlatformPkg.dec
> +  MdePkg/MdePkg.dec
> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +
> +[LibraryClasses]
> +  BaseMemoryLib
> +  DebugLib
> +  MemoryAllocationLib
> +
> +[Guids]
> +  gSpiNorMmGuid
> +
> +[Protocols]
> +  gEfiMmCommunicationProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> new file mode 100644
> index 000000000000..9207dee643a5
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> @@ -0,0 +1,42 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef FLASH_LIB_H_
> +#define FLASH_LIB_H_
> +
> +EFI_STATUS
> +EFIAPI
> +FlashGetNvRamInfo (
> +  OUT UINT64 *NvRamBase,
> +  OUT UINT32 *NvRamSize
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashEraseCommand (
> +  IN UINT8  *pBlockAddress,
> +  IN UINT32 Length
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashProgramCommand (
> +  IN     UINT8 *pByteAddress,
> +  IN     UINT8 *Byte,
> +  IN OUT UINTN *Length
> +  );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashReadCommand (
> +  IN     UINT8 *pByteAddress,
> +  OUT    UINT8 *Byte,
> +  IN OUT UINTN *Length
> +  );
> +
> +#endif /* FLASH_LIB_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
> new file mode 100644
> index 000000000000..dcd92151b7d2
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
> @@ -0,0 +1,525 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/DebugLib.h>
> +#include <Library/FlashLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeLib.h>
> +#include <Protocol/FirmwareVolumeBlock.h>
> +
> +//
> +// These temporary buffers are used to calculate and convert linear virtual
> +// to physical address
> +//
> +STATIC UINT64 mNvFlashBase;
> +STATIC UINT32 mNvFlashSize;
> +STATIC UINT32 mFlashBlockSize;
> +STATIC UINT64 mNvStorageBase;
> +STATIC UINT64 mNvStorageSize;
> +
> +/**
> +  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
> +**/
> +VOID
> +EFIAPI
> +FlashFvbAddressChangeEvent (
> +  IN EFI_EVENT Event,
> +  IN VOID      *Context
> +  )
> +{
> +  EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
> +}
> +
> +/**
> +  The GetAttributes() 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
> +FlashFvbDxeGetAttributes (
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  OUT      EFI_FVB_ATTRIBUTES_2                *Attributes
> +  )
> +{
> +  ASSERT (Attributes != NULL);
> +
> +  *Attributes = EFI_FVB2_READ_ENABLED_CAP   | // Reads may be enabled
> +                EFI_FVB2_READ_STATUS        | // Reads are currently enabled
> +                EFI_FVB2_WRITE_STATUS       | // Writes are currently enabled
> +                EFI_FVB2_WRITE_ENABLED_CAP  | // Writes may be 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_ALIGNMENT          |
> +                EFI_FVB2_ERASE_POLARITY;      // After erasure all bits take this value (i.e. '1')
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  The SetAttributes() function sets configurable firmware volume
> +  attributes and returns the new settings of the firmware volume.
> +
> +  @param This         Indicates the 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. Type
> +                      EFI_FVB_ATTRIBUTES_2 is defined in
> +                      EFI_FIRMWARE_VOLUME_HEADER.
> +
> +  @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
> +FlashFvbDxeSetAttributes (
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  IN OUT   EFI_FVB_ATTRIBUTES_2                *Attributes
> +  )
> +{
> +  return EFI_SUCCESS;  // ignore for now
> +}
> +
> +/**
> +  The GetPhysicalAddress() function retrieves the base address of
> +  a memory-mapped firmware volume. This function should be called
> +  only for memory-mapped firmware volumes.
> +
> +  @param This     Indicates the 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_UNSUPPORTED   The firmware volume is not memory mapped.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeGetPhysicalAddress (
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  OUT      EFI_PHYSICAL_ADDRESS                *Address
> +  )
> +{
> +  ASSERT (Address != NULL);
> +
> +  *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  The GetBlockSize() function retrieves the size of the requested
> +  block. It also returns the number of additional blocks with
> +  the identical size. The GetBlockSize() function is used to
> +  retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
> +
> +
> +  @param This           Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> +  @param Lba            Indicates the block for which to return the size.
> +
> +  @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
> +FlashFvbDxeGetBlockSize (
> +  IN  CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  IN        EFI_LBA                             Lba,
> +  OUT       UINTN                               *BlockSize,
> +  OUT       UINTN                               *NumberOfBlocks
> +  )
> +{
> +  UINTN TotalNvStorageBlocks;
> +
> +  ASSERT (BlockSize != NULL);
> +  ASSERT (NumberOfBlocks != NULL);
> +
> +  TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
> +
> +  if (TotalNvStorageBlocks <= (UINTN)Lba) {
> +    DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
> +  *BlockSize = mFlashBlockSize;
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Reads the specified number of bytes into a buffer from the specified block.
> +
> +  The Read() 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 Read() function must return the status code
> +  EFI_ACCESS_DENIED without modifying the contents of the
> +  buffer. The Read() 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     Indicates the 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
> +FlashFvbDxeRead (
> +  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 Status;
> +
> +  ASSERT (NumBytes != NULL);
> +  ASSERT (Buffer != NULL);
> +
> +  if (Offset + *NumBytes > mFlashBlockSize) {
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +
> +  Status = FlashReadCommand (
> +             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
> +             Buffer,
> +             NumBytes
> +             );
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Writes the specified number of bytes from the input buffer to the block.
> +
> +  The Write() 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 Write()
> +  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
> +  Write() function,  it is recommended for the caller to first call
> +  the EraseBlocks() 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 Write() function must
> +  return the status code EFI_ACCESS_DENIED without modifying the
> +  contents of the firmware volume. The Write() 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 Write() service
> +  returns.
> +
> +  @param This     Indicates the 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
> +FlashFvbDxeWrite (
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  IN       EFI_LBA                             Lba,
> +  IN       UINTN                               Offset,
> +  IN OUT   UINTN                               *NumBytes,
> +  IN       UINT8                               *Buffer
> +  )
> +{
> +  EFI_STATUS Status;
> +
> +  ASSERT (NumBytes != NULL);
> +  ASSERT (Buffer != NULL);
> +
> +  if (Offset + *NumBytes > mFlashBlockSize) {
> +    return EFI_BAD_BUFFER_SIZE;
> +  }
> +
> +  Status = FlashProgramCommand (
> +             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
> +             Buffer,
> +             NumBytes
> +             );
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return Status;
> +}
> +
> +/**
> +  Erases and initializes a firmware volume block.
> +
> +  The EraseBlocks() 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 EraseBlocks() 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 EraseBlocks() function must return the
> +  status code EFI_ACCESS_DENIED without modifying the contents of
> +  the firmware volume. All calls to EraseBlocks() must be fully
> +  flushed to the hardware before the EraseBlocks() service
> +  returns.
> +
> +  @param This   Indicates the 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. For example, the
> +                following indicates that two ranges of blocks
> +                (5-7 and 10-11) are to be erased: EraseBlocks
> +                (This, 5, 3, 10, 2, 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
> +FlashFvbDxeErase (
> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> +  ...
> +  )
> +{
> +  VA_LIST    Args;
> +  EFI_LBA    Start;
> +  UINTN      Length;
> +  EFI_STATUS Status;
> +
> +  Status = EFI_SUCCESS;
> +
> +  VA_START (Args, This);
> +
> +  for (Start = VA_ARG (Args, EFI_LBA);
> +       Start != EFI_LBA_LIST_TERMINATOR;
> +       Start = VA_ARG (Args, EFI_LBA))
> +  {
> +    Length = VA_ARG (Args, UINTN);
> +    Status = FlashEraseCommand (
> +               (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
> +               Length * mFlashBlockSize
> +               );
> +  }
> +
> +  VA_END (Args);
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
> +  FlashFvbDxeGetAttributes,
> +  FlashFvbDxeSetAttributes,
> +  FlashFvbDxeGetPhysicalAddress,
> +  FlashFvbDxeGetBlockSize,
> +  FlashFvbDxeRead,
> +  FlashFvbDxeWrite,
> +  FlashFvbDxeErase
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeInitialize (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  EFI_STATUS Status;
> +  EFI_HANDLE FvbHandle = NULL;
> +  EFI_EVENT  VirtualAddressChangeEvent;
> +
> +  // Get NV store FV info
> +  mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
> +  mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
> +  mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
> +                   FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
> +                   FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  DEBUG ((
> +    DEBUG_INFO,
> +    "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
> +    __FUNCTION__,
> +    mNvStorageBase,
> +    mNvStorageSize
> +    ));
> +
> +  // Get NV Flash information
> +  Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  if (mNvFlashSize >= (mNvStorageSize * 2)) {
> +    DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
> +  } else {
> +    DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  Status = gBS->CreateEventEx (
> +                  EVT_NOTIFY_SIGNAL,
> +                  TPL_NOTIFY,
> +                  FlashFvbAddressChangeEvent,
> +                  NULL,
> +                  &gEfiEventVirtualAddressChangeGuid,
> +                  &VirtualAddressChangeEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = gBS->InstallMultipleProtocolInterfaces (
> +                  &FvbHandle,
> +                  &gEfiFirmwareVolumeBlockProtocolGuid,
> +                  &mFlashFvbProtocol,
> +                  NULL
> +                  );
> +
> +  if (EFI_ERROR (Status)) {
> +    DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
> +    return Status;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
> new file mode 100644
> index 000000000000..6bfbbbebaa85
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
> @@ -0,0 +1,283 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <Uefi.h>
> +
> +#include <Library/ArmSmcLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MmCommunicationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <MmLib.h>
> +
> +// Convert to string
> +#define _STR(x)          #x
> +
> +// Make sure the argument is expanded before converting to string
> +#define STR(x)          _STR(x)
> +
> +// Use dynamic UEFI_UUID of each build time
> +#define UEFI_UUID_BUILD      STR(UEFI_UUID)
> +
> +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
> +
> +STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
> +STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
> +
> +STATIC
> +EFI_STATUS
> +UefiMmCreateSpiNorReq (
> +  VOID   *Data,
> +  UINT64 Size
> +  )
> +{
> +  CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
> +  mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
> +
> +  if (Size != 0) {
> +    ASSERT (Data);
> +    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
> +
> +    CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Entry point function for the PEIM
> +
> +  @param FileHandle      Handle of the file being invoked.
> +  @param PeiServices     Describes the list of possible PEI Services.
> +
> +  @return EFI_SUCCESS    If we installed our PPI
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashPeiEntryPoint (
> +  IN       EFI_PEI_FILE_HANDLE FileHandle,
> +  IN CONST EFI_PEI_SERVICES    **PeiServices
> +  )
> +{
> +  UINT64                               FWNvRamStartOffset;
> +  EFI_STATUS                           Status;
> +  EFI_MM_COMMUNICATE_SPINOR_RES        *MmSpiNorRes;
> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
> +  UINT64                               MmData[5];
> +  UINTN                                Size;
> +  VOID                                 *NvRamAddress;
> +  UINTN                                NvRamSize;
> +
> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
> +  UINT64                               NV2Base, NV2Size;
> +#endif
> +
> +  NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
> +  NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
> +              FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
> +              FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> +  /* Find out about the start offset of NVRAM to be passed to SMC */
> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +  Status = MmCommunicationCommunicate (
> +             (VOID *)&mEfiMmSpiNorReq,
> +             &Size
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
> +  if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
> +    /* Old FW so just exit */
> +    return EFI_SUCCESS;
> +  }
> +  FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
> +
> +  CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
> +  if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
> +    /* NVRAM size provided by FW is not enough */
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
> +  MmData[0] = MM_SPINOR_FUNC_READ;
> +  MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> +  MmData[2] = (UINT64)sizeof (mStoredUuid);
> +  MmData[3] = (UINT64)mStoredUuid;
> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +  Status = MmCommunicationCommunicate (
> +             (VOID *)&mEfiMmSpiNorReq,
> +             &Size
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +    return Status;
> +  }
> +
> +  if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_ERASE;
> +    MmData[1] = (UINT64)FWNvRamStartOffset;
> +    MmData[2] = (UINT64)(NvRamSize * 2);
> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = MmCommunicationCommunicate (
> +               (VOID *)&mEfiMmSpiNorReq,
> +               &Size
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      return Status;
> +    }
> +
> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
> +    MmData[1] = (UINT64)FWNvRamStartOffset;
> +    MmData[2] = (UINT64)(NvRamSize * 2);
> +    MmData[3] = (UINT64)NvRamAddress;
> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = MmCommunicationCommunicate (
> +               (VOID *)&mEfiMmSpiNorReq,
> +               &Size
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      return Status;
> +    }
> +
> +    /* Update UUID */
> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_ERASE;
> +    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> +    MmData[2] = (UINT64)sizeof (mBuildUuid);
> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = MmCommunicationCommunicate (
> +               (VOID *)&mEfiMmSpiNorReq,
> +               &Size
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      return Status;
> +    }
> +
> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
> +    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> +    MmData[2] = (UINT64)sizeof (mBuildUuid);
> +    MmData[3] = (UINT64)mBuildUuid;
> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = MmCommunicationCommunicate (
> +               (VOID *)&mEfiMmSpiNorReq,
> +               &Size
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      return Status;
> +    }
> +    DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
> +
> +    /* Indicate that NVRAM was cleared */
> +    PcdSetBoolS (PcdNvramErased, TRUE);
> +  } else {
> +    /* Copy the stored NVRAM to RAM */
> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_READ;
> +    MmData[1] = (UINT64)FWNvRamStartOffset;
> +    MmData[2] = (UINT64)(NvRamSize * 2);
> +    MmData[3] = (UINT64)NvRamAddress;
> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = MmCommunicationCommunicate (
> +               (VOID *)&mEfiMmSpiNorReq,
> +               &Size
> +               );
> +    ASSERT_EFI_ERROR (Status);
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      return Status;
> +    }
> +    DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
> +  }
> +
> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
> +  /* Find out about the start offset of NVRAM2 to be passed to SMC */
> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +  Status = MmCommunicationCommunicate (
> +             (VOID *)&mEfiMmSpiNorReq,
> +             &Size
> +             );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
> +  if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
> +    NV2Base = MmSpiNorNV2InfoRes->NVBase;
> +    NV2Size = MmSpiNorNV2InfoRes->NVSize;
> +    /* Make sure the requested size is smaller than allocated */
> +    if (RAM_BLOCKIO_SIZE <= NV2Size) {
> +      /* Copy the ramdisk image to RAM */
> +      ZeroMem ((VOID *)MmData, sizeof (MmData));
> +      MmData[0] = MM_SPINOR_FUNC_READ;
> +      MmData[1] = (UINT64)NV2Base; /* Start virtual address */
> +      MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
> +      MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
> +      UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> +      Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +      Status = MmCommunicationCommunicate (
> +                 (VOID *)&mEfiMmSpiNorReq,
> +                 &Size
> +                 );
> +      ASSERT_EFI_ERROR (Status);
> +
> +      MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> +      ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
> +    }
> +
> +    BuildMemoryAllocationHob (
> +      (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
> +      EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
> +      EfiLoaderData
> +      );
> +  }
> +#endif
> +
> +  return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
> new file mode 100644
> index 000000000000..cd77aed3cfe1
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
> @@ -0,0 +1,358 @@
> +/** @file
> +
> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> +  SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/FlashLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <MmLib.h>
> +#include <Protocol/MmCommunication.h>
> +
> +STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
> +STATIC EFI_MM_COMM_REQUEST           *mCommBuffer              = NULL;
> +
> +BOOLEAN mIsEfiRuntime;
> +UINT8   *mTmpBufVirt;
> +UINT8   *mTmpBufPhy;
> +
> +/**
> +  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
> +  event. It converts a pointer to a new virtual address.
> +
> +  @param  Event        Event whose notification function is being invoked.
> +  @param  Context      Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +FlashLibAddressChangeEvent (
> +  IN EFI_EVENT Event,
> +  IN VOID      *Context
> +  )
> +{
> +  gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
> +  gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
> +  gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
> +
> +  mIsEfiRuntime = TRUE;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashLibConstructor (
> +  IN EFI_HANDLE       ImageHandle,
> +  IN EFI_SYSTEM_TABLE *SystemTable
> +  )
> +{
> +  EFI_EVENT  VirtualAddressChangeEvent = NULL;
> +  EFI_STATUS Status = EFI_SUCCESS;
> +
> +  mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
> +  ASSERT (mCommBuffer != NULL);
> +
> +  mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
> +  mTmpBufVirt = mTmpBufPhy;
> +  ASSERT (mTmpBufPhy != NULL);
> +
> +  Status = gBS->LocateProtocol (
> +                  &gEfiMmCommunicationProtocolGuid,
> +                  NULL,
> +                  (VOID **)&mMmCommunicationProtocol
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  Status = gBS->CreateEvent (
> +                  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
> +                  TPL_CALLBACK,
> +                  FlashLibAddressChangeEvent,
> +                  NULL,
> +                  &VirtualAddressChangeEvent
> +                  );
> +  ASSERT_EFI_ERROR (Status);
> +
> +  return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +FlashMmCommunicate (
> +  IN OUT VOID  *CommBuffer,
> +  IN OUT UINTN *CommSize
> +  )
> +{
> +  if (mMmCommunicationProtocol == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  return mMmCommunicationProtocol->Communicate (
> +                                     mMmCommunicationProtocol,
> +                                     CommBuffer,
> +                                     CommSize
> +                                     );
> +}
> +
> +STATIC
> +EFI_STATUS
> +UefiMmCreateSpiNorReq (
> +  IN VOID   *Data,
> +  IN UINT64 Size
> +  )
> +{
> +  if (mCommBuffer == NULL) {
> +    return EFI_INVALID_PARAMETER;
> +  }
> +
> +  CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
> +  mCommBuffer->EfiMmHdr.MsgLength = Size;
> +
> +  if (Size != 0) {
> +    ASSERT (Data);
> +    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
> +
> +    CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +/**
> +  Convert Virtual Address to Physical Address at Runtime Services
> +
> +  @param  VirtualPtr          Virtual Address Pointer
> +  @param  Size                Total bytes of the buffer
> +
> +  @retval Ptr                 Return the pointer of the converted address
> +
> +**/
> +STATIC
> +UINT8 *
> +ConvertVirtualToPhysical (
> +  IN UINT8 *VirtualPtr,
> +  IN UINTN Size
> +  )
> +{
> +  if (mIsEfiRuntime) {
> +    ASSERT (VirtualPtr != NULL);
> +    CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
> +    return (UINT8 *)mTmpBufPhy;
> +  }
> +
> +  return (UINT8 *)VirtualPtr;
> +}
> +
> +/**
> +  Convert Physical Address to Virtual Address at Runtime Services
> +
> +  @param  VirtualPtr          Physical Address Pointer
> +  @param  Size                Total bytes of the buffer
> +
> +**/
> +STATIC
> +VOID
> +ConvertPhysicaltoVirtual (
> +  IN UINT8 *PhysicalPtr,
> +  IN UINTN Size
> +  )
> +{
> +  if (mIsEfiRuntime) {
> +    ASSERT (PhysicalPtr != NULL);
> +    CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
> +  }
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashGetNvRamInfo (
> +  OUT UINT64 *NvRamBase,
> +  OUT UINT32 *NvRamSize
> +  )
> +{
> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
> +  EFI_STATUS                           Status;
> +  UINT64                               MmData[5];
> +  UINTN                                Size;
> +
> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
> +
> +  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +  Status = FlashMmCommunicate (
> +             mCommBuffer,
> +             &Size
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
> +  if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
> +    *NvRamBase = MmSpiNorNVInfoRes->NVBase;
> +    *NvRamSize = MmSpiNorNVInfoRes->NVSize;
> +    DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashEraseCommand (
> +  IN UINT8  *pBlockAddress,
> +  IN UINT32 Length
> +  )
> +{
> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> +  EFI_STATUS                    Status;
> +  UINT64                        MmData[5];
> +  UINTN                         Size;
> +
> +  ASSERT (pBlockAddress != NULL);
> +
> +  MmData[0] = MM_SPINOR_FUNC_ERASE;
> +  MmData[1] = (UINT64)pBlockAddress;
> +  MmData[2] = Length;
> +
> +  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +  Status = FlashMmCommunicate (
> +             mCommBuffer,
> +             &Size
> +             );
> +  if (EFI_ERROR (Status)) {
> +    return Status;
> +  }
> +
> +  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> +  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +    DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
> +    return EFI_DEVICE_ERROR;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashProgramCommand (
> +  IN     UINT8 *pByteAddress,
> +  IN     UINT8 *Byte,
> +  IN OUT UINTN *Length
> +  )
> +{
> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> +  EFI_STATUS                    Status;
> +  UINT64                        MmData[5];
> +  UINTN                         Remain, Size, NumWrite;
> +  UINTN                         Count = 0;
> +
> +  ASSERT (pByteAddress != NULL);
> +  ASSERT (Byte != NULL);
> +  ASSERT (Length != NULL);
> +
> +  Remain = *Length;
> +  while (Remain > 0) {
> +    NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
> +
> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
> +    MmData[1] = (UINT64)pByteAddress;
> +    MmData[2] = NumWrite;
> +    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
> +
> +    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = FlashMmCommunicate (
> +               mCommBuffer,
> +               &Size
> +               );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
> +      return EFI_DEVICE_ERROR;
> +    }
> +
> +    Remain -= NumWrite;
> +    Count += NumWrite;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashReadCommand (
> +  IN     UINT8 *pByteAddress,
> +  OUT    UINT8 *Byte,
> +  IN OUT UINTN *Length
> +  )
> +{
> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> +  EFI_STATUS                    Status;
> +  UINT64                        MmData[5];
> +  UINTN                         Remain, Size, NumRead;
> +  UINTN                         Count = 0;
> +
> +  ASSERT (pByteAddress != NULL);
> +  ASSERT (Byte != NULL);
> +  ASSERT (Length != NULL);
> +
> +  Remain = *Length;
> +  while (Remain > 0) {
> +    NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
> +
> +    MmData[0] = MM_SPINOR_FUNC_READ;
> +    MmData[1] = (UINT64)pByteAddress;
> +    MmData[2] = NumRead;
> +    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
> +
> +    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> +    Status = FlashMmCommunicate (
> +               mCommBuffer,
> +               &Size
> +               );
> +    if (EFI_ERROR (Status)) {
> +      return Status;
> +    }
> +
> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> +      DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
> +      return EFI_DEVICE_ERROR;
> +    }
> +
> +    ConvertPhysicaltoVirtual (Byte + Count, NumRead);
> +    Remain -= NumRead;
> +    Count += NumRead;
> +  }
> +
> +  return EFI_SUCCESS;
> +}
> -- 
> 2.17.1
> 


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76090): https://edk2.groups.io/g/devel/message/76090
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-


Re: [edk2-devel] [edk2-platforms][PATCH v2 09/32] AmpereAltraPkg: Support non-volatile variables
Posted by Nhi Pham via groups.io 4 years, 7 months ago
On 6/5/21 06:36, Leif Lindholm wrote:
> On Wed, May 26, 2021 at 17:07:01 +0700, Nhi Pham wrote:
>> From: Vu Nguyen <vunguyen@os.amperecomputing.com>
>>
>> Non-volatile variables now can be stored on flash. MM communication
>> protocol is used to access storage on flash.
>>
>> Included in this change are:
>> * FlashPei module is used to compare saved UUID with firmware's
>>    UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
>>    Otherwise fill the storage with default value from NVRAM FV.
>> * FlashLib provide APIs to access flash through MM Communication
>>    protocol
>> * FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
>>    used by the variable services to get/set variables.
>>
>> Cc: Thang Nguyen <thang@os.amperecomputing.com>
>> Cc: Chuong Tran <chuong@os.amperecomputing.com>
>> Cc: Phong Vo <phong@os.amperecomputing.com>
>> Cc: Leif Lindholm <leif@nuviainc.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
>> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>>
>> Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
>> ---
>>   Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                  |   3 +
>>   Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec              |   3 +
>>   Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc              |  11 +-
>>   Platform/Ampere/JadePkg/Jade.dsc                                  |   1 +
>>   Platform/Ampere/JadePkg/Jade.fdf                                  |  62 ++-
>>   Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf |  54 ++
>>   Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf       |  51 ++
>>   Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf       |  36 ++
>>   Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h          |  42 ++
>>   Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c   | 525 ++++++++++++++++++++
>>   Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c         | 283 +++++++++++
>>   Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c         | 358 +++++++++++++
>>   12 files changed, 1425 insertions(+), 4 deletions(-)
>>
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> index be827dd19a96..d5b12a81e9bf 100644
>> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> @@ -37,6 +37,9 @@ [LibraryClasses]
>>     ##  @libraryclass  Defines a set of methods to communicate with secure parition over MM interface.
>>     MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
>>   
>> +  ##  @libraryclass  Defines a set of methods to access flash memory.
>> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> +
>>     ##  @libraryclass  Defines a set of methods to generate random numbers by using Hardware RNG.
>>     TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
>>   
>> diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> index 6ebdf7db0a57..26e020715290 100755
>> --- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> @@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
>>     # Firmware Volume Pcds
>>     #
>>     gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
>> +
>> +  # NVRam Pcds
>> +  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> index 9f75da6f05ad..65973569a41d 100755
>> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> @@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
>>   
>>   [BuildOptions]
>>     GCC:RELEASE_*_*_CC_FLAGS  = -DMDEPKG_NDEBUG
>> +  GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)
> This isn't obvious enough. I'm a bear of very little brain, and I
> could possibly figure out what's happening here, given time, but
> please put a proper description in commit message (and possibly here?
> whatever makes sense).

Thanks, Leif. I will use a PCD instead of build option flag like above 
and will update the commit message to explain how it works.

Best regards,

Nhi

>
>>   
>>   [LibraryClasses.common]
>>   !if $(TARGET) == RELEASE
>> @@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
>>     SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
>>     PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
>>     MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
>> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>>   
>>   [LibraryClasses.common.UEFI_APPLICATION]
>>     UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
>> @@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>   
>>     EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
>>     ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
>> +  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>>   
>>   [LibraryClasses.ARM,LibraryClasses.AARCH64]
>>     #
>> @@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
>>     gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
>>     gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
>>   
>> +  gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
>> +
>>   ################################################################################
>>   #
>>   # Component Section - list of all EDK II Component Entries defined by this Platform
>> @@ -520,8 +525,10 @@ [Components.common]
>>     Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>>     Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>>     Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
>> +  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>>     ArmPkg/Drivers/CpuPei/CpuPei.inf
>>     UefiCpuPkg/CpuIoPei/CpuIoPei.inf
>> +  MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>>     MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>>     MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
>>       <LibraryClasses>
>> @@ -575,9 +582,9 @@ [Components.common]
>>     #
>>     # Environment Variables Protocol
>>     #
>> +  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> +  MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>>     MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
>> -    <PcdsFixedAtBuild>
>> -      gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
>>       <LibraryClasses>
>>         BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
>>         TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
>> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
>> index f37ab1a92e44..9b9a5d0bad0f 100755
>> --- a/Platform/Ampere/JadePkg/Jade.dsc
>> +++ b/Platform/Ampere/JadePkg/Jade.dsc
>> @@ -52,6 +52,7 @@ [Defines]
>>     DEFINE EDK2_SKIP_PEICORE       = TRUE
>>     DEFINE SECURE_BOOT_ENABLE      = FALSE
>>     DEFINE INCLUDE_TFTP_COMMAND    = TRUE
>> +  DEFINE UEFI_UUID               = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
> This is a horrible name for a UUID. What is it meant to identify?
>
>>     #
>>     # Network definition
>> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
>> index 1857296a8ea5..375455086d0b 100755
>> --- a/Platform/Ampere/JadePkg/Jade.fdf
>> +++ b/Platform/Ampere/JadePkg/Jade.fdf
>> @@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
>>   ErasePolarity = 1
>>   
>>   # This one is tricky, it must be: BlockSize * NumBlocks = Size
>> -BlockSize     = 0x10000
>> +BlockSize     = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
>>   NumBlocks     = 0x7C
>>   
>>   ################################################################################
>> @@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
>>   
>>   #
>>   # NV Variables
>> -# T.B.D
> Ah. If I can make a retroactive comment - could this be introduced as
> "Placeholder" rather than "T.B.D."?
>
> /
>      Leif
>
>> +# Offset: 0x00740000
>> +# Size:   0x00080000
>>   #
>> +0x00740000|0x00030000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +DATA = {
>> +  ## This is the EFI_FIRMWARE_VOLUME_HEADER
>> +  # ZeroVector []
>> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> +  # FileSystemGuid: gEfiSystemNvDataFvGuid         =
>> +  #   { 0xFFF12B8D, 0x7696, 0x4C8B,
>> +  #     { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
>> +  0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
>> +  0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
>> +  # FvLength: 0x80000
>> +  0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
>> +  # Signature "_FVH"       # Attributes
>> +  0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
>> +  # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
>> +  0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
>> +  # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
>> +  0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
>> +  # Blockmap[1]: End
>> +  0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> +  ## This is the VARIABLE_STORE_HEADER
>> +  # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
>> +  # Signature: gEfiAuthenticatedVariableGuid =
>> +  #   { 0xaaf32c78, 0x947b, 0x439a,
>> +  #     { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
>> +  0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
>> +  0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
>> +  # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
>> +  #         0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
>> +  # This can speed up the Variable Dispatch a bit.
>> +  0xB8, 0xFF, 0x02, 0x00,
>> +  # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
>> +  0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +}
>> +
>> +0x00770000|0x00010000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +DATA = {
>> +  # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
>> +  #  { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
>> +  0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
>> +  0xa0, 0xce, 0x65,  0x0, 0xfd, 0x9f, 0x1b, 0x95,
>> +  # Crc:UINT32            #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
>> +  0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
>> +  # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
>> +  0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +}
>> +
>> +0x00780000|0x00040000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>>   
>>   ################################################################################
>>   #
>> @@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
>>     INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>>     INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>>     INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
>> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>>     INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
>>     INF ArmPkg/Drivers/CpuPei/CpuPei.inf
>>     INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
>> +  INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>>     INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>>     INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
>>     INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
>> @@ -144,6 +199,7 @@ [FV.FvMain]
>>     INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
>>     INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
>>     INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
>> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>>   }
>>   
>>     INF MdeModulePkg/Core/Dxe/DxeMain.inf
>> @@ -173,6 +229,8 @@ [FV.FvMain]
>>     # Environment Variables Protocol
>>     #
>>     INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>> +  INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>> +  INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>>   
>>     #
>>     # Multiple Console IO support
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> new file mode 100644
>> index 000000000000..782278615094
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> @@ -0,0 +1,54 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = FlashFvbDxe
>> +  FILE_GUID                      = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
>> +  MODULE_TYPE                    = DXE_RUNTIME_DRIVER
>> +  VERSION_STRING                 = 0.1
>> +  ENTRY_POINT                    = FlashFvbDxeInitialize
>> +
>> +[Sources]
>> +  FlashFvbDxe.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  MdePkg/MdePkg.dec
>> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +
>> +[LibraryClasses]
>> +  DebugLib
>> +  FlashLib
>> +  PcdLib
>> +  UefiBootServicesTableLib
>> +  UefiDriverEntryPoint
>> +  UefiRuntimeLib
>> +
>> +[FixedPcd]
>> +  gAmpereTokenSpaceGuid.PcdFvBlockSize
>> +
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +[Pcd]
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
>> +
>> +[Guids]
>> +  gEfiEventVirtualAddressChangeGuid
>> +  gSpiNorMmGuid
>> +
>> +[Protocols]
>> +  gEfiFirmwareVolumeBlockProtocolGuid             ## PRODUCES
>> +  gEfiMmCommunicationProtocolGuid                 ## CONSUMES
>> +
>> +[Depex]
>> +  gEfiMmCommunicationProtocolGuid
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> new file mode 100644
>> index 000000000000..a4eaf5039bb0
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> @@ -0,0 +1,51 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                    = 0x0001001B
>> +  BASE_NAME                      = FlashPei
>> +  FILE_GUID                      = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
>> +  MODULE_TYPE                    = PEIM
>> +  VERSION_STRING                 = 1.0
>> +  ENTRY_POINT                    = FlashPeiEntryPoint
>> +
>> +[Sources]
>> +  FlashPei.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  MdeModulePkg/MdeModulePkg.dec
>> +  MdePkg/MdePkg.dec
>> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +
>> +[LibraryClasses]
>> +  ArmSmcLib
>> +  BaseMemoryLib
>> +  DebugLib
>> +  MmCommunicationLib
>> +  PcdLib
>> +  PeimEntryPoint
>> +
>> +[Guids]
>> +  gSpiNorMmGuid
>> +
>> +[FixedPcd]
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +[Pcd]
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
>> +  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
>> +
>> +  gAmpereTokenSpaceGuid.PcdNvramErased
>> +
>> +[Depex]
>> +  TRUE
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>> new file mode 100644
>> index 000000000000..2d5003d1af17
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>> @@ -0,0 +1,36 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> +  INF_VERSION                   = 0x0001001B
>> +  BASE_NAME                     = FlashLib
>> +  FILE_GUID                     = 9E9D093D-6484-45AE-BA49-0745AA0BB481
>> +  MODULE_TYPE                   = DXE_DRIVER
>> +  VERSION_STRING                = 0.1
>> +  LIBRARY_CLASS                 = FlashLib
>> +  CONSTRUCTOR                   = FlashLibConstructor
>> +
>> +[Sources.common]
>> +  FlashLib.c
>> +
>> +[Packages]
>> +  ArmPkg/ArmPkg.dec
>> +  ArmPlatformPkg/ArmPlatformPkg.dec
>> +  MdePkg/MdePkg.dec
>> +  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +
>> +[LibraryClasses]
>> +  BaseMemoryLib
>> +  DebugLib
>> +  MemoryAllocationLib
>> +
>> +[Guids]
>> +  gSpiNorMmGuid
>> +
>> +[Protocols]
>> +  gEfiMmCommunicationProtocolGuid
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> new file mode 100644
>> index 000000000000..9207dee643a5
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> @@ -0,0 +1,42 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef FLASH_LIB_H_
>> +#define FLASH_LIB_H_
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashGetNvRamInfo (
>> +  OUT UINT64 *NvRamBase,
>> +  OUT UINT32 *NvRamSize
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashEraseCommand (
>> +  IN UINT8  *pBlockAddress,
>> +  IN UINT32 Length
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashProgramCommand (
>> +  IN     UINT8 *pByteAddress,
>> +  IN     UINT8 *Byte,
>> +  IN OUT UINTN *Length
>> +  );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashReadCommand (
>> +  IN     UINT8 *pByteAddress,
>> +  OUT    UINT8 *Byte,
>> +  IN OUT UINTN *Length
>> +  );
>> +
>> +#endif /* FLASH_LIB_H_ */
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
>> new file mode 100644
>> index 000000000000..dcd92151b7d2
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
>> @@ -0,0 +1,525 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Library/DebugLib.h>
>> +#include <Library/FlashLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeLib.h>
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +//
>> +// These temporary buffers are used to calculate and convert linear virtual
>> +// to physical address
>> +//
>> +STATIC UINT64 mNvFlashBase;
>> +STATIC UINT32 mNvFlashSize;
>> +STATIC UINT32 mFlashBlockSize;
>> +STATIC UINT64 mNvStorageBase;
>> +STATIC UINT64 mNvStorageSize;
>> +
>> +/**
>> +  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
>> +**/
>> +VOID
>> +EFIAPI
>> +FlashFvbAddressChangeEvent (
>> +  IN EFI_EVENT Event,
>> +  IN VOID      *Context
>> +  )
>> +{
>> +  EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
>> +}
>> +
>> +/**
>> +  The GetAttributes() 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
>> +FlashFvbDxeGetAttributes (
>> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  OUT      EFI_FVB_ATTRIBUTES_2                *Attributes
>> +  )
>> +{
>> +  ASSERT (Attributes != NULL);
>> +
>> +  *Attributes = EFI_FVB2_READ_ENABLED_CAP   | // Reads may be enabled
>> +                EFI_FVB2_READ_STATUS        | // Reads are currently enabled
>> +                EFI_FVB2_WRITE_STATUS       | // Writes are currently enabled
>> +                EFI_FVB2_WRITE_ENABLED_CAP  | // Writes may be 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_ALIGNMENT          |
>> +                EFI_FVB2_ERASE_POLARITY;      // After erasure all bits take this value (i.e. '1')
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  The SetAttributes() function sets configurable firmware volume
>> +  attributes and returns the new settings of the firmware volume.
>> +
>> +  @param This         Indicates the 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. Type
>> +                      EFI_FVB_ATTRIBUTES_2 is defined in
>> +                      EFI_FIRMWARE_VOLUME_HEADER.
>> +
>> +  @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
>> +FlashFvbDxeSetAttributes (
>> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  IN OUT   EFI_FVB_ATTRIBUTES_2                *Attributes
>> +  )
>> +{
>> +  return EFI_SUCCESS;  // ignore for now
>> +}
>> +
>> +/**
>> +  The GetPhysicalAddress() function retrieves the base address of
>> +  a memory-mapped firmware volume. This function should be called
>> +  only for memory-mapped firmware volumes.
>> +
>> +  @param This     Indicates the 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_UNSUPPORTED   The firmware volume is not memory mapped.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeGetPhysicalAddress (
>> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  OUT      EFI_PHYSICAL_ADDRESS                *Address
>> +  )
>> +{
>> +  ASSERT (Address != NULL);
>> +
>> +  *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  The GetBlockSize() function retrieves the size of the requested
>> +  block. It also returns the number of additional blocks with
>> +  the identical size. The GetBlockSize() function is used to
>> +  retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
>> +
>> +
>> +  @param This           Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> +  @param Lba            Indicates the block for which to return the size.
>> +
>> +  @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
>> +FlashFvbDxeGetBlockSize (
>> +  IN  CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  IN        EFI_LBA                             Lba,
>> +  OUT       UINTN                               *BlockSize,
>> +  OUT       UINTN                               *NumberOfBlocks
>> +  )
>> +{
>> +  UINTN TotalNvStorageBlocks;
>> +
>> +  ASSERT (BlockSize != NULL);
>> +  ASSERT (NumberOfBlocks != NULL);
>> +
>> +  TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
>> +
>> +  if (TotalNvStorageBlocks <= (UINTN)Lba) {
>> +    DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
>> +  *BlockSize = mFlashBlockSize;
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Reads the specified number of bytes into a buffer from the specified block.
>> +
>> +  The Read() 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 Read() function must return the status code
>> +  EFI_ACCESS_DENIED without modifying the contents of the
>> +  buffer. The Read() 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     Indicates the 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
>> +FlashFvbDxeRead (
>> +  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 Status;
>> +
>> +  ASSERT (NumBytes != NULL);
>> +  ASSERT (Buffer != NULL);
>> +
>> +  if (Offset + *NumBytes > mFlashBlockSize) {
>> +    return EFI_BAD_BUFFER_SIZE;
>> +  }
>> +
>> +  Status = FlashReadCommand (
>> +             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
>> +             Buffer,
>> +             NumBytes
>> +             );
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Writes the specified number of bytes from the input buffer to the block.
>> +
>> +  The Write() 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 Write()
>> +  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
>> +  Write() function,  it is recommended for the caller to first call
>> +  the EraseBlocks() 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 Write() function must
>> +  return the status code EFI_ACCESS_DENIED without modifying the
>> +  contents of the firmware volume. The Write() 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 Write() service
>> +  returns.
>> +
>> +  @param This     Indicates the 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
>> +FlashFvbDxeWrite (
>> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  IN       EFI_LBA                             Lba,
>> +  IN       UINTN                               Offset,
>> +  IN OUT   UINTN                               *NumBytes,
>> +  IN       UINT8                               *Buffer
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +
>> +  ASSERT (NumBytes != NULL);
>> +  ASSERT (Buffer != NULL);
>> +
>> +  if (Offset + *NumBytes > mFlashBlockSize) {
>> +    return EFI_BAD_BUFFER_SIZE;
>> +  }
>> +
>> +  Status = FlashProgramCommand (
>> +             (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
>> +             Buffer,
>> +             NumBytes
>> +             );
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  return Status;
>> +}
>> +
>> +/**
>> +  Erases and initializes a firmware volume block.
>> +
>> +  The EraseBlocks() 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 EraseBlocks() 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 EraseBlocks() function must return the
>> +  status code EFI_ACCESS_DENIED without modifying the contents of
>> +  the firmware volume. All calls to EraseBlocks() must be fully
>> +  flushed to the hardware before the EraseBlocks() service
>> +  returns.
>> +
>> +  @param This   Indicates the 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. For example, the
>> +                following indicates that two ranges of blocks
>> +                (5-7 and 10-11) are to be erased: EraseBlocks
>> +                (This, 5, 3, 10, 2, 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
>> +FlashFvbDxeErase (
>> +  IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> +  ...
>> +  )
>> +{
>> +  VA_LIST    Args;
>> +  EFI_LBA    Start;
>> +  UINTN      Length;
>> +  EFI_STATUS Status;
>> +
>> +  Status = EFI_SUCCESS;
>> +
>> +  VA_START (Args, This);
>> +
>> +  for (Start = VA_ARG (Args, EFI_LBA);
>> +       Start != EFI_LBA_LIST_TERMINATOR;
>> +       Start = VA_ARG (Args, EFI_LBA))
>> +  {
>> +    Length = VA_ARG (Args, UINTN);
>> +    Status = FlashEraseCommand (
>> +               (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
>> +               Length * mFlashBlockSize
>> +               );
>> +  }
>> +
>> +  VA_END (Args);
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
>> +  FlashFvbDxeGetAttributes,
>> +  FlashFvbDxeSetAttributes,
>> +  FlashFvbDxeGetPhysicalAddress,
>> +  FlashFvbDxeGetBlockSize,
>> +  FlashFvbDxeRead,
>> +  FlashFvbDxeWrite,
>> +  FlashFvbDxeErase
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeInitialize (
>> +  IN EFI_HANDLE       ImageHandle,
>> +  IN EFI_SYSTEM_TABLE *SystemTable
>> +  )
>> +{
>> +  EFI_STATUS Status;
>> +  EFI_HANDLE FvbHandle = NULL;
>> +  EFI_EVENT  VirtualAddressChangeEvent;
>> +
>> +  // Get NV store FV info
>> +  mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
>> +  mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
>> +  mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
>> +                   FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>> +                   FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  DEBUG ((
>> +    DEBUG_INFO,
>> +    "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
>> +    __FUNCTION__,
>> +    mNvStorageBase,
>> +    mNvStorageSize
>> +    ));
>> +
>> +  // Get NV Flash information
>> +  Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  if (mNvFlashSize >= (mNvStorageSize * 2)) {
>> +    DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
>> +  } else {
>> +    DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  Status = gBS->CreateEventEx (
>> +                  EVT_NOTIFY_SIGNAL,
>> +                  TPL_NOTIFY,
>> +                  FlashFvbAddressChangeEvent,
>> +                  NULL,
>> +                  &gEfiEventVirtualAddressChangeGuid,
>> +                  &VirtualAddressChangeEvent
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  Status = gBS->InstallMultipleProtocolInterfaces (
>> +                  &FvbHandle,
>> +                  &gEfiFirmwareVolumeBlockProtocolGuid,
>> +                  &mFlashFvbProtocol,
>> +                  NULL
>> +                  );
>> +
>> +  if (EFI_ERROR (Status)) {
>> +    DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
>> +    return Status;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
>> new file mode 100644
>> index 000000000000..6bfbbbebaa85
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
>> @@ -0,0 +1,283 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <PiPei.h>
>> +#include <Uefi.h>
>> +
>> +#include <Library/ArmSmcLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MmCommunicationLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/PeimEntryPoint.h>
>> +#include <MmLib.h>
>> +
>> +// Convert to string
>> +#define _STR(x)          #x
>> +
>> +// Make sure the argument is expanded before converting to string
>> +#define STR(x)          _STR(x)
>> +
>> +// Use dynamic UEFI_UUID of each build time
>> +#define UEFI_UUID_BUILD      STR(UEFI_UUID)
>> +
>> +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
>> +
>> +STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
>> +STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
>> +
>> +STATIC
>> +EFI_STATUS
>> +UefiMmCreateSpiNorReq (
>> +  VOID   *Data,
>> +  UINT64 Size
>> +  )
>> +{
>> +  CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
>> +  mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
>> +
>> +  if (Size != 0) {
>> +    ASSERT (Data);
>> +    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
>> +
>> +    CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Entry point function for the PEIM
>> +
>> +  @param FileHandle      Handle of the file being invoked.
>> +  @param PeiServices     Describes the list of possible PEI Services.
>> +
>> +  @return EFI_SUCCESS    If we installed our PPI
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashPeiEntryPoint (
>> +  IN       EFI_PEI_FILE_HANDLE FileHandle,
>> +  IN CONST EFI_PEI_SERVICES    **PeiServices
>> +  )
>> +{
>> +  UINT64                               FWNvRamStartOffset;
>> +  EFI_STATUS                           Status;
>> +  EFI_MM_COMMUNICATE_SPINOR_RES        *MmSpiNorRes;
>> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
>> +  UINT64                               MmData[5];
>> +  UINTN                                Size;
>> +  VOID                                 *NvRamAddress;
>> +  UINTN                                NvRamSize;
>> +
>> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
>> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
>> +  UINT64                               NV2Base, NV2Size;
>> +#endif
>> +
>> +  NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
>> +  NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
>> +              FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>> +              FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> +  /* Find out about the start offset of NVRAM to be passed to SMC */
>> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
>> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +  Status = MmCommunicationCommunicate (
>> +             (VOID *)&mEfiMmSpiNorReq,
>> +             &Size
>> +             );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +  if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +    /* Old FW so just exit */
>> +    return EFI_SUCCESS;
>> +  }
>> +  FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
>> +
>> +  CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
>> +  if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
>> +    /* NVRAM size provided by FW is not enough */
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
>> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +  MmData[0] = MM_SPINOR_FUNC_READ;
>> +  MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> +  MmData[2] = (UINT64)sizeof (mStoredUuid);
>> +  MmData[3] = (UINT64)mStoredUuid;
>> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +  Status = MmCommunicationCommunicate (
>> +             (VOID *)&mEfiMmSpiNorReq,
>> +             &Size
>> +             );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +    return Status;
>> +  }
>> +
>> +  if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
>> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +    MmData[0] = MM_SPINOR_FUNC_ERASE;
>> +    MmData[1] = (UINT64)FWNvRamStartOffset;
>> +    MmData[2] = (UINT64)(NvRamSize * 2);
>> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = MmCommunicationCommunicate (
>> +               (VOID *)&mEfiMmSpiNorReq,
>> +               &Size
>> +               );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      return Status;
>> +    }
>> +
>> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
>> +    MmData[1] = (UINT64)FWNvRamStartOffset;
>> +    MmData[2] = (UINT64)(NvRamSize * 2);
>> +    MmData[3] = (UINT64)NvRamAddress;
>> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = MmCommunicationCommunicate (
>> +               (VOID *)&mEfiMmSpiNorReq,
>> +               &Size
>> +               );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      return Status;
>> +    }
>> +
>> +    /* Update UUID */
>> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +    MmData[0] = MM_SPINOR_FUNC_ERASE;
>> +    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> +    MmData[2] = (UINT64)sizeof (mBuildUuid);
>> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = MmCommunicationCommunicate (
>> +               (VOID *)&mEfiMmSpiNorReq,
>> +               &Size
>> +               );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      return Status;
>> +    }
>> +
>> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
>> +    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> +    MmData[2] = (UINT64)sizeof (mBuildUuid);
>> +    MmData[3] = (UINT64)mBuildUuid;
>> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = MmCommunicationCommunicate (
>> +               (VOID *)&mEfiMmSpiNorReq,
>> +               &Size
>> +               );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      return Status;
>> +    }
>> +    DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
>> +
>> +    /* Indicate that NVRAM was cleared */
>> +    PcdSetBoolS (PcdNvramErased, TRUE);
>> +  } else {
>> +    /* Copy the stored NVRAM to RAM */
>> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +    MmData[0] = MM_SPINOR_FUNC_READ;
>> +    MmData[1] = (UINT64)FWNvRamStartOffset;
>> +    MmData[2] = (UINT64)(NvRamSize * 2);
>> +    MmData[3] = (UINT64)NvRamAddress;
>> +    UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = MmCommunicationCommunicate (
>> +               (VOID *)&mEfiMmSpiNorReq,
>> +               &Size
>> +               );
>> +    ASSERT_EFI_ERROR (Status);
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      return Status;
>> +    }
>> +    DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
>> +  }
>> +
>> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
>> +  /* Find out about the start offset of NVRAM2 to be passed to SMC */
>> +  ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
>> +  UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +  Status = MmCommunicationCommunicate (
>> +             (VOID *)&mEfiMmSpiNorReq,
>> +             &Size
>> +             );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +  if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
>> +    NV2Base = MmSpiNorNV2InfoRes->NVBase;
>> +    NV2Size = MmSpiNorNV2InfoRes->NVSize;
>> +    /* Make sure the requested size is smaller than allocated */
>> +    if (RAM_BLOCKIO_SIZE <= NV2Size) {
>> +      /* Copy the ramdisk image to RAM */
>> +      ZeroMem ((VOID *)MmData, sizeof (MmData));
>> +      MmData[0] = MM_SPINOR_FUNC_READ;
>> +      MmData[1] = (UINT64)NV2Base; /* Start virtual address */
>> +      MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
>> +      MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
>> +      UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> +      Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +      Status = MmCommunicationCommunicate (
>> +                 (VOID *)&mEfiMmSpiNorReq,
>> +                 &Size
>> +                 );
>> +      ASSERT_EFI_ERROR (Status);
>> +
>> +      MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> +      ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
>> +    }
>> +
>> +    BuildMemoryAllocationHob (
>> +      (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
>> +      EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
>> +      EfiLoaderData
>> +      );
>> +  }
>> +#endif
>> +
>> +  return EFI_SUCCESS;
>> +}
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
>> new file mode 100644
>> index 000000000000..cd77aed3cfe1
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
>> @@ -0,0 +1,358 @@
>> +/** @file
>> +
>> +  Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> +  SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Uefi.h>
>> +
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/FlashLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeServicesTableLib.h>
>> +#include <MmLib.h>
>> +#include <Protocol/MmCommunication.h>
>> +
>> +STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
>> +STATIC EFI_MM_COMM_REQUEST           *mCommBuffer              = NULL;
>> +
>> +BOOLEAN mIsEfiRuntime;
>> +UINT8   *mTmpBufVirt;
>> +UINT8   *mTmpBufPhy;
>> +
>> +/**
>> +  This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
>> +  event. It converts a pointer to a new virtual address.
>> +
>> +  @param  Event        Event whose notification function is being invoked.
>> +  @param  Context      Pointer to the notification function's context
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +FlashLibAddressChangeEvent (
>> +  IN EFI_EVENT Event,
>> +  IN VOID      *Context
>> +  )
>> +{
>> +  gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
>> +  gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
>> +  gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
>> +
>> +  mIsEfiRuntime = TRUE;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashLibConstructor (
>> +  IN EFI_HANDLE       ImageHandle,
>> +  IN EFI_SYSTEM_TABLE *SystemTable
>> +  )
>> +{
>> +  EFI_EVENT  VirtualAddressChangeEvent = NULL;
>> +  EFI_STATUS Status = EFI_SUCCESS;
>> +
>> +  mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
>> +  ASSERT (mCommBuffer != NULL);
>> +
>> +  mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
>> +  mTmpBufVirt = mTmpBufPhy;
>> +  ASSERT (mTmpBufPhy != NULL);
>> +
>> +  Status = gBS->LocateProtocol (
>> +                  &gEfiMmCommunicationProtocolGuid,
>> +                  NULL,
>> +                  (VOID **)&mMmCommunicationProtocol
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  Status = gBS->CreateEvent (
>> +                  EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
>> +                  TPL_CALLBACK,
>> +                  FlashLibAddressChangeEvent,
>> +                  NULL,
>> +                  &VirtualAddressChangeEvent
>> +                  );
>> +  ASSERT_EFI_ERROR (Status);
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +FlashMmCommunicate (
>> +  IN OUT VOID  *CommBuffer,
>> +  IN OUT UINTN *CommSize
>> +  )
>> +{
>> +  if (mMmCommunicationProtocol == NULL) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  return mMmCommunicationProtocol->Communicate (
>> +                                     mMmCommunicationProtocol,
>> +                                     CommBuffer,
>> +                                     CommSize
>> +                                     );
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +UefiMmCreateSpiNorReq (
>> +  IN VOID   *Data,
>> +  IN UINT64 Size
>> +  )
>> +{
>> +  if (mCommBuffer == NULL) {
>> +    return EFI_INVALID_PARAMETER;
>> +  }
>> +
>> +  CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
>> +  mCommBuffer->EfiMmHdr.MsgLength = Size;
>> +
>> +  if (Size != 0) {
>> +    ASSERT (Data);
>> +    ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
>> +
>> +    CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> +  Convert Virtual Address to Physical Address at Runtime Services
>> +
>> +  @param  VirtualPtr          Virtual Address Pointer
>> +  @param  Size                Total bytes of the buffer
>> +
>> +  @retval Ptr                 Return the pointer of the converted address
>> +
>> +**/
>> +STATIC
>> +UINT8 *
>> +ConvertVirtualToPhysical (
>> +  IN UINT8 *VirtualPtr,
>> +  IN UINTN Size
>> +  )
>> +{
>> +  if (mIsEfiRuntime) {
>> +    ASSERT (VirtualPtr != NULL);
>> +    CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
>> +    return (UINT8 *)mTmpBufPhy;
>> +  }
>> +
>> +  return (UINT8 *)VirtualPtr;
>> +}
>> +
>> +/**
>> +  Convert Physical Address to Virtual Address at Runtime Services
>> +
>> +  @param  VirtualPtr          Physical Address Pointer
>> +  @param  Size                Total bytes of the buffer
>> +
>> +**/
>> +STATIC
>> +VOID
>> +ConvertPhysicaltoVirtual (
>> +  IN UINT8 *PhysicalPtr,
>> +  IN UINTN Size
>> +  )
>> +{
>> +  if (mIsEfiRuntime) {
>> +    ASSERT (PhysicalPtr != NULL);
>> +    CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
>> +  }
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashGetNvRamInfo (
>> +  OUT UINT64 *NvRamBase,
>> +  OUT UINT32 *NvRamSize
>> +  )
>> +{
>> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
>> +  EFI_STATUS                           Status;
>> +  UINT64                               MmData[5];
>> +  UINTN                                Size;
>> +
>> +  MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
>> +
>> +  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +  Status = FlashMmCommunicate (
>> +             mCommBuffer,
>> +             &Size
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
>> +  if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
>> +    *NvRamBase = MmSpiNorNVInfoRes->NVBase;
>> +    *NvRamSize = MmSpiNorNVInfoRes->NVSize;
>> +    DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashEraseCommand (
>> +  IN UINT8  *pBlockAddress,
>> +  IN UINT32 Length
>> +  )
>> +{
>> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> +  EFI_STATUS                    Status;
>> +  UINT64                        MmData[5];
>> +  UINTN                         Size;
>> +
>> +  ASSERT (pBlockAddress != NULL);
>> +
>> +  MmData[0] = MM_SPINOR_FUNC_ERASE;
>> +  MmData[1] = (UINT64)pBlockAddress;
>> +  MmData[2] = Length;
>> +
>> +  Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +  Status = FlashMmCommunicate (
>> +             mCommBuffer,
>> +             &Size
>> +             );
>> +  if (EFI_ERROR (Status)) {
>> +    return Status;
>> +  }
>> +
>> +  MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> +  if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +    DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
>> +    return EFI_DEVICE_ERROR;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashProgramCommand (
>> +  IN     UINT8 *pByteAddress,
>> +  IN     UINT8 *Byte,
>> +  IN OUT UINTN *Length
>> +  )
>> +{
>> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> +  EFI_STATUS                    Status;
>> +  UINT64                        MmData[5];
>> +  UINTN                         Remain, Size, NumWrite;
>> +  UINTN                         Count = 0;
>> +
>> +  ASSERT (pByteAddress != NULL);
>> +  ASSERT (Byte != NULL);
>> +  ASSERT (Length != NULL);
>> +
>> +  Remain = *Length;
>> +  while (Remain > 0) {
>> +    NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
>> +
>> +    MmData[0] = MM_SPINOR_FUNC_WRITE;
>> +    MmData[1] = (UINT64)pByteAddress;
>> +    MmData[2] = NumWrite;
>> +    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
>> +
>> +    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +    if (EFI_ERROR (Status)) {
>> +      return Status;
>> +    }
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = FlashMmCommunicate (
>> +               mCommBuffer,
>> +               &Size
>> +               );
>> +    if (EFI_ERROR (Status)) {
>> +      return Status;
>> +    }
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
>> +      return EFI_DEVICE_ERROR;
>> +    }
>> +
>> +    Remain -= NumWrite;
>> +    Count += NumWrite;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashReadCommand (
>> +  IN     UINT8 *pByteAddress,
>> +  OUT    UINT8 *Byte,
>> +  IN OUT UINTN *Length
>> +  )
>> +{
>> +  EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> +  EFI_STATUS                    Status;
>> +  UINT64                        MmData[5];
>> +  UINTN                         Remain, Size, NumRead;
>> +  UINTN                         Count = 0;
>> +
>> +  ASSERT (pByteAddress != NULL);
>> +  ASSERT (Byte != NULL);
>> +  ASSERT (Length != NULL);
>> +
>> +  Remain = *Length;
>> +  while (Remain > 0) {
>> +    NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
>> +
>> +    MmData[0] = MM_SPINOR_FUNC_READ;
>> +    MmData[1] = (UINT64)pByteAddress;
>> +    MmData[2] = NumRead;
>> +    MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
>> +
>> +    Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +    if (EFI_ERROR (Status)) {
>> +      return Status;
>> +    }
>> +
>> +    Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> +    Status = FlashMmCommunicate (
>> +               mCommBuffer,
>> +               &Size
>> +               );
>> +    if (EFI_ERROR (Status)) {
>> +      return Status;
>> +    }
>> +
>> +    MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> +    if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> +      DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
>> +      return EFI_DEVICE_ERROR;
>> +    }
>> +
>> +    ConvertPhysicaltoVirtual (Byte + Count, NumRead);
>> +    Remain -= NumRead;
>> +    Count += NumRead;
>> +  }
>> +
>> +  return EFI_SUCCESS;
>> +}
>> -- 
>> 2.17.1
>>


-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76546): https://edk2.groups.io/g/devel/message/76546
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-