public inbox for devel@edk2.groups.io
 help / color / mirror / Atom feed
From: "Nhi Pham" <nhi@os.amperecomputing.com>
To: devel@edk2.groups.io
Cc: Vu Nguyen <vunguyen@os.amperecomputing.com>
Subject: [edk2-platforms][PATCH 10/34] Silicon/Ampere: Support Non Volatile storage for Variable service
Date: Wed,  9 Dec 2020 16:25:07 +0700	[thread overview]
Message-ID: <20201209092531.30867-11-nhi@os.amperecomputing.com> (raw)
In-Reply-To: <20201209092531.30867-1-nhi@os.amperecomputing.com>

From: Vu Nguyen <vunguyen@os.amperecomputing.com>

Switch to use Flash as the storage for Variable services. Accessing
to Flash was done by using MM communication protocol.

This change includes three parts:
    - MmCommunication provide functions to communicate with secure
        partition in PEI and DXE phase.
    - FlashPei is to verify current stored data on Flash by comparing
        saved UUID with firmware's UEFI_UUID. If they are identical,
        stored data to RAM, otherwise replace stored data with default
        value from NVRAM Fv.
    - FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which
        will be used as a backend for VariableDxe to get/set variables.

Test cases:
    - Enter UEFI menu, change settings and verify these values at
        next boot.
    - For runtime, use efibootmgr Linux command to change EFI
        variables (BootNext, BootTime,...) and verify at next boot.

Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
 Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec                         |   3 +
 Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc                     |   7 +-
 Platform/Ampere/JadePkg/Jade.dsc                                  |   1 +
 Platform/Ampere/JadePkg/Jade.fdf                                  |  57 ++-
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf |  55 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf       |  48 ++
 Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf       |  36 ++
 Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h          |  42 ++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c   | 524 ++++++++++++++++++++
 Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c         | 276 +++++++++++
 Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c         | 357 +++++++++++++
 11 files changed, 1403 insertions(+), 3 deletions(-)

diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
index c34d580255b9..cc513d8ac69f 100644
--- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
@@ -37,6 +37,9 @@ [LibraryClasses]
   ##  @libraryclass  Defines a set of methods to communicate with PMPro.
   PMProLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/PMProLib.h
 
+  ##  @libraryclass  Defines a set of methods to access flash memory.
+  FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
+
 [Guids]
 
   ## SPI NOR Proxy MM GUID
diff --git a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc
index ecd67511a8be..3fc1fd94ee62 100755
--- a/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.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
@@ -262,6 +264,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
   EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
   ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
   NVParamLib|Silicon/Ampere/AmpereAltraPkg/Library/NVParamDxeLib/NVParamDxeLib.inf
+  FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
 
 [LibraryClasses.ARM,LibraryClasses.AARCH64]
   #
@@ -519,6 +522,7 @@ [Components.common]
   Silicon/Ampere/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/Variable/Pei/VariablePei.inf
@@ -571,10 +575,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 e92d5079c3a0..66f1b6ab94d2 100755
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -31,6 +31,7 @@ [Defines]
   DEFINE EDK2_SKIP_PEICORE       = TRUE
   DEFINE SECURE_BOOT_ENABLE      = FALSE
   DEFINE INCLUDE_TFTP_COMMAND    = TRUE
+  DEFINE UEFI_UUID               = 21A80447-B2DD-4D8C-BCA2-04305F025EA4
 
   #
   # Network definition
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 321156fb8f60..8efbd79461de 100755
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -58,8 +58,59 @@ [FD.BL33_JADE_UEFI]
 # NV Variables
 # Offset: 0x000C0000
 # Size:   0x00080000
-# T.B.D
 #
+0x000C0000|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, 0x19, 0xF9, 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
+}
+
+0x000F0000|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
+}
+
+0x00100000|0x00040000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
 
 #
 # NVRAM Backup
@@ -123,6 +174,7 @@ [FV.FV_PEI]
   INF Silicon/Ampere/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 ArmPkg/Drivers/CpuPei/CpuPei.inf
   INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
   INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
@@ -157,6 +209,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
@@ -185,6 +238,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..26516d0d0efb
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
@@ -0,0 +1,55 @@
+## @file
+#
+# Copyright (c) 2020, 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
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Silicon/Ampere/AmperePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
+
+[LibraryClasses]
+  DebugLib
+  PcdLib
+  FlashLib
+  UefiDriverEntryPoint
+  UefiBootServicesTableLib
+  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..b4c086800256
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
@@ -0,0 +1,48 @@
+## @file
+#
+# Copyright (c) 2020, 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
+  MdePkg/MdePkg.dec
+  MdeModulePkg/MdeModulePkg.dec
+  Silicon/Ampere/AmperePkg.dec
+  Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.dec
+
+[LibraryClasses]
+  ArmSmcLib
+  BaseMemoryLib
+  DebugLib
+  MmCommunicationLib
+  PeimEntryPoint
+
+[Guids]
+  gSpiNorMmGuid
+
+[FixedPcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Pcd]
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+  gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+
+[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..a5f7a4ceff1d
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
@@ -0,0 +1,36 @@
+## @file
+#
+# Copyright (c) 2020, 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]
+  MdePkg/MdePkg.dec
+  ArmPkg/ArmPkg.dec
+  ArmPlatformPkg/ArmPlatformPkg.dec
+  Silicon/Ampere/AmpereAltraPkg/Ac01Pkg.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..18f12d4c86ef
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
@@ -0,0 +1,42 @@
+/** @file
+
+  Copyright (c) 2020, 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..7428f9c17111
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
@@ -0,0 +1,524 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/FlashLib.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..3fd5a709e58e
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
@@ -0,0 +1,276 @@
+/** @file
+
+  Copyright (c) 2020, Ampere Computing LLC. All rights reserved.<BR>
+
+  SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Uefi/UefiSpec.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/MmCommunicationLib.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"));
+  } 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..6826c5032086
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
@@ -0,0 +1,357 @@
+/** @file
+
+  Copyright (c) 2020, 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/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/FlashLib.h>
+#include <Protocol/MmCommunication.h>
+#include <MmLib.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


  parent reply	other threads:[~2020-12-09  9:24 UTC|newest]

Thread overview: 40+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2020-12-09  9:24 [edk2-platforms][PATCH 00/34] Add new Ampere Mt. Jade platform Nhi Pham
2020-12-09  9:24 ` [edk2-platforms][PATCH 01/34] Initial support for Ampere Altra and " Nhi Pham
2021-01-07 23:57   ` [edk2-devel] " Leif Lindholm
2021-01-15  4:59     ` Vu Nguyen
2020-12-09  9:24 ` [edk2-platforms][PATCH 02/34] Platform/Ampere: Implement FailSafe library Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 03/34] Platform/Ampere: Add FailSafe and WDT support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 04/34] AmpereAltraPkg: Implement GpioLib and I2cLib modules Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 05/34] JadePkg: Implement RealTimeClockLib for PCF85063 Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 06/34] Platform/Ampere: Add AcpiPccLib to support ACPI PCCT Table Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 07/34] Platform/Ampere: Add AcpiHelperLib to update ACPI DSDT table Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 08/34] JadePkg: Initial support for static ACPI tables Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 09/34] JadePkg: Install some ACPI tables at runtime Nhi Pham
2020-12-09  9:25 ` Nhi Pham [this message]
2020-12-09  9:25 ` [edk2-platforms][PATCH 11/34] Silicon/Ampere: Support PlatformManagerUiLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 12/34] AmpereAltraPkg: Add PcieCore Library Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 13/34] AmpereAltraPkg: Add PciHostBridge driver Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 14/34] JadePkg: Add implementation for PcieBoardLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 15/34] JadePkg: Enable PCIe support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 16/34] JadePkg: Add ASpeed GOP driver Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 17/34] Silicon/Ampere: Add Random Number Generator Support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 18/34] Silicon/Ampere: Fixup runtime memory attribute Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 19/34] JadePkg: Add SMBIOS tables support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 20/34] AmpereAltraPkg: Add DebugInfoPei module Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 21/34] Silicon/Ampere: Add platform info screen Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 22/34] Silicon/Ampere: Add Memory " Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 23/34] AmpereAltraPkg: Add CPU Configuration for SubNUMA Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 24/34] AmpereAltraPkg: Add ACPI configuration screen Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 25/34] AmpereAltraPkg: Implement PlatformFlashAccessLib instance Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 26/34] JadePkg: Add implementation for UEFI Capsule Update Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 27/34] JadePkg: Add Capsule Update support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 28/34] Silicon/Ampere: Implement PlatformBootManagerLib for LinuxBoot Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 29/34] Platform/Ampere: Add LinuxBoot image Nhi Pham
2020-12-10 12:40   ` [edk2-devel] " Leif Lindholm
2020-12-11  2:38     ` Nhi Pham
2020-12-11 11:15       ` Leif Lindholm
2020-12-09  9:25 ` [edk2-platforms][PATCH 30/34] JadePkg: Support LinuxBoot DSC/FDF build for Jade platform Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 31/34] AmpereAltraPkg: Add BootProgress support Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 32/34] JadePkg: Add ACPI/APEI tables Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 33/34] Platform/Ampere: Add AcpiApeiLib Nhi Pham
2020-12-09  9:25 ` [edk2-platforms][PATCH 34/34] AmpereAltraPkg, JadePkg: Add RAS setting screen Nhi Pham

Reply instructions:

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

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

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

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

  git send-email \
    --in-reply-to=20201209092531.30867-11-nhi@os.amperecomputing.com \
    --to=devel@edk2.groups.io \
    /path/to/YOUR_REPLY

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

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