On Wed, Sep 15, 2021 at 22:55:08 +0700, Nhi Pham wrote:
> From: Vu Nguyen <vungu...@os.amperecomputing.com>
> 
> This supports storing the UEFI non-volatile varibles on flash through
> the MM communication interface instead of emulating. Below are modules
> added for this support:
> * FlashLib provides APIs to access flash through MM service.
> * FlashPei driver helps to restore the saved variables from
>   flash on each boot.
> * FlashFvbDxe driver provides the implementation for the
>   gEfiFirmwareVolumeBlock protocol
> 
> Cc: Thang Nguyen <th...@os.amperecomputing.com>
> Cc: Chuong Tran <chu...@os.amperecomputing.com>
> Cc: Phong Vo <ph...@os.amperecomputing.com>
> Cc: Leif Lindholm <l...@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kin...@intel.com>
> Cc: Ard Biesheuvel <ardb+tianoc...@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desim...@intel.com>
> 
> Signed-off-by: Vu Nguyen <vungu...@os.amperecomputing.com>
> ---
>  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec                  |   3 +
>  Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec              |   8 +
>  Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc              |  10 +-
>  Platform/Ampere/JadePkg/Jade.dsc                                  |   5 +
>  Platform/Ampere/JadePkg/Jade.fdf                                  |  62 ++-
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf |  54 ++
>  Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf       |  52 ++
>  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         | 273 
> ++++++++++
>  Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c         | 358 
> +++++++++++++
>  12 files changed, 1424 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..646a53fc031c 100644
> --- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> @@ -31,6 +31,11 @@ [Guids]
>  [Ppis]
>  
>  [PcdsFixedAtBuild]
> +  #
> +  # NVRAM
> +  #
> +  
> gAmpereTokenSpaceGuid.PcdNvramUuid|"C416535D-970B-41B9-859A-3CAF0FAF198C"|VOID*|0x00000010

This still makes no semantic sense. The UUID does not identify the
NVRAM, it identifies "something somehow related to the NVRAM".
Please eename the Pcd something that describes *what* it identifies.

> +
>    #
>    # SMpro PMpro Pcds
>    #
> @@ -44,3 +49,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 bb144183164d..7f84ac2df50a 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> @@ -226,6 +226,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
> @@ -256,6 +257,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
>    
> AmpereCpuLib|Silicon/Ampere/AmpereAltraPkg/Library/AmpereCpuLib/RuntimeAmpereCpuLib.inf
>  
>  [LibraryClasses.ARM,LibraryClasses.AARCH64]
> @@ -508,6 +510,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
> @@ -528,8 +532,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>
> @@ -583,9 +589,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 332cd8ac0c8e..c670fd0f34b6 100644
> --- 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 NVRAM_UUID              = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5

And rename this define similarly.

>  
>    #
>    # Network definition
> @@ -89,6 +90,10 @@ [LibraryClasses]
>  
> ################################################################################
>  [PcdsFeatureFlag.common]
>  [PcdsFixedAtBuild.common]
> +  #
> +  # NVRAM
> +  #
> +  gAmpereTokenSpaceGuid.PcdNvramUuid|"$(NVRAM_UUID)"
>  
>  !if $(SECURE_BOOT_ENABLE) == TRUE
>    # Override the default values from SecurityPkg to ensure images
> diff --git a/Platform/Ampere/JadePkg/Jade.fdf 
> b/Platform/Ampere/JadePkg/Jade.fdf
> index 1857296a8ea5..375455086d0b 100644
> --- 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

As requested for v2, please reword "T.B.D" as "Placeholder" in the
patch where it is introduced.

> +# 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..9b640adb6421
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> @@ -0,0 +1,52 @@
> +## @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
> +  gAmpereTokenSpaceGuid.PcdNvramUuid
> +
> +[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..0939f1b70869
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
> @@ -0,0 +1,273 @@
> +/** @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>
> +
> +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
> +
> +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 (

This function is very long, and would really benefit from breaking up
into some smaller helper functions. Those could then be given helpful
names which would help clarify what's going on.

> +  IN       EFI_PEI_FILE_HANDLE FileHandle,
> +  IN CONST EFI_PEI_SERVICES    **PeiServices
> +  )
> +{
> +  CHAR8                                BuildUuid[PcdGetSize (PcdNvramUuid)];
> +  CHAR8                                StoredUuid[PcdGetSize (PcdNvramUuid)];
> +  EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
> +  EFI_MM_COMMUNICATE_SPINOR_RES        *MmSpiNorRes;
> +  EFI_STATUS                           Status;
> +  UINT64                               FWNvRamStartOffset;
> +  UINT64                               MmData[5];
> +  UINTN                                NvRamSize;
> +  UINTN                                Size;
> +  VOID                                 *NvRamAddress;
> +
> +#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 *)BuildUuid, PcdGetPtr (PcdNvramUuid), sizeof (BuildUuid));
> +  if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (BuildUuid))) {
> +    /* 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 (StoredUuid);
> +  MmData[3] = (UINT64)StoredUuid;
> +  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 *)StoredUuid, (VOID *)BuildUuid, sizeof 
> (BuildUuid))) {

Definitely helper function for this scope.

> +    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 */

Which UUID? Describe the content, not the storage format.
But this also seems like a clear logic block to move to a helper, at
which point the function name will be as useful as a comment.

> +    ZeroMem ((VOID *)MmData, sizeof (MmData));
> +    MmData[0] = MM_SPINOR_FUNC_ERASE;
> +    MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> +    MmData[2] = (UINT64)sizeof (BuildUuid);
> +    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 (BuildUuid);
> +    MmData[3] = (UINT64)BuildUuid;
> +    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 {

Another helper function for the other path.

> +    /* 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)

Can the whole contents of the #ifdef block be moved into a helper
function, only built if these conditions match?

/
    Leif

> +  /* 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 (#81030): https://edk2.groups.io/g/devel/message/81030
Mute This Topic: https://groups.io/mt/85631144/21656
Group Owner: devel+ow...@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [arch...@mail-archive.com]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to