Date   

[`edk2-devel][PATCH 8/8] UefiPayloadPkg: Add SMM support and SMM variable support

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

Add SMM variable support for universal UEFI payload.
By default they are disabled.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/UefiPayloadPkg.dsc | 101 +++++++++++++++++++++++++++---
UefiPayloadPkg/UefiPayloadPkg.fdf | 38 ++++++++++-
2 files changed, 128 insertions(+), 11 deletions(-)

diff --git a/UefiPayloadPkg/UefiPayloadPkg.dsc b/UefiPayloadPkg/UefiPayload=
Pkg.dsc
index fb805dc772..9dd17136b9 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dsc
+++ b/UefiPayloadPkg/UefiPayloadPkg.dsc
@@ -31,12 +31,13 @@
DEFINE RAM_DISK_ENABLE =3D FALSE=0D
DEFINE SIO_BUS_ENABLE =3D FALSE=0D
DEFINE UNIVERSAL_PAYLOAD =3D FALSE=0D
+ DEFINE SMM_SUPPORT =3D FALSE=0D
=0D
#=0D
# SBL: UEFI payload for Slim Bootloader=0D
# COREBOOT: UEFI payload for coreboot=0D
#=0D
- DEFINE BOOTLOADER =3D SBL=0D
+ DEFINE BOOTLOADER =3D SBL=0D
=0D
#=0D
# CPU options=0D
@@ -90,7 +91,13 @@
#=0D
DEFINE SHELL_TYPE =3D BUILD_SHELL=0D
=0D
- DEFINE EMU_VARIABLE_ENABLE =3D TRUE=0D
+ #=0D
+ # EMU: UEFI payload with EMU variable=0D
+ # SPI: UEFI payload with SPI NV variable support=0D
+ # NONE: UEFI payload with no variable modules=0D
+ #=0D
+ DEFINE VARIABLE_SUPPORT =3D EMU=0D
+=0D
DEFINE DISABLE_RESET_SYSTEM =3D FALSE=0D
DEFINE NETWORK_DRIVER_ENABLE =3D FALSE=0D
=0D
@@ -250,10 +257,18 @@
LockBoxLib|MdeModulePkg/Library/LockBoxNullLib/LockBoxNullLib.inf=0D
FileExplorerLib|MdeModulePkg/Library/FileExplorerLib/FileExplorerLib.inf=
=0D
AuthVariableLib|MdeModulePkg/Library/AuthVariableLibNull/AuthVariableLib=
Null.inf=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "EMU"=0D
TpmMeasurementLib|MdeModulePkg/Library/TpmMeasurementLibNull/TpmMeasurem=
entLibNull.inf=0D
+!elseif $(VARIABLE_SUPPORT) =3D=3D "SPI"=0D
+ PlatformSecureLib|SecurityPkg/Library/PlatformSecureLibNull/PlatformSecu=
reLibNull.inf=0D
+ TpmMeasurementLib|SecurityPkg/Library/DxeTpmMeasurementLib/DxeTpmMeasure=
mentLib.inf=0D
+ S3BootScriptLib|MdePkg/Library/BaseS3BootScriptLibNull/BaseS3BootScriptL=
ibNull.inf=0D
+ MmUnblockMemoryLib|MdePkg/Library/MmUnblockMemoryLib/MmUnblockMemoryLibN=
ull.inf=0D
+!endif=0D
VarCheckLib|MdeModulePkg/Library/VarCheckLib/VarCheckLib.inf=0D
VariablePolicyLib|MdeModulePkg/Library/VariablePolicyLib/VariablePolicyL=
ib.inf=0D
VariablePolicyHelperLib|MdeModulePkg/Library/VariablePolicyHelperLib/Var=
iablePolicyHelperLib.inf=0D
+ VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf=0D
=0D
[LibraryClasses.common.SEC]=0D
HobLib|UefiPayloadPkg/Library/PayloadEntryHobLib/HobLib.inf=0D
@@ -271,7 +286,6 @@
DebugAgentLib|SourceLevelDebugPkg/Library/DebugAgent/DxeDebugAgentLib.in=
f=0D
!endif=0D
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuE=
xceptionHandlerLib.inf=0D
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf=0D
=0D
[LibraryClasses.common.DXE_DRIVER]=0D
PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf=0D
@@ -283,7 +297,6 @@
!endif=0D
CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuE=
xceptionHandlerLib.inf=0D
MpInitLib|UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf=0D
- VmgExitLib|UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf=0D
=0D
[LibraryClasses.common.DXE_RUNTIME_DRIVER]=0D
PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf=0D
@@ -296,6 +309,37 @@
MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAll=
ocationLib.inf=0D
ReportStatusCodeLib|MdeModulePkg/Library/DxeReportStatusCodeLib/DxeRepor=
tStatusCodeLib.inf=0D
=0D
+[LibraryClasses.common.SMM_CORE]=0D
+!if $(SMM_SUPPORT) =3D=3D TRUE=0D
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf=0D
+ SmmServicesTableLib|MdeModulePkg/Library/PiSmmCoreSmmServicesTableLib/Pi=
SmmCoreSmmServicesTableLib.inf=0D
+=0D
+ MemoryAllocationLib|MdeModulePkg/Library/PiSmmCoreMemoryAllocationLib/Pi=
SmmCoreMemoryAllocationLib.inf=0D
+ SmmCorePlatformHookLib|MdeModulePkg/Library/SmmCorePlatformHookLibNull/S=
mmCorePlatformHookLibNull.inf=0D
+ SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf=0D
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseRepor=
tStatusCodeLibNull.inf=0D
+!endif=0D
+=0D
+[LibraryClasses.common.DXE_SMM_DRIVER]=0D
+!if $(SMM_SUPPORT) =3D=3D TRUE=0D
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf=0D
+=0D
+ MemoryAllocationLib|MdePkg/Library/SmmMemoryAllocationLib/SmmMemoryAlloc=
ationLib.inf=0D
+ SmmServicesTableLib|MdePkg/Library/SmmServicesTableLib/SmmServicesTableL=
ib.inf=0D
+ SmmMemLib|MdePkg/Library/SmmMemLib/SmmMemLib.inf=0D
+ MmServicesTableLib|MdePkg/Library/MmServicesTableLib/MmServicesTableLib.=
inf=0D
+ DebugLib|MdePkg/Library/BaseDebugLibSerialPort/BaseDebugLibSerialPort.in=
f=0D
+ SmmCpuPlatformHookLib|UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCp=
uPlatformHookLibNull.inf=0D
+ SmmCpuFeaturesLib|UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib=
.inf=0D
+ CpuExceptionHandlerLib|UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuE=
xceptionHandlerLib.inf=0D
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseRepor=
tStatusCodeLibNull.inf=0D
+!endif=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "SPI"=0D
+ SpiFlashLib|UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf=0D
+ FlashDeviceLib|UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf=
=0D
+ BaseCryptLib|CryptoPkg/Library/BaseCryptLib/SmmCryptLib.inf=0D
+!endif=0D
+=0D
##########################################################################=
######=0D
#=0D
# Pcd Section - list of all EDK II PCD Entries defined by this Platform.=0D
@@ -309,15 +353,17 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdInstallAcpiSdtProtocol|TRUE=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdHiiOsRuntimeSupport|FALSE=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdPciDegradeResourceForOptionRom|FALSE=0D
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmEnableBspElection|FALSE=0D
=0D
[PcdsFixedAtBuild]=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxVariableSize|0x10000=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdMaxHardwareErrorVariableSize|0x8000=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdVariableStoreSize|0x10000=0D
- #=0D
- # Make VariableRuntimeDxe work at emulated non-volatile variable mode.=0D
- #=0D
- gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable|TRUE=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "EMU"=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable |TRUE=0D
+!else=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdEmuVariableNvModeEnable |FALSE=
=0D
+!endif=0D
=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdVpdBaseAddress|0x0=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory|FALSE=0D
@@ -328,6 +374,7 @@
!if $(SOURCE_DEBUG_ENABLE)=0D
gEfiSourceLevelDebugPkgTokenSpaceGuid.PcdDebugLoadImageMethod|0x2=0D
!endif=0D
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackSize|0x4000=0D
=0D
[PcdsPatchableInModule.X64]=0D
gPcAtChipsetPkgTokenSpaceGuid.PcdRtcIndexRegister|$(RTC_INDEX_REGISTER)=
=0D
@@ -398,6 +445,14 @@
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase|0=0D
gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase|0=0D
gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut|3=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "SPI"=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize |0=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize|0=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize |0=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase |0=0D
+!endif=0D
+ # Disable SMM S3 script=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiS3Enable|FALSE=0D
=0D
## This PCD defines the video horizontal resolution.=0D
# This PCD could be set to 0 then video resolution could be at highest =
resolution.=0D
@@ -585,6 +640,36 @@
!endif=0D
UefiPayloadPkg/GraphicsOutputDxe/GraphicsOutputDxe.inf=0D
=0D
+ #=0D
+ # SMM Support=0D
+ #=0D
+!if $(SMM_SUPPORT) =3D=3D TRUE=0D
+ UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf=0D
+ UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf=0D
+ UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf=0D
+ MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf=0D
+ MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf=0D
+ UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf=0D
+ UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf=0D
+ UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf=0D
+!endif=0D
+=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "EMU"=0D
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf=0D
+!elseif $(VARIABLE_SUPPORT) =3D=3D "SPI"=0D
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf {=0D
+ <LibraryClasses>=0D
+ NULL|MdeModulePkg/Library/VarCheckUefiLib/VarCheckUefiLib.inf=0D
+ NULL|MdeModulePkg/Library/VarCheckHiiLib/VarCheckHiiLib.inf=0D
+ NULL|MdeModulePkg/Library/VarCheckPcdLib/VarCheckPcdLib.inf=0D
+ NULL|MdeModulePkg/Library/VarCheckPolicyLib/VarCheckPolicyLib.inf=0D
+ }=0D
+=0D
+ UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf=0D
+ MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.inf=0D
+ MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf=0D
+!endif=0D
+=0D
#------------------------------=0D
# Build the shell=0D
#------------------------------=0D
diff --git a/UefiPayloadPkg/UefiPayloadPkg.fdf b/UefiPayloadPkg/UefiPayload=
Pkg.fdf
index 6b48bfc869..79ce12ee2c 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.fdf
+++ b/UefiPayloadPkg/UefiPayloadPkg.fdf
@@ -112,11 +112,29 @@ INF MdeModulePkg/Universal/MonotonicCounterRuntimeDxe=
/MonotonicCounterRuntimeDxe
!if $(DISABLE_RESET_SYSTEM) =3D=3D FALSE=0D
INF MdeModulePkg/Universal/ResetSystemRuntimeDxe/ResetSystemRuntimeDxe.inf=
=0D
!endif=0D
-=0D
INF PcAtChipsetPkg/PcatRealTimeClockRuntimeDxe/PcatRealTimeClockRuntimeDxe=
.inf=0D
=0D
-!if $(EMU_VARIABLE_ENABLE) =3D=3D TRUE=0D
-INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf=0D
+#=0D
+# SMM Support=0D
+#=0D
+!if $(SMM_SUPPORT) =3D=3D TRUE=0D
+ INF UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf=0D
+ INF UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf=0D
+ INF UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf=0D
+ INF MdeModulePkg/Core/PiSmmCore/PiSmmIpl.inf=0D
+ INF MdeModulePkg/Core/PiSmmCore/PiSmmCore.inf=0D
+ INF UefiCpuPkg/CpuIo2Smm/CpuIo2Smm.inf=0D
+ INF UefiCpuPkg/PiSmmCpuDxeSmm/PiSmmCpuDxeSmm.inf=0D
+ INF UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf=0D
+!endif=0D
+=0D
+!if $(VARIABLE_SUPPORT) =3D=3D "EMU"=0D
+ INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableRuntimeDxe.inf=0D
+!elseif $(VARIABLE_SUPPORT) =3D=3D "SPI"=0D
+ INF UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf=0D
+ INF MdeModulePkg/Universal/FaultTolerantWriteDxe/FaultTolerantWriteSmm.i=
nf=0D
+ INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmm.inf=0D
+ INF MdeModulePkg/Universal/Variable/RuntimeDxe/VariableSmmRuntimeDxe.inf=
=0D
!endif=0D
=0D
INF UefiCpuPkg/CpuIo2Dxe/CpuIo2Dxe.inf=0D
@@ -269,6 +287,20 @@ INF ShellPkg/Application/Shell/Shell.inf
UI STRING=3D"$(MODULE_NAME)" Optional=0D
VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBER=
)=0D
}=0D
+[Rule.Common.DXE_SMM_DRIVER]=0D
+ FILE SMM =3D $(NAMED_GUID) {=0D
+ SMM_DEPEX SMM_DEPEX Optional $(INF_OUTPUT)/$(MODULE_NAME).depex=
=0D
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi=0D
+ UI STRING=3D"$(MODULE_NAME)" Optional=0D
+ VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBE=
R)=0D
+ }=0D
+=0D
+[Rule.Common.SMM_CORE]=0D
+ FILE SMM_CORE =3D $(NAMED_GUID) {=0D
+ PE32 PE32 $(INF_OUTPUT)/$(MODULE_NAME).efi=0D
+ UI STRING=3D"$(MODULE_NAME)" Optional=0D
+ VERSION STRING=3D"$(INF_VERSION)" Optional BUILD_NUM=3D$(BUILD_NUMBER=
)=0D
+ }=0D
=0D
[Rule.Common.UEFI_DRIVER]=0D
FILE DRIVER =3D $(NAMED_GUID) {=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 6/8] UefiPayloadPkg: Add a common FVB SMM module

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

This FVB module is used to initialize NV variable region
and provide SMM FVB protocol to read/write SPI variable region.

This module consume HOB gNvVariableInfoGuid and depends on
FlashDeviceLib for the actual SPI device operate.

During FVB initialization, it will initialize the variable region
if the variable region is not valid. And it support to write initial
variable data from FFS file if it is found.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c | 143 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbService.c | 1085 +++++++++++++++++
UefiPayloadPkg/FvbRuntimeDxe/FvbService.h | 187 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c | 139 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf | 71 ++
UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h | 69 ++
.../Include/Guid/NvVariableInfoGuid.h | 30 +
UefiPayloadPkg/UefiPayloadPkg.dec | 6 +
8 files changed, 1730 insertions(+)
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbService.h
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h
create mode 100644 UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h

diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c b/UefiPayloadPkg/FvbRun=
timeDxe/FvbInfo.c
new file mode 100644
index 0000000000..e4ce27b5b3
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c
@@ -0,0 +1,143 @@
+/** @file=0D
+=0D
+ Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include <PiDxe.h>=0D
+#include <Protocol/FirmwareVolumeBlock.h>=0D
+#include <Library/PcdLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Guid/FirmwareFileSystem2.h>=0D
+#include <Guid/SystemNvDataGuid.h>=0D
+#include <Guid/NvVariableInfoGuid.h>=0D
+#include <Library/HobLib.h>=0D
+=0D
+#define FVB_MEDIA_BLOCK_SIZE 0x1000=0D
+=0D
+typedef struct {=0D
+ EFI_FIRMWARE_VOLUME_HEADER FvInfo;=0D
+ EFI_FV_BLOCK_MAP_ENTRY End[1];=0D
+} EFI_FVB2_MEDIA_INFO;=0D
+=0D
+//=0D
+// This data structure contains a template of FV header which is used to r=
estore=0D
+// Fv header if it's corrupted.=0D
+//=0D
+EFI_FVB2_MEDIA_INFO mFvbMediaInfo =3D {=0D
+ {=0D
+ {0,}, // ZeroVector[16]=0D
+ EFI_SYSTEM_NV_DATA_FV_GUID,=0D
+ 0,=0D
+ EFI_FVH_SIGNATURE,=0D
+ 0x0004feff, // check PiFirmwareVolume.h for details on EFI_FVB_ATT=
RIBUTES_2=0D
+ sizeof (EFI_FIRMWARE_VOLUME_HEADER) + sizeof (EFI_FV_BLOCK_MAP_ENTRY),=
=0D
+ 0, // CheckSum which will be calucated dynamically.=0D
+ 0, // ExtHeaderOffset=0D
+ {0,},=0D
+ EFI_FVH_REVISION,=0D
+ {=0D
+ {=0D
+ 0,=0D
+ FVB_MEDIA_BLOCK_SIZE,=0D
+ }=0D
+ }=0D
+ },=0D
+ {=0D
+ {=0D
+ 0,=0D
+ 0=0D
+ }=0D
+ }=0D
+};=0D
+=0D
+=0D
+EFI_STATUS=0D
+InitVariableStore (=0D
+ VOID=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 NvStorageBase;=0D
+ UINT32 NvStorageSize;=0D
+ UINT32 NvVariableSize;=0D
+ UINT32 FtwWorkingSize;=0D
+ UINT32 FtwSpareSize;=0D
+ EFI_HOB_GUID_TYPE *GuidHob;=0D
+ NV_VARIABLE_INFO *NvVariableInfo;=0D
+=0D
+ //=0D
+ // Find SPI flash variable hob=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gNvVariableInfoGuid);=0D
+ if (GuidHob =3D=3D NULL) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+ NvVariableInfo =3D (NV_VARIABLE_INFO *) GET_GUID_HOB_DATA (GuidHob);=0D
+=0D
+ //=0D
+ // Get variable region base and size.=0D
+ //=0D
+ NvStorageSize =3D NvVariableInfo->VariableStoreSize;=0D
+ NvStorageBase =3D NvVariableInfo->VariableStoreBase;=0D
+=0D
+ //=0D
+ // NvStorageBase needs to be 4KB aligned, NvStorageSize needs to be 8KB =
* n=0D
+ //=0D
+ if (((NvStorageBase & (SIZE_4KB - 1)) !=3D 0) || ((NvStorageSize & (SIZE=
_8KB - 1)) !=3D 0)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ FtwSpareSize =3D NvStorageSize / 2;=0D
+ FtwWorkingSize =3D 0x2000;=0D
+ NvVariableSize =3D NvStorageSize / 2 - FtwWorkingSize;=0D
+ DEBUG ((DEBUG_INFO, "NvStorageBase:0x%x, NvStorageSize:0x%x\n", NvStorag=
eBase, NvStorageSize));=0D
+=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageVariableSize, NvVariableSize);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageVariableBase, NvStorageBase);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ Status =3D PcdSet64S(PcdFlashNvStorageVariableBase64, NvStorageBase);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageFtwWorkingSize, FtwWorkingSize);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageFtwWorkingBase, NvStorageBase + Nv=
VariableSize);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageFtwSpareSize, FtwSpareSize);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ Status =3D PcdSet32S(PcdFlashNvStorageFtwSpareBase, NvStorageBase + Ft=
wSpareSize);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Get a heathy FV header used for variable store recovery=0D
+=0D
+ @retval The FV header.=0D
+=0D
+**/=0D
+EFI_FIRMWARE_VOLUME_HEADER *=0D
+GetFvHeaderTemplate (=0D
+ VOID=0D
+ )=0D
+{=0D
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;=0D
+ UINTN FvSize;=0D
+=0D
+ FvSize =3D PcdGet32(PcdFlashNvStorageFtwSpareSize) * 2;=0D
+ FvHeader =3D &mFvbMediaInfo.FvInfo;=0D
+ FvHeader->FvLength =3D FvSize;=0D
+ FvHeader->BlockMap[0].NumBlocks =3D (UINT32) (FvSize / FvHeader->BlockMa=
p[0].Length);=0D
+ FvHeader->Checksum =3D 0;=0D
+ FvHeader->Checksum =3D CalculateCheckSum16 ((UINT16 *) FvHeader, FvHeade=
r->HeaderLength);=0D
+=0D
+ return FvHeader;=0D
+}=0D
+=0D
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c b/UefiPayloadPkg/Fvb=
RuntimeDxe/FvbService.c
new file mode 100644
index 0000000000..dc213073df
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
@@ -0,0 +1,1085 @@
+/** @file=0D
+Firmware Volume Block Driver to provide FVB service.=0D
+=0D
+ Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include "FvbService.h"=0D
+=0D
+//=0D
+// Global variable for this FVB driver which contains=0D
+// the private data of all firmware volume block instances=0D
+//=0D
+FWB_GLOBAL mFvbModuleGlobal;=0D
+=0D
+FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate =3D {=0D
+ {=0D
+ {=0D
+ HARDWARE_DEVICE_PATH,=0D
+ HW_MEMMAP_DP,=0D
+ {=0D
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH)),=0D
+ (UINT8)(sizeof (MEMMAP_DEVICE_PATH) >> 8)=0D
+ }=0D
+ },=0D
+ EfiMemoryMappedIO,=0D
+ (EFI_PHYSICAL_ADDRESS) 0,=0D
+ (EFI_PHYSICAL_ADDRESS) 0,=0D
+ },=0D
+ {=0D
+ END_DEVICE_PATH_TYPE,=0D
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D
+ {=0D
+ END_DEVICE_PATH_LENGTH,=0D
+ 0=0D
+ }=0D
+ }=0D
+};=0D
+=0D
+FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate =3D {=0D
+ {=0D
+ {=0D
+ MEDIA_DEVICE_PATH,=0D
+ MEDIA_PIWG_FW_VOL_DP,=0D
+ {=0D
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH)),=0D
+ (UINT8)(sizeof (MEDIA_FW_VOL_DEVICE_PATH) >> 8)=0D
+ }=0D
+ },=0D
+ { 0 }=0D
+ },=0D
+ {=0D
+ END_DEVICE_PATH_TYPE,=0D
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,=0D
+ {=0D
+ END_DEVICE_PATH_LENGTH,=0D
+ 0=0D
+ }=0D
+ }=0D
+};=0D
+=0D
+=0D
+EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate =3D {=0D
+ FVB_DEVICE_SIGNATURE,=0D
+ NULL,=0D
+ 0, // Instance=0D
+ {=0D
+ FvbProtocolGetAttributes,=0D
+ FvbProtocolSetAttributes,=0D
+ FvbProtocolGetPhysicalAddress,=0D
+ FvbProtocolGetBlockSize,=0D
+ FvbProtocolRead,=0D
+ FvbProtocolWrite,=0D
+ FvbProtocolEraseBlocks,=0D
+ NULL=0D
+ } // FwVolBlockInstance=0D
+};=0D
+=0D
+=0D
+/**=0D
+ Get the pointer to EFI_FW_VOL_INSTANCE from the buffer pointed=0D
+ by mFvbModuleGlobal.FvInstance based on a index.=0D
+ Each EFI_FW_VOL_INSTANCE is with variable length as=0D
+ we have a block map at the end of the EFI_FIRMWARE_VOLUME_HEADER.=0D
+=0D
+ @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.=0D
+=0D
+ @return A pointer to EFI_FW_VOL_INSTANCE.=0D
+=0D
+**/=0D
+EFI_FW_VOL_INSTANCE *=0D
+GetFvbInstance (=0D
+ IN UINTN Instance=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_INSTANCE *FwhRecord;=0D
+=0D
+ if ( Instance >=3D mFvbModuleGlobal.NumFv ) {=0D
+ ASSERT_EFI_ERROR (EFI_INVALID_PARAMETER);=0D
+ return NULL;=0D
+ }=0D
+=0D
+ //=0D
+ // Find the right instance of the FVB private data=0D
+ //=0D
+ FwhRecord =3D mFvbModuleGlobal.FvInstance;=0D
+ while ( Instance > 0 ) {=0D
+ FwhRecord =3D (EFI_FW_VOL_INSTANCE *) ((UINTN)((UINT8 *)FwhRecord) +=0D
+ FwhRecord->VolumeHeader.HeaderLength +=0D
+ (sizeof (EFI_FW_VOL_INSTANCE) - sizeof (EFI_FIRMWARE_VOLUM=
E_HEADER)));=0D
+ Instance--;=0D
+ }=0D
+=0D
+ return FwhRecord;=0D
+=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Get the EFI_FVB_ATTRIBUTES_2 of a FV.=0D
+=0D
+ @param[in] The index of the EFI_FW_VOL_INSTANCE.=0D
+=0D
+ @return EFI_FVB_ATTRIBUTES_2 of the FV identified by Instance.=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_FVB_ATTRIBUTES_2=0D
+FvbGetVolumeAttributes (=0D
+ IN UINTN Instance=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_INSTANCE * FwInstance;=0D
+ FwInstance =3D GetFvbInstance(Instance);=0D
+ ASSERT (FwInstance !=3D NULL);=0D
+=0D
+ if (FwInstance =3D=3D NULL) {=0D
+ return 0;=0D
+ }=0D
+=0D
+ return FwInstance->VolumeHeader.Attributes;=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ Retrieves the starting address of an LBA in an FV. It also=0D
+ return a few other attribut of the FV.=0D
+=0D
+ @param[in] Instance The index of the EFI_FW_VOL_INSTANCE.=0D
+ @param[in] Lba The logical block address=0D
+ @param[out] LbaAddress On output, contains the physical starting ad=
dress=0D
+ of the Lba=0D
+ @param[out] LbaLength On output, contains the length of the block=
=0D
+ @param[out] NumOfBlocks A pointer to a caller allocated UINTN in whi=
ch the=0D
+ number of consecutive blocks starting with L=
ba is=0D
+ returned. All blocks in this range have a si=
ze of=0D
+ BlockSize=0D
+=0D
+ @retval EFI_SUCCESS Successfully returns=0D
+ @retval EFI_INVALID_PARAMETER Instance not found=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+FvbGetLbaAddress (=0D
+ IN UINTN Instance,=0D
+ IN EFI_LBA Lba,=0D
+ OUT UINTN *LbaAddress,=0D
+ OUT UINTN *LbaLength,=0D
+ OUT UINTN *NumOfBlocks=0D
+ )=0D
+{=0D
+ UINT32 NumBlocks;=0D
+ UINT32 BlockLength;=0D
+ UINTN Offset;=0D
+ EFI_LBA StartLba;=0D
+ EFI_LBA NextLba;=0D
+ EFI_FW_VOL_INSTANCE *FwhInstance;=0D
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;=0D
+=0D
+ //=0D
+ // Find the right instance of the FVB private data=0D
+ //=0D
+ FwhInstance =3D GetFvbInstance (Instance);=0D
+ if (FwhInstance =3D=3D NULL) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ StartLba =3D 0;=0D
+ Offset =3D 0;=0D
+ BlockMap =3D &FwhInstance->VolumeHeader.BlockMap[0];=0D
+ ASSERT (BlockMap !=3D NULL);=0D
+=0D
+ //=0D
+ // Parse the blockmap of the FV to find which map entry the Lba belongs =
to=0D
+ //=0D
+ while (TRUE) {=0D
+ if ( BlockMap !=3D NULL) {=0D
+ NumBlocks =3D BlockMap->NumBlocks;=0D
+ BlockLength =3D BlockMap->Length;=0D
+ }=0D
+=0D
+ if ( NumBlocks =3D=3D 0 || BlockLength =3D=3D 0) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ NextLba =3D StartLba + NumBlocks;=0D
+=0D
+ //=0D
+ // The map entry found=0D
+ //=0D
+ if (Lba >=3D StartLba && Lba < NextLba) {=0D
+ Offset =3D Offset + (UINTN)MultU64x32((Lba - StartLba), BlockLength)=
;=0D
+ if (LbaAddress !=3D NULL) {=0D
+ *LbaAddress =3D FwhInstance->FvBase + Offset;=0D
+ }=0D
+=0D
+ if (LbaLength !=3D NULL) {=0D
+ *LbaLength =3D BlockLength;=0D
+ }=0D
+=0D
+ if (NumOfBlocks !=3D NULL) {=0D
+ *NumOfBlocks =3D (UINTN)(NextLba - Lba);=0D
+ }=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ StartLba =3D NextLba;=0D
+ Offset =3D Offset + NumBlocks * BlockLength;=0D
+ BlockMap++;=0D
+ }=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Reads specified number of bytes into a buffer from the specified block=0D
+=0D
+ @param[in] Instance The FV instance to be read from=0D
+ @param[in] Lba The logical block address to be read fro=
m=0D
+ @param[in] BlockOffset Offset into the block at which to begin =
reading=0D
+ @param[in] NumBytes Pointer that on input contains the total=
size of=0D
+ the buffer. On output, it contains the t=
otal number=0D
+ of bytes read=0D
+ @param[in] Buffer Pointer to a caller allocated buffer tha=
t will be=0D
+ used to hold the data read=0D
+=0D
+=0D
+ @retval EFI_SUCCESS The firmware volume was read success=
fully and=0D
+ contents are in Buffer=0D
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary=
. On output,=0D
+ NumBytes contains the total number o=
f bytes returned=0D
+ in Buffer=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDi=
sabled state=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning =
correctly and=0D
+ could not be read=0D
+ @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, B=
uffer are NULL=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+FvbReadBlock (=0D
+ IN UINTN Instance,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN BlockOffset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_FVB_ATTRIBUTES_2 Attributes;=0D
+ UINTN LbaAddress;=0D
+ UINTN LbaLength;=0D
+ EFI_STATUS Status;=0D
+=0D
+ if ( (NumBytes =3D=3D NULL) || (Buffer =3D=3D NULL)) {=0D
+ return (EFI_INVALID_PARAMETER);=0D
+ }=0D
+ if (*NumBytes =3D=3D 0) {=0D
+ return (EFI_INVALID_PARAMETER);=0D
+ }=0D
+=0D
+ Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL=
L);=0D
+ if (EFI_ERROR(Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ Attributes =3D FvbGetVolumeAttributes (Instance);=0D
+=0D
+ if ( (Attributes & EFI_FVB2_READ_STATUS) =3D=3D 0) {=0D
+ return (EFI_ACCESS_DENIED);=0D
+ }=0D
+=0D
+ if (BlockOffset > LbaLength) {=0D
+ return (EFI_INVALID_PARAMETER);=0D
+ }=0D
+=0D
+ if (LbaLength < ( *NumBytes + BlockOffset ) ) {=0D
+ *NumBytes =3D (UINT32) (LbaLength - BlockOffset);=0D
+ Status =3D EFI_BAD_BUFFER_SIZE;=0D
+ }=0D
+=0D
+ Status =3D LibFvbFlashDeviceRead (LbaAddress + BlockOffset, NumBytes, Bu=
ffer);=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Writes specified number of bytes from the input buffer to the block=0D
+=0D
+ @param[in] Instance The FV instance to be written to=0D
+ @param[in] Lba The starting logical block index to write =
to=0D
+ @param[in] BlockOffset Offset into the block at which to begin wr=
iting=0D
+ @param[in] NumBytes Pointer that on input contains the total s=
ize of=0D
+ the buffer. On output, it contains the to=
tal number=0D
+ of bytes actually written=0D
+ @param[in] Buffer Pointer to a caller allocated buffer that =
contains=0D
+ the source for the write=0D
+ @retval EFI_SUCCESS The firmware volume was written successf=
ully=0D
+ @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. O=
n output,=0D
+ NumBytes contains the total number of by=
tes=0D
+ actually written=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisab=
led state=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning corr=
ectly and=0D
+ could not be written=0D
+ @retval EFI_INVALID_PARAMETER Instance not found, or NumBytes, Buffe=
r are NULL=0D
+=0D
+**/=0D
+=0D
+EFI_STATUS=0D
+FvbWriteBlock (=0D
+ IN UINTN Instance,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN BlockOffset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_FVB_ATTRIBUTES_2 Attributes;=0D
+ UINTN LbaAddress;=0D
+ UINTN LbaLength;=0D
+ EFI_STATUS Status;=0D
+=0D
+ if ( (NumBytes =3D=3D NULL) || (Buffer =3D=3D NULL)) {=0D
+ return (EFI_INVALID_PARAMETER);=0D
+ }=0D
+ if (*NumBytes =3D=3D 0) {=0D
+ return (EFI_INVALID_PARAMETER);=0D
+ }=0D
+=0D
+ Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL=
L);=0D
+ if (EFI_ERROR(Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ //=0D
+ // Check if the FV is write enabled=0D
+ //=0D
+ Attributes =3D FvbGetVolumeAttributes (Instance);=0D
+ if ( (Attributes & EFI_FVB2_WRITE_STATUS) =3D=3D 0) {=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+=0D
+ //=0D
+ // Perform boundary checks and adjust NumBytes=0D
+ //=0D
+ if (BlockOffset > LbaLength) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if ( LbaLength < ( *NumBytes + BlockOffset ) ) {=0D
+ DEBUG ((DEBUG_ERROR,=0D
+ "FvWriteBlock: Reducing Numbytes from 0x%x to 0x%x\n",=0D
+ *NumBytes, (UINT32)(LbaLength - BlockOffset)));=0D
+ *NumBytes =3D (UINT32) (LbaLength - BlockOffset);=0D
+ return EFI_BAD_BUFFER_SIZE;=0D
+ }=0D
+=0D
+ LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);=0D
+ Status =3D LibFvbFlashDeviceWrite (LbaAddress + BlockOffset, NumBytes, B=
uffer);=0D
+=0D
+ LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);=0D
+ WriteBackInvalidateDataCacheRange ((VOID *) (LbaAddress + BlockOffset), =
*NumBytes);=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Erases and initializes a firmware volume block=0D
+=0D
+ @param[in] Instance The FV instance to be erased=0D
+ @param[in] Lba The logical block index to be erased=0D
+=0D
+ @retval EFI_SUCCESS The erase request was successfully completed=
=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled =
state=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctl=
y and=0D
+ could not be written. Firmware device may ha=
ve been=0D
+ partially erased=0D
+ @retval EFI_INVALID_PARAMETER Instance not found=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+FvbEraseBlock (=0D
+ IN UINTN Instance,=0D
+ IN EFI_LBA Lba=0D
+ )=0D
+{=0D
+=0D
+ EFI_FVB_ATTRIBUTES_2 Attributes;=0D
+ UINTN LbaAddress;=0D
+ UINTN LbaLength;=0D
+ EFI_STATUS Status;=0D
+=0D
+ //=0D
+ // Check if the FV is write enabled=0D
+ //=0D
+ Attributes =3D FvbGetVolumeAttributes (Instance);=0D
+=0D
+ if( (Attributes & EFI_FVB2_WRITE_STATUS) =3D=3D 0) {=0D
+ return (EFI_ACCESS_DENIED);=0D
+ }=0D
+=0D
+ //=0D
+ // Get the starting address of the block for erase.=0D
+ //=0D
+ Status =3D FvbGetLbaAddress (Instance, Lba, &LbaAddress, &LbaLength, NUL=
L);=0D
+ if (EFI_ERROR(Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, FALSE);=0D
+=0D
+ Status =3D LibFvbFlashDeviceBlockErase (LbaAddress, LbaLength);=0D
+=0D
+ LibFvbFlashDeviceBlockLock (LbaAddress, LbaLength, TRUE);=0D
+=0D
+ WriteBackInvalidateDataCacheRange ((VOID *) LbaAddress, LbaLength);=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Modifies the current settings of the firmware volume according to the=0D
+ input parameter, and returns the new setting of the volume=0D
+=0D
+ @param[in] Instance The FV instance whose attributes is go=
ing to be=0D
+ modified=0D
+ @param[in] Attributes On input, it is a pointer to EFI_FVB_A=
TTRIBUTES_2=0D
+ containing the desired firmware volume=
settings.=0D
+ On successful return, it contains the =
new settings=0D
+ of the firmware volume=0D
+=0D
+ @retval EFI_SUCCESS Successfully returns=0D
+ @retval EFI_ACCESS_DENIED The volume setting is locked and canno=
t be modified=0D
+ @retval EFI_INVALID_PARAMETER Instance not found, or The attributes =
requested are=0D
+ in conflict with the capabilities as d=
eclared in the=0D
+ firmware volume header=0D
+=0D
+**/=0D
+STATIC=0D
+EFI_STATUS=0D
+FvbSetVolumeAttributes (=0D
+ IN UINTN Instance,=0D
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_INSTANCE *FwhInstance;=0D
+ EFI_FVB_ATTRIBUTES_2 OldAttributes;=0D
+ EFI_FVB_ATTRIBUTES_2 *AttribPtr;=0D
+ EFI_FVB_ATTRIBUTES_2 UnchangedAttributes;=0D
+ UINT32 Capabilities;=0D
+ UINT32 OldStatus, NewStatus;=0D
+=0D
+ //=0D
+ // Find the right instance of the FVB private data=0D
+ //=0D
+ FwhInstance =3D GetFvbInstance (Instance);=0D
+ if (FwhInstance =3D=3D NULL) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ AttribPtr =3D (EFI_FVB_ATTRIBUTES_2 *) &(FwhInstance->VolumeHeader.Attri=
butes);=0D
+ ASSERT (AttribPtr !=3D NULL);=0D
+ if ( AttribPtr =3D=3D NULL) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ OldAttributes =3D *AttribPtr;=0D
+ Capabilities =3D OldAttributes & EFI_FVB2_CAPABILITIES;=0D
+ OldStatus =3D OldAttributes & EFI_FVB2_STATUS;=0D
+ NewStatus =3D *Attributes & EFI_FVB2_STATUS;=0D
+=0D
+ UnchangedAttributes =3D EFI_FVB2_READ_DISABLED_CAP | \=0D
+ EFI_FVB2_READ_ENABLED_CAP | \=0D
+ EFI_FVB2_WRITE_DISABLED_CAP | \=0D
+ EFI_FVB2_WRITE_ENABLED_CAP | \=0D
+ EFI_FVB2_LOCK_CAP | \=0D
+ EFI_FVB2_STICKY_WRITE | \=0D
+ EFI_FVB2_MEMORY_MAPPED | \=0D
+ EFI_FVB2_ERASE_POLARITY | \=0D
+ EFI_FVB2_READ_LOCK_CAP | \=0D
+ EFI_FVB2_WRITE_LOCK_CAP | \=0D
+ EFI_FVB2_ALIGNMENT;=0D
+=0D
+ //=0D
+ // Some attributes of FV is read only can *not* be set=0D
+ //=0D
+ if ((OldAttributes & UnchangedAttributes) ^ (*Attributes & UnchangedAttr=
ibutes)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ //=0D
+ // If firmware volume is locked, no status bit can be updated=0D
+ //=0D
+ if ( OldAttributes & EFI_FVB2_LOCK_STATUS ) {=0D
+ if ( OldStatus ^ NewStatus ) {=0D
+ return EFI_ACCESS_DENIED;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Test read disable=0D
+ //=0D
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) =3D=3D 0) {=0D
+ if ((NewStatus & EFI_FVB2_READ_STATUS) =3D=3D 0) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Test read enable=0D
+ //=0D
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) =3D=3D 0) {=0D
+ if (NewStatus & EFI_FVB2_READ_STATUS) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Test write disable=0D
+ //=0D
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) =3D=3D 0) {=0D
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) =3D=3D 0) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Test write enable=0D
+ //=0D
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) =3D=3D 0) {=0D
+ if (NewStatus & EFI_FVB2_WRITE_STATUS) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Test lock=0D
+ //=0D
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) =3D=3D 0) {=0D
+ if (NewStatus & EFI_FVB2_LOCK_STATUS) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ }=0D
+=0D
+ *AttribPtr =3D (*AttribPtr) & (0xFFFFFFFF & (~EFI_FVB2_STATUS));=0D
+ *AttribPtr =3D (*AttribPtr) | NewStatus;=0D
+ *Attributes =3D *AttribPtr;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Retrieves the physical address of the device.=0D
+=0D
+ @param[in] This A pointer to EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL.=0D
+ @param[out] Address Output buffer containing the address.=0D
+=0D
+ @retval EFI_SUCCESS The function always return successfully.=0D
+ @retval EFI_INVALID_PARAMETER Instance not found.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetPhysicalAddress (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ OUT EFI_PHYSICAL_ADDRESS *Address=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+ EFI_FW_VOL_INSTANCE *FwhInstance;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ FwhInstance =3D GetFvbInstance(FvbDevice->Instance);=0D
+ if (FwhInstance =3D=3D NULL) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ *Address =3D FwhInstance->FvBase;=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ Retrieve the size of a logical block=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[in] Lba Indicates which block to return the size for.=0D
+ @param[out] BlockSize A pointer to a caller allocated UINTN in which=0D
+ the size of the block is returned=0D
+ @param[out] NumOfBlocks A pointer to a caller allocated UINTN in which t=
he=0D
+ number of consecutive blocks starting with Lba i=
s=0D
+ returned. All blocks in this range have a size o=
f=0D
+ BlockSize=0D
+=0D
+ @retval EFI_SUCCESS The function always return successfully.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetBlockSize (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ OUT UINTN *BlockSize,=0D
+ OUT UINTN *NumOfBlocks=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ return FvbGetLbaAddress (FvbDevice->Instance, Lba, NULL, BlockSize, NumO=
fBlocks);=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Retrieves Volume attributes. No polarity translations are done.=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[out] Attributes Output buffer which contains attributes=0D
+=0D
+ @retval EFI_SUCCESS The function always return successfully.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetAttributes (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ *Attributes =3D FvbGetVolumeAttributes (FvbDevice->Instance);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Sets Volume attributes. No polarity translations are done.=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[out] Attributes Output buffer which contains attributes=0D
+=0D
+ @retval EFI_SUCCESS The function always return successfully.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolSetAttributes (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ Status =3D FvbSetVolumeAttributes (FvbDevice->Instance, Attributes);=
=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ This function erases one or more blocks as denoted by the=0D
+ variable argument list. The entire parameter list of blocks must be veri=
fied=0D
+ prior to erasing any blocks. If a block is requested that does not exis=
t=0D
+ within the associated firmware volume (it has a larger index than the la=
st=0D
+ block of the firmware volume), the EraseBlock() function must return=0D
+ EFI_INVALID_PARAMETER without modifying the contents of the firmware vol=
ume.=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[in] ... Starting LBA followed by Number of Lba to erase.=
=0D
+ a -1 to terminate the list.=0D
+=0D
+ @retval EFI_SUCCESS The erase request was successfully completed=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisabled st=
ate=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning correctly =
and=0D
+ could not be written. Firmware device may have=
been=0D
+ partially erased=0D
+=0D
+**/EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolEraseBlocks (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ ...=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+ EFI_FW_VOL_INSTANCE *FwhInstance;=0D
+ UINTN NumOfBlocks;=0D
+ VA_LIST args;=0D
+ EFI_LBA StartingLba;=0D
+ UINTN NumOfLba;=0D
+ EFI_STATUS Status;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ FwhInstance =3D GetFvbInstance (FvbDevice->Instance);=0D
+ if (FwhInstance =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ NumOfBlocks =3D FwhInstance->NumOfBlocks;=0D
+ VA_START (args, This);=0D
+=0D
+ do {=0D
+ StartingLba =3D VA_ARG (args, EFI_LBA);=0D
+ if ( StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR ) {=0D
+ break;=0D
+ }=0D
+=0D
+ NumOfLba =3D VA_ARG (args, UINT32);=0D
+=0D
+ //=0D
+ // Check input parameters=0D
+ //=0D
+ if (NumOfLba =3D=3D 0) {=0D
+ VA_END (args);=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ if ( ( StartingLba + NumOfLba ) > NumOfBlocks ) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+ } while ( 1 );=0D
+=0D
+ VA_END (args);=0D
+=0D
+ VA_START (args, This);=0D
+ do {=0D
+ StartingLba =3D VA_ARG (args, EFI_LBA);=0D
+ if (StartingLba =3D=3D EFI_LBA_LIST_TERMINATOR) {=0D
+ break;=0D
+ }=0D
+=0D
+ NumOfLba =3D VA_ARG (args, UINT32);=0D
+=0D
+ while ( NumOfLba > 0 ) {=0D
+ Status =3D FvbEraseBlock (FvbDevice->Instance, StartingLba);=0D
+ if ( EFI_ERROR(Status)) {=0D
+ VA_END (args);=0D
+ return Status;=0D
+ }=0D
+ StartingLba++;=0D
+ NumOfLba--;=0D
+ }=0D
+ } while ( 1 );=0D
+=0D
+ VA_END (args);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ Writes data beginning at Lba:Offset from FV. The write terminates either=
=0D
+ when *NumBytes of data have been written, or when a block boundary is=0D
+ reached. *NumBytes is updated to reflect the actual number of bytes=0D
+ written. The write opertion does not include erase. This routine will=0D
+ attempt to write only the specified bytes. If the writes do not stick,=0D
+ it will return an error.=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[in] Lba Block in which to begin write=0D
+ @param[in] Offset Offset in the block at which to begin write=0D
+ @param[in,out] NumBytes On input, indicates the requested write size. =
On=0D
+ output, indicates the actual number of bytes w=
ritten=0D
+ @param[in] Buffer Buffer containing source data for the write.=0D
+=0D
+ @retval EFI_SUCCESS The firmware volume was written successful=
ly=0D
+ @retval EFI_BAD_BUFFER_SIZE Write attempted across a LBA boundary. On =
output,=0D
+ NumBytes contains the total number of byte=
s=0D
+ actually written=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the WriteDisable=
d state=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning correc=
tly and=0D
+ could not be written=0D
+ @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolWrite (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN Offset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+ EFI_STATUS Status;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ Status =3D FvbWriteBlock (FvbDevice->Instance, Lba, Offset, NumBytes,=
Buffer);=0D
+ DEBUG((DEBUG_VERBOSE,=0D
+ "FvbWrite: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x Status=
:%r\n",=0D
+ Lba, Offset, *NumBytes, Buffer, Status));=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ Reads data beginning at Lba:Offset from FV. The Read terminates either=0D
+ when *NumBytes of data have been read, or when a block boundary is=0D
+ reached. *NumBytes is updated to reflect the actual number of bytes=0D
+ written. The write opertion does not include erase. This routine will=0D
+ attempt to write only the specified bytes. If the writes do not stick,=0D
+ it will return an error.=0D
+=0D
+ @param[in] This Calling context=0D
+ @param[in] Lba Block in which to begin write=0D
+ @param[in] Offset Offset in the block at which to begin write=0D
+ @param[in,out] NumBytes On input, indicates the requested write size. =
On=0D
+ output, indicates the actual number of bytes w=
ritten=0D
+ @param[in] Buffer Buffer containing source data for the write.=0D
+=0D
+=0D
+Returns:=0D
+ @retval EFI_SUCCESS The firmware volume was read successfully =
and=0D
+ contents are in Buffer=0D
+ @retval EFI_BAD_BUFFER_SIZE Read attempted across a LBA boundary. On o=
utput,=0D
+ NumBytes contains the total number of byte=
s returned=0D
+ in Buffer=0D
+ @retval EFI_ACCESS_DENIED The firmware volume is in the ReadDisabled=
state=0D
+ @retval EFI_DEVICE_ERROR The block device is not functioning correc=
tly and=0D
+ could not be read=0D
+ @retval EFI_INVALID_PARAMETER NumBytes or Buffer are NULL=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolRead (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN Offset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ OUT UINT8 *Buffer=0D
+ )=0D
+{=0D
+=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+ EFI_STATUS Status;=0D
+=0D
+ FvbDevice =3D FVB_DEVICE_FROM_THIS (This);=0D
+ Status =3D FvbReadBlock (FvbDevice->Instance, Lba, Offset, NumBytes, =
Buffer);=0D
+ DEBUG((DEBUG_VERBOSE,=0D
+ "FvbRead: Lba: 0x%lx Offset: 0x%x NumBytes: 0x%x, Buffer: 0x%x, Status=
:%r\n",=0D
+ Lba, Offset, *NumBytes, Buffer, Status));=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Check the integrity of firmware volume header in FvBase=0D
+=0D
+ @param[in] FvBase A pointer to firmware volume base address.=0D
+=0D
+ @retval TRUE The firmware volume is consistent=0D
+ @retval FALSE The firmware volume has corrupted.=0D
+=0D
+**/=0D
+BOOLEAN=0D
+IsFvHeaderValid (=0D
+ IN EFI_PHYSICAL_ADDRESS FvBase=0D
+ )=0D
+{=0D
+ UINT16 Sum;=0D
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;=0D
+=0D
+ FwVolHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvBase;=0D
+ if (FvBase =3D=3D PcdGet32(PcdFlashNvStorageVariableBase)) {=0D
+ if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiSystemNvDataFvGuid,=
sizeof(EFI_GUID)) !=3D 0 ) {=0D
+ DEBUG((DEBUG_INFO, " --FileSystemGuid not match: %g\n", &FwVolHeade=
r->FileSystemGuid));=0D
+ return FALSE;=0D
+ }=0D
+ } else {=0D
+ if (CompareMem (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem2=
Guid, sizeof(EFI_GUID)) !=3D 0 ) {=0D
+ DEBUG((DEBUG_INFO, " --not expected guid.\n"));=0D
+ return FALSE;=0D
+ }=0D
+ }=0D
+=0D
+ if ( (FwVolHeader->Revision !=3D EFI_FVH_REVISION) ||=0D
+ (FwVolHeader->Signature !=3D EFI_FVH_SIGNATURE) ||=0D
+ (FwVolHeader->FvLength =3D=3D ((UINTN) -1)) ||=0D
+ ((FwVolHeader->HeaderLength & 0x01 ) !=3D0) ) {=0D
+ DEBUG((DEBUG_INFO, " -- >Revision =3D 0x%x, Signature =3D 0x%x\n", Fw=
VolHeader->Revision, FwVolHeader->Signature ));=0D
+ DEBUG((DEBUG_INFO, " -- >FvLength =3D 0x%lx, HeaderLength =3D 0x%x\n"=
, FwVolHeader->FvLength, FwVolHeader->HeaderLength ));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ Sum =3D CalculateSum16 ((UINT16 *) FwVolHeader, FwVolHeader->HeaderLengt=
h);=0D
+ if (Sum !=3D 0) {=0D
+ DEBUG((DEBUG_INFO, "error: checksum: 0x%04X (expect 0x0)\n", Sum));=0D
+ return FALSE;=0D
+ }=0D
+=0D
+ return TRUE;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Get intial variable data.=0D
+=0D
+ @param[out] VarData Valid variable data.=0D
+ @param[out] VarSize Valid variable size.=0D
+=0D
+ @retval RETURN_SUCCESS Successfully found initial variable data.=
=0D
+ @retval RETURN_NOT_FOUND Failed to find the variable data file from=
FV.=0D
+ @retval EFI_INVALID_PARAMETER VarData or VarSize is null.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+GetInitialVariableData (=0D
+ OUT VOID **VarData,=0D
+ OUT UINTN *VarSize=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ VOID *ImageData;=0D
+ UINTN ImageSize;=0D
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;=0D
+ VARIABLE_STORE_HEADER *VariableStore;=0D
+ AUTHENTICATED_VARIABLE_HEADER *Variable;=0D
+ UINTN VariableSize;=0D
+ UINTN VarEndAddr;=0D
+=0D
+ if ((VarData =3D=3D NULL) || (VarSize =3D=3D NULL)) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ Status =3D GetSectionFromAnyFv (PcdGetPtr(PcdNvsDataFile), EFI_SECTION_R=
AW, 0, &ImageData, &ImageSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) ImageData;=0D
+ VariableStore =3D (VARIABLE_STORE_HEADER *) ((UINT8 *)ImageData + FvHead=
er->HeaderLength);=0D
+ VarEndAddr =3D (UINTN)VariableStore + VariableStore->Size;=0D
+ Variable =3D (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN (Variab=
leStore + 1);=0D
+ *VarData =3D (VOID *)Variable;=0D
+ while (((UINTN)Variable < VarEndAddr)) {=0D
+ if (Variable->StartId !=3D VARIABLE_DATA) {=0D
+ break;=0D
+ }=0D
+ VariableSize =3D sizeof (AUTHENTICATED_VARIABLE_HEADER);=0D
+ VariableSize =3D sizeof (AUTHENTICATED_VARIABLE_HEADER) + Variable->Da=
taSize + Variable->NameSize;=0D
+ Variable =3D (AUTHENTICATED_VARIABLE_HEADER *) HEADER_ALIGN ((UINT=
N) Variable + VariableSize);=0D
+ }=0D
+=0D
+ *VarSize =3D (UINTN)Variable - HEADER_ALIGN (VariableStore + 1);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ The function does the necessary initialization work for=0D
+ Firmware Volume Block Driver.=0D
+=0D
+ @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.=0D
+ It will ASSERT on errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+FvbInitialize (=0D
+ VOID=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_INSTANCE *FwVolInstance;=0D
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;=0D
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;=0D
+ EFI_PHYSICAL_ADDRESS BaseAddress;=0D
+ UINTN WriteAddr;=0D
+ EFI_STATUS Status;=0D
+ UINTN BufferSize;=0D
+ UINTN Length;=0D
+ VARIABLE_STORE_HEADER VariableStore;=0D
+ VOID *VarData;=0D
+=0D
+ InitVariableStore ();=0D
+ BaseAddress =3D PcdGet32(PcdFlashNvStorageVariableBase);=0D
+ FvHeader =3D (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) BaseAddress;=0D
+=0D
+ //=0D
+ // Check FV header and variable store header=0D
+ //=0D
+ if (!IsFvHeaderValid (BaseAddress)) {=0D
+ //=0D
+ // Write back a healthy FV header=0D
+ //=0D
+ DEBUG ((DEBUG_ERROR, "Fvb: Writing back a healthy FV header: 0x%lx\n",=
BaseAddress));=0D
+ FvHeader =3D GetFvHeaderTemplate ();=0D
+ LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Le=
ngth, FALSE);=0D
+=0D
+ Status =3D LibFvbFlashDeviceBlockErase ((UINTN)BaseAddress, FvHeader->=
BlockMap->Length);=0D
+ ASSERT_EFI_ERROR(Status);=0D
+=0D
+ Length =3D FvHeader->HeaderLength;=0D
+ WriteAddr =3D (UINTN)BaseAddress;=0D
+ Status =3D LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) FvHea=
der);=0D
+ WriteAddr +=3D Length;=0D
+ ASSERT_EFI_ERROR(Status);=0D
+=0D
+ //=0D
+ // Write back variable store header=0D
+ //=0D
+ VariableStore.Size =3D PcdGet32(PcdFlashNvStorageVariableSize) - FvH=
eader->HeaderLength;=0D
+ VariableStore.Format =3D VARIABLE_STORE_FORMATTED;=0D
+ VariableStore.State =3D VARIABLE_STORE_HEALTHY;=0D
+ CopyGuid (&VariableStore.Signature, &gEfiAuthenticatedVariableGuid);=0D
+ BufferSize =3D sizeof (VARIABLE_STORE_HEADER);=0D
+ Status =3D LibFvbFlashDeviceWrite (WriteAddr, &BufferSize, (UINT8 *) &=
VariableStore);=0D
+ WriteAddr +=3D BufferSize;=0D
+ ASSERT_EFI_ERROR(Status);=0D
+=0D
+ //=0D
+ // Write initial variable data if found=0D
+ //=0D
+ Status =3D GetInitialVariableData (&VarData, &Length);=0D
+ if (!EFI_ERROR (Status)) {=0D
+ Status =3D LibFvbFlashDeviceWrite (WriteAddr, &Length, (UINT8 *) Var=
Data);=0D
+ ASSERT_EFI_ERROR(Status);=0D
+ }=0D
+=0D
+ LibFvbFlashDeviceBlockLock ((UINTN)BaseAddress, FvHeader->BlockMap->Le=
ngth, TRUE);=0D
+ WriteBackInvalidateDataCacheRange ((VOID *) (UINTN) BaseAddress, FvHea=
der->BlockMap->Length);=0D
+ }=0D
+=0D
+ //=0D
+ // Create a new FW volume instance for NVS variable=0D
+ //=0D
+ BufferSize =3D FvHeader->HeaderLength + sizeof (EFI_FW_VOL_INSTANCE) =
- sizeof (EFI_FIRMWARE_VOLUME_HEADER);=0D
+ FwVolInstance =3D (EFI_FW_VOL_INSTANCE *) AllocateRuntimeZeroPool (Buffe=
rSize);=0D
+ if (FwVolInstance =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ FwVolInstance->FvBase =3D (UINTN)BaseAddress;=0D
+ CopyMem (&FwVolInstance->VolumeHeader, FvHeader, FvHeader->HeaderLength)=
;=0D
+=0D
+ //=0D
+ // Process the block map for each FV. Assume it has same block size.=0D
+ //=0D
+ FwVolInstance->NumOfBlocks =3D 0;=0D
+ FvHeader =3D &FwVolInstance->VolumeHeader;=0D
+ for (BlockMap =3D FvHeader->BlockMap; BlockMap->NumBlocks !=3D 0; BlockM=
ap++) {=0D
+ FwVolInstance->NumOfBlocks +=3D BlockMap->NumBlocks;=0D
+ }=0D
+=0D
+ //=0D
+ // Add a FVB Protocol Instance=0D
+ //=0D
+ Status =3D InstallFvbProtocol (FwVolInstance, mFvbModuleGlobal.NumFv);=0D
+ mFvbModuleGlobal.NumFv++;=0D
+ mFvbModuleGlobal.FvInstance =3D FwVolInstance;=0D
+=0D
+ return Status;=0D
+}=0D
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h b/UefiPayloadPkg/Fvb=
RuntimeDxe/FvbService.h
new file mode 100644
index 0000000000..8eb5657b07
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbService.h
@@ -0,0 +1,187 @@
+/** @file=0D
+The header file for Firmware volume block driver.=0D
+=0D
+Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef _FW_BLOCK_SERVICE_H_=0D
+#define _FW_BLOCK_SERVICE_H_=0D
+=0D
+#include <Guid/EventGroup.h>=0D
+#include <Guid/FirmwareFileSystem2.h>=0D
+#include <Guid/SystemNvDataGuid.h>=0D
+#include <Guid/VariableFormat.h>=0D
+#include <Protocol/DevicePath.h>=0D
+#include <Protocol/FirmwareVolumeBlock.h>=0D
+#include <Library/UefiDriverEntryPoint.h>=0D
+#include <Library/UefiBootServicesTableLib.h>=0D
+#include <Library/UefiLib.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Library/IoLib.h>=0D
+#include <Library/CacheMaintenanceLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/PcdLib.h>=0D
+#include <Library/FlashDeviceLib.h>=0D
+#include <Library/DevicePathLib.h>=0D
+#include <Library/HobLib.h>=0D
+#include <Library/DxeServicesLib.h>=0D
+#include <Guid/NvVariableInfoGuid.h>=0D
+#include <Register/ArchitecturalMsr.h>=0D
+=0D
+//=0D
+// Define two helper macro to extract the Capability field or Status field=
in FVB=0D
+// bit fields=0D
+//=0D
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \=0D
+ EFI_FVB2_READ_ENABLED_CAP | \=0D
+ EFI_FVB2_WRITE_DISABLED_CAP | \=0D
+ EFI_FVB2_WRITE_ENABLED_CAP | \=0D
+ EFI_FVB2_LOCK_CAP \=0D
+ )=0D
+=0D
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EF=
I_FVB2_LOCK_STATUS)=0D
+=0D
+=0D
+typedef struct {=0D
+ UINTN FvBase;=0D
+ UINTN NumOfBlocks;=0D
+ //=0D
+ // Note!!!: VolumeHeader must be the last element=0D
+ // of the structure.=0D
+ //=0D
+ EFI_FIRMWARE_VOLUME_HEADER VolumeHeader;=0D
+} EFI_FW_VOL_INSTANCE;=0D
+=0D
+=0D
+typedef struct {=0D
+ EFI_FW_VOL_INSTANCE *FvInstance;=0D
+ UINT32 NumFv;=0D
+ UINT32 Flags;=0D
+} FWB_GLOBAL;=0D
+=0D
+//=0D
+// Fvb Protocol instance data=0D
+//=0D
+#define FVB_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FwVolBlockI=
nstance, FVB_DEVICE_SIGNATURE)=0D
+#define FVB_EXTEND_DEVICE_FROM_THIS(a) CR(a, EFI_FW_VOL_BLOCK_DEVICE, FvbE=
xtension, FVB_DEVICE_SIGNATURE)=0D
+#define FVB_DEVICE_SIGNATURE SIGNATURE_32('F','V','B','C')=0D
+=0D
+typedef struct {=0D
+ MEDIA_FW_VOL_DEVICE_PATH FvDevPath;=0D
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;=0D
+} FV_PIWG_DEVICE_PATH;=0D
+=0D
+typedef struct {=0D
+ MEMMAP_DEVICE_PATH MemMapDevPath;=0D
+ EFI_DEVICE_PATH_PROTOCOL EndDevPath;=0D
+} FV_MEMMAP_DEVICE_PATH;=0D
+=0D
+typedef struct {=0D
+ UINT32 Signature;=0D
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;=0D
+ UINTN Instance;=0D
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL FwVolBlockInstance;=0D
+} EFI_FW_VOL_BLOCK_DEVICE;=0D
+=0D
+/**=0D
+ Get a heathy FV header used for variable store recovery=0D
+=0D
+ @retval The FV header.=0D
+=0D
+**/=0D
+EFI_FIRMWARE_VOLUME_HEADER *=0D
+GetFvHeaderTemplate (=0D
+ VOID=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+InitVariableStore (=0D
+ VOID=0D
+ );=0D
+=0D
+//=0D
+// Protocol APIs=0D
+//=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetAttributes (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolSetAttributes (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN OUT EFI_FVB_ATTRIBUTES_2 *Attributes=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetPhysicalAddress (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ OUT EFI_PHYSICAL_ADDRESS *Address=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolGetBlockSize (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ OUT UINTN *BlockSize,=0D
+ OUT UINTN *NumOfBlocks=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolRead (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN Offset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ OUT UINT8 *Buffer=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolWrite (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ IN EFI_LBA Lba,=0D
+ IN UINTN Offset,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbProtocolEraseBlocks (=0D
+ IN CONST EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *This,=0D
+ ...=0D
+ );=0D
+=0D
+EFI_FW_VOL_INSTANCE *=0D
+GetFvbInstance (=0D
+ IN UINTN Instance=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+InstallFvbProtocol (=0D
+ IN EFI_FW_VOL_INSTANCE *FwhInstance,=0D
+ IN UINTN InstanceNum=0D
+ );=0D
+=0D
+EFI_STATUS=0D
+FvbInitialize (=0D
+ VOID=0D
+ );=0D
+=0D
+extern FWB_GLOBAL mFvbModuleGlobal;=0D
+extern EFI_FW_VOL_BLOCK_DEVICE mFvbDeviceTemplate;=0D
+extern FV_MEMMAP_DEVICE_PATH mFvMemmapDevicePathTemplate;=0D
+extern FV_PIWG_DEVICE_PATH mFvPIWGDevicePathTemplate;=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c b/UefiPayloadPkg/=
FvbRuntimeDxe/FvbServiceSmm.c
new file mode 100644
index 0000000000..0f1f4b369c
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c
@@ -0,0 +1,139 @@
+/** @file=0D
+ SMM Firmware Volume Block Driver.=0D
+=0D
+ Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include <PiSmm.h>=0D
+#include <Library/SmmServicesTableLib.h>=0D
+#include "FvbSmmCommon.h"=0D
+#include "FvbService.h"=0D
+=0D
+/**=0D
+ The function installs EFI_SMM_FIRMWARE_VOLUME_BLOCK protocol=0D
+ for each FV in the system.=0D
+=0D
+ @param[in] FwhInstance The pointer to a FW volume instance structure,=
=0D
+ which contains the information about one FV.=0D
+ @param[in] InstanceNum The instance number which can be used as a ID=
=0D
+ to locate this FwhInstance in other functions.=
=0D
+=0D
+ @retval EFI_SUCESS Installed successfully.=0D
+ @retval Else Did not install successfully.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+InstallFvbProtocol (=0D
+ IN EFI_FW_VOL_INSTANCE *FwhInstance,=0D
+ IN UINTN InstanceNum=0D
+ )=0D
+{=0D
+ EFI_FW_VOL_BLOCK_DEVICE *FvbDevice;=0D
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;=0D
+ EFI_STATUS Status;=0D
+ EFI_HANDLE FvbHandle;=0D
+ FV_MEMMAP_DEVICE_PATH *FvDevicePath;=0D
+ VOID *TempPtr;=0D
+=0D
+ FvbDevice =3D (EFI_FW_VOL_BLOCK_DEVICE *) AllocateRuntimeCopyPool (=0D
+ sizeof (EFI_FW_VOL_BLOCK_DEVIC=
E),=0D
+ &mFvbDeviceTemplate=0D
+ );=0D
+ if (FvbDevice =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ FvbDevice->Instance =3D InstanceNum;=0D
+ FwVolHeader =3D &FwhInstance->VolumeHeader;=0D
+=0D
+ //=0D
+ // Set up the devicepath=0D
+ //=0D
+ if (FwVolHeader->ExtHeaderOffset =3D=3D 0) {=0D
+ //=0D
+ // FV does not contains extension header, then produce MEMMAP_DEVICE_P=
ATH=0D
+ //=0D
+ TempPtr =3D AllocateRuntimeCopyPool (sizeof (FV_MEMMAP_DEVICE_PATH), &=
mFvMemmapDevicePathTemplate);=0D
+ FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;=0D
+ if (FvbDevice->DevicePath =3D=3D NULL) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ FvDevicePath =3D (FV_MEMMAP_DEVICE_PATH *) FvbDevice->DevicePath;=0D
+ FvDevicePath->MemMapDevPath.StartingAddress =3D FwhInstance->FvBase;=0D
+ FvDevicePath->MemMapDevPath.EndingAddress =3D FwhInstance->FvBase + =
FwVolHeader->FvLength - 1;=0D
+ } else {=0D
+ TempPtr =3D AllocateRuntimeCopyPool (sizeof (FV_PIWG_DEVICE_PATH), &mF=
vPIWGDevicePathTemplate);=0D
+ FvbDevice->DevicePath =3D (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;=0D
+ if (FvbDevice->DevicePath =3D=3D NULL) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+=0D
+ CopyGuid (=0D
+ &((FV_PIWG_DEVICE_PATH *)FvbDevice->DevicePath)->FvDevPath.FvName,=0D
+ (GUID *)(UINTN)(FwhInstance->FvBase + FwVolHeader->ExtHeaderOffset)=
=0D
+ );=0D
+ }=0D
+=0D
+ //=0D
+ // Install the SMM Firmware Volume Block Protocol and Device Path Protoc=
ol=0D
+ //=0D
+ FvbHandle =3D NULL;=0D
+ Status =3D gSmst->SmmInstallProtocolInterface (=0D
+ &FvbHandle,=0D
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,=0D
+ EFI_NATIVE_INTERFACE,=0D
+ &FvbDevice->FwVolBlockInstance=0D
+ );=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ Status =3D gSmst->SmmInstallProtocolInterface (=0D
+ &FvbHandle,=0D
+ &gEfiDevicePathProtocolGuid,=0D
+ EFI_NATIVE_INTERFACE,=0D
+ FvbDevice->DevicePath=0D
+ );=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ //=0D
+ // Notify the Fvb wrapper driver SMM fvb is ready=0D
+ //=0D
+ FvbHandle =3D NULL;=0D
+ Status =3D gBS->InstallProtocolInterface (=0D
+ &FvbHandle,=0D
+ &gEfiSmmFirmwareVolumeBlockProtocolGuid,=0D
+ EFI_NATIVE_INTERFACE,=0D
+ &FvbDevice->FwVolBlockInstance=0D
+ );=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ The driver entry point for SMM Firmware Volume Block Driver.=0D
+=0D
+ The function does the necessary initialization work=0D
+ Firmware Volume Block Driver.=0D
+=0D
+ @param[in] ImageHandle The firmware allocated handle for the UEFI=
image.=0D
+ @param[in] SystemTable A pointer to the EFI system table.=0D
+=0D
+ @retval EFI_SUCCESS This funtion always return EFI_SUCCESS.=0D
+ It will ASSERT on errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+FvbSmmInitialize (=0D
+ IN EFI_HANDLE ImageHandle,=0D
+ IN EFI_SYSTEM_TABLE *SystemTable=0D
+ )=0D
+{=0D
+ FvbInitialize ();=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf b/UefiPayloadPkg/FvbRu=
ntimeDxe/FvbSmm.inf
new file mode 100644
index 0000000000..2a262076d6
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf
@@ -0,0 +1,71 @@
+## @file=0D
+# This driver installs the EFI_SMM_FIRMWARE_VOLUMEN_PROTOCOL.=0D
+#=0D
+#=0D
+# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=
=0D
+#=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D FvbSmm=0D
+ FILE_GUID =3D A4EC8ADB-B7A8-47d1-8E52-EC820D0ACF6F=
=0D
+ MODULE_TYPE =3D DXE_SMM_DRIVER=0D
+ VERSION_STRING =3D 1.0=0D
+ PI_SPECIFICATION_VERSION =3D 0x0001000A=0D
+ ENTRY_POINT =3D FvbSmmInitialize=0D
+=0D
+[Sources]=0D
+ FvbInfo.c=0D
+ FvbService.h=0D
+ FvbService.c=0D
+ FvbServiceSmm.c=0D
+ FvbSmmCommon.h=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
+ UefiCpuPkg/UefiCpuPkg.dec=0D
+ UefiPayloadPkg/UefiPayloadPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ FlashDeviceLib=0D
+ PcdLib=0D
+ MemoryAllocationLib=0D
+ CacheMaintenanceLib=0D
+ IoLib=0D
+ BaseMemoryLib=0D
+ DebugLib=0D
+ BaseLib=0D
+ UefiLib=0D
+ SmmServicesTableLib=0D
+ UefiBootServicesTableLib=0D
+ UefiDriverEntryPoint=0D
+ HobLib=0D
+ DxeServicesLib=0D
+=0D
+[Guids]=0D
+ gEfiFirmwareFileSystem2Guid # ALWAYS_CONSUMED=0D
+ gEfiSystemNvDataFvGuid # ALWAYS_CONSUMED=0D
+ gEfiAuthenticatedVariableGuid=0D
+ gNvVariableInfoGuid=0D
+=0D
+ [Protocols]=0D
+ gEfiDevicePathProtocolGuid # PROTOCOL ALWAYS_PRODUCED=
=0D
+ gEfiSmmFirmwareVolumeBlockProtocolGuid # PROTOCOL ALWAYS_PRODUCED=
=0D
+=0D
+[Pcd]=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableSize=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingSize=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareSize=0D
+=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageVariableBase64=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwWorkingBase=0D
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFlashNvStorageFtwSpareBase=0D
+ gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile=0D
+=0D
+[Depex]=0D
+ TRUE=0D
diff --git a/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h b/UefiPayloadPkg/F=
vbRuntimeDxe/FvbSmmCommon.h
new file mode 100644
index 0000000000..08577c78db
--- /dev/null
+++ b/UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h
@@ -0,0 +1,69 @@
+/** @file=0D
+ The common header file for SMM FVB module.=0D
+=0D
+Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef _SMM_FVB_COMMON_H_=0D
+#define _SMM_FVB_COMMON_H_=0D
+=0D
+#include <Protocol/SmmFirmwareVolumeBlock.h>=0D
+=0D
+#define EFI_FUNCTION_GET_ATTRIBUTES 1=0D
+#define EFI_FUNCTION_SET_ATTRIBUTES 2=0D
+#define EFI_FUNCTION_GET_PHYSICAL_ADDRESS 3=0D
+#define EFI_FUNCTION_GET_BLOCK_SIZE 4=0D
+#define EFI_FUNCTION_READ 5=0D
+#define EFI_FUNCTION_WRITE 6=0D
+#define EFI_FUNCTION_ERASE_BLOCKS 7=0D
+=0D
+typedef struct {=0D
+ UINTN Function;=0D
+ EFI_STATUS ReturnStatus;=0D
+ UINT8 Data[1];=0D
+} SMM_FVB_COMMUNICATE_FUNCTION_HEADER;=0D
+=0D
+=0D
+///=0D
+/// Size of SMM communicate header, without including the payload.=0D
+///=0D
+#define SMM_COMMUNICATE_HEADER_SIZE (OFFSET_OF (EFI_SMM_COMMUNICATE_HEADE=
R, Data))=0D
+=0D
+///=0D
+/// Size of SMM FVB communicate function header, without including the pay=
load.=0D
+///=0D
+#define SMM_FVB_COMMUNICATE_HEADER_SIZE (OFFSET_OF (SMM_FVB_COMMUNICATE_F=
UNCTION_HEADER, Data))=0D
+=0D
+typedef struct {=0D
+ EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;=0D
+ EFI_FVB_ATTRIBUTES_2 Attributes;=0D
+} SMM_FVB_ATTRIBUTES_HEADER;=0D
+=0D
+typedef struct {=0D
+ EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;=0D
+ EFI_PHYSICAL_ADDRESS Address;=0D
+} SMM_FVB_PHYSICAL_ADDRESS_HEADER;=0D
+=0D
+typedef struct {=0D
+ EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;=0D
+ EFI_LBA Lba;=0D
+ UINTN BlockSize;=0D
+ UINTN NumOfBlocks;=0D
+} SMM_FVB_BLOCK_SIZE_HEADER;=0D
+=0D
+typedef struct {=0D
+ EFI_SMM_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;=0D
+ EFI_LBA Lba;=0D
+ UINTN Offset;=0D
+ UINTN NumBytes;=0D
+} SMM_FVB_READ_WRITE_HEADER;=0D
+=0D
+typedef struct {=0D
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *SmmFvb;=0D
+ EFI_LBA StartLba;=0D
+ UINTN NumOfLba;=0D
+} SMM_FVB_BLOCKS_HEADER;=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h b/UefiPayload=
Pkg/Include/Guid/NvVariableInfoGuid.h
new file mode 100644
index 0000000000..a19ce9b287
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h
@@ -0,0 +1,30 @@
+/** @file=0D
+ This file defines the hob structure for the SPI flash variable info.=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+ This program and the accompanying materials=0D
+ are licensed and made available under the terms and conditions of the BS=
D License=0D
+ which accompanies this distribution. The full text of the license may b=
e found at=0D
+ http://opensource.org/licenses/bsd-license.php.=0D
+=0D
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,=0D
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMP=
LIED.=0D
+=0D
+**/=0D
+=0D
+#ifndef __NV_VARIABLE_INFO_GUID_H__=0D
+#define __NV_VARIABLE_INFO_GUID_H__=0D
+=0D
+//=0D
+// NV variable hob info GUID=0D
+//=0D
+extern EFI_GUID gNvVariableInfoGuid;=0D
+=0D
+typedef struct {=0D
+ UINT8 Revision;=0D
+ UINT8 Reserved[3];=0D
+ UINT32 VariableStoreBase;=0D
+ UINT32 VariableStoreSize;=0D
+} NV_VARIABLE_INFO;=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload=
Pkg.dec
index 2467dc76d6..024c4ed920 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -37,6 +37,8 @@
gUefiSerialPortInfoGuid =3D { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98,=
0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }=0D
gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,=
0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }=0D
=0D
+ # SMM variable support=0D
+ gNvVariableInfoGuid =3D { 0x7a345dca, 0xc26, 0x4f2a, { 0xa8, 0x9a,=
0x57, 0xc0, 0x8d, 0xdd, 0x22, 0xee } }=0D
gSpiFlashInfoGuid =3D { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c,=
0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } }=0D
gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,=
0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }=0D
gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,=
0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } }=0D
@@ -81,3 +83,7 @@ gUefiPayloadPkgTokenSpaceGuid.PcdMemoryTypeEfiRuntimeServ=
icesCode|0x80|UINT32|0x
gUefiPayloadPkgTokenSpaceGuid.PcdSystemMemoryUefiRegionSize|0x02000000|UIN=
T32|0x00000017=0D
=0D
gUefiPayloadPkgTokenSpaceGuid.PcdPcdDriverFile|{ 0x57, 0x72, 0xcf, 0x80, 0=
xab, 0x87, 0xf9, 0x47, 0xa3, 0xfe, 0xD5, 0x0B, 0x76, 0xd8, 0x95, 0x41 }|VOI=
D*|0x00000018=0D
+=0D
+## FFS filename to find the default variable initial data file.=0D
+# @Prompt FFS Name of variable initial data file=0D
+ gUefiPayloadPkgTokenSpaceGuid.PcdNvsDataFile |{ 0x1a, 0xf1, 0xb1, 0xae, 0=
x42, 0xcc, 0xcf, 0x4e, 0xac, 0x60, 0xdb, 0xab, 0xf6, 0xca, 0x69, 0xe6 }|VOI=
D*|0x00000025=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 5/8] UefiPayloadPkg: Add FlashDeviceLib

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

This library provides FlashDeviceLib APIs based on
SpiFlashLib and consumed by FVB driver.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
.../Include/Library/FlashDeviceLib.h | 108 ++++++++++++
.../Library/FlashDeviceLib/FlashDeviceLib.c | 165 ++++++++++++++++++
.../Library/FlashDeviceLib/FlashDeviceLib.inf | 38 ++++
3 files changed, 311 insertions(+)
create mode 100644 UefiPayloadPkg/Include/Library/FlashDeviceLib.h
create mode 100644 UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c
create mode 100644 UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf

diff --git a/UefiPayloadPkg/Include/Library/FlashDeviceLib.h b/UefiPayloadP=
kg/Include/Library/FlashDeviceLib.h
new file mode 100644
index 0000000000..32694b317e
--- /dev/null
+++ b/UefiPayloadPkg/Include/Library/FlashDeviceLib.h
@@ -0,0 +1,108 @@
+/** @file=0D
+ Flash device library class header file.=0D
+=0D
+ Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+=0D
+#ifndef __FLASHDEVICE_LIB_H__=0D
+#define __FLASHDEVICE_LIB_H__=0D
+=0D
+/**=0D
+ Read NumBytes bytes of data from the address specified by=0D
+ PAddress into Buffer.=0D
+=0D
+ @param[in] PAddress The starting physical address of the read.=0D
+ @param[in,out] NumBytes On input, the number of bytes to read. On ou=
tput, the number=0D
+ of bytes actually read.=0D
+ @param[out] Buffer The destination data buffer for the read.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceRead (=0D
+ IN UINTN PAddress,=0D
+ IN OUT UINTN *NumBytes,=0D
+ OUT UINT8 *Buffer=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ Write NumBytes bytes of data from Buffer to the address specified by=0D
+ PAddresss.=0D
+=0D
+ @param[in] PAddress The starting physical address of the write.=0D
+ @param[in,out] NumBytes On input, the number of bytes to write. On outp=
ut,=0D
+ the actual number of bytes written.=0D
+ @param[in] Buffer The source data buffer for the write.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceWrite (=0D
+ IN UINTN PAddress,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ Erase the block staring at PAddress.=0D
+=0D
+ @param[in] PAddress The starting physical address of the region to be e=
rased.=0D
+ @param[in] LbaLength The length of the region to be erased. This para=
meter is necessary=0D
+ as the physical block size on a flash device could =
be different than=0D
+ the logical block size of Firmware Volume Block pro=
tocol. Erase on=0D
+ flash chip is always performed block by block. Ther=
efore, the ERASE=0D
+ operation to a logical block is converted a number =
of ERASE operation=0D
+ (or a partial erase) on the hardware.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceBlockErase (=0D
+ IN UINTN PAddress,=0D
+ IN UINTN LbaLength=0D
+);=0D
+=0D
+=0D
+/**=0D
+ Lock or unlock the block staring at PAddress.=0D
+=0D
+ @param[in] PAddress The starting physical address of region to be (un)l=
ocked.=0D
+ @param[in] LbaLength The length of the region to be (un)locked. This =
parameter is necessary=0D
+ as the physical block size on a flash device could =
be different than=0D
+ the logical block size of Firmware Volume Block pro=
tocol. (Un)Lock on=0D
+ flash chip is always performed block by block. Ther=
efore, the (Un)Lock=0D
+ operation to a logical block is converted a number =
of (Un)Lock operation=0D
+ (or a partial erase) on the hardware.=0D
+ @param[in] Lock TRUE to lock. FALSE to unlock.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceBlockLock (=0D
+ IN UINTN PAddress,=0D
+ IN UINTN LbaLength,=0D
+ IN BOOLEAN Lock=0D
+);=0D
+=0D
+PHYSICAL_ADDRESS=0D
+EFIAPI=0D
+LibFvbFlashDeviceMemoryMap (=0D
+);=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c b/UefiP=
ayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c
new file mode 100644
index 0000000000..efefd53466
--- /dev/null
+++ b/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c
@@ -0,0 +1,165 @@
+/** @file=0D
+ Flash Device Library based on SPI Flash library.=0D
+=0D
+Copyright (c) 2018 - 2021, Intel Corporation. All rights reserved. <BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include <PiDxe.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/SpiFlashLib.h>=0D
+=0D
+/**=0D
+ Initialize spi flash device.=0D
+=0D
+ @retval EFI_SUCCESS The tested spi flash device is supporte=
d.=0D
+ @retval EFI_UNSUPPORTED The tested spi flash device is not supp=
orted.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceInit (=0D
+ VOID=0D
+ )=0D
+{=0D
+ return SpiConstructor ();=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Read NumBytes bytes of data from the address specified by=0D
+ PAddress into Buffer.=0D
+=0D
+ @param[in] PAddress The starting physical address of the read.=
=0D
+ @param[in,out] NumBytes On input, the number of bytes to read. On =
output, the number=0D
+ of bytes actually read.=0D
+ @param[out] Buffer The destination data buffer for the read.=
=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceRead (=0D
+ IN UINTN PAddress,=0D
+ IN OUT UINTN *NumBytes,=0D
+ OUT UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 ByteCount;=0D
+ UINT32 RgnSize;=0D
+ UINT32 AddrOffset;=0D
+=0D
+ Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg=
nSize))=0D
+ // which equal (PAddress + RgnSize) here.=0D
+ AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize);=0D
+ ByteCount =3D (UINT32)*NumBytes;=0D
+ return SpiFlashRead (FlashRegionBios, AddrOffset, ByteCount, Buffer);=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Write NumBytes bytes of data from Buffer to the address specified by=0D
+ PAddresss.=0D
+=0D
+ @param[in] PAddress The starting physical address of the wri=
te.=0D
+ @param[in,out] NumBytes On input, the number of bytes to write. =
On output,=0D
+ the actual number of bytes written.=0D
+ @param[in] Buffer The source data buffer for the write.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceWrite (=0D
+ IN UINTN PAddress,=0D
+ IN OUT UINTN *NumBytes,=0D
+ IN UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 ByteCount;=0D
+ UINT32 RgnSize;=0D
+ UINT32 AddrOffset;=0D
+=0D
+ Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg=
nSize))=0D
+ // which equal (PAddress + RgnSize) here.=0D
+ AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize);=0D
+ ByteCount =3D (UINT32)*NumBytes;=0D
+ return SpiFlashWrite (FlashRegionBios, AddrOffset, ByteCount, Buffer);=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Erase the block staring at PAddress.=0D
+=0D
+ @param[in] PAddress The starting physical address of the block t=
o be erased.=0D
+ This library assume that caller garantee tha=
t the PAddress=0D
+ is at the starting address of this block.=0D
+ @param[in] LbaLength The length of the logical block to be erased=
.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceBlockErase (=0D
+ IN UINTN PAddress,=0D
+ IN UINTN LbaLength=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 RgnSize;=0D
+ UINT32 AddrOffset;=0D
+=0D
+ Status =3D SpiGetRegionAddress (FlashRegionBios, NULL, &RgnSize);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ // BIOS region offset can be calculated by (PAddress - (0x100000000 - Rg=
nSize))=0D
+ // which equal (PAddress + RgnSize) here.=0D
+ AddrOffset =3D (UINT32)((UINT32)PAddress + RgnSize);=0D
+ return SpiFlashErase (FlashRegionBios, AddrOffset, (UINT32)LbaLength);=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Lock or unlock the block staring at PAddress.=0D
+=0D
+ @param[in] PAddress The starting physical address of region to b=
e (un)locked.=0D
+ @param[in] LbaLength The length of the logical block to be erased=
.=0D
+ @param[in] Lock TRUE to lock. FALSE to unlock.=0D
+=0D
+ @retval EFI_SUCCESS. Opertion is successful.=0D
+ @retval EFI_DEVICE_ERROR If there is any device errors.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+LibFvbFlashDeviceBlockLock (=0D
+ IN UINTN PAddress,=0D
+ IN UINTN LbaLength,=0D
+ IN BOOLEAN Lock=0D
+ )=0D
+{=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
diff --git a/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf b/Uef=
iPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf
new file mode 100644
index 0000000000..0ad22cffba
--- /dev/null
+++ b/UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf
@@ -0,0 +1,38 @@
+## @file=0D
+# Library instace of Flash Device Library Class=0D
+#=0D
+# This library implement the flash device library class for the lakeport p=
latform.=0D
+#@copyright=0D
+# Copyright (c) 2014 - 2021 Intel Corporation. All rights reserved=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D FlashDeviceLib=0D
+ FILE_GUID =3D BA7CA537-1C65-4a90-9379-622A24A08141=
=0D
+ MODULE_TYPE =3D DXE_DRIVER=0D
+ VERSION_STRING =3D 1.0=0D
+ LIBRARY_CLASS =3D FlashDeviceLib | DXE_SMM_DRIVER DXE_R=
UNTIME_DRIVER=0D
+=0D
+=0D
+#=0D
+# The following information is for reference only and not required by the =
build tools.=0D
+#=0D
+# VALID_ARCHITECTURES =3D IA32 X64=0D
+#=0D
+=0D
+[Sources]=0D
+ FlashDeviceLib.c=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
+ UefiPayloadPkg/UefiPayloadPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ DebugLib=0D
+ BaseMemoryLib=0D
+ SpiFlashLib=0D
+=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 4/8] UefiPayloadPkg: Add SpiFlashLib

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

This is a common SPI Flash library used for the Intel platform that
supports SPI hardware sequence. This library provides actual SPI flash
operation via Intel PCH SPI controller.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
.../Include/Guid/SpiFlashInfoGuid.h | 38 +
UefiPayloadPkg/Include/Library/SpiFlashLib.h | 215 +++++
UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c | 180 ++++
UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h | 129 +++
.../Library/SpiFlashLib/SpiCommon.h | 208 +++++
.../Library/SpiFlashLib/SpiFlashLib.c | 857 ++++++++++++++++++
.../Library/SpiFlashLib/SpiFlashLib.inf | 47 +
UefiPayloadPkg/UefiPayloadPkg.dec | 1 +
8 files changed, 1675 insertions(+)
create mode 100644 UefiPayloadPkg/Include/Guid/SpiFlashInfoGuid.h
create mode 100644 UefiPayloadPkg/Include/Library/SpiFlashLib.h
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiCommon.h
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf

diff --git a/UefiPayloadPkg/Include/Guid/SpiFlashInfoGuid.h b/UefiPayloadPk=
g/Include/Guid/SpiFlashInfoGuid.h
new file mode 100644
index 0000000000..d073e8aaa8
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/SpiFlashInfoGuid.h
@@ -0,0 +1,38 @@
+/** @file=0D
+ This file defines the hob structure for the SPI flash variable info.=0D
+=0D
+ Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef __SPI_FLASH_INFO_GUID_H__=0D
+#define __SPI_FLASH_INFO_GUID_H__=0D
+=0D
+#include <IndustryStandard/Acpi.h>=0D
+//=0D
+// SPI Flash infor hob GUID=0D
+//=0D
+extern EFI_GUID gSpiFlashInfoGuid;=0D
+=0D
+//=0D
+// Set this bit if platform need disable SMM write protection when writing=
flash=0D
+// in SMM mode using this method: -- AsmWriteMsr32 (0x1FE, MmioRead32 (0x=
FED30880) | BIT0);=0D
+//=0D
+#define FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT BIT0=0D
+=0D
+//=0D
+// Reuse ACPI definition=0D
+//=0D
+typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS;=0D
+#define SPACE_ID_PCI_CONFIGURATION EFI_ACPI_3_0_PCI_CONFIGURA=
TION_SPACE=0D
+#define REGISTER_BIT_WIDTH_DWORD EFI_ACPI_3_0_DWORD=0D
+=0D
+typedef struct {=0D
+ UINT8 Revision;=0D
+ UINT8 Reserved;=0D
+ UINT16 Flags;=0D
+ PLD_GENERIC_ADDRESS SpiAddress;=0D
+} SPI_FLASH_INFO;=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/Include/Library/SpiFlashLib.h b/UefiPayloadPkg/=
Include/Library/SpiFlashLib.h
new file mode 100644
index 0000000000..7c334bf4cb
--- /dev/null
+++ b/UefiPayloadPkg/Include/Library/SpiFlashLib.h
@@ -0,0 +1,215 @@
+/** @file=0D
+ PCH SPI Common Driver implements the SPI Host Controller Compatibility I=
nterface.=0D
+=0D
+ Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef __SPI_FLASH_LIB_H__=0D
+#define __SPI_FLASH_LIB_H__=0D
+=0D
+/**=0D
+ Flash Region Type=0D
+**/=0D
+typedef enum {=0D
+ FlashRegionDescriptor,=0D
+ FlashRegionBios,=0D
+ FlashRegionMe,=0D
+ FlashRegionGbE,=0D
+ FlashRegionPlatformData,=0D
+ FlashRegionDer,=0D
+ FlashRegionAll,=0D
+ FlashRegionMax=0D
+} FLASH_REGION_TYPE;=0D
+=0D
+/**=0D
+ Read SFDP data from the flash part.=0D
+=0D
+ @param[in] ComponentNumber The Component Number for chip select=0D
+ @param[in] ByteCount Number of bytes in SFDP data portion of =
the SPI cycle, the max number is 64=0D
+ @param[out] SfdpData The Pointer to caller-allocated buffer c=
ontaining the SFDP data received=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadSfdp (=0D
+ IN UINT8 ComponentNumber,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *SfdpData=0D
+ );=0D
+=0D
+/**=0D
+ Read Jedec Id from the flash part.=0D
+=0D
+ @param[in] ComponentNumber The Component Number for chip select=0D
+ @param[in] ByteCount Number of bytes in JedecId data portion =
of the SPI cycle, the data size is 3 typically=0D
+ @param[out] JedecId The Pointer to caller-allocated buffer c=
ontaining JEDEC ID received=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadJedecId (=0D
+ IN UINT8 ComponentNumber,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *JedecId=0D
+ );=0D
+=0D
+/**=0D
+ Write the status register in the flash part.=0D
+=0D
+ @param[in] ByteCount Number of bytes in Status data portion o=
f the SPI cycle, the data size is 1 typically=0D
+ @param[in] StatusValue The Pointer to caller-allocated buffer c=
ontaining the value of Status register writing=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashWriteStatus (=0D
+ IN UINT32 ByteCount,=0D
+ IN UINT8 *StatusValue=0D
+ );=0D
+=0D
+/**=0D
+ Read status register in the flash part.=0D
+=0D
+ @param[in] ByteCount Number of bytes in Status data portion o=
f the SPI cycle, the data size is 1 typically=0D
+ @param[out] StatusValue The Pointer to caller-allocated buffer c=
ontaining the value of Status register received.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadStatus (=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *StatusValue=0D
+ );=0D
+=0D
+/**=0D
+ Read SC Soft Strap Values=0D
+=0D
+ @param[in] SoftStrapAddr SC Soft Strap address offset from FPSBA.=
=0D
+ @param[in] ByteCount Number of bytes in SoftStrap data portio=
n of the SPI cycle=0D
+ @param[out] SoftStrapValue The Pointer to caller-allocated buffer c=
ontaining SC Soft Strap Value.=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiReadPchSoftStrap (=0D
+ IN UINT32 SoftStrapAddr,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *SoftStrapValue=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ Read data from the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[out] Buffer The Pointer to caller-allocated buffer c=
ontaining the dada received.=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashRead (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Erase some area on the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashErase (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount=0D
+ );=0D
+=0D
+/**=0D
+ Write data to the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[in] Buffer Pointer to caller-allocated buffer conta=
ining the data sent during the SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashWrite (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ IN UINT8 *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Initialize an SPI library.=0D
+=0D
+ @retval EFI_SUCCESS The protocol instance was properly initi=
alized=0D
+ @exception EFI_UNSUPPORTED The SC is not supported by this module=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiConstructor (=0D
+ VOID=0D
+ );=0D
+=0D
+/**=0D
+ Get the SPI region base and size, based on the enum type=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for for the base a=
ddress which is listed in the Descriptor.=0D
+ @param[out] BaseAddress The Flash Linear Address for the Region =
'n' Base=0D
+ @param[out] RegionSize The size for the Region 'n'=0D
+=0D
+ @retval EFI_SUCCESS Read success=0D
+ @retval EFI_INVALID_PARAMETER Invalid region type given=0D
+ @retval EFI_DEVICE_ERROR The region is not used=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiGetRegionAddress (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ OUT UINT32 *BaseAddress, OPTIONAL=0D
+ OUT UINT32 *RegionSize OPTIONAL=0D
+ );=0D
+=0D
+#endif=0D
+=0D
diff --git a/UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c b/UefiPayloadPkg/L=
ibrary/SpiFlashLib/PchSpi.c
new file mode 100644
index 0000000000..58fb0010d6
--- /dev/null
+++ b/UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c
@@ -0,0 +1,180 @@
+/** @file=0D
+=0D
+ Copyright (c) 2017-2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+#include "SpiCommon.h"=0D
+=0D
+/**=0D
+ Acquire SPI MMIO BAR=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval Return SPI BAR Address=0D
+=0D
+**/=0D
+UINT32=0D
+AcquireSpiBar0 (=0D
+ IN UINTN PchSpiBase=0D
+ )=0D
+{=0D
+ return MmioRead32 (PchSpiBase + R_SPI_BASE) & ~(B_SPI_BAR0_MASK);=0D
+}=0D
+=0D
+/**=0D
+ Release SPI MMIO BAR. Do nothing.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+ReleaseSpiBar0 (=0D
+ IN UINTN PchSpiBase=0D
+ )=0D
+{=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ This function is to enable/disable BIOS Write Protect in SMM phase.=0D
+=0D
+ @param[in] EnableSmmSts Flag to Enable/disable Bios write protect=
=0D
+=0D
+ @retval None=0D
+**/=0D
+VOID=0D
+CpuSmmDisableBiosWriteProtect (=0D
+ IN BOOLEAN EnableSmmSts=0D
+ )=0D
+{=0D
+ UINT32 Data32;=0D
+=0D
+ if(EnableSmmSts){=0D
+ //=0D
+ // Disable BIOS Write Protect in SMM phase.=0D
+ //=0D
+ Data32 =3D MmioRead32 ((UINTN) (0xFED30880)) | (UINT32) (BIT0);=0D
+ AsmWriteMsr32 (0x000001FE, Data32);=0D
+ } else {=0D
+ //=0D
+ // Enable BIOS Write Protect in SMM phase=0D
+ //=0D
+ Data32 =3D MmioRead32 ((UINTN) (0xFED30880)) & (UINT32) (~BIT0);=0D
+ AsmWriteMsr32 (0x000001FE, Data32);=0D
+ }=0D
+=0D
+ //=0D
+ // Read FED30880h back to ensure the setting went through.=0D
+ //=0D
+ Data32 =3D MmioRead32 (0xFED30880);=0D
+}=0D
+=0D
+=0D
+/**=0D
+ This function is a hook for Spi to disable BIOS Write Protect=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote=
ction or not=0D
+=0D
+ @retval EFI_SUCCESS The protocol instance was properly initi=
alized=0D
+ @retval EFI_ACCESS_DENIED The BIOS Region can only be updated in S=
MM phase=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+DisableBiosWriteProtect (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 CpuSmmBwp=0D
+ )=0D
+{=0D
+=0D
+ //=0D
+ // Write clear BC_SYNC_SS prior to change WPD from 0 to 1.=0D
+ //=0D
+ MmioOr8 (PchSpiBase + R_SPI_BCR + 1, (B_SPI_BCR_SYNC_SS >> 8));=0D
+=0D
+ //=0D
+ // Enable the access to the BIOS space for both read and write cycles=0D
+ //=0D
+ MmioOr8 (PchSpiBase + R_SPI_BCR, B_SPI_BCR_BIOSWE);=0D
+=0D
+ if (CpuSmmBwp !=3D 0) {=0D
+ CpuSmmDisableBiosWriteProtect (TRUE);=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This function is a hook for Spi to enable BIOS Write Protect=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote=
ction or not=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+EFIAPI=0D
+EnableBiosWriteProtect (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 CpuSmmBwp=0D
+ )=0D
+{=0D
+=0D
+ //=0D
+ // Disable the access to the BIOS space for write cycles=0D
+ //=0D
+ MmioAnd8 (PchSpiBase + R_SPI_BCR, (UINT8) (~B_SPI_BCR_BIOSWE));=0D
+=0D
+ if (CpuSmmBwp !=3D 0) {=0D
+ CpuSmmDisableBiosWriteProtect (FALSE);=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ This function disables SPI Prefetching and caching,=0D
+ and returns previous BIOS Control Register value before disabling.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval Previous BIOS Control Register value=0D
+=0D
+**/=0D
+UINT8=0D
+SaveAndDisableSpiPrefetchCache (=0D
+ IN UINTN PchSpiBase=0D
+ )=0D
+{=0D
+ UINT8 BiosCtlSave;=0D
+=0D
+ BiosCtlSave =3D MmioRead8 (PchSpiBase + R_SPI_BCR) & B_SPI_BCR_SRC;=0D
+=0D
+ MmioAndThenOr32 (PchSpiBase + R_SPI_BCR, \=0D
+ (UINT32) (~B_SPI_BCR_SRC), \=0D
+ (UINT32) (V_SPI_BCR_SRC_PREF_DIS_CACHE_DIS << B_SPI_BCR_SRC));=0D
+=0D
+ return BiosCtlSave;=0D
+}=0D
+=0D
+/**=0D
+ This function updates BIOS Control Register with the given value.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] BiosCtlValue BIOS Control Register Value to be update=
d=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+SetSpiBiosControlRegister (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 BiosCtlValue=0D
+ )=0D
+{=0D
+ MmioAndThenOr8 (PchSpiBase + R_SPI_BCR, (UINT8) ~B_SPI_BCR_SRC, BiosCtlV=
alue);=0D
+}=0D
diff --git a/UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h b/UefiPayloadPkg/=
Library/SpiFlashLib/RegsSpi.h
new file mode 100644
index 0000000000..c80c9017e7
--- /dev/null
+++ b/UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h
@@ -0,0 +1,129 @@
+/** @file=0D
+ Register names for SPI device.=0D
+=0D
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef _REGS_SPI_H_=0D
+#define _REGS_SPI_H_=0D
+=0D
+#define R_SPI_BASE 0x10 ///< 32-bit Memory =
Base Address Register=0D
+#define B_SPI_BAR0_MASK 0x0FFF=0D
+#define R_SPI_BCR 0xDC ///< BIOS Control =
Register=0D
+#define B_SPI_BCR_SRC (BIT3 | BIT2) ///< SPI Read Confi=
guration (SRC)=0D
+#define V_SPI_BCR_SRC_PREF_DIS_CACHE_DIS 0x04 ///< Prefetch Disab=
le, Cache Disable=0D
+#define B_SPI_BCR_SYNC_SS BIT8=0D
+#define B_SPI_BCR_BIOSWE BIT0 ///< Write Protect =
Disable (WPD)=0D
+=0D
+///=0D
+/// SPI Host Interface Registers=0D
+#define R_SPI_HSFS 0x04 ///< Hardware Seque=
ncing Flash Status and Control Register(32bits)=0D
+#define B_SPI_HSFS_FDBC_MASK 0x3F000000 ///< Flash Data Byt=
e Count ( <=3D 64), Count =3D (Value in this field) + 1.=0D
+#define N_SPI_HSFS_FDBC 24=0D
+#define B_SPI_HSFS_CYCLE_MASK 0x001E0000 ///< Flash Cycle.=0D
+#define N_SPI_HSFS_CYCLE 17=0D
+#define V_SPI_HSFS_CYCLE_READ 0 ///< Flash Cycle Re=
ad=0D
+#define V_SPI_HSFS_CYCLE_WRITE 2 ///< Flash Cycle Wr=
ite=0D
+#define V_SPI_HSFS_CYCLE_4K_ERASE 3 ///< Flash Cycle 4K=
Block Erase=0D
+#define V_SPI_HSFS_CYCLE_64K_ERASE 4 ///< Flash Cycle 64=
K Sector Erase=0D
+#define V_SPI_HSFS_CYCLE_READ_SFDP 5 ///< Flash Cycle Re=
ad SFDP=0D
+#define V_SPI_HSFS_CYCLE_READ_JEDEC_ID 6 ///< Flash Cycle Re=
ad JEDEC ID=0D
+#define V_SPI_HSFS_CYCLE_WRITE_STATUS 7 ///< Flash Cycle Wr=
ite Status=0D
+#define V_SPI_HSFS_CYCLE_READ_STATUS 8 ///< Flash Cycle Re=
ad Status=0D
+#define B_SPI_HSFS_CYCLE_FGO BIT16 ///< Flash Cycle Go=
.=0D
+#define B_SPI_HSFS_FDV BIT14 ///< Flash Descript=
or Valid=0D
+#define B_SPI_HSFS_SCIP BIT5 ///< SPI Cycle in P=
rogress=0D
+#define B_SPI_HSFS_FCERR BIT1 ///< Flash Cycle Er=
ror=0D
+#define B_SPI_HSFS_FDONE BIT0 ///< Flash Cycle Do=
ne=0D
+=0D
+=0D
+#define R_SPI_FADDR 0x08 ///< SPI Flash Address=0D
+#define B_SPI_FADDR_MASK 0x07FFFFFF ///< SPI Flash Address=
Mask (0~26bit)=0D
+=0D
+=0D
+#define R_SPI_FDATA00 0x10 ///< SPI Data 00 (32 bits)=
=0D
+=0D
+#define R_SPI_FRAP 0x50 ///< SPI Flash Regions Acce=
ss Permissions Register=0D
+#define B_SPI_FRAP_BRWA_PLATFORM BIT12 //< Region write access for=
Region4 PlatformData=0D
+#define B_SPI_FRAP_BRWA_GBE BIT11 //< Region write access for=
Region3 GbE=0D
+#define B_SPI_FRAP_BRWA_SEC BIT10 ///< Region Write Access fo=
r Region2 SEC=0D
+#define B_SPI_FRAP_BRWA_BIOS BIT9 ///< Region Write Access fo=
r Region1 BIOS=0D
+#define B_SPI_FRAP_BRWA_FLASHD BIT8 ///< Region Write Access fo=
r Region0 Flash Descriptor=0D
+#define B_SPI_FRAP_BRRA_PLATFORM BIT4 ///< Region read acces=
s for Region4 PlatformData=0D
+#define B_SPI_FRAP_BRRA_GBE BIT3 ///< Region read acces=
s for Region3 GbE=0D
+#define B_SPI_FRAP_BRRA_SEC BIT2 ///< Region Read Acces=
s for Region2 SEC=0D
+#define B_SPI_FRAP_BRRA_BIOS BIT1 ///< Region Read Acces=
s for Region1 BIOS=0D
+#define B_SPI_FRAP_BRRA_FLASHD BIT0 ///< Region Read Acces=
s for Region0 Flash Descriptor=0D
+=0D
+=0D
+#define R_SPI_FREG0_FLASHD 0x54 ///< Flash Region 0 (F=
lash Descriptor) (32bits)=0D
+#define B_SPI_FREG0_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her=
e represents limit[26:12]=0D
+#define N_SPI_FREG0_LIMIT 4 ///< Bit 30:16 identif=
ies address bits [26:12]=0D
+#define B_SPI_FREG0_BASE_MASK 0x00007FFF ///< Base, [14:0] her=
e represents base [26:12]=0D
+#define N_SPI_FREG0_BASE 12 ///< Bit 14:0 identifi=
es address bits [26:2]=0D
+=0D
+#define R_SPI_FREG1_BIOS 0x58 ///< Flash Region 1 (B=
IOS) (32bits)=0D
+#define B_SPI_FREG1_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her=
e represents limit[26:12]=0D
+#define N_SPI_FREG1_LIMIT 4 ///< Bit 30:16 identif=
ies address bits [26:12]=0D
+#define B_SPI_FREG1_BASE_MASK 0x00007FFF ///< Base, [14:0] her=
e represents base [26:12]=0D
+#define N_SPI_FREG1_BASE 12 ///< Bit 14:0 identifi=
es address bits [26:2]=0D
+=0D
+#define R_SPI_FREG2_SEC 0x5C ///< Flash Region 2 (S=
EC) (32bits)=0D
+#define B_SPI_FREG2_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her=
e represents limit[26:12]=0D
+#define N_SPI_FREG2_LIMIT 4 //< Bit 30:16 identifi=
es address bits [26:12]=0D
+#define B_SPI_FREG2_BASE_MASK 0x00007FFF ///< Base, [14:0] her=
e represents base [26:12]=0D
+#define N_SPI_FREG2_BASE 12 //< Bit 14:0 identifie=
s address bits [26:2]=0D
+=0D
+#define R_SPI_FREG3_GBE 0x60 //< Flash Region 3(GbE=
)(32bits)=0D
+#define B_SPI_FREG3_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her=
e represents limit[26:12]=0D
+#define N_SPI_FREG3_LIMIT 4 //< Bit 30:16 identifi=
es address bits [26:12]=0D
+#define B_SPI_FREG3_BASE_MASK 0x00007FFF ///< Base, [14:0] her=
e represents base [26:12]=0D
+#define N_SPI_FREG3_BASE 12 //< Bit 14:0 identifie=
s address bits [26:2]=0D
+=0D
+#define R_SPI_FREG4_PLATFORM_DATA 0x64 ///< Flash Region 4 (P=
latform Data) (32bits)=0D
+#define B_SPI_FREG4_LIMIT_MASK 0x7FFF0000 ///< Size, [30:16] her=
e represents limit[26:12]=0D
+#define N_SPI_FREG4_LIMIT 4 ///< Bit 30:16 identif=
ies address bits [26:12]=0D
+#define B_SPI_FREG4_BASE_MASK 0x00007FFF ///< Base, [14:0] her=
e represents base [26:12]=0D
+#define N_SPI_FREG4_BASE 12 ///< Bit 14:0 identifi=
es address bits [26:2]=0D
+=0D
+=0D
+#define S_SPI_FREGX 4 ///< Size of Flash Reg=
ion register=0D
+#define B_SPI_FREGX_LIMIT_MASK 0x7FFF0000 ///< Flash Region Limi=
t [30:16] represents [26:12], [11:0] are assumed to be FFFh=0D
+#define N_SPI_FREGX_LIMIT 16 ///< Region limit bit =
position=0D
+#define N_SPI_FREGX_LIMIT_REPR 12 ///< Region limit bit =
represents position=0D
+#define B_SPI_FREGX_BASE_MASK 0x00007FFF ///< Flash Region Base=
, [14:0] represents [26:12]=0D
+=0D
+=0D
+#define R_SPI_FDOC 0xB4 ///< Flash Descriptor Obser=
vability Control Register (32 bits)=0D
+#define B_SPI_FDOC_FDSS_MASK (BIT14 | BIT13 | BIT12) ///< Flas=
h Descriptor Section Select=0D
+#define V_SPI_FDOC_FDSS_FSDM 0x0000 ///< Flash Signature and D=
escriptor Map=0D
+#define V_SPI_FDOC_FDSS_COMP 0x1000 ///< Component=0D
+#define B_SPI_FDOC_FDSI_MASK 0x0FFC ///< Flash Descriptor Sect=
ion Index=0D
+=0D
+#define R_SPI_FDOD 0xB8 ///< Flash Descriptor Obser=
vability Data Register (32 bits)=0D
+=0D
+=0D
+#define R_SPI_LVSCC 0xC4 ///<Vendor Specific Compone=
nt Capabilities for Component 0 (32 bits)=0D
+#define B_SPI_LVSCC_EO_64K BIT29 ///<< 64k Erase valid (EO_6=
4k_valid)=0D
+=0D
+#define R_SPI_UVSCC 0xC8 ///< Vendor Specific Compon=
ent Capabilities for Component 1 (32 bits)=0D
+=0D
+=0D
+#define R_SPI_FDBAR_FLASH_MAP0 0x14 ///< Flash MAP 0=0D
+#define N_SPI_FDBAR_NC 8 ///<< Number Of Component=
s=0D
+#define B_SPI_FDBAR_NC 0x00000300 ///< Number Of Compone=
nts=0D
+=0D
+#define R_SPI_FDBAR_FLASH_MAP1 0x18 ///< Flash MAP 1=0D
+#define B_SPI_FDBAR_FPSBA 0x00FF0000 ///< Flash Strap Base =
Address=0D
+=0D
+=0D
+//=0D
+// Flash Component Base Address (FCBA) from Flash Region 0=0D
+//=0D
+#define R_SPI_FCBA_FLCOMP 0x00 ///< Flash Components Regis=
ter=0D
+#define B_SPI_FLCOMP_COMP1_MASK 0x0F ///< Flash Component 1 Dens=
ity=0D
+=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/Library/SpiFlashLib/SpiCommon.h b/UefiPayloadPk=
g/Library/SpiFlashLib/SpiCommon.h
new file mode 100644
index 0000000000..3c673853db
--- /dev/null
+++ b/UefiPayloadPkg/Library/SpiFlashLib/SpiCommon.h
@@ -0,0 +1,208 @@
+/** @file=0D
+ Header file for the SPI flash module.=0D
+=0D
+ Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef _SPI_COMMON_LIB_H_=0D
+#define _SPI_COMMON_LIB_H_=0D
+=0D
+#include <PiDxe.h>=0D
+#include <Uefi/UefiBaseType.h>=0D
+#include <IndustryStandard/Pci30.h>=0D
+#include <Library/IoLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Library/SpiFlashLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Library/HobLib.h>=0D
+#include <Library/TimerLib.h>=0D
+#include <Guid/SpiFlashInfoGuid.h>=0D
+#include "RegsSpi.h"=0D
+=0D
+///=0D
+/// Maximum time allowed while waiting the SPI cycle to complete=0D
+/// Wait Time =3D 6 seconds =3D 6000000 microseconds=0D
+/// Wait Period =3D 10 microseconds=0D
+///=0D
+#define WAIT_TIME 6000000 ///< Wait Time =3D 6 seconds =3D 6000000 m=
icroseconds=0D
+#define WAIT_PERIOD 10 ///< Wait Period =3D 10 microseconds=0D
+=0D
+///=0D
+/// Flash cycle Type=0D
+///=0D
+typedef enum {=0D
+ FlashCycleRead,=0D
+ FlashCycleWrite,=0D
+ FlashCycleErase,=0D
+ FlashCycleReadSfdp,=0D
+ FlashCycleReadJedecId,=0D
+ FlashCycleWriteStatus,=0D
+ FlashCycleReadStatus,=0D
+ FlashCycleMax=0D
+} FLASH_CYCLE_TYPE;=0D
+=0D
+///=0D
+/// Flash Component Number=0D
+///=0D
+typedef enum {=0D
+ FlashComponent0,=0D
+ FlashComponent1,=0D
+ FlashComponentMax=0D
+} FLASH_COMPONENT_NUM;=0D
+=0D
+///=0D
+/// Private data structure definitions for the driver=0D
+///=0D
+#define SC_SPI_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('P', 'S', 'P', 'I')=0D
+=0D
+typedef struct {=0D
+ UINTN Signature;=0D
+ EFI_HANDLE Handle;=0D
+ UINT32 AcpiTmrReg;=0D
+ UINTN PchSpiBase;=0D
+ UINT16 RegionPermission;=0D
+ UINT32 SfdpVscc0Value;=0D
+ UINT32 SfdpVscc1Value;=0D
+ UINT32 StrapBaseAddress;=0D
+ UINT8 NumberOfComponents;=0D
+ UINT16 Flags;=0D
+ UINT32 Component1StartAddr;=0D
+} SPI_INSTANCE;=0D
+=0D
+=0D
+/**=0D
+ Acquire SPI MMIO BAR=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval Return SPI BAR Address=0D
+=0D
+**/=0D
+UINT32=0D
+AcquireSpiBar0 (=0D
+ IN UINTN PchSpiBase=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ Release SPI MMIO BAR. Do nothing.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+ReleaseSpiBar0 (=0D
+ IN UINTN PchSpiBase=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ This function is a hook for Spi to disable BIOS Write Protect=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote=
ction or not=0D
+=0D
+ @retval EFI_SUCCESS The protocol instance was properly initi=
alized=0D
+ @retval EFI_ACCESS_DENIED The BIOS Region can only be updated in S=
MM phase=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+DisableBiosWriteProtect (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 CpuSmmBwp=0D
+ );=0D
+=0D
+/**=0D
+ This function is a hook for Spi to enable BIOS Write Protect=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] CpuSmmBwp Need to disable CPU SMM Bios write prote=
ction or not=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+EFIAPI=0D
+EnableBiosWriteProtect (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 CpuSmmBwp=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ This function disables SPI Prefetching and caching,=0D
+ and returns previous BIOS Control Register value before disabling.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+=0D
+ @retval Previous BIOS Control Register value=0D
+=0D
+**/=0D
+UINT8=0D
+SaveAndDisableSpiPrefetchCache (=0D
+ IN UINTN PchSpiBase=0D
+ );=0D
+=0D
+/**=0D
+ This function updates BIOS Control Register with the given value.=0D
+=0D
+ @param[in] PchSpiBase PCH SPI PCI Base Address=0D
+ @param[in] BiosCtlValue BIOS Control Register Value to be update=
d=0D
+=0D
+ @retval None=0D
+=0D
+**/=0D
+VOID=0D
+SetSpiBiosControlRegister (=0D
+ IN UINTN PchSpiBase,=0D
+ IN UINT8 BiosCtlValue=0D
+ );=0D
+=0D
+=0D
+/**=0D
+ This function sends the programmed SPI command to the slave device.=0D
+=0D
+ @param[in] SpiRegionType The SPI Region type for flash cycle whic=
h is listed in the Descriptor=0D
+ @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (H=
ardware Sequencing Flash Control Register) register=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[in,out] Buffer Pointer to caller-allocated buffer conta=
ining the data received or sent during the SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS SPI command completes successfully.=0D
+ @retval EFI_DEVICE_ERROR Device error, the command aborts abnorma=
lly.=0D
+ @retval EFI_ACCESS_DENIED Some unrecognized command encountered in=
hardware sequencing mode=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+**/=0D
+EFI_STATUS=0D
+SendSpiCmd (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN FLASH_CYCLE_TYPE FlashCycleType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ IN OUT UINT8 *Buffer=0D
+ );=0D
+=0D
+/**=0D
+ Wait execution cycle to complete on the SPI interface.=0D
+=0D
+ @param[in] PchSpiBar0 Spi MMIO base address=0D
+ @param[in] ErrorCheck TRUE if the SpiCycle needs to do the err=
or check=0D
+=0D
+ @retval TRUE SPI cycle completed on the interface.=0D
+ @retval FALSE Time out while waiting the SPI cycle to =
complete.=0D
+ It's not safe to program the next comman=
d on the SPI interface.=0D
+**/=0D
+BOOLEAN=0D
+WaitForSpiCycleComplete (=0D
+ IN UINT32 PchSpiBar0,=0D
+ IN BOOLEAN ErrorCheck=0D
+ );=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c b/UefiPayload=
Pkg/Library/SpiFlashLib/SpiFlashLib.c
new file mode 100644
index 0000000000..11e4d0ea00
--- /dev/null
+++ b/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c
@@ -0,0 +1,857 @@
+/** @file=0D
+ Generic driver using Hardware Sequencing registers.=0D
+=0D
+ Copyright (c) 2017-2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+#include "SpiCommon.h"=0D
+=0D
+SPI_INSTANCE *mSpiInstance =3D NULL;=0D
+=0D
+/**=0D
+ Get SPI Instance from library global data..=0D
+=0D
+ @retval SpiInstance Return SPI instance=0D
+**/=0D
+SPI_INSTANCE *=0D
+GetSpiInstance (=0D
+ VOID=0D
+)=0D
+{=0D
+ if (mSpiInstance =3D=3D NULL) {=0D
+ mSpiInstance =3D AllocatePool (sizeof(SPI_INSTANCE));=0D
+ if (mSpiInstance =3D=3D NULL) {=0D
+ return NULL;=0D
+ }=0D
+ ZeroMem (mSpiInstance, sizeof(SPI_INSTANCE));=0D
+ }=0D
+=0D
+ return mSpiInstance;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Initialize an SPI library.=0D
+=0D
+ @retval EFI_SUCCESS The protocol instance was properly initi=
alized=0D
+ @exception EFI_UNSUPPORTED The SC is not supported by this module=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiConstructor (=0D
+ VOID=0D
+ )=0D
+{=0D
+ UINT32 ScSpiBar0;=0D
+ UINT8 Comp0Density;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+ EFI_HOB_GUID_TYPE *GuidHob;=0D
+ SPI_FLASH_INFO *SpiFlashInfo;=0D
+=0D
+ //=0D
+ // Find SPI flash hob=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gSpiFlashInfoGuid);=0D
+ if (GuidHob =3D=3D NULL) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+ SpiFlashInfo =3D (SPI_FLASH_INFO *) GET_GUID_HOB_DATA (GuidHob);=0D
+=0D
+ //=0D
+ // Initialize the SPI instance=0D
+ //=0D
+ SpiInstance =3D GetSpiInstance ();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+ DEBUG ((DEBUG_INFO, "SpiInstance =3D %08X\n", SpiInstance));=0D
+=0D
+ SpiInstance->Signature =3D SC_SPI_PRIVATE_DATA_SIGNATURE;=0D
+ SpiInstance->Handle =3D NULL;=0D
+=0D
+ //=0D
+ // Check the SPI address=0D
+ //=0D
+ if ((SpiFlashInfo->SpiAddress.AddressSpaceId !=3D EFI_ACPI_3_0_PCI_CONF=
IGURATION_SPACE) ||=0D
+ (SpiFlashInfo->SpiAddress.RegisterBitWidth !=3D 32) ||=0D
+ (SpiFlashInfo->SpiAddress.RegisterBitOffset !=3D 0) ||=0D
+ (SpiFlashInfo->SpiAddress.AccessSize !=3D EFI_ACPI_3_0_DWORD)){=0D
+ DEBUG ((DEBUG_ERROR, "SPI FLASH HOB is not expected. need check the ho=
b or enhance SPI flash driver.\n"));=0D
+ }=0D
+ SpiInstance->PchSpiBase =3D (UINT32)(UINTN)SpiFlashInfo->SpiAddress.Addr=
ess;=0D
+ SpiInstance->Flags =3D SpiFlashInfo->Flags;=0D
+ DEBUG ((DEBUG_INFO, "PchSpiBase at 0x%x\n", SpiInstance->PchSpiBase));=0D
+=0D
+ ScSpiBar0 =3D AcquireSpiBar0 (SpiInstance->PchSpiBase);=0D
+ DEBUG ((DEBUG_INFO, "ScSpiBar0 at 0x%08X\n", ScSpiBar0));=0D
+=0D
+ if (ScSpiBar0 =3D=3D 0) {=0D
+ ASSERT (FALSE);=0D
+ }=0D
+=0D
+ if ((MmioRead32 (ScSpiBar0 + R_SPI_HSFS) & B_SPI_HSFS_FDV) =3D=3D 0) {=0D
+ DEBUG ((DEBUG_ERROR, "SPI Flash descriptor invalid, cannot use Hardwar=
e Sequencing registers!\n"));=0D
+ ASSERT (FALSE);=0D
+ }=0D
+=0D
+ MmioOr32 (SpiInstance->PchSpiBase + PCI_COMMAND_OFFSET, EFI_PCI_COMMAND_=
MEMORY_SPACE);=0D
+ SpiInstance->RegionPermission =3D MmioRead16 (ScSpiBar0 + R_SPI_FRAP);=0D
+ SpiInstance->SfdpVscc0Value =3D MmioRead32 (ScSpiBar0 + R_SPI_LVSCC);=
=0D
+ SpiInstance->SfdpVscc1Value =3D MmioRead32 (ScSpiBar0 + R_SPI_UVSCC);=
=0D
+=0D
+ //=0D
+ // Select to Flash Map 0 Register to get the number of flash Component=0D
+ //=0D
+ MmioAndThenOr32 (=0D
+ ScSpiBar0 + R_SPI_FDOC,=0D
+ (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),=0D
+ (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP0)=0D
+ );=0D
+=0D
+ //=0D
+ // Copy Zero based Number Of Components=0D
+ //=0D
+ SpiInstance->NumberOfComponents =3D (UINT8) ((MmioRead16 (ScSpiBar0 + R_=
SPI_FDOD) & B_SPI_FDBAR_NC) >> N_SPI_FDBAR_NC);=0D
+=0D
+ MmioAndThenOr32 (=0D
+ ScSpiBar0 + R_SPI_FDOC,=0D
+ (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),=0D
+ (UINT32) (V_SPI_FDOC_FDSS_COMP | R_SPI_FCBA_FLCOMP)=0D
+ );=0D
+=0D
+ //=0D
+ // Copy Component 0 Density=0D
+ //=0D
+ Comp0Density =3D (UINT8) MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & B_SPI_FLC=
OMP_COMP1_MASK;=0D
+ SpiInstance->Component1StartAddr =3D (UINT32) (SIZE_512KB << Comp0Densit=
y);=0D
+=0D
+ //=0D
+ // Select FLASH_MAP1 to get Flash SC Strap Base Address=0D
+ //=0D
+ MmioAndThenOr32 (=0D
+ (ScSpiBar0 + R_SPI_FDOC),=0D
+ (UINT32) (~(B_SPI_FDOC_FDSS_MASK | B_SPI_FDOC_FDSI_MASK)),=0D
+ (UINT32) (V_SPI_FDOC_FDSS_FSDM | R_SPI_FDBAR_FLASH_MAP1)=0D
+ );=0D
+=0D
+ SpiInstance->StrapBaseAddress =3D MmioRead32 (ScSpiBar0 + R_SPI_FDOD) & =
B_SPI_FDBAR_FPSBA;=0D
+=0D
+ //=0D
+ // Align FPSBA with address bits for the SC Strap portion of flash descr=
iptor=0D
+ //=0D
+ SpiInstance->StrapBaseAddress &=3D B_SPI_FDBAR_FPSBA;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Read data from the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[out] Buffer The Pointer to caller-allocated buffer c=
ontaining the data received.=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashRead (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D SendSpiCmd (FlashRegionType, FlashCycleRead, Address, ByteCou=
nt, Buffer);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Write data to the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[in] Buffer Pointer to caller-allocated buffer conta=
ining the data sent during the SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashWrite (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ IN UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D SendSpiCmd (FlashRegionType, FlashCycleWrite, Address, ByteCo=
unt, Buffer);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Erase some area on the flash part.=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for flash cycle wh=
ich is listed in the Descriptor.=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashErase (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D SendSpiCmd (FlashRegionType, FlashCycleErase, Address, ByteCo=
unt, NULL);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Read SFDP data from the flash part.=0D
+=0D
+ @param[in] ComponentNumber The Component Number for chip select=0D
+ @param[in] ByteCount Number of bytes in SFDP data portion of =
the SPI cycle, the max number is 64=0D
+ @param[out] SfdpData The Pointer to caller-allocated buffer c=
ontaining the SFDP data received=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadSfdp (=0D
+ IN UINT8 ComponentNumber,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *SfdpData=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 Address;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+=0D
+ SpiInstance =3D GetSpiInstance ();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ if ((ByteCount > 64) || (ComponentNumber > SpiInstance->NumberOfComponen=
ts)) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ Address =3D 0;=0D
+ if (ComponentNumber =3D=3D FlashComponent1) {=0D
+ Address =3D SpiInstance->Component1StartAddr;=0D
+ }=0D
+=0D
+ Status =3D SendSpiCmd (0, FlashCycleReadSfdp, Address, ByteCount, SfdpDa=
ta);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Read Jedec Id from the flash part.=0D
+=0D
+ @param[in] ComponentNumber The Component Number for chip select=0D
+ @param[in] ByteCount Number of bytes in JedecId data portion =
of the SPI cycle, the data size is 3 typically=0D
+ @param[out] JedecId The Pointer to caller-allocated buffer c=
ontaining JEDEC ID received=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadJedecId (=0D
+ IN UINT8 ComponentNumber,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *JedecId=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 Address;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+=0D
+ SpiInstance =3D GetSpiInstance ();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ if (ComponentNumber > SpiInstance->NumberOfComponents) {=0D
+ ASSERT (FALSE);=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ Address =3D 0;=0D
+ if (ComponentNumber =3D=3D FlashComponent1) {=0D
+ Address =3D SpiInstance->Component1StartAddr;=0D
+ }=0D
+=0D
+ Status =3D SendSpiCmd (0, FlashCycleReadJedecId, Address, ByteCount, Jed=
ecId);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Write the status register in the flash part.=0D
+=0D
+ @param[in] ByteCount Number of bytes in Status data portion o=
f the SPI cycle, the data size is 1 typically=0D
+ @param[in] StatusValue The Pointer to caller-allocated buffer c=
ontaining the value of Status register writing=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashWriteStatus (=0D
+ IN UINT32 ByteCount,=0D
+ IN UINT8 *StatusValue=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D SendSpiCmd (0, FlashCycleWriteStatus, 0, ByteCount, StatusVal=
ue);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Read status register in the flash part.=0D
+=0D
+ @param[in] ByteCount Number of bytes in Status data portion o=
f the SPI cycle, the data size is 1 typically=0D
+ @param[out] StatusValue The Pointer to caller-allocated buffer c=
ontaining the value of Status register received.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiFlashReadStatus (=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *StatusValue=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+=0D
+ Status =3D SendSpiCmd (0, FlashCycleReadStatus, 0, ByteCount, StatusValu=
e);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Read SC Soft Strap Values=0D
+=0D
+ @param[in] SoftStrapAddr SC Soft Strap address offset from FPSBA.=
=0D
+ @param[in] ByteCount Number of bytes in SoftStrap data portio=
n of the SPI cycle=0D
+ @param[out] SoftStrapValue The Pointer to caller-allocated buffer c=
ontaining SC Soft Strap Value.=0D
+ It is the caller's responsibility to mak=
e sure Buffer is large enough for the total number of bytes read.=0D
+=0D
+ @retval EFI_SUCCESS Command succeed.=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+ @retval EFI_DEVICE_ERROR Device error, command aborts abnormally.=
=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiReadPchSoftStrap (=0D
+ IN UINT32 SoftStrapAddr,=0D
+ IN UINT32 ByteCount,=0D
+ OUT UINT8 *SoftStrapValue=0D
+ )=0D
+{=0D
+ UINT32 StrapFlashAddr;=0D
+ EFI_STATUS Status;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+=0D
+ SpiInstance =3D GetSpiInstance ();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ ASSERT (SpiInstance->StrapBaseAddress !=3D 0);=0D
+ //=0D
+ // SC Strap Flash Address =3D FPSBA + RamAddr=0D
+ //=0D
+ StrapFlashAddr =3D SpiInstance->StrapBaseAddress + SoftStrapAddr;=0D
+=0D
+ Status =3D SendSpiCmd (FlashRegionDescriptor, FlashCycleRead, StrapFlash=
Addr, ByteCount, SoftStrapValue);=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ This function sends the programmed SPI command to the slave device.=0D
+=0D
+ @param[in] SpiRegionType The SPI Region type for flash cycle whic=
h is listed in the Descriptor=0D
+ @param[in] FlashCycleType The Flash SPI cycle type list in HSFC (H=
ardware Sequencing Flash Control Register) register=0D
+ @param[in] Address The Flash Linear Address must fall withi=
n a region for which BIOS has access permissions.=0D
+ @param[in] ByteCount Number of bytes in the data portion of t=
he SPI cycle.=0D
+ @param[in,out] Buffer Pointer to caller-allocated buffer conta=
ining the data received or sent during the SPI cycle.=0D
+=0D
+ @retval EFI_SUCCESS SPI command completes successfully.=0D
+ @retval EFI_DEVICE_ERROR Device error, the command aborts abnorma=
lly.=0D
+ @retval EFI_ACCESS_DENIED Some unrecognized command encountered in=
hardware sequencing mode=0D
+ @retval EFI_INVALID_PARAMETER The parameters specified are not valid.=
=0D
+**/=0D
+EFI_STATUS=0D
+SendSpiCmd (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ IN FLASH_CYCLE_TYPE FlashCycleType,=0D
+ IN UINT32 Address,=0D
+ IN UINT32 ByteCount,=0D
+ IN OUT UINT8 *Buffer=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINT32 Index;=0D
+ UINTN SpiBaseAddress;=0D
+ UINT32 ScSpiBar0;=0D
+ UINT32 LimitAddress;=0D
+ UINT32 HardwareSpiAddr;=0D
+ UINT16 PermissionBit;=0D
+ UINT32 SpiDataCount;=0D
+ UINT32 FlashCycle;=0D
+ UINT8 BiosCtlSave;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+ UINT32 Data32;=0D
+=0D
+ SpiInstance =3D GetSpiInstance ();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ Status =3D EFI_SUCCESS;=0D
+ SpiBaseAddress =3D SpiInstance->PchSpiBase;=0D
+ ScSpiBar0 =3D AcquireSpiBar0 (SpiBaseAddress);=0D
+ BiosCtlSave =3D 0;=0D
+ SpiInstance->RegionPermission =3D MmioRead16 (ScSpiBar0 + R_SPI_FRAP);=0D
+=0D
+ //=0D
+ // If it's write cycle, disable Prefetching, Caching and disable BIOS Wr=
ite Protect=0D
+ //=0D
+ if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D Fl=
ashCycleErase)) {=0D
+ Status =3D DisableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flag=
s & FLAGS_SPI_DISABLE_SMM_WRITE_PROTECT);=0D
+ if (EFI_ERROR (Status)) {=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+ BiosCtlSave =3D SaveAndDisableSpiPrefetchCache (SpiBaseAddress);=0D
+ }=0D
+=0D
+ //=0D
+ // Make sure it's safe to program the command.=0D
+ //=0D
+ if (!WaitForSpiCycleComplete (ScSpiBar0, FALSE)) {=0D
+ Status =3D EFI_DEVICE_ERROR;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+=0D
+ HardwareSpiAddr =3D Address;=0D
+ if ((FlashCycleType =3D=3D FlashCycleRead) ||=0D
+ (FlashCycleType =3D=3D FlashCycleWrite) ||=0D
+ (FlashCycleType =3D=3D FlashCycleErase)) {=0D
+=0D
+ switch (FlashRegionType) {=0D
+ case FlashRegionDescriptor:=0D
+ if (FlashCycleType =3D=3D FlashCycleRead) {=0D
+ PermissionBit =3D B_SPI_FRAP_BRRA_FLASHD;=0D
+ } else {=0D
+ PermissionBit =3D B_SPI_FRAP_BRWA_FLASHD;=0D
+ }=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD);=0D
+ HardwareSpiAddr +=3D (Data32 & B_SPI_FREG0_BASE_MASK) << N_SPI_FREG0=
_BASE;=0D
+ LimitAddress =3D (Data32 & B_SPI_FREG0_LIMIT_MASK) >> N_SPI_FREG=
0_LIMIT;=0D
+ break;=0D
+=0D
+ case FlashRegionBios:=0D
+ if (FlashCycleType =3D=3D FlashCycleRead) {=0D
+ PermissionBit =3D B_SPI_FRAP_BRRA_BIOS;=0D
+ } else {=0D
+ PermissionBit =3D B_SPI_FRAP_BRWA_BIOS;=0D
+ }=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG1_BIOS);=0D
+ HardwareSpiAddr +=3D (Data32 & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1=
_BASE;=0D
+ LimitAddress =3D (Data32 & B_SPI_FREG1_LIMIT_MASK) >> N_SPI_FREG=
1_LIMIT;=0D
+ break;=0D
+=0D
+ case FlashRegionMe:=0D
+ if (FlashCycleType =3D=3D FlashCycleRead) {=0D
+ PermissionBit =3D B_SPI_FRAP_BRRA_SEC;=0D
+ } else {=0D
+ PermissionBit =3D B_SPI_FRAP_BRWA_SEC;=0D
+ }=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG2_SEC);=0D
+ HardwareSpiAddr +=3D (Data32 & B_SPI_FREG2_BASE_MASK) << N_SPI_FREG2=
_BASE;=0D
+ LimitAddress =3D (Data32 & B_SPI_FREG2_LIMIT_MASK) >> N_SPI_FREG=
2_LIMIT;=0D
+ break;=0D
+=0D
+ case FlashRegionGbE:=0D
+ if (FlashCycleType =3D=3D FlashCycleRead) {=0D
+ PermissionBit =3D B_SPI_FRAP_BRRA_GBE;=0D
+ } else {=0D
+ PermissionBit =3D B_SPI_FRAP_BRWA_GBE;=0D
+ }=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG3_GBE);=0D
+ HardwareSpiAddr +=3D (Data32 & B_SPI_FREG3_BASE_MASK) << N_SPI_FREG3=
_BASE;=0D
+ LimitAddress =3D (Data32 & B_SPI_FREG3_LIMIT_MASK) >> N_SPI_FREG=
3_LIMIT;=0D
+ break;=0D
+=0D
+ case FlashRegionPlatformData:=0D
+ if (FlashCycleType =3D=3D FlashCycleRead) {=0D
+ PermissionBit =3D B_SPI_FRAP_BRRA_PLATFORM;=0D
+ } else {=0D
+ PermissionBit =3D B_SPI_FRAP_BRWA_PLATFORM;=0D
+ }=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG4_PLATFORM_DATA);=0D
+ HardwareSpiAddr +=3D (Data32 & B_SPI_FREG4_BASE_MASK) << N_SPI_FREG4=
_BASE;=0D
+ LimitAddress =3D (Data32 & B_SPI_FREG4_LIMIT_MASK) >> N_SPI_FREG=
4_LIMIT;=0D
+ break;=0D
+=0D
+ case FlashRegionAll:=0D
+ //=0D
+ // FlashRegionAll indicates address is relative to flash device=0D
+ // No error checking for this case=0D
+ //=0D
+ LimitAddress =3D 0;=0D
+ PermissionBit =3D 0;=0D
+ break;=0D
+=0D
+ default:=0D
+ Status =3D EFI_UNSUPPORTED;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+=0D
+ if ((LimitAddress !=3D 0) && (Address > LimitAddress)) {=0D
+ Status =3D EFI_INVALID_PARAMETER;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+=0D
+ //=0D
+ // If the operation is read, but the region attribute is not read allo=
wed, return error.=0D
+ // If the operation is write, but the region attribute is not write al=
lowed, return error.=0D
+ //=0D
+ if ((PermissionBit !=3D 0) && ((SpiInstance->RegionPermission & Permis=
sionBit) =3D=3D 0)) {=0D
+ Status =3D EFI_ACCESS_DENIED;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Check for SC SPI hardware sequencing required commands=0D
+ //=0D
+ FlashCycle =3D 0;=0D
+ switch (FlashCycleType) {=0D
+ case FlashCycleRead:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ << N_SPI_HSFS_CYCLE);=0D
+ break;=0D
+=0D
+ case FlashCycleWrite:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_WRITE << N_SPI_HSFS_CYCLE);=
=0D
+ break;=0D
+=0D
+ case FlashCycleErase:=0D
+ if (((ByteCount % SIZE_4KB) !=3D 0) || ((HardwareSpiAddr % SIZE_4KB) !=
=3D 0)) {=0D
+ DEBUG ((DEBUG_ERROR, "Erase and erase size must be 4KB aligned. \n")=
);=0D
+ ASSERT (FALSE);=0D
+ Status =3D EFI_INVALID_PARAMETER;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+ break;=0D
+=0D
+ case FlashCycleReadSfdp:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_SFDP << N_SPI_HSFS_CYCL=
E);=0D
+ break;=0D
+=0D
+ case FlashCycleReadJedecId:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_JEDEC_ID << N_SPI_HSFS_=
CYCLE);=0D
+ break;=0D
+=0D
+ case FlashCycleWriteStatus:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_WRITE_STATUS << N_SPI_HSFS_C=
YCLE);=0D
+ break;=0D
+=0D
+ case FlashCycleReadStatus:=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_READ_STATUS << N_SPI_HSFS_CY=
CLE);=0D
+ break;=0D
+=0D
+ default:=0D
+ //=0D
+ // Unrecognized Operation=0D
+ //=0D
+ ASSERT (FALSE);=0D
+ Status =3D EFI_INVALID_PARAMETER;=0D
+ goto SendSpiCmdEnd;=0D
+ break;=0D
+ }=0D
+=0D
+ do {=0D
+ SpiDataCount =3D ByteCount;=0D
+ if ((FlashCycleType =3D=3D FlashCycleRead) || (FlashCycleType =3D=3D F=
lashCycleWrite)) {=0D
+ //=0D
+ // Trim at 256 byte boundary per operation,=0D
+ // - SC SPI controller requires trimming at 4KB boundary=0D
+ // - Some SPI chips require trimming at 256 byte boundary for write =
operation=0D
+ // - Trimming has limited performance impact as we can read / write =
at most 64 byte=0D
+ // per operation=0D
+ //=0D
+ if (HardwareSpiAddr + ByteCount > ((HardwareSpiAddr + BIT8) &~(BIT8 =
- 1))) {=0D
+ SpiDataCount =3D (((UINT32) (HardwareSpiAddr) + BIT8) &~(BIT8 - 1)=
) - (UINT32) (HardwareSpiAddr);=0D
+ }=0D
+ //=0D
+ // Calculate the number of bytes to shift in/out during the SPI data=
cycle.=0D
+ // Valid settings for the number of bytes during each data portion o=
f the=0D
+ // SC SPI cycles are: 0, 1, 2, 3, 4, 5, 6, 7, 8, 16, 24, 32, 40, 48,=
56, 64=0D
+ //=0D
+ if (SpiDataCount >=3D 64) {=0D
+ SpiDataCount =3D 64;=0D
+ } else if ((SpiDataCount &~0x07) !=3D 0) {=0D
+ SpiDataCount =3D SpiDataCount &~0x07;=0D
+ }=0D
+ }=0D
+=0D
+ if (FlashCycleType =3D=3D FlashCycleErase) {=0D
+ if (((ByteCount / SIZE_64KB) !=3D 0) &&=0D
+ ((ByteCount % SIZE_64KB) =3D=3D 0) &&=0D
+ ((HardwareSpiAddr % SIZE_64KB) =3D=3D 0)) {=0D
+ if (HardwareSpiAddr < SpiInstance->Component1StartAddr) {=0D
+ //=0D
+ // Check whether Component0 support 64k Erase=0D
+ //=0D
+ if ((SpiInstance->SfdpVscc0Value & B_SPI_LVSCC_EO_64K) !=3D 0) {=
=0D
+ SpiDataCount =3D SIZE_64KB;=0D
+ } else {=0D
+ SpiDataCount =3D SIZE_4KB;=0D
+ }=0D
+ } else {=0D
+ //=0D
+ // Check whether Component1 support 64k Erase=0D
+ //=0D
+ if ((SpiInstance->SfdpVscc1Value & B_SPI_LVSCC_EO_64K) !=3D 0) {=
=0D
+ SpiDataCount =3D SIZE_64KB;=0D
+ } else {=0D
+ SpiDataCount =3D SIZE_4KB;=0D
+ }=0D
+ }=0D
+ } else {=0D
+ SpiDataCount =3D SIZE_4KB;=0D
+ }=0D
+ if (SpiDataCount =3D=3D SIZE_4KB) {=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_4K_ERASE << N_SPI_HSFS_C=
YCLE);=0D
+ } else {=0D
+ FlashCycle =3D (UINT32) (V_SPI_HSFS_CYCLE_64K_ERASE << N_SPI_HSFS_=
CYCLE);=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // If it's write cycle, load data into the SPI data buffer.=0D
+ //=0D
+ if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D =
FlashCycleWriteStatus)) {=0D
+ if ((SpiDataCount & 0x07) !=3D 0) {=0D
+ //=0D
+ // Use Byte write if Data Count is 0, 1, 2, 3, 4, 5, 6, 7=0D
+ //=0D
+ for (Index =3D 0; Index < SpiDataCount; Index++) {=0D
+ MmioWrite8 (ScSpiBar0 + R_SPI_FDATA00 + Index, Buffer[Index]);=0D
+ }=0D
+ } else {=0D
+ //=0D
+ // Use Dword write if Data Count is 8, 16, 24, 32, 40, 48, 56, 64=
=0D
+ //=0D
+ for (Index =3D 0; Index < SpiDataCount; Index +=3D sizeof (UINT32)=
) {=0D
+ MmioWrite32 (ScSpiBar0 + R_SPI_FDATA00 + Index, *(UINT32 *) (Buf=
fer + Index));=0D
+ }=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Set the Flash Address=0D
+ //=0D
+ MmioWrite32 (ScSpiBar0 + R_SPI_FADDR, (UINT32) (HardwareSpiAddr & B_SP=
I_FADDR_MASK));=0D
+=0D
+ //=0D
+ // Set Data count, Flash cycle, and Set Go bit to start a cycle=0D
+ //=0D
+ MmioAndThenOr32 (=0D
+ ScSpiBar0 + R_SPI_HSFS,=0D
+ (UINT32) (~(B_SPI_HSFS_FDBC_MASK | B_SPI_HSFS_CYCLE_MASK)),=0D
+ (UINT32) (((SpiDataCount - 1) << N_SPI_HSFS_FDBC) | FlashCycle | B_S=
PI_HSFS_CYCLE_FGO)=0D
+ );=0D
+=0D
+ //=0D
+ // Wait for command execution complete.=0D
+ //=0D
+ if (!WaitForSpiCycleComplete (ScSpiBar0, TRUE)) {=0D
+ Status =3D EFI_DEVICE_ERROR;=0D
+ goto SendSpiCmdEnd;=0D
+ }=0D
+=0D
+ //=0D
+ // If it's read cycle, load data into the caller's buffer.=0D
+ //=0D
+ if ((FlashCycleType =3D=3D FlashCycleRead) ||=0D
+ (FlashCycleType =3D=3D FlashCycleReadSfdp) ||=0D
+ (FlashCycleType =3D=3D FlashCycleReadJedecId) ||=0D
+ (FlashCycleType =3D=3D FlashCycleReadStatus)) {=0D
+ if ((SpiDataCount & 0x07) !=3D 0) {=0D
+ //=0D
+ // Use Byte read if Data Count is 0, 1, 2, 3, 4, 5, 6, 7=0D
+ //=0D
+ for (Index =3D 0; Index < SpiDataCount; Index++) {=0D
+ Buffer[Index] =3D MmioRead8 (ScSpiBar0 + R_SPI_FDATA00 + Index);=
=0D
+ }=0D
+ } else {=0D
+ //=0D
+ // Use Dword read if Data Count is 8, 16, 24, 32, 40, 48, 56, 64=0D
+ //=0D
+ for (Index =3D 0; Index < SpiDataCount; Index +=3D sizeof (UINT32)=
) {=0D
+ *(UINT32 *) (Buffer + Index) =3D MmioRead32 (ScSpiBar0 + R_SPI_F=
DATA00 + Index);=0D
+ }=0D
+ }=0D
+ }=0D
+=0D
+ HardwareSpiAddr +=3D SpiDataCount;=0D
+ Buffer +=3D SpiDataCount;=0D
+ ByteCount -=3D SpiDataCount;=0D
+ } while (ByteCount > 0);=0D
+=0D
+SendSpiCmdEnd:=0D
+ ///=0D
+ /// Restore the settings for SPI Prefetching and Caching and enable BIOS=
Write Protect=0D
+ ///=0D
+ if ((FlashCycleType =3D=3D FlashCycleWrite) || (FlashCycleType =3D=3D Fl=
ashCycleErase)) {=0D
+ EnableBiosWriteProtect (SpiBaseAddress, mSpiInstance->Flags & FLAGS_S=
PI_DISABLE_SMM_WRITE_PROTECT);=0D
+ SetSpiBiosControlRegister (SpiBaseAddress, BiosCtlSave);=0D
+ }=0D
+=0D
+ ReleaseSpiBar0 (SpiBaseAddress);=0D
+=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ Wait execution cycle to complete on the SPI interface.=0D
+=0D
+ @param[in] ScSpiBar0 Spi MMIO base address=0D
+ @param[in] ErrorCheck TRUE if the SpiCycle needs to do the err=
or check=0D
+=0D
+ @retval TRUE SPI cycle completed on the interface.=0D
+ @retval FALSE Time out while waiting the SPI cycle to =
complete.=0D
+ It's not safe to program the next comman=
d on the SPI interface.=0D
+**/=0D
+BOOLEAN=0D
+WaitForSpiCycleComplete (=0D
+ IN UINT32 ScSpiBar0,=0D
+ IN BOOLEAN ErrorCheck=0D
+ )=0D
+{=0D
+ UINT64 WaitTicks;=0D
+ UINT64 WaitCount;=0D
+ UINT32 Data32;=0D
+=0D
+ //=0D
+ // Convert the wait period allowed into to tick count=0D
+ //=0D
+ WaitCount =3D WAIT_TIME / WAIT_PERIOD;=0D
+ //=0D
+ // Wait for the SPI cycle to complete.=0D
+ //=0D
+ for (WaitTicks =3D 0; WaitTicks < WaitCount; WaitTicks++) {=0D
+ Data32 =3D MmioRead32 (ScSpiBar0 + R_SPI_HSFS);=0D
+ if ((Data32 & B_SPI_HSFS_SCIP) =3D=3D 0) {=0D
+ MmioWrite32 (ScSpiBar0 + R_SPI_HSFS, B_SPI_HSFS_FCERR | B_SPI_HSFS_F=
DONE);=0D
+ if (((Data32 & B_SPI_HSFS_FCERR) !=3D 0) && ErrorCheck) {=0D
+ return FALSE;=0D
+ } else {=0D
+ return TRUE;=0D
+ }=0D
+ }=0D
+ MicroSecondDelay ( WAIT_PERIOD);=0D
+ }=0D
+ return FALSE;=0D
+}=0D
+=0D
+/**=0D
+ Get the SPI region base and size, based on the enum type=0D
+=0D
+ @param[in] FlashRegionType The Flash Region type for for the base a=
ddress which is listed in the Descriptor.=0D
+ @param[out] BaseAddress The Flash Linear Address for the Region =
'n' Base=0D
+ @param[out] RegionSize The size for the Region 'n'=0D
+=0D
+ @retval EFI_SUCCESS Read success=0D
+ @retval EFI_INVALID_PARAMETER Invalid region type given=0D
+ @retval EFI_DEVICE_ERROR The region is not used=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SpiGetRegionAddress (=0D
+ IN FLASH_REGION_TYPE FlashRegionType,=0D
+ OUT UINT32 *BaseAddress, OPTIONAL=0D
+ OUT UINT32 *RegionSize OPTIONAL=0D
+ )=0D
+{=0D
+ UINT32 ScSpiBar0;=0D
+ UINT32 ReadValue;=0D
+ UINT32 Base;=0D
+ SPI_INSTANCE *SpiInstance;=0D
+=0D
+ if (FlashRegionType >=3D FlashRegionMax) {=0D
+ return EFI_INVALID_PARAMETER;=0D
+ }=0D
+=0D
+ SpiInstance =3D GetSpiInstance();=0D
+ if (SpiInstance =3D=3D NULL) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ if (FlashRegionType =3D=3D FlashRegionAll) {=0D
+ if (BaseAddress !=3D NULL) {=0D
+ *BaseAddress =3D 0;=0D
+ }=0D
+ if (RegionSize !=3D NULL) {=0D
+ *RegionSize =3D SpiInstance->Component1StartAddr;=0D
+ }=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ ScSpiBar0 =3D AcquireSpiBar0 (SpiInstance->PchSpiBase);=0D
+ ReadValue =3D MmioRead32 (ScSpiBar0 + R_SPI_FREG0_FLASHD + S_SPI_FREGX *=
(UINT32) FlashRegionType);=0D
+ ReleaseSpiBar0 (SpiInstance->PchSpiBase);=0D
+=0D
+ //=0D
+ // If the region is not used, the Region Base is 7FFFh and Region Limit =
is 0000h=0D
+ //=0D
+ if (ReadValue =3D=3D B_SPI_FREGX_BASE_MASK) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ Base =3D (ReadValue & B_SPI_FREG1_BASE_MASK) << N_SPI_FREG1_BASE;=0D
+ if (BaseAddress !=3D NULL) {=0D
+ *BaseAddress =3D Base;=0D
+ }=0D
+=0D
+ if (RegionSize !=3D NULL) {=0D
+ *RegionSize =3D ((((ReadValue & B_SPI_FREGX_LIMIT_MASK) >> N_SPI_FREG=
X_LIMIT) + 1) <<=0D
+ N_SPI_FREGX_LIMIT_REPR) - Base;=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
diff --git a/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf b/UefiPaylo=
adPkg/Library/SpiFlashLib/SpiFlashLib.inf
new file mode 100644
index 0000000000..7e8ecfda41
--- /dev/null
+++ b/UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf
@@ -0,0 +1,47 @@
+## @file=0D
+#=0D
+# Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=
=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D SpiFlashLib=0D
+ FILE_GUID =3D 6F96AFCB-DE89-4ca1-A63F-8703EE8FDE50=
=0D
+ MODULE_TYPE =3D BASE=0D
+ VERSION_STRING =3D 1.0=0D
+ LIBRARY_CLASS =3D SpiFlashLib=0D
+ CONSTRUCTOR =3D SpiConstructor=0D
+=0D
+#=0D
+# The following information is for reference only and not required by the =
build tools.=0D
+#=0D
+# VALID_ARCHITECTURES =3D IA32 X64=0D
+#=0D
+=0D
+[Sources]=0D
+ RegsSpi.h=0D
+ SpiCommon.h=0D
+ PchSpi.c=0D
+ SpiFlashLib.c=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
+ UefiPayloadPkg/UefiPayloadPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ BaseLib=0D
+ PcdLib=0D
+ IoLib=0D
+ PciLib=0D
+ HobLib=0D
+ TimerLib=0D
+ BaseLib=0D
+=0D
+[Guids]=0D
+ gSpiFlashInfoGuid=0D
+=0D
+[Pcd]=0D
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress=0D
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload=
Pkg.dec
index 417a70f4e8..2467dc76d6 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -37,6 +37,7 @@
gUefiSerialPortInfoGuid =3D { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98,=
0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }=0D
gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,=
0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }=0D
=0D
+ gSpiFlashInfoGuid =3D { 0x2d4aac1b, 0x91a5, 0x4cd5, { 0x9b, 0x5c,=
0xb4, 0x0f, 0x5d, 0x28, 0x51, 0xa1 } }=0D
gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,=
0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }=0D
gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,=
0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } }=0D
=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 3/8] UefiPayloadPkg: Add bootloader SMM support module

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

This module is only used for SMM S3 support for the bootloader that
doesn't support SMM.
The payload would save SMM rebase info to SMM communication area in
normal boot and expect the bootloader in S3 path to rebase the SMM
and trigger SMI by writing 0xB2 port with the given value from SMM
communication area. The payload SMM handler would get chance to
restore some registers in S3 path.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c | 409 ++++++++++++++++++
UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h | 41 ++
UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf | 49 +++
.../Include/Guid/SmmS3CommunicationInfoGuid.h | 54 +++
UefiPayloadPkg/UefiPayloadPkg.dec | 1 +
5 files changed, 554 insertions(+)
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf
create mode 100644 UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h

diff --git a/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c b/UefiPayloadPkg/Bl=
SupportSmm/BlSupportSmm.c
new file mode 100644
index 0000000000..f84494d905
--- /dev/null
+++ b/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c
@@ -0,0 +1,409 @@
+/** @file=0D
+ This driver is used for SMM S3 support for the bootloader that=0D
+ doesn't support SMM.=0D
+ The payload would save SMM rebase info to SMM communication area.=0D
+ The bootloader is expected to rebase the SMM and trigger SMI by=0D
+ writting 0xB2 port with given value from SMM communication area.=0D
+ The paylaod SMM handler got chance to restore regs in S3 path.=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include <BlSupportSmm.h>=0D
+=0D
+PLD_S3_COMMUNICATION mPldS3Hob;=0D
+EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *mSmramHob =3D NULL;=0D
+PLD_SMM_REGISTERS *mSmmRegisterHob =3D NULL;;=0D
+UINT64 mSmmFeatureControl =3D 0;=0D
+=0D
+/**=0D
+ Save SMM rebase and SMI handler information to SMM communication area=0D
+=0D
+ The function detects SMM communication region for boot loader, if it is =
detected, it=0D
+ will save SMM rebase information and S3 SMI handler information to SMM c=
ommunication=0D
+ region. Bootloader should consume these information in S3 path to restor=
e smm base,=0D
+ and write the 0xB2 port to trigger SMI so that payload could resume S3 r=
egisters.=0D
+=0D
+ @param[in] Id Value written to 0xB2 to trigger SMI ha=
ndler.=0D
+=0D
+ @retval EFI_SUCCESS Save reg Value success.=0D
+ @retval EFI_NOT_FOUND RegInfo not populated by=0D
+**/=0D
+EFI_STATUS=0D
+SaveSmmInfoForS3 (=0D
+ IN UINT8 BlSwSmiHandlerInput=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;=0D
+ EFI_MP_SERVICES_PROTOCOL *MpService;=0D
+ CPU_SMMBASE *SmmBaseInfo;=0D
+ PLD_TO_BL_SMM_INFO *PldSmmInfo;=0D
+ UINTN Index;=0D
+=0D
+ PldSmmInfo =3D (PLD_TO_BL_SMM_INFO *)(UINTN)mPldS3Hob.CommBuffer.Physica=
lStart;=0D
+ CopyGuid (&PldSmmInfo->Header.Name, &gS3CommunicationGuid);=0D
+ PldSmmInfo->Header.Header.HobType =3D EFI_HOB_TYPE_GUID_EXTENSION;=0D
+ PldSmmInfo->S3Info.SwSmiTriggerValue =3D BlSwSmiHandlerInput;=0D
+=0D
+ //=0D
+ // Save APIC ID and SMM base=0D
+ //=0D
+ Status =3D gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID =
**)&MpService);=0D
+ if (EFI_ERROR(Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ PldSmmInfo->Header.Header.HobLength =3D (UINT16)(sizeof (PLD_TO_BL_SMM_I=
NFO) + gSmst->NumberOfCpus * sizeof (CPU_SMMBASE));=0D
+ PldSmmInfo->S3Info.CpuCount =3D (UINT32)gSmst->NumberOfCpus;=0D
+ SmmBaseInfo =3D &PldSmmInfo->S3Info.SmmBase[0];=0D
+ for (Index =3D 0; Index < gSmst->NumberOfCpus; Index++) {=0D
+ Status =3D MpService->GetProcessorInfo (MpService, Index, &ProcessorIn=
fo);=0D
+ if (EFI_ERROR(Status)) {=0D
+ return Status;=0D
+ }=0D
+=0D
+ SmmBaseInfo->ApicId =3D (UINT32)(UINTN)ProcessorInfo.ProcessorId;=0D
+ SmmBaseInfo->SmmBase =3D (UINT32)(UINTN)gSmst->CpuSaveState[Index] - S=
MRAM_SAVE_STATE_MAP_OFFSET;=0D
+ DEBUG ((DEBUG_INFO, "CPU%d ID:%02X Base: %08X\n", Index, SmmBaseInfo->=
ApicId, SmmBaseInfo->SmmBase));=0D
+ SmmBaseInfo++;=0D
+ }=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Get specified SMI register based on given register ID=0D
+=0D
+ @param[in] Id The register ID to get.=0D
+=0D
+ @retval NULL The register is not found=0D
+ @return smi register=0D
+=0D
+**/=0D
+PLD_GENERIC_REGISTER *=0D
+GetRegisterById (=0D
+ UINT64 Id=0D
+ )=0D
+{=0D
+ UINT32 Index;=0D
+=0D
+ for (Index =3D 0; Index < mSmmRegisterHob->Count; Index++) {=0D
+ if (mSmmRegisterHob->Registers[Index].Id =3D=3D Id) {=0D
+ return &mSmmRegisterHob->Registers[Index];=0D
+ }=0D
+ }=0D
+ return NULL;=0D
+}=0D
+=0D
+/**=0D
+ Set SMM SMI Global enable lock=0D
+=0D
+**/=0D
+VOID=0D
+LockSmiGlobalEn (=0D
+ VOID=0D
+ )=0D
+{=0D
+ PLD_GENERIC_REGISTER *SmiLockReg;=0D
+=0D
+ DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn .....\n"));=0D
+=0D
+ SmiLockReg =3D GetRegisterById (REGISTER_ID_SMI_GBL_EN_LOCK);=0D
+ if (SmiLockReg =3D=3D NULL) {=0D
+ DEBUG ((DEBUG_ERROR, "SMI global enable lock reg not found.\n"));=0D
+ return;=0D
+ }=0D
+=0D
+ //=0D
+ // Set SMM SMI lock in S3 path=0D
+ //=0D
+ if ((SmiLockReg->Address.AccessSize =3D=3D EFI_ACPI_3_0_DWORD) &&=
=0D
+ (SmiLockReg->Address.Address !=3D 0) &&=0D
+ (SmiLockReg->Address.RegisterBitWidth =3D=3D 1) &&=0D
+ (SmiLockReg->Address.AddressSpaceId =3D=3D EFI_ACPI_3_0_SYSTEM_MEM=
ORY) &&=0D
+ (SmiLockReg->Value =3D=3D 1)) {=0D
+ DEBUG ((DEBUG_ERROR, "LockSmiGlobalEn ....is locked\n"));=0D
+=0D
+ MmioOr32 ((UINT32)SmiLockReg->Address.Address, 1 << SmiLockReg->Addres=
s.RegisterBitOffset);=0D
+ } else {=0D
+ DEBUG ((DEBUG_ERROR, "Unexpected SMM SMI lock register, need enhanceme=
nt here.\n"));=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ Check and set SMM feature lock bit and code check enable bit=0D
+ in S3 path.=0D
+=0D
+**/=0D
+VOID=0D
+SmmFeatureLockOnS3 (=0D
+ VOID=0D
+ )=0D
+{=0D
+=0D
+ if (mSmmFeatureControl !=3D 0) {=0D
+ return;=0D
+ }=0D
+=0D
+ mSmmFeatureControl =3D AsmReadMsr64(MSR_SMM_FEATURE_CONTROL);=0D
+ if ((mSmmFeatureControl & 0x5) !=3D 0x5) {=0D
+ //=0D
+ // Set Lock bit [BIT0] for this register and SMM code check enable bit=
[BIT2]=0D
+ //=0D
+ AsmWriteMsr64 (MSR_SMM_FEATURE_CONTROL, mSmmFeatureControl | 0x5);=0D
+ }=0D
+ mSmmFeatureControl =3D AsmReadMsr64(MSR_SMM_FEATURE_CONTROL);=0D
+}=0D
+=0D
+=0D
+=0D
+/**=0D
+ Function to program SMRR base and mask.=0D
+=0D
+ @param[in] ProcedureArgument Pointer to SMRR_BASE_MASK structure.=0D
+**/=0D
+VOID=0D
+SetSmrr (=0D
+ IN VOID *ProcedureArgument=0D
+ )=0D
+{=0D
+ if (ProcedureArgument !=3D NULL) {=0D
+ AsmWriteMsr64 (MSR_IA32_SMRR_PHYSBASE, ((SMRR_BASE_MASK *)ProcedureArg=
ument)->Base);=0D
+ AsmWriteMsr64 (MSR_IA32_SMRR_PHYSMASK, ((SMRR_BASE_MASK *)ProcedureArg=
ument)->Mask);=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ Set SMRR in S3 path.=0D
+=0D
+**/=0D
+VOID=0D
+SetSmrrOnS3 (=0D
+ VOID=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ SMRR_BASE_MASK Arguments;=0D
+ UINTN Index;=0D
+ UINT32 SmmBase;=0D
+ UINT32 SmmSize;=0D
+=0D
+ if ((AsmReadMsr64 (MSR_IA32_SMRR_PHYSBASE) !=3D 0) && ((AsmReadMsr64 (MS=
R_IA32_SMRR_PHYSMASK) & BIT11) !=3D 0)) {=0D
+ return;=0D
+ }=0D
+=0D
+ SmmBase =3D (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalStart;=0D
+ SmmSize =3D (UINT32)(UINTN)mSmramHob->Descriptor[0].PhysicalSize;=0D
+ if ((mSmramHob->NumberOfSmmReservedRegions > 2) || (mSmramHob->NumberOfS=
mmReservedRegions =3D=3D 0)) {=0D
+ DEBUG ((DEBUG_ERROR, "%d SMM ranges are not supported.\n", mSmramHob->=
NumberOfSmmReservedRegions));=0D
+ return;=0D
+ } else if (mSmramHob->NumberOfSmmReservedRegions =3D=3D 2) {=0D
+ if ((mSmramHob->Descriptor[1].PhysicalStart + mSmramHob->Descriptor[1]=
.PhysicalSize) =3D=3D SmmBase){=0D
+ SmmBase =3D (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalStart;=0D
+ } else if (mSmramHob->Descriptor[1].PhysicalStart =3D=3D (SmmBase + Sm=
mSize)) {=0D
+ DEBUG ((DEBUG_ERROR, "Two SMM regions are not continous.\n"));=0D
+ return;=0D
+ }=0D
+ SmmSize +=3D (UINT32)(UINTN)mSmramHob->Descriptor[1].PhysicalSize;=0D
+ }=0D
+=0D
+ if ((SmmBase =3D=3D 0) || (SmmSize < SIZE_4KB)) {=0D
+ DEBUG ((DEBUG_ERROR, "Invalid SMM range.\n"));=0D
+ return ;=0D
+ }=0D
+=0D
+ //=0D
+ // SMRR size must be of length 2^n=0D
+ // SMRR base alignment cannot be less than SMRR length=0D
+ //=0D
+ if ((SmmSize !=3D GetPowerOfTwo32 (SmmSize)) || ((SmmBase & ~(SmmSize - =
1)) !=3D SmmBase)) {=0D
+ DEBUG ((DEBUG_ERROR, " Invalid SMM range.\n"));=0D
+ return ;=0D
+ }=0D
+=0D
+ //=0D
+ // Calculate smrr base, mask and pass them as arguments.=0D
+ //=0D
+ Arguments.Base =3D (SmmSize | MTRR_CACHE_WRITE_BACK);=0D
+ Arguments.Mask =3D (~(SmmSize - 1) & EFI_MSR_SMRR_MASK);=0D
+=0D
+ //=0D
+ // Set SMRR valid bit=0D
+ //=0D
+ Arguments.Mask |=3D BIT11;=0D
+=0D
+ //=0D
+ // Program smrr base and mask on BSP first and then on APs=0D
+ //=0D
+ SetSmrr(&Arguments);=0D
+ for (Index =3D 0; Index < gSmst->NumberOfCpus; Index++) {=0D
+ if (Index !=3D gSmst->CurrentlyExecutingCpu) {=0D
+ Status =3D gSmst->SmmStartupThisAp (SetSmrr, Index, (VOID *)&Argumen=
ts);=0D
+ if (EFI_ERROR(Status)) {=0D
+ DEBUG ((DEBUG_ERROR, "Programming SMRR on AP# %d status: %r\n", In=
dex, Status));=0D
+ }=0D
+ }=0D
+ }=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Software SMI callback for restoring SMRR base and mask in S3 path.=0D
+=0D
+ @param[in] DispatchHandle The unique handle assigned to this handl=
er by SmiHandlerRegister().=0D
+ @param[in] Context Points to an optional handler context wh=
ich was specified when the=0D
+ handler was registered.=0D
+ @param[in, out] CommBuffer A pointer to a collection of data in mem=
ory that will=0D
+ be conveyed from a non-SMM environment i=
nto an SMM environment.=0D
+ @param[in, out] CommBufferSize The size of the CommBuffer.=0D
+=0D
+ @retval EFI_SUCCESS The interrupt was handled successfully.=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+BlSwSmiHandler (=0D
+ IN EFI_HANDLE DispatchHandle,=0D
+ IN CONST VOID *Context,=0D
+ IN OUT VOID *CommBuffer,=0D
+ IN OUT UINTN *CommBufferSize=0D
+ )=0D
+{=0D
+ SetSmrrOnS3 ();=0D
+ SmmFeatureLockOnS3 ();=0D
+ LockSmiGlobalEn ();=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Lock SMI in this SMM ready to lock event.=0D
+=0D
+ @param Protocol Points to the protocol's unique identifier=0D
+ @param Interface Points to the interface instance=0D
+ @param Handle The handle on which the interface was installed=0D
+=0D
+ @retval EFI_SUCCESS SmmEventCallback runs successfully=0D
+ @retval EFI_NOT_FOUND The Fvb protocol for variable is not found.=0D
+ **/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+BlSupportSmmReadyToLockCallback (=0D
+ IN CONST EFI_GUID *Protocol,=0D
+ IN VOID *Interface,=0D
+ IN EFI_HANDLE Handle=0D
+ )=0D
+{=0D
+ //=0D
+ // Set SMM SMI lock=0D
+ //=0D
+ LockSmiGlobalEn ();=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ The driver's entry point.=0D
+=0D
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.=
=0D
+ @param[in] SystemTable A pointer to the EFI System Table.=0D
+=0D
+ @retval EFI_SUCCESS The entry point is executed successfully.=0D
+ @retval Others Some error occurs when executing this entry poin=
t.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+BlSupportSmm (=0D
+ IN EFI_HANDLE ImageHandle,=0D
+ IN EFI_SYSTEM_TABLE *SystemTable=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_SMM_SW_DISPATCH2_PROTOCOL *SwDispatch;=0D
+ EFI_SMM_SW_REGISTER_CONTEXT SwContext;=0D
+ EFI_HANDLE SwHandle;=0D
+ EFI_HOB_GUID_TYPE *GuidHob;=0D
+ VOID *SmmHob;=0D
+ VOID *Registration;=0D
+=0D
+ //=0D
+ // Get SMM S3 communication hob and save it=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gS3CommunicationGuid);=0D
+ if (GuidHob !=3D NULL) {=0D
+ SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob));=0D
+ CopyMem (&mPldS3Hob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob));=0D
+ } else {=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+=0D
+ if (mPldS3Hob.PldAcpiS3Enable) {=0D
+ // Other drivers will take care of S3.=0D
+ return EFI_SUCCESS;=0D
+ }=0D
+=0D
+ //=0D
+ // Get smram hob and save it=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);=0D
+ if (GuidHob !=3D NULL) {=0D
+ SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob));=0D
+ mSmramHob =3D AllocatePool (GET_GUID_HOB_DATA_SIZE(GuidHob));=0D
+ if (mSmramHob =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ CopyMem (mSmramHob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob));=0D
+ } else {=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+=0D
+ //=0D
+ // Get SMM register hob and save it=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gSmmRegisterInfoGuid);=0D
+ if (GuidHob !=3D NULL) {=0D
+ SmmHob =3D (VOID *) (GET_GUID_HOB_DATA(GuidHob));=0D
+ mSmmRegisterHob =3D AllocatePool (GET_GUID_HOB_DATA_SIZE(GuidHob));=0D
+ if (mSmmRegisterHob =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ CopyMem (mSmmRegisterHob, SmmHob, GET_GUID_HOB_DATA_SIZE(GuidHob));=0D
+ } else {=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+=0D
+ //=0D
+ // Get the Sw dispatch protocol and register SMI handler.=0D
+ //=0D
+ Status =3D gSmst->SmmLocateProtocol (&gEfiSmmSwDispatch2ProtocolGuid, NU=
LL, (VOID**)&SwDispatch);=0D
+ if (EFI_ERROR (Status)) {=0D
+ return Status;=0D
+ }=0D
+ SwContext.SwSmiInputValue =3D (UINTN) -1;=0D
+ Status =3D SwDispatch->Register (SwDispatch, BlSwSmiHandler, &SwContext,=
&SwHandle);=0D
+ if (EFI_ERROR (Status)) {=0D
+ DEBUG ((DEBUG_ERROR, "Registering S3 smi handler failed: %r\n", Status=
));=0D
+ return Status;=0D
+ }=0D
+=0D
+ //=0D
+ // Register SMM ready to lock callback=0D
+ //=0D
+ Status =3D gSmst->SmmRegisterProtocolNotify (=0D
+ &gEfiSmmReadyToLockProtocolGuid,=0D
+ BlSupportSmmReadyToLockCallback,=0D
+ &Registration=0D
+ );=0D
+ ASSERT_EFI_ERROR (Status);=0D
+=0D
+ SaveSmmInfoForS3 ((UINT8)SwContext.SwSmiInputValue);=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
diff --git a/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h b/UefiPayloadPkg/Bl=
SupportSmm/BlSupportSmm.h
new file mode 100644
index 0000000000..ed2b28960c
--- /dev/null
+++ b/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h
@@ -0,0 +1,41 @@
+/** @file=0D
+ The header file of bootloader support SMM.=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+#ifndef _BL_SUPPORT_SMM_H=0D
+#define _BL_SUPPORT_SMM_H=0D
+=0D
+#include <PiDxe.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/IoLib.h>=0D
+#include <Library/HobLib.h>=0D
+#include <Library/MtrrLib.h>=0D
+#include <Library/UefiLib.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/SmmServicesTableLib.h>=0D
+#include <Library/PciLib.h>=0D
+#include <Protocol/SmmSwDispatch2.h>=0D
+#include <Protocol/SmmAccess2.h>=0D
+#include <protocol/MpService.h>=0D
+#include <Library/UefiBootServicesTableLib.h>=0D
+#include <Register/Intel/ArchitecturalMsr.h>=0D
+#include <Guid/SmmRegisterInfoGuid.h>=0D
+#include <Guid/SmmS3CommunicationInfoGuid.h>=0D
+#include <Guid/SmramMemoryReserve.h>=0D
+=0D
+#define EFI_MSR_SMRR_MASK 0xFFFFF000=0D
+#define MSR_SMM_FEATURE_CONTROL 0x4E0=0D
+#define SMRAM_SAVE_STATE_MAP_OFFSET 0xFC00 /// Save state offset from=
SMBASE=0D
+=0D
+typedef struct {=0D
+ UINT32 Base;=0D
+ UINT32 Mask;=0D
+} SMRR_BASE_MASK;=0D
+=0D
+#endif=0D
+=0D
diff --git a/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf b/UefiPayloadPkg/=
BlSupportSmm/BlSupportSmm.inf
new file mode 100644
index 0000000000..75d4777971
--- /dev/null
+++ b/UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf
@@ -0,0 +1,49 @@
+## @file=0D
+# Bootloader Support SMM module=0D
+#=0D
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+#=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D BlSupportSmm=0D
+ FILE_GUID =3D AA292DE7-E11E-42E6-846B-5813A5A8D982=
=0D
+ MODULE_TYPE =3D DXE_SMM_DRIVER=0D
+ PI_SPECIFICATION_VERSION =3D 0x0001000A=0D
+ VERSION_STRING =3D 1.0=0D
+ ENTRY_POINT =3D BlSupportSmm=0D
+=0D
+[Sources]=0D
+ BlSupportSmm.c=0D
+ BlSupportSmm.h=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
+ UefiCpuPkg/UefiCpuPkg.dec=0D
+ UefiPayloadPkg/UefiPayloadPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ UefiDriverEntryPoint=0D
+ UefiBootServicesTableLib=0D
+ SmmServicesTableLib=0D
+ MemoryAllocationLib=0D
+ BaseLib=0D
+ IoLib=0D
+ HobLib=0D
+=0D
+[Guids]=0D
+ gS3CommunicationGuid=0D
+ gEfiSmmSmramMemoryGuid=0D
+ gSmmRegisterInfoGuid=0D
+=0D
+[Protocols]=0D
+ gEfiSmmSwDispatch2ProtocolGuid=0D
+ gEfiMpServiceProtocolGuid=0D
+ gEfiSmmReadyToLockProtocolGuid=0D
+=0D
+[Depex]=0D
+ gEfiSmmSwDispatch2ProtocolGuid=0D
diff --git a/UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h b/Uef=
iPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h
new file mode 100644
index 0000000000..0295ae77d2
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h
@@ -0,0 +1,54 @@
+/** @file=0D
+ This file defines the SMM S3 communication hob structure.=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef __PAYLOAD_S3_COMMUNICATION_GUID_H__=0D
+#define __PAYLOAD_S3_COMMUNICATION_GUID_H__=0D
+=0D
+extern EFI_GUID gS3CommunicationGuid;=0D
+=0D
+#pragma pack(1)=0D
+=0D
+typedef struct {=0D
+ EFI_SMRAM_DESCRIPTOR CommBuffer;=0D
+ BOOLEAN PldAcpiS3Enable;=0D
+} PLD_S3_COMMUNICATION;=0D
+=0D
+///=0D
+/// The information below is used for communication between bootloader and=
payload.=0D
+/// It is used to save/store some registers in S3 path=0D
+///=0D
+/// This region exists only when gEfiAcpiVariableGuid HOB exist.=0D
+/// when PLD_S3_INFO.PldAcpiS3Enable is false, the communication buffer is=
defined as below.=0D
+///=0D
+=0D
+typedef struct {=0D
+ UINT32 ApicId;=0D
+ UINT32 SmmBase;=0D
+} CPU_SMMBASE;=0D
+=0D
+typedef struct {=0D
+ UINT8 SwSmiData;=0D
+ UINT8 SwSmiTriggerValue;=0D
+ UINT16 Reserved;=0D
+ UINT32 CpuCount;=0D
+ CPU_SMMBASE SmmBase[0];=0D
+} SMM_S3_INFO;=0D
+=0D
+//=0D
+// Payload would save this structure to S3 communication area in normal bo=
ot.=0D
+// In S3 path, bootloader need restore SMM base and writie IO port 0xB2 wi=
th SwSmiTriggerValue=0D
+// to trigger SMI to let payload to restore S3.=0D
+//=0D
+typedef struct {=0D
+ EFI_HOB_GUID_TYPE Header;=0D
+ SMM_S3_INFO S3Info;=0D
+} PLD_TO_BL_SMM_INFO;=0D
+=0D
+#pragma pack()=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayload=
Pkg.dec
index 1705f28ec4..417a70f4e8 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -38,6 +38,7 @@
gLoaderMemoryMapInfoGuid =3D { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4,=
0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }=0D
=0D
gSmmRegisterInfoGuid =3D { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9,=
0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }=0D
+ gS3CommunicationGuid =3D { 0x88e31ba1, 0x1856, 0x4b8b, { 0xbb, 0xdf,=
0xf8, 0x16, 0xdd, 0x94, 0xa, 0xef } }=0D
=0D
[Ppis]=0D
gEfiPayLoadHobBasePpiGuid =3D { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6,=
0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} }=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 2/8] UefiPayloadPkg: Add a common SMM control Runtime DXE module

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

This module consumes SMM Registers HOB (SMI_GBL_EN and SMI_APM_EN) to
install SMM control 2 protocol gEfiSmmControl2ProtocolGuid.
The protocol activate() would set SMI_GBL_EN and SMI_APM_EN and trigger
SMI by writing to IO port 0xB3 and 0xB2.

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
.../Include/Guid/SmmRegisterInfoGuid.h | 48 ++++
.../SmmControlRuntimeDxe.c | 252 ++++++++++++++++++
.../SmmControlRuntimeDxe.inf | 50 ++++
UefiPayloadPkg/UefiPayloadPkg.dec | 2 +
4 files changed, 352 insertions(+)
create mode 100644 UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h
create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf

diff --git a/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h b/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h
new file mode 100644
index 0000000000..bf908b24f2
--- /dev/null
+++ b/UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h
@@ -0,0 +1,48 @@
+/** @file
+ This file defines the SMM info hob structure.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef __PAYLOAD_SMM_REGISTER_INFO_GUID_H__
+#define __PAYLOAD_SMM_REGISTER_INFO_GUID_H__
+
+#include <IndustryStandard/Acpi.h>
+
+///
+/// SMM Information GUID
+///
+extern EFI_GUID gSmmRegisterInfoGuid;
+
+///
+/// Reuse ACPI definition
+/// AddressSpaceId(0xC00xFF) is defined by OEM for MSR and other spaces
+///
+typedef EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PLD_GENERIC_ADDRESS;
+
+#define REGISTER_ID_SMI_GBL_EN 1
+#define REGISTER_ID_SMI_GBL_EN_LOCK 2
+#define REGISTER_ID_SMI_EOS 3
+#define REGISTER_ID_SMI_APM_EN 4
+#define REGISTER_ID_SMI_APM_STS 5
+
+#pragma pack(1)
+typedef struct {
+ UINT64 Id;
+ UINT64 Value;
+ PLD_GENERIC_ADDRESS Address;
+} PLD_GENERIC_REGISTER;
+
+typedef struct {
+ UINT16 Revision;
+ UINT16 Reserved;
+ UINT32 Count;
+ PLD_GENERIC_REGISTER Registers[0];
+} PLD_SMM_REGISTERS;
+
+
+#pragma pack()
+
+#endif
diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
new file mode 100644
index 0000000000..1558b17319
--- /dev/null
+++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
@@ -0,0 +1,252 @@
+/** @file
+ This module produces the SMM Control2 Protocol
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/SmmControl2.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Guid/SmmRegisterInfoGuid.h>
+
+#define SMM_DATA_PORT 0xB3
+#define SMM_CONTROL_PORT 0xB2
+
+typedef struct {
+ UINT8 GblBitOffset;
+ UINT8 ApmBitOffset;
+ UINT32 Address;
+} SMM_CONTROL2_REG;
+
+SMM_CONTROL2_REG mSmiCtrlReg;
+
+/**
+ Generates an SMI using the parameters passed in.
+
+ @param This A pointer to an instance of
+ EFI_SMM_CONTROL_PROTOCOL
+ @param ArgumentBuffer The argument buffer
+ @param ArgumentBufferSize The size of the argument buffer
+ @param Periodic TRUE to indicate a periodical SMI
+ @param ActivationInterval Interval of the periodical SMI
+
+ @retval EFI_INVALID_PARAMETER Periodic is TRUE or ArgumentBufferSize > 1
+ @retval EFI_SUCCESS SMI generated
+
+**/
+EFI_STATUS
+EFIAPI
+Activate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN OUT UINT8 *CommandPort OPTIONAL,
+ IN OUT UINT8 *DataPort OPTIONAL,
+ IN BOOLEAN Periodic OPTIONAL,
+ IN EFI_SMM_PERIOD ActivationInterval OPTIONAL
+ )
+{
+ UINT32 SmiEn;
+ UINT32 SmiEnableBits;
+
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SmiEn = IoRead32 (mSmiCtrlReg.Address);
+ SmiEnableBits = (1 << mSmiCtrlReg.GblBitOffset) | (1 << mSmiCtrlReg.ApmBitOffset);
+ if ((SmiEn & SmiEnableBits) != SmiEnableBits) {
+ //
+ // Set the "global SMI enable" bit and APM bit
+ //
+ IoWrite32 (mSmiCtrlReg.Address, SmiEn | SmiEnableBits);
+ }
+
+ IoWrite8 (SMM_DATA_PORT, DataPort == NULL ? 0 : *DataPort);
+ IoWrite8 (SMM_CONTROL_PORT, CommandPort == NULL ? 0 : *CommandPort);
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears an SMI.
+
+ @param This Pointer to an instance of EFI_SMM_CONTROL_PROTOCOL
+ @param Periodic TRUE to indicate a periodical SMI
+
+ @return Return value from SmmClear ()
+
+**/
+EFI_STATUS
+EFIAPI
+Deactivate (
+ IN CONST EFI_SMM_CONTROL2_PROTOCOL *This,
+ IN BOOLEAN Periodic
+ )
+{
+ if (Periodic) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Temporarily do nothing here
+ //
+ return EFI_SUCCESS;
+}
+
+///
+/// SMM COntrol2 Protocol instance
+///
+EFI_SMM_CONTROL2_PROTOCOL mSmmControl2 = {
+ Activate,
+ Deactivate,
+ 0
+};
+
+/**
+ Get specified SMI register based on given register ID
+
+ @param[in] SmmRegister SMI related register array from bootloader
+ @param[in] Id The register ID to get.
+
+ @retval NULL The register is not found or the format is not expected.
+ @return smi register
+
+**/
+PLD_GENERIC_REGISTER *
+GetSmmCtrlRegById (
+ IN PLD_SMM_REGISTERS *SmmRegister,
+ IN UINT32 Id
+ )
+{
+ UINT32 Index;
+ PLD_GENERIC_REGISTER *PldReg;
+
+ PldReg = NULL;
+ for (Index = 0; Index < SmmRegister->Count; Index++) {
+ if (SmmRegister->Registers[Index].Id == Id) {
+ PldReg = &SmmRegister->Registers[Index];
+ break;
+ }
+ }
+
+ if (PldReg == NULL) {
+ DEBUG ((DEBUG_INFO, "Register %d not found.\n", Id));
+ return NULL;
+ }
+
+ //
+ // Checking the register if it is expected.
+ //
+ if ((PldReg->Address.AccessSize != EFI_ACPI_3_0_DWORD) ||
+ (PldReg->Address.Address == 0) ||
+ (PldReg->Address.RegisterBitWidth != 1) ||
+ (PldReg->Address.AddressSpaceId != EFI_ACPI_3_0_SYSTEM_IO) ||
+ (PldReg->Value != 1)) {
+ DEBUG ((DEBUG_INFO, "Unexpected SMM register.\n"));
+ DEBUG ((DEBUG_INFO, "AddressSpaceId= 0x%x\n", PldReg->Address.AddressSpaceId));
+ DEBUG ((DEBUG_INFO, "RegBitWidth = 0x%x\n", PldReg->Address.RegisterBitWidth));
+ DEBUG ((DEBUG_INFO, "RegBitOffset = 0x%x\n", PldReg->Address.RegisterBitOffset));
+ DEBUG ((DEBUG_INFO, "AccessSize = 0x%x\n", PldReg->Address.AccessSize));
+ DEBUG ((DEBUG_INFO, "Address = 0x%lx\n",PldReg->Address.Address ));
+ return NULL;
+ }
+ return PldReg;
+}
+
+
+/**
+ Fixup data pointers so that the services can be called in virtual mode.
+
+ @param[in] Event The event registered.
+ @param[in] Context Event context.
+
+**/
+VOID
+EFIAPI
+SmmControlVirtualAddressChangeEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Trigger));
+ EfiConvertPointer (0x0, (VOID **) &(mSmmControl2.Clear));
+}
+
+
+/**
+ This function installs EFI_SMM_CONTROL2_PROTOCOL.
+
+ @param ImageHandle Handle for the image of this driver
+ @param SystemTable Pointer to the EFI System Table
+
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform
+ @return The status returned from InstallProtocolInterface().
+
+**/
+EFI_STATUS
+EFIAPI
+SmmControlEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ PLD_SMM_REGISTERS *SmmRegister;
+ PLD_GENERIC_REGISTER *SmiGblEnReg;
+ PLD_GENERIC_REGISTER *SmiApmEnReg;
+ EFI_EVENT Event;
+
+ GuidHob = GetFirstGuidHob (&gSmmRegisterInfoGuid);
+ if (GuidHob == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SmmRegister = (PLD_SMM_REGISTERS *) (GET_GUID_HOB_DATA(GuidHob));
+ SmiGblEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_GBL_EN);
+ if (SmiGblEnReg == NULL) {
+ DEBUG ((DEBUG_ERROR, "SMI global enable reg not found.\n"));
+ return EFI_NOT_FOUND;
+ }
+ mSmiCtrlReg.Address = (UINT32)SmiGblEnReg->Address.Address;
+ mSmiCtrlReg.GblBitOffset = SmiGblEnReg->Address.RegisterBitOffset;
+
+ SmiApmEnReg = GetSmmCtrlRegById (SmmRegister, REGISTER_ID_SMI_APM_EN);
+ if (SmiApmEnReg == NULL) {
+ DEBUG ((DEBUG_ERROR, "SMI APM enable reg not found.\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (SmiApmEnReg->Address.Address != mSmiCtrlReg.Address) {
+ DEBUG ((DEBUG_ERROR, "SMI APM EN and SMI GBL EN are expected to have same register base\n"));
+ DEBUG ((DEBUG_ERROR, "APM:0x%x, GBL:0x%x\n", SmiApmEnReg->Address.Address, mSmiCtrlReg.Address));
+ return EFI_UNSUPPORTED;
+ }
+ mSmiCtrlReg.ApmBitOffset = SmiApmEnReg->Address.RegisterBitOffset;
+
+ //
+ // Install our protocol interfaces on the device's handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiSmmControl2ProtocolGuid,
+ &mSmmControl2,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ SmmControlVirtualAddressChangeEvent,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &Event
+ );
+ return Status;
+}
diff --git a/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf
new file mode 100644
index 0000000000..f0c2a4586b
--- /dev/null
+++ b/UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf
@@ -0,0 +1,50 @@
+## @file
+# SMM Control runtime DXE Module
+#
+# Provides the ability to generate a software SMI.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmControlRuntimeDxe
+ FILE_GUID = C3099578-F815-4a96-84A3-FC593760181D
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SmmControlEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmControlRuntimeDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiPayloadPkg/UefiPayloadPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+ UefiRuntimeLib
+ PcdLib
+ IoLib
+ HobLib
+
+[Guids]
+ gSmmRegisterInfoGuid
+ gEfiEventVirtualAddressChangeGuid
+
+[Protocols]
+ gEfiSmmControl2ProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
diff --git a/UefiPayloadPkg/UefiPayloadPkg.dec b/UefiPayloadPkg/UefiPayloadPkg.dec
index 8f0a7e3f95..1705f28ec4 100644
--- a/UefiPayloadPkg/UefiPayloadPkg.dec
+++ b/UefiPayloadPkg/UefiPayloadPkg.dec
@@ -37,6 +37,8 @@
gUefiSerialPortInfoGuid = { 0x6c6872fe, 0x56a9, 0x4403, { 0xbb, 0x98, 0x95, 0x8d, 0x62, 0xde, 0x87, 0xf1 } }
gLoaderMemoryMapInfoGuid = { 0xa1ff7424, 0x7a1a, 0x478e, { 0xa9, 0xe4, 0x92, 0xf3, 0x57, 0xd1, 0x28, 0x32 } }

+ gSmmRegisterInfoGuid = { 0xaa9bd7a7, 0xcafb, 0x4499, { 0xa4, 0xa9, 0xb, 0x34, 0x6b, 0x40, 0xa6, 0x22 } }
+
[Ppis]
gEfiPayLoadHobBasePpiGuid = { 0xdbe23aa1, 0xa342, 0x4b97, {0x85, 0xb6, 0xb2, 0x26, 0xf1, 0x61, 0x73, 0x89} }

--
2.32.0.windows.2


[`edk2-devel][PATCH 1/8] UefiPayloadPkg: Add a common SmmAccessDxe module

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

SmmAccessDxe module would consume EFI_SMRAM_HOB_DESCRIPTOR_BLOCK HOB to
produce SMM access protocol gEfiSmmAccess2ProtocolGuid (open, close, lock,
and GetCapabilities.)

Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c | 254 +++++++++++++++++++
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h | 38 +++
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf | 51 ++++
3 files changed, 343 insertions(+)
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf

diff --git a/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c b/UefiPayloadPkg/Sm=
mAccessDxe/SmmAccessDxe.c
new file mode 100644
index 0000000000..ad75c6a2d9
--- /dev/null
+++ b/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c
@@ -0,0 +1,254 @@
+/** @file=0D
+ This driver publishes the SMM Access 2 Protocol.=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include "SmmAccessDxe.h"=0D
+=0D
+SMM_ACCESS_PRIVATE_DATA mSmmAccess;=0D
+=0D
+/**=0D
+ Update region state from SMRAM description=0D
+=0D
+ @param[in] OrLogic Indicate to use OR if ture or AND if false.=0D
+ @param[in] Value The value to set to region state based on OrLogi=
c.=0D
+=0D
+**/=0D
+VOID=0D
+SyncRegionState2SmramDesc(=0D
+ IN BOOLEAN OrLogic,=0D
+ IN UINT64 Value=0D
+ )=0D
+{=0D
+ UINT32 Index;=0D
+=0D
+ for (Index =3D 0; Index < mSmmAccess.NumberRegions; Index++) {=0D
+ if (OrLogic) {=0D
+ mSmmAccess.SmramDesc[Index].RegionState |=3D Value;=0D
+ } else {=0D
+ mSmmAccess.SmramDesc[Index].RegionState &=3D Value;=0D
+ }=0D
+ }=0D
+}=0D
+=0D
+/**=0D
+ This routine accepts a request to "open" a region of SMRAM. The=0D
+ region could be legacy ABSEG, HSEG, or TSEG near top of physical memory=
.=0D
+ The use of "open" means that the memory is visible from all boot-servic=
e=0D
+ and SMM agents.=0D
+=0D
+ @param This Pointer to the SMM Access Interface.=0D
+=0D
+ @retval EFI_SUCCESS The region was successfully opened.=0D
+ @retval EFI_DEVICE_ERROR The region could not be opened because l=
ocked by chipset.=0D
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Open (=0D
+ IN EFI_SMM_ACCESS2_PROTOCOL *This=0D
+ )=0D
+{=0D
+ if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) !=3D 0) {=0D
+ //=0D
+ // Cannot open a "locked" region=0D
+ //=0D
+ DEBUG ((DEBUG_INFO, "Cannot open the locked SMRAM Region\n"));=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ mSmmAccess.SmmRegionState &=3D ~(EFI_SMRAM_CLOSED | EFI_ALLOCATED);=0D
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~(EFI_SMRAM_CLOSED | EF=
I_ALLOCATED)));=0D
+=0D
+ mSmmAccess.SmmRegionState |=3D EFI_SMRAM_OPEN;=0D
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_OPEN);=0D
+ mSmmAccess.SmmAccess.OpenState =3D TRUE;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This routine accepts a request to "close" a region of SMRAM. The region=
=0D
+ could be legacy AB or TSEG near top of physical memory.=0D
+ The use of "close" means that the memory is only visible from SMM agent=
s,=0D
+ not from BS or RT code.=0D
+=0D
+ @param This Pointer to the SMM Access Interface.=0D
+=0D
+ @retval EFI_SUCCESS The region was successfully closed.=0D
+ @retval EFI_DEVICE_ERROR The region could not be closed because=
locked by=0D
+ chipset.=0D
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds=
.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Close (=0D
+ IN EFI_SMM_ACCESS2_PROTOCOL *This=0D
+ )=0D
+{=0D
+ if ((mSmmAccess.SmmRegionState & EFI_SMRAM_LOCKED) !=3D 0) {=0D
+ //=0D
+ // Cannot close a "locked" region=0D
+ //=0D
+ DEBUG ((DEBUG_INFO, "Cannot close the locked SMRAM Region\n"));=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ if ((mSmmAccess.SmmRegionState & EFI_SMRAM_CLOSED) !=3D 0) {=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ mSmmAccess.SmmRegionState &=3D ~EFI_SMRAM_OPEN;=0D
+ SyncRegionState2SmramDesc(FALSE, (UINT64)(UINTN)(~EFI_SMRAM_OPEN));=0D
+=0D
+ mSmmAccess.SmmRegionState |=3D (EFI_SMRAM_CLOSED | EFI_ALLOCATED);=0D
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_CLOSED | EFI_ALLOCATED);=0D
+=0D
+ mSmmAccess.SmmAccess.OpenState =3D FALSE;=0D
+=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This routine accepts a request to "lock" SMRAM. The=0D
+ region could be legacy AB or TSEG near top of physical memory.=0D
+ The use of "lock" means that the memory can no longer be opened=0D
+ to BS state.=0D
+=0D
+ @param This Pointer to the SMM Access Interface.=0D
+=0D
+ @retval EFI_SUCCESS The region was successfully locked.=0D
+ @retval EFI_DEVICE_ERROR The region could not be locked because =
at least=0D
+ one range is still open.=0D
+ @retval EFI_INVALID_PARAMETER The descriptor index was out of bounds.=
=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+Lock (=0D
+ IN EFI_SMM_ACCESS2_PROTOCOL *This=0D
+ )=0D
+{=0D
+ if (mSmmAccess.SmmAccess.OpenState) {=0D
+ DEBUG ((DEBUG_INFO, "Cannot lock SMRAM when it is still open\n"));=0D
+ return EFI_DEVICE_ERROR;=0D
+ }=0D
+=0D
+ mSmmAccess.SmmRegionState |=3D EFI_SMRAM_LOCKED;=0D
+ SyncRegionState2SmramDesc(TRUE, EFI_SMRAM_LOCKED);=0D
+ mSmmAccess.SmmAccess.LockState =3D TRUE;=0D
+ return EFI_SUCCESS;=0D
+}=0D
+=0D
+/**=0D
+ This routine services a user request to discover the SMRAM=0D
+ capabilities of this platform. This will report the possible=0D
+ ranges that are possible for SMRAM access, based upon the=0D
+ memory controller capabilities.=0D
+=0D
+ @param This Pointer to the SMRAM Access Interface.=0D
+ @param SmramMapSize Pointer to the variable containing size of the=0D
+ buffer to contain the description information.=0D
+ @param SmramMap Buffer containing the data describing the Smram=
=0D
+ region descriptors.=0D
+=0D
+ @retval EFI_BUFFER_TOO_SMALL The user did not provide a sufficient buf=
fer.=0D
+ @retval EFI_SUCCESS The user provided a sufficiently-sized bu=
ffer.=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+GetCapabilities (=0D
+ IN CONST EFI_SMM_ACCESS2_PROTOCOL *This,=0D
+ IN OUT UINTN *SmramMapSize,=0D
+ IN OUT EFI_SMRAM_DESCRIPTOR *SmramMap=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ UINTN NecessaryBufferSize;=0D
+=0D
+ NecessaryBufferSize =3D mSmmAccess.NumberRegions * sizeof(EFI_SMRAM_DESC=
RIPTOR);=0D
+ if (*SmramMapSize < NecessaryBufferSize) {=0D
+ Status =3D EFI_BUFFER_TOO_SMALL;=0D
+ } else {=0D
+ CopyMem(SmramMap, mSmmAccess.SmramDesc, NecessaryBufferSize);=0D
+ Status =3D EFI_SUCCESS;=0D
+ }=0D
+=0D
+ *SmramMapSize =3D NecessaryBufferSize;=0D
+ return Status;=0D
+}=0D
+=0D
+/**=0D
+ This function installs EFI_SMM_ACCESS_PROTOCOL.=0D
+=0D
+ @param ImageHandle Handle for the image of this driver=0D
+ @param SystemTable Pointer to the EFI System Table=0D
+=0D
+ @retval EFI_UNSUPPORTED There's no Intel ICH on this platform=0D
+ @return The status returned from InstallProtocolInterface().=0D
+=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+SmmAccessEntryPoint (=0D
+ IN EFI_HANDLE ImageHandle,=0D
+ IN EFI_SYSTEM_TABLE *SystemTable=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ EFI_HOB_GUID_TYPE *GuidHob;=0D
+ UINT32 SmmRegionNum;=0D
+ EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *SmramHob;=0D
+ UINT32 Index;=0D
+=0D
+ //=0D
+ // Get SMRAM info HOB=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob (&gEfiSmmSmramMemoryGuid);=0D
+ if (GuidHob =3D=3D NULL) {=0D
+ DEBUG ((DEBUG_INFO, "SMRAM HOB NOT found\n"));=0D
+ return EFI_NOT_FOUND;=0D
+ }=0D
+ SmramHob =3D (EFI_SMRAM_HOB_DESCRIPTOR_BLOCK *) GET_GUID_HOB_DATA(Gu=
idHob);=0D
+ SmmRegionNum =3D SmramHob->NumberOfSmmReservedRegions;=0D
+ mSmmAccess.SmramDesc =3D AllocateZeroPool (sizeof (EFI_SMRAM_DESCRIPTOR)=
* SmmRegionNum);=0D
+ if (mSmmAccess.SmramDesc =3D=3D NULL) {=0D
+ return EFI_OUT_OF_RESOURCES;=0D
+ }=0D
+ CopyMem (mSmmAccess.SmramDesc, &SmramHob->Descriptor, sizeof (EFI_SMRAM_=
DESCRIPTOR) * SmmRegionNum);=0D
+=0D
+ DEBUG ((DEBUG_INFO, "NumberOfSmmReservedRegions =3D 0x%x\n", SmmRegionNu=
m));=0D
+ for (Index =3D 0; Index < SmmRegionNum; Index++) {=0D
+ DEBUG ((DEBUG_INFO, "%d: base=3D0x%x, size =3D 0x%x, State=3D0x%x\n",I=
ndex,=0D
+ SmramHob->Descriptor[Index].PhysicalStart,=0D
+ SmramHob->Descriptor[Index].PhysicalSize,=0D
+ SmramHob->Descriptor[Index].RegionState));=0D
+ mSmmAccess.SmramDesc[Index].RegionState &=3D EFI_ALLOCATED;=0D
+ mSmmAccess.SmramDesc[Index].RegionState |=3D EFI_SMRAM_CLOSED | EFI_C=
ACHEABLE;=0D
+ }=0D
+=0D
+ mSmmAccess.Signature =3D SMM_ACCESS_PRIVATE_DATA_SIGN=
ATURE;=0D
+ mSmmAccess.NumberRegions =3D SmmRegionNum;=0D
+ mSmmAccess.SmmAccess.Open =3D Open;=0D
+ mSmmAccess.SmmAccess.Close =3D Close;=0D
+ mSmmAccess.SmmAccess.Lock =3D Lock;=0D
+ mSmmAccess.SmmAccess.GetCapabilities =3D GetCapabilities;=0D
+ mSmmAccess.SmmAccess.LockState =3D FALSE;=0D
+ mSmmAccess.SmmAccess.OpenState =3D FALSE;=0D
+ mSmmAccess.SmmRegionState =3D EFI_SMRAM_CLOSED;=0D
+=0D
+ Status =3D gBS->InstallMultipleProtocolInterfaces (=0D
+ &mSmmAccess.Handle,=0D
+ &gEfiSmmAccess2ProtocolGuid,=0D
+ &mSmmAccess.SmmAccess,=0D
+ NULL=0D
+ );=0D
+=0D
+ return Status;=0D
+}=0D
diff --git a/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h b/UefiPayloadPkg/Sm=
mAccessDxe/SmmAccessDxe.h
new file mode 100644
index 0000000000..7b64c0afcb
--- /dev/null
+++ b/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h
@@ -0,0 +1,38 @@
+/** @file=0D
+ The header file of SMM access DXE.=0D
+=0D
+Copyright (c) 2014 - 2021, Intel Corporation. All rights reserved.<BR>=0D
+SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#ifndef _SMM_ACCESS_DRIVER_H=0D
+#define _SMM_ACCESS_DRIVER_H=0D
+=0D
+#include <PiDxe.h>=0D
+#include <Protocol/SmmAccess2.h>=0D
+//#include <Protocol/SmmControl2.h>=0D
+#include <Library/HobLib.h>=0D
+#include <Library/BaseLib.h>=0D
+#include <Library/UefiBootServicesTableLib.h>=0D
+#include <Library/DebugLib.h>=0D
+#include <Library/MemoryAllocationLib.h>=0D
+#include <Library/BaseMemoryLib.h>=0D
+#include <Guid/SmramMemoryReserve.h>=0D
+=0D
+=0D
+#define SMM_ACCESS_PRIVATE_DATA_SIGNATURE SIGNATURE_32 ('S', 'M', 'M', '=
A')=0D
+=0D
+typedef struct {=0D
+ UINTN Signature;=0D
+ EFI_HANDLE Handle;=0D
+ EFI_SMM_ACCESS2_PROTOCOL SmmAccess;=0D
+ //=0D
+ // Local Data for SMM Access interface goes here=0D
+ //=0D
+ UINT32 SmmRegionState;=0D
+ UINT32 NumberRegions;=0D
+ EFI_SMRAM_DESCRIPTOR *SmramDesc;=0D
+} SMM_ACCESS_PRIVATE_DATA;=0D
+=0D
+#endif=0D
diff --git a/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf b/UefiPayloadPkg/=
SmmAccessDxe/SmmAccessDxe.inf
new file mode 100644
index 0000000000..aac5ee8f28
--- /dev/null
+++ b/UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf
@@ -0,0 +1,51 @@
+## @file=0D
+# SMM Access 2 Protocol Dxe Driver=0D
+#=0D
+# This module produces the SMM Access 2 Protocol.=0D
+#=0D
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+#=0D
+# SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+#=0D
+##=0D
+=0D
+[Defines]=0D
+ INF_VERSION =3D 0x00010005=0D
+ BASE_NAME =3D SmmAccessDxe=0D
+ FILE_GUID =3D 47579CF5-1E4F-4b41-99BB-A5C334846D3B=
=0D
+ MODULE_TYPE =3D DXE_DRIVER=0D
+ VERSION_STRING =3D 1.0=0D
+ ENTRY_POINT =3D SmmAccessEntryPoint=0D
+=0D
+#=0D
+# The following information is for reference only and not required by the =
build tools.=0D
+#=0D
+# VALID_ARCHITECTURES =3D IA32 X64=0D
+#=0D
+=0D
+[Sources]=0D
+ SmmAccessDxe.c=0D
+ SmmAccessDxe.h=0D
+=0D
+[Packages]=0D
+ MdePkg/MdePkg.dec=0D
+ MdeModulePkg/MdeModulePkg.dec=0D
+ UefiPayloadPkg/UefiPayloadPkg.dec=0D
+=0D
+[LibraryClasses]=0D
+ UefiDriverEntryPoint=0D
+ UefiBootServicesTableLib=0D
+ DebugLib=0D
+ BaseLib=0D
+ BaseMemoryLib=0D
+ MemoryAllocationLib=0D
+ HobLib=0D
+=0D
+[Guids]=0D
+ gEfiSmmSmramMemoryGuid=0D
+=0D
+[Protocols]=0D
+ gEfiSmmAccess2ProtocolGuid ## PRODUCES=0D
+=0D
+[Depex]=0D
+ TRUE=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH 0/8] Add SMM variable support for UEFI payload

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

https://bugzilla.tianocore.org/show_bug.cgi?id=3084

Currently UEFI payload uses emulated variable driver. So it could
not support secureboot and measured boot since both need NV variable
support.

EDKII already has SMM modules and variable modules. And modern Intel
platform supports SPI flash hardware sequence to operate flash. So it
is possible to have a common SPI module for Intel platforms.

This patch enhances UEFI payload to support SMM variable with a
common SPI library for Intel platforms. To avoid impact existing
usage, all the new modules are included under SMM_ENABLE and
VARIABLE_SUPPORT and by default SMM variable is not be enabled.

SMM variable could be enabled only when UNIVERSAL_PAYLOAD is set
since non-universal payload need update ParseLib to provide SMM
variable related infromation which is not in the plan.

Signed-off-by: Guo Dong <guo.dong@intel.com>

Guo Dong (8):
UefiPayloadPkg: Add a common SmmAccessDxe module
UefiPayloadPkg: Add a common SMM control Runtime DXE module
UefiPayloadPkg: Add bootloader SMM support module
UefiPayloadPkg: Add SpiFlashLib
UefiPayloadPkg: Add FlashDeviceLib
UefiPayloadPkg: Add a common FVB SMM module
UefiPayloadPkg: Add a SMM dispatch module
UefiPayloadPkg: Add SMM support and SMM variable support

UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c | 409 +++++++
UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h | 41 +
UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf | 49 +
UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c | 143 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbService.c | 1085 +++++++++++++++++
UefiPayloadPkg/FvbRuntimeDxe/FvbService.h | 187 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c | 139 +++
UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf | 71 ++
UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h | 69 ++
.../Include/Guid/NvVariableInfoGuid.h | 30 +
.../Include/Guid/SmmRegisterInfoGuid.h | 48 +
.../Include/Guid/SmmS3CommunicationInfoGuid.h | 54 +
.../Include/Guid/SpiFlashInfoGuid.h | 38 +
.../Include/Library/FlashDeviceLib.h | 108 ++
UefiPayloadPkg/Include/Library/SpiFlashLib.h | 215 ++++
.../Library/FlashDeviceLib/FlashDeviceLib.c | 165 +++
.../Library/FlashDeviceLib/FlashDeviceLib.inf | 38 +
UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c | 180 +++
UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h | 129 ++
.../Library/SpiFlashLib/SpiCommon.h | 208 ++++
.../Library/SpiFlashLib/SpiFlashLib.c | 857 +++++++++++++
.../Library/SpiFlashLib/SpiFlashLib.inf | 47 +
.../PchSmiDispatchSmm/PchSmiDispatchSmm.c | 455 +++++++
.../PchSmiDispatchSmm/PchSmiDispatchSmm.h | 39 +
.../PchSmiDispatchSmm/PchSmiDispatchSmm.inf | 51 +
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c | 254 ++++
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h | 38 +
UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf | 51 +
.../SmmControlRuntimeDxe.c | 252 ++++
.../SmmControlRuntimeDxe.inf | 50 +
UefiPayloadPkg/UefiPayloadPkg.dec | 10 +
UefiPayloadPkg/UefiPayloadPkg.dsc | 101 +-
UefiPayloadPkg/UefiPayloadPkg.fdf | 38 +-
33 files changed, 5638 insertions(+), 11 deletions(-)
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.c
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.h
create mode 100644 UefiPayloadPkg/BlSupportSmm/BlSupportSmm.inf
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbInfo.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbService.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbService.h
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbServiceSmm.c
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbSmm.inf
create mode 100644 UefiPayloadPkg/FvbRuntimeDxe/FvbSmmCommon.h
create mode 100644 UefiPayloadPkg/Include/Guid/NvVariableInfoGuid.h
create mode 100644 UefiPayloadPkg/Include/Guid/SmmRegisterInfoGuid.h
create mode 100644 UefiPayloadPkg/Include/Guid/SmmS3CommunicationInfoGuid.h
create mode 100644 UefiPayloadPkg/Include/Guid/SpiFlashInfoGuid.h
create mode 100644 UefiPayloadPkg/Include/Library/FlashDeviceLib.h
create mode 100644 UefiPayloadPkg/Include/Library/SpiFlashLib.h
create mode 100644 UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.c
create mode 100644 UefiPayloadPkg/Library/FlashDeviceLib/FlashDeviceLib.inf
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/PchSpi.c
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/RegsSpi.h
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiCommon.h
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.c
create mode 100644 UefiPayloadPkg/Library/SpiFlashLib/SpiFlashLib.inf
create mode 100644 UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.c
create mode 100644 UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.h
create mode 100644 UefiPayloadPkg/PchSmiDispatchSmm/PchSmiDispatchSmm.inf
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.c
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.h
create mode 100644 UefiPayloadPkg/SmmAccessDxe/SmmAccessDxe.inf
create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.c
create mode 100644 UefiPayloadPkg/SmmControlRuntimeDxe/SmmControlRuntimeDxe.inf

--
2.32.0.windows.2


Re: [`edk2-devel][PATCH] UefiPayloadPkg: Add ".upld_info" in universal payload

Andrew Fish
 



On Sep 24, 2021, at 8:57 PM, Guo Dong <guo.dong@...> wrote:

From: Guo Dong <guo.dong@...>

From the universal scalable firmware payload requirement V0.75,
Payload must have Universal Payload Information Section ".upld_info"
So update the build tool to add this section.

Cc: Ray Ni <ray.ni@...>
Cc: Maurice Ma <maurice.ma@...>
Cc: Benjamin You <benjamin.you@...>
Signed-off-by: Guo Dong <guo.dong@...>
---
UefiPayloadPkg/UniversalPayloadBuild.py | 42 +++++++++++++++++++++++++++++++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/UniversalPayloadBuild.py
index b78c6a7620..842f92ac1a 100644
--- a/UefiPayloadPkg/UniversalPayloadBuild.py
+++ b/UefiPayloadPkg/UniversalPayloadBuild.py
@@ -10,6 +10,31 @@ import subprocess
import os
import shutil
import sys
+from   ctypes import *
+
+sys.dont_write_bytecode = True
+
+class UPLD_INFO_HEADER(Structure):

Guo,

Structure is the endian of the machine running Python which might not be correct. It would be more correct to use LittleEndianStructure vs Structure. This is probably good practice like using “<“ vs “=“ or “@“ with struct.pack format strings. 

I don’t remember us requiring the edk2 build machine to be little endian? 

My M1 Mac mini is little endian like a lot of ARM machines, but big endian machines do exist. 
>>> import sys; sys.byteorder
'little'

Thanks,

Andrew Fish

+    _pack_ = 1
+    _fields_ = [
+        ('Identifier',           ARRAY(c_char, 4)),
+        ('HeaderLength',         c_uint32),
+        ('SpecRevision',         c_uint16),
+        ('Reserved',             c_uint16),
+        ('Revision',             c_uint32),
+        ('Attribute',            c_uint32),
+        ('Capability',           c_uint32),
+        ('ProducerId',           ARRAY(c_char, 16)),
+        ('ImageId',              ARRAY(c_char, 16)),
+        ]
+
+    def __init__(self):
+        self.Identifier     =  b'UPLD'
+        self.HeaderLength   = sizeof(UPLD_INFO_HEADER)
+        self.HeaderRevision = 0x0075
+        self.Revision       = 0x0000010105
+        self.ImageId        = b'UEFI'
+        self.ProducerId     = b'INTEL'

def RunCommand(cmd):
    print(cmd)
@@ -37,6 +62,7 @@ def BuildUniversalPayload(Args, MacroList):
    EntryOutputDir = os.path.join(BuildDir, f"{BuildTarget}_{ElfToolChain}", os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry/DEBUG/UniversalPayloadEntry.dll"))
    PayloadReportPath = os.path.join(BuildDir, "UefiUniversalPayload.txt")
    ModuleReportPath = os.path.join(BuildDir, "UefiUniversalPayloadEntry.txt")
+    UpldInfoFile = os.path.join(BuildDir, "UniversalPayloadInfo.bin")

    if "CLANG_BIN" in os.environ:
        LlvmObjcopyPath = os.path.join(os.environ["CLANG_BIN"], "llvm-objcopy")
@@ -65,12 +91,21 @@ def BuildUniversalPayload(Args, MacroList):
    BuildModule += Defines
    RunCommand(BuildModule)

+    #
+    # Buid Universal Payload Information Section ".upld_info"
+    #
+    upld_info_hdr = UPLD_INFO_HEADER()
+    upld_info_hdr.ImageId = Args.ImageId.encode()[:16]
+    fp = open(UpldInfoFile, 'wb')
+    fp.write(bytearray(upld_info_hdr))
+    fp.close()
+
    #
    # Copy the DXEFV as a section in elf format Universal Payload entry.
    #
-    remove_section = '"%s" -I elf64-x86-64 -O elf64-x86-64 --remove-section .upld.uefi_fv %s'%(LlvmObjcopyPath, EntryOutputDir)
-    add_section = '"%s" -I elf64-x86-64 -O elf64-x86-64 --add-section .upld.uefi_fv=%s %s'%(LlvmObjcopyPath, FvOutputDir, EntryOutputDir)
-    set_section = '"%s" -I elf64-x86-64 -O elf64-x86-64 --set-section-alignment .upld.uefi_fv=16 %s'%(LlvmObjcopyPath, EntryOutputDir)
+    remove_section = '"%s" -I elf64-x86-64 -O elf64-x86-64 --remove-section .upld_info --remove-section .upld.uefi_fv %s'%(LlvmObjcopyPath, EntryOutputDir)
+    add_section    = '"%s" -I elf64-x86-64 -O elf64-x86-64 --add-section .upld_info=%s --add-section .upld.uefi_fv=%s %s'%(LlvmObjcopyPath, UpldInfoFile, FvOutputDir, EntryOutputDir)
+    set_section    = '"%s" -I elf64-x86-64 -O elf64-x86-64 --set-section-alignment .upld.upld_info=16 --set-section-alignment .upld.uefi_fv=16 %s'%(LlvmObjcopyPath, EntryOutputDir)
    RunCommand(remove_section)
    RunCommand(add_section)
    RunCommand(set_section)
@@ -82,6 +117,7 @@ def main():
    parser.add_argument('-t', '--ToolChain')
    parser.add_argument('-b', '--Target', default='DEBUG')
    parser.add_argument("-D", "--Macro", action="append", default=["UNIVERSAL_PAYLOAD=TRUE"])
+    parser.add_argument('-i', '--ImageId', type=str, help='Specify payload ID (16 bytes maximal).', default ='UEFI')
    MacroList = {}
    args = parser.parse_args()
    if args.Macro is not None:
--
2.32.0.windows.2








OVMF_CODE/VARS unable to reboot a mac os vm during installation (only first stage)

Daniele Crudo
 

Hi, forwarding this also to the mailing list:
https://bugzilla.tianocore.org/show_bug.cgi?id=3640
---->
Hello,
it's been about a year I'm experiencing a strange issue, not a stopper, so I started only recently to investigate.
I found that it's OVMF.

System: x86_64 manjaro 21.1.3 (only cli), qemu 6.1.0, libvirt 7.7.0

Issue:

after an ota delta update from within the virtual machine (mac os big sur and monterey were tested), from system preferences, or after the installation from a mac os installer disc, the virtual machine doesn't automatically reboot, ONLY after the first stage.
Installation and updates in mac os have several stages, unfortunately I don't know in details what's going on during each stage.

This is what happens (OTA delta update in the guest):

system preferences (in the vm) --> software updates: start to download the ota delta update,
download finishes, mac os prepares installation, then asks to reboot.
Mac os seems to start the reboot, signal to gpu (passed through) is lost, but it never starts again: virsh is reporting that the virtual machine is running.
After 30+ minutes I need to force the shutdown of the virtual machine (virsh reboot/virsh shutdown have no effect, only virsh destroy is able to force the shutdown) and manually start the vm again.
After this force shutdown/manual start, the installation completes without issues, mac os is rebooted automatically and automatically completes all the other installation stages.

After an installation from a mac os installer disc (empty virtual hd, or empty passed through sata controller+ssd):

Installation starts with a gui, after some minutes (less than 10 min) it reboots. then after some time (about 20 minutes) it tries to restart.
Mac os seems to start the reboot, signal to gpu (passed through) is lost, but it never starts again: virsh is reporting that the virtual machine is running.
After 30+ minutes I need to force the shutdown of the virtual machine (virsh reboot nor virsh shutdown have no effect, only virsh destroy is able to force the shutdown) and manually start again.
After this force shutdown/manual start, the installation completes without issues, mac os is reboot automatically and automatically completes all the other stages.

Side note:
reboot/shutdown work without issue in other cases, it's only after the first stage of a mac os installation.
Note that I tested also a very basic mac os vm, without any passthrough.

What I did:
tested different versions of qemu, from 5.1.0 to 6.1.0.
tested different versions of libvirt, from 6.5.0 to 7.7.0.
tested different versions of OVMF.

OVMF is the culprit.
I tested only release versions, compiled by me in kali linux, GCC5.
After compilation I use OVMF_CODE.fd and OVMF_VARS.fd for my virtual machine:

OVMF version 202011 (stable): it works, reboots mac os after first stage, no issue.
OVMF version 202102 (stable): it doesn't work as expected, doesn't reboot mac os after first stage, as explained.
OVMF version 202105 (stable): it doesn't work as expected, doesn't reboot mac os after first stage, as explained.
OVMF version 202108 (stable): it doesn't work as expected, doesn't reboot mac os after first stage, as explained.

The latest working OVMF version is 202011 stable, it seems something broke it between 202011 and 202102 stable.
Strange thing, as I said, is that it doesn't reboot only after this first installation stage (it's not random, it's always), everything seems normal when the vm is rebooted from the installed os.
I don't know if it matters, but last lines in the vm bootloader, before the forced shutdown after the first installation stage, complain about system being shutdown and applesmc (which is emulated).

I'm available to perform more tests if guided, please take into account that 1 test lasts about 45-50 minutes, because every time I need to install the os from scratch to reach the end of the 1st stage of installation.

Thank you for your attention.


[`edk2-devel][PATCH] UefiPayloadPkg: Use dummy constructor for PlatformHookLib

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

The Library constructor is only used for library dependency.
So use a dummy function to make it clear instead of using an
actual function.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLib.c =
| 17 +++++++++++++++++
UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLib.inf=
| 2 +-
2 files changed, 18 insertions(+), 1 deletion(-)

diff --git a/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/Platfor=
mHookLib.c b/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/Platfor=
mHookLib.c
index bd433bdbe0..004fcd8b7c 100644
--- a/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLi=
b.c
+++ b/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLi=
b.c
@@ -13,6 +13,23 @@
#include <Library/PcdLib.h>=0D
#include <Library/HobLib.h>=0D
=0D
+=0D
+/** Library Constructor=0D
+=0D
+ @retval RETURN_SUCCESS Success.=0D
+**/=0D
+EFI_STATUS=0D
+EFIAPI=0D
+PlatformHookSerialPortConstructor (=0D
+ VOID=0D
+ )=0D
+{=0D
+ // Nothing to do here. This constructor is added to=0D
+ // enable the chain of constructor invocation for=0D
+ // dependent libraries.=0D
+ return RETURN_SUCCESS;=0D
+}=0D
+=0D
/**=0D
Performs platform specific initialization required for the CPU to access=
=0D
the hardware associated with a SerialPortLib instance. This function do=
es=0D
diff --git a/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/Platfor=
mHookLib.inf b/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/Platf=
ormHookLib.inf
index 2dfd8b1216..7ac6bfa1b1 100644
--- a/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLi=
b.inf
+++ b/UefiPayloadPkg/Library/UniversalPayloadPlatformHookLib/PlatformHookLi=
b.inf
@@ -14,7 +14,7 @@
MODULE_TYPE =3D BASE=0D
VERSION_STRING =3D 1.0=0D
LIBRARY_CLASS =3D PlatformHookLib=0D
- CONSTRUCTOR =3D PlatformHookSerialPortInitialize=0D
+ CONSTRUCTOR =3D PlatformHookSerialPortConstructor=0D
=0D
[Sources]=0D
PlatformHookLib.c=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH] UefiPayloadPkg: Build a HOB from bootloader ACPI table

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

For universal UEFI payload, build a HOB from the ACPI table, so that
other modules could use this info from HOB at very early DXE phase.
This code are shared by universal payload and non universal payload.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c | 202 ++++++++++=
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++=
++++++++++++++++++++++++++++++++++++++++++
UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c | 192 ++++++++++=
++++-----------------------------------------------------------------------=
---------------------------------------------------------------------------=
--------------------------------
UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h | 14 ++++++++++=
++++
UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf | 1 +
UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c | 12 ++++++++++=
++
UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf | 2 +-
6 files changed, 244 insertions(+), 179 deletions(-)

diff --git a/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c b/UefiPayloadPkg/U=
efiPayloadEntry/AcpiTable.c
new file mode 100644
index 0000000000..6547fd8ab1
--- /dev/null
+++ b/UefiPayloadPkg/UefiPayloadEntry/AcpiTable.c
@@ -0,0 +1,202 @@
+/** @file=0D
+=0D
+=0D
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>=0D
+=0D
+ SPDX-License-Identifier: BSD-2-Clause-Patent=0D
+=0D
+**/=0D
+=0D
+#include "UefiPayloadEntry.h"=0D
+=0D
+=0D
+/**=0D
+ Find the board related info from ACPI table=0D
+=0D
+ @param AcpiTableBase ACPI table start address in memory=0D
+ @param AcpiBoardInfo Pointer to the acpi board info strucutre=
=0D
+=0D
+ @retval RETURN_SUCCESS Successfully find out all the required inform=
ation.=0D
+ @retval RETURN_NOT_FOUND Failed to find the required info.=0D
+=0D
+**/=0D
+RETURN_STATUS=0D
+ParseAcpiInfo (=0D
+ IN UINT64 AcpiTableBase,=0D
+ OUT ACPI_BOARD_INFO *AcpiBoardInfo=0D
+ )=0D
+{=0D
+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;=0D
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;=0D
+ UINT32 *Entry32;=0D
+ UINTN Entry32Num;=0D
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;=0D
+ EFI_ACPI_DESCRIPTION_HEADER *Xsdt;=0D
+ UINT64 *Entry64;=0D
+ UINTN Entry64Num;=0D
+ UINTN Idx;=0D
+ UINT32 *Signature;=0D
+ EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *MmCfgHdr=
;=0D
+ EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCAT=
ION_STRUCTURE *MmCfgBase;=0D
+=0D
+ Rsdp =3D (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)AcpiTabl=
eBase;=0D
+ DEBUG ((DEBUG_INFO, "Rsdp at 0x%p\n", Rsdp));=0D
+ DEBUG ((DEBUG_INFO, "Rsdt at 0x%x, Xsdt at 0x%lx\n", Rsdp->RsdtAddress, =
Rsdp->XsdtAddress));=0D
+=0D
+ //=0D
+ // Search Rsdt First=0D
+ //=0D
+ Fadt =3D NULL;=0D
+ MmCfgHdr =3D NULL;=0D
+ Rsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);=
=0D
+ if (Rsdt !=3D NULL) {=0D
+ Entry32 =3D (UINT32 *)(Rsdt + 1);=0D
+ Entry32Num =3D (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >>=
2;=0D
+ for (Idx =3D 0; Idx < Entry32Num; Idx++) {=0D
+ Signature =3D (UINT32 *)(UINTN)Entry32[Idx];=0D
+ if (*Signature =3D=3D EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGN=
ATURE) {=0D
+ Fadt =3D (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;=0D
+ DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n"));=0D
+ }=0D
+=0D
+ if (*Signature =3D=3D EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGU=
RATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {=0D
+ MmCfgHdr =3D (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TA=
BLE_HEADER *)Signature;=0D
+ DEBUG ((DEBUG_INFO, "Found MM config address in Rsdt\n"));=0D
+ }=0D
+=0D
+ if ((Fadt !=3D NULL) && (MmCfgHdr !=3D NULL)) {=0D
+ goto Done;=0D
+ }=0D
+ }=0D
+ }=0D
+=0D
+ //=0D
+ // Search Xsdt Second=0D
+ //=0D
+ Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);=
=0D
+ if (Xsdt !=3D NULL) {=0D
+ Entry64 =3D (UINT64 *)(Xsdt + 1);=0D
+ Entry64Num =3D (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >>=
3;=0D
+ for (Idx =3D 0; Idx < Entry64Num; Idx++) {=0D
+ Signature =3D (UINT32 *)(UINTN)Entry64[Idx];=0D
+ if (*Signature =3D=3D EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGN=
ATURE) {=0D
+ Fadt =3D (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;=0D
+ DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n"));=0D
+ }=0D
+=0D
+ if (*Signature =3D=3D EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGU=
RATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {=0D
+ MmCfgHdr =3D (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TA=
BLE_HEADER *)Signature;=0D
+ DEBUG ((DEBUG_INFO, "Found MM config address in Xsdt\n"));=0D
+ }=0D
+=0D
+ if ((Fadt !=3D NULL) && (MmCfgHdr !=3D NULL)) {=0D
+ goto Done;=0D
+ }=0D
+ }=0D
+ }=0D
+=0D
+ if (Fadt =3D=3D NULL) {=0D
+ return RETURN_NOT_FOUND;=0D
+ }=0D
+=0D
+Done:=0D
+=0D
+ AcpiBoardInfo->PmCtrlRegBase =3D Fadt->Pm1aCntBlk;=0D
+ AcpiBoardInfo->PmTimerRegBase =3D Fadt->PmTmrBlk;=0D
+ AcpiBoardInfo->ResetRegAddress =3D Fadt->ResetReg.Address;=0D
+ AcpiBoardInfo->ResetValue =3D Fadt->ResetValue;=0D
+ AcpiBoardInfo->PmEvtBase =3D Fadt->Pm1aEvtBlk;=0D
+ AcpiBoardInfo->PmGpeEnBase =3D Fadt->Gpe0Blk + Fadt->Gpe0BlkLen / 2;=
=0D
+=0D
+ if (MmCfgHdr !=3D NULL) {=0D
+ MmCfgBase =3D (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BAS=
E_ADDRESS_ALLOCATION_STRUCTURE *)((UINT8*) MmCfgHdr + sizeof (*MmCfgHdr));=
=0D
+ AcpiBoardInfo->PcieBaseAddress =3D MmCfgBase->BaseAddress;=0D
+ AcpiBoardInfo->PcieBaseSize =3D (MmCfgBase->EndBusNumber + 1 - MmCfgBa=
se->StartBusNumber) * 4096 * 32 * 8;=0D
+ } else {=0D
+ AcpiBoardInfo->PcieBaseAddress =3D 0;=0D
+ AcpiBoardInfo->PcieBaseSize =3D 0;=0D
+ }=0D
+ DEBUG ((DEBUG_INFO, "PmCtrl Reg 0x%lx\n", AcpiBoardInfo->PmCtrlRegBase=
));=0D
+ DEBUG ((DEBUG_INFO, "PmTimer Reg 0x%lx\n", AcpiBoardInfo->PmTimerRegBas=
e));=0D
+ DEBUG ((DEBUG_INFO, "Reset Reg 0x%lx\n", AcpiBoardInfo->ResetRegAddre=
ss));=0D
+ DEBUG ((DEBUG_INFO, "Reset Value 0x%x\n", AcpiBoardInfo->ResetValue));=
=0D
+ DEBUG ((DEBUG_INFO, "PmEvt Reg 0x%lx\n", AcpiBoardInfo->PmEvtBase));=
=0D
+ DEBUG ((DEBUG_INFO, "PmGpeEn Reg 0x%lx\n", AcpiBoardInfo->PmGpeEnBase))=
;=0D
+ DEBUG ((DEBUG_INFO, "PcieBaseAddr 0x%lx\n", AcpiBoardInfo->PcieBaseAddre=
ss));=0D
+ DEBUG ((DEBUG_INFO, "PcieBaseSize 0x%lx\n", AcpiBoardInfo->PcieBaseSize)=
);=0D
+=0D
+ //=0D
+ // Verify values for proper operation=0D
+ //=0D
+ ASSERT(Fadt->Pm1aCntBlk !=3D 0);=0D
+ ASSERT(Fadt->PmTmrBlk !=3D 0);=0D
+ ASSERT(Fadt->ResetReg.Address !=3D 0);=0D
+ ASSERT(Fadt->Pm1aEvtBlk !=3D 0);=0D
+ ASSERT(Fadt->Gpe0Blk !=3D 0);=0D
+=0D
+ DEBUG_CODE_BEGIN ();=0D
+ BOOLEAN SciEnabled;=0D
+=0D
+ //=0D
+ // Check the consistency of SCI enabling=0D
+ //=0D
+=0D
+ //=0D
+ // Get SCI_EN value=0D
+ //=0D
+ if (Fadt->Pm1CntLen =3D=3D 4) {=0D
+ SciEnabled =3D (IoRead32 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;=0D
+ } else {=0D
+ //=0D
+ // if (Pm1CntLen =3D=3D 2), use 16 bit IO read;=0D
+ // if (Pm1CntLen !=3D 2 && Pm1CntLen !=3D 4), use 16 bit IO read as =
a fallback=0D
+ //=0D
+ SciEnabled =3D (IoRead16 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;=0D
+ }=0D
+=0D
+ if (!(Fadt->Flags & EFI_ACPI_5_0_HW_REDUCED_ACPI) &&=0D
+ (Fadt->SmiCmd =3D=3D 0) &&=0D
+ !SciEnabled) {=0D
+ //=0D
+ // The ACPI enabling status is inconsistent: SCI is not enabled but =
ACPI=0D
+ // table does not provide a means to enable it through FADT->SmiCmd=
=0D
+ //=0D
+ DEBUG ((DEBUG_ERROR, "ERROR: The ACPI enabling status is inconsisten=
t: SCI is not"=0D
+ " enabled but the ACPI table does not provide a means to enable it=
through FADT->SmiCmd."=0D
+ " This may cause issues in OS.\n"));=0D
+ }=0D
+ DEBUG_CODE_END ();=0D
+=0D
+ return RETURN_SUCCESS;=0D
+}=0D
+=0D
+=0D
+/**=0D
+ Build ACPI board info HOB using infomation from ACPI table=0D
+=0D
+ @param AcpiTableBase ACPI table start address in memory=0D
+=0D
+ @retval RETURN_SUCCESS Successfully build HOB from ACPI table.=0D
+ @retval RETURN_NOT_FOUND Failed to build the HOB.=0D
+**/=0D
+EFI_STATUS=0D
+BuildHobFromAcpi (=0D
+ IN UINT64 AcpiTableBase=0D
+ )=0D
+{=0D
+ EFI_STATUS Status;=0D
+ ACPI_BOARD_INFO AcpiBoardInfo;=0D
+ ACPI_BOARD_INFO *NewAcpiBoardInfo;=0D
+=0D
+ Status =3D ParseAcpiInfo (AcpiTableBase, &AcpiBoardInfo);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ if (!EFI_ERROR (Status)) {=0D
+ NewAcpiBoardInfo =3D BuildGuidHob (&gUefiAcpiBoardInfoGuid, sizeof (AC=
PI_BOARD_INFO));=0D
+ ASSERT (NewAcpiBoardInfo !=3D NULL);=0D
+ CopyMem (NewAcpiBoardInfo, &AcpiBoardInfo, sizeof (ACPI_BOARD_INFO));=
=0D
+ DEBUG ((DEBUG_INFO, "Create acpi board info guid hob\n"));=0D
+ }=0D
+ return Status;=0D
+}=0D
+=0D
+=0D
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c b/UefiPaylo=
adPkg/UefiPayloadEntry/UefiPayloadEntry.c
index ae16f25c7c..d8e745bf32 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.c
@@ -7,7 +7,8 @@
=0D
#include "UefiPayloadEntry.h"=0D
=0D
-STATIC UINT32 mTopOfLowerUsableDram =3D 0;=0D
+STATIC UINT32 mTopOfLowerUsableDram =3D 0;=0D
+STATIC ACPI_BOARD_INFO *mAcpiBoardInfo =3D NULL;=0D
=0D
/**=0D
Callback function to build resource descriptor HOB=0D
@@ -32,11 +33,16 @@ MemInfoCallbackMmio (
EFI_RESOURCE_TYPE Type;=0D
UINT64 Size;=0D
EFI_RESOURCE_ATTRIBUTE_TYPE Attribue;=0D
- ACPI_BOARD_INFO *AcpiBoardInfo;=0D
+ EFI_HOB_GUID_TYPE *GuidHob;=0D
=0D
- AcpiBoardInfo =3D (ACPI_BOARD_INFO *)Params;=0D
- if (AcpiBoardInfo =3D=3D NULL) {=0D
- return EFI_INVALID_PARAMETER;=0D
+=0D
+ //=0D
+ // Find the acpi board information guid hob=0D
+ //=0D
+ if (mAcpiBoardInfo =3D=3D NULL) {=0D
+ GuidHob =3D GetFirstGuidHob (&gUefiAcpiBoardInfoGuid);=0D
+ ASSERT (GuidHob !=3D NULL);=0D
+ mAcpiBoardInfo =3D (ACPI_BOARD_INFO *)GET_GUID_HOB_DATA (GuidHob);=0D
}=0D
=0D
//=0D
@@ -46,7 +52,7 @@ MemInfoCallbackMmio (
return EFI_SUCCESS;=0D
}=0D
=0D
- if (MemoryMapEntry->Base =3D=3D AcpiBoardInfo->PcieBaseAddress) {=0D
+ if (MemoryMapEntry->Base =3D=3D mAcpiBoardInfo->PcieBaseAddress) {=0D
//=0D
// MMCONF is always MMIO=0D
//=0D
@@ -211,168 +217,6 @@ MemInfoCallback (
}=0D
=0D
=0D
-=0D
-/**=0D
- Find the board related info from ACPI table=0D
-=0D
- @param AcpiTableBase ACPI table start address in memory=0D
- @param AcpiBoardInfo Pointer to the acpi board info strucutre=
=0D
-=0D
- @retval RETURN_SUCCESS Successfully find out all the required inform=
ation.=0D
- @retval RETURN_NOT_FOUND Failed to find the required info.=0D
-=0D
-**/=0D
-RETURN_STATUS=0D
-ParseAcpiInfo (=0D
- IN UINT64 AcpiTableBase,=0D
- OUT ACPI_BOARD_INFO *AcpiBoardInfo=0D
- )=0D
-{=0D
- EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;=0D
- EFI_ACPI_DESCRIPTION_HEADER *Rsdt;=0D
- UINT32 *Entry32;=0D
- UINTN Entry32Num;=0D
- EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;=0D
- EFI_ACPI_DESCRIPTION_HEADER *Xsdt;=0D
- UINT64 *Entry64;=0D
- UINTN Entry64Num;=0D
- UINTN Idx;=0D
- UINT32 *Signature;=0D
- EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TABLE_HEADER *MmCfgHdr=
;=0D
- EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BASE_ADDRESS_ALLOCAT=
ION_STRUCTURE *MmCfgBase;=0D
-=0D
- Rsdp =3D (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *)(UINTN)AcpiTabl=
eBase;=0D
- DEBUG ((DEBUG_INFO, "Rsdp at 0x%p\n", Rsdp));=0D
- DEBUG ((DEBUG_INFO, "Rsdt at 0x%x, Xsdt at 0x%lx\n", Rsdp->RsdtAddress, =
Rsdp->XsdtAddress));=0D
-=0D
- //=0D
- // Search Rsdt First=0D
- //=0D
- Fadt =3D NULL;=0D
- MmCfgHdr =3D NULL;=0D
- Rsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->RsdtAddress);=
=0D
- if (Rsdt !=3D NULL) {=0D
- Entry32 =3D (UINT32 *)(Rsdt + 1);=0D
- Entry32Num =3D (Rsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >>=
2;=0D
- for (Idx =3D 0; Idx < Entry32Num; Idx++) {=0D
- Signature =3D (UINT32 *)(UINTN)Entry32[Idx];=0D
- if (*Signature =3D=3D EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGN=
ATURE) {=0D
- Fadt =3D (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;=0D
- DEBUG ((DEBUG_INFO, "Found Fadt in Rsdt\n"));=0D
- }=0D
-=0D
- if (*Signature =3D=3D EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGU=
RATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {=0D
- MmCfgHdr =3D (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TA=
BLE_HEADER *)Signature;=0D
- DEBUG ((DEBUG_INFO, "Found MM config address in Rsdt\n"));=0D
- }=0D
-=0D
- if ((Fadt !=3D NULL) && (MmCfgHdr !=3D NULL)) {=0D
- goto Done;=0D
- }=0D
- }=0D
- }=0D
-=0D
- //=0D
- // Search Xsdt Second=0D
- //=0D
- Xsdt =3D (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN)(Rsdp->XsdtAddress);=
=0D
- if (Xsdt !=3D NULL) {=0D
- Entry64 =3D (UINT64 *)(Xsdt + 1);=0D
- Entry64Num =3D (Xsdt->Length - sizeof(EFI_ACPI_DESCRIPTION_HEADER)) >>=
3;=0D
- for (Idx =3D 0; Idx < Entry64Num; Idx++) {=0D
- Signature =3D (UINT32 *)(UINTN)Entry64[Idx];=0D
- if (*Signature =3D=3D EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGN=
ATURE) {=0D
- Fadt =3D (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *)Signature;=0D
- DEBUG ((DEBUG_INFO, "Found Fadt in Xsdt\n"));=0D
- }=0D
-=0D
- if (*Signature =3D=3D EFI_ACPI_5_0_PCI_EXPRESS_MEMORY_MAPPED_CONFIGU=
RATION_SPACE_BASE_ADDRESS_DESCRIPTION_TABLE_SIGNATURE) {=0D
- MmCfgHdr =3D (EFI_ACPI_MEMORY_MAPPED_CONFIGURATION_BASE_ADDRESS_TA=
BLE_HEADER *)Signature;=0D
- DEBUG ((DEBUG_INFO, "Found MM config address in Xsdt\n"));=0D
- }=0D
-=0D
- if ((Fadt !=3D NULL) && (MmCfgHdr !=3D NULL)) {=0D
- goto Done;=0D
- }=0D
- }=0D
- }=0D
-=0D
- if (Fadt =3D=3D NULL) {=0D
- return RETURN_NOT_FOUND;=0D
- }=0D
-=0D
-Done:=0D
-=0D
- AcpiBoardInfo->PmCtrlRegBase =3D Fadt->Pm1aCntBlk;=0D
- AcpiBoardInfo->PmTimerRegBase =3D Fadt->PmTmrBlk;=0D
- AcpiBoardInfo->ResetRegAddress =3D Fadt->ResetReg.Address;=0D
- AcpiBoardInfo->ResetValue =3D Fadt->ResetValue;=0D
- AcpiBoardInfo->PmEvtBase =3D Fadt->Pm1aEvtBlk;=0D
- AcpiBoardInfo->PmGpeEnBase =3D Fadt->Gpe0Blk + Fadt->Gpe0BlkLen / 2;=
=0D
-=0D
- if (MmCfgHdr !=3D NULL) {=0D
- MmCfgBase =3D (EFI_ACPI_MEMORY_MAPPED_ENHANCED_CONFIGURATION_SPACE_BAS=
E_ADDRESS_ALLOCATION_STRUCTURE *)((UINT8*) MmCfgHdr + sizeof (*MmCfgHdr));=
=0D
- AcpiBoardInfo->PcieBaseAddress =3D MmCfgBase->BaseAddress;=0D
- AcpiBoardInfo->PcieBaseSize =3D (MmCfgBase->EndBusNumber + 1 - MmCfgBa=
se->StartBusNumber) * 4096 * 32 * 8;=0D
- } else {=0D
- AcpiBoardInfo->PcieBaseAddress =3D 0;=0D
- AcpiBoardInfo->PcieBaseSize =3D 0;=0D
- }=0D
- DEBUG ((DEBUG_INFO, "PmCtrl Reg 0x%lx\n", AcpiBoardInfo->PmCtrlRegBase=
));=0D
- DEBUG ((DEBUG_INFO, "PmTimer Reg 0x%lx\n", AcpiBoardInfo->PmTimerRegBas=
e));=0D
- DEBUG ((DEBUG_INFO, "Reset Reg 0x%lx\n", AcpiBoardInfo->ResetRegAddre=
ss));=0D
- DEBUG ((DEBUG_INFO, "Reset Value 0x%x\n", AcpiBoardInfo->ResetValue));=
=0D
- DEBUG ((DEBUG_INFO, "PmEvt Reg 0x%lx\n", AcpiBoardInfo->PmEvtBase));=
=0D
- DEBUG ((DEBUG_INFO, "PmGpeEn Reg 0x%lx\n", AcpiBoardInfo->PmGpeEnBase))=
;=0D
- DEBUG ((DEBUG_INFO, "PcieBaseAddr 0x%lx\n", AcpiBoardInfo->PcieBaseAddre=
ss));=0D
- DEBUG ((DEBUG_INFO, "PcieBaseSize 0x%lx\n", AcpiBoardInfo->PcieBaseSize)=
);=0D
-=0D
- //=0D
- // Verify values for proper operation=0D
- //=0D
- ASSERT(Fadt->Pm1aCntBlk !=3D 0);=0D
- ASSERT(Fadt->PmTmrBlk !=3D 0);=0D
- ASSERT(Fadt->ResetReg.Address !=3D 0);=0D
- ASSERT(Fadt->Pm1aEvtBlk !=3D 0);=0D
- ASSERT(Fadt->Gpe0Blk !=3D 0);=0D
-=0D
- DEBUG_CODE_BEGIN ();=0D
- BOOLEAN SciEnabled;=0D
-=0D
- //=0D
- // Check the consistency of SCI enabling=0D
- //=0D
-=0D
- //=0D
- // Get SCI_EN value=0D
- //=0D
- if (Fadt->Pm1CntLen =3D=3D 4) {=0D
- SciEnabled =3D (IoRead32 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;=0D
- } else {=0D
- //=0D
- // if (Pm1CntLen =3D=3D 2), use 16 bit IO read;=0D
- // if (Pm1CntLen !=3D 2 && Pm1CntLen !=3D 4), use 16 bit IO read as =
a fallback=0D
- //=0D
- SciEnabled =3D (IoRead16 (Fadt->Pm1aCntBlk) & BIT0)? TRUE : FALSE;=0D
- }=0D
-=0D
- if (!(Fadt->Flags & EFI_ACPI_5_0_HW_REDUCED_ACPI) &&=0D
- (Fadt->SmiCmd =3D=3D 0) &&=0D
- !SciEnabled) {=0D
- //=0D
- // The ACPI enabling status is inconsistent: SCI is not enabled but =
ACPI=0D
- // table does not provide a means to enable it through FADT->SmiCmd=
=0D
- //=0D
- DEBUG ((DEBUG_ERROR, "ERROR: The ACPI enabling status is inconsisten=
t: SCI is not"=0D
- " enabled but the ACPI table does not provide a means to enable it=
through FADT->SmiCmd."=0D
- " This may cause issues in OS.\n"));=0D
- }=0D
- DEBUG_CODE_END ();=0D
-=0D
- return RETURN_SUCCESS;=0D
-}=0D
-=0D
-=0D
/**=0D
It will build HOBs based on information from bootloaders.=0D
=0D
@@ -387,8 +231,6 @@ BuildHobFromBl (
EFI_STATUS Status;=0D
SYSTEM_TABLE_INFO SysTableInfo;=0D
SYSTEM_TABLE_INFO *NewSysTableInfo;=0D
- ACPI_BOARD_INFO AcpiBoardInfo;=0D
- ACPI_BOARD_INFO *NewAcpiBoardInfo;=0D
EFI_PEI_GRAPHICS_INFO_HOB GfxInfo;=0D
EFI_PEI_GRAPHICS_INFO_HOB *NewGfxInfo;=0D
EFI_PEI_GRAPHICS_DEVICE_INFO_HOB GfxDeviceInfo;=0D
@@ -471,20 +313,14 @@ BuildHobFromBl (
//=0D
// Create guid hob for acpi board information=0D
//=0D
- Status =3D ParseAcpiInfo (SysTableInfo.AcpiTableBase, &AcpiBoardInfo);=0D
+ Status =3D BuildHobFromAcpi (SysTableInfo.AcpiTableBase);=0D
ASSERT_EFI_ERROR (Status);=0D
- if (!EFI_ERROR (Status)) {=0D
- NewAcpiBoardInfo =3D BuildGuidHob (&gUefiAcpiBoardInfoGuid, sizeof (AC=
PI_BOARD_INFO));=0D
- ASSERT (NewAcpiBoardInfo !=3D NULL);=0D
- CopyMem (NewAcpiBoardInfo, &AcpiBoardInfo, sizeof (ACPI_BOARD_INFO));=
=0D
- DEBUG ((DEBUG_INFO, "Create acpi board info guid hob\n"));=0D
- }=0D
=0D
//=0D
// Parse memory info and build memory HOBs for reserved DRAM and MMIO=0D
//=0D
DEBUG ((DEBUG_INFO , "Building ResourceDescriptorHobs for reserved memor=
y:\n"));=0D
- Status =3D ParseMemoryInfo (MemInfoCallbackMmio, &AcpiBoardInfo);=0D
+ Status =3D ParseMemoryInfo (MemInfoCallbackMmio, NULL);=0D
if (EFI_ERROR(Status)) {=0D
return Status;=0D
}=0D
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h b/UefiPaylo=
adPkg/UefiPayloadEntry/UefiPayloadEntry.h
index 331724c687..00e9e34933 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.h
@@ -204,4 +204,18 @@ FvFindFileByTypeGuid (
IN EFI_GUID *Guid OPTIONAL,=0D
OUT EFI_FFS_FILE_HEADER **FileHeader=0D
);=0D
+=0D
+/**=0D
+ Build ACPI board info HOB using infomation from ACPI table=0D
+=0D
+ @param AcpiTableBase ACPI table start address in memory=0D
+=0D
+ @retval RETURN_SUCCESS Successfully build HOB from ACPI table.=0D
+ @retval RETURN_NOT_FOUND Failed to build the HOB.=0D
+**/=0D
+EFI_STATUS=0D
+BuildHobFromAcpi (=0D
+ IN UINT64 AcpiTableBase=0D
+ );=0D
+=0D
#endif=0D
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf b/UefiPay=
loadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
index 8d42925fcd..4c5170d9cc 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
+++ b/UefiPayloadPkg/UefiPayloadEntry/UefiPayloadEntry.inf
@@ -25,6 +25,7 @@
UefiPayloadEntry.c=0D
LoadDxeCore.c=0D
MemoryAllocation.c=0D
+ AcpiTable.c=0D
=0D
[Sources.Ia32]=0D
X64/VirtualMemory.h=0D
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c b/Uefi=
PayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c
index 03ad9c457b..b64b6529c3 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c
+++ b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.c
@@ -260,6 +260,8 @@ BuildHobs (
UNIVERSAL_PAYLOAD_EXTRA_DATA *ExtraData;=0D
UINT8 *GuidHob;=0D
EFI_HOB_FIRMWARE_VOLUME *FvHob;=0D
+ EFI_STATUS Status;=0D
+ UNIVERSAL_PAYLOAD_ACPI_TABLE *AcpiTable;=0D
=0D
Hob.Raw =3D (UINT8 *) BootloaderParameter;=0D
MinimalNeededSize =3D FixedPcdGet32 (PcdSystemMemoryUefiRegionSize);=0D
@@ -351,6 +353,16 @@ BuildHobs (
*DxeFv =3D (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) ExtraData->Entry[0].Ba=
se;=0D
ASSERT ((*DxeFv)->FvLength =3D=3D ExtraData->Entry[0].Size);=0D
=0D
+ //=0D
+ // Create guid hob for acpi board information=0D
+ //=0D
+ GuidHob =3D GetFirstGuidHob(&gUniversalPayloadAcpiTableGuid);=0D
+ if (GuidHob !=3D NULL) {=0D
+ AcpiTable =3D (UNIVERSAL_PAYLOAD_ACPI_TABLE *) GET_GUID_HOB_DATA (Guid=
Hob);=0D
+ Status =3D BuildHobFromAcpi ((UINT64)AcpiTable->Rsdp);=0D
+ ASSERT_EFI_ERROR (Status);=0D
+ }=0D
+=0D
//=0D
// Update DXE FV information to first fv hob in the hob list, which=0D
// is the empty FvHob created before.=0D
diff --git a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf b/Ue=
fiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
index 3ee449219d..e7e05b744a 100644
--- a/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
+++ b/UefiPayloadPkg/UefiPayloadEntry/UniversalPayloadEntry.inf
@@ -25,6 +25,7 @@
LoadDxeCore.c=0D
MemoryAllocation.c=0D
PrintHob.c=0D
+ AcpiTable.c=0D
=0D
[Sources.Ia32]=0D
X64/VirtualMemory.h=0D
@@ -61,7 +62,6 @@
gEfiGraphicsDeviceInfoHobGuid=0D
gUefiAcpiBoardInfoGuid=0D
gEfiSmbiosTableGuid=0D
- gEfiAcpiTableGuid=0D
gUefiSerialPortInfoGuid=0D
gUniversalPayloadExtraDataGuid=0D
gPcdDataBaseHobGuid=0D
--=20
2.32.0.windows.2


[`edk2-devel][PATCH] UefiPayloadPkg: Add ".upld_info" in universal payload

Guo Dong
 

From: Guo Dong <guo.dong@intel.com>

From the universal scalable firmware payload requirement V0.75,
Payload must have Universal Payload Information Section ".upld_info"
So update the build tool to add this section.

Cc: Ray Ni <ray.ni@intel.com>
Cc: Maurice Ma <maurice.ma@intel.com>
Cc: Benjamin You <benjamin.you@intel.com>
Signed-off-by: Guo Dong <guo.dong@intel.com>
---
UefiPayloadPkg/UniversalPayloadBuild.py | 42 +++++++++++++++++++++++++++++=
++++++++++---
1 file changed, 39 insertions(+), 3 deletions(-)

diff --git a/UefiPayloadPkg/UniversalPayloadBuild.py b/UefiPayloadPkg/Unive=
rsalPayloadBuild.py
index b78c6a7620..842f92ac1a 100644
--- a/UefiPayloadPkg/UniversalPayloadBuild.py
+++ b/UefiPayloadPkg/UniversalPayloadBuild.py
@@ -10,6 +10,31 @@ import subprocess
import os=0D
import shutil=0D
import sys=0D
+from ctypes import *=0D
+=0D
+sys.dont_write_bytecode =3D True=0D
+=0D
+class UPLD_INFO_HEADER(Structure):=0D
+ _pack_ =3D 1=0D
+ _fields_ =3D [=0D
+ ('Identifier', ARRAY(c_char, 4)),=0D
+ ('HeaderLength', c_uint32),=0D
+ ('SpecRevision', c_uint16),=0D
+ ('Reserved', c_uint16),=0D
+ ('Revision', c_uint32),=0D
+ ('Attribute', c_uint32),=0D
+ ('Capability', c_uint32),=0D
+ ('ProducerId', ARRAY(c_char, 16)),=0D
+ ('ImageId', ARRAY(c_char, 16)),=0D
+ ]=0D
+=0D
+ def __init__(self):=0D
+ self.Identifier =3D b'UPLD'=0D
+ self.HeaderLength =3D sizeof(UPLD_INFO_HEADER)=0D
+ self.HeaderRevision =3D 0x0075=0D
+ self.Revision =3D 0x0000010105=0D
+ self.ImageId =3D b'UEFI'=0D
+ self.ProducerId =3D b'INTEL'=0D
=0D
def RunCommand(cmd):=0D
print(cmd)=0D
@@ -37,6 +62,7 @@ def BuildUniversalPayload(Args, MacroList):
EntryOutputDir =3D os.path.join(BuildDir, f"{BuildTarget}_{ElfToolChai=
n}", os.path.normpath("X64/UefiPayloadPkg/UefiPayloadEntry/UniversalPayload=
Entry/DEBUG/UniversalPayloadEntry.dll"))=0D
PayloadReportPath =3D os.path.join(BuildDir, "UefiUniversalPayload.txt=
")=0D
ModuleReportPath =3D os.path.join(BuildDir, "UefiUniversalPayloadEntry=
.txt")=0D
+ UpldInfoFile =3D os.path.join(BuildDir, "UniversalPayloadInfo.bin")=0D
=0D
if "CLANG_BIN" in os.environ:=0D
LlvmObjcopyPath =3D os.path.join(os.environ["CLANG_BIN"], "llvm-ob=
jcopy")=0D
@@ -65,12 +91,21 @@ def BuildUniversalPayload(Args, MacroList):
BuildModule +=3D Defines=0D
RunCommand(BuildModule)=0D
=0D
+ #=0D
+ # Buid Universal Payload Information Section ".upld_info"=0D
+ #=0D
+ upld_info_hdr =3D UPLD_INFO_HEADER()=0D
+ upld_info_hdr.ImageId =3D Args.ImageId.encode()[:16]=0D
+ fp =3D open(UpldInfoFile, 'wb')=0D
+ fp.write(bytearray(upld_info_hdr))=0D
+ fp.close()=0D
+=0D
#=0D
# Copy the DXEFV as a section in elf format Universal Payload entry.=0D
#=0D
- remove_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --remove-sect=
ion .upld.uefi_fv %s'%(LlvmObjcopyPath, EntryOutputDir)=0D
- add_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --add-section .u=
pld.uefi_fv=3D%s %s'%(LlvmObjcopyPath, FvOutputDir, EntryOutputDir)=0D
- set_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --set-section-al=
ignment .upld.uefi_fv=3D16 %s'%(LlvmObjcopyPath, EntryOutputDir)=0D
+ remove_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --remove-sect=
ion .upld_info --remove-section .upld.uefi_fv %s'%(LlvmObjcopyPath, EntryOu=
tputDir)=0D
+ add_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --add-section=
.upld_info=3D%s --add-section .upld.uefi_fv=3D%s %s'%(LlvmObjcopyPath, Upl=
dInfoFile, FvOutputDir, EntryOutputDir)=0D
+ set_section =3D '"%s" -I elf64-x86-64 -O elf64-x86-64 --set-section=
-alignment .upld.upld_info=3D16 --set-section-alignment .upld.uefi_fv=3D16 =
%s'%(LlvmObjcopyPath, EntryOutputDir)=0D
RunCommand(remove_section)=0D
RunCommand(add_section)=0D
RunCommand(set_section)=0D
@@ -82,6 +117,7 @@ def main():
parser.add_argument('-t', '--ToolChain')=0D
parser.add_argument('-b', '--Target', default=3D'DEBUG')=0D
parser.add_argument("-D", "--Macro", action=3D"append", default=3D["UN=
IVERSAL_PAYLOAD=3DTRUE"])=0D
+ parser.add_argument('-i', '--ImageId', type=3Dstr, help=3D'Specify pay=
load ID (16 bytes maximal).', default =3D'UEFI')=0D
MacroList =3D {}=0D
args =3D parser.parse_args()=0D
if args.Macro is not None:=0D
--=20
2.32.0.windows.2


Re: [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

Brijesh Singh
 

Hi Min,


On 9/24/21 7:03 PM, Xu, Min M wrote:
On September 24, 2021 6:58 PM, Brijesh Singh wrote:
Hi Min,

On 9/21/21 4:05 AM, Min Xu wrote:
;
; Modified: EAX, EBX, ECX, EDX
;
SetCr3ForPageTables64:
-
- ; Clear the WorkArea header. The SEV probe routines will populate the
- ; work area when detected.
- mov byte[WORK_AREA_GUEST_TYPE], 0
Why you are removing the above block ? The workarea hdr must be initialized
to zero, its not safe to assume that the guest memory is zero'ed in the non-
encrypted case.
Hi, Brijesh
Please see below explanation (It is in the commit message)
- In Main16 entry point, after TransitionFromReal16To32BitFlat,
WORK_AREA_GUEST_TYPE is cleared to 0. WORK_AREA_GUEST_TYPE was
previously cleared in SetCr3ForPageTables64 (see commit ab77b60).
This doesn't work after TDX is introduced in Ovmf. It is because all
TDX CPUs (BSP and APs) start to run from 0xfffffff0. In previous code
WORK_AREA_GUEST_TYPE will be cleared multi-times in TDX guest. So for
SEV and Legacy guest it is moved to Main16 entry point (after
TransitionFromReal16To32BitFlat). For TDX guest WORK_AREA_GUEST_TYPE
is cleared and set in InitTdxWorkarea
thanks for clarifying it.

This is very busy commit and making several changes at once, so some of
important common code movement is getting lost. Maybe I recommend you to
please break it into multiple. e,g  this particular change can be very
easily broken into two commits

1) Since TDX support need the change in the boot flow, and you are no
longer using the Main.asm from the UefiCpuPkg. This can be a pre-patch
in which you copy UefiCpuPkg/ResetVector/Vtf0/main.asm ->
OvmfPkg/ResetVector/Main.asm and document reason behind the move.

2) Remove clearing of workarea from SetCr3ForPageTables64 to Main.asm

Now that we have override for the Main.asm, I think clearing of the
workarea should be done for all architecture (Ia32, x64) to cover the
cases where someone builds the OVMF for 32bit or IA32 and X64.

thanks

Thanks!
Min


[RFC] [PATCH 2/2] ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL

Rebecca Cran <rebecca@...>
 

Add support for EFI_MP_SERVICES_PROTOCOL during the DXE phase under
AArch64.

Call PSCI_CPU_ON to power on the core, call the supplied procedure and
then call PSCI_CPU_OFF to power off the core.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
ArmPkg/ArmPkg.dec | 4 +
ArmPkg/ArmPkg.dsc | 4 +
ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 +
ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 +
ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 604 ++++++++
ArmPkg/Include/Library/MpInitLib.h | 366 +++++
ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 61 +
ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 +
ArmPkg/Library/MpInitLib/DxeMpLib.c | 1498 ++++++++++++++++++++
ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 358 +++++
ArmVirtPkg/ArmVirt.dsc.inc | 3 +
14 files changed, 3013 insertions(+)

diff --git a/ArmPkg/ArmPkg.dec b/ArmPkg/ArmPkg.dec
index 6ed51edd0340..cd4458de6ec1 100644
--- a/ArmPkg/ArmPkg.dec
+++ b/ArmPkg/ArmPkg.dec
@@ -74,6 +74,10 @@
#
DefaultExceptionHandlerLib|Include/Library/DefaultExceptionHandlerLib.h

+ ## @libraryclass Provides a MP Services interface.
+ #
+ MpInitLib|Include/Library/MpInitLib.h
+
## @libraryclass Provides an interface to query miscellaneous OEM
# information.
#
diff --git a/ArmPkg/ArmPkg.dsc b/ArmPkg/ArmPkg.dsc
index 8abe3713c829..26fb8bb94c07 100644
--- a/ArmPkg/ArmPkg.dsc
+++ b/ArmPkg/ArmPkg.dsc
@@ -99,6 +99,9 @@
PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf

+[LibraryClasses.AARCH64]
+ MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
+
[LibraryClasses.ARM, LibraryClasses.AARCH64]
NULL|ArmPkg/Library/CompilerIntrinsicsLib/CompilerIntrinsicsLib.inf

@@ -163,4 +166,5 @@
ArmPkg/Library/ArmMmuLib/ArmMmuPeiLib.inf

[Components.AARCH64, Components.ARM]
+ ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
ArmPkg/Library/StandaloneMmMmuLib/ArmMmuStandaloneMmLib.inf
diff --git a/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
new file mode 100644
index 000000000000..a4b9e9037100
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
@@ -0,0 +1,22 @@
+/** @file
+ Architecture specific functions.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <CpuDxe.h>
+
+/** Initializes multi-processor support.
+ *
+**/
+VOID
+ArchInitializeMpSupport (
+ VOID
+ )
+{
+ InitializeMpSupport ();
+}
diff --git a/ArmPkg/Drivers/CpuDxe/Arm/Arch.c b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c
new file mode 100644
index 000000000000..0ded264cd06a
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/Arm/Arch.c
@@ -0,0 +1,22 @@
+/** @file
+ Architecture specific functions.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#include <CpuDxe.h>
+
+/** Initializes multi-processor support.
+ *
+**/
+VOID
+ArchInitializeMpSupport (
+ VOID
+ )
+{
+ /* Nothing to do - ARM doesn't support EFI_MP_SERVICES_PROTOCOL */
+}
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.c b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
index 082ef30fb6c4..db8752f5b54f 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.c
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.c
@@ -279,5 +279,7 @@ CpuDxeInitialize (
);
ASSERT_EFI_ERROR (Status);

+ ArchInitializeMpSupport ();
+
return Status;
}
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.h b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
index 4cf3ab258c24..6e7ceafa4436 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.h
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.h
@@ -143,4 +143,14 @@ SetGcdMemorySpaceAttributes (
IN UINT64 Attributes
);

+VOID
+InitializeMpSupport (
+ VOID
+ );
+
+VOID
+ArchInitializeMpSupport (
+ VOID
+ );
+
#endif // CPU_DXE_H_
diff --git a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
index e5549fc71df7..f4cdb8ab5613 100644
--- a/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
+++ b/ArmPkg/Drivers/CpuDxe/CpuDxe.inf
@@ -26,10 +26,13 @@
Exception.c

[Sources.ARM]
+ Arm/Arch.c
Arm/Mmu.c

[Sources.AARCH64]
+ AArch64/Arch.c
AArch64/Mmu.c
+ CpuMpInit.c

[Packages]
ArmPkg/ArmPkg.dec
@@ -37,6 +40,9 @@
MdePkg/MdePkg.dec
MdeModulePkg/MdeModulePkg.dec

+[LibraryClasses.AARCH64]
+ MpInitLib
+
[LibraryClasses]
ArmLib
ArmMmuLib
diff --git a/ArmPkg/Drivers/CpuDxe/CpuMpInit.c b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c
new file mode 100644
index 000000000000..5bf4ed12b711
--- /dev/null
+++ b/ArmPkg/Drivers/CpuDxe/CpuMpInit.c
@@ -0,0 +1,604 @@
+/** @file
+ Construct MP Services Protocol.
+
+ The MP Services Protocol provides a generalized way of performing following tasks:
+ - Retrieving information of multi-processor environment and MP-related status of
+ specific processors.
+ - Dispatching user-provided function to APs.
+ - Maintain MP-related processor status.
+
+ The MP Services Protocol must be produced on any system with more than one logical
+ processor.
+
+ The Protocol is available only during boot time.
+
+ MP Services Protocol is hardware-independent. Most of the logic of this protocol
+ is architecturally neutral. It abstracts the multi-processor environment and
+ status of processors, and provides interfaces to retrieve information, maintain,
+ and dispatch.
+
+ MP Services Protocol may be consumed by ACPI module. The ACPI module may use this
+ protocol to retrieve data that are needed for an MP platform and report them to OS.
+ MP Services Protocol may also be used to program and configure processors, such
+ as MTRR synchronization for memory space attributes setting in DXE Services.
+ MP Services Protocol may be used by non-CPU DXE drivers to speed up platform boot
+ by taking advantage of the processing capabilities of the APs, for example, using
+ APs to help test system memory in parallel with other device initialization.
+ Diagnostics applications may also use this protocol for multi-processor.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ This function is used to retrieve the following information:
+ - The number of logical processors that are present in the system.
+ - The number of enabled logical processors in the system at the instant
+ this call is made.
+
+ Because MP Service Protocol provides services to enable and disable processors
+ dynamically, the number of enabled logical processors may vary during the
+ course of a boot session.
+
+ If this service is called from an AP, then EFI_DEVICE_ERROR is returned.
+ If NumberOfProcessors or NumberOfEnabledProcessors is NULL, then
+ EFI_INVALID_PARAMETER is returned. Otherwise, the total number of processors
+ is returned in NumberOfProcessors, the number of currently enabled processor
+ is returned in NumberOfEnabledProcessors, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ return MpInitLibGetNumberOfProcessors (
+ This,
+ NumberOfProcessors,
+ NumberOfEnabledProcessors
+ );
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ This service retrieves detailed MP-related information about any processor
+ on the platform. Note the following:
+ - The processor information may change during the course of a boot session.
+ - The information presented here is entirely MP related.
+
+ Information regarding the number of caches and their sizes, frequency of
+ operation, slot numbers is all considered platform-related information and is
+ not provided by this service.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorNumber The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+GetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ return MpInitLibGetProcessorInfo (
+ This,
+ ProcessorNumber,
+ ProcessorInfoBuffer
+ );
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ This function is used to dispatch all the enabled APs to the function
+ specified by Procedure. If any enabled AP is busy, then EFI_NOT_READY is
+ returned immediately and Procedure is not started on any AP.
+
+ If SingleThread is TRUE, all the enabled APs execute the function specified by
+ Procedure one by one, in ascending order of processor handle number.
+ Otherwise, all the enabled APs execute the function specified by Procedure
+ simultaneously.
+
+ If WaitEvent is NULL, execution is in blocking mode. The BSP waits until all
+ APs finish or TimeoutInMicroseconds expires. Otherwise, execution is in
+ non-blocking mode, and the BSP returns from this service without waiting for
+ APs. If a non-blocking mode is requested after the UEFI Event
+ EFI_EVENT_GROUP_READY_TO_BOOT is signaled, then EFI_UNSUPPORTED must be
+ returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before all APs
+ return from Procedure, then Procedure on the failed APs is terminated.
+ All enabled APs are always available for further calls to
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP(). If FailedCpuList is not NULL, its
+ content points to the list of processor handle numbers in which Procedure was
+ terminated.
+
+ Note: It is the responsibility of the consumer of the
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() to make sure that the nature of the
+ code that is executed on the BSP and the dispatched APs is well controlled.
+ The MP Services Protocol does not guarantee that the Procedure function is
+ MP-safe. Hence, the tasks that can be run in parallel are limited to certain
+ independent tasks and well-controlled exclusive code. EFI services and
+ protocols may not be called by APs unless otherwise specified.
+
+ In blocking execution mode, BSP waits until all APs finish or
+ TimeoutInMicroseconds expires.
+
+ In non-blocking execution mode, BSP is freed to return to the caller and then
+ proceed to the next task without having to wait for APs. The following
+ sequence needs to occur in a non-blocking execution mode:
+
+ -# The caller that intends to use this MP Services Protocol in non-blocking
+ mode creates WaitEvent by calling the EFI CreateEvent() service. The
+ caller invokes EFI_MP_SERVICES_PROTOCOL.StartupAllAPs(). If the parameter
+ WaitEvent is not NULL, then StartupAllAPs() executes in non-blocking
+ mode. It requests the function specified by Procedure to be started on
+ all the enabled APs, and releases the BSP to continue with other tasks.
+ -# The caller can use the CheckEvent() and WaitForEvent() services to check
+ the state of the WaitEvent created in step 1.
+ -# When the APs complete their task or TimeoutInMicroSecondss expires, the
+ MP Service signals WaitEvent by calling the EFI SignalEvent() function.
+ If FailedCpuList is not NULL, its content is available when WaitEvent is
+ signaled. If all APs returned from Procedure prior to the timeout, then
+ FailedCpuList is set to NULL. If not all APs return from Procedure before
+ the timeout, then FailedCpuList is filled in with the list of the failed
+ APs. The buffer is allocated by MP Service Protocol using AllocatePool().
+ It is the caller's responsibility to free the buffer with FreePool()
+ service.
+ -# This invocation of SignalEvent() function informs the caller that invoked
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() that either all the APs
+ completed the specified task or a timeout occurred. The contents of
+ FailedCpuList can be examined to determine which APs did not complete the
+ specified task prior to the timeout.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ return MpInitLibStartupAllAPs (
+ This,
+ Procedure,
+ SingleThread,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ This function is used to dispatch one enabled AP to the function specified by
+ Procedure passing in the argument specified by ProcedureArgument. If WaitEvent
+ is NULL, execution is in blocking mode. The BSP waits until the AP finishes or
+ TimeoutInMicroSecondss expires. Otherwise, execution is in non-blocking mode.
+ BSP proceeds to the next task without waiting for the AP. If a non-blocking mode
+ is requested after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled,
+ then EFI_UNSUPPORTED must be returned.
+
+ If the timeout specified by TimeoutInMicroseconds expires before the AP returns
+ from Procedure, then execution of Procedure by the AP is terminated. The AP is
+ available for subsequent calls to EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() and
+ EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+StartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ return MpInitLibStartupThisAP (
+ This,
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. The new BSP can take over the
+ execution of the old BSP and continue seamlessly from where the old one left
+ off. This service may not be supported after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT
+ is signaled.
+
+ If the BSP cannot be switched prior to the return from this service, then
+ EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+SwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return MpInitLibSwitchBSP (This, ProcessorNumber, EnableOldBSP);
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ This service allows the caller enable or disable an AP from this point onward.
+ The caller can optionally specify the health status of the AP by Health. If
+ an AP is being disabled, then the state of the disabled AP is implementation
+ dependent. If an AP is enabled, then the implementation must guarantee that a
+ complete initialization sequence is performed on the AP, so the AP is in a state
+ that is compatible with an MP operating system. This service may not be supported
+ after the UEFI Event EFI_EVENT_GROUP_READY_TO_BOOT is signaled.
+
+ If the enable or disable AP operation cannot be completed prior to the return
+ from this service, then EFI_UNSUPPORTED must be returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+EnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return MpInitLibEnableDisableAP (This, ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ This service returns the processor handle number for the calling processor.
+ The returned value is in the range from 0 to the total number of logical
+ processors minus 1. The total number of logical processors can be retrieved
+ with EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors(). This service may be
+ called from the BSP and APs. If ProcessorNumber is NULL, then EFI_INVALID_PARAMETER
+ is returned. Otherwise, the current processors handle number is returned in
+ ProcessorNumber, and EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+WhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ return MpInitLibWhoAmI (This, ProcessorNumber);
+}
+
+EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate = {
+ GetNumberOfProcessors,
+ GetProcessorInfo,
+ StartupAllAPs,
+ StartupThisAP,
+ SwitchBSP,
+ EnableDisableAP,
+ WhoAmI
+};
+
+/** Initialize multi-processor support.
+
+**/
+VOID
+InitializeMpSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ UINTN MaxCpus;
+ EFI_HOB_GENERIC_HEADER *Hob;
+ VOID *HobData;
+ UINTN HobDataSize;
+ ARM_PROCESSOR_TABLE CpuInfo;
+
+ DEBUG ((DEBUG_INFO, "Starting MP services"));
+
+ Hob = GetFirstGuidHob (&gArmMpCoreInfoGuid);
+ if (Hob != NULL) {
+ HobData = GET_GUID_HOB_DATA (Hob);
+ HobDataSize = GET_GUID_HOB_DATA_SIZE (Hob);
+ CpuInfo.ArmCpus = (ARM_CORE_INFO *)HobData;
+ CpuInfo.NumberOfEntries = HobDataSize / sizeof (ARM_CORE_INFO);
+ MaxCpus = CpuInfo.NumberOfEntries;
+ }
+
+ if (MaxCpus == 1) {
+ DEBUG ((DEBUG_WARN, "Trying to use EFI_MP_SERVICES_PROTOCOL on a UP system"));
+ // We are not MP so nothing to do
+ return;
+ }
+
+ MpInitLibInitialize (MaxCpus, &CpuInfo);
+
+ //
+ // Now install the MP services protocol.
+ //
+ Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Handle,
+ &gEfiMpServiceProtocolGuid,
+ &mMpServicesTemplate,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
diff --git a/ArmPkg/Include/Library/MpInitLib.h b/ArmPkg/Include/Library/MpInitLib.h
new file mode 100644
index 000000000000..a4b80c18a9e8
--- /dev/null
+++ b/ArmPkg/Include/Library/MpInitLib.h
@@ -0,0 +1,366 @@
+/** @file
+
+Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2011, Apple Inc. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INITLIB_H_
+#define MP_INITLIB_H_
+
+#include <Protocol/Cpu.h>
+#include <Protocol/MpService.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Guid/ArmMpCoreInfo.h>
+
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorIndex The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ );
+
+/** Initializes the MP Services system data
+
+ @param NumberOfProcessors The number of processors, both BSP and AP.
+ @param CpuInfo CPU information gathered earlier during boot.
+
+**/
+VOID
+MpInitLibInitialize (
+ IN UINTN NumberOfProcessors,
+ IN ARM_PROCESSOR_TABLE *CpuInfo
+ );
+
+
+
+#endif /* MP_INITLIB_H_ */
diff --git a/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
new file mode 100644
index 000000000000..287db060e594
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
@@ -0,0 +1,61 @@
+#===============================================================================
+# Copyright (c) 2021 NUVIA Inc. All rights reserved.
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#===============================================================================
+
+.text
+.align 3
+
+#include <AsmMacroIoLibV8.h>
+#include <IndustryStandard/ArmStdSmc.h>
+
+#include "InternalMpInitLib.h"
+
+GCC_ASM_IMPORT (gApStacksBase)
+GCC_ASM_IMPORT (gProcessorIDs)
+GCC_ASM_IMPORT (ApProcedure)
+GCC_ASM_IMPORT (gApStackSize)
+
+GCC_ASM_EXPORT (ApEntryPoint)
+
+StartupAddr: .8byte ASM_PFX(ApProcedure)
+
+// Entry-point for the AP
+// VOID
+// ApEntryPoint (
+// VOID
+// );
+ASM_PFX(ApEntryPoint):
+ mrs x0, mpidr_el1
+ ldr x1, gProcessorIDs
+ mov x2, 0 // x2 = processor index
+ mov x3, 0 // x3 = address offset
+
+// Find index in gProcessorIDs for current processor
+1:
+ ldr x4, [x1, x3] // x4 = gProcessorIDs + x3
+ cmp x4, 0 // check if we've reached the end of gProcessorIDs
+ beq ProcessorNotFound
+ add x3, x3, 8 // x3 += sizeof (*gProcessorIDs)
+ add x2, x2, 1 // x2++
+ cmp x0, x4 // if mpidr_el1 != *(gProcessorIDs + x3) then loop
+ bne 1b
+ sub x2, x2, 1
+
+// Calculate stack address
+ // x2 contains the index for the current processor
+ ldr x0, gApStacksBase
+ ldr x1, gApStackSize
+ mul x3, x2, x1 // x3 = ProcessorIndex * gApStackSize
+ add x4, x0, x3 // x4 = gApStacksBase + x3
+ add sp, x4, x1 // sp = x4 + gApStackSize
+
+ ldr x0, StartupAddr // ASM_PFX(ApProcedure)
+ blr x0 // doesn't return
+
+ProcessorNotFound:
+// Turn off the processor
+ MOV32 (w0, ARM_SMC_ID_PSCI_CPU_OFF)
+ smc #0
+ b .
diff --git a/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
new file mode 100644
index 000000000000..2275b6cca33a
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -0,0 +1,53 @@
+#/** @file
+#
+# Component description file for the DxeMpInitLib module.
+#
+# Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#**/
+
+[Defines]
+ INF_VERSION = 1.29
+ BASE_NAME = DxeMpInitLib
+ FILE_GUID = c9ca773c-8ae4-4b74-82fd-f7345503294e
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MpInitLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = AARCH64
+#
+
+[Sources.AARCH64]
+ AArch64/MpFuncs.S
+
+[Sources]
+ DxeMpLib.c
+ InternalMpInitLib.h
+
+[Packages]
+ ArmPkg/ArmPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ MdePkg/MdePkg.dec
+
+[LibraryClasses]
+ ArmLib
+ ArmSmcLib
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ HobLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Protocols]
+ gEfiMpServiceProtocolGuid
+
+[Guids]
+ gArmMpCoreInfoGuid
diff --git a/ArmPkg/Library/MpInitLib/DxeMpLib.c b/ArmPkg/Library/MpInitLib/DxeMpLib.c
new file mode 100644
index 000000000000..6053db740624
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/DxeMpLib.c
@@ -0,0 +1,1498 @@
+/** @file
+ Construct MP Services Protocol.
+
+ Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+ Portions Copyright (c) 2011, Apple Inc. All rights reserved.
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Ppi/ArmMpCoreInfo.h>
+#include <Library/ArmLib.h>
+#include <Library/ArmSmcLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/MpInitLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <IndustryStandard/ArmStdSmc.h>
+
+#include "InternalMpInitLib.h"
+
+#define POLL_INTERVAL_US 50000
+
+STATIC CPU_MP_DATA mCpuMpData;
+STATIC BOOLEAN mNonBlockingModeAllowed;
+UINT64 *gApStacksBase;
+UINT64 *gProcessorIDs;
+CONST UINT64 gApStackSize = AP_STACK_SIZE;
+
+/** C entry-point for the AP.
+ This function gets called from the assembly function ApEntryPoint.
+
+**/
+VOID
+ApProcedure (
+ VOID
+ )
+{
+ ARM_SMC_ARGS Args;
+ EFI_AP_PROCEDURE ApProcedure;
+ VOID *ApParameter;
+ UINTN ProcessorIndex;
+
+ MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex);
+
+ /* Fetch the user-supplied procedure and parameter to execute */
+ ApProcedure = mCpuMpData.CpuData[ProcessorIndex].Procedure;
+ ApParameter = mCpuMpData.CpuData[ProcessorIndex].Parameter;
+
+ ApProcedure (ApParameter);
+
+ mCpuMpData.CpuData[ProcessorIndex].State = CpuStateFinished;
+
+ /* Since we're finished with this AP, turn it off */
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_OFF;
+ ArmCallSmc (&Args);
+
+ /* Should never be reached */
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+}
+
+/** Turns on the specified core using PSCI and executes the user-supplied
+ function that's been configured via a previous call to SetApProcedure.
+
+ @param ProcessorIndex The index of the core to turn on.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_DEVICE_ERROR The processor could not be turned on.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+DispatchCpu (
+ IN UINTN ProcessorIndex
+ )
+{
+ ARM_SMC_ARGS Args;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+
+ mCpuMpData.CpuData[ProcessorIndex].State = CpuStateBusy;
+
+ /* Turn the AP on */
+ if (sizeof (Args.Arg0) == sizeof (UINT32)) {
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH32;
+ } else {
+ Args.Arg0 = ARM_SMC_ID_PSCI_CPU_ON_AARCH64;
+ }
+ Args.Arg1 = gProcessorIDs[ProcessorIndex];
+ Args.Arg2 = (UINTN)ApEntryPoint;
+
+ ArmCallSmc (&Args);
+
+ if (Args.Arg0 != ARM_SMC_PSCI_RET_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "PSCI_CPU_ON call failed: %d", Args.Arg0));
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/** Returns whether the specified processor is the BSP.
+
+ @param[in] ProcessorIndex The index the processor to check.
+
+ @return TRUE if the processor is the BSP, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorBSP (
+ UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ return (CpuInfo->StatusFlag & PROCESSOR_AS_BSP_BIT) != 0;
+}
+
+/** Returns whether the processor executing this function is the BSP.
+
+ @return Whether the current processor is the BSP.
+**/
+STATIC
+BOOLEAN
+IsCurrentProcessorBSP (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorIndex;
+
+ Status = MpInitLibWhoAmI (&mMpServicesTemplate, &ProcessorIndex);
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return IsProcessorBSP (ProcessorIndex);
+}
+
+/** Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP.
+
+ @return The AP status.
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ )
+{
+ return CpuData->State;
+}
+
+/** Configures the processor context with the user-supplied procedure and
+ argument.
+
+ @param CpuData The processor context.
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+
+**/
+STATIC
+VOID
+SetApProcedure (
+ IN CPU_AP_DATA *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ )
+{
+ ASSERT (CpuData != NULL);
+ ASSERT (Procedure != NULL);
+
+ CpuData->Parameter = ProcedureArgument;
+ CpuData->Procedure = Procedure;
+}
+
+/** Returns the index of the next processor that is blocked.
+
+ @param[out] NextNumber The index of the next blocked processor.
+
+ @retval EFI_SUCCESS Successfully found the next blocked processor.
+ @retval EFI_NOT_FOUND There are no blocked processors.
+
+**/
+STATIC
+EFI_STATUS
+GetNextBlockedNumber (
+ OUT UINTN *NextNumber
+ )
+{
+ UINTN Index;
+ CPU_STATE State;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ State = CpuData->State;
+
+ if (State == CpuStateBlocked) {
+ *NextNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/** Stalls the BSP for the minimum of POLL_INTERVAL_US and Timeout.
+
+ @param[in] Timeout The time limit in microseconds remaining for
+ APs to return from Procedure.
+
+ @retval StallTime Time of execution stall.
+**/
+STATIC
+UINTN
+CalculateAndStallInterval (
+ IN UINTN Timeout
+ )
+{
+ UINTN StallTime;
+
+ if (Timeout < POLL_INTERVAL_US && Timeout != 0) {
+ StallTime = Timeout;
+ } else {
+ StallTime = POLL_INTERVAL_US;
+ }
+
+ gBS->Stall (StallTime);
+
+ return StallTime;
+}
+
+/**
+ This service retrieves the number of logical processor in the platform
+ and the number of those logical processors that are enabled on this boot.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the
+ EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] NumberOfProcessors Pointer to the total number of logical
+ processors in the system, including
+ the BSP and disabled APs.
+ @param[out] NumberOfEnabledProcessors Pointer to the number of enabled
+ logical processors that exist in the
+ system, including the BSP.
+
+ @retval EFI_SUCCESS The number of logical processors and enabled
+ logical processors was retrieved.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER NumberOfProcessors is NULL.
+ @retval EFI_INVALID_PARAMETER NumberOfEnabledProcessors is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *NumberOfProcessors,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ if ((NumberOfProcessors == NULL) || (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ *NumberOfProcessors = mCpuMpData.NumberOfProcessors;
+ *NumberOfEnabledProcessors = mCpuMpData.NumberOfEnabledProcessors;
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] ProcessorIndex The index of the processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information
+ for the requested processor is deposited.
+
+ @retval EFI_SUCCESS Processor information was returned.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_INVALID_PARAMETER ProcessorInfoBuffer is NULL.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist in the platform.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorIndex,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorIndex &= ~CPU_V2_EXTENDED_TOPOLOGY;
+
+ if (ProcessorIndex >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ CopyMem (
+ ProcessorInfoBuffer,
+ &mCpuMpData.CpuData[ProcessorIndex],
+ sizeof (EFI_PROCESSOR_INFORMATION)
+ );
+ return EFI_SUCCESS;
+}
+
+/** Returns whether the specified processor is enabled.
+
+ @param[in] ProcessorIndex The index of the processor to check.
+
+ @return TRUE if the processor is enabled, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorEnabled (
+ UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ return (CpuInfo->StatusFlag & PROCESSOR_ENABLED_BIT) != 0;
+}
+
+/** Returns whether all processors are in the idle state.
+
+ @return Whether all the processors are idle.
+
+**/
+STATIC
+BOOLEAN
+CheckAllCpusReady (
+ VOID
+ )
+{
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/** Sets up the state for the StartupAllAPs function.
+
+ @param SingleThread Whether the APs will execute sequentially.
+
+**/
+STATIC
+VOID
+StartupAllAPsPrepareState (
+ IN BOOLEAN SingleThread
+ )
+{
+ UINTN Index;
+ CPU_STATE APInitialState;
+ CPU_AP_DATA *CpuData;
+
+ mCpuMpData.FinishCount = 0;
+ mCpuMpData.StartCount = 0;
+ mCpuMpData.SingleThread = SingleThread;
+
+ APInitialState = CpuStateReady;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+
+ //
+ // Get APs prepared, and put failing APs into FailedCpuList.
+ // If "SingleThread", only 1 AP will put into ready state, other AP will be
+ // put into ready state 1 by 1, until the previous 1 finished its task.
+ // If not "SingleThread", all APs are put into ready state from the
+ // beginning
+ //
+
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ if (mCpuMpData.FailedList != NULL) {
+ mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
+ }
+
+ continue;
+ }
+
+ ASSERT (GetApState (CpuData) == CpuStateIdle);
+ CpuData->State = APInitialState;
+
+ mCpuMpData.StartCount++;
+ if (SingleThread) {
+ APInitialState = CpuStateBlocked;
+ }
+ }
+}
+
+/** Handles execution of StartupAllAPs when a WaitEvent has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param WaitEvent The wait event to be signaled when the work is
+ complete or a timeout has occurred.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsWithWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN EFI_EVENT WaitEvent,
+ IN UINTN TimeoutInMicroseconds
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ if (GetApState (CpuData) == CpuStateReady) {
+ SetApProcedure (CpuData, Procedure, ProcedureArgument);
+ }
+ }
+
+ //
+ // Save data into private data structure, and create timer to poll AP state
+ // before exiting
+ //
+ mCpuMpData.Procedure = Procedure;
+ mCpuMpData.ProcedureArgument = ProcedureArgument;
+ mCpuMpData.WaitEvent = WaitEvent;
+ mCpuMpData.Timeout = TimeoutInMicroseconds;
+ mCpuMpData.TimeoutActive = (BOOLEAN)(TimeoutInMicroseconds != 0);
+ Status = gBS->SetTimer (
+ mCpuMpData.CheckAllAPsEvent,
+ TimerPeriodic,
+ POLL_INTERVAL_US
+ );
+ return Status;
+}
+
+/** Handles execution of StartupAllAPs when no wait event has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+ @param SingleThread Whether the APs will execute sequentially.
+ @param FailedCpuList User-supplied pointer for list of failed CPUs.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsNoWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN UINTN TimeoutInMicroseconds,
+ IN BOOLEAN SingleThread,
+ IN UINTN **FailedCpuList
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NextIndex;
+ UINTN Timeout;
+ CPU_AP_DATA *CpuData;
+
+ Timeout = TimeoutInMicroseconds;
+
+ while (TRUE) {
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ switch (GetApState (CpuData)) {
+ case CpuStateReady:
+ SetApProcedure (CpuData, Procedure, ProcedureArgument);
+ Status = DispatchCpu (Index);
+ if (EFI_ERROR (Status)) {
+ CpuData->State = CpuStateIdle;
+ Status = EFI_NOT_READY;
+ goto Done;
+ }
+
+ break;
+
+ case CpuStateFinished:
+ mCpuMpData.FinishCount++;
+ if (SingleThread) {
+ Status = GetNextBlockedNumber (&NextIndex);
+ if (!EFI_ERROR (Status)) {
+ mCpuMpData.CpuData[NextIndex].State = CpuStateReady;
+ }
+ }
+
+ CpuData->State = CpuStateIdle;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ if (mCpuMpData.FinishCount == mCpuMpData.StartCount) {
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+
+ if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
+ Status = EFI_TIMEOUT;
+ goto Done;
+ }
+
+ Timeout -= CalculateAndStallInterval (Timeout);
+ }
+
+Done:
+ if (FailedCpuList != NULL) {
+ if (mCpuMpData.FailedListIndex == 0) {
+ FreePool (*FailedCpuList);
+ *FailedCpuList = NULL;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ This service executes a caller provided function on all enabled APs. APs can
+ run either simultaneously or one at a time in sequence. This service supports
+ both blocking and non-blocking requests. The non-blocking requests use EFI
+ events so the BSP can detect when the APs have finished. This service may only
+ be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] SingleThread If TRUE, then all the enabled APs execute
+ the function specified by Procedure one by
+ one, in ascending order of processor
+ handle number. If FALSE, then all the
+ enabled APs execute the function specified
+ by Procedure simultaneously.
+ @param[in] WaitEvent The event created by the caller with
+ CreateEvent() service. If it is NULL,
+ then execute in blocking mode. BSP waits
+ until all APs finish or
+ TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking
+ mode. BSP requests the function specified
+ by Procedure to be started on all the
+ enabled APs, and go on executing
+ immediately. If all return from Procedure,
+ or TimeoutInMicroseconds expires, this
+ event is signaled. The BSP can use the
+ CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds
+ for APs to return from Procedure, either
+ for blocking or non-blocking mode. Zero
+ means infinity. If the timeout expires
+ before all APs return from Procedure, then
+ Procedure on the failed APs is terminated.
+ All enabled APs are available for next
+ function assigned by
+ EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList If NULL, this parameter is ignored.
+ Otherwise, if all APs finish successfully,
+ then its content is set to NULL. If not
+ all APs finish before timeout expires,
+ then its content is set to address of the
+ buffer holding handle numbers of the
+ failed APs.
+ The buffer is allocated by MP Service
+ Protocol, and it's the caller's
+ responsibility to free the buffer with
+ FreePool() service.
+ In blocking mode, it is ready for
+ consumption when the call returns. In
+ non-blocking mode, it is ready when
+ WaitEvent is signaled. The list of failed
+ CPU is terminated by END_OF_CPU_LIST.
+
+ @retval EFI_SUCCESS In blocking mode, all APs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been
+ dispatched to all enabled APs.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_STARTED No enabled APs exist in the system.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ all enabled APs have finished.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllAPs (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mCpuMpData.NumberOfProcessors == 1) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!CheckAllCpusReady ()) {
+ return EFI_NOT_READY;
+ }
+
+ if (FailedCpuList != NULL) {
+ mCpuMpData.FailedList = AllocatePool (
+ (mCpuMpData.NumberOfProcessors + 1) *
+ sizeof (UINTN)
+ );
+ if (mCpuMpData.FailedList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SetMemN (
+ mCpuMpData.FailedList,
+ (mCpuMpData.NumberOfProcessors + 1) *
+ sizeof (UINTN),
+ END_OF_CPU_LIST
+ );
+ mCpuMpData.FailedListIndex = 0;
+ *FailedCpuList = mCpuMpData.FailedList;
+ }
+
+ StartupAllAPsPrepareState (SingleThread);
+
+ if (WaitEvent != NULL) {
+ Status = StartupAllAPsWithWaitEvent (
+ Procedure,
+ ProcedureArgument,
+ WaitEvent,
+ TimeoutInMicroseconds
+ );
+ } else {
+ Status = StartupAllAPsNoWaitEvent (
+ Procedure,
+ ProcedureArgument,
+ TimeoutInMicroseconds,
+ SingleThread,
+ FailedCpuList
+ );
+ }
+
+ return Status;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function. The caller can request the BSP to either wait for the completion
+ of the AP or just proceed with the next task by using the EFI event mechanism.
+ See EFI_MP_SERVICES_PROTOCOL.StartupAllAPs() for more details on non-blocking
+ execution support. This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL
+ instance.
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @param[in] ProcessorNumber The handle number of the AP. The range is
+ from 0 to the total number of logical
+ processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until all APs finish
+ or TimeoutInMicroseconds expires. If it's
+ not NULL, then execute in non-blocking mode.
+ BSP requests the function specified by
+ Procedure to be started on all the enabled
+ APs, and go on executing immediately. If
+ all return from Procedure or TimeoutInMicroseconds
+ expires, this event is signaled. The BSP
+ can use the CheckEvent() or WaitForEvent()
+ services to check the state of event. Type
+ EFI_EVENT is defined in CreateEvent() in
+ the Unified Extensible Firmware Interface
+ Specification.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ all APs return from Procedure, then Procedure
+ on the failed APs is terminated. All enabled
+ APs are available for next function assigned
+ by EFI_MP_SERVICES_PROTOCOL.StartupAllAPs()
+ or EFI_MP_SERVICES_PROTOCOL.StartupThisAP().
+ If the timeout expires in blocking mode,
+ BSP returns EFI_TIMEOUT. If the timeout
+ expires in non-blocking mode, WaitEvent
+ is signaled with SignalEvent().
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If NULL, this parameter is ignored. In
+ blocking mode, this parameter is ignored.
+ In non-blocking mode, if AP returns from
+ Procedure before the timeout expires, its
+ content is set to TRUE. Otherwise, the
+ value is set to FALSE. The caller can
+ determine if the AP returned from Procedure
+ by evaluating this value.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval EFI_SUCCESS In non-blocking mode, the function has been
+ dispatched to specified AP.
+ @retval EFI_UNSUPPORTED A non-blocking mode request was made after the
+ UEFI event EFI_EVENT_GROUP_READY_TO_BOOT was
+ signaled.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_TIMEOUT In blocking mode, the timeout expired before
+ the specified AP has finished.
+ @retval EFI_NOT_READY The specified AP is busy.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP or disabled AP.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupThisAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Timeout;
+ CPU_AP_DATA *CpuData;
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_NOT_READY;
+ }
+
+ if ((WaitEvent != NULL) && !mNonBlockingModeAllowed) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Timeout = TimeoutInMicroseconds;
+
+ mCpuMpData.StartCount = 1;
+ mCpuMpData.FinishCount = 0;
+
+ SetApProcedure (
+ CpuData,
+ Procedure,
+ ProcedureArgument
+ );
+
+ Status = DispatchCpu (ProcessorNumber);
+ if (EFI_ERROR (Status)) {
+ CpuData->State = CpuStateIdle;
+ return EFI_NOT_READY;
+ }
+
+ if (WaitEvent != NULL) {
+ // Non Blocking
+ mCpuMpData.WaitEvent = WaitEvent;
+ gBS->SetTimer (
+ CpuData->CheckThisAPEvent,
+ TimerPeriodic,
+ POLL_INTERVAL_US
+ );
+ return EFI_SUCCESS;
+ }
+
+ // Blocking
+ while (TRUE) {
+ if (GetApState (CpuData) == CpuStateFinished) {
+ CpuData->State = CpuStateIdle;
+ break;
+ }
+
+ if ((TimeoutInMicroseconds != 0) && (Timeout == 0)) {
+ return EFI_TIMEOUT;
+ }
+
+ Timeout -= CalculateAndStallInterval (Timeout);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This service switches the requested AP to be the BSP from that point onward.
+ This service changes the BSP for all purposes. This call can only be
+ performed by the current BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableOldBSP If TRUE, then the old BSP will be listed as an
+ enabled AP. Otherwise, it will be disabled.
+
+ @retval EFI_SUCCESS BSP successfully switched.
+ @retval EFI_UNSUPPORTED Switching the BSP cannot be completed prior to
+ this service returning.
+ @retval EFI_UNSUPPORTED Switching the BSP is not supported.
+ @retval EFI_SUCCESS The calling processor is an AP.
+ @retval EFI_NOT_FOUND The processor with the handle specified by
+ ProcessorNumber does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the current BSP or
+ a disabled AP.
+ @retval EFI_NOT_READY The specified AP is busy.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (IsProcessorBSP (Index)) {
+ break;
+ }
+ }
+
+ ASSERT (Index != mCpuMpData.NumberOfProcessors);
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_NOT_READY;
+ }
+
+ // Skip for now as we need switch a bunch of stack stuff around and it's
+ // complex. May not be worth it?
+ return EFI_NOT_READY;
+}
+
+/**
+ This service lets the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[in] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+ @param[in] EnableAP Specifies the new state for the processor for
+ enabled, FALSE for disabled.
+ @param[in] HealthFlag If not NULL, a pointer to a value that specifies
+ the new health status of the AP. This flag
+ corresponds to StatusFlag defined in
+ EFI_MP_SERVICES_PROTOCOL.GetProcessorInfo(). Only
+ the PROCESSOR_HEALTH_STATUS_BIT is used. All other
+ bits are ignored. If it is NULL, this parameter
+ is ignored.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP cannot be completed
+ prior to this service returning.
+ @retval EFI_UNSUPPORTED Enabling or disabling an AP is not supported.
+ @retval EFI_DEVICE_ERROR The calling processor is an AP.
+ @retval EFI_NOT_FOUND Processor with the handle specified by ProcessorNumber
+ does not exist.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber specifies the BSP.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ UINTN StatusFlag;
+ CPU_AP_DATA *CpuData;
+
+ StatusFlag = mCpuMpData.CpuData[ProcessorNumber].Info.StatusFlag;
+ CpuData = &mCpuMpData.CpuData[ProcessorNumber];
+
+ if (!IsCurrentProcessorBSP ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= mCpuMpData.NumberOfProcessors) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (IsProcessorBSP (ProcessorNumber)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (GetApState (CpuData) != CpuStateIdle) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (EnableAP) {
+ if (!IsProcessorEnabled (ProcessorNumber)) {
+ mCpuMpData.NumberOfEnabledProcessors++;
+ }
+
+ StatusFlag |= PROCESSOR_ENABLED_BIT;
+ } else {
+ if (IsProcessorEnabled (ProcessorNumber)) {
+ mCpuMpData.NumberOfEnabledProcessors--;
+ }
+
+ StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ }
+
+ if (HealthFlag != NULL) {
+ StatusFlag &= ~PROCESSOR_HEALTH_STATUS_BIT;
+ StatusFlag |= (*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[in] This A pointer to the EFI_MP_SERVICES_PROTOCOL instance.
+ @param[out] ProcessorNumber The handle number of AP that is to become the new
+ BSP. The range is from 0 to the total number of
+ logical processors minus 1. The total number of
+ logical processors can be retrieved by
+ EFI_MP_SERVICES_PROTOCOL.GetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ IN EFI_MP_SERVICES_PROTOCOL *This,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN Index;
+ UINT64 ProcessorId;
+ CPU_AP_DATA *CpuData;
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ProcessorId = ArmReadMpidr ();
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (CpuData->Info.ProcessorId == ProcessorId) {
+ break;
+ }
+ }
+
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+}
+
+/** Adds the specified processor the list of failed processors.
+
+ @param ProcessorIndex The processor index to add.
+ @param ApState Processor state.
+
+**/
+STATIC
+VOID
+AddProcessorToFailedList (
+ UINTN ProcessorIndex,
+ CPU_STATE ApState
+ )
+{
+ UINTN Index;
+ BOOLEAN Found;
+
+ Found = FALSE;
+
+ if (ApState == CpuStateIdle) {
+ return;
+ }
+
+ // If we are retrying make sure we don't double count
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (mCpuMpData.FailedList[Index] == END_OF_CPU_LIST) {
+ break;
+ }
+
+ if (mCpuMpData.FailedList[ProcessorIndex] == Index) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ /* If the CPU isn't already in the FailedList, add it */
+ if (!Found) {
+ mCpuMpData.FailedList[mCpuMpData.FailedListIndex++] = Index;
+ }
+}
+
+/** Handles the StartupAllAPs case where the timeout has occurred.
+
+**/
+STATIC
+VOID
+ProcessStartupAllAPsTimeout (
+ VOID
+ )
+{
+ CPU_AP_DATA *CpuData;
+ UINTN Index;
+
+ if (mCpuMpData.FailedList == NULL) {
+ return;
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ CpuData = &mCpuMpData.CpuData[Index];
+ if (IsProcessorBSP (Index)) {
+ // Skip BSP
+ continue;
+ }
+
+ if (!IsProcessorEnabled (Index)) {
+ // Skip Disabled processors
+ continue;
+ }
+
+ AddProcessorToFailedList (Index, GetApState (CpuData));
+ }
+}
+
+/** Updates the status of the APs.
+
+ @param[in] ProcessorIndex The index of the AP to update.
+**/
+STATIC
+VOID
+UpdateApStatus (
+ IN UINTN ProcessorIndex
+ )
+{
+ EFI_STATUS Status;
+ CPU_AP_DATA *CpuData;
+ CPU_AP_DATA *NextCpuData;
+ CPU_STATE State;
+ UINTN NextNumber;
+
+ CpuData = &mCpuMpData.CpuData[ProcessorIndex];
+
+ if (IsProcessorBSP (ProcessorIndex)) {
+ // Skip BSP
+ return;
+ }
+
+ if (!IsProcessorEnabled (ProcessorIndex)) {
+ // Skip Disabled processors
+ return;
+ }
+
+ State = GetApState (CpuData);
+
+ switch (State) {
+ case CpuStateFinished:
+ if (mCpuMpData.SingleThread) {
+ Status = GetNextBlockedNumber (&NextNumber);
+ if (!EFI_ERROR (Status)) {
+ NextCpuData = &mCpuMpData.CpuData[NextNumber];
+
+ NextCpuData->State = CpuStateReady;
+
+ SetApProcedure (
+ NextCpuData,
+ mCpuMpData.Procedure,
+ mCpuMpData.ProcedureArgument
+ );
+ }
+ }
+
+ CpuData->State = CpuStateIdle;
+ mCpuMpData.FinishCount++;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ If a timeout is specified in StartupAllAps(), a timer is set, which invokes
+ this procedure periodically to check whether all APs have finished.
+
+ @param[in] Event The WaitEvent the user supplied.
+ @param[in] Context The event context.
+**/
+STATIC
+VOID
+EFIAPI
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ UINTN Index;
+
+ if (mCpuMpData.TimeoutActive) {
+ mCpuMpData.Timeout -= CalculateAndStallInterval (mCpuMpData.Timeout);
+ }
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ UpdateApStatus (Index);
+ }
+
+ if (mCpuMpData.TimeoutActive && mCpuMpData.Timeout == 0) {
+ ProcessStartupAllAPsTimeout ();
+
+ // Force terminal exit
+ mCpuMpData.FinishCount = mCpuMpData.StartCount;
+ }
+
+ if (mCpuMpData.FinishCount != mCpuMpData.StartCount) {
+ return;
+ }
+
+ gBS->SetTimer (
+ mCpuMpData.CheckAllAPsEvent,
+ TimerCancel,
+ 0
+ );
+
+ if (mCpuMpData.FailedListIndex == 0) {
+ if (mCpuMpData.FailedList != NULL) {
+ FreePool (mCpuMpData.FailedList);
+ mCpuMpData.FailedList = NULL;
+ }
+ }
+
+ gBS->SignalEvent (mCpuMpData.WaitEvent);
+}
+
+/** Invoked periodically via a timer to check the state of the processor.
+
+ @param Event The event supplied by the timer expiration.
+ @param Context The processor context.
+
+**/
+STATIC
+VOID
+EFIAPI
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ CPU_AP_DATA *CpuData;
+ CPU_STATE State;
+
+ CpuData = Context;
+ CpuData->TimeTaken += POLL_INTERVAL_US;
+
+ State = GetApState (CpuData);
+
+ if (State == CpuStateFinished) {
+ Status = gBS->SetTimer (CpuData->CheckThisAPEvent, TimerCancel, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ if (mCpuMpData.WaitEvent != NULL) {
+ Status = gBS->SignalEvent (mCpuMpData.WaitEvent);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ CpuData->State = CpuStateIdle;
+ }
+
+ if (CpuData->TimeTaken > CpuData->Timeout) {
+ if (mCpuMpData.WaitEvent != NULL) {
+ Status = gBS->SignalEvent (mCpuMpData.WaitEvent);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects
+ MP related data.
+
+ @param BSP TRUE if the processor is the BSP.
+ @param Mpidr The MPIDR for the specified processor.
+ @param ProcessorIndex The index of the processor.
+
+ @return EFI_SUCCESS if the data for the processor collected and filled in.
+
+**/
+STATIC
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINTN Mpidr,
+ IN UINTN ProcessorIndex
+ )
+{
+ EFI_PROCESSOR_INFORMATION *CpuInfo;
+
+ CpuInfo = &mCpuMpData.CpuData[ProcessorIndex].Info;
+
+ /* The MPIDR passed in may be a pseudo-MPIDR that's missing the bit 31 RES1.
+ * Fix it so it's a proper MPIDR.
+ */
+ CpuInfo->ProcessorId = BIT31 | Mpidr;
+ CpuInfo->StatusFlag = PROCESSOR_ENABLED_BIT | PROCESSOR_HEALTH_STATUS_BIT;
+
+ if (BSP) {
+ CpuInfo->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+
+ CpuInfo->Location.Package = GET_CLUSTER_ID (Mpidr);
+ CpuInfo->Location.Core = GET_CORE_ID (Mpidr);
+ CpuInfo->Location.Thread = 0;
+
+ CpuInfo->ExtendedInformation.Location2.Package = 0;
+ CpuInfo->ExtendedInformation.Location2.Module = 0;
+ CpuInfo->ExtendedInformation.Location2.Tile = 0;
+ CpuInfo->ExtendedInformation.Location2.Die = GET_CLUSTER_ID (Mpidr);
+ CpuInfo->ExtendedInformation.Location2.Core = GET_CORE_ID (Mpidr);
+ CpuInfo->ExtendedInformation.Location2.Thread = 0;
+
+ mCpuMpData.CpuData[ProcessorIndex].State = BSP ? CpuStateBusy : CpuStateIdle;
+
+ mCpuMpData.CpuData[ProcessorIndex].Procedure = NULL;
+ mCpuMpData.CpuData[ProcessorIndex].Parameter = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/** Initializes the MP Services system data
+
+ @param NumberOfProcessors The number of processors, both BSP and AP.
+ @param CpuInfo CPU information gathered earlier during boot.
+
+**/
+VOID
+MpInitLibInitialize (
+ IN UINTN NumberOfProcessors,
+ IN ARM_PROCESSOR_TABLE *CpuInfo
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_EVENT ReadyToBootEvent;
+
+ //
+ // Clear the data structure area first.
+ //
+ ZeroMem (&mCpuMpData, sizeof (CPU_MP_DATA));
+ //
+ // First BSP fills and inits all known values, including its own records.
+ //
+ mCpuMpData.NumberOfProcessors = NumberOfProcessors;
+ mCpuMpData.NumberOfEnabledProcessors = NumberOfProcessors;
+
+ mCpuMpData.CpuData = AllocateZeroPool (
+ mCpuMpData.NumberOfProcessors *
+ sizeof (CPU_AP_DATA)
+ );
+ ASSERT (mCpuMpData.CpuData != NULL);
+
+ /* Allocate one extra for the NULL entry at the end */
+ gProcessorIDs = AllocatePool ((mCpuMpData.NumberOfProcessors + 1) * sizeof (UINT64));
+ ASSERT (gProcessorIDs != NULL);
+
+ FillInProcessorInformation (TRUE, CpuInfo->ArmCpus[0].Mpidr, 0);
+ gProcessorIDs[0] = mCpuMpData.CpuData[0].Info.ProcessorId;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ CheckAllAPsStatus,
+ NULL,
+ &mCpuMpData.CheckAllAPsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gApStacksBase = AllocatePool (
+ mCpuMpData.NumberOfProcessors *
+ gApStackSize
+ );
+ ASSERT (gApStacksBase != NULL);
+
+ for (Index = 0; Index < mCpuMpData.NumberOfProcessors; Index++) {
+ if (IsProcessorBSP (Index)) {
+ /* Skip BSP */
+ continue;
+ }
+
+ FillInProcessorInformation (FALSE, CpuInfo->ArmCpus[Index].Mpidr, Index);
+
+ gProcessorIDs[Index] = mCpuMpData.CpuData[Index].Info.ProcessorId;
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ CheckThisAPStatus,
+ (VOID *)&mCpuMpData.CpuData[Index],
+ &mCpuMpData.CpuData[Index].CheckThisAPEvent
+ );
+ ASSERT (Status == EFI_SUCCESS);
+ }
+
+ Status = EfiCreateEventReadyToBootEx (
+ TPL_CALLBACK,
+ ReadyToBootSignaled,
+ NULL,
+ &ReadyToBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ gProcessorIDs[Index] = 0;
+}
+
+/**
+ Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
+ signaled. After this point, non-blocking mode is no longer allowed.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+STATIC
+VOID
+EFIAPI
+ReadyToBootSignaled (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mNonBlockingModeAllowed = FALSE;
+}
+
diff --git a/ArmPkg/Library/MpInitLib/InternalMpInitLib.h b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h
new file mode 100644
index 000000000000..d08bb76246d7
--- /dev/null
+++ b/ArmPkg/Library/MpInitLib/InternalMpInitLib.h
@@ -0,0 +1,358 @@
+/** @file
+
+Copyright (c) 2021, NUVIA Inc. All rights reserved.<BR>
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+Portions copyright (c) 2011, Apple Inc. All rights reserved.
+
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef MP_INTERNAL_INIT_LIB_H_
+#define MP_INTERNAL_INIT_LIB_H_
+
+#include <Protocol/Cpu.h>
+#include <Protocol/MpService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+
+
+#define AP_STACK_SIZE 0x1000
+
+//
+// Internal Data Structures
+//
+
+//
+// AP state
+//
+// The state transitions for an AP when it process a procedure are:
+// Idle ----> Ready ----> Busy ----> Idle
+// [BSP] [AP] [AP]
+//
+typedef enum {
+ CpuStateIdle,
+ CpuStateReady,
+ CpuStateBlocked,
+ CpuStateBusy,
+ CpuStateFinished,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
+// Define Individual Processor Data block.
+//
+typedef struct {
+ EFI_PROCESSOR_INFORMATION Info;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ CPU_STATE State;
+ EFI_EVENT CheckThisAPEvent;
+ UINTN Timeout;
+ UINTN TimeTaken;
+} CPU_AP_DATA;
+
+//
+// Define MP data block which consumes individual processor block.
+//
+typedef struct {
+ UINTN NumberOfProcessors;
+ UINTN NumberOfEnabledProcessors;
+ EFI_EVENT CheckAllAPsEvent;
+ EFI_EVENT WaitEvent;
+ UINTN FinishCount;
+ UINTN StartCount;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcedureArgument;
+ BOOLEAN SingleThread;
+ UINTN StartedNumber;
+ CPU_AP_DATA *CpuData;
+ UINTN Timeout;
+ UINTN *FailedList;
+ UINTN FailedListIndex;
+ BOOLEAN TimeoutActive;
+} CPU_MP_DATA;
+
+EFI_STATUS
+EFIAPI
+CpuMpServicesInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+extern EFI_MP_SERVICES_PROTOCOL mMpServicesTemplate;
+
+/** Secondary core entry point.
+
+**/
+VOID ApEntryPoint (
+ VOID
+ );
+
+/** C entry-point for the AP.
+ This function gets called from the assembly function ApEntryPoint.
+**/
+VOID
+ApProcedure (
+ VOID
+ );
+
+/** Turns on the specified core using PSCI and executes the user-supplied
+ function that's been configured via a previous call to SetApProcedure.
+
+ @param ProcessorIndex The index of the core to turn on.
+
+ @retval EFI_SUCCESS The processor was successfully turned on.
+ @retval EFI_DEVICE_ERROR An error occurred turning the processor on.
+
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+DispatchCpu (
+ IN UINTN ProcessorIndex
+ );
+
+/** Returns whether the specified processor is the BSP.
+
+ @param[in] ProcessorIndex The index the processor to check.
+
+ @return TRUE if the processor is the BSP, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorBSP (
+ UINTN ProcessorIndex
+ );
+
+/** Returns whether the processor executing this function is the BSP.
+
+ @return Whether the current processor is the BSP.
+**/
+STATIC
+BOOLEAN
+IsCurrentProcessorBSP (
+ VOID
+ );
+
+/** Returns whether the specified processor is enabled.
+
+ @param[in] ProcessorIndex The index of the processor to check.
+
+ @return TRUE if the processor is enabled, FALSE otherwise.
+**/
+STATIC
+BOOLEAN
+IsProcessorEnabled (
+ UINTN ProcessorIndex
+ );
+
+/** Configures the processor context with the user-supplied procedure and
+ argument.
+
+ @param CpuData The processor context.
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+
+**/
+STATIC
+VOID
+SetApProcedure (
+ IN CPU_AP_DATA *CpuData,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ );
+
+/**
+ Get the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+
+ @return The AP status
+**/
+CPU_STATE
+GetApState (
+ IN CPU_AP_DATA *CpuData
+ );
+
+/** Returns the index of the next processor that is blocked.
+
+ @param[out] NextNumber The index of the next blocked processor.
+
+ @retval EFI_SUCCESS Successfully found the next blocked processor.
+ @retval EFI_NOT_FOUND There are no blocked processors.
+
+**/
+STATIC
+EFI_STATUS
+GetNextBlockedNumber (
+ OUT UINTN *NextNumber
+ );
+
+/** Stalls the BSP for the minimum of gPollInterval and Timeout.
+
+ @param[in] Timeout The time limit in microseconds remaining for
+ APs to return from Procedure.
+
+ @retval StallTime Time of execution stall.
+**/
+STATIC
+UINTN
+CalculateAndStallInterval (
+ IN UINTN Timeout
+ );
+
+/** Returns whether all processors are in the idle state.
+
+ @return Whether all the processors are idle.
+
+**/
+STATIC
+BOOLEAN
+CheckAllCpusReady (
+ VOID
+ );
+
+/** Sets up the state for the StartupAllAPs function.
+
+ @param SingleThread Whether the APs will execute sequentially.
+
+**/
+STATIC
+VOID
+StartupAllAPsPrepareState (
+ IN BOOLEAN SingleThread
+ );
+
+/** Handles execution of StartupAllAPs when a WaitEvent has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param WaitEvent The wait event to be signaled when the work is
+ complete or a timeout has occurred.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsWithWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN EFI_EVENT WaitEvent,
+ IN UINTN TimeoutInMicroseconds
+ );
+
+/** Handles execution of StartupAllAPs when no wait event has been specified.
+
+ @param Procedure The user-supplied procedure.
+ @param ProcedureArgument The user-supplied procedure argument.
+ @param TimeoutInMicroseconds The timeout for the work to be completed. Zero
+ indicates an infinite timeout.
+ @param SingleThread Whether the APs will execute sequentially.
+ @param FailedCpuList User-supplied pointer for list of failed CPUs.
+
+ @return EFI_SUCCESS on success.
+**/
+STATIC
+EFI_STATUS
+StartupAllAPsNoWaitEvent (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument,
+ IN UINTN TimeoutInMicroseconds,
+ IN BOOLEAN SingleThread,
+ IN UINTN **FailedCpuList
+ );
+
+
+/** Adds the specified processor the list of failed processors.
+
+ @param ProcessorIndex The processor index to add.
+ @param ApState Processor state.
+
+**/
+STATIC
+VOID
+AddProcessorToFailedList (
+ UINTN ProcessorIndex,
+ CPU_STATE ApState
+ );
+
+/** Handles the StartupAllAPs case where the timeout has occurred.
+
+**/
+STATIC
+VOID
+ProcessStartupAllAPsTimeout (
+ VOID
+ );
+
+/**
+ If a timeout is specified in StartupAllAps(), a timer is set, which invokes
+ this procedure periodically to check whether all APs have finished.
+
+ @param[in] Event The WaitEvent the user supplied.
+ @param[in] Context The event context.
+**/
+STATIC
+VOID
+EFIAPI
+CheckAllAPsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/** Invoked periodically via a timer to check the state of the processor.
+
+ @param Event The event supplied by the timer expiration.
+ @param Context The processor context.
+
+**/
+STATIC
+VOID
+EFIAPI
+CheckThisAPStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ This function is called by all processors (both BSP and AP) once and collects
+ MP related data.
+
+ @param BSP TRUE if the processor is the BSP.
+ @param Mpidr The MPIDR for the specified processor.
+ @param ProcessorIndex The index of the processor.
+
+ @return EFI_SUCCESS if the data for the processor collected and filled in.
+
+**/
+STATIC
+EFI_STATUS
+FillInProcessorInformation (
+ IN BOOLEAN BSP,
+ IN UINTN Mpidr,
+ IN UINTN ProcessorIndex
+ );
+
+/**
+ Event notification function called when the EFI_EVENT_GROUP_READY_TO_BOOT is
+ signaled. After this point, non-blocking mode is no longer allowed.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+STATIC
+VOID
+EFIAPI
+ReadyToBootSignaled (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+
+#endif /* MP_INTERNAL_INIT_LIB_H_ */
diff --git a/ArmVirtPkg/ArmVirt.dsc.inc b/ArmVirtPkg/ArmVirt.dsc.inc
index 5a1598d90ca7..af6e48fd6cfc 100644
--- a/ArmVirtPkg/ArmVirt.dsc.inc
+++ b/ArmVirtPkg/ArmVirt.dsc.inc
@@ -261,6 +261,9 @@
[LibraryClasses.ARM]
ArmSoftFloatLib|ArmPkg/Library/ArmSoftFloatLib/ArmSoftFloatLib.inf

+[LibraryClasses.AARCH64]
+ MpInitLib|ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
+
[BuildOptions]
RVCT:RELEASE_*_*_CC_FLAGS = -DMDEPKG_NDEBUG

--
2.31.1


[RFC] [PATCH 1/2] ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO struct

Rebecca Cran <rebecca@...>
 

Remove the ClusterId and CoreId fields in the ARM_CORE_INFO structure in
favor of a new Mpidr field. Update code in
ArmPlatformPkg/PrePeiCore/MainMPCore and ArmPlatformPkg/PrePi/MainMPCore.c
to use the new field and call new macros GET_MPIDR_AFF0 and GET_MPIDR_AFF1
instead.

Signed-off-by: Rebecca Cran <rebecca@nuviainc.com>
---
ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +--
ArmPkg/Include/Library/ArmLib.h | 4 ++++
ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 ++++----
ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +-
ArmPlatformPkg/PrePi/MainMPCore.c | 2 +-
5 files changed, 11 insertions(+), 8 deletions(-)

diff --git a/ArmPkg/Include/Guid/ArmMpCoreInfo.h b/ArmPkg/Include/Guid/ArmMpCoreInfo.h
index b810767879ae..04c44650ebf5 100644
--- a/ArmPkg/Include/Guid/ArmMpCoreInfo.h
+++ b/ArmPkg/Include/Guid/ArmMpCoreInfo.h
@@ -14,8 +14,7 @@
#define MPIDR_U_BIT_MASK 0x40000000

typedef struct {
- UINT32 ClusterId;
- UINT32 CoreId;
+ UINT64 Mpidr;

// MP Core Mailbox
EFI_PHYSICAL_ADDRESS MailboxSetAddress;
diff --git a/ArmPkg/Include/Library/ArmLib.h b/ArmPkg/Include/Library/ArmLib.h
index 79ea755777a9..d764cc670970 100644
--- a/ArmPkg/Include/Library/ArmLib.h
+++ b/ArmPkg/Include/Library/ArmLib.h
@@ -107,6 +107,10 @@ typedef enum {
#define GET_CORE_ID(MpId) ((MpId) & ARM_CORE_MASK)
#define GET_CLUSTER_ID(MpId) (((MpId) & ARM_CLUSTER_MASK) >> 8)
#define GET_MPID(ClusterId, CoreId) (((ClusterId) << 8) | (CoreId))
+#define GET_MPIDR_AFF0(MpId) ((MpId) & ARM_CORE_AFF0)
+#define GET_MPIDR_AFF1(MpId) (((MpId) & ARM_CORE_AFF1) >> 8)
+#define GET_MPIDR_AFF2(MpId) (((MpId) & ARM_CORE_AFF2) >> 16)
+#define GET_MPIDR_AFF3(MpId) (((MpId) & ARM_CORE_AFF3) >> 32)
#define PRIMARY_CORE_ID (PcdGet32(PcdArmPrimaryCore) & ARM_CORE_MASK)

/** Reads the CCSIDR register for the specified cache.
diff --git a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
index 1cd9ec30a977..6630cb68452c 100644
--- a/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
+++ b/ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c
@@ -15,7 +15,7 @@
ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
{
// Cluster 0, Core 0
- 0x0, 0x0,
+ 0x0,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -25,7 +25,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 1
- 0x0, 0x1,
+ 0x1,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -35,7 +35,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 2
- 0x0, 0x2,
+ 0x2,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
@@ -45,7 +45,7 @@ ARM_CORE_INFO mArmPlatformNullMpCoreInfoTable[] = {
},
{
// Cluster 0, Core 3
- 0x0, 0x3,
+ 0x3,

// MP Core MailBox Set/Get/Clear Addresses and Clear Value
(EFI_PHYSICAL_ADDRESS)0,
diff --git a/ArmPlatformPkg/PrePeiCore/MainMPCore.c b/ArmPlatformPkg/PrePeiCore/MainMPCore.c
index 859f1adf2078..5f8a268bf664 100644
--- a/ArmPlatformPkg/PrePeiCore/MainMPCore.c
+++ b/ArmPlatformPkg/PrePeiCore/MainMPCore.c
@@ -65,7 +65,7 @@ SecondaryMain (

// Find the core in the ArmCoreTable
for (Index = 0; Index < ArmCoreCount; Index++) {
- if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
+ if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) {
break;
}
}
diff --git a/ArmPlatformPkg/PrePi/MainMPCore.c b/ArmPlatformPkg/PrePi/MainMPCore.c
index 091464df2aa9..6497a1ad27fd 100644
--- a/ArmPlatformPkg/PrePi/MainMPCore.c
+++ b/ArmPlatformPkg/PrePi/MainMPCore.c
@@ -64,7 +64,7 @@ SecondaryMain (

// Find the core in the ArmCoreTable
for (Index = 0; Index < ArmCoreCount; Index++) {
- if ((ArmCoreInfoTable[Index].ClusterId == ClusterId) && (ArmCoreInfoTable[Index].CoreId == CoreId)) {
+ if ((GET_MPIDR_AFF1 (ArmCoreInfoTable[Index].Mpidr) == ClusterId) && (GET_MPIDR_AFF0 (ArmCoreInfoTable[Index].Mpidr) == CoreId)) {
break;
}
}
--
2.31.1


[RFC] [PATCH 0/2] Proposal to add EFI_MP_SERVICES_PROTOCOL support for AARCH64

Rebecca Cran <rebecca@...>
 

I'd like to propose adding EFI_MP_SERVICES_PROTOCOL support for
AARCH64 systems. I've attached two patches to implement support for it
in the DXE phase, based on code in EmulatorPkg and UefiCpuPkg. It's added
under ArmPkg for now, but longer term it should probably be moved into
UefiCpuPkg.

Patch 1/2 is the start of addressing the issue that the Aff0 field of
the MPIDR is no longer guaranteed to be the core, and should be referred
to in a more generic way: for example it could be the thread, with Aff1
being the core and Aff2 the cluster. Clearly much more work is needed
to fully remove that assumption.

Patch 2/2 implements the EFI_MP_SERVICES_PROTOCOL for DXE in Library/MpInitLib.
CpuDxe initializes the MP support, and as a result gains a dependency on
MpInitLib. ArmVirt.dsc.inc needs updated to add the new library, as will
all AARCH64 platforms.

I sent out a patch for MdeModulePkg last week to add a corresponding test
application, MpServicesTest (see https://edk2.groups.io/g/devel/message/80878).

Rebecca Cran (2):
ArmPkg: Replace CoreId and ClusterId with Mpidr in ARM_CORE_INFO
struct
ArmPkg: Add Library/MpInitLib to support EFI_MP_SERVICES_PROTOCOL

ArmPkg/ArmPkg.dec | 4 +
ArmPkg/ArmPkg.dsc | 4 +
ArmPkg/Drivers/CpuDxe/AArch64/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/Arm/Arch.c | 22 +
ArmPkg/Drivers/CpuDxe/CpuDxe.c | 2 +
ArmPkg/Drivers/CpuDxe/CpuDxe.h | 10 +
ArmPkg/Drivers/CpuDxe/CpuDxe.inf | 6 +
ArmPkg/Drivers/CpuDxe/CpuMpInit.c | 604 ++++++++
ArmPkg/Include/Guid/ArmMpCoreInfo.h | 3 +-
ArmPkg/Include/Library/ArmLib.h | 4 +
ArmPkg/Include/Library/MpInitLib.h | 366 +++++
ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S | 61 +
ArmPkg/Library/MpInitLib/DxeMpInitLib.inf | 53 +
ArmPkg/Library/MpInitLib/DxeMpLib.c | 1498 ++++++++++++++++++++
ArmPkg/Library/MpInitLib/InternalMpInitLib.h | 358 +++++
ArmPlatformPkg/Library/ArmPlatformLibNull/ArmPlatformLibNull.c | 8 +-
ArmPlatformPkg/PrePeiCore/MainMPCore.c | 2 +-
ArmPlatformPkg/PrePi/MainMPCore.c | 2 +-
ArmVirtPkg/ArmVirt.dsc.inc | 3 +
19 files changed, 3024 insertions(+), 8 deletions(-)
create mode 100644 ArmPkg/Drivers/CpuDxe/AArch64/Arch.c
create mode 100644 ArmPkg/Drivers/CpuDxe/Arm/Arch.c
create mode 100644 ArmPkg/Drivers/CpuDxe/CpuMpInit.c
create mode 100644 ArmPkg/Include/Library/MpInitLib.h
create mode 100644 ArmPkg/Library/MpInitLib/AArch64/MpFuncs.S
create mode 100644 ArmPkg/Library/MpInitLib/DxeMpInitLib.inf
create mode 100644 ArmPkg/Library/MpInitLib/DxeMpLib.c
create mode 100644 ArmPkg/Library/MpInitLib/InternalMpInitLib.h

--
2.31.1


Re: [PATCH V7 1/1] OvmfPkg: Enable TDX in ResetVector

Min Xu
 

On September 24, 2021 6:58 PM, Brijesh Singh wrote:
Hi Min,

On 9/21/21 4:05 AM, Min Xu wrote:
;
; Modified: EAX, EBX, ECX, EDX
;
SetCr3ForPageTables64:
-
- ; Clear the WorkArea header. The SEV probe routines will populate the
- ; work area when detected.
- mov byte[WORK_AREA_GUEST_TYPE], 0
Why you are removing the above block ? The workarea hdr must be initialized
to zero, its not safe to assume that the guest memory is zero'ed in the non-
encrypted case.
Hi, Brijesh
Please see below explanation (It is in the commit message)
- In Main16 entry point, after TransitionFromReal16To32BitFlat,
WORK_AREA_GUEST_TYPE is cleared to 0. WORK_AREA_GUEST_TYPE was
previously cleared in SetCr3ForPageTables64 (see commit ab77b60).
This doesn't work after TDX is introduced in Ovmf. It is because all
TDX CPUs (BSP and APs) start to run from 0xfffffff0. In previous code
WORK_AREA_GUEST_TYPE will be cleared multi-times in TDX guest. So for
SEV and Legacy guest it is moved to Main16 entry point (after
TransitionFromReal16To32BitFlat). For TDX guest WORK_AREA_GUEST_TYPE
is cleared and set in InitTdxWorkarea
Thanks!
Min


Re: [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-Guest firmware

Yao, Jiewen
 

Hi Liming
We just published the GHCI spec version 1.0 revision 002 at https://software.intel.com/content/dam/develop/external/us/en/documents/intel-tdx-guest-hypervisor-communication-interface-1.0-344426-002.pdf

4.3.2 include the EFI_TD_PROTOCOL.

Thank you
Yao Jiewen

-----Original Message-----
From: devel@edk2.groups.io <devel@edk2.groups.io> On Behalf Of gaoliming
Sent: Wednesday, September 15, 2021 1:50 PM
To: devel@edk2.groups.io; Xu, Min M <min.m.xu@intel.com>
Cc: Kinney, Michael D <michael.d.kinney@intel.com>; Liu, Zhiguang
<zhiguang.liu@intel.com>; Yao, Jiewen <jiewen.yao@intel.com>; Wang, Jian J
<jian.j.wang@intel.com>; Lu, Ken <ken.lu@intel.com>
Subject: 回复: [edk2-devel] [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-
Guest firmware

Min:
Which public spec defines this new protocol?

Thanks
Liming
-----邮件原件-----
发件人: devel@edk2.groups.io <devel@edk2.groups.io> 代表 Min Xu
发送时间: 2021年9月14日 9:57
收件人: devel@edk2.groups.io
抄送: Min Xu <min.m.xu@intel.com>; Michael D Kinney
<michael.d.kinney@intel.com>; Liming Gao <gaoliming@byosoft.com.cn>;
Zhiguang Liu <zhiguang.liu@intel.com>; Jiewen Yao <jiewen.yao@intel.com>;
Jian J Wang <jian.j.wang@intel.com>; Ken Lu <ken.lu@intel.com>
主题: [edk2-devel] [PATCH 1/2] MdePkg: Introduce TdProtocol for TD-Guest
firmware

BZ: https://bugzilla.tianocore.org/show_bug.cgi?id=3625

If TD-Guest firmware supports measurement and an event is created,
TD-Guest firmware is designed to report the event log with the same data
structure in TCG-Platform-Firmware-Profile specification with
EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 format.

The TD-Guest firmware supports measurement, the TD Guest Firmware is
designed to produce EFI_TD_PROTOCOL with new GUID
EFI_TD_PROTOCOL_GUID
to report event log and provides hash capability.

Cc: Michael D Kinney <michael.d.kinney@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Zhiguang Liu <zhiguang.liu@intel.com>
Cc: Jiewen Yao <jiewen.yao@intel.com>
Cc: Jian J Wang <jian.j.wang@intel.com>
Cc: Ken Lu <ken.lu@intel.com>
Signed-off-by: Min Xu <min.m.xu@intel.com>
---
MdePkg/Include/Protocol/TdProtocol.h | 305
+++++++++++++++++++++++++++
MdePkg/MdePkg.dec | 3 +
2 files changed, 308 insertions(+)
create mode 100644 MdePkg/Include/Protocol/TdProtocol.h

diff --git a/MdePkg/Include/Protocol/TdProtocol.h
b/MdePkg/Include/Protocol/TdProtocol.h
new file mode 100644
index 000000000000..5a015fca0079
--- /dev/null
+++ b/MdePkg/Include/Protocol/TdProtocol.h
@@ -0,0 +1,305 @@
+/** @file
+ If TD-Guest firmware supports measurement and an event is created,
TD-Guest
+ firmware is designed to report the event log with the same data
structure
+ in TCG-Platform-Firmware-Profile specification with
+ EFI_TCG2_EVENT_LOG_FORMAT_TCG_2 format.
+
+ The TD-Guest firmware supports measurement, the TD Guest Firmware is
designed
+ to produce EFI_TD_PROTOCOL with new GUID EFI_TD_PROTOCOL_GUID
to report
+ event log and provides hash capability.
+
+Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+
+#ifndef TD_PROTOCOL_H_
+#define TD_PROTOCOL_H_
+
+#include <Uefi/UefiBaseType.h>
+#include <IndustryStandard/UefiTcgPlatform.h>
+#include <IndustryStandard/Tpm20.h>
+
+
+#define EFI_TD_PROTOCOL_GUID \
+ { 0x96751a3d, 0x72f4, 0x41a6, { 0xa7, 0x94, 0xed, 0x5d, 0x0e, 0x67,
0xae,
0x6b }}
+extern EFI_GUID gEfiTdProtocolGuid;
+
+typedef struct _EFI_TD_PROTOCOL EFI_TD_PROTOCOL;
+
+typedef struct {
+ UINT8 Major;
+ UINT8 Minor;
+} EFI_TD_VERSION;
+
+typedef UINT32 EFI_TD_EVENT_LOG_BITMAP;
+typedef UINT32 EFI_TD_EVENT_LOG_FORMAT;
+typedef UINT32
EFI_TD_EVENT_ALGORITHM_BITMAP;
+typedef UINT32 EFI_TD_MR_INDEX;
+
+#define EFI_TD_EVENT_LOG_FORMAT_TCG_2 0x00000002
+#define EFI_TD_BOOT_HASH_ALG_SHA384 0x00000004
+
+//
+// This bit is shall be set when an event shall be extended but not
logged.
+//
+#define EFI_TD_FLAG_EXTEND_ONLY 0x0000000000000001
+//
+// This bit shall be set when the intent is to measure a PE/COFF image.
+//
+#define EFI_TD_FLAG_PE_COFF_IMAGE 0x0000000000000010
+
+#define MR_INDEX_MRTD 0
+#define MR_INDEX_RTMR0 1
+#define MR_INDEX_RTMR1 2
+#define MR_INDEX_RTMR2 3
+#define MR_INDEX_RTMR3 4
+
+//
+// This bit shall be set when the intent is to measure a PE/COFF image.
+//
+#define PE_COFF_IMAGE 0x0000000000000010
+
+#pragma pack (1)
+
+#define EFI_TD_EVENT_HEADER_VERSION 1
+
+typedef struct {
+ //
+ // Size of the event header itself (sizeof(EFI_TD_EVENT_HEADER)).
+ //
+ UINT32 HeaderSize;
+ //
+ // Header version. For this version of this specification, the value
shall be
1.
+ //
+ UINT16 HeaderVersion;
+ //
+ // Index of the MR that shall be extended.
+ //
+ EFI_TD_MR_INDEX MrIndex;
+ //
+ // Type of the event that shall be extended (and optionally logged).
+ //
+ UINT32 EventType;
+} EFI_TD_EVENT_HEADER;
+
+typedef struct {
+ //
+ // Total size of the event including the Size component, the header and
the
Event data.
+ //
+ UINT32 Size;
+ EFI_TD_EVENT_HEADER Header;
+ UINT8 Event[1];
+} EFI_TD_EVENT;
+
+#pragma pack()
+
+
+typedef struct {
+ //
+ // Allocated size of the structure
+ //
+ UINT8 Size;
+ //
+ // Version of the EFI_TD_BOOT_SERVICE_CAPABILITY structure itself.
+ // For this version of the protocol, the Major version shall be set to
1
+ // and the Minor version shall be set to 1.
+ //
+ EFI_TD_VERSION StructureVersion;
+ //
+ // Version of the EFI TD protocol.
+ // For this version of the protocol, the Major version shall be set to
1
+ // and the Minor version shall be set to 1.
+ //
+ EFI_TD_VERSION ProtocolVersion;
+ //
+ // Supported hash algorithms
+ //
+ EFI_TD_EVENT_ALGORITHM_BITMAP HashAlgorithmBitmap;
+ //
+ // Bitmap of supported event log formats
+ //
+ EFI_TD_EVENT_LOG_BITMAP SupportedEventLogs;
+
+ //
+ // False = TD not present
+ //
+ BOOLEAN TdPresentFlag;
+} EFI_TD_BOOT_SERVICE_CAPABILITY;
+
+/**
+ The EFI_TD_PROTOCOL GetCapability function call provides protocol
+ capability information and state information.
+
+ @param[in] This Indicates the calling context
+ @param[in, out] ProtocolCapability The caller allocates memory for a
EFI_TD_BOOT_SERVICE_CAPABILITY
+ structure and sets the size
field to the size of the structure allocated.
+ The callee fills in the fields
with the EFI protocol capability information
+ and the current EFI TD state
information up to the number of fields which
+ fit within the size of the
structure passed in.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ The ProtocolCapability variable will
not be populated.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect.
+ The ProtocolCapability variable will
not be populated.
+ @retval EFI_BUFFER_TOO_SMALL The ProtocolCapability variable is
too small to hold the full response.
+ It will be partially populated
(required Size field will be set).
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TD_GET_CAPABILITY) (
+ IN EFI_TD_PROTOCOL *This,
+ IN OUT EFI_TD_BOOT_SERVICE_CAPABILITY *ProtocolCapability
+ );
+
+/**
+ The EFI_TD_PROTOCOL Get Event Log function call allows a caller to
+ retrieve the address of a given event log and its last entry.
+
+ @param[in] This Indicates the calling context
+ @param[in] EventLogFormat The type of the event log for which
the information is requested.
+ @param[out] EventLogLocation A pointer to the memory address of
the event log.
+ @param[out] EventLogLastEntry If the Event Log contains more than
one entry, this is a pointer to the
+ address of the start of the last
entry in the event log in memory.
+ @param[out] EventLogTruncated If the Event Log is missing at least one
entry because an event would
+ have exceeded the area allocated
for events, this value is set to TRUE.
+ Otherwise, the value will be FALSE
and the Event Log will be complete.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect
+ (e.g. asking for an event log whose
format is not supported).
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_TD_GET_EVENT_LOG) (
+ IN EFI_TD_PROTOCOL *This,
+ IN EFI_TD_EVENT_LOG_FORMAT EventLogFormat,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLocation,
+ OUT EFI_PHYSICAL_ADDRESS *EventLogLastEntry,
+ OUT BOOLEAN *EventLogTruncated
+ );
+
+/**
+ The EFI_TD_PROTOCOL HashLogExtendEvent function call provides callers
with
+ an opportunity to extend and optionally log events without requiring
+ knowledge of actual TD commands.
+ The extend operation will occur even if this function cannot create an
event
+ log entry (e.g. due to the event log being full).
+
+ @param[in] This Indicates the calling context
+ @param[in] Flags Bitmap providing additional
information.
+ @param[in] DataToHash Physical address of the start of the
data buffer to be hashed.
+ @param[in] DataToHashLen The length in bytes of the buffer
referenced by DataToHash.
+ @param[in] EfiTdEvent Pointer to data buffer containing
information about the event.
+
+ @retval EFI_SUCCESS Operation completed successfully.
+ @retval EFI_DEVICE_ERROR The command was unsuccessful.
+ @retval EFI_VOLUME_FULL The extend operation occurred, but
the event could not be written to one or more event logs.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters are
incorrect.
+ @retval EFI_UNSUPPORTED The PE/COFF image type is not
supported.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_TD_HASH_LOG_EXTEND_EVENT) (
+ IN EFI_TD_PROTOCOL *This,
+ IN UINT64 Flags,
+ IN EFI_PHYSICAL_ADDRESS DataToHash,
+ IN UINT64 DataToHashLen,
+ IN EFI_TD_EVENT *EfiTdEvent
+ );
+
+/**
+ The EFI_TD_PROTOCOL MapPcrToMrIndex function call provides callers
+ the info on TPM PCR<-> measurement register mapping information.
+
+ In current version, we use below mapping:
+ PCR0 -> MRTD (Index 0)
+ PCR1 -> RTMR0 (Index 1)
+ PCR2~6 -> RTMR1 (Index 2)
+ PCR7 -> RTMR0 (Index 1)
+ PCR8~15 -> RTMR2 (Index 3)
+
+ @param[in] This Indicates the calling context
+ @param[in] PcrIndex TPM PCR index.
+ @param[out] MrIndex Measurement register index.
+
+ @retval EFI_SUCCESS The MR index is returned.
+ @retval EFI_INVALID_PARAMETER The MrIndex is NULL.
+ @retval EFI_UNSUPPORTED The PcrIndex is invalid.
+**/
+typedef
+EFI_STATUS
+(EFIAPI * EFI_TD_MAP_PCR_TO_MR_INDEX) (
+ IN EFI_TD_PROTOCOL *This,
+ IN TCG_PCRINDEX PcrIndex,
+ OUT EFI_TD_MR_INDEX *MrIndex
+ );
+
+struct _EFI_TD_PROTOCOL {
+ EFI_TD_GET_CAPABILITY GetCapability;
+ EFI_TD_GET_EVENT_LOG GetEventLog;
+ EFI_TD_HASH_LOG_EXTEND_EVENT
HashLogExtendEvent;
+ EFI_TD_MAP_PCR_TO_MR_INDEX MapPcrToMrIndex;
+};
+
+
+//
+// TD event log
+//
+
+#pragma pack(1)
+
+//
+// Crypto Agile Log Entry Format.
+// It is similar with TCG_PCR_EVENT2 except the field of MrIndex and
PCRIndex.
+//
+typedef struct {
+ EFI_TD_MR_INDEX MrIndex;
+ UINT32 EventType;
+ TPML_DIGEST_VALUES Digests;
+ UINT32 EventSize;
+ UINT8 Event[1];
+} TD_EVENT;
+
+//
+// EFI TD Event Header
+// It is similar with TCG_PCR_EVENT2_HDR except the field of MrIndex and
PCRIndex
+//
+typedef struct {
+ EFI_TD_MR_INDEX MrIndex;
+ UINT32 EventType;
+ TPML_DIGEST_VALUES Digests;
+ UINT32 EventSize;
+} TD_EVENT_HDR;
+
+#pragma pack()
+
+//
+// Log entries after Get Event Log service
+//
+
+
+typedef struct {
+ //
+ // The version of this structure. It shall be set ot 1.
+ //
+ UINT64 Version;
+ //
+ // Number of events recorded after invocation of GetEventLog API
+ //
+ UINT64 NumberOfEvents;
+ //
+ // List of events of type TCG_TD_EVENT.
+ //
+ //TD_EVENT Event[1];
+} EFI_TD_FINAL_EVENTS_TABLE;
+
+
+#define EFI_TD_FINAL_EVENTS_TABLE_GUID \
+ {0xdd4a4648, 0x2de7, 0x4665, {0x96, 0x4d, 0x21, 0xd9, 0xef, 0x5f, 0xb4,
0x46}}
+
+extern EFI_GUID gEfiTdFinalEventsTableGuid;
+
+#endif
diff --git a/MdePkg/MdePkg.dec b/MdePkg/MdePkg.dec
index a28a2daaffa8..2f48f6c40c1e 100644
--- a/MdePkg/MdePkg.dec
+++ b/MdePkg/MdePkg.dec
@@ -1008,6 +1008,9 @@
## Include/Protocol/PcdInfo.h
gGetPcdInfoProtocolGuid = { 0x5be40f57, 0xfa68, 0x4610, { 0xbb,
0xbf, 0xe9, 0xc5, 0xfc, 0xda, 0xd3, 0x65 } }

+ ## Include/Protocol/TdProtocol.h
+ gEfiTdProtocolGuid = { 0x96751a3d, 0x72f4, 0x41a6, { 0xa7,
0x94, 0xed, 0x5d, 0x0e, 0x67, 0xae, 0x6b }}
+
#
# Protocols defined in PI1.0.
#
--
2.29.2.windows.2










[edk2-platforms][PATCH v2 1/1] MinPlatformPkg/AcpiTables: Update structures for ACPI 6.3

Michael Kubacki
 

From: Daniel Maddy <danmad@microsoft.com>

REF:https://bugzilla.tianocore.org/show_bug.cgi?id=3D3535

Updates ACPI table structures in MinPlatformPkg for ACPI 6.3.

Cc: Chasel Chiu <chasel.chiu@intel.com>
Cc: Nate DeSimone <nathaniel.l.desimone@intel.com>
Cc: Liming Gao <gaoliming@byosoft.com.cn>
Cc: Eric Dong <eric.dong@intel.com>
Cc: Daniel Maddy <danmad@microsoft.com>
Co-authored-by: Michael Kubacki <michael.kubacki@microsoft.com>
Signed-off-by: Michael Kubacki <michael.kubacki@microsoft.com>
Reviewed-by: Nate DeSimone <nathaniel.l.desimone@intel.com>
---
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c | 181 +++++=
+++++----------
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c | 11 +-
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c | 74 ++++-=
---
3 files changed, 138 insertions(+), 128 deletions(-)

diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c=
b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
index 843ba832ce67..f5c4f2c3f1a9 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/AcpiPlatform.c
@@ -2,6 +2,7 @@
ACPI Platform Driver
=20
Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -11,7 +12,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
#pragma pack(1)
=20
typedef struct {
- UINT32 AcpiProcessorId;
+ UINT32 AcpiProcessorUid;
UINT32 ApicId;
UINT32 Flags;
UINT32 SocketNum;
@@ -25,9 +26,9 @@ typedef struct {
// Define Union of IO APIC & Local APIC structure;
//
typedef union {
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
- EFI_ACPI_4_0_IO_APIC_STRUCTURE AcpiIoApic;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE AcpiLocalApic;
+ EFI_ACPI_6_3_IO_APIC_STRUCTURE AcpiIoApic;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE AcpiLocalx2Apic;
struct {
UINT8 Type;
UINT8 Length;
@@ -36,9 +37,9 @@ typedef union {
=20
#pragma pack()
=20
-extern EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs;
-extern EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt;
-extern EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER Hpet;
+extern EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs;
+extern EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE Fadt;
+extern EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER Hpet;
extern EFI_ACPI_WSMT_TABLE Wsmt;
=20
VOID *mLocalTable[] =3D {
@@ -103,7 +104,7 @@ DebugDisplayReOrderTable (
for (Index =3D 0; Index < mNumberOfCpus; Index++) {
DEBUG ((DEBUG_INFO, " %02d 0x%02X 0x%02X %d %d=
%d\n",
Index,
- CpuApicIdOrderTable[Index].AcpiProcessorId,
+ CpuApicIdOrderTable[Index].AcpiProcessorUid,
CpuApicIdOrderTable[Index].ApicId,
CpuApicIdOrderTable[Index].Thread,
CpuApicIdOrderTable[Index].Flags,
@@ -118,31 +119,31 @@ AppendCpuMapTableEntry (
)
{
EFI_STATUS Status;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApicPtr;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicPtr;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE *LocalApicPtr;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE *LocalX2ApicPtr;
UINT8 Type;
=20
Status =3D EFI_SUCCESS;
Type =3D ((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiApicCommon.Type;
- LocalApicPtr =3D (EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE *)(&((AC=
PI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalApic);
- LocalX2ApicPtr =3D (EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)(&=
((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalx2Apic);
+ LocalApicPtr =3D (EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE *)(&((AC=
PI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalApic);
+ LocalX2ApicPtr =3D (EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE *)(&=
((ACPI_APIC_STRUCTURE_PTR *)ApicPtr)->AcpiLocalx2Apic);
=20
- if(Type =3D=3D EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC) {
+ if(Type =3D=3D EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC) {
if(!mX2ApicEnabled) {
- LocalApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].Flags;
- LocalApicPtr->ApicId =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].ApicId;
- LocalApicPtr->AcpiProcessorId =3D (UINT8)mCpuApicIdOrderTable[Loca=
lApicCounter].AcpiProcessorId;
+ LocalApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].Flags;
+ LocalApicPtr->ApicId =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].ApicId;
+ LocalApicPtr->AcpiProcessorUid =3D (UINT8)mCpuApicIdOrderTable[Loc=
alApicCounter].AcpiProcessorUid;
} else {
- LocalApicPtr->Flags =3D 0;
- LocalApicPtr->ApicId =3D 0xFF;
- LocalApicPtr->AcpiProcessorId =3D (UINT8)0xFF;
+ LocalApicPtr->Flags =3D 0;
+ LocalApicPtr->ApicId =3D 0xFF;
+ LocalApicPtr->AcpiProcessorUid =3D (UINT8)0xFF;
Status =3D EFI_UNSUPPORTED;
}
- } else if(Type =3D=3D EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC) {
+ } else if(Type =3D=3D EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC) {
if(mX2ApicEnabled) {
LocalX2ApicPtr->Flags =3D (UINT8)mCpuApicIdOrderTable[L=
ocalApicCounter].Flags;
LocalX2ApicPtr->X2ApicId =3D mCpuApicIdOrderTable[LocalApi=
cCounter].ApicId;
- LocalX2ApicPtr->AcpiProcessorUid =3D mCpuApicIdOrderTable[LocalApi=
cCounter].AcpiProcessorId;
+ LocalX2ApicPtr->AcpiProcessorUid =3D mCpuApicIdOrderTable[LocalApi=
cCounter].AcpiProcessorUid;
} else {
LocalX2ApicPtr->Flags =3D 0;
LocalX2ApicPtr->X2ApicId =3D (UINT32)-1;
@@ -201,15 +202,15 @@ SortCpuLocalApicInTable (
//update processorbitMask
if (CpuIdMapPtr->Flags =3D=3D 1) {
if (mForceX2ApicId) {
- CpuIdMapPtr->SocketNum &=3D 0x7;
- CpuIdMapPtr->AcpiProcessorId &=3D 0xFF; //keep lower 8bit due =
to use Proc obj in dsdt
+ CpuIdMapPtr->SocketNum &=3D 0x7;
+ CpuIdMapPtr->AcpiProcessorUid &=3D 0xFF; //keep lower 8bit due=
to use Proc obj in dsdt
}
}
} else { //not enabled
- CpuIdMapPtr->ApicId =3D (UINT32)-1;
- CpuIdMapPtr->Thread =3D (UINT32)-1;
- CpuIdMapPtr->Flags =3D 0;
- CpuIdMapPtr->SocketNum =3D (UINT32)-1;
+ CpuIdMapPtr->ApicId =3D (UINT32)-1;
+ CpuIdMapPtr->Thread =3D (UINT32)-1;
+ CpuIdMapPtr->Flags =3D 0;
+ CpuIdMapPtr->SocketNum =3D (UINT32)-1;
} //end if PROC ENABLE
} //end for CurrentProcessor
=20
@@ -280,12 +281,12 @@ SortCpuLocalApicInTable (
}
=20
//
- // 5. Re-assigen AcpiProcessorId for AcpiProcessorUId uses purpose.
+ // 5. Re-assign AcpiProcessorId for AcpiProcessorUid uses purpose.
//
for (Socket =3D 0; Socket < FixedPcdGet32 (PcdMaxCpuSocketCount); Sock=
et++) {
for (CurrProcessor =3D 0, Index =3D 0; CurrProcessor < mNumberOfCpus=
; CurrProcessor++) {
if (mCpuApicIdOrderTable[CurrProcessor].Flags && (mCpuApicIdOrderT=
able[CurrProcessor].SocketNum =3D=3D Socket)) {
- mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorId =3D (Process=
orInfoBuffer.Location.Package << mNumOfBitShift) + Index;
+ mCpuApicIdOrderTable[CurrProcessor].AcpiProcessorUid =3D (Proces=
sorInfoBuffer.Location.Package << mNumOfBitShift) + Index;
Index++;
}
}
@@ -312,17 +313,17 @@ typedef struct {
} STRUCTURE_HEADER;
=20
STRUCTURE_HEADER mMadtStructureTable[] =3D {
- {EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_APIC_STRUCTURE)},
- {EFI_ACPI_4_0_IO_APIC, sizeof (EFI_ACPI_4_0_IO_A=
PIC_STRUCTURE)},
- {EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE, sizeof (EFI_ACPI_4_0_INTE=
RRUPT_SOURCE_OVERRIDE_STRUCTURE)},
- {EFI_ACPI_4_0_NON_MASKABLE_INTERRUPT_SOURCE, sizeof (EFI_ACPI_4_0_NON_=
MASKABLE_INTERRUPT_SOURCE_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_APIC_NMI, sizeof (EFI_ACPI_4_0_LOCA=
L_APIC_NMI_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_APIC_ADDRESS_OVERRIDE, sizeof (EFI_ACPI_4_0_LOCA=
L_APIC_ADDRESS_OVERRIDE_STRUCTURE)},
- {EFI_ACPI_4_0_IO_SAPIC, sizeof (EFI_ACPI_4_0_IO_S=
APIC_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_SAPIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_SAPIC_STRUCTURE)},
- {EFI_ACPI_4_0_PLATFORM_INTERRUPT_SOURCES, sizeof (EFI_ACPI_4_0_PLAT=
FORM_INTERRUPT_SOURCES_STRUCTURE)},
- {EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC, sizeof (EFI_ACPI_4_0_PROC=
ESSOR_LOCAL_X2APIC_STRUCTURE)},
- {EFI_ACPI_4_0_LOCAL_X2APIC_NMI, sizeof (EFI_ACPI_4_0_LOCA=
L_X2APIC_NMI_STRUCTURE)}
+ {EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_IO_APIC, sizeof (EFI_ACPI_6_3_IO_A=
PIC_STRUCTURE)},
+ {EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE, sizeof (EFI_ACPI_6_3_INTE=
RRUPT_SOURCE_OVERRIDE_STRUCTURE)},
+ {EFI_ACPI_6_3_NON_MASKABLE_INTERRUPT_SOURCE, sizeof (EFI_ACPI_6_3_NON_=
MASKABLE_INTERRUPT_SOURCE_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_APIC_NMI, sizeof (EFI_ACPI_6_3_LOCA=
L_APIC_NMI_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_APIC_ADDRESS_OVERRIDE, sizeof (EFI_ACPI_6_3_LOCA=
L_APIC_ADDRESS_OVERRIDE_STRUCTURE)},
+ {EFI_ACPI_6_3_IO_SAPIC, sizeof (EFI_ACPI_6_3_IO_S=
APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_SAPIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_SAPIC_STRUCTURE)},
+ {EFI_ACPI_6_3_PLATFORM_INTERRUPT_SOURCES, sizeof (EFI_ACPI_6_3_PLAT=
FORM_INTERRUPT_SOURCES_STRUCTURE)},
+ {EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC, sizeof (EFI_ACPI_6_3_PROC=
ESSOR_LOCAL_X2APIC_STRUCTURE)},
+ {EFI_ACPI_6_3_LOCAL_X2APIC_NMI, sizeof (EFI_ACPI_6_3_LOCA=
L_X2APIC_NMI_STRUCTURE)}
};
=20
/**
@@ -481,7 +482,7 @@ InitializeHeader (
**/
EFI_STATUS
InitializeMadtHeader (
- IN OUT EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader
+ IN OUT EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *MadtHeader
)
{
EFI_STATUS Status;
@@ -493,8 +494,8 @@ InitializeMadtHeader (
=20
Status =3D InitializeHeader (
&MadtHeader->Header,
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE,
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_REVISION,
0
);
if (EFI_ERROR (Status)) {
@@ -502,7 +503,7 @@ InitializeMadtHeader (
}
=20
MadtHeader->LocalApicAddress =3D PcdGet32(PcdLocalApicAddress);
- MadtHeader->Flags =3D EFI_ACPI_4_0_PCAT_COMPAT;
+ MadtHeader->Flags =3D EFI_ACPI_6_3_PCAT_COMPAT;
=20
return EFI_SUCCESS;
}
@@ -539,7 +540,7 @@ CopyStructure (
//
// Initialize the number of table entries and the table based on the t=
able header passed in.
//
- if (Header->Signature =3D=3D EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TA=
BLE_SIGNATURE) {
+ if (Header->Signature =3D=3D EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TA=
BLE_SIGNATURE) {
TableNumEntries =3D sizeof (mMadtStructureTable) / sizeof (STRUCTURE=
_HEADER);
StructureTable =3D mMadtStructureTable;
} else {
@@ -649,7 +650,7 @@ BuildAcpiTable (
return EFI_INVALID_PARAMETER;
}
=20
- if (AcpiHeader->Signature !=3D EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_=
TABLE_SIGNATURE) {
+ if (AcpiHeader->Signature !=3D EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_=
TABLE_SIGNATURE) {
DEBUG ((
DEBUG_ERROR,
"MADT header signature is expected, actually 0x%08x\n",
@@ -740,15 +741,15 @@ InstallMadtFromScratch (
{
EFI_STATUS Status;
UINTN Index;
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable;
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER *NewMadtTable;
UINTN TableHandle;
- EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC_STRUCTURE ProcLocalApicStruc=
t;
- EFI_ACPI_4_0_IO_APIC_STRUCTURE IoApicStruct;
- EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE IntSrcOverrideStru=
ct;
- EFI_ACPI_4_0_LOCAL_APIC_NMI_STRUCTURE LocalApciNmiStruct=
;
- EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC_STRUCTURE ProcLocalX2ApicStr=
uct;
- EFI_ACPI_4_0_LOCAL_X2APIC_NMI_STRUCTURE LocalX2ApicNmiStru=
ct;
+ EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER MadtTableHeader;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC_STRUCTURE ProcLocalApicStruc=
t;
+ EFI_ACPI_6_3_IO_APIC_STRUCTURE IoApicStruct;
+ EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE_STRUCTURE IntSrcOverrideStru=
ct;
+ EFI_ACPI_6_3_LOCAL_APIC_NMI_STRUCTURE LocalApciNmiStruct=
;
+ EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC_STRUCTURE ProcLocalX2ApicStr=
uct;
+ EFI_ACPI_6_3_LOCAL_X2APIC_NMI_STRUCTURE LocalX2ApicNmiStru=
ct;
STRUCTURE_HEADER **MadtStructs;
UINTN MaxMadtStructCount=
;
UINTN MadtStructsIndex;
@@ -809,11 +810,11 @@ InstallMadtFromScratch (
//
// Build Processor Local APIC Structures and Processor Local X2APIC St=
ructures
//
- ProcLocalApicStruct.Type =3D EFI_ACPI_4_0_PROCESSOR_LOCAL_APIC;
- ProcLocalApicStruct.Length =3D sizeof (EFI_ACPI_4_0_PROCESSOR_LOCAL_AP=
IC_STRUCTURE);
+ ProcLocalApicStruct.Type =3D EFI_ACPI_6_3_PROCESSOR_LOCAL_APIC;
+ ProcLocalApicStruct.Length =3D sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_AP=
IC_STRUCTURE);
=20
- ProcLocalX2ApicStruct.Type =3D EFI_ACPI_4_0_PROCESSOR_LOCAL_X2APIC;
- ProcLocalX2ApicStruct.Length =3D sizeof (EFI_ACPI_4_0_PROCESSOR_LOCAL_=
X2APIC_STRUCTURE);
+ ProcLocalX2ApicStruct.Type =3D EFI_ACPI_6_3_PROCESSOR_LOCAL_X2APIC;
+ ProcLocalX2ApicStruct.Length =3D sizeof (EFI_ACPI_6_3_PROCESSOR_LOCAL_=
X2APIC_STRUCTURE);
ProcLocalX2ApicStruct.Reserved[0] =3D 0;
ProcLocalX2ApicStruct.Reserved[1] =3D 0;
=20
@@ -824,9 +825,9 @@ InstallMadtFromScratch (
// use a processor local x2APIC structure.
//
if (!mX2ApicEnabled && mCpuApicIdOrderTable[Index].ApicId < MAX_UINT=
8) {
- ProcLocalApicStruct.Flags =3D (UINT8) mCpuApicIdOrderTab=
le[Index].Flags;
- ProcLocalApicStruct.ApicId =3D (UINT8) mCpuApicIdOrderTab=
le[Index].ApicId;
- ProcLocalApicStruct.AcpiProcessorId =3D (UINT8) mCpuApicIdOrderTab=
le[Index].AcpiProcessorId;
+ ProcLocalApicStruct.Flags =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].Flags;
+ ProcLocalApicStruct.ApicId =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].ApicId;
+ ProcLocalApicStruct.AcpiProcessorUid =3D (UINT8) mCpuApicIdOrderTa=
ble[Index].AcpiProcessorUid;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -837,7 +838,7 @@ InstallMadtFromScratch (
} else if (mCpuApicIdOrderTable[Index].ApicId !=3D 0xFFFFFFFF) {
ProcLocalX2ApicStruct.Flags =3D (UINT8) mCpuApicIdOrder=
Table[Index].Flags;
ProcLocalX2ApicStruct.X2ApicId =3D mCpuApicIdOrderTable[In=
dex].ApicId;
- ProcLocalX2ApicStruct.AcpiProcessorUid =3D mCpuApicIdOrderTable[In=
dex].AcpiProcessorId;
+ ProcLocalX2ApicStruct.AcpiProcessorUid =3D mCpuApicIdOrderTable[In=
dex].AcpiProcessorUid;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -855,8 +856,8 @@ InstallMadtFromScratch (
//
// Build I/O APIC Structures
//
- IoApicStruct.Type =3D EFI_ACPI_4_0_IO_APIC;
- IoApicStruct.Length =3D sizeof (EFI_ACPI_4_0_IO_APIC_STRUCTURE);
+ IoApicStruct.Type =3D EFI_ACPI_6_3_IO_APIC;
+ IoApicStruct.Length =3D sizeof (EFI_ACPI_6_3_IO_APIC_STRUCTURE);
IoApicStruct.Reserved =3D 0;
=20
PcIoApicEnable =3D PcdGet32 (PcdPcIoApicEnable);
@@ -902,8 +903,8 @@ InstallMadtFromScratch (
//
// Build Interrupt Source Override Structures
//
- IntSrcOverrideStruct.Type =3D EFI_ACPI_4_0_INTERRUPT_SOURCE_OVERRIDE;
- IntSrcOverrideStruct.Length =3D sizeof (EFI_ACPI_4_0_INTERRUPT_SOURCE_=
OVERRIDE_STRUCTURE);
+ IntSrcOverrideStruct.Type =3D EFI_ACPI_6_3_INTERRUPT_SOURCE_OVERRIDE;
+ IntSrcOverrideStruct.Length =3D sizeof (EFI_ACPI_6_3_INTERRUPT_SOURCE_=
OVERRIDE_STRUCTURE);
=20
//
// IRQ0=3D>IRQ2 Interrupt Source Override Structure
@@ -946,11 +947,11 @@ InstallMadtFromScratch (
//
// Build Local APIC NMI Structures
//
- LocalApciNmiStruct.Type =3D EFI_ACPI_4_0_LOCAL_APIC_NMI;
- LocalApciNmiStruct.Length =3D sizeof (EFI_ACPI_4_0_LOCAL_APIC_NMI_STRU=
CTURE);
- LocalApciNmiStruct.AcpiProcessorId =3D 0xFF; // Applies to all pr=
ocessors
- LocalApciNmiStruct.Flags =3D 0x0005; // Flags - Edge-tigg=
ered, Active High
- LocalApciNmiStruct.LocalApicLint =3D 0x1;
+ LocalApciNmiStruct.Type =3D EFI_ACPI_6_3_LOCAL_APIC_NMI;
+ LocalApciNmiStruct.Length =3D sizeof (EFI_ACPI_6_3_LOCAL_APIC_NMI_STRU=
CTURE);
+ LocalApciNmiStruct.AcpiProcessorUid =3D 0xFF; // Applies to all p=
rocessors
+ LocalApciNmiStruct.Flags =3D 0x0005; // Flags - Edge-tig=
gered, Active High
+ LocalApciNmiStruct.LocalApicLint =3D 0x1;
=20
ASSERT (MadtStructsIndex < MaxMadtStructCount);
Status =3D CopyStructure (
@@ -967,8 +968,8 @@ InstallMadtFromScratch (
// Build Local x2APIC NMI Structure
//
if (mX2ApicEnabled) {
- LocalX2ApicNmiStruct.Type =3D EFI_ACPI_4_0_LOCAL_X2APIC_NMI;
- LocalX2ApicNmiStruct.Length =3D sizeof (EFI_ACPI_4_0_LOCAL_X2APIC_NM=
I_STRUCTURE);
+ LocalX2ApicNmiStruct.Type =3D EFI_ACPI_6_3_LOCAL_X2APIC_NMI;
+ LocalX2ApicNmiStruct.Length =3D sizeof (EFI_ACPI_6_3_LOCAL_X2APIC_NM=
I_STRUCTURE);
LocalX2ApicNmiStruct.Flags =3D 0x000D; // Flags - Le=
vel-tiggered, Active High
LocalX2ApicNmiStruct.AcpiProcessorUid =3D 0xFFFFFFFF; // Applies to=
all processors
LocalX2ApicNmiStruct.LocalX2ApicLint =3D 0x01;
@@ -992,12 +993,12 @@ InstallMadtFromScratch (
// Build Madt Structure from the Madt Header and collection of pointer=
s in MadtStructs[]
//
Status =3D BuildAcpiTable (
- (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader,
- sizeof (EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER=
),
- MadtStructs,
- MadtStructsIndex,
- (UINT8 **) &NewMadtTable
- );
+ (EFI_ACPI_DESCRIPTION_HEADER *) &MadtTableHeader,
+ sizeof (EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_HEADER)=
,
+ MadtStructs,
+ MadtStructsIndex,
+ (UINT8 **)&NewMadtTable
+ );
if (EFI_ERROR (Status)) {
DEBUG ((DEBUG_ERROR, "BuildAcpiTable failed: %r\n", Status));
goto Done;
@@ -1087,7 +1088,7 @@ InstallMcfgFromScratch (
}
=20
//
- // Publish Madt Structure to ACPI
+ // Publish Mcfg Structure to ACPI
//
Status =3D mAcpiTable->InstallAcpiTable (
mAcpiTable,
@@ -1120,7 +1121,7 @@ PlatformUpdateTables (
EFI_ACPI_DESCRIPTION_HEADER *TableHeader;
UINT8 *TempOemId;
UINT64 TempOemTableId;
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader;
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *FadtHeader;
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *HpetTable;
UINT32 HpetBaseAddress;
EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_BLOCK_ID HpetBlockId;
@@ -1177,12 +1178,12 @@ PlatformUpdateTables (
//
switch (Table->Signature) {
=20
- case EFI_ACPI_4_0_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
- ASSERT (FALSE);
+ case EFI_ACPI_6_3_MULTIPLE_APIC_DESCRIPTION_TABLE_SIGNATURE:
+ ASSERT(FALSE);
break;
=20
- case EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
- FadtHeader =3D (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE *) Tabl=
e;
+ case EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ FadtHeader =3D (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *) Table;
=20
FadtHeader->PreferredPmProfile =3D PcdGet8 (PcdFadtPreferredPmProfil=
e);
FadtHeader->IaPcBootArch =3D PcdGet16 (PcdFadtIaPcBootArch);
@@ -1228,7 +1229,7 @@ PlatformUpdateTables (
DEBUG ((DEBUG_INFO, " Flags 0x%x\n", FadtHeader->Flags));
break;
=20
- case EFI_ACPI_3_0_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
+ case EFI_ACPI_6_3_HIGH_PRECISION_EVENT_TIMER_TABLE_SIGNATURE:
HpetTable =3D (EFI_ACPI_HIGH_PRECISION_EVENT_TIMER_TABLE_HEADER *)Ta=
ble;
HpetBaseAddress =3D PcdGet32 (PcdHpetBaseAddress);
HpetTable->BaseAddressLower32Bit.Address =3D HpetBaseAddress;
@@ -1280,8 +1281,8 @@ IsHardwareChange (
UINTN HWChangeSize;
UINT32 PciId;
UINTN Handle;
- EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *FacsPtr;
- EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *pFADT;
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE *FacsPtr;
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE *pFADT;
=20
HandleCount =3D 0;
HandleBuffer =3D NULL;
@@ -1327,7 +1328,7 @@ IsHardwareChange (
//
Handle =3D 0;
Status =3D LocateAcpiTableBySignature (
- EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
(EFI_ACPI_DESCRIPTION_HEADER **) &pFADT,
&Handle
);
@@ -1349,7 +1350,7 @@ IsHardwareChange (
//
// Set HardwareSignature value based on CRC value.
//
- FacsPtr =3D (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)pFA=
DT->FirmwareCtrl;
+ FacsPtr =3D (EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)pFA=
DT->FirmwareCtrl;
FacsPtr->HardwareSignature =3D CRC;
FreePool (HWChange);
}
diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c b/=
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
index cde6e478c6b9..8700c44e633d 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Facs/Facs.c
@@ -1,9 +1,10 @@
/** @file
- This file contains a structure definition for the ACPI 5.0 Firmware AC=
PI
+ This file contains a structure definition for the ACPI 6.3 Firmware AC=
PI
Control Structure (FACS). The contents of this file should only be mo=
dified
for bug fixes, no porting is required.
=20
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -35,9 +36,9 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Please modify all values in Facs.h only.
//
=20
-EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
- EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
- sizeof (EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE),
+EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE,
+ sizeof (EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE),
=20
//
// Hardware Signature will be updated at runtime
@@ -48,7 +49,7 @@ EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE Facs =3D {
EFI_ACPI_GLOBAL_LOCK,
EFI_ACPI_FIRMWARE_CONTROL_STRUCTURE_FLAGS,
EFI_ACPI_X_FIRMWARE_WAKING_VECTOR,
- EFI_ACPI_5_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
+ EFI_ACPI_6_3_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION,
{
EFI_ACPI_RESERVED_BYTE,
EFI_ACPI_RESERVED_BYTE,
diff --git a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c b/=
Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
index 6efb38cda40d..3418e960972f 100644
--- a/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
+++ b/Platform/Intel/MinPlatformPkg/Acpi/AcpiTables/Fadt/Fadt.c
@@ -1,9 +1,10 @@
/** @file
- This file contains a structure definition for the ACPI 5.0 Fixed ACPI
+ This file contains a structure definition for the ACPI 6.3 Fixed ACPI
Description Table (FADT). The contents of this file should only be mo=
dified
for bug fixes, no porting is required.
=20
Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
SPDX-License-Identifier: BSD-2-Clause-Patent
=20
**/
@@ -44,9 +45,13 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// IA-PC Boot Architecture Flags
//
-
#define EFI_ACPI_IAPC_BOOT_ARCH 0 // To be fixed
=20
+//
+// ARM Boot Architecture Flags
+//
+#define EFI_ACPI_ARM_BOOT_ARCH 0 // To be fixed
+
//
// Fixed Feature Flags
//
@@ -55,7 +60,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1A Event Register Block Generic Address Information
//
-#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1A_EVT_BLK_BIT_WIDTH 0x20
#define EFI_ACPI_PM1A_EVT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1A_EVT_BLK_ADDRESS 0 // To be fixed
@@ -63,7 +68,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1B Event Register Block Generic Address Information
//
-#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1B_EVT_BLK_BIT_WIDTH 0x00
#define EFI_ACPI_PM1B_EVT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1B_EVT_BLK_ADDRESS 0 // To be fixed
@@ -71,7 +76,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1A Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1A_CNT_BLK_BIT_WIDTH 0x10
#define EFI_ACPI_PM1A_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1A_CNT_BLK_ADDRESS 0 // To be fixed
@@ -79,7 +84,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM1B Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM1B_CNT_BLK_BIT_WIDTH 0x00
#define EFI_ACPI_PM1B_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM1B_CNT_BLK_ADDRESS 0 // To be fixed
@@ -87,7 +92,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
//
// PM2 Control Register Block Generic Address Information
//
-#define EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM2_CNT_BLK_BIT_WIDTH 0x08
#define EFI_ACPI_PM2_CNT_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM2_CNT_BLK_ADDRESS 0 // To be fixed
@@ -96,7 +101,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Power Management Timer Control Register Block Generic Address
// Information
//
-#define EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_PM_TMR_BLK_BIT_WIDTH 0x20
#define EFI_ACPI_PM_TMR_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_PM_TMR_BLK_ADDRESS 0 // To be fixed
@@ -105,7 +110,7 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// General Purpose Event 0 Register Block Generic Address
// Information
//
-#define EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_GPE0_BLK_BIT_WIDTH 0 // size of R_PCH_ACPI_GPE=
0_STS_127_96 + R_PCH_ACPI_GPE0_EN_127_96
#define EFI_ACPI_GPE0_BLK_BIT_OFFSET 0x00
#define EFI_ACPI_GPE0_BLK_ADDRESS 0 // To be fixed
@@ -114,14 +119,14 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// General Purpose Event 1 Register Block Generic Address
// Information
//
-#define EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_GPE1_BLK_BIT_WIDTH 0x0
#define EFI_ACPI_GPE1_BLK_BIT_OFFSET 0x0
#define EFI_ACPI_GPE1_BLK_ADDRESS 0 // To be fixed
//
// Reset Register Generic Address Information
//
-#define EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID EFI_ACPI_2_0_SYSTEM_IO
+#define EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID EFI_ACPI_6_3_SYSTEM_IO
#define EFI_ACPI_RESET_REG_BIT_WIDTH 0x08
#define EFI_ACPI_RESET_REG_BIT_OFFSET 0x00
#define EFI_ACPI_RESET_REG_ADDRESS 0x00000CF9
@@ -162,11 +167,11 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
// Please modify all values in Fadt.h only.
//
=20
-EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
+EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
{
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
- sizeof (EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE),
- EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE,
+ sizeof (EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE),
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_REVISION,
=20
//
// Checksum will be updated at runtime
@@ -187,9 +192,9 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
//
// These addresses will be updated at runtime
//
- 0x00000000,=20
0x00000000,
- =20
+ 0x00000000,
+
EFI_ACPI_RESERVED_BYTE,
EFI_ACPI_PREFERRED_PM_PROFILE,
EFI_ACPI_SCI_INT,
@@ -198,7 +203,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_ACPI_DISABLE,
EFI_ACPI_S4_BIOS_REQ,
EFI_ACPI_PSTATE_CNT,
- =20
+
EFI_ACPI_PM1A_EVT_BLK_ADDRESS,
EFI_ACPI_PM1B_EVT_BLK_ADDRESS,
EFI_ACPI_PM1A_CNT_BLK_ADDRESS,
@@ -240,15 +245,13 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D =
{
EFI_ACPI_RESET_REG_ADDRESS_SPACE_ID,
EFI_ACPI_RESET_REG_BIT_WIDTH,
EFI_ACPI_RESET_REG_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_RESET_REG_ADDRESS
},
EFI_ACPI_RESET_VALUE,
- {
- EFI_ACPI_RESERVED_BYTE,
- EFI_ACPI_RESERVED_BYTE,
- EFI_ACPI_RESERVED_BYTE
- },
+
+ EFI_ACPI_ARM_BOOT_ARCH,
+ EFI_ACPI_6_3_FIXED_ACPI_DESCRIPTION_TABLE_MINOR_REVISION,
=20
//
// These addresses will be updated at runtime
@@ -263,7 +266,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1A_EVT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1A_EVT_BLK_BIT_WIDTH,
EFI_ACPI_PM1A_EVT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1A_EVT_BLK_ADDRESS
},
{
@@ -273,7 +276,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1B_EVT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1B_EVT_BLK_BIT_WIDTH,
EFI_ACPI_PM1B_EVT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1B_EVT_BLK_ADDRESS
},
{
@@ -283,7 +286,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1A_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1A_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM1A_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1A_CNT_BLK_ADDRESS
},
{
@@ -293,7 +296,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM1B_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM1B_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM1B_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_WORD,
+ EFI_ACPI_6_3_WORD,
EFI_ACPI_PM1B_CNT_BLK_ADDRESS
},
{
@@ -303,7 +306,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM2_CNT_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM2_CNT_BLK_BIT_WIDTH,
EFI_ACPI_PM2_CNT_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_PM2_CNT_BLK_ADDRESS
},
{
@@ -313,7 +316,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_PM_TMR_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_PM_TMR_BLK_BIT_WIDTH,
EFI_ACPI_PM_TMR_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_DWORD,
+ EFI_ACPI_6_3_DWORD,
EFI_ACPI_PM_TMR_BLK_ADDRESS
},
{
@@ -323,7 +326,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_GPE0_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_GPE0_BLK_BIT_WIDTH,
EFI_ACPI_GPE0_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_GPE0_BLK_ADDRESS
},
{
@@ -333,7 +336,7 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
EFI_ACPI_GPE1_BLK_ADDRESS_SPACE_ID,
EFI_ACPI_GPE1_BLK_BIT_WIDTH,
EFI_ACPI_GPE1_BLK_BIT_OFFSET,
- EFI_ACPI_5_0_BYTE,
+ EFI_ACPI_6_3_BYTE,
EFI_ACPI_GPE1_BLK_ADDRESS
},
{
@@ -355,5 +358,10 @@ EFI_ACPI_5_0_FIXED_ACPI_DESCRIPTION_TABLE Fadt =3D {
0,
0,
0
- }
+ },
+
+ //
+ // Hypervisor Vendor Identity
+ //
+ 0x0000000000000000,
};
--=20
2.28.0.windows.1

4941 - 4960 of 85992