From: Vu Nguyen <vunguyen@os.amperecomputing.com>
Non-volatile variables now can be stored on flash. MM communication
protocol is used to access storage on flash.
Included in this change are:
* FlashPei module is used to compare saved UUID with firmware's
UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
Otherwise fill the storage with default value from NVRAM FV.
* FlashLib provide APIs to access flash through MM Communication
protocol
* FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
used by the variable services to get/set variables.
Cc: Thang Nguyen <thang@os.amperecomputing.com>
Cc: Chuong Tran <chuong@os.amperecomputing.com>
Cc: Phong Vo <phong@os.amperecomputing.com>
Cc: Leif Lindholm <leif@nuviainc.com>
Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
---
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec | 3 +
Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 11 +-
Platform/Ampere/JadePkg/Jade.dsc | 1 +
Platform/Ampere/JadePkg/Jade.fdf | 62 ++-
Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf | 54 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf | 51 ++
Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf | 36 ++
Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h | 42 ++
Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c | 525 ++++++++++++++++++++
Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c | 283 +++++++++++
Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c | 358 +++++++++++++
12 files changed, 1425 insertions(+), 4 deletions(-)
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
index be827dd19a96..d5b12a81e9bf 100644
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
@@ -37,6 +37,9 @@ [LibraryClasses]
## @libraryclass Defines a set of methods to communicate with secure parition over MM interface.
MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
+ ## @libraryclass Defines a set of methods to access flash memory.
+ FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
+
## @libraryclass Defines a set of methods to generate random numbers by using Hardware RNG.
TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
index 6ebdf7db0a57..26e020715290 100755
--- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
@@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
# Firmware Volume Pcds
#
gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
+
+ # NVRam Pcds
+ gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
index 9f75da6f05ad..65973569a41d 100755
--- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
+++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
@@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
[BuildOptions]
GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
+ GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)
[LibraryClasses.common]
!if $(TARGET) == RELEASE
@@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+ FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
[LibraryClasses.common.UEFI_APPLICATION]
UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
@@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
+ FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
[LibraryClasses.ARM,LibraryClasses.AARCH64]
#
@@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
+ gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
+
################################################################################
#
# Component Section - list of all EDK II Component Entries defined by this Platform
@@ -520,8 +525,10 @@ [Components.common]
Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
+ Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
ArmPkg/Drivers/CpuPei/CpuPei.inf
UefiCpuPkg/CpuIoPei/CpuIoPei.inf
+ MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
<LibraryClasses>
@@ -575,9 +582,9 @@ [Components.common]
#
# Environment Variables Protocol
#
+ Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
- <PcdsFixedAtBuild>
- gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
<LibraryClasses>
BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
index f37ab1a92e44..9b9a5d0bad0f 100755
--- a/Platform/Ampere/JadePkg/Jade.dsc
+++ b/Platform/Ampere/JadePkg/Jade.dsc
@@ -52,6 +52,7 @@ [Defines]
DEFINE EDK2_SKIP_PEICORE = TRUE
DEFINE SECURE_BOOT_ENABLE = FALSE
DEFINE INCLUDE_TFTP_COMMAND = TRUE
+ DEFINE UEFI_UUID = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
#
# Network definition
diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
index 1857296a8ea5..375455086d0b 100755
--- a/Platform/Ampere/JadePkg/Jade.fdf
+++ b/Platform/Ampere/JadePkg/Jade.fdf
@@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
ErasePolarity = 1
# This one is tricky, it must be: BlockSize * NumBlocks = Size
-BlockSize = 0x10000
+BlockSize = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
NumBlocks = 0x7C
################################################################################
@@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
#
# NV Variables
-# T.B.D
+# Offset: 0x00740000
+# Size: 0x00080000
#
+0x00740000|0x00030000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+DATA = {
+ ## This is the EFI_FIRMWARE_VOLUME_HEADER
+ # ZeroVector []
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # FileSystemGuid: gEfiSystemNvDataFvGuid =
+ # { 0xFFF12B8D, 0x7696, 0x4C8B,
+ # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
+ 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
+ 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
+ # FvLength: 0x80000
+ 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
+ # Signature "_FVH" # Attributes
+ 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
+ # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
+ 0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
+ # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
+ 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
+ # Blockmap[1]: End
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ ## This is the VARIABLE_STORE_HEADER
+ # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
+ # Signature: gEfiAuthenticatedVariableGuid =
+ # { 0xaaf32c78, 0x947b, 0x439a,
+ # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
+ 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
+ 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
+ # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
+ # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
+ # This can speed up the Variable Dispatch a bit.
+ 0xB8, 0xFF, 0x02, 0x00,
+ # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
+ 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00770000|0x00010000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+DATA = {
+ # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
+ # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
+ 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
+ 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
+ # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
+ 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
+ # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
+ 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+}
+
+0x00780000|0x00040000
+gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
################################################################################
#
@@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
INF ArmPkg/Drivers/CpuPei/CpuPei.inf
INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
+ INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
@@ -144,6 +199,7 @@ [FV.FvMain]
INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
}
INF MdeModulePkg/Core/Dxe/DxeMain.inf
@@ -173,6 +229,8 @@ [FV.FvMain]
# Environment Variables Protocol
#
INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
+ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
+ INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
#
# Multiple Console IO support
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
new file mode 100644
index 000000000000..782278615094
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
@@ -0,0 +1,54 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = FlashFvbDxe
+ FILE_GUID = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 0.1
+ ENTRY_POINT = FlashFvbDxeInitialize
+
+[Sources]
+ FlashFvbDxe.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ FlashLib
+ PcdLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeLib
+
+[FixedPcd]
+ gAmpereTokenSpaceGuid.PcdFvBlockSize
+
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+
+[Guids]
+ gEfiEventVirtualAddressChangeGuid
+ gSpiNorMmGuid
+
+[Protocols]
+ gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES
+ gEfiMmCommunicationProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiMmCommunicationProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
new file mode 100644
index 000000000000..a4eaf5039bb0
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
@@ -0,0 +1,51 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = FlashPei
+ FILE_GUID = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = FlashPeiEntryPoint
+
+[Sources]
+ FlashPei.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+ Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
+
+[LibraryClasses]
+ ArmSmcLib
+ BaseMemoryLib
+ DebugLib
+ MmCommunicationLib
+ PcdLib
+ PeimEntryPoint
+
+[Guids]
+ gSpiNorMmGuid
+
+[FixedPcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
+
+ gAmpereTokenSpaceGuid.PcdNvramErased
+
+[Depex]
+ TRUE
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
new file mode 100644
index 000000000000..2d5003d1af17
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
@@ -0,0 +1,36 @@
+## @file
+#
+# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x0001001B
+ BASE_NAME = FlashLib
+ FILE_GUID = 9E9D093D-6484-45AE-BA49-0745AA0BB481
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 0.1
+ LIBRARY_CLASS = FlashLib
+ CONSTRUCTOR = FlashLibConstructor
+
+[Sources.common]
+ FlashLib.c
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ ArmPlatformPkg/ArmPlatformPkg.dec
+ MdePkg/MdePkg.dec
+ Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+
+[Guids]
+ gSpiNorMmGuid
+
+[Protocols]
+ gEfiMmCommunicationProtocolGuid
diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
new file mode 100644
index 000000000000..9207dee643a5
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
@@ -0,0 +1,42 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef FLASH_LIB_H_
+#define FLASH_LIB_H_
+
+EFI_STATUS
+EFIAPI
+FlashGetNvRamInfo (
+ OUT UINT64 *NvRamBase,
+ OUT UINT32 *NvRamSize
+ );
+
+EFI_STATUS
+EFIAPI
+FlashEraseCommand (
+ IN UINT8 *pBlockAddress,
+ IN UINT32 Length
+ );
+
+EFI_STATUS
+EFIAPI
+FlashProgramCommand (
+ IN UINT8 *pByteAddress,
+ IN UINT8 *Byte,
+ IN OUT UINTN *Length
+ );
+
+EFI_STATUS
+EFIAPI
+FlashReadCommand (
+ IN UINT8 *pByteAddress,
+ OUT UINT8 *Byte,
+ IN OUT UINTN *Length
+ );
+
+#endif /* FLASH_LIB_H_ */
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
new file mode 100644
index 000000000000..dcd92151b7d2
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
@@ -0,0 +1,525 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/FlashLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+//
+// These temporary buffers are used to calculate and convert linear virtual
+// to physical address
+//
+STATIC UINT64 mNvFlashBase;
+STATIC UINT32 mNvFlashSize;
+STATIC UINT32 mFlashBlockSize;
+STATIC UINT64 mNvStorageBase;
+STATIC UINT64 mNvStorageSize;
+
+/**
+ Fixup internal data so that EFI can be call in virtual mode.
+ Call the passed in Child Notify event and convert any pointers in
+ lib to virtual mode.
+
+ @param[in] Event The Event that is being processed
+ @param[in] Context Event Context
+**/
+VOID
+EFIAPI
+FlashFvbAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
+}
+
+/**
+ The GetAttributes() function retrieves the attributes and
+ current settings of the block.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
+ attributes and current settings are
+ returned. Type EFI_FVB_ATTRIBUTES_2 is defined
+ in EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were
+ returned.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeGetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ ASSERT (Attributes != NULL);
+
+ *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
+ EFI_FVB2_READ_STATUS | // Reads are currently enabled
+ EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
+ EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be enabled
+ EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
+ EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
+ EFI_FVB2_ALIGNMENT |
+ EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1')
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The SetAttributes() function sets configurable firmware volume
+ attributes and returns the new settings of the firmware volume.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Attributes On input, Attributes is a pointer to
+ EFI_FVB_ATTRIBUTES_2 that contains the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. Type
+ EFI_FVB_ATTRIBUTES_2 is defined in
+ EFI_FIRMWARE_VOLUME_HEADER.
+
+ @retval EFI_SUCCESS The firmware volume attributes were returned.
+
+ @retval EFI_INVALID_PARAMETER The attributes requested are in
+ conflict with the capabilities
+ as declared in the firmware
+ volume header.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeSetAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
+ )
+{
+ return EFI_SUCCESS; // ignore for now
+}
+
+/**
+ The GetPhysicalAddress() function retrieves the base address of
+ a memory-mapped firmware volume. This function should be called
+ only for memory-mapped firmware volumes.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Address Pointer to a caller-allocated
+ EFI_PHYSICAL_ADDRESS that, on successful
+ return from GetPhysicalAddress(), contains the
+ base address of the firmware volume.
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_UNSUPPORTED The firmware volume is not memory mapped.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeGetPhysicalAddress (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ OUT EFI_PHYSICAL_ADDRESS *Address
+ )
+{
+ ASSERT (Address != NULL);
+
+ *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The GetBlockSize() function retrieves the size of the requested
+ block. It also returns the number of additional blocks with
+ the identical size. The GetBlockSize() function is used to
+ retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
+
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba Indicates the block for which to return the size.
+
+ @param BlockSize Pointer to a caller-allocated UINTN in which
+ the size of the block is returned.
+
+ @param NumberOfBlocks Pointer to a caller-allocated UINTN in
+ which the number of consecutive blocks,
+ starting with Lba, is returned. All
+ blocks in this range have a size of
+ BlockSize.
+
+
+ @retval EFI_SUCCESS The firmware volume base address was returned.
+
+ @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeGetBlockSize (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ OUT UINTN *BlockSize,
+ OUT UINTN *NumberOfBlocks
+ )
+{
+ UINTN TotalNvStorageBlocks;
+
+ ASSERT (BlockSize != NULL);
+ ASSERT (NumberOfBlocks != NULL);
+
+ TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
+
+ if (TotalNvStorageBlocks <= (UINTN)Lba) {
+ DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
+ *BlockSize = mFlashBlockSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the specified number of bytes into a buffer from the specified block.
+
+ The Read() function reads the requested number of bytes from the
+ requested block and stores them in the provided buffer.
+ Implementations should be mindful that the firmware volume
+ might be in the ReadDisabled state. If it is in this state,
+ the Read() function must return the status code
+ EFI_ACCESS_DENIED without modifying the contents of the
+ buffer. The Read() function must also prevent spanning block
+ boundaries. If a read is requested that would span a block
+ boundary, the read must read up to the boundary but not
+ beyond. The output parameter NumBytes must be set to correctly
+ indicate the number of bytes actually read. The caller must be
+ aware that a read may be partially completed.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index
+ from which to read.
+
+ @param Offset Offset into the block at which to begin reading.
+
+ @param NumBytes Pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes read.
+
+ @param Buffer Pointer to a caller-allocated buffer that will
+ be used to hold the data that is read.
+
+ @retval EFI_SUCCESS The firmware volume was read successfully,
+ and contents are in Buffer.
+
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
+ boundary. On output, NumBytes
+ contains the total number of bytes
+ returned in Buffer.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ ReadDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is not
+ functioning correctly and could
+ not be read.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeRead (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN OUT UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (NumBytes != NULL);
+ ASSERT (Buffer != NULL);
+
+ if (Offset + *NumBytes > mFlashBlockSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ Status = FlashReadCommand (
+ (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
+ Buffer,
+ NumBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes the specified number of bytes from the input buffer to the block.
+
+ The Write() function writes the specified number of bytes from
+ the provided buffer to the specified block and offset. If the
+ firmware volume is sticky write, the caller must ensure that
+ all the bits of the specified range to write are in the
+ EFI_FVB_ERASE_POLARITY state before calling the Write()
+ function, or else the result will be unpredictable. This
+ unpredictability arises because, for a sticky-write firmware
+ volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
+ state but cannot flip it back again. Before calling the
+ Write() function, it is recommended for the caller to first call
+ the EraseBlocks() function to erase the specified block to
+ write. A block erase cycle will transition bits from the
+ (NOT)EFI_FVB_ERASE_POLARITY state back to the
+ EFI_FVB_ERASE_POLARITY state. Implementations should be
+ mindful that the firmware volume might be in the WriteDisabled
+ state. If it is in this state, the Write() function must
+ return the status code EFI_ACCESS_DENIED without modifying the
+ contents of the firmware volume. The Write() function must
+ also prevent spanning block boundaries. If a write is
+ requested that spans a block boundary, the write must store up
+ to the boundary but not beyond. The output parameter NumBytes
+ must be set to correctly indicate the number of bytes actually
+ written. The caller must be aware that a write may be
+ partially completed. All writes, partial or otherwise, must be
+ fully flushed to the hardware before the Write() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
+
+ @param Lba The starting logical block index to write to.
+
+ @param Offset Offset into the block at which to begin writing.
+
+ @param NumBytes The pointer to a UINTN. At entry, *NumBytes
+ contains the total size of the buffer. At
+ exit, *NumBytes contains the total number of
+ bytes actually written.
+
+ @param Buffer The pointer to a caller-allocated buffer that
+ contains the source for the write.
+
+ @retval EFI_SUCCESS The firmware volume was written successfully.
+
+ @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
+ LBA boundary. On output, NumBytes
+ contains the total number of bytes
+ actually written.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+
+ @retval EFI_DEVICE_ERROR The block device is malfunctioning
+ and could not be written.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeWrite (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (NumBytes != NULL);
+ ASSERT (Buffer != NULL);
+
+ if (Offset + *NumBytes > mFlashBlockSize) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ Status = FlashProgramCommand (
+ (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
+ Buffer,
+ NumBytes
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Erases and initializes a firmware volume block.
+
+ The EraseBlocks() function erases one or more blocks as denoted
+ by the variable argument list. The entire parameter list of
+ blocks must be verified before erasing any blocks. If a block is
+ requested that does not exist within the associated firmware
+ volume (it has a larger index than the last block of the
+ firmware volume), the EraseBlocks() function must return the
+ status code EFI_INVALID_PARAMETER without modifying the contents
+ of the firmware volume. Implementations should be mindful that
+ the firmware volume might be in the WriteDisabled state. If it
+ is in this state, the EraseBlocks() function must return the
+ status code EFI_ACCESS_DENIED without modifying the contents of
+ the firmware volume. All calls to EraseBlocks() must be fully
+ flushed to the hardware before the EraseBlocks() service
+ returns.
+
+ @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
+ instance.
+
+ @param ... The variable argument list is a list of tuples.
+ Each tuple describes a range of LBAs to erase
+ and consists of the following:
+ - An EFI_LBA that indicates the starting LBA
+ - A UINTN that indicates the number of blocks to
+ erase.
+
+ The list is terminated with an
+ EFI_LBA_LIST_TERMINATOR. For example, the
+ following indicates that two ranges of blocks
+ (5-7 and 10-11) are to be erased: EraseBlocks
+ (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
+
+ @retval EFI_SUCCESS The erase request successfully
+ completed.
+
+ @retval EFI_ACCESS_DENIED The firmware volume is in the
+ WriteDisabled state.
+ @retval EFI_DEVICE_ERROR The block device is not functioning
+ correctly and could not be written.
+ The firmware device may have been
+ partially erased.
+ @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
+ in the variable argument list do
+ not exist in the firmware volume.
+
+**/
+EFI_STATUS
+EFIAPI
+FlashFvbDxeErase (
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_LBA Start;
+ UINTN Length;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ VA_START (Args, This);
+
+ for (Start = VA_ARG (Args, EFI_LBA);
+ Start != EFI_LBA_LIST_TERMINATOR;
+ Start = VA_ARG (Args, EFI_LBA))
+ {
+ Length = VA_ARG (Args, UINTN);
+ Status = FlashEraseCommand (
+ (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
+ Length * mFlashBlockSize
+ );
+ }
+
+ VA_END (Args);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
+ FlashFvbDxeGetAttributes,
+ FlashFvbDxeSetAttributes,
+ FlashFvbDxeGetPhysicalAddress,
+ FlashFvbDxeGetBlockSize,
+ FlashFvbDxeRead,
+ FlashFvbDxeWrite,
+ FlashFvbDxeErase
+};
+
+EFI_STATUS
+EFIAPI
+FlashFvbDxeInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE FvbHandle = NULL;
+ EFI_EVENT VirtualAddressChangeEvent;
+
+ // Get NV store FV info
+ mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
+ mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
+ mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
+ __FUNCTION__,
+ mNvStorageBase,
+ mNvStorageSize
+ ));
+
+ // Get NV Flash information
+ Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mNvFlashSize >= (mNvStorageSize * 2)) {
+ DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
+ } else {
+ DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FlashFvbAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &VirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &FvbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ &mFlashFvbProtocol,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
new file mode 100644
index 000000000000..6bfbbbebaa85
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
@@ -0,0 +1,283 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Uefi.h>
+
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MmCommunicationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <MmLib.h>
+
+// Convert to string
+#define _STR(x) #x
+
+// Make sure the argument is expanded before converting to string
+#define STR(x) _STR(x)
+
+// Use dynamic UEFI_UUID of each build time
+#define UEFI_UUID_BUILD STR(UEFI_UUID)
+
+EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
+
+STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
+STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
+
+STATIC
+EFI_STATUS
+UefiMmCreateSpiNorReq (
+ VOID *Data,
+ UINT64 Size
+ )
+{
+ CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
+ mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
+
+ if (Size != 0) {
+ ASSERT (Data);
+ ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
+
+ CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point function for the PEIM
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @return EFI_SUCCESS If we installed our PPI
+
+**/
+EFI_STATUS
+EFIAPI
+FlashPeiEntryPoint (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ UINT64 FWNvRamStartOffset;
+ EFI_STATUS Status;
+ EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+ EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
+ UINT64 MmData[5];
+ UINTN Size;
+ VOID *NvRamAddress;
+ UINTN NvRamSize;
+
+#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
+ EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
+ UINT64 NV2Base, NV2Size;
+#endif
+
+ NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
+ NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
+ FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
+
+ /* Find out about the start offset of NVRAM to be passed to SMC */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
+ /* Old FW so just exit */
+ return EFI_SUCCESS;
+ }
+ FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
+
+ CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
+ if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
+ /* NVRAM size provided by FW is not enough */
+ return EFI_INVALID_PARAMETER;
+ }
+
+ /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_READ;
+ MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+ MmData[2] = (UINT64)sizeof (mStoredUuid);
+ MmData[3] = (UINT64)mStoredUuid;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+
+ if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_ERASE;
+ MmData[1] = (UINT64)FWNvRamStartOffset;
+ MmData[2] = (UINT64)(NvRamSize * 2);
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_WRITE;
+ MmData[1] = (UINT64)FWNvRamStartOffset;
+ MmData[2] = (UINT64)(NvRamSize * 2);
+ MmData[3] = (UINT64)NvRamAddress;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+
+ /* Update UUID */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_ERASE;
+ MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+ MmData[2] = (UINT64)sizeof (mBuildUuid);
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_WRITE;
+ MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
+ MmData[2] = (UINT64)sizeof (mBuildUuid);
+ MmData[3] = (UINT64)mBuildUuid;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
+
+ /* Indicate that NVRAM was cleared */
+ PcdSetBoolS (PcdNvramErased, TRUE);
+ } else {
+ /* Copy the stored NVRAM to RAM */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_READ;
+ MmData[1] = (UINT64)FWNvRamStartOffset;
+ MmData[2] = (UINT64)(NvRamSize * 2);
+ MmData[3] = (UINT64)NvRamAddress;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ return Status;
+ }
+ DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
+ }
+
+#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
+ /* Find out about the start offset of NVRAM2 to be passed to SMC */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
+ if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
+ NV2Base = MmSpiNorNV2InfoRes->NVBase;
+ NV2Size = MmSpiNorNV2InfoRes->NVSize;
+ /* Make sure the requested size is smaller than allocated */
+ if (RAM_BLOCKIO_SIZE <= NV2Size) {
+ /* Copy the ramdisk image to RAM */
+ ZeroMem ((VOID *)MmData, sizeof (MmData));
+ MmData[0] = MM_SPINOR_FUNC_READ;
+ MmData[1] = (UINT64)NV2Base; /* Start virtual address */
+ MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
+ MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
+ UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = MmCommunicationCommunicate (
+ (VOID *)&mEfiMmSpiNorReq,
+ &Size
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
+ ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
+ }
+
+ BuildMemoryAllocationHob (
+ (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
+ EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
+ EfiLoaderData
+ );
+ }
+#endif
+
+ return EFI_SUCCESS;
+}
diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
new file mode 100644
index 000000000000..cd77aed3cfe1
--- /dev/null
+++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
@@ -0,0 +1,358 @@
+/** @file
+
+ Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/FlashLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <MmLib.h>
+#include <Protocol/MmCommunication.h>
+
+STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
+STATIC EFI_MM_COMM_REQUEST *mCommBuffer = NULL;
+
+BOOLEAN mIsEfiRuntime;
+UINT8 *mTmpBufVirt;
+UINT8 *mTmpBufPhy;
+
+/**
+ This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ event. It converts a pointer to a new virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+FlashLibAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
+ gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
+ gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
+
+ mIsEfiRuntime = TRUE;
+}
+
+EFI_STATUS
+EFIAPI
+FlashLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_EVENT VirtualAddressChangeEvent = NULL;
+ EFI_STATUS Status = EFI_SUCCESS;
+
+ mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
+ ASSERT (mCommBuffer != NULL);
+
+ mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
+ mTmpBufVirt = mTmpBufPhy;
+ ASSERT (mTmpBufPhy != NULL);
+
+ Status = gBS->LocateProtocol (
+ &gEfiMmCommunicationProtocolGuid,
+ NULL,
+ (VOID **)&mMmCommunicationProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
+ TPL_CALLBACK,
+ FlashLibAddressChangeEvent,
+ NULL,
+ &VirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+STATIC
+EFI_STATUS
+FlashMmCommunicate (
+ IN OUT VOID *CommBuffer,
+ IN OUT UINTN *CommSize
+ )
+{
+ if (mMmCommunicationProtocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return mMmCommunicationProtocol->Communicate (
+ mMmCommunicationProtocol,
+ CommBuffer,
+ CommSize
+ );
+}
+
+STATIC
+EFI_STATUS
+UefiMmCreateSpiNorReq (
+ IN VOID *Data,
+ IN UINT64 Size
+ )
+{
+ if (mCommBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
+ mCommBuffer->EfiMmHdr.MsgLength = Size;
+
+ if (Size != 0) {
+ ASSERT (Data);
+ ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
+
+ CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert Virtual Address to Physical Address at Runtime Services
+
+ @param VirtualPtr Virtual Address Pointer
+ @param Size Total bytes of the buffer
+
+ @retval Ptr Return the pointer of the converted address
+
+**/
+STATIC
+UINT8 *
+ConvertVirtualToPhysical (
+ IN UINT8 *VirtualPtr,
+ IN UINTN Size
+ )
+{
+ if (mIsEfiRuntime) {
+ ASSERT (VirtualPtr != NULL);
+ CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
+ return (UINT8 *)mTmpBufPhy;
+ }
+
+ return (UINT8 *)VirtualPtr;
+}
+
+/**
+ Convert Physical Address to Virtual Address at Runtime Services
+
+ @param VirtualPtr Physical Address Pointer
+ @param Size Total bytes of the buffer
+
+**/
+STATIC
+VOID
+ConvertPhysicaltoVirtual (
+ IN UINT8 *PhysicalPtr,
+ IN UINTN Size
+ )
+{
+ if (mIsEfiRuntime) {
+ ASSERT (PhysicalPtr != NULL);
+ CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
+ }
+}
+
+EFI_STATUS
+EFIAPI
+FlashGetNvRamInfo (
+ OUT UINT64 *NvRamBase,
+ OUT UINT32 *NvRamSize
+ )
+{
+ EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
+ EFI_STATUS Status;
+ UINT64 MmData[5];
+ UINTN Size;
+
+ MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
+
+ Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = FlashMmCommunicate (
+ mCommBuffer,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
+ if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
+ *NvRamBase = MmSpiNorNVInfoRes->NVBase;
+ *NvRamSize = MmSpiNorNVInfoRes->NVSize;
+ DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashEraseCommand (
+ IN UINT8 *pBlockAddress,
+ IN UINT32 Length
+ )
+{
+ EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+ EFI_STATUS Status;
+ UINT64 MmData[5];
+ UINTN Size;
+
+ ASSERT (pBlockAddress != NULL);
+
+ MmData[0] = MM_SPINOR_FUNC_ERASE;
+ MmData[1] = (UINT64)pBlockAddress;
+ MmData[2] = Length;
+
+ Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = FlashMmCommunicate (
+ mCommBuffer,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashProgramCommand (
+ IN UINT8 *pByteAddress,
+ IN UINT8 *Byte,
+ IN OUT UINTN *Length
+ )
+{
+ EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+ EFI_STATUS Status;
+ UINT64 MmData[5];
+ UINTN Remain, Size, NumWrite;
+ UINTN Count = 0;
+
+ ASSERT (pByteAddress != NULL);
+ ASSERT (Byte != NULL);
+ ASSERT (Length != NULL);
+
+ Remain = *Length;
+ while (Remain > 0) {
+ NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
+
+ MmData[0] = MM_SPINOR_FUNC_WRITE;
+ MmData[1] = (UINT64)pByteAddress;
+ MmData[2] = NumWrite;
+ MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
+
+ Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = FlashMmCommunicate (
+ mCommBuffer,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ Remain -= NumWrite;
+ Count += NumWrite;
+ }
+
+ return EFI_SUCCESS;
+}
+
+EFI_STATUS
+EFIAPI
+FlashReadCommand (
+ IN UINT8 *pByteAddress,
+ OUT UINT8 *Byte,
+ IN OUT UINTN *Length
+ )
+{
+ EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
+ EFI_STATUS Status;
+ UINT64 MmData[5];
+ UINTN Remain, Size, NumRead;
+ UINTN Count = 0;
+
+ ASSERT (pByteAddress != NULL);
+ ASSERT (Byte != NULL);
+ ASSERT (Length != NULL);
+
+ Remain = *Length;
+ while (Remain > 0) {
+ NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
+
+ MmData[0] = MM_SPINOR_FUNC_READ;
+ MmData[1] = (UINT64)pByteAddress;
+ MmData[2] = NumRead;
+ MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
+
+ Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
+ Status = FlashMmCommunicate (
+ mCommBuffer,
+ &Size
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
+ if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
+ return EFI_DEVICE_ERROR;
+ }
+
+ ConvertPhysicaltoVirtual (Byte + Count, NumRead);
+ Remain -= NumRead;
+ Count += NumRead;
+ }
+
+ return EFI_SUCCESS;
+}
--
2.17.1
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#75617): https://edk2.groups.io/g/devel/message/75617
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
On Wed, May 26, 2021 at 17:07:01 +0700, Nhi Pham wrote:
> From: Vu Nguyen <vunguyen@os.amperecomputing.com>
>
> Non-volatile variables now can be stored on flash. MM communication
> protocol is used to access storage on flash.
>
> Included in this change are:
> * FlashPei module is used to compare saved UUID with firmware's
> UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
> Otherwise fill the storage with default value from NVRAM FV.
> * FlashLib provide APIs to access flash through MM Communication
> protocol
> * FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
> used by the variable services to get/set variables.
>
> Cc: Thang Nguyen <thang@os.amperecomputing.com>
> Cc: Chuong Tran <chuong@os.amperecomputing.com>
> Cc: Phong Vo <phong@os.amperecomputing.com>
> Cc: Leif Lindholm <leif@nuviainc.com>
> Cc: Michael D Kinney <michael.d.kinney@intel.com>
> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>
> Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
> ---
> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
> Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec | 3 +
> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 11 +-
> Platform/Ampere/JadePkg/Jade.dsc | 1 +
> Platform/Ampere/JadePkg/Jade.fdf | 62 ++-
> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf | 54 ++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf | 51 ++
> Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf | 36 ++
> Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h | 42 ++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c | 525 ++++++++++++++++++++
> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c | 283 +++++++++++
> Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c | 358 +++++++++++++
> 12 files changed, 1425 insertions(+), 4 deletions(-)
>
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> index be827dd19a96..d5b12a81e9bf 100644
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> @@ -37,6 +37,9 @@ [LibraryClasses]
> ## @libraryclass Defines a set of methods to communicate with secure parition over MM interface.
> MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
>
> + ## @libraryclass Defines a set of methods to access flash memory.
> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> +
> ## @libraryclass Defines a set of methods to generate random numbers by using Hardware RNG.
> TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
>
> diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> index 6ebdf7db0a57..26e020715290 100755
> --- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> @@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
> # Firmware Volume Pcds
> #
> gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
> +
> + # NVRam Pcds
> + gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> index 9f75da6f05ad..65973569a41d 100755
> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
> @@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
>
> [BuildOptions]
> GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
> + GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)
This isn't obvious enough. I'm a bear of very little brain, and I
could possibly figure out what's happening here, given time, but
please put a proper description in commit message (and possibly here?
whatever makes sense).
>
> [LibraryClasses.common]
> !if $(TARGET) == RELEASE
> @@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
> SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
> PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
> MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>
> [LibraryClasses.common.UEFI_APPLICATION]
> UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
> @@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>
> EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
> ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>
> [LibraryClasses.ARM,LibraryClasses.AARCH64]
> #
> @@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
>
> + gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
> +
> ################################################################################
> #
> # Component Section - list of all EDK II Component Entries defined by this Platform
> @@ -520,8 +525,10 @@ [Components.common]
> Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
> Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
> Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
> + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> ArmPkg/Drivers/CpuPei/CpuPei.inf
> UefiCpuPkg/CpuIoPei/CpuIoPei.inf
> + MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
> <LibraryClasses>
> @@ -575,9 +582,9 @@ [Components.common]
> #
> # Environment Variables Protocol
> #
> + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
> - <PcdsFixedAtBuild>
> - gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
> <LibraryClasses>
> BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
> TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
> index f37ab1a92e44..9b9a5d0bad0f 100755
> --- a/Platform/Ampere/JadePkg/Jade.dsc
> +++ b/Platform/Ampere/JadePkg/Jade.dsc
> @@ -52,6 +52,7 @@ [Defines]
> DEFINE EDK2_SKIP_PEICORE = TRUE
> DEFINE SECURE_BOOT_ENABLE = FALSE
> DEFINE INCLUDE_TFTP_COMMAND = TRUE
> + DEFINE UEFI_UUID = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
This is a horrible name for a UUID. What is it meant to identify?
> #
> # Network definition
> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
> index 1857296a8ea5..375455086d0b 100755
> --- a/Platform/Ampere/JadePkg/Jade.fdf
> +++ b/Platform/Ampere/JadePkg/Jade.fdf
> @@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
> ErasePolarity = 1
>
> # This one is tricky, it must be: BlockSize * NumBlocks = Size
> -BlockSize = 0x10000
> +BlockSize = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
> NumBlocks = 0x7C
>
> ################################################################################
> @@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
>
> #
> # NV Variables
> -# T.B.D
Ah. If I can make a retroactive comment - could this be introduced as
"Placeholder" rather than "T.B.D."?
/
Leif
> +# Offset: 0x00740000
> +# Size: 0x00080000
> #
> +0x00740000|0x00030000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> +DATA = {
> + ## This is the EFI_FIRMWARE_VOLUME_HEADER
> + # ZeroVector []
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + # FileSystemGuid: gEfiSystemNvDataFvGuid =
> + # { 0xFFF12B8D, 0x7696, 0x4C8B,
> + # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
> + 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
> + 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
> + # FvLength: 0x80000
> + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
> + # Signature "_FVH" # Attributes
> + 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
> + # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
> + 0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
> + # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
> + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
> + # Blockmap[1]: End
> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
> + ## This is the VARIABLE_STORE_HEADER
> + # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
> + # Signature: gEfiAuthenticatedVariableGuid =
> + # { 0xaaf32c78, 0x947b, 0x439a,
> + # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
> + 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
> + 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
> + # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
> + # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
> + # This can speed up the Variable Dispatch a bit.
> + 0xB8, 0xFF, 0x02, 0x00,
> + # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
> + 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +}
> +
> +0x00770000|0x00010000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> +DATA = {
> + # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
> + # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
> + 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
> + 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
> + # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
> + 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
> + # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
> + 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
> +}
> +
> +0x00780000|0x00040000
> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>
> ################################################################################
> #
> @@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
> INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
> INF ArmPkg/Drivers/CpuPei/CpuPei.inf
> INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
> + INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
> INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
> INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
> INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
> @@ -144,6 +199,7 @@ [FV.FvMain]
> INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
> INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> }
>
> INF MdeModulePkg/Core/Dxe/DxeMain.inf
> @@ -173,6 +229,8 @@ [FV.FvMain]
> # Environment Variables Protocol
> #
> INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
> + INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>
> #
> # Multiple Console IO support
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> new file mode 100644
> index 000000000000..782278615094
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
> @@ -0,0 +1,54 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = FlashFvbDxe
> + FILE_GUID = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
> + MODULE_TYPE = DXE_RUNTIME_DRIVER
> + VERSION_STRING = 0.1
> + ENTRY_POINT = FlashFvbDxeInitialize
> +
> +[Sources]
> + FlashFvbDxe.c
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> + DebugLib
> + FlashLib
> + PcdLib
> + UefiBootServicesTableLib
> + UefiDriverEntryPoint
> + UefiRuntimeLib
> +
> +[FixedPcd]
> + gAmpereTokenSpaceGuid.PcdFvBlockSize
> +
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +[Pcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
> +
> +[Guids]
> + gEfiEventVirtualAddressChangeGuid
> + gSpiNorMmGuid
> +
> +[Protocols]
> + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES
> + gEfiMmCommunicationProtocolGuid ## CONSUMES
> +
> +[Depex]
> + gEfiMmCommunicationProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> new file mode 100644
> index 000000000000..a4eaf5039bb0
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
> @@ -0,0 +1,51 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = FlashPei
> + FILE_GUID = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
> + MODULE_TYPE = PEIM
> + VERSION_STRING = 1.0
> + ENTRY_POINT = FlashPeiEntryPoint
> +
> +[Sources]
> + FlashPei.c
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + MdeModulePkg/MdeModulePkg.dec
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
> +
> +[LibraryClasses]
> + ArmSmcLib
> + BaseMemoryLib
> + DebugLib
> + MmCommunicationLib
> + PcdLib
> + PeimEntryPoint
> +
> +[Guids]
> + gSpiNorMmGuid
> +
> +[FixedPcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
> +
> +[Pcd]
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
> +
> + gAmpereTokenSpaceGuid.PcdNvramErased
> +
> +[Depex]
> + TRUE
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
> new file mode 100644
> index 000000000000..2d5003d1af17
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
> @@ -0,0 +1,36 @@
> +## @file
> +#
> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +#
> +# SPDX-License-Identifier: BSD-2-Clause-Patent
> +#
> +##
> +
> +[Defines]
> + INF_VERSION = 0x0001001B
> + BASE_NAME = FlashLib
> + FILE_GUID = 9E9D093D-6484-45AE-BA49-0745AA0BB481
> + MODULE_TYPE = DXE_DRIVER
> + VERSION_STRING = 0.1
> + LIBRARY_CLASS = FlashLib
> + CONSTRUCTOR = FlashLibConstructor
> +
> +[Sources.common]
> + FlashLib.c
> +
> +[Packages]
> + ArmPkg/ArmPkg.dec
> + ArmPlatformPkg/ArmPlatformPkg.dec
> + MdePkg/MdePkg.dec
> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
> +
> +[LibraryClasses]
> + BaseMemoryLib
> + DebugLib
> + MemoryAllocationLib
> +
> +[Guids]
> + gSpiNorMmGuid
> +
> +[Protocols]
> + gEfiMmCommunicationProtocolGuid
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> new file mode 100644
> index 000000000000..9207dee643a5
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
> @@ -0,0 +1,42 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#ifndef FLASH_LIB_H_
> +#define FLASH_LIB_H_
> +
> +EFI_STATUS
> +EFIAPI
> +FlashGetNvRamInfo (
> + OUT UINT64 *NvRamBase,
> + OUT UINT32 *NvRamSize
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashEraseCommand (
> + IN UINT8 *pBlockAddress,
> + IN UINT32 Length
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashProgramCommand (
> + IN UINT8 *pByteAddress,
> + IN UINT8 *Byte,
> + IN OUT UINTN *Length
> + );
> +
> +EFI_STATUS
> +EFIAPI
> +FlashReadCommand (
> + IN UINT8 *pByteAddress,
> + OUT UINT8 *Byte,
> + IN OUT UINTN *Length
> + );
> +
> +#endif /* FLASH_LIB_H_ */
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
> new file mode 100644
> index 000000000000..dcd92151b7d2
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
> @@ -0,0 +1,525 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Library/DebugLib.h>
> +#include <Library/FlashLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeLib.h>
> +#include <Protocol/FirmwareVolumeBlock.h>
> +
> +//
> +// These temporary buffers are used to calculate and convert linear virtual
> +// to physical address
> +//
> +STATIC UINT64 mNvFlashBase;
> +STATIC UINT32 mNvFlashSize;
> +STATIC UINT32 mFlashBlockSize;
> +STATIC UINT64 mNvStorageBase;
> +STATIC UINT64 mNvStorageSize;
> +
> +/**
> + Fixup internal data so that EFI can be call in virtual mode.
> + Call the passed in Child Notify event and convert any pointers in
> + lib to virtual mode.
> +
> + @param[in] Event The Event that is being processed
> + @param[in] Context Event Context
> +**/
> +VOID
> +EFIAPI
> +FlashFvbAddressChangeEvent (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
> +}
> +
> +/**
> + The GetAttributes() function retrieves the attributes and
> + current settings of the block.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
> + attributes and current settings are
> + returned. Type EFI_FVB_ATTRIBUTES_2 is defined
> + in EFI_FIRMWARE_VOLUME_HEADER.
> +
> + @retval EFI_SUCCESS The firmware volume attributes were
> + returned.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeGetAttributes (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes
> + )
> +{
> + ASSERT (Attributes != NULL);
> +
> + *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
> + EFI_FVB2_READ_STATUS | // Reads are currently enabled
> + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
> + EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be enabled
> + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
> + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
> + EFI_FVB2_ALIGNMENT |
> + EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1')
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The SetAttributes() function sets configurable firmware volume
> + attributes and returns the new settings of the firmware volume.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Attributes On input, Attributes is a pointer to
> + EFI_FVB_ATTRIBUTES_2 that contains the
> + desired firmware volume settings. On
> + successful return, it contains the new
> + settings of the firmware volume. Type
> + EFI_FVB_ATTRIBUTES_2 is defined in
> + EFI_FIRMWARE_VOLUME_HEADER.
> +
> + @retval EFI_SUCCESS The firmware volume attributes were returned.
> +
> + @retval EFI_INVALID_PARAMETER The attributes requested are in
> + conflict with the capabilities
> + as declared in the firmware
> + volume header.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeSetAttributes (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
> + )
> +{
> + return EFI_SUCCESS; // ignore for now
> +}
> +
> +/**
> + The GetPhysicalAddress() function retrieves the base address of
> + a memory-mapped firmware volume. This function should be called
> + only for memory-mapped firmware volumes.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Address Pointer to a caller-allocated
> + EFI_PHYSICAL_ADDRESS that, on successful
> + return from GetPhysicalAddress(), contains the
> + base address of the firmware volume.
> +
> + @retval EFI_SUCCESS The firmware volume base address was returned.
> +
> + @retval EFI_UNSUPPORTED The firmware volume is not memory mapped.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeGetPhysicalAddress (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + OUT EFI_PHYSICAL_ADDRESS *Address
> + )
> +{
> + ASSERT (Address != NULL);
> +
> + *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + The GetBlockSize() function retrieves the size of the requested
> + block. It also returns the number of additional blocks with
> + the identical size. The GetBlockSize() function is used to
> + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
> +
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba Indicates the block for which to return the size.
> +
> + @param BlockSize Pointer to a caller-allocated UINTN in which
> + the size of the block is returned.
> +
> + @param NumberOfBlocks Pointer to a caller-allocated UINTN in
> + which the number of consecutive blocks,
> + starting with Lba, is returned. All
> + blocks in this range have a size of
> + BlockSize.
> +
> +
> + @retval EFI_SUCCESS The firmware volume base address was returned.
> +
> + @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeGetBlockSize (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN EFI_LBA Lba,
> + OUT UINTN *BlockSize,
> + OUT UINTN *NumberOfBlocks
> + )
> +{
> + UINTN TotalNvStorageBlocks;
> +
> + ASSERT (BlockSize != NULL);
> + ASSERT (NumberOfBlocks != NULL);
> +
> + TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
> +
> + if (TotalNvStorageBlocks <= (UINTN)Lba) {
> + DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
> + *BlockSize = mFlashBlockSize;
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Reads the specified number of bytes into a buffer from the specified block.
> +
> + The Read() function reads the requested number of bytes from the
> + requested block and stores them in the provided buffer.
> + Implementations should be mindful that the firmware volume
> + might be in the ReadDisabled state. If it is in this state,
> + the Read() function must return the status code
> + EFI_ACCESS_DENIED without modifying the contents of the
> + buffer. The Read() function must also prevent spanning block
> + boundaries. If a read is requested that would span a block
> + boundary, the read must read up to the boundary but not
> + beyond. The output parameter NumBytes must be set to correctly
> + indicate the number of bytes actually read. The caller must be
> + aware that a read may be partially completed.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba The starting logical block index
> + from which to read.
> +
> + @param Offset Offset into the block at which to begin reading.
> +
> + @param NumBytes Pointer to a UINTN. At entry, *NumBytes
> + contains the total size of the buffer. At
> + exit, *NumBytes contains the total number of
> + bytes read.
> +
> + @param Buffer Pointer to a caller-allocated buffer that will
> + be used to hold the data that is read.
> +
> + @retval EFI_SUCCESS The firmware volume was read successfully,
> + and contents are in Buffer.
> +
> + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
> + boundary. On output, NumBytes
> + contains the total number of bytes
> + returned in Buffer.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the
> + ReadDisabled state.
> +
> + @retval EFI_DEVICE_ERROR The block device is not
> + functioning correctly and could
> + not be read.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeRead (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN OUT UINTN *NumBytes,
> + IN OUT UINT8 *Buffer
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT (NumBytes != NULL);
> + ASSERT (Buffer != NULL);
> +
> + if (Offset + *NumBytes > mFlashBlockSize) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + Status = FlashReadCommand (
> + (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
> + Buffer,
> + NumBytes
> + );
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Writes the specified number of bytes from the input buffer to the block.
> +
> + The Write() function writes the specified number of bytes from
> + the provided buffer to the specified block and offset. If the
> + firmware volume is sticky write, the caller must ensure that
> + all the bits of the specified range to write are in the
> + EFI_FVB_ERASE_POLARITY state before calling the Write()
> + function, or else the result will be unpredictable. This
> + unpredictability arises because, for a sticky-write firmware
> + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
> + state but cannot flip it back again. Before calling the
> + Write() function, it is recommended for the caller to first call
> + the EraseBlocks() function to erase the specified block to
> + write. A block erase cycle will transition bits from the
> + (NOT)EFI_FVB_ERASE_POLARITY state back to the
> + EFI_FVB_ERASE_POLARITY state. Implementations should be
> + mindful that the firmware volume might be in the WriteDisabled
> + state. If it is in this state, the Write() function must
> + return the status code EFI_ACCESS_DENIED without modifying the
> + contents of the firmware volume. The Write() function must
> + also prevent spanning block boundaries. If a write is
> + requested that spans a block boundary, the write must store up
> + to the boundary but not beyond. The output parameter NumBytes
> + must be set to correctly indicate the number of bytes actually
> + written. The caller must be aware that a write may be
> + partially completed. All writes, partial or otherwise, must be
> + fully flushed to the hardware before the Write() service
> + returns.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
> +
> + @param Lba The starting logical block index to write to.
> +
> + @param Offset Offset into the block at which to begin writing.
> +
> + @param NumBytes The pointer to a UINTN. At entry, *NumBytes
> + contains the total size of the buffer. At
> + exit, *NumBytes contains the total number of
> + bytes actually written.
> +
> + @param Buffer The pointer to a caller-allocated buffer that
> + contains the source for the write.
> +
> + @retval EFI_SUCCESS The firmware volume was written successfully.
> +
> + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
> + LBA boundary. On output, NumBytes
> + contains the total number of bytes
> + actually written.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the
> + WriteDisabled state.
> +
> + @retval EFI_DEVICE_ERROR The block device is malfunctioning
> + and could not be written.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeWrite (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + IN EFI_LBA Lba,
> + IN UINTN Offset,
> + IN OUT UINTN *NumBytes,
> + IN UINT8 *Buffer
> + )
> +{
> + EFI_STATUS Status;
> +
> + ASSERT (NumBytes != NULL);
> + ASSERT (Buffer != NULL);
> +
> + if (Offset + *NumBytes > mFlashBlockSize) {
> + return EFI_BAD_BUFFER_SIZE;
> + }
> +
> + Status = FlashProgramCommand (
> + (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
> + Buffer,
> + NumBytes
> + );
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return Status;
> +}
> +
> +/**
> + Erases and initializes a firmware volume block.
> +
> + The EraseBlocks() function erases one or more blocks as denoted
> + by the variable argument list. The entire parameter list of
> + blocks must be verified before erasing any blocks. If a block is
> + requested that does not exist within the associated firmware
> + volume (it has a larger index than the last block of the
> + firmware volume), the EraseBlocks() function must return the
> + status code EFI_INVALID_PARAMETER without modifying the contents
> + of the firmware volume. Implementations should be mindful that
> + the firmware volume might be in the WriteDisabled state. If it
> + is in this state, the EraseBlocks() function must return the
> + status code EFI_ACCESS_DENIED without modifying the contents of
> + the firmware volume. All calls to EraseBlocks() must be fully
> + flushed to the hardware before the EraseBlocks() service
> + returns.
> +
> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
> + instance.
> +
> + @param ... The variable argument list is a list of tuples.
> + Each tuple describes a range of LBAs to erase
> + and consists of the following:
> + - An EFI_LBA that indicates the starting LBA
> + - A UINTN that indicates the number of blocks to
> + erase.
> +
> + The list is terminated with an
> + EFI_LBA_LIST_TERMINATOR. For example, the
> + following indicates that two ranges of blocks
> + (5-7 and 10-11) are to be erased: EraseBlocks
> + (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
> +
> + @retval EFI_SUCCESS The erase request successfully
> + completed.
> +
> + @retval EFI_ACCESS_DENIED The firmware volume is in the
> + WriteDisabled state.
> + @retval EFI_DEVICE_ERROR The block device is not functioning
> + correctly and could not be written.
> + The firmware device may have been
> + partially erased.
> + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
> + in the variable argument list do
> + not exist in the firmware volume.
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeErase (
> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
> + ...
> + )
> +{
> + VA_LIST Args;
> + EFI_LBA Start;
> + UINTN Length;
> + EFI_STATUS Status;
> +
> + Status = EFI_SUCCESS;
> +
> + VA_START (Args, This);
> +
> + for (Start = VA_ARG (Args, EFI_LBA);
> + Start != EFI_LBA_LIST_TERMINATOR;
> + Start = VA_ARG (Args, EFI_LBA))
> + {
> + Length = VA_ARG (Args, UINTN);
> + Status = FlashEraseCommand (
> + (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
> + Length * mFlashBlockSize
> + );
> + }
> +
> + VA_END (Args);
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
> + FlashFvbDxeGetAttributes,
> + FlashFvbDxeSetAttributes,
> + FlashFvbDxeGetPhysicalAddress,
> + FlashFvbDxeGetBlockSize,
> + FlashFvbDxeRead,
> + FlashFvbDxeWrite,
> + FlashFvbDxeErase
> +};
> +
> +EFI_STATUS
> +EFIAPI
> +FlashFvbDxeInitialize (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_STATUS Status;
> + EFI_HANDLE FvbHandle = NULL;
> + EFI_EVENT VirtualAddressChangeEvent;
> +
> + // Get NV store FV info
> + mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
> + mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
> + mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
> + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
> + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> + DEBUG ((
> + DEBUG_INFO,
> + "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
> + __FUNCTION__,
> + mNvStorageBase,
> + mNvStorageSize
> + ));
> +
> + // Get NV Flash information
> + Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + if (mNvFlashSize >= (mNvStorageSize * 2)) {
> + DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
> + } else {
> + DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Status = gBS->CreateEventEx (
> + EVT_NOTIFY_SIGNAL,
> + TPL_NOTIFY,
> + FlashFvbAddressChangeEvent,
> + NULL,
> + &gEfiEventVirtualAddressChangeGuid,
> + &VirtualAddressChangeEvent
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->InstallMultipleProtocolInterfaces (
> + &FvbHandle,
> + &gEfiFirmwareVolumeBlockProtocolGuid,
> + &mFlashFvbProtocol,
> + NULL
> + );
> +
> + if (EFI_ERROR (Status)) {
> + DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
> + return Status;
> + }
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
> new file mode 100644
> index 000000000000..6bfbbbebaa85
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
> @@ -0,0 +1,283 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <PiPei.h>
> +#include <Uefi.h>
> +
> +#include <Library/ArmSmcLib.h>
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/MmCommunicationLib.h>
> +#include <Library/PcdLib.h>
> +#include <Library/PeimEntryPoint.h>
> +#include <MmLib.h>
> +
> +// Convert to string
> +#define _STR(x) #x
> +
> +// Make sure the argument is expanded before converting to string
> +#define STR(x) _STR(x)
> +
> +// Use dynamic UEFI_UUID of each build time
> +#define UEFI_UUID_BUILD STR(UEFI_UUID)
> +
> +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
> +
> +STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
> +STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
> +
> +STATIC
> +EFI_STATUS
> +UefiMmCreateSpiNorReq (
> + VOID *Data,
> + UINT64 Size
> + )
> +{
> + CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
> + mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
> +
> + if (Size != 0) {
> + ASSERT (Data);
> + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
> +
> + CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Entry point function for the PEIM
> +
> + @param FileHandle Handle of the file being invoked.
> + @param PeiServices Describes the list of possible PEI Services.
> +
> + @return EFI_SUCCESS If we installed our PPI
> +
> +**/
> +EFI_STATUS
> +EFIAPI
> +FlashPeiEntryPoint (
> + IN EFI_PEI_FILE_HANDLE FileHandle,
> + IN CONST EFI_PEI_SERVICES **PeiServices
> + )
> +{
> + UINT64 FWNvRamStartOffset;
> + EFI_STATUS Status;
> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
> + UINT64 MmData[5];
> + UINTN Size;
> + VOID *NvRamAddress;
> + UINTN NvRamSize;
> +
> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
> + UINT64 NV2Base, NV2Size;
> +#endif
> +
> + NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
> + NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
> + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
> + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
> +
> + /* Find out about the start offset of NVRAM to be passed to SMC */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
> + /* Old FW so just exit */
> + return EFI_SUCCESS;
> + }
> + FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
> +
> + CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
> + if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
> + /* NVRAM size provided by FW is not enough */
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_READ;
> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> + MmData[2] = (UINT64)sizeof (mStoredUuid);
> + MmData[3] = (UINT64)mStoredUuid;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> +
> + if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_ERASE;
> + MmData[1] = (UINT64)FWNvRamStartOffset;
> + MmData[2] = (UINT64)(NvRamSize * 2);
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> +
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_WRITE;
> + MmData[1] = (UINT64)FWNvRamStartOffset;
> + MmData[2] = (UINT64)(NvRamSize * 2);
> + MmData[3] = (UINT64)NvRamAddress;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> +
> + /* Update UUID */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_ERASE;
> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> + MmData[2] = (UINT64)sizeof (mBuildUuid);
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> +
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_WRITE;
> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
> + MmData[2] = (UINT64)sizeof (mBuildUuid);
> + MmData[3] = (UINT64)mBuildUuid;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> + DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
> +
> + /* Indicate that NVRAM was cleared */
> + PcdSetBoolS (PcdNvramErased, TRUE);
> + } else {
> + /* Copy the stored NVRAM to RAM */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_READ;
> + MmData[1] = (UINT64)FWNvRamStartOffset;
> + MmData[2] = (UINT64)(NvRamSize * 2);
> + MmData[3] = (UINT64)NvRamAddress;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + return Status;
> + }
> + DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
> + }
> +
> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
> + /* Find out about the start offset of NVRAM2 to be passed to SMC */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
> + if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
> + NV2Base = MmSpiNorNV2InfoRes->NVBase;
> + NV2Size = MmSpiNorNV2InfoRes->NVSize;
> + /* Make sure the requested size is smaller than allocated */
> + if (RAM_BLOCKIO_SIZE <= NV2Size) {
> + /* Copy the ramdisk image to RAM */
> + ZeroMem ((VOID *)MmData, sizeof (MmData));
> + MmData[0] = MM_SPINOR_FUNC_READ;
> + MmData[1] = (UINT64)NV2Base; /* Start virtual address */
> + MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
> + MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = MmCommunicationCommunicate (
> + (VOID *)&mEfiMmSpiNorReq,
> + &Size
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
> + ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
> + }
> +
> + BuildMemoryAllocationHob (
> + (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
> + EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
> + EfiLoaderData
> + );
> + }
> +#endif
> +
> + return EFI_SUCCESS;
> +}
> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
> new file mode 100644
> index 000000000000..cd77aed3cfe1
> --- /dev/null
> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
> @@ -0,0 +1,358 @@
> +/** @file
> +
> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
> +
> + SPDX-License-Identifier: BSD-2-Clause-Patent
> +
> +**/
> +
> +#include <Uefi.h>
> +
> +#include <Library/BaseMemoryLib.h>
> +#include <Library/DebugLib.h>
> +#include <Library/FlashLib.h>
> +#include <Library/MemoryAllocationLib.h>
> +#include <Library/UefiBootServicesTableLib.h>
> +#include <Library/UefiRuntimeServicesTableLib.h>
> +#include <MmLib.h>
> +#include <Protocol/MmCommunication.h>
> +
> +STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
> +STATIC EFI_MM_COMM_REQUEST *mCommBuffer = NULL;
> +
> +BOOLEAN mIsEfiRuntime;
> +UINT8 *mTmpBufVirt;
> +UINT8 *mTmpBufPhy;
> +
> +/**
> + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
> + event. It converts a pointer to a new virtual address.
> +
> + @param Event Event whose notification function is being invoked.
> + @param Context Pointer to the notification function's context
> +
> +**/
> +VOID
> +EFIAPI
> +FlashLibAddressChangeEvent (
> + IN EFI_EVENT Event,
> + IN VOID *Context
> + )
> +{
> + gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
> + gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
> + gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
> +
> + mIsEfiRuntime = TRUE;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashLibConstructor (
> + IN EFI_HANDLE ImageHandle,
> + IN EFI_SYSTEM_TABLE *SystemTable
> + )
> +{
> + EFI_EVENT VirtualAddressChangeEvent = NULL;
> + EFI_STATUS Status = EFI_SUCCESS;
> +
> + mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
> + ASSERT (mCommBuffer != NULL);
> +
> + mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
> + mTmpBufVirt = mTmpBufPhy;
> + ASSERT (mTmpBufPhy != NULL);
> +
> + Status = gBS->LocateProtocol (
> + &gEfiMmCommunicationProtocolGuid,
> + NULL,
> + (VOID **)&mMmCommunicationProtocol
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + Status = gBS->CreateEvent (
> + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
> + TPL_CALLBACK,
> + FlashLibAddressChangeEvent,
> + NULL,
> + &VirtualAddressChangeEvent
> + );
> + ASSERT_EFI_ERROR (Status);
> +
> + return EFI_SUCCESS;
> +}
> +
> +STATIC
> +EFI_STATUS
> +FlashMmCommunicate (
> + IN OUT VOID *CommBuffer,
> + IN OUT UINTN *CommSize
> + )
> +{
> + if (mMmCommunicationProtocol == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + return mMmCommunicationProtocol->Communicate (
> + mMmCommunicationProtocol,
> + CommBuffer,
> + CommSize
> + );
> +}
> +
> +STATIC
> +EFI_STATUS
> +UefiMmCreateSpiNorReq (
> + IN VOID *Data,
> + IN UINT64 Size
> + )
> +{
> + if (mCommBuffer == NULL) {
> + return EFI_INVALID_PARAMETER;
> + }
> +
> + CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
> + mCommBuffer->EfiMmHdr.MsgLength = Size;
> +
> + if (Size != 0) {
> + ASSERT (Data);
> + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
> +
> + CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +/**
> + Convert Virtual Address to Physical Address at Runtime Services
> +
> + @param VirtualPtr Virtual Address Pointer
> + @param Size Total bytes of the buffer
> +
> + @retval Ptr Return the pointer of the converted address
> +
> +**/
> +STATIC
> +UINT8 *
> +ConvertVirtualToPhysical (
> + IN UINT8 *VirtualPtr,
> + IN UINTN Size
> + )
> +{
> + if (mIsEfiRuntime) {
> + ASSERT (VirtualPtr != NULL);
> + CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
> + return (UINT8 *)mTmpBufPhy;
> + }
> +
> + return (UINT8 *)VirtualPtr;
> +}
> +
> +/**
> + Convert Physical Address to Virtual Address at Runtime Services
> +
> + @param VirtualPtr Physical Address Pointer
> + @param Size Total bytes of the buffer
> +
> +**/
> +STATIC
> +VOID
> +ConvertPhysicaltoVirtual (
> + IN UINT8 *PhysicalPtr,
> + IN UINTN Size
> + )
> +{
> + if (mIsEfiRuntime) {
> + ASSERT (PhysicalPtr != NULL);
> + CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
> + }
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashGetNvRamInfo (
> + OUT UINT64 *NvRamBase,
> + OUT UINT32 *NvRamSize
> + )
> +{
> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
> + EFI_STATUS Status;
> + UINT64 MmData[5];
> + UINTN Size;
> +
> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
> +
> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = FlashMmCommunicate (
> + mCommBuffer,
> + &Size
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
> + if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
> + *NvRamBase = MmSpiNorNVInfoRes->NVBase;
> + *NvRamSize = MmSpiNorNVInfoRes->NVSize;
> + DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashEraseCommand (
> + IN UINT8 *pBlockAddress,
> + IN UINT32 Length
> + )
> +{
> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> + EFI_STATUS Status;
> + UINT64 MmData[5];
> + UINTN Size;
> +
> + ASSERT (pBlockAddress != NULL);
> +
> + MmData[0] = MM_SPINOR_FUNC_ERASE;
> + MmData[1] = (UINT64)pBlockAddress;
> + MmData[2] = Length;
> +
> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = FlashMmCommunicate (
> + mCommBuffer,
> + &Size
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashProgramCommand (
> + IN UINT8 *pByteAddress,
> + IN UINT8 *Byte,
> + IN OUT UINTN *Length
> + )
> +{
> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> + EFI_STATUS Status;
> + UINT64 MmData[5];
> + UINTN Remain, Size, NumWrite;
> + UINTN Count = 0;
> +
> + ASSERT (pByteAddress != NULL);
> + ASSERT (Byte != NULL);
> + ASSERT (Length != NULL);
> +
> + Remain = *Length;
> + while (Remain > 0) {
> + NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
> +
> + MmData[0] = MM_SPINOR_FUNC_WRITE;
> + MmData[1] = (UINT64)pByteAddress;
> + MmData[2] = NumWrite;
> + MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
> +
> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = FlashMmCommunicate (
> + mCommBuffer,
> + &Size
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + Remain -= NumWrite;
> + Count += NumWrite;
> + }
> +
> + return EFI_SUCCESS;
> +}
> +
> +EFI_STATUS
> +EFIAPI
> +FlashReadCommand (
> + IN UINT8 *pByteAddress,
> + OUT UINT8 *Byte,
> + IN OUT UINTN *Length
> + )
> +{
> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
> + EFI_STATUS Status;
> + UINT64 MmData[5];
> + UINTN Remain, Size, NumRead;
> + UINTN Count = 0;
> +
> + ASSERT (pByteAddress != NULL);
> + ASSERT (Byte != NULL);
> + ASSERT (Length != NULL);
> +
> + Remain = *Length;
> + while (Remain > 0) {
> + NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
> +
> + MmData[0] = MM_SPINOR_FUNC_READ;
> + MmData[1] = (UINT64)pByteAddress;
> + MmData[2] = NumRead;
> + MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
> +
> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
> + Status = FlashMmCommunicate (
> + mCommBuffer,
> + &Size
> + );
> + if (EFI_ERROR (Status)) {
> + return Status;
> + }
> +
> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
> + DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
> + return EFI_DEVICE_ERROR;
> + }
> +
> + ConvertPhysicaltoVirtual (Byte + Count, NumRead);
> + Remain -= NumRead;
> + Count += NumRead;
> + }
> +
> + return EFI_SUCCESS;
> +}
> --
> 2.17.1
>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76090): https://edk2.groups.io/g/devel/message/76090
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
On 6/5/21 06:36, Leif Lindholm wrote:
> On Wed, May 26, 2021 at 17:07:01 +0700, Nhi Pham wrote:
>> From: Vu Nguyen <vunguyen@os.amperecomputing.com>
>>
>> Non-volatile variables now can be stored on flash. MM communication
>> protocol is used to access storage on flash.
>>
>> Included in this change are:
>> * FlashPei module is used to compare saved UUID with firmware's
>> UEFI_UUID on each boot. If UUIDs match, data is stored to RAM.
>> Otherwise fill the storage with default value from NVRAM FV.
>> * FlashLib provide APIs to access flash through MM Communication
>> protocol
>> * FlashFvbDxe installs gEfiFirmwareVolumeBlock protocol which will be
>> used by the variable services to get/set variables.
>>
>> Cc: Thang Nguyen <thang@os.amperecomputing.com>
>> Cc: Chuong Tran <chuong@os.amperecomputing.com>
>> Cc: Phong Vo <phong@os.amperecomputing.com>
>> Cc: Leif Lindholm <leif@nuviainc.com>
>> Cc: Michael D Kinney <michael.d.kinney@intel.com>
>> Cc: Ard Biesheuvel <ardb+tianocore@kernel.org>
>> Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
>>
>> Signed-off-by: Vu Nguyen <vunguyen@os.amperecomputing.com>
>> ---
>> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec | 3 +
>> Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec | 3 +
>> Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc | 11 +-
>> Platform/Ampere/JadePkg/Jade.dsc | 1 +
>> Platform/Ampere/JadePkg/Jade.fdf | 62 ++-
>> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf | 54 ++
>> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf | 51 ++
>> Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf | 36 ++
>> Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h | 42 ++
>> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c | 525 ++++++++++++++++++++
>> Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c | 283 +++++++++++
>> Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c | 358 +++++++++++++
>> 12 files changed, 1425 insertions(+), 4 deletions(-)
>>
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> index be827dd19a96..d5b12a81e9bf 100644
>> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> @@ -37,6 +37,9 @@ [LibraryClasses]
>> ## @libraryclass Defines a set of methods to communicate with secure parition over MM interface.
>> MmCommunicationLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/MmCommunicationLib.h
>>
>> + ## @libraryclass Defines a set of methods to access flash memory.
>> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> +
>> ## @libraryclass Defines a set of methods to generate random numbers by using Hardware RNG.
>> TrngLib|Silicon/Ampere/AmpereAltraPkg/Include/Library/TrngLib.h
>>
>> diff --git a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> index 6ebdf7db0a57..26e020715290 100755
>> --- a/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +++ b/Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> @@ -44,3 +44,6 @@ [PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx]
>> # Firmware Volume Pcds
>> #
>> gAmpereTokenSpaceGuid.PcdFvBlockSize|0|UINT32|0xB0000001
>> +
>> + # NVRam Pcds
>> + gAmpereTokenSpaceGuid.PcdNvramErased|FALSE|BOOLEAN|0xB0000009
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> index 9f75da6f05ad..65973569a41d 100755
>> --- a/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> +++ b/Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dsc.inc
>> @@ -14,6 +14,7 @@ [BuildOptions.common.EDKII.DXE_RUNTIME_DRIVER]
>>
>> [BuildOptions]
>> GCC:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG
>> + GCC:*_*_*_CC_FLAGS = -DUEFI_UUID=$(UEFI_UUID)
> This isn't obvious enough. I'm a bear of very little brain, and I
> could possibly figure out what's happening here, given time, but
> please put a proper description in commit message (and possibly here?
> whatever makes sense).
Thanks, Leif. I will use a PCD instead of build option flag like above
and will update the commit message to explain how it works.
Best regards,
Nhi
>
>>
>> [LibraryClasses.common]
>> !if $(TARGET) == RELEASE
>> @@ -224,6 +225,7 @@ [LibraryClasses.common.DXE_DRIVER]
>> SecurityManagementLib|MdeModulePkg/Library/DxeSecurityManagementLib/DxeSecurityManagementLib.inf
>> PerformanceLib|MdeModulePkg/Library/DxePerformanceLib/DxePerformanceLib.inf
>> MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
>> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>>
>> [LibraryClasses.common.UEFI_APPLICATION]
>> UefiDecompressLib|MdePkg/Library/BaseUefiDecompressLib/BaseUefiTianoCustomDecompressLib.inf
>> @@ -254,6 +256,7 @@ [LibraryClasses.common.DXE_RUNTIME_DRIVER]
>>
>> EfiResetSystemLib|ArmPkg/Library/ArmPsciResetSystemLib/ArmPsciResetSystemLib.inf
>> ArmSmcLib|ArmPkg/Library/ArmSmcLib/ArmSmcLib.inf
>> + FlashLib|Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>>
>> [LibraryClasses.ARM,LibraryClasses.AARCH64]
>> #
>> @@ -500,6 +503,8 @@ [PcdsDynamicDefault.common]
>> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|0x0
>> gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|0x0
>>
>> + gAmpereTokenSpaceGuid.PcdNvramErased|FALSE
>> +
>> ################################################################################
>> #
>> # Component Section - list of all EDK II Component Entries defined by this Platform
>> @@ -520,8 +525,10 @@ [Components.common]
>> Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>> Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>> Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
>> + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> ArmPkg/Drivers/CpuPei/CpuPei.inf
>> UefiCpuPkg/CpuIoPei/CpuIoPei.inf
>> + MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>> MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>> MdeModulePkg/Core/DxeIplPeim/DxeIpl.inf {
>> <LibraryClasses>
>> @@ -575,9 +582,9 @@ [Components.common]
>> #
>> # Environment Variables Protocol
>> #
>> + Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> + MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>> MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf {
>> - <PcdsFixedAtBuild>
>> - gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE
>> <LibraryClasses>
>> BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
>> TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurementLibNull.inf
>> diff --git a/Platform/Ampere/JadePkg/Jade.dsc b/Platform/Ampere/JadePkg/Jade.dsc
>> index f37ab1a92e44..9b9a5d0bad0f 100755
>> --- a/Platform/Ampere/JadePkg/Jade.dsc
>> +++ b/Platform/Ampere/JadePkg/Jade.dsc
>> @@ -52,6 +52,7 @@ [Defines]
>> DEFINE EDK2_SKIP_PEICORE = TRUE
>> DEFINE SECURE_BOOT_ENABLE = FALSE
>> DEFINE INCLUDE_TFTP_COMMAND = TRUE
>> + DEFINE UEFI_UUID = 84BC921F-9D4A-4D1D-A1A1-1AE13EDD07E5
> This is a horrible name for a UUID. What is it meant to identify?
>
>> #
>> # Network definition
>> diff --git a/Platform/Ampere/JadePkg/Jade.fdf b/Platform/Ampere/JadePkg/Jade.fdf
>> index 1857296a8ea5..375455086d0b 100755
>> --- a/Platform/Ampere/JadePkg/Jade.fdf
>> +++ b/Platform/Ampere/JadePkg/Jade.fdf
>> @@ -26,7 +26,7 @@ [FD.BL33_JADE_UEFI]
>> ErasePolarity = 1
>>
>> # This one is tricky, it must be: BlockSize * NumBlocks = Size
>> -BlockSize = 0x10000
>> +BlockSize = 0x10000|gAmpereTokenSpaceGuid.PcdFvBlockSize
>> NumBlocks = 0x7C
>>
>> ################################################################################
>> @@ -56,8 +56,61 @@ [FD.BL33_JADE_UEFI]
>>
>> #
>> # NV Variables
>> -# T.B.D
> Ah. If I can make a retroactive comment - could this be introduced as
> "Placeholder" rather than "T.B.D."?
>
> /
> Leif
>
>> +# Offset: 0x00740000
>> +# Size: 0x00080000
>> #
>> +0x00740000|0x00030000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> +DATA = {
>> + ## This is the EFI_FIRMWARE_VOLUME_HEADER
>> + # ZeroVector []
>> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> + # FileSystemGuid: gEfiSystemNvDataFvGuid =
>> + # { 0xFFF12B8D, 0x7696, 0x4C8B,
>> + # { 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50 }}
>> + 0x8D, 0x2B, 0xF1, 0xFF, 0x96, 0x76, 0x8B, 0x4C,
>> + 0xA9, 0x85, 0x27, 0x47, 0x07, 0x5B, 0x4F, 0x50,
>> + # FvLength: 0x80000
>> + 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00,
>> + # Signature "_FVH" # Attributes
>> + 0x5f, 0x46, 0x56, 0x48, 0xff, 0xfe, 0x04, 0x00,
>> + # HeaderLength # CheckSum # ExtHeaderOffset #Reserved #Revision
>> + 0x48, 0x00, 0x2D, 0x09, 0x00, 0x00, 0x00, 0x02,
>> + # Blockmap[0]: 0x2 Blocks * 0x40000 Bytes / Block
>> + 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00,
>> + # Blockmap[1]: End
>> + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
>> + ## This is the VARIABLE_STORE_HEADER
>> + # It is compatible with SECURE_BOOT_ENABLE == FALSE as well.
>> + # Signature: gEfiAuthenticatedVariableGuid =
>> + # { 0xaaf32c78, 0x947b, 0x439a,
>> + # { 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92 }}
>> + 0x78, 0x2c, 0xf3, 0xaa, 0x7b, 0x94, 0x9a, 0x43,
>> + 0xa1, 0x80, 0x2e, 0x14, 0x4e, 0xc3, 0x77, 0x92,
>> + # Size: 0x30000 (gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize) -
>> + # 0x48 (size of EFI_FIRMWARE_VOLUME_HEADER) = 0x2FFB8
>> + # This can speed up the Variable Dispatch a bit.
>> + 0xB8, 0xFF, 0x02, 0x00,
>> + # FORMATTED: 0x5A #HEALTHY: 0xFE #Reserved: UINT16 #Reserved1: UINT32
>> + 0x5A, 0xFE, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +}
>> +
>> +0x00770000|0x00010000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> +DATA = {
>> + # EFI_FAULT_TOLERANT_WORKING_BLOCK_HEADER->Signature = gEdkiiWorkingBlockSignatureGuid =
>> + # { 0x9e58292b, 0x7c68, 0x497d, { 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95 }}
>> + 0x2b, 0x29, 0x58, 0x9e, 0x68, 0x7c, 0x7d, 0x49,
>> + 0xa0, 0xce, 0x65, 0x0, 0xfd, 0x9f, 0x1b, 0x95,
>> + # Crc:UINT32 #WorkingBlockValid:1, WorkingBlockInvalid:1, Reserved
>> + 0x2c, 0xaf, 0x2c, 0x64, 0xFE, 0xFF, 0xFF, 0xFF,
>> + # WriteQueueSize: UINT64 Size: 0x10000 - 0x20 (FTW_WORKING_HEADER) = 0xFFE0
>> + 0xE0, 0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
>> +}
>> +
>> +0x00780000|0x00040000
>> +gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64|gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>>
>> ################################################################################
>> #
>> @@ -102,9 +155,11 @@ [FV.FVMAIN_COMPACT]
>> INF Silicon/Ampere/AmpereAltraPkg/Drivers/ATFHobPei/ATFHobPeim.inf
>> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MemoryInitPeim/MemoryInitPeim.inf
>> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationPei/MmCommunicationPei.inf
>> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> INF Silicon/Ampere/AmpereAltraPkg/Drivers/BootProgress/BootProgressPeim/BootProgressPeim.inf
>> INF ArmPkg/Drivers/CpuPei/CpuPei.inf
>> INF MdeModulePkg/Universal/PCD/Pei/Pcd.inf
>> + INF MdeModulePkg/Universal/FaultTolerantWritePei/FaultTolerantWritePei.inf
>> INF MdeModulePkg/Universal/Variable/Pei/VariablePei.inf
>> INF MdeModulePkg/Universal/ReportStatusCodeRouter/Pei/ReportStatusCodeRouterPei.inf
>> INF MdeModulePkg/Universal/StatusCodeHandler/Pei/StatusCodeHandlerPei.inf
>> @@ -144,6 +199,7 @@ [FV.FvMain]
>> INF MdeModulePkg/Universal/ReportStatusCodeRouter/RuntimeDxe/ReportStatusCodeRouterRuntimeDxe.inf
>> INF MdeModulePkg/Universal/StatusCodeHandler/RuntimeDxe/StatusCodeHandlerRuntimeDxe.inf
>> INF Silicon/Ampere/AmpereAltraPkg/Drivers/MmCommunicationDxe/MmCommunication.inf
>> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> }
>>
>> INF MdeModulePkg/Core/Dxe/DxeMain.inf
>> @@ -173,6 +229,8 @@ [FV.FvMain]
>> # Environment Variables Protocol
>> #
>> INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf
>> + INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteDxe.inf
>> + INF Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>>
>> #
>> # Multiple Console IO support
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> new file mode 100644
>> index 000000000000..782278615094
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.inf
>> @@ -0,0 +1,54 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x0001001B
>> + BASE_NAME = FlashFvbDxe
>> + FILE_GUID = 9E6EA240-DF80-11EA-8B6E-0800200C9A66
>> + MODULE_TYPE = DXE_RUNTIME_DRIVER
>> + VERSION_STRING = 0.1
>> + ENTRY_POINT = FlashFvbDxeInitialize
>> +
>> +[Sources]
>> + FlashFvbDxe.c
>> +
>> +[Packages]
>> + ArmPkg/ArmPkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + MdePkg/MdePkg.dec
>> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +
>> +[LibraryClasses]
>> + DebugLib
>> + FlashLib
>> + PcdLib
>> + UefiBootServicesTableLib
>> + UefiDriverEntryPoint
>> + UefiRuntimeLib
>> +
>> +[FixedPcd]
>> + gAmpereTokenSpaceGuid.PcdFvBlockSize
>> +
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +[Pcd]
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
>> +
>> +[Guids]
>> + gEfiEventVirtualAddressChangeGuid
>> + gSpiNorMmGuid
>> +
>> +[Protocols]
>> + gEfiFirmwareVolumeBlockProtocolGuid ## PRODUCES
>> + gEfiMmCommunicationProtocolGuid ## CONSUMES
>> +
>> +[Depex]
>> + gEfiMmCommunicationProtocolGuid
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> new file mode 100644
>> index 000000000000..a4eaf5039bb0
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.inf
>> @@ -0,0 +1,51 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x0001001B
>> + BASE_NAME = FlashPei
>> + FILE_GUID = 967CFBD0-DF81-11EA-8B6E-0800200C9A66
>> + MODULE_TYPE = PEIM
>> + VERSION_STRING = 1.0
>> + ENTRY_POINT = FlashPeiEntryPoint
>> +
>> +[Sources]
>> + FlashPei.c
>> +
>> +[Packages]
>> + ArmPkg/ArmPkg.dec
>> + MdeModulePkg/MdeModulePkg.dec
>> + MdePkg/MdePkg.dec
>> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> + Silicon/Ampere/AmpereSiliconPkg/AmpereSiliconPkg.dec
>> +
>> +[LibraryClasses]
>> + ArmSmcLib
>> + BaseMemoryLib
>> + DebugLib
>> + MmCommunicationLib
>> + PcdLib
>> + PeimEntryPoint
>> +
>> +[Guids]
>> + gSpiNorMmGuid
>> +
>> +[FixedPcd]
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize
>> +
>> +[Pcd]
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase64
>> + gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase64
>> +
>> + gAmpereTokenSpaceGuid.PcdNvramErased
>> +
>> +[Depex]
>> + TRUE
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>> new file mode 100644
>> index 000000000000..2d5003d1af17
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.inf
>> @@ -0,0 +1,36 @@
>> +## @file
>> +#
>> +# Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +#
>> +# SPDX-License-Identifier: BSD-2-Clause-Patent
>> +#
>> +##
>> +
>> +[Defines]
>> + INF_VERSION = 0x0001001B
>> + BASE_NAME = FlashLib
>> + FILE_GUID = 9E9D093D-6484-45AE-BA49-0745AA0BB481
>> + MODULE_TYPE = DXE_DRIVER
>> + VERSION_STRING = 0.1
>> + LIBRARY_CLASS = FlashLib
>> + CONSTRUCTOR = FlashLibConstructor
>> +
>> +[Sources.common]
>> + FlashLib.c
>> +
>> +[Packages]
>> + ArmPkg/ArmPkg.dec
>> + ArmPlatformPkg/ArmPlatformPkg.dec
>> + MdePkg/MdePkg.dec
>> + Silicon/Ampere/AmpereAltraPkg/AmpereAltraPkg.dec
>> +
>> +[LibraryClasses]
>> + BaseMemoryLib
>> + DebugLib
>> + MemoryAllocationLib
>> +
>> +[Guids]
>> + gSpiNorMmGuid
>> +
>> +[Protocols]
>> + gEfiMmCommunicationProtocolGuid
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> new file mode 100644
>> index 000000000000..9207dee643a5
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Include/Library/FlashLib.h
>> @@ -0,0 +1,42 @@
>> +/** @file
>> +
>> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#ifndef FLASH_LIB_H_
>> +#define FLASH_LIB_H_
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashGetNvRamInfo (
>> + OUT UINT64 *NvRamBase,
>> + OUT UINT32 *NvRamSize
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashEraseCommand (
>> + IN UINT8 *pBlockAddress,
>> + IN UINT32 Length
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashProgramCommand (
>> + IN UINT8 *pByteAddress,
>> + IN UINT8 *Byte,
>> + IN OUT UINTN *Length
>> + );
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashReadCommand (
>> + IN UINT8 *pByteAddress,
>> + OUT UINT8 *Byte,
>> + IN OUT UINTN *Length
>> + );
>> +
>> +#endif /* FLASH_LIB_H_ */
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
>> new file mode 100644
>> index 000000000000..dcd92151b7d2
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashFvbDxe/FlashFvbDxe.c
>> @@ -0,0 +1,525 @@
>> +/** @file
>> +
>> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Library/DebugLib.h>
>> +#include <Library/FlashLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeLib.h>
>> +#include <Protocol/FirmwareVolumeBlock.h>
>> +
>> +//
>> +// These temporary buffers are used to calculate and convert linear virtual
>> +// to physical address
>> +//
>> +STATIC UINT64 mNvFlashBase;
>> +STATIC UINT32 mNvFlashSize;
>> +STATIC UINT32 mFlashBlockSize;
>> +STATIC UINT64 mNvStorageBase;
>> +STATIC UINT64 mNvStorageSize;
>> +
>> +/**
>> + Fixup internal data so that EFI can be call in virtual mode.
>> + Call the passed in Child Notify event and convert any pointers in
>> + lib to virtual mode.
>> +
>> + @param[in] Event The Event that is being processed
>> + @param[in] Context Event Context
>> +**/
>> +VOID
>> +EFIAPI
>> +FlashFvbAddressChangeEvent (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +{
>> + EfiConvertPointer (0x0, (VOID **)&mNvStorageBase);
>> +}
>> +
>> +/**
>> + The GetAttributes() function retrieves the attributes and
>> + current settings of the block.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Attributes Pointer to EFI_FVB_ATTRIBUTES_2 in which the
>> + attributes and current settings are
>> + returned. Type EFI_FVB_ATTRIBUTES_2 is defined
>> + in EFI_FIRMWARE_VOLUME_HEADER.
>> +
>> + @retval EFI_SUCCESS The firmware volume attributes were
>> + returned.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeGetAttributes (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + OUT EFI_FVB_ATTRIBUTES_2 *Attributes
>> + )
>> +{
>> + ASSERT (Attributes != NULL);
>> +
>> + *Attributes = EFI_FVB2_READ_ENABLED_CAP | // Reads may be enabled
>> + EFI_FVB2_READ_STATUS | // Reads are currently enabled
>> + EFI_FVB2_WRITE_STATUS | // Writes are currently enabled
>> + EFI_FVB2_WRITE_ENABLED_CAP | // Writes may be enabled
>> + EFI_FVB2_STICKY_WRITE | // A block erase is required to flip bits into EFI_FVB2_ERASE_POLARITY
>> + EFI_FVB2_MEMORY_MAPPED | // It is memory mapped
>> + EFI_FVB2_ALIGNMENT |
>> + EFI_FVB2_ERASE_POLARITY; // After erasure all bits take this value (i.e. '1')
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + The SetAttributes() function sets configurable firmware volume
>> + attributes and returns the new settings of the firmware volume.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Attributes On input, Attributes is a pointer to
>> + EFI_FVB_ATTRIBUTES_2 that contains the
>> + desired firmware volume settings. On
>> + successful return, it contains the new
>> + settings of the firmware volume. Type
>> + EFI_FVB_ATTRIBUTES_2 is defined in
>> + EFI_FIRMWARE_VOLUME_HEADER.
>> +
>> + @retval EFI_SUCCESS The firmware volume attributes were returned.
>> +
>> + @retval EFI_INVALID_PARAMETER The attributes requested are in
>> + conflict with the capabilities
>> + as declared in the firmware
>> + volume header.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeSetAttributes (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes
>> + )
>> +{
>> + return EFI_SUCCESS; // ignore for now
>> +}
>> +
>> +/**
>> + The GetPhysicalAddress() function retrieves the base address of
>> + a memory-mapped firmware volume. This function should be called
>> + only for memory-mapped firmware volumes.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Address Pointer to a caller-allocated
>> + EFI_PHYSICAL_ADDRESS that, on successful
>> + return from GetPhysicalAddress(), contains the
>> + base address of the firmware volume.
>> +
>> + @retval EFI_SUCCESS The firmware volume base address was returned.
>> +
>> + @retval EFI_UNSUPPORTED The firmware volume is not memory mapped.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeGetPhysicalAddress (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + OUT EFI_PHYSICAL_ADDRESS *Address
>> + )
>> +{
>> + ASSERT (Address != NULL);
>> +
>> + *Address = (EFI_PHYSICAL_ADDRESS)mNvStorageBase;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + The GetBlockSize() function retrieves the size of the requested
>> + block. It also returns the number of additional blocks with
>> + the identical size. The GetBlockSize() function is used to
>> + retrieve the block map (see EFI_FIRMWARE_VOLUME_HEADER).
>> +
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Lba Indicates the block for which to return the size.
>> +
>> + @param BlockSize Pointer to a caller-allocated UINTN in which
>> + the size of the block is returned.
>> +
>> + @param NumberOfBlocks Pointer to a caller-allocated UINTN in
>> + which the number of consecutive blocks,
>> + starting with Lba, is returned. All
>> + blocks in this range have a size of
>> + BlockSize.
>> +
>> +
>> + @retval EFI_SUCCESS The firmware volume base address was returned.
>> +
>> + @retval EFI_INVALID_PARAMETER The requested LBA is out of range.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeGetBlockSize (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + IN EFI_LBA Lba,
>> + OUT UINTN *BlockSize,
>> + OUT UINTN *NumberOfBlocks
>> + )
>> +{
>> + UINTN TotalNvStorageBlocks;
>> +
>> + ASSERT (BlockSize != NULL);
>> + ASSERT (NumberOfBlocks != NULL);
>> +
>> + TotalNvStorageBlocks = mNvStorageSize / mFlashBlockSize;
>> +
>> + if (TotalNvStorageBlocks <= (UINTN)Lba) {
>> + DEBUG ((DEBUG_ERROR, "The requested LBA is out of range\n"));
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + *NumberOfBlocks = TotalNvStorageBlocks - (UINTN)Lba;
>> + *BlockSize = mFlashBlockSize;
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Reads the specified number of bytes into a buffer from the specified block.
>> +
>> + The Read() function reads the requested number of bytes from the
>> + requested block and stores them in the provided buffer.
>> + Implementations should be mindful that the firmware volume
>> + might be in the ReadDisabled state. If it is in this state,
>> + the Read() function must return the status code
>> + EFI_ACCESS_DENIED without modifying the contents of the
>> + buffer. The Read() function must also prevent spanning block
>> + boundaries. If a read is requested that would span a block
>> + boundary, the read must read up to the boundary but not
>> + beyond. The output parameter NumBytes must be set to correctly
>> + indicate the number of bytes actually read. The caller must be
>> + aware that a read may be partially completed.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Lba The starting logical block index
>> + from which to read.
>> +
>> + @param Offset Offset into the block at which to begin reading.
>> +
>> + @param NumBytes Pointer to a UINTN. At entry, *NumBytes
>> + contains the total size of the buffer. At
>> + exit, *NumBytes contains the total number of
>> + bytes read.
>> +
>> + @param Buffer Pointer to a caller-allocated buffer that will
>> + be used to hold the data that is read.
>> +
>> + @retval EFI_SUCCESS The firmware volume was read successfully,
>> + and contents are in Buffer.
>> +
>> + @retval EFI_BAD_BUFFER_SIZE Read attempted across an LBA
>> + boundary. On output, NumBytes
>> + contains the total number of bytes
>> + returned in Buffer.
>> +
>> + @retval EFI_ACCESS_DENIED The firmware volume is in the
>> + ReadDisabled state.
>> +
>> + @retval EFI_DEVICE_ERROR The block device is not
>> + functioning correctly and could
>> + not be read.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeRead (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN OUT UINTN *NumBytes,
>> + IN OUT UINT8 *Buffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + ASSERT (NumBytes != NULL);
>> + ASSERT (Buffer != NULL);
>> +
>> + if (Offset + *NumBytes > mFlashBlockSize) {
>> + return EFI_BAD_BUFFER_SIZE;
>> + }
>> +
>> + Status = FlashReadCommand (
>> + (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
>> + Buffer,
>> + NumBytes
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Failed to do flash read\n"));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Writes the specified number of bytes from the input buffer to the block.
>> +
>> + The Write() function writes the specified number of bytes from
>> + the provided buffer to the specified block and offset. If the
>> + firmware volume is sticky write, the caller must ensure that
>> + all the bits of the specified range to write are in the
>> + EFI_FVB_ERASE_POLARITY state before calling the Write()
>> + function, or else the result will be unpredictable. This
>> + unpredictability arises because, for a sticky-write firmware
>> + volume, a write may negate a bit in the EFI_FVB_ERASE_POLARITY
>> + state but cannot flip it back again. Before calling the
>> + Write() function, it is recommended for the caller to first call
>> + the EraseBlocks() function to erase the specified block to
>> + write. A block erase cycle will transition bits from the
>> + (NOT)EFI_FVB_ERASE_POLARITY state back to the
>> + EFI_FVB_ERASE_POLARITY state. Implementations should be
>> + mindful that the firmware volume might be in the WriteDisabled
>> + state. If it is in this state, the Write() function must
>> + return the status code EFI_ACCESS_DENIED without modifying the
>> + contents of the firmware volume. The Write() function must
>> + also prevent spanning block boundaries. If a write is
>> + requested that spans a block boundary, the write must store up
>> + to the boundary but not beyond. The output parameter NumBytes
>> + must be set to correctly indicate the number of bytes actually
>> + written. The caller must be aware that a write may be
>> + partially completed. All writes, partial or otherwise, must be
>> + fully flushed to the hardware before the Write() service
>> + returns.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL instance.
>> +
>> + @param Lba The starting logical block index to write to.
>> +
>> + @param Offset Offset into the block at which to begin writing.
>> +
>> + @param NumBytes The pointer to a UINTN. At entry, *NumBytes
>> + contains the total size of the buffer. At
>> + exit, *NumBytes contains the total number of
>> + bytes actually written.
>> +
>> + @param Buffer The pointer to a caller-allocated buffer that
>> + contains the source for the write.
>> +
>> + @retval EFI_SUCCESS The firmware volume was written successfully.
>> +
>> + @retval EFI_BAD_BUFFER_SIZE The write was attempted across an
>> + LBA boundary. On output, NumBytes
>> + contains the total number of bytes
>> + actually written.
>> +
>> + @retval EFI_ACCESS_DENIED The firmware volume is in the
>> + WriteDisabled state.
>> +
>> + @retval EFI_DEVICE_ERROR The block device is malfunctioning
>> + and could not be written.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeWrite (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + IN EFI_LBA Lba,
>> + IN UINTN Offset,
>> + IN OUT UINTN *NumBytes,
>> + IN UINT8 *Buffer
>> + )
>> +{
>> + EFI_STATUS Status;
>> +
>> + ASSERT (NumBytes != NULL);
>> + ASSERT (Buffer != NULL);
>> +
>> + if (Offset + *NumBytes > mFlashBlockSize) {
>> + return EFI_BAD_BUFFER_SIZE;
>> + }
>> +
>> + Status = FlashProgramCommand (
>> + (UINT8 *)(mNvFlashBase + Lba * mFlashBlockSize + Offset),
>> + Buffer,
>> + NumBytes
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Failed to do flash program\n"));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return Status;
>> +}
>> +
>> +/**
>> + Erases and initializes a firmware volume block.
>> +
>> + The EraseBlocks() function erases one or more blocks as denoted
>> + by the variable argument list. The entire parameter list of
>> + blocks must be verified before erasing any blocks. If a block is
>> + requested that does not exist within the associated firmware
>> + volume (it has a larger index than the last block of the
>> + firmware volume), the EraseBlocks() function must return the
>> + status code EFI_INVALID_PARAMETER without modifying the contents
>> + of the firmware volume. Implementations should be mindful that
>> + the firmware volume might be in the WriteDisabled state. If it
>> + is in this state, the EraseBlocks() function must return the
>> + status code EFI_ACCESS_DENIED without modifying the contents of
>> + the firmware volume. All calls to EraseBlocks() must be fully
>> + flushed to the hardware before the EraseBlocks() service
>> + returns.
>> +
>> + @param This Indicates the EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL
>> + instance.
>> +
>> + @param ... The variable argument list is a list of tuples.
>> + Each tuple describes a range of LBAs to erase
>> + and consists of the following:
>> + - An EFI_LBA that indicates the starting LBA
>> + - A UINTN that indicates the number of blocks to
>> + erase.
>> +
>> + The list is terminated with an
>> + EFI_LBA_LIST_TERMINATOR. For example, the
>> + following indicates that two ranges of blocks
>> + (5-7 and 10-11) are to be erased: EraseBlocks
>> + (This, 5, 3, 10, 2, EFI_LBA_LIST_TERMINATOR);
>> +
>> + @retval EFI_SUCCESS The erase request successfully
>> + completed.
>> +
>> + @retval EFI_ACCESS_DENIED The firmware volume is in the
>> + WriteDisabled state.
>> + @retval EFI_DEVICE_ERROR The block device is not functioning
>> + correctly and could not be written.
>> + The firmware device may have been
>> + partially erased.
>> + @retval EFI_INVALID_PARAMETER One or more of the LBAs listed
>> + in the variable argument list do
>> + not exist in the firmware volume.
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeErase (
>> + IN CONST EFI_FIRMWARE_VOLUME_BLOCK2_PROTOCOL *This,
>> + ...
>> + )
>> +{
>> + VA_LIST Args;
>> + EFI_LBA Start;
>> + UINTN Length;
>> + EFI_STATUS Status;
>> +
>> + Status = EFI_SUCCESS;
>> +
>> + VA_START (Args, This);
>> +
>> + for (Start = VA_ARG (Args, EFI_LBA);
>> + Start != EFI_LBA_LIST_TERMINATOR;
>> + Start = VA_ARG (Args, EFI_LBA))
>> + {
>> + Length = VA_ARG (Args, UINTN);
>> + Status = FlashEraseCommand (
>> + (UINT8 *)(mNvFlashBase + Start * mFlashBlockSize),
>> + Length * mFlashBlockSize
>> + );
>> + }
>> +
>> + VA_END (Args);
>> +
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Failed to do flash erase\n"));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL mFlashFvbProtocol = {
>> + FlashFvbDxeGetAttributes,
>> + FlashFvbDxeSetAttributes,
>> + FlashFvbDxeGetPhysicalAddress,
>> + FlashFvbDxeGetBlockSize,
>> + FlashFvbDxeRead,
>> + FlashFvbDxeWrite,
>> + FlashFvbDxeErase
>> +};
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashFvbDxeInitialize (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + EFI_STATUS Status;
>> + EFI_HANDLE FvbHandle = NULL;
>> + EFI_EVENT VirtualAddressChangeEvent;
>> +
>> + // Get NV store FV info
>> + mFlashBlockSize = FixedPcdGet32 (PcdFvBlockSize);
>> + mNvStorageBase = PcdGet64 (PcdFlashNvStorageVariableBase64);
>> + mNvStorageSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
>> + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>> + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> + DEBUG ((
>> + DEBUG_INFO,
>> + "%a: Using NV store FV in-memory copy at 0x%lx with size 0x%x\n",
>> + __FUNCTION__,
>> + mNvStorageBase,
>> + mNvStorageSize
>> + ));
>> +
>> + // Get NV Flash information
>> + Status = FlashGetNvRamInfo ((UINT64 *)&mNvFlashBase, (UINT32 *)&mNvFlashSize);
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "%a: Failed to get Flash info\n", __FUNCTION__));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + if (mNvFlashSize >= (mNvStorageSize * 2)) {
>> + DEBUG ((DEBUG_INFO, "%a: NV store on Flash is valid\n", __FUNCTION__));
>> + } else {
>> + DEBUG ((DEBUG_ERROR, "%a: NV store on Flash is invalid\n", __FUNCTION__));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Status = gBS->CreateEventEx (
>> + EVT_NOTIFY_SIGNAL,
>> + TPL_NOTIFY,
>> + FlashFvbAddressChangeEvent,
>> + NULL,
>> + &gEfiEventVirtualAddressChangeGuid,
>> + &VirtualAddressChangeEvent
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->InstallMultipleProtocolInterfaces (
>> + &FvbHandle,
>> + &gEfiFirmwareVolumeBlockProtocolGuid,
>> + &mFlashFvbProtocol,
>> + NULL
>> + );
>> +
>> + if (EFI_ERROR (Status)) {
>> + DEBUG ((DEBUG_ERROR, "Failed to install Firmware Volume Block protocol\n"));
>> + return Status;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
>> new file mode 100644
>> index 000000000000..6bfbbbebaa85
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Drivers/FlashPei/FlashPei.c
>> @@ -0,0 +1,283 @@
>> +/** @file
>> +
>> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <PiPei.h>
>> +#include <Uefi.h>
>> +
>> +#include <Library/ArmSmcLib.h>
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/MmCommunicationLib.h>
>> +#include <Library/PcdLib.h>
>> +#include <Library/PeimEntryPoint.h>
>> +#include <MmLib.h>
>> +
>> +// Convert to string
>> +#define _STR(x) #x
>> +
>> +// Make sure the argument is expanded before converting to string
>> +#define STR(x) _STR(x)
>> +
>> +// Use dynamic UEFI_UUID of each build time
>> +#define UEFI_UUID_BUILD STR(UEFI_UUID)
>> +
>> +EFI_MM_COMM_REQUEST mEfiMmSpiNorReq;
>> +
>> +STATIC CHAR8 mBuildUuid[sizeof (UEFI_UUID_BUILD)];
>> +STATIC CHAR8 mStoredUuid[sizeof (UEFI_UUID_BUILD)];
>> +
>> +STATIC
>> +EFI_STATUS
>> +UefiMmCreateSpiNorReq (
>> + VOID *Data,
>> + UINT64 Size
>> + )
>> +{
>> + CopyGuid (&mEfiMmSpiNorReq.EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
>> + mEfiMmSpiNorReq.EfiMmHdr.MsgLength = Size;
>> +
>> + if (Size != 0) {
>> + ASSERT (Data);
>> + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
>> +
>> + CopyMem (mEfiMmSpiNorReq.PayLoad.Data, Data, Size);
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Entry point function for the PEIM
>> +
>> + @param FileHandle Handle of the file being invoked.
>> + @param PeiServices Describes the list of possible PEI Services.
>> +
>> + @return EFI_SUCCESS If we installed our PPI
>> +
>> +**/
>> +EFI_STATUS
>> +EFIAPI
>> +FlashPeiEntryPoint (
>> + IN EFI_PEI_FILE_HANDLE FileHandle,
>> + IN CONST EFI_PEI_SERVICES **PeiServices
>> + )
>> +{
>> + UINT64 FWNvRamStartOffset;
>> + EFI_STATUS Status;
>> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
>> + UINT64 MmData[5];
>> + UINTN Size;
>> + VOID *NvRamAddress;
>> + UINTN NvRamSize;
>> +
>> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
>> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNV2InfoRes;
>> + UINT64 NV2Base, NV2Size;
>> +#endif
>> +
>> + NvRamAddress = (VOID *)PcdGet64 (PcdFlashNvStorageVariableBase64);
>> + NvRamSize = FixedPcdGet32 (PcdFlashNvStorageVariableSize) +
>> + FixedPcdGet32 (PcdFlashNvStorageFtwWorkingSize) +
>> + FixedPcdGet32 (PcdFlashNvStorageFtwSpareSize);
>> +
>> + /* Find out about the start offset of NVRAM to be passed to SMC */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorNVInfoRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + /* Old FW so just exit */
>> + return EFI_SUCCESS;
>> + }
>> + FWNvRamStartOffset = MmSpiNorNVInfoRes->NVBase;
>> +
>> + CopyMem ((VOID *)mBuildUuid, (VOID *)UEFI_UUID_BUILD, sizeof (UEFI_UUID_BUILD));
>> + if (MmSpiNorNVInfoRes->NVSize < (NvRamSize * 2 + sizeof (mBuildUuid))) {
>> + /* NVRAM size provided by FW is not enough */
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + /* We stored BIOS UUID build at the offset NVRAM_SIZE * 2 */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_READ;
>> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> + MmData[2] = (UINT64)sizeof (mStoredUuid);
>> + MmData[3] = (UINT64)mStoredUuid;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> +
>> + if (CompareMem ((VOID *)mStoredUuid, (VOID *)mBuildUuid, sizeof (mBuildUuid))) {
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_ERASE;
>> + MmData[1] = (UINT64)FWNvRamStartOffset;
>> + MmData[2] = (UINT64)(NvRamSize * 2);
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> +
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_WRITE;
>> + MmData[1] = (UINT64)FWNvRamStartOffset;
>> + MmData[2] = (UINT64)(NvRamSize * 2);
>> + MmData[3] = (UINT64)NvRamAddress;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> +
>> + /* Update UUID */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_ERASE;
>> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> + MmData[2] = (UINT64)sizeof (mBuildUuid);
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> +
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_WRITE;
>> + MmData[1] = (UINT64)(FWNvRamStartOffset + NvRamSize * 2);
>> + MmData[2] = (UINT64)sizeof (mBuildUuid);
>> + MmData[3] = (UINT64)mBuildUuid;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> + DEBUG ((DEBUG_INFO, "UUID Changed, Update Storage with FV NVRAM\n"));
>> +
>> + /* Indicate that NVRAM was cleared */
>> + PcdSetBoolS (PcdNvramErased, TRUE);
>> + } else {
>> + /* Copy the stored NVRAM to RAM */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_READ;
>> + MmData[1] = (UINT64)FWNvRamStartOffset;
>> + MmData[2] = (UINT64)(NvRamSize * 2);
>> + MmData[3] = (UINT64)NvRamAddress;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + return Status;
>> + }
>> + DEBUG ((DEBUG_INFO, "Identical UUID, copy stored NVRAM to RAM\n"));
>> + }
>> +
>> +#if defined(RAM_BLOCKIO_START_ADDRESS) && defined(RAM_BLOCKIO_SIZE)
>> + /* Find out about the start offset of NVRAM2 to be passed to SMC */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM2_INFO;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorNV2InfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + if (MmSpiNorNV2InfoRes->Status == MM_SPINOR_RES_SUCCESS) {
>> + NV2Base = MmSpiNorNV2InfoRes->NVBase;
>> + NV2Size = MmSpiNorNV2InfoRes->NVSize;
>> + /* Make sure the requested size is smaller than allocated */
>> + if (RAM_BLOCKIO_SIZE <= NV2Size) {
>> + /* Copy the ramdisk image to RAM */
>> + ZeroMem ((VOID *)MmData, sizeof (MmData));
>> + MmData[0] = MM_SPINOR_FUNC_READ;
>> + MmData[1] = (UINT64)NV2Base; /* Start virtual address */
>> + MmData[2] = (UINT64)RAM_BLOCKIO_SIZE;
>> + MmData[3] = (UINT64)RAM_BLOCKIO_START_ADDRESS;
>> + UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = MmCommunicationCommunicate (
>> + (VOID *)&mEfiMmSpiNorReq,
>> + &Size
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mEfiMmSpiNorReq.PayLoad;
>> + ASSERT (MmSpiNorRes->Status == MM_SPINOR_RES_SUCCESS);
>> + }
>> +
>> + BuildMemoryAllocationHob (
>> + (EFI_PHYSICAL_ADDRESS)RAM_BLOCKIO_START_ADDRESS,
>> + EFI_SIZE_TO_PAGES (RAM_BLOCKIO_SIZE) * EFI_PAGE_SIZE,
>> + EfiLoaderData
>> + );
>> + }
>> +#endif
>> +
>> + return EFI_SUCCESS;
>> +}
>> diff --git a/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
>> new file mode 100644
>> index 000000000000..cd77aed3cfe1
>> --- /dev/null
>> +++ b/Silicon/Ampere/AmpereAltraPkg/Library/FlashLib/FlashLib.c
>> @@ -0,0 +1,358 @@
>> +/** @file
>> +
>> + Copyright (c) 2020 - 2021, Ampere Computing LLC. All rights reserved.<BR>
>> +
>> + SPDX-License-Identifier: BSD-2-Clause-Patent
>> +
>> +**/
>> +
>> +#include <Uefi.h>
>> +
>> +#include <Library/BaseMemoryLib.h>
>> +#include <Library/DebugLib.h>
>> +#include <Library/FlashLib.h>
>> +#include <Library/MemoryAllocationLib.h>
>> +#include <Library/UefiBootServicesTableLib.h>
>> +#include <Library/UefiRuntimeServicesTableLib.h>
>> +#include <MmLib.h>
>> +#include <Protocol/MmCommunication.h>
>> +
>> +STATIC EFI_MM_COMMUNICATION_PROTOCOL *mMmCommunicationProtocol = NULL;
>> +STATIC EFI_MM_COMM_REQUEST *mCommBuffer = NULL;
>> +
>> +BOOLEAN mIsEfiRuntime;
>> +UINT8 *mTmpBufVirt;
>> +UINT8 *mTmpBufPhy;
>> +
>> +/**
>> + This is a notification function registered on EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
>> + event. It converts a pointer to a new virtual address.
>> +
>> + @param Event Event whose notification function is being invoked.
>> + @param Context Pointer to the notification function's context
>> +
>> +**/
>> +VOID
>> +EFIAPI
>> +FlashLibAddressChangeEvent (
>> + IN EFI_EVENT Event,
>> + IN VOID *Context
>> + )
>> +{
>> + gRT->ConvertPointer (0x0, (VOID **)&mTmpBufVirt);
>> + gRT->ConvertPointer (0x0, (VOID **)&mCommBuffer);
>> + gRT->ConvertPointer (0x0, (VOID **)&mMmCommunicationProtocol);
>> +
>> + mIsEfiRuntime = TRUE;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashLibConstructor (
>> + IN EFI_HANDLE ImageHandle,
>> + IN EFI_SYSTEM_TABLE *SystemTable
>> + )
>> +{
>> + EFI_EVENT VirtualAddressChangeEvent = NULL;
>> + EFI_STATUS Status = EFI_SUCCESS;
>> +
>> + mCommBuffer = AllocateRuntimeZeroPool (sizeof (EFI_MM_COMM_REQUEST));
>> + ASSERT (mCommBuffer != NULL);
>> +
>> + mTmpBufPhy = AllocateRuntimeZeroPool (EFI_MM_MAX_TMP_BUF_SIZE);
>> + mTmpBufVirt = mTmpBufPhy;
>> + ASSERT (mTmpBufPhy != NULL);
>> +
>> + Status = gBS->LocateProtocol (
>> + &gEfiMmCommunicationProtocolGuid,
>> + NULL,
>> + (VOID **)&mMmCommunicationProtocol
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + Status = gBS->CreateEvent (
>> + EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE,
>> + TPL_CALLBACK,
>> + FlashLibAddressChangeEvent,
>> + NULL,
>> + &VirtualAddressChangeEvent
>> + );
>> + ASSERT_EFI_ERROR (Status);
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +FlashMmCommunicate (
>> + IN OUT VOID *CommBuffer,
>> + IN OUT UINTN *CommSize
>> + )
>> +{
>> + if (mMmCommunicationProtocol == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + return mMmCommunicationProtocol->Communicate (
>> + mMmCommunicationProtocol,
>> + CommBuffer,
>> + CommSize
>> + );
>> +}
>> +
>> +STATIC
>> +EFI_STATUS
>> +UefiMmCreateSpiNorReq (
>> + IN VOID *Data,
>> + IN UINT64 Size
>> + )
>> +{
>> + if (mCommBuffer == NULL) {
>> + return EFI_INVALID_PARAMETER;
>> + }
>> +
>> + CopyGuid (&mCommBuffer->EfiMmHdr.HeaderGuid, &gSpiNorMmGuid);
>> + mCommBuffer->EfiMmHdr.MsgLength = Size;
>> +
>> + if (Size != 0) {
>> + ASSERT (Data);
>> + ASSERT (Size <= EFI_MM_MAX_PAYLOAD_SIZE);
>> +
>> + CopyMem (mCommBuffer->PayLoad.Data, Data, Size);
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +/**
>> + Convert Virtual Address to Physical Address at Runtime Services
>> +
>> + @param VirtualPtr Virtual Address Pointer
>> + @param Size Total bytes of the buffer
>> +
>> + @retval Ptr Return the pointer of the converted address
>> +
>> +**/
>> +STATIC
>> +UINT8 *
>> +ConvertVirtualToPhysical (
>> + IN UINT8 *VirtualPtr,
>> + IN UINTN Size
>> + )
>> +{
>> + if (mIsEfiRuntime) {
>> + ASSERT (VirtualPtr != NULL);
>> + CopyMem ((VOID *)mTmpBufVirt, (VOID *)VirtualPtr, Size);
>> + return (UINT8 *)mTmpBufPhy;
>> + }
>> +
>> + return (UINT8 *)VirtualPtr;
>> +}
>> +
>> +/**
>> + Convert Physical Address to Virtual Address at Runtime Services
>> +
>> + @param VirtualPtr Physical Address Pointer
>> + @param Size Total bytes of the buffer
>> +
>> +**/
>> +STATIC
>> +VOID
>> +ConvertPhysicaltoVirtual (
>> + IN UINT8 *PhysicalPtr,
>> + IN UINTN Size
>> + )
>> +{
>> + if (mIsEfiRuntime) {
>> + ASSERT (PhysicalPtr != NULL);
>> + CopyMem ((VOID *)PhysicalPtr, (VOID *)mTmpBufVirt, Size);
>> + }
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashGetNvRamInfo (
>> + OUT UINT64 *NvRamBase,
>> + OUT UINT32 *NvRamSize
>> + )
>> +{
>> + EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *MmSpiNorNVInfoRes;
>> + EFI_STATUS Status;
>> + UINT64 MmData[5];
>> + UINTN Size;
>> +
>> + MmData[0] = MM_SPINOR_FUNC_GET_NVRAM_INFO;
>> +
>> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = FlashMmCommunicate (
>> + mCommBuffer,
>> + &Size
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + MmSpiNorNVInfoRes = (EFI_MM_COMMUNICATE_SPINOR_NVINFO_RES *)&mCommBuffer->PayLoad;
>> + if (MmSpiNorNVInfoRes->Status == MM_SPINOR_RES_SUCCESS) {
>> + *NvRamBase = MmSpiNorNVInfoRes->NVBase;
>> + *NvRamSize = MmSpiNorNVInfoRes->NVSize;
>> + DEBUG ((DEBUG_INFO, "NVInfo Base 0x%llx, Size 0x%lx\n", *NvRamBase, *NvRamSize));
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashEraseCommand (
>> + IN UINT8 *pBlockAddress,
>> + IN UINT32 Length
>> + )
>> +{
>> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> + EFI_STATUS Status;
>> + UINT64 MmData[5];
>> + UINTN Size;
>> +
>> + ASSERT (pBlockAddress != NULL);
>> +
>> + MmData[0] = MM_SPINOR_FUNC_ERASE;
>> + MmData[1] = (UINT64)pBlockAddress;
>> + MmData[2] = Length;
>> +
>> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = FlashMmCommunicate (
>> + mCommBuffer,
>> + &Size
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + DEBUG ((DEBUG_ERROR, "Flash Erase: Device error %llx\n", MmSpiNorRes->Status));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashProgramCommand (
>> + IN UINT8 *pByteAddress,
>> + IN UINT8 *Byte,
>> + IN OUT UINTN *Length
>> + )
>> +{
>> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> + EFI_STATUS Status;
>> + UINT64 MmData[5];
>> + UINTN Remain, Size, NumWrite;
>> + UINTN Count = 0;
>> +
>> + ASSERT (pByteAddress != NULL);
>> + ASSERT (Byte != NULL);
>> + ASSERT (Length != NULL);
>> +
>> + Remain = *Length;
>> + while (Remain > 0) {
>> + NumWrite = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
>> +
>> + MmData[0] = MM_SPINOR_FUNC_WRITE;
>> + MmData[1] = (UINT64)pByteAddress;
>> + MmData[2] = NumWrite;
>> + MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumWrite);
>> +
>> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = FlashMmCommunicate (
>> + mCommBuffer,
>> + &Size
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + DEBUG ((DEBUG_ERROR, "Flash program: Device error 0x%llx\n", MmSpiNorRes->Status));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + Remain -= NumWrite;
>> + Count += NumWrite;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> +
>> +EFI_STATUS
>> +EFIAPI
>> +FlashReadCommand (
>> + IN UINT8 *pByteAddress,
>> + OUT UINT8 *Byte,
>> + IN OUT UINTN *Length
>> + )
>> +{
>> + EFI_MM_COMMUNICATE_SPINOR_RES *MmSpiNorRes;
>> + EFI_STATUS Status;
>> + UINT64 MmData[5];
>> + UINTN Remain, Size, NumRead;
>> + UINTN Count = 0;
>> +
>> + ASSERT (pByteAddress != NULL);
>> + ASSERT (Byte != NULL);
>> + ASSERT (Length != NULL);
>> +
>> + Remain = *Length;
>> + while (Remain > 0) {
>> + NumRead = (Remain > EFI_MM_MAX_TMP_BUF_SIZE) ? EFI_MM_MAX_TMP_BUF_SIZE : Remain;
>> +
>> + MmData[0] = MM_SPINOR_FUNC_READ;
>> + MmData[1] = (UINT64)pByteAddress;
>> + MmData[2] = NumRead;
>> + MmData[3] = (UINT64)ConvertVirtualToPhysical (Byte + Count, NumRead);
>> +
>> + Status = UefiMmCreateSpiNorReq ((VOID *)&MmData, sizeof (MmData));
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + Size = sizeof (EFI_MM_COMM_HEADER_NOPAYLOAD) + sizeof (MmData);
>> + Status = FlashMmCommunicate (
>> + mCommBuffer,
>> + &Size
>> + );
>> + if (EFI_ERROR (Status)) {
>> + return Status;
>> + }
>> +
>> + MmSpiNorRes = (EFI_MM_COMMUNICATE_SPINOR_RES *)&mCommBuffer->PayLoad;
>> + if (MmSpiNorRes->Status != MM_SPINOR_RES_SUCCESS) {
>> + DEBUG ((DEBUG_ERROR, "Flash Read: Device error %llx\n", MmSpiNorRes->Status));
>> + return EFI_DEVICE_ERROR;
>> + }
>> +
>> + ConvertPhysicaltoVirtual (Byte + Count, NumRead);
>> + Remain -= NumRead;
>> + Count += NumRead;
>> + }
>> +
>> + return EFI_SUCCESS;
>> +}
>> --
>> 2.17.1
>>
-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#76546): https://edk2.groups.io/g/devel/message/76546
Mute This Topic: https://groups.io/mt/83097104/1787277
Group Owner: devel+owner@edk2.groups.io
Unsubscribe: https://edk2.groups.io/g/devel/unsub [importer@patchew.org]
-=-=-=-=-=-=-=-=-=-=-=-
© 2016 - 2026 Red Hat, Inc.