summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-11 08:17:27 +0000
commitf215e02bf85f68d3a6106c2a1f4f7f063f819064 (patch)
tree6bb5b92c046312c4e95ac2620b10ddf482d3fa8b /src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library
parentInitial commit. (diff)
downloadvirtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.tar.xz
virtualbox-f215e02bf85f68d3a6106c2a1f4f7f063f819064.zip
Adding upstream version 7.0.14-dfsg.upstream/7.0.14-dfsg
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library')
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c38
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf41
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.nasm68
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm51
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c1254
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf45
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c1349
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf45
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c441
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni15
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c127
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf43
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h170
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c119
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf43
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Aesni.c119
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/C1e.c81
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ClockModulation.c131
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeatures.h1039
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c231
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf64
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.uni20
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Eist.c87
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FastStrings.c58
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c280
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/LimitCpuIdMaxval.c90
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MachineCheck.c344
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MonitorMwait.c88
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/PendingBreak.c95
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Ppin.c164
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c473
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/X2Apic.c137
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c183
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h321
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf63
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c287
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c427
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h46
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm456
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm390
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c262
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf62
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c314
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c228
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf55
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf58
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c154
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c427
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h43
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm400
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm455
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf60
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.uni18
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c41
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf35
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni17
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c279
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c322
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf32
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf78
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c956
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm348
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Microcode.c374
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpEqu.inc99
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.c2938
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.h745
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf74
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c729
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm778
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.c442
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf37
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.c2815
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf40
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c1163
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h195
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf43
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/RandomNumber.c5009
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c987
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c84
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf31
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni14
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c1190
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.c276
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf57
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.c309
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf57
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h268
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c1291
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.uni16
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf54
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.uni26
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c260
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/CpuFeaturesLib.h48
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiEntry.nasm276
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiException.nasm173
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmmStmSupport.c77
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c31
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf37
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni12
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibCommon.c613
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibNoStm.c84
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf74
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c1281
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.h179
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c50
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf38
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c28
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiEntry.nasm276
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiException.nasm176
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmmStmSupport.c89
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c102
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf34
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni12
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c165
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf27
-rw-r--r--src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni15
127 files changed, 38641 insertions, 0 deletions
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c
new file mode 100644
index 00000000..6b066671
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.c
@@ -0,0 +1,38 @@
+/** @file
+ This library defines some routines that are generic for IA32 family CPU.
+
+ The library routines are UEFI specification compliant.
+
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+
+#include <Library/BaseLib.h>
+#include <Library/UefiCpuLib.h>
+
+/**
+ Determine if the standard CPU signature is "AuthenticAMD".
+
+ @retval TRUE The CPU signature matches.
+ @retval FALSE The CPU signature does not match.
+
+**/
+BOOLEAN
+EFIAPI
+StandardSignatureIsAuthenticAMD (
+ VOID
+ )
+{
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+ UINT32 RegEdx;
+
+ AsmCpuid (CPUID_SIGNATURE, NULL, &RegEbx, &RegEcx, &RegEdx);
+ return (RegEbx == CPUID_SIGNATURE_AUTHENTIC_AMD_EBX &&
+ RegEcx == CPUID_SIGNATURE_AUTHENTIC_AMD_ECX &&
+ RegEdx == CPUID_SIGNATURE_AUTHENTIC_AMD_EDX);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
new file mode 100644
index 00000000..894917a3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.inf
@@ -0,0 +1,41 @@
+## @file
+# This library defines some routines that are generic for IA32 family CPU.
+#
+# The library routines are UEFI specification compliant.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseUefiCpuLib
+ MODULE_UNI_FILE = BaseUefiCpuLib.uni
+ FILE_GUID = 34C24FD7-7A90-45c2-89FD-946473D9CE98
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiCpuLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.IA32]
+ Ia32/InitializeFpu.nasm
+
+[Sources.X64]
+ X64/InitializeFpu.nasm
+
+[Sources]
+ BaseUefiCpuLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.uni
new file mode 100644
index 00000000..83c96cea
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/BaseUefiCpuLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// This library defines some routines that are generic for IA32 family CPU.
+//
+// The library routines are UEFI specification compliant.
+//
+// Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Defines generic routines for IA32 family CPUs."
+
+#string STR_MODULE_DESCRIPTION #language en-US "The library routines comply with the UEFI Specification."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.nasm
new file mode 100644
index 00000000..4ba5953b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/Ia32/InitializeFpu.nasm
@@ -0,0 +1,68 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2016 - 2017, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+ SECTION .rodata
+
+;
+; Float control word initial value:
+; all exceptions masked, double-precision, round-to-nearest
+;
+mFpuControlWord: DW 0x27F
+;
+; Multimedia-extensions control word:
+; all exceptions masked, round-to-nearest, flush to zero for masked underflow
+;
+mMmxControlWord: DD 0x1F80
+
+ SECTION .text
+
+;
+; Initializes floating point units for requirement of UEFI specification.
+;
+; This function initializes floating-point control word to 0x027F (all exceptions
+; masked,double-precision, round-to-nearest) and multimedia-extensions control word
+; (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero
+; for masked underflow).
+;
+global ASM_PFX(InitializeFloatingPointUnits)
+ASM_PFX(InitializeFloatingPointUnits):
+
+ push ebx
+
+ ;
+ ; Initialize floating point units
+ ;
+ finit
+ fldcw [mFpuControlWord]
+
+ ;
+ ; Use CpuId instructuion (CPUID.01H:EDX.SSE[bit 25] = 1) to test
+ ; whether the processor supports SSE instruction.
+ ;
+ mov eax, 1
+ cpuid
+ bt edx, 25
+ jnc Done
+
+ ;
+ ; Set OSFXSR bit 9 in CR4
+ ;
+ mov eax, cr4
+ or eax, BIT9
+ mov cr4, eax
+
+ ;
+ ; The processor should support SSE instruction and we can use
+ ; ldmxcsr instruction
+ ;
+ ldmxcsr [mMmxControlWord]
+Done:
+ pop ebx
+
+ ret
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm
new file mode 100644
index 00000000..bec21a2d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseUefiCpuLib/X64/InitializeFpu.nasm
@@ -0,0 +1,51 @@
+;------------------------------------------------------------------------------
+;*
+;* Copyright (c) 2009 - 2017, Intel Corporation. All rights reserved.<BR>
+;* SPDX-License-Identifier: BSD-2-Clause-Patent
+;*
+;*
+;------------------------------------------------------------------------------
+
+ SECTION .rodata
+;
+; Float control word initial value:
+; all exceptions masked, double-extended-precision, round-to-nearest
+;
+mFpuControlWord: DW 0x37F
+;
+; Multimedia-extensions control word:
+; all exceptions masked, round-to-nearest, flush to zero for masked underflow
+;
+mMmxControlWord: DD 0x1F80
+
+DEFAULT REL
+SECTION .text
+
+;
+; Initializes floating point units for requirement of UEFI specification.
+;
+; This function initializes floating-point control word to 0x027F (all exceptions
+; masked,double-precision, round-to-nearest) and multimedia-extensions control word
+; (if supported) to 0x1F80 (all exceptions masked, round-to-nearest, flush to zero
+; for masked underflow).
+;
+global ASM_PFX(InitializeFloatingPointUnits)
+ASM_PFX(InitializeFloatingPointUnits):
+
+ ;
+ ; Initialize floating point units
+ ;
+ finit
+ fldcw [mFpuControlWord]
+
+ ;
+ ; Set OSFXSR bit 9 in CR4
+ ;
+ mov rax, cr4
+ or rax, BIT9
+ mov cr4, rax
+
+ ldmxcsr [mMmxControlWord]
+
+ ret
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
new file mode 100644
index 00000000..434647ad
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.c
@@ -0,0 +1,1254 @@
+/** @file
+ Local APIC Library.
+
+ This local APIC library instance supports xAPIC mode only.
+
+ Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+#include <Register/Intel/Msr.h>
+#include <Register/Intel/LocalApic.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+
+//
+// Library internal functions
+//
+
+/**
+ Determine if the CPU supports the Local APIC Base Address MSR.
+
+ @retval TRUE The CPU supports the Local APIC Base Address MSR.
+ @retval FALSE The CPU does not support the Local APIC Base Address MSR.
+
+**/
+BOOLEAN
+LocalApicBaseAddressMsrSupported (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINTN FamilyId;
+
+ AsmCpuid (1, &RegEax, NULL, NULL, NULL);
+ FamilyId = BitFieldRead32 (RegEax, 8, 11);
+ if (FamilyId == 0x04 || FamilyId == 0x05) {
+ //
+ // CPUs with a FamilyId of 0x04 or 0x05 do not support the
+ // Local APIC Base Address MSR
+ //
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Retrieve the base address of local APIC.
+
+ @return The base address of local APIC.
+
+**/
+UINTN
+EFIAPI
+GetLocalApicBaseAddress (
+ VOID
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // If CPU does not support Local APIC Base Address MSR, then retrieve
+ // Local APIC Base Address from PCD
+ //
+ return PcdGet32 (PcdCpuLocalApicBaseAddress);
+ }
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
+ (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
+}
+
+/**
+ Set the base address of local APIC.
+
+ If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
+
+ @param[in] BaseAddress Local APIC base address to be set.
+
+**/
+VOID
+EFIAPI
+SetLocalApicBaseAddress (
+ IN UINTN BaseAddress
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // Ignore set request if the CPU does not support APIC Base Address MSR
+ //
+ return;
+ }
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ ApicBaseMsr.Bits.ApicBase = (UINT32) (BaseAddress >> 12);
+ ApicBaseMsr.Bits.ApicBaseHi = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
+
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+}
+
+/**
+ Read from a local APIC register.
+
+ This function reads from a local APIC register either in xAPIC or x2APIC mode.
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
+ accessed using multiple 32-bit loads or stores, so this function only performs
+ 32-bit read.
+
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
+ It must be 16-byte aligned.
+
+ @return 32-bit Value read from the register.
+**/
+UINT32
+EFIAPI
+ReadLocalApicReg (
+ IN UINTN MmioOffset
+ )
+{
+ ASSERT ((MmioOffset & 0xf) == 0);
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+
+ return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
+}
+
+/**
+ Write to a local APIC register.
+
+ This function writes to a local APIC register either in xAPIC or x2APIC mode.
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
+ accessed using multiple 32-bit loads or stores, so this function only performs
+ 32-bit write.
+
+ if the register index is invalid or unsupported in current APIC mode, then ASSERT.
+
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
+ It must be 16-byte aligned.
+ @param Value Value to be written to the register.
+**/
+VOID
+EFIAPI
+WriteLocalApicReg (
+ IN UINTN MmioOffset,
+ IN UINT32 Value
+ )
+{
+ ASSERT ((MmioOffset & 0xf) == 0);
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+
+ MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
+}
+
+/**
+ Send an IPI by writing to ICR.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param IcrLow 32-bit value to be written to the low half of ICR.
+ @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
+**/
+VOID
+SendIpi (
+ IN UINT32 IcrLow,
+ IN UINT32 ApicId
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLowReg;
+ UINT32 IcrHigh;
+ BOOLEAN InterruptState;
+
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+ ASSERT (ApicId <= 0xff);
+
+ InterruptState = SaveAndDisableInterrupts ();
+
+ //
+ // Save existing contents of ICR high 32 bits
+ //
+ IcrHigh = ReadLocalApicReg (XAPIC_ICR_HIGH_OFFSET);
+
+ //
+ // Wait for DeliveryStatus clear in case a previous IPI
+ // is still being sent
+ //
+ do {
+ IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
+ //
+ WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
+ WriteLocalApicReg (XAPIC_ICR_LOW_OFFSET, IcrLow);
+
+ //
+ // Wait for DeliveryStatus clear again
+ //
+ do {
+ IcrLowReg.Uint32 = ReadLocalApicReg (XAPIC_ICR_LOW_OFFSET);
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // And restore old contents of ICR high
+ //
+ WriteLocalApicReg (XAPIC_ICR_HIGH_OFFSET, IcrHigh);
+
+ SetInterruptState (InterruptState);
+
+}
+
+//
+// Library API implementation functions
+//
+
+/**
+ Get the current local APIC mode.
+
+ If local APIC is disabled, then ASSERT.
+
+ @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
+ @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
+**/
+UINTN
+EFIAPI
+GetApicMode (
+ VOID
+ )
+{
+ DEBUG_CODE (
+ {
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ //
+ // Check to see if the CPU supports the APIC Base Address MSR
+ //
+ if (LocalApicBaseAddressMsrSupported ()) {
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ //
+ // Local APIC should have been enabled
+ //
+ ASSERT (ApicBaseMsr.Bits.EN != 0);
+ ASSERT (ApicBaseMsr.Bits.EXTD == 0);
+ }
+ }
+ );
+ return LOCAL_APIC_MODE_XAPIC;
+}
+
+/**
+ Set the current local APIC mode.
+
+ If the specified local APIC mode is not valid, then ASSERT.
+ If the specified local APIC mode can't be set as current, then ASSERT.
+
+ @param ApicMode APIC mode to be set.
+
+ @note This API must not be called from an interrupt handler or SMI handler.
+ It may result in unpredictable behavior.
+**/
+VOID
+EFIAPI
+SetApicMode (
+ IN UINTN ApicMode
+ )
+{
+ ASSERT (ApicMode == LOCAL_APIC_MODE_XAPIC);
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+}
+
+/**
+ Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
+
+ In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
+ In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
+ the 32-bit local APIC ID is returned as initial APIC ID.
+
+ @return 32-bit initial local APIC ID of the executing processor.
+**/
+UINT32
+EFIAPI
+GetInitialApicId (
+ VOID
+ )
+{
+ UINT32 ApicId;
+ UINT32 MaxCpuIdIndex;
+ UINT32 RegEbx;
+
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If CPUID Leaf B is supported,
+ // And CPUID.0BH:EBX[15:0] reports a non-zero value,
+ // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
+ // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
+ //
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
+ if ((RegEbx & (BIT16 - 1)) != 0) {
+ return ApicId;
+ }
+ }
+
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ return RegEbx >> 24;
+}
+
+/**
+ Get the local APIC ID of the executing processor.
+
+ @return 32-bit local APIC ID of the executing processor.
+**/
+UINT32
+EFIAPI
+GetApicId (
+ VOID
+ )
+{
+ UINT32 ApicId;
+
+ ASSERT (GetApicMode () == LOCAL_APIC_MODE_XAPIC);
+
+ if ((ApicId = GetInitialApicId ()) < 0x100) {
+ //
+ // If the initial local APIC ID is less 0x100, read APIC ID from
+ // XAPIC_ID_OFFSET, otherwise return the initial local APIC ID.
+ //
+ ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
+ ApicId >>= 24;
+ }
+ return ApicId;
+}
+
+/**
+ Get the value of the local APIC version register.
+
+ @return the value of the local APIC version register.
+**/
+UINT32
+EFIAPI
+GetApicVersion (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
+}
+
+/**
+ Send a Fixed IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId The local APIC ID of the target processor.
+ @param Vector The vector number of the interrupt being sent.
+**/
+VOID
+EFIAPI
+SendFixedIpi (
+ IN UINT32 ApicId,
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.Vector = Vector;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send a Fixed IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+
+ @param Vector The vector number of the interrupt being sent.
+**/
+VOID
+EFIAPI
+SendFixedIpiAllExcludingSelf (
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ IcrLow.Bits.Vector = Vector;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send a SMI IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+**/
+VOID
+EFIAPI
+SendSmiIpi (
+ IN UINT32 ApicId
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send a SMI IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+**/
+VOID
+EFIAPI
+SendSmiIpiAllExcludingSelf (
+ VOID
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send an INIT IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+**/
+VOID
+EFIAPI
+SendInitIpi (
+ IN UINT32 ApicId
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send an INIT IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+**/
+VOID
+EFIAPI
+SendInitIpiAllExcludingSelf (
+ VOID
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ if StartupRoutine >= 1M, then ASSERT.
+ if StartupRoutine is not multiple of 4K, then ASSERT.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+ @param StartupRoutine Points to a start-up routine which is below 1M physical
+ address and 4K aligned.
+**/
+VOID
+EFIAPI
+SendInitSipiSipi (
+ IN UINT32 ApicId,
+ IN UINT32 StartupRoutine
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ ASSERT (StartupRoutine < 0x100000);
+ ASSERT ((StartupRoutine & 0xfff) == 0);
+
+ SendInitIpi (ApicId);
+ MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+ if (!StandardSignatureIsAuthenticAMD ()) {
+ MicroSecondDelay (200);
+ SendIpi (IcrLow.Uint32, ApicId);
+ }
+}
+
+/**
+ Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+
+ if StartupRoutine >= 1M, then ASSERT.
+ if StartupRoutine is not multiple of 4K, then ASSERT.
+
+ @param StartupRoutine Points to a start-up routine which is below 1M physical
+ address and 4K aligned.
+**/
+VOID
+EFIAPI
+SendInitSipiSipiAllExcludingSelf (
+ IN UINT32 StartupRoutine
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ ASSERT (StartupRoutine < 0x100000);
+ ASSERT ((StartupRoutine & 0xfff) == 0);
+
+ SendInitIpiAllExcludingSelf ();
+ MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+ if (!StandardSignatureIsAuthenticAMD ()) {
+ MicroSecondDelay (200);
+ SendIpi (IcrLow.Uint32, 0);
+ }
+}
+
+/**
+ Initialize the state of the SoftwareEnable bit in the Local APIC
+ Spurious Interrupt Vector register.
+
+ @param Enable If TRUE, then set SoftwareEnable to 1
+ If FALSE, then set SoftwareEnable to 0.
+
+**/
+VOID
+EFIAPI
+InitializeLocalApicSoftwareEnable (
+ IN BOOLEAN Enable
+ )
+{
+ LOCAL_APIC_SVR Svr;
+
+ //
+ // Set local APIC software-enabled bit.
+ //
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
+ if (Enable) {
+ if (Svr.Bits.SoftwareEnable == 0) {
+ Svr.Bits.SoftwareEnable = 1;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+ }
+ } else {
+ if (Svr.Bits.SoftwareEnable == 1) {
+ Svr.Bits.SoftwareEnable = 0;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+ }
+ }
+}
+
+/**
+ Programming Virtual Wire Mode.
+
+ This function programs the local APIC for virtual wire mode following
+ the example described in chapter A.3 of the MP 1.4 spec.
+
+ IOxAPIC is not involved in this type of virtual wire mode.
+**/
+VOID
+EFIAPI
+ProgramVirtualWireMode (
+ VOID
+ )
+{
+ LOCAL_APIC_SVR Svr;
+ LOCAL_APIC_LVT_LINT Lint;
+
+ //
+ // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
+ //
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
+ Svr.Bits.SpuriousVector = 0xf;
+ Svr.Bits.SoftwareEnable = 1;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+
+ //
+ // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
+ //
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
+ Lint.Bits.InputPinPolarity = 0;
+ Lint.Bits.TriggerMode = 0;
+ Lint.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
+
+ //
+ // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
+ //
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
+ Lint.Bits.InputPinPolarity = 0;
+ Lint.Bits.TriggerMode = 0;
+ Lint.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
+}
+
+/**
+ Disable LINT0 & LINT1 interrupts.
+
+ This function sets the mask flag in the LVT LINT0 & LINT1 registers.
+**/
+VOID
+EFIAPI
+DisableLvtInterrupts (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_LINT LvtLint;
+
+ LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
+ LvtLint.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
+
+ LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
+ LvtLint.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
+}
+
+/**
+ Read the initial count value from the init-count register.
+
+ @return The initial count value read from the init-count register.
+**/
+UINT32
+EFIAPI
+GetApicTimerInitCount (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
+}
+
+/**
+ Read the current count value from the current-count register.
+
+ @return The current count value read from the current-count register.
+**/
+UINT32
+EFIAPI
+GetApicTimerCurrentCount (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
+}
+
+/**
+ Initialize the local APIC timer.
+
+ The local APIC timer is initialized and enabled.
+
+ @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
+ If it is 0, then use the current divide value in the DCR.
+ @param InitCount The initial count value.
+ @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
+ @param Vector The timer interrupt vector number.
+**/
+VOID
+EFIAPI
+InitializeApicTimer (
+ IN UINTN DivideValue,
+ IN UINT32 InitCount,
+ IN BOOLEAN PeriodicMode,
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_DCR Dcr;
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+ UINT32 Divisor;
+
+ //
+ // Ensure local APIC is in software-enabled state.
+ //
+ InitializeLocalApicSoftwareEnable (TRUE);
+
+ //
+ // Program init-count register.
+ //
+ WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
+
+ if (DivideValue != 0) {
+ ASSERT (DivideValue <= 128);
+ ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
+ Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
+
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
+ Dcr.Bits.DivideValue1 = (Divisor & 0x3);
+ Dcr.Bits.DivideValue2 = (Divisor >> 2);
+ WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
+ }
+
+ //
+ // Enable APIC timer interrupt with specified timer mode.
+ //
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ if (PeriodicMode) {
+ LvtTimer.Bits.TimerMode = 1;
+ } else {
+ LvtTimer.Bits.TimerMode = 0;
+ }
+ LvtTimer.Bits.Mask = 0;
+ LvtTimer.Bits.Vector = Vector;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Get the state of the local APIC timer.
+
+ This function will ASSERT if the local APIC is not software enabled.
+
+ @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
+ @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
+ @param Vector Return the timer interrupt vector number.
+**/
+VOID
+EFIAPI
+GetApicTimerState (
+ OUT UINTN *DivideValue OPTIONAL,
+ OUT BOOLEAN *PeriodicMode OPTIONAL,
+ OUT UINT8 *Vector OPTIONAL
+ )
+{
+ UINT32 Divisor;
+ LOCAL_APIC_DCR Dcr;
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ //
+ // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
+ // Vector Register.
+ // This bit will be 1, if local APIC is software enabled.
+ //
+ ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
+
+ if (DivideValue != NULL) {
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
+ Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
+ Divisor = (Divisor + 1) & 0x7;
+ *DivideValue = ((UINTN)1) << Divisor;
+ }
+
+ if (PeriodicMode != NULL || Vector != NULL) {
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ if (PeriodicMode != NULL) {
+ if (LvtTimer.Bits.TimerMode == 1) {
+ *PeriodicMode = TRUE;
+ } else {
+ *PeriodicMode = FALSE;
+ }
+ }
+ if (Vector != NULL) {
+ *Vector = (UINT8) LvtTimer.Bits.Vector;
+ }
+ }
+}
+
+/**
+ Enable the local APIC timer interrupt.
+**/
+VOID
+EFIAPI
+EnableApicTimerInterrupt (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ LvtTimer.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Disable the local APIC timer interrupt.
+**/
+VOID
+EFIAPI
+DisableApicTimerInterrupt (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ LvtTimer.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Get the local APIC timer interrupt state.
+
+ @retval TRUE The local APIC timer interrupt is enabled.
+ @retval FALSE The local APIC timer interrupt is disabled.
+**/
+BOOLEAN
+EFIAPI
+GetApicTimerInterruptState (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
+}
+
+/**
+ Send EOI to the local APIC.
+**/
+VOID
+EFIAPI
+SendApicEoi (
+ VOID
+ )
+{
+ WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
+}
+
+/**
+ Get the 32-bit address that a device should use to send a Message Signaled
+ Interrupt (MSI) to the Local APIC of the currently executing processor.
+
+ @return 32-bit address used to send an MSI to the Local APIC.
+**/
+UINT32
+EFIAPI
+GetApicMsiAddress (
+ VOID
+ )
+{
+ LOCAL_APIC_MSI_ADDRESS MsiAddress;
+
+ //
+ // Return address for an MSI interrupt to be delivered only to the APIC ID
+ // of the currently executing processor.
+ //
+ MsiAddress.Uint32 = 0;
+ MsiAddress.Bits.BaseAddress = 0xFEE;
+ MsiAddress.Bits.DestinationId = GetApicId ();
+ return MsiAddress.Uint32;
+}
+
+/**
+ Get the 64-bit data value that a device should use to send a Message Signaled
+ Interrupt (MSI) to the Local APIC of the currently executing processor.
+
+ If Vector is not in range 0x10..0xFE, then ASSERT().
+ If DeliveryMode is not supported, then ASSERT().
+
+ @param Vector The 8-bit interrupt vector associated with the MSI.
+ Must be in the range 0x10..0xFE
+ @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
+ is handled. The only supported values are:
+ 0: LOCAL_APIC_DELIVERY_MODE_FIXED
+ 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
+ 2: LOCAL_APIC_DELIVERY_MODE_SMI
+ 4: LOCAL_APIC_DELIVERY_MODE_NMI
+ 5: LOCAL_APIC_DELIVERY_MODE_INIT
+ 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
+
+ @param LevelTriggered TRUE specifies a level triggered interrupt.
+ FALSE specifies an edge triggered interrupt.
+ @param AssertionLevel Ignored if LevelTriggered is FALSE.
+ TRUE specifies a level triggered interrupt that active
+ when the interrupt line is asserted.
+ FALSE specifies a level triggered interrupt that active
+ when the interrupt line is deasserted.
+
+ @return 64-bit data value used to send an MSI to the Local APIC.
+**/
+UINT64
+EFIAPI
+GetApicMsiValue (
+ IN UINT8 Vector,
+ IN UINTN DeliveryMode,
+ IN BOOLEAN LevelTriggered,
+ IN BOOLEAN AssertionLevel
+ )
+{
+ LOCAL_APIC_MSI_DATA MsiData;
+
+ ASSERT (Vector >= 0x10 && Vector <= 0xFE);
+ ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
+
+ MsiData.Uint64 = 0;
+ MsiData.Bits.Vector = Vector;
+ MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
+ if (LevelTriggered) {
+ MsiData.Bits.TriggerMode = 1;
+ if (AssertionLevel) {
+ MsiData.Bits.Level = 1;
+ }
+ }
+ return MsiData.Uint64;
+}
+
+/**
+ Get Package ID/Core ID/Thread ID of a processor.
+
+ The algorithm assumes the target system has symmetry across physical
+ package boundaries with respect to the number of logical processors
+ per package, number of cores per package.
+
+ @param[in] InitialApicId Initial APIC ID of the target logical processor.
+ @param[out] Package Returns the processor package ID.
+ @param[out] Core Returns the processor core ID.
+ @param[out] Thread Returns the processor thread ID.
+**/
+VOID
+EFIAPI
+GetProcessorLocationByApicId (
+ IN UINT32 InitialApicId,
+ OUT UINT32 *Package OPTIONAL,
+ OUT UINT32 *Core OPTIONAL,
+ OUT UINT32 *Thread OPTIONAL
+ )
+{
+ BOOLEAN TopologyLeafSupported;
+ CPUID_VERSION_INFO_EBX VersionInfoEbx;
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+ CPUID_CACHE_PARAMS_EAX CacheParamsEax;
+ CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
+ CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
+ CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
+ CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
+ CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
+ CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
+ UINT32 MaxStandardCpuIdIndex;
+ UINT32 MaxExtendedCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+ UINTN ThreadBits;
+ UINTN CoreBits;
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.HTT == 0) {
+ if (Thread != NULL) {
+ *Thread = 0;
+ }
+ if (Core != NULL) {
+ *Core = 0;
+ }
+ if (Package != NULL) {
+ *Package = 0;
+ }
+ return;
+ }
+
+ //
+ // Assume three-level mapping of APIC ID: Package|Core|Thread.
+ //
+ ThreadBits = 0;
+ CoreBits = 0;
+
+ //
+ // Get max index of CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If the extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ TopologyLeafSupported = FALSE;
+ if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx(
+ CPUID_EXTENDED_TOPOLOGY,
+ 0,
+ &ExtendedTopologyEax.Uint32,
+ &ExtendedTopologyEbx.Uint32,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ //
+ // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
+ // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
+ // supported on that processor.
+ //
+ if (ExtendedTopologyEbx.Uint32 != 0) {
+ TopologyLeafSupported = TRUE;
+
+ //
+ // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
+ // the SMT sub-field of x2APIC ID.
+ //
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
+ ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
+
+ //
+ // Software must not assume any "level type" encoding
+ // value to be related to any sub-leaf index, except sub-leaf 0.
+ //
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (
+ CPUID_EXTENDED_TOPOLOGY,
+ SubIndex,
+ &ExtendedTopologyEax.Uint32,
+ NULL,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+ }
+ }
+
+ if (!TopologyLeafSupported) {
+ //
+ // Get logical processor count
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
+ MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
+
+ //
+ // Assume single-core processor
+ //
+ MaxCoresPerPackage = 1;
+
+ //
+ // Check for topology extensions on AMD processor
+ //
+ if (StandardSignatureIsAuthenticAMD()) {
+ if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
+ if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
+ //
+ // Account for max possible thread count to decode ApicId
+ //
+ AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
+ MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
+
+ //
+ // Get cores per processor package
+ //
+ AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
+ MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
+ }
+ }
+ }
+ else {
+ //
+ // Extract core count based on CACHE information
+ //
+ if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
+ if (CacheParamsEax.Uint32 != 0) {
+ MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
+ }
+ }
+ }
+
+ ThreadBits = (UINTN)(HighBitSet32(MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN)(HighBitSet32(MaxCoresPerPackage - 1) + 1);
+ }
+
+ if (Thread != NULL) {
+ *Thread = InitialApicId & ((1 << ThreadBits) - 1);
+ }
+ if (Core != NULL) {
+ *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
+ }
+ if (Package != NULL) {
+ *Package = (InitialApicId >> (ThreadBits + CoreBits));
+ }
+}
+
+/**
+ Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
+
+ The algorithm assumes the target system has symmetry across physical
+ package boundaries with respect to the number of threads per core, number of
+ cores per module, number of modules per tile, number of tiles per die, number
+ of dies per package.
+
+ @param[in] InitialApicId Initial APIC ID of the target logical processor.
+ @param[out] Package Returns the processor package ID.
+ @param[out] Die Returns the processor die ID.
+ @param[out] Tile Returns the processor tile ID.
+ @param[out] Module Returns the processor module ID.
+ @param[out] Core Returns the processor core ID.
+ @param[out] Thread Returns the processor thread ID.
+**/
+VOID
+EFIAPI
+GetProcessorLocation2ByApicId (
+ IN UINT32 InitialApicId,
+ OUT UINT32 *Package OPTIONAL,
+ OUT UINT32 *Die OPTIONAL,
+ OUT UINT32 *Tile OPTIONAL,
+ OUT UINT32 *Module OPTIONAL,
+ OUT UINT32 *Core OPTIONAL,
+ OUT UINT32 *Thread OPTIONAL
+ )
+{
+ CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
+ CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
+ UINT32 MaxStandardCpuIdIndex;
+ UINT32 Index;
+ UINTN LevelType;
+ UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
+ UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
+
+ for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
+ Bits[LevelType] = 0;
+ }
+
+ //
+ // Get max index of CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
+ if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
+ if (Die != NULL) {
+ *Die = 0;
+ }
+ if (Tile != NULL) {
+ *Tile = 0;
+ }
+ if (Module != NULL) {
+ *Module = 0;
+ }
+ GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
+ return;
+ }
+
+ //
+ // If the V2 extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ for (Index = 0; ; Index++) {
+ AsmCpuidEx(
+ CPUID_V2_EXTENDED_TOPOLOGY,
+ Index,
+ &ExtendedTopologyEax.Uint32,
+ NULL,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+
+ //
+ // first level reported should be SMT.
+ //
+ ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
+ break;
+ }
+ ASSERT (LevelType < ARRAY_SIZE (Bits));
+ Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
+ }
+
+ for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
+ //
+ // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
+ // and treated as an extension of the last known level (i.e., level-1 in this case).
+ //
+ if (Bits[LevelType] == 0) {
+ Bits[LevelType] = Bits[LevelType - 1];
+ }
+ }
+
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE ] = Die;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE ] = Tile;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE ] = Module;
+ Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE ] = Core;
+ Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT ] = Thread;
+
+ Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
+
+ for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
+ ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
+ ; LevelType ++
+ ) {
+ if (Location[LevelType] != NULL) {
+ //
+ // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
+ // topology ID of the next level type.
+ //
+ *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
+
+ //
+ // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
+ //
+ *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
+ }
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
new file mode 100644
index 00000000..c55a7382
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.inf
@@ -0,0 +1,45 @@
+## @file
+# The Local Apic library supports xAPIC mode only.
+#
+# Note: Local APIC library assumes local APIC is enabled. It does not handle cases
+# where local APIC is disabled.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseXApicLib
+ MODULE_UNI_FILE = BaseXApicLib.uni
+ FILE_GUID = D87CA0A8-1AC2-439b-90F8-EF4A2AC88DAF
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = LocalApicLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ BaseXApicLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ TimerLib
+ IoLib
+ PcdLib
+ UefiCpuLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.uni
new file mode 100644
index 00000000..1e645f59
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicLib/BaseXApicLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The Local Apic library supports xAPIC mode only.
+//
+// Note: Local APIC library assumes local APIC is enabled. It does not handle cases
+// where local APIC is disabled.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Supports xAPIC mode only"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note: Local APIC library assumes local APIC is enabled. It does not handle cases where local APIC is disabled."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
new file mode 100644
index 00000000..5bd4c2b7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.c
@@ -0,0 +1,1349 @@
+/** @file
+ Local APIC Library.
+
+ This local APIC library instance supports x2APIC capable processors
+ which have xAPIC and x2APIC modes.
+
+ Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2017 - 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+#include <Register/Intel/Msr.h>
+#include <Register/Intel/LocalApic.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/IoLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiCpuLib.h>
+
+//
+// Library internal functions
+//
+
+/**
+ Determine if the CPU supports the Local APIC Base Address MSR.
+
+ @retval TRUE The CPU supports the Local APIC Base Address MSR.
+ @retval FALSE The CPU does not support the Local APIC Base Address MSR.
+
+**/
+BOOLEAN
+LocalApicBaseAddressMsrSupported (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINTN FamilyId;
+
+ AsmCpuid (1, &RegEax, NULL, NULL, NULL);
+ FamilyId = BitFieldRead32 (RegEax, 8, 11);
+ if (FamilyId == 0x04 || FamilyId == 0x05) {
+ //
+ // CPUs with a FamilyId of 0x04 or 0x05 do not support the
+ // Local APIC Base Address MSR
+ //
+ return FALSE;
+ }
+ return TRUE;
+}
+
+/**
+ Retrieve the base address of local APIC.
+
+ @return The base address of local APIC.
+
+**/
+UINTN
+EFIAPI
+GetLocalApicBaseAddress (
+ VOID
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // If CPU does not support Local APIC Base Address MSR, then retrieve
+ // Local APIC Base Address from PCD
+ //
+ return PcdGet32 (PcdCpuLocalApicBaseAddress);
+ }
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ return (UINTN)(LShiftU64 ((UINT64) ApicBaseMsr.Bits.ApicBaseHi, 32)) +
+ (((UINTN)ApicBaseMsr.Bits.ApicBase) << 12);
+}
+
+/**
+ Set the base address of local APIC.
+
+ If BaseAddress is not aligned on a 4KB boundary, then ASSERT().
+
+ @param[in] BaseAddress Local APIC base address to be set.
+
+**/
+VOID
+EFIAPI
+SetLocalApicBaseAddress (
+ IN UINTN BaseAddress
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ ASSERT ((BaseAddress & (SIZE_4KB - 1)) == 0);
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // Ignore set request of the CPU does not support APIC Base Address MSR
+ //
+ return;
+ }
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+
+ ApicBaseMsr.Bits.ApicBase = (UINT32) (BaseAddress >> 12);
+ ApicBaseMsr.Bits.ApicBaseHi = (UINT32) (RShiftU64((UINT64) BaseAddress, 32));
+
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+}
+
+/**
+ Read from a local APIC register.
+
+ This function reads from a local APIC register either in xAPIC or x2APIC mode.
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
+ accessed using multiple 32-bit loads or stores, so this function only performs
+ 32-bit read.
+
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
+ It must be 16-byte aligned.
+
+ @return 32-bit Value read from the register.
+**/
+UINT32
+EFIAPI
+ReadLocalApicReg (
+ IN UINTN MmioOffset
+ )
+{
+ UINT32 MsrIndex;
+
+ ASSERT ((MmioOffset & 0xf) == 0);
+
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
+ return MmioRead32 (GetLocalApicBaseAddress() + MmioOffset);
+ } else {
+ //
+ // DFR is not supported in x2APIC mode.
+ //
+ ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
+ //
+ // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
+ // is not supported in this function for simplicity.
+ //
+ ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
+
+ MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
+ return AsmReadMsr32 (MsrIndex);
+ }
+}
+
+/**
+ Write to a local APIC register.
+
+ This function writes to a local APIC register either in xAPIC or x2APIC mode.
+ It is required that in xAPIC mode wider registers (64-bit or 256-bit) must be
+ accessed using multiple 32-bit loads or stores, so this function only performs
+ 32-bit write.
+
+ if the register index is invalid or unsupported in current APIC mode, then ASSERT.
+
+ @param MmioOffset The MMIO offset of the local APIC register in xAPIC mode.
+ It must be 16-byte aligned.
+ @param Value Value to be written to the register.
+**/
+VOID
+EFIAPI
+WriteLocalApicReg (
+ IN UINTN MmioOffset,
+ IN UINT32 Value
+ )
+{
+ UINT32 MsrIndex;
+
+ ASSERT ((MmioOffset & 0xf) == 0);
+
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
+ MmioWrite32 (GetLocalApicBaseAddress() + MmioOffset, Value);
+ } else {
+ //
+ // DFR is not supported in x2APIC mode.
+ //
+ ASSERT (MmioOffset != XAPIC_ICR_DFR_OFFSET);
+ //
+ // Note that in x2APIC mode, ICR is a 64-bit MSR that needs special treatment. It
+ // is not supported in this function for simplicity.
+ //
+ ASSERT (MmioOffset != XAPIC_ICR_HIGH_OFFSET);
+ ASSERT (MmioOffset != XAPIC_ICR_LOW_OFFSET);
+
+ MsrIndex = (UINT32)(MmioOffset >> 4) + X2APIC_MSR_BASE_ADDRESS;
+ //
+ // The serializing semantics of WRMSR are relaxed when writing to the APIC registers.
+ // Use memory fence here to force the serializing semantics to be consisent with xAPIC mode.
+ //
+ MemoryFence ();
+ AsmWriteMsr32 (MsrIndex, Value);
+ }
+}
+
+/**
+ Send an IPI by writing to ICR.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param IcrLow 32-bit value to be written to the low half of ICR.
+ @param ApicId APIC ID of the target processor if this IPI is targeted for a specific processor.
+**/
+VOID
+SendIpi (
+ IN UINT32 IcrLow,
+ IN UINT32 ApicId
+ )
+{
+ UINT64 MsrValue;
+ LOCAL_APIC_ICR_LOW IcrLowReg;
+ UINTN LocalApciBaseAddress;
+ UINT32 IcrHigh;
+ BOOLEAN InterruptState;
+
+ //
+ // Legacy APIC or X2APIC?
+ //
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
+ ASSERT (ApicId <= 0xff);
+
+ InterruptState = SaveAndDisableInterrupts ();
+
+ //
+ // Get base address of this LAPIC
+ //
+ LocalApciBaseAddress = GetLocalApicBaseAddress();
+
+ //
+ // Save existing contents of ICR high 32 bits
+ //
+ IcrHigh = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET);
+
+ //
+ // Wait for DeliveryStatus clear in case a previous IPI
+ // is still being sent
+ //
+ do {
+ IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // For xAPIC, the act of writing to the low doubleword of the ICR causes the IPI to be sent.
+ //
+ MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, ApicId << 24);
+ MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET, IcrLow);
+
+ //
+ // Wait for DeliveryStatus clear again
+ //
+ do {
+ IcrLowReg.Uint32 = MmioRead32 (LocalApciBaseAddress + XAPIC_ICR_LOW_OFFSET);
+ } while (IcrLowReg.Bits.DeliveryStatus != 0);
+
+ //
+ // And restore old contents of ICR high
+ //
+ MmioWrite32 (LocalApciBaseAddress + XAPIC_ICR_HIGH_OFFSET, IcrHigh);
+
+ SetInterruptState (InterruptState);
+
+ } else {
+ //
+ // For x2APIC, A single MSR write to the Interrupt Command Register is required for dispatching an
+ // interrupt in x2APIC mode.
+ //
+ MsrValue = LShiftU64 ((UINT64) ApicId, 32) | IcrLow;
+ AsmWriteMsr64 (X2APIC_MSR_ICR_ADDRESS, MsrValue);
+ }
+}
+
+//
+// Library API implementation functions
+//
+
+/**
+ Get the current local APIC mode.
+
+ If local APIC is disabled, then ASSERT.
+
+ @retval LOCAL_APIC_MODE_XAPIC current APIC mode is xAPIC.
+ @retval LOCAL_APIC_MODE_X2APIC current APIC mode is x2APIC.
+**/
+UINTN
+EFIAPI
+GetApicMode (
+ VOID
+ )
+{
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // If CPU does not support APIC Base Address MSR, then return XAPIC mode
+ //
+ return LOCAL_APIC_MODE_XAPIC;
+ }
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ //
+ // Local APIC should have been enabled
+ //
+ ASSERT (ApicBaseMsr.Bits.EN != 0);
+ if (ApicBaseMsr.Bits.EXTD != 0) {
+ return LOCAL_APIC_MODE_X2APIC;
+ } else {
+ return LOCAL_APIC_MODE_XAPIC;
+ }
+}
+
+/**
+ Set the current local APIC mode.
+
+ If the specified local APIC mode is not valid, then ASSERT.
+ If the specified local APIC mode can't be set as current, then ASSERT.
+
+ @param ApicMode APIC mode to be set.
+
+ @note This API must not be called from an interrupt handler or SMI handler.
+ It may result in unpredictable behavior.
+**/
+VOID
+EFIAPI
+SetApicMode (
+ IN UINTN ApicMode
+ )
+{
+ UINTN CurrentMode;
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+
+ if (!LocalApicBaseAddressMsrSupported ()) {
+ //
+ // Ignore set request if the CPU does not support APIC Base Address MSR
+ //
+ return;
+ }
+
+ CurrentMode = GetApicMode ();
+ if (CurrentMode == LOCAL_APIC_MODE_XAPIC) {
+ switch (ApicMode) {
+ case LOCAL_APIC_MODE_XAPIC:
+ break;
+ case LOCAL_APIC_MODE_X2APIC:
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.EXTD = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ } else {
+ switch (ApicMode) {
+ case LOCAL_APIC_MODE_XAPIC:
+ //
+ // Transition from x2APIC mode to xAPIC mode is a two-step process:
+ // x2APIC -> Local APIC disabled -> xAPIC
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.EXTD = 0;
+ ApicBaseMsr.Bits.EN = 0;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ ApicBaseMsr.Bits.EN = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ break;
+ case LOCAL_APIC_MODE_X2APIC:
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ }
+}
+
+/**
+ Get the initial local APIC ID of the executing processor assigned by hardware upon power on or reset.
+
+ In xAPIC mode, the initial local APIC ID may be different from current APIC ID.
+ In x2APIC mode, the local APIC ID can't be changed and there is no concept of initial APIC ID. In this case,
+ the 32-bit local APIC ID is returned as initial APIC ID.
+
+ @return 32-bit initial local APIC ID of the executing processor.
+**/
+UINT32
+EFIAPI
+GetInitialApicId (
+ VOID
+ )
+{
+ UINT32 ApicId;
+ UINT32 MaxCpuIdIndex;
+ UINT32 RegEbx;
+
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
+ //
+ // Get the max index of basic CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxCpuIdIndex, NULL, NULL, NULL);
+ //
+ // If CPUID Leaf B is supported,
+ // And CPUID.0BH:EBX[15:0] reports a non-zero value,
+ // Then the initial 32-bit APIC ID = CPUID.0BH:EDX
+ // Else the initial 8-bit APIC ID = CPUID.1:EBX[31:24]
+ //
+ if (MaxCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, NULL, &RegEbx, NULL, &ApicId);
+ if ((RegEbx & (BIT16 - 1)) != 0) {
+ return ApicId;
+ }
+ }
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &RegEbx, NULL, NULL);
+ return RegEbx >> 24;
+ } else {
+ return GetApicId ();
+ }
+}
+
+/**
+ Get the local APIC ID of the executing processor.
+
+ @return 32-bit local APIC ID of the executing processor.
+**/
+UINT32
+EFIAPI
+GetApicId (
+ VOID
+ )
+{
+ UINT32 ApicId;
+ UINT32 InitApicId;
+
+ ApicId = ReadLocalApicReg (XAPIC_ID_OFFSET);
+ if (GetApicMode () == LOCAL_APIC_MODE_XAPIC) {
+ ApicId = ((InitApicId = GetInitialApicId ()) < 0x100) ? (ApicId >> 24) : InitApicId;
+ }
+
+ return ApicId;
+}
+
+/**
+ Get the value of the local APIC version register.
+
+ @return the value of the local APIC version register.
+**/
+UINT32
+EFIAPI
+GetApicVersion (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_VERSION_OFFSET);
+}
+
+/**
+ Send a Fixed IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId The local APIC ID of the target processor.
+ @param Vector The vector number of the interrupt being sent.
+**/
+VOID
+EFIAPI
+SendFixedIpi (
+ IN UINT32 ApicId,
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.Vector = Vector;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send a Fixed IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+
+ @param Vector The vector number of the interrupt being sent.
+**/
+VOID
+EFIAPI
+SendFixedIpiAllExcludingSelf (
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_FIXED;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ IcrLow.Bits.Vector = Vector;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send a SMI IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+**/
+VOID
+EFIAPI
+SendSmiIpi (
+ IN UINT32 ApicId
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send a SMI IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+**/
+VOID
+EFIAPI
+SendSmiIpiAllExcludingSelf (
+ VOID
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_SMI;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send an INIT IPI to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+**/
+VOID
+EFIAPI
+SendInitIpi (
+ IN UINT32 ApicId
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+}
+
+/**
+ Send an INIT IPI to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+**/
+VOID
+EFIAPI
+SendInitIpiAllExcludingSelf (
+ VOID
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_INIT;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+}
+
+/**
+ Send an INIT-Start-up-Start-up IPI sequence to a specified target processor.
+
+ This function returns after the IPI has been accepted by the target processor.
+
+ if StartupRoutine >= 1M, then ASSERT.
+ if StartupRoutine is not multiple of 4K, then ASSERT.
+
+ @param ApicId Specify the local APIC ID of the target processor.
+ @param StartupRoutine Points to a start-up routine which is below 1M physical
+ address and 4K aligned.
+**/
+VOID
+EFIAPI
+SendInitSipiSipi (
+ IN UINT32 ApicId,
+ IN UINT32 StartupRoutine
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ ASSERT (StartupRoutine < 0x100000);
+ ASSERT ((StartupRoutine & 0xfff) == 0);
+
+ SendInitIpi (ApicId);
+ MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
+ IcrLow.Bits.Level = 1;
+ SendIpi (IcrLow.Uint32, ApicId);
+ if (!StandardSignatureIsAuthenticAMD ()) {
+ MicroSecondDelay (200);
+ SendIpi (IcrLow.Uint32, ApicId);
+ }
+}
+
+/**
+ Send an INIT-Start-up-Start-up IPI sequence to all processors excluding self.
+
+ This function returns after the IPI has been accepted by the target processors.
+
+ if StartupRoutine >= 1M, then ASSERT.
+ if StartupRoutine is not multiple of 4K, then ASSERT.
+
+ @param StartupRoutine Points to a start-up routine which is below 1M physical
+ address and 4K aligned.
+**/
+VOID
+EFIAPI
+SendInitSipiSipiAllExcludingSelf (
+ IN UINT32 StartupRoutine
+ )
+{
+ LOCAL_APIC_ICR_LOW IcrLow;
+
+ ASSERT (StartupRoutine < 0x100000);
+ ASSERT ((StartupRoutine & 0xfff) == 0);
+
+ SendInitIpiAllExcludingSelf ();
+ MicroSecondDelay (PcdGet32(PcdCpuInitIpiDelayInMicroSeconds));
+ IcrLow.Uint32 = 0;
+ IcrLow.Bits.Vector = (StartupRoutine >> 12);
+ IcrLow.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_STARTUP;
+ IcrLow.Bits.Level = 1;
+ IcrLow.Bits.DestinationShorthand = LOCAL_APIC_DESTINATION_SHORTHAND_ALL_EXCLUDING_SELF;
+ SendIpi (IcrLow.Uint32, 0);
+ if (!StandardSignatureIsAuthenticAMD ()) {
+ MicroSecondDelay (200);
+ SendIpi (IcrLow.Uint32, 0);
+ }
+}
+
+/**
+ Initialize the state of the SoftwareEnable bit in the Local APIC
+ Spurious Interrupt Vector register.
+
+ @param Enable If TRUE, then set SoftwareEnable to 1
+ If FALSE, then set SoftwareEnable to 0.
+
+**/
+VOID
+EFIAPI
+InitializeLocalApicSoftwareEnable (
+ IN BOOLEAN Enable
+ )
+{
+ LOCAL_APIC_SVR Svr;
+
+ //
+ // Set local APIC software-enabled bit.
+ //
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
+ if (Enable) {
+ if (Svr.Bits.SoftwareEnable == 0) {
+ Svr.Bits.SoftwareEnable = 1;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+ }
+ } else {
+ if (Svr.Bits.SoftwareEnable == 1) {
+ Svr.Bits.SoftwareEnable = 0;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+ }
+ }
+}
+
+/**
+ Programming Virtual Wire Mode.
+
+ This function programs the local APIC for virtual wire mode following
+ the example described in chapter A.3 of the MP 1.4 spec.
+
+ IOxAPIC is not involved in this type of virtual wire mode.
+**/
+VOID
+EFIAPI
+ProgramVirtualWireMode (
+ VOID
+ )
+{
+ LOCAL_APIC_SVR Svr;
+ LOCAL_APIC_LVT_LINT Lint;
+
+ //
+ // Enable the APIC via SVR and set the spurious interrupt to use Int 00F.
+ //
+ Svr.Uint32 = ReadLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET);
+ Svr.Bits.SpuriousVector = 0xf;
+ Svr.Bits.SoftwareEnable = 1;
+ WriteLocalApicReg (XAPIC_SPURIOUS_VECTOR_OFFSET, Svr.Uint32);
+
+ //
+ // Program the LINT0 vector entry as ExtInt. Not masked, edge, active high.
+ //
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_EXTINT;
+ Lint.Bits.InputPinPolarity = 0;
+ Lint.Bits.TriggerMode = 0;
+ Lint.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, Lint.Uint32);
+
+ //
+ // Program the LINT0 vector entry as NMI. Not masked, edge, active high.
+ //
+ Lint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
+ Lint.Bits.DeliveryMode = LOCAL_APIC_DELIVERY_MODE_NMI;
+ Lint.Bits.InputPinPolarity = 0;
+ Lint.Bits.TriggerMode = 0;
+ Lint.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, Lint.Uint32);
+}
+
+/**
+ Disable LINT0 & LINT1 interrupts.
+
+ This function sets the mask flag in the LVT LINT0 & LINT1 registers.
+**/
+VOID
+EFIAPI
+DisableLvtInterrupts (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_LINT LvtLint;
+
+ LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT0_OFFSET);
+ LvtLint.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_LINT0_OFFSET, LvtLint.Uint32);
+
+ LvtLint.Uint32 = ReadLocalApicReg (XAPIC_LVT_LINT1_OFFSET);
+ LvtLint.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_LINT1_OFFSET, LvtLint.Uint32);
+}
+
+/**
+ Read the initial count value from the init-count register.
+
+ @return The initial count value read from the init-count register.
+**/
+UINT32
+EFIAPI
+GetApicTimerInitCount (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET);
+}
+
+/**
+ Read the current count value from the current-count register.
+
+ @return The current count value read from the current-count register.
+**/
+UINT32
+EFIAPI
+GetApicTimerCurrentCount (
+ VOID
+ )
+{
+ return ReadLocalApicReg (XAPIC_TIMER_CURRENT_COUNT_OFFSET);
+}
+
+/**
+ Initialize the local APIC timer.
+
+ The local APIC timer is initialized and enabled.
+
+ @param DivideValue The divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
+ If it is 0, then use the current divide value in the DCR.
+ @param InitCount The initial count value.
+ @param PeriodicMode If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
+ @param Vector The timer interrupt vector number.
+**/
+VOID
+EFIAPI
+InitializeApicTimer (
+ IN UINTN DivideValue,
+ IN UINT32 InitCount,
+ IN BOOLEAN PeriodicMode,
+ IN UINT8 Vector
+ )
+{
+ LOCAL_APIC_DCR Dcr;
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+ UINT32 Divisor;
+
+ //
+ // Ensure local APIC is in software-enabled state.
+ //
+ InitializeLocalApicSoftwareEnable (TRUE);
+
+ //
+ // Program init-count register.
+ //
+ WriteLocalApicReg (XAPIC_TIMER_INIT_COUNT_OFFSET, InitCount);
+
+ if (DivideValue != 0) {
+ ASSERT (DivideValue <= 128);
+ ASSERT (DivideValue == GetPowerOfTwo32((UINT32)DivideValue));
+ Divisor = (UINT32)((HighBitSet32 ((UINT32)DivideValue) - 1) & 0x7);
+
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
+ Dcr.Bits.DivideValue1 = (Divisor & 0x3);
+ Dcr.Bits.DivideValue2 = (Divisor >> 2);
+ WriteLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET, Dcr.Uint32);
+ }
+
+ //
+ // Enable APIC timer interrupt with specified timer mode.
+ //
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ if (PeriodicMode) {
+ LvtTimer.Bits.TimerMode = 1;
+ } else {
+ LvtTimer.Bits.TimerMode = 0;
+ }
+ LvtTimer.Bits.Mask = 0;
+ LvtTimer.Bits.Vector = Vector;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Get the state of the local APIC timer.
+
+ This function will ASSERT if the local APIC is not software enabled.
+
+ @param DivideValue Return the divide value for the DCR. It is one of 1,2,4,8,16,32,64,128.
+ @param PeriodicMode Return the timer mode. If TRUE, timer mode is peridoic. Othewise, timer mode is one-shot.
+ @param Vector Return the timer interrupt vector number.
+**/
+VOID
+EFIAPI
+GetApicTimerState (
+ OUT UINTN *DivideValue OPTIONAL,
+ OUT BOOLEAN *PeriodicMode OPTIONAL,
+ OUT UINT8 *Vector OPTIONAL
+ )
+{
+ UINT32 Divisor;
+ LOCAL_APIC_DCR Dcr;
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ //
+ // Check the APIC Software Enable/Disable bit (bit 8) in Spurious-Interrupt
+ // Vector Register.
+ // This bit will be 1, if local APIC is software enabled.
+ //
+ ASSERT ((ReadLocalApicReg(XAPIC_SPURIOUS_VECTOR_OFFSET) & BIT8) != 0);
+
+ if (DivideValue != NULL) {
+ Dcr.Uint32 = ReadLocalApicReg (XAPIC_TIMER_DIVIDE_CONFIGURATION_OFFSET);
+ Divisor = Dcr.Bits.DivideValue1 | (Dcr.Bits.DivideValue2 << 2);
+ Divisor = (Divisor + 1) & 0x7;
+ *DivideValue = ((UINTN)1) << Divisor;
+ }
+
+ if (PeriodicMode != NULL || Vector != NULL) {
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ if (PeriodicMode != NULL) {
+ if (LvtTimer.Bits.TimerMode == 1) {
+ *PeriodicMode = TRUE;
+ } else {
+ *PeriodicMode = FALSE;
+ }
+ }
+ if (Vector != NULL) {
+ *Vector = (UINT8) LvtTimer.Bits.Vector;
+ }
+ }
+}
+
+/**
+ Enable the local APIC timer interrupt.
+**/
+VOID
+EFIAPI
+EnableApicTimerInterrupt (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ LvtTimer.Bits.Mask = 0;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Disable the local APIC timer interrupt.
+**/
+VOID
+EFIAPI
+DisableApicTimerInterrupt (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ LvtTimer.Bits.Mask = 1;
+ WriteLocalApicReg (XAPIC_LVT_TIMER_OFFSET, LvtTimer.Uint32);
+}
+
+/**
+ Get the local APIC timer interrupt state.
+
+ @retval TRUE The local APIC timer interrupt is enabled.
+ @retval FALSE The local APIC timer interrupt is disabled.
+**/
+BOOLEAN
+EFIAPI
+GetApicTimerInterruptState (
+ VOID
+ )
+{
+ LOCAL_APIC_LVT_TIMER LvtTimer;
+
+ LvtTimer.Uint32 = ReadLocalApicReg (XAPIC_LVT_TIMER_OFFSET);
+ return (BOOLEAN)(LvtTimer.Bits.Mask == 0);
+}
+
+/**
+ Send EOI to the local APIC.
+**/
+VOID
+EFIAPI
+SendApicEoi (
+ VOID
+ )
+{
+ WriteLocalApicReg (XAPIC_EOI_OFFSET, 0);
+}
+
+/**
+ Get the 32-bit address that a device should use to send a Message Signaled
+ Interrupt (MSI) to the Local APIC of the currently executing processor.
+
+ @return 32-bit address used to send an MSI to the Local APIC.
+**/
+UINT32
+EFIAPI
+GetApicMsiAddress (
+ VOID
+ )
+{
+ LOCAL_APIC_MSI_ADDRESS MsiAddress;
+
+ //
+ // Return address for an MSI interrupt to be delivered only to the APIC ID
+ // of the currently executing processor.
+ //
+ MsiAddress.Uint32 = 0;
+ MsiAddress.Bits.BaseAddress = 0xFEE;
+ MsiAddress.Bits.DestinationId = GetApicId ();
+ return MsiAddress.Uint32;
+}
+
+/**
+ Get the 64-bit data value that a device should use to send a Message Signaled
+ Interrupt (MSI) to the Local APIC of the currently executing processor.
+
+ If Vector is not in range 0x10..0xFE, then ASSERT().
+ If DeliveryMode is not supported, then ASSERT().
+
+ @param Vector The 8-bit interrupt vector associated with the MSI.
+ Must be in the range 0x10..0xFE
+ @param DeliveryMode A 3-bit value that specifies how the recept of the MSI
+ is handled. The only supported values are:
+ 0: LOCAL_APIC_DELIVERY_MODE_FIXED
+ 1: LOCAL_APIC_DELIVERY_MODE_LOWEST_PRIORITY
+ 2: LOCAL_APIC_DELIVERY_MODE_SMI
+ 4: LOCAL_APIC_DELIVERY_MODE_NMI
+ 5: LOCAL_APIC_DELIVERY_MODE_INIT
+ 7: LOCAL_APIC_DELIVERY_MODE_EXTINT
+
+ @param LevelTriggered TRUE specifies a level triggered interrupt.
+ FALSE specifies an edge triggered interrupt.
+ @param AssertionLevel Ignored if LevelTriggered is FALSE.
+ TRUE specifies a level triggered interrupt that active
+ when the interrupt line is asserted.
+ FALSE specifies a level triggered interrupt that active
+ when the interrupt line is deasserted.
+
+ @return 64-bit data value used to send an MSI to the Local APIC.
+**/
+UINT64
+EFIAPI
+GetApicMsiValue (
+ IN UINT8 Vector,
+ IN UINTN DeliveryMode,
+ IN BOOLEAN LevelTriggered,
+ IN BOOLEAN AssertionLevel
+ )
+{
+ LOCAL_APIC_MSI_DATA MsiData;
+
+ ASSERT (Vector >= 0x10 && Vector <= 0xFE);
+ ASSERT (DeliveryMode < 8 && DeliveryMode != 6 && DeliveryMode != 3);
+
+ MsiData.Uint64 = 0;
+ MsiData.Bits.Vector = Vector;
+ MsiData.Bits.DeliveryMode = (UINT32)DeliveryMode;
+ if (LevelTriggered) {
+ MsiData.Bits.TriggerMode = 1;
+ if (AssertionLevel) {
+ MsiData.Bits.Level = 1;
+ }
+ }
+ return MsiData.Uint64;
+}
+
+/**
+ Get Package ID/Core ID/Thread ID of a processor.
+
+ The algorithm assumes the target system has symmetry across physical
+ package boundaries with respect to the number of logical processors
+ per package, number of cores per package.
+
+ @param[in] InitialApicId Initial APIC ID of the target logical processor.
+ @param[out] Package Returns the processor package ID.
+ @param[out] Core Returns the processor core ID.
+ @param[out] Thread Returns the processor thread ID.
+**/
+VOID
+EFIAPI
+GetProcessorLocationByApicId (
+ IN UINT32 InitialApicId,
+ OUT UINT32 *Package OPTIONAL,
+ OUT UINT32 *Core OPTIONAL,
+ OUT UINT32 *Thread OPTIONAL
+ )
+{
+ BOOLEAN TopologyLeafSupported;
+ CPUID_VERSION_INFO_EBX VersionInfoEbx;
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+ CPUID_CACHE_PARAMS_EAX CacheParamsEax;
+ CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
+ CPUID_EXTENDED_TOPOLOGY_EBX ExtendedTopologyEbx;
+ CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
+ CPUID_AMD_EXTENDED_CPU_SIG_ECX AmdExtendedCpuSigEcx;
+ CPUID_AMD_PROCESSOR_TOPOLOGY_EBX AmdProcessorTopologyEbx;
+ CPUID_AMD_VIR_PHY_ADDRESS_SIZE_ECX AmdVirPhyAddressSizeEcx;
+ UINT32 MaxStandardCpuIdIndex;
+ UINT32 MaxExtendedCpuIdIndex;
+ UINT32 SubIndex;
+ UINTN LevelType;
+ UINT32 MaxLogicProcessorsPerPackage;
+ UINT32 MaxCoresPerPackage;
+ UINTN ThreadBits;
+ UINTN CoreBits;
+
+ //
+ // Check if the processor is capable of supporting more than one logical processor.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.HTT == 0) {
+ if (Thread != NULL) {
+ *Thread = 0;
+ }
+ if (Core != NULL) {
+ *Core = 0;
+ }
+ if (Package != NULL) {
+ *Package = 0;
+ }
+ return;
+ }
+
+ //
+ // Assume three-level mapping of APIC ID: Package|Core|Thread.
+ //
+ ThreadBits = 0;
+ CoreBits = 0;
+
+ //
+ // Get max index of CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedCpuIdIndex, NULL, NULL, NULL);
+
+ //
+ // If the extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ TopologyLeafSupported = FALSE;
+ if (MaxStandardCpuIdIndex >= CPUID_EXTENDED_TOPOLOGY) {
+ AsmCpuidEx(
+ CPUID_EXTENDED_TOPOLOGY,
+ 0,
+ &ExtendedTopologyEax.Uint32,
+ &ExtendedTopologyEbx.Uint32,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ //
+ // If CPUID.(EAX=0BH, ECX=0H):EBX returns zero and maximum input value for
+ // basic CPUID information is greater than 0BH, then CPUID.0BH leaf is not
+ // supported on that processor.
+ //
+ if (ExtendedTopologyEbx.Uint32 != 0) {
+ TopologyLeafSupported = TRUE;
+
+ //
+ // Sub-leaf index 0 (ECX= 0 as input) provides enumeration parameters to extract
+ // the SMT sub-field of x2APIC ID.
+ //
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ ASSERT (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT);
+ ThreadBits = ExtendedTopologyEax.Bits.ApicIdShift;
+
+ //
+ // Software must not assume any "level type" encoding
+ // value to be related to any sub-leaf index, except sub-leaf 0.
+ //
+ SubIndex = 1;
+ do {
+ AsmCpuidEx (
+ CPUID_EXTENDED_TOPOLOGY,
+ SubIndex,
+ &ExtendedTopologyEax.Uint32,
+ NULL,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE) {
+ CoreBits = ExtendedTopologyEax.Bits.ApicIdShift - ThreadBits;
+ break;
+ }
+ SubIndex++;
+ } while (LevelType != CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID);
+ }
+ }
+
+ if (!TopologyLeafSupported) {
+ //
+ // Get logical processor count
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, &VersionInfoEbx.Uint32, NULL, NULL);
+ MaxLogicProcessorsPerPackage = VersionInfoEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
+
+ //
+ // Assume single-core processor
+ //
+ MaxCoresPerPackage = 1;
+
+ //
+ // Check for topology extensions on AMD processor
+ //
+ if (StandardSignatureIsAuthenticAMD()) {
+ if (MaxExtendedCpuIdIndex >= CPUID_AMD_PROCESSOR_TOPOLOGY) {
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, &AmdExtendedCpuSigEcx.Uint32, NULL);
+ if (AmdExtendedCpuSigEcx.Bits.TopologyExtensions != 0) {
+ //
+ // Account for max possible thread count to decode ApicId
+ //
+ AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, NULL, NULL, &AmdVirPhyAddressSizeEcx.Uint32, NULL);
+ MaxLogicProcessorsPerPackage = 1 << AmdVirPhyAddressSizeEcx.Bits.ApicIdCoreIdSize;
+
+ //
+ // Get cores per processor package
+ //
+ AsmCpuid (CPUID_AMD_PROCESSOR_TOPOLOGY, NULL, &AmdProcessorTopologyEbx.Uint32, NULL, NULL);
+ MaxCoresPerPackage = MaxLogicProcessorsPerPackage / (AmdProcessorTopologyEbx.Bits.ThreadsPerCore + 1);
+ }
+ }
+ }
+ else {
+ //
+ // Extract core count based on CACHE information
+ //
+ if (MaxStandardCpuIdIndex >= CPUID_CACHE_PARAMS) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CacheParamsEax.Uint32, NULL, NULL, NULL);
+ if (CacheParamsEax.Uint32 != 0) {
+ MaxCoresPerPackage = CacheParamsEax.Bits.MaximumAddressableIdsForLogicalProcessors + 1;
+ }
+ }
+ }
+
+ ThreadBits = (UINTN)(HighBitSet32(MaxLogicProcessorsPerPackage / MaxCoresPerPackage - 1) + 1);
+ CoreBits = (UINTN)(HighBitSet32(MaxCoresPerPackage - 1) + 1);
+ }
+
+ if (Thread != NULL) {
+ *Thread = InitialApicId & ((1 << ThreadBits) - 1);
+ }
+ if (Core != NULL) {
+ *Core = (InitialApicId >> ThreadBits) & ((1 << CoreBits) - 1);
+ }
+ if (Package != NULL) {
+ *Package = (InitialApicId >> (ThreadBits + CoreBits));
+ }
+}
+
+/**
+ Get Package ID/Die ID/Tile ID/Module ID/Core ID/Thread ID of a processor.
+
+ The algorithm assumes the target system has symmetry across physical
+ package boundaries with respect to the number of threads per core, number of
+ cores per module, number of modules per tile, number of tiles per die, number
+ of dies per package.
+
+ @param[in] InitialApicId Initial APIC ID of the target logical processor.
+ @param[out] Package Returns the processor package ID.
+ @param[out] Die Returns the processor die ID.
+ @param[out] Tile Returns the processor tile ID.
+ @param[out] Module Returns the processor module ID.
+ @param[out] Core Returns the processor core ID.
+ @param[out] Thread Returns the processor thread ID.
+**/
+VOID
+EFIAPI
+GetProcessorLocation2ByApicId (
+ IN UINT32 InitialApicId,
+ OUT UINT32 *Package OPTIONAL,
+ OUT UINT32 *Die OPTIONAL,
+ OUT UINT32 *Tile OPTIONAL,
+ OUT UINT32 *Module OPTIONAL,
+ OUT UINT32 *Core OPTIONAL,
+ OUT UINT32 *Thread OPTIONAL
+ )
+{
+ CPUID_EXTENDED_TOPOLOGY_EAX ExtendedTopologyEax;
+ CPUID_EXTENDED_TOPOLOGY_ECX ExtendedTopologyEcx;
+ UINT32 MaxStandardCpuIdIndex;
+ UINT32 Index;
+ UINTN LevelType;
+ UINT32 Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
+ UINT32 *Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 2];
+
+ for (LevelType = 0; LevelType < ARRAY_SIZE (Bits); LevelType++) {
+ Bits[LevelType] = 0;
+ }
+
+ //
+ // Get max index of CPUID
+ //
+ AsmCpuid (CPUID_SIGNATURE, &MaxStandardCpuIdIndex, NULL, NULL, NULL);
+ if (MaxStandardCpuIdIndex < CPUID_V2_EXTENDED_TOPOLOGY) {
+ if (Die != NULL) {
+ *Die = 0;
+ }
+ if (Tile != NULL) {
+ *Tile = 0;
+ }
+ if (Module != NULL) {
+ *Module = 0;
+ }
+ GetProcessorLocationByApicId (InitialApicId, Package, Core, Thread);
+ return;
+ }
+
+ //
+ // If the V2 extended topology enumeration leaf is available, it
+ // is the preferred mechanism for enumerating topology.
+ //
+ for (Index = 0; ; Index++) {
+ AsmCpuidEx(
+ CPUID_V2_EXTENDED_TOPOLOGY,
+ Index,
+ &ExtendedTopologyEax.Uint32,
+ NULL,
+ &ExtendedTopologyEcx.Uint32,
+ NULL
+ );
+
+ LevelType = ExtendedTopologyEcx.Bits.LevelType;
+
+ //
+ // first level reported should be SMT.
+ //
+ ASSERT ((Index != 0) || (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT));
+ if (LevelType == CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_INVALID) {
+ break;
+ }
+ ASSERT (LevelType < ARRAY_SIZE (Bits));
+ Bits[LevelType] = ExtendedTopologyEax.Bits.ApicIdShift;
+ }
+
+ for (LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE; LevelType < ARRAY_SIZE (Bits); LevelType++) {
+ //
+ // If there are more levels between level-1 (low-level) and level-2 (high-level), the unknown levels will be ignored
+ // and treated as an extension of the last known level (i.e., level-1 in this case).
+ //
+ if (Bits[LevelType] == 0) {
+ Bits[LevelType] = Bits[LevelType - 1];
+ }
+ }
+
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = Package;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE ] = Die;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_TILE ] = Tile;
+ Location[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_MODULE ] = Module;
+ Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_CORE ] = Core;
+ Location[CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT ] = Thread;
+
+ Bits[CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1] = 32;
+
+ for ( LevelType = CPUID_EXTENDED_TOPOLOGY_LEVEL_TYPE_SMT
+ ; LevelType <= CPUID_V2_EXTENDED_TOPOLOGY_LEVEL_TYPE_DIE + 1
+ ; LevelType ++
+ ) {
+ if (Location[LevelType] != NULL) {
+ //
+ // Bits[i] holds the number of bits to shift right on x2APIC ID to get a unique
+ // topology ID of the next level type.
+ //
+ *Location[LevelType] = InitialApicId >> Bits[LevelType - 1];
+
+ //
+ // Bits[i] - Bits[i-1] holds the number of bits for the next ONE level type.
+ //
+ *Location[LevelType] &= (1 << (Bits[LevelType] - Bits[LevelType - 1])) - 1;
+ }
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
new file mode 100644
index 00000000..564c1a97
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.inf
@@ -0,0 +1,45 @@
+## @file
+# The Local Apic library supports x2APIC capable processors which have xAPIC and x2APIC modes.
+#
+# Note: Local APIC library assumes local APIC is enabled. It does not handle cases
+# where local APIC is disabled.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseXApicX2ApicLib
+ MODULE_UNI_FILE = BaseXApicX2ApicLib.uni
+ FILE_GUID = 967B6E05-F10D-4c10-8BF7-365291CA143F
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = LocalApicLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ BaseXApicX2ApicLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ TimerLib
+ IoLib
+ PcdLib
+ UefiCpuLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuInitIpiDelayInMicroSeconds ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuLocalApicBaseAddress ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.uni
new file mode 100644
index 00000000..e614c938
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/BaseXApicX2ApicLib/BaseXApicX2ApicLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// The Local Apic library supports x2APIC capable processors which have xAPIC and x2APIC modes.
+//
+// Note: Local APIC library assumes local APIC is enabled. It does not handle cases
+// where local APIC is disabled.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Supports x2APIC capable processors that have xAPIC and x2APIC modes"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Note: Local APIC library assumes local APIC is enabled. It does not handle cases where local APIC is disabled."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
new file mode 100644
index 00000000..8eee5b77
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.c
@@ -0,0 +1,441 @@
+/** @file
+ Provides cache info for each package, core type, cache level and cache type.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "InternalCpuCacheInfoLib.h"
+
+/**
+ Print CpuCacheInfo array.
+
+ @param[in] CpuCacheInfo Pointer to the CpuCacheInfo array.
+ @param[in] CpuCacheInfoCount The length of CpuCacheInfo array.
+
+**/
+VOID
+CpuCacheInfoPrintCpuCacheInfoTable (
+ IN CPU_CACHE_INFO *CpuCacheInfo,
+ IN UINTN CpuCacheInfoCount
+ )
+{
+ UINTN Index;
+
+ DEBUG ((DEBUG_INFO, "+-------+--------------------------------------------------------------------------------------+\n"));
+ DEBUG ((DEBUG_INFO, "| Index | Packge CoreType CacheLevel CacheType CacheWays (FA|DM) CacheSizeinKB CacheCount |\n"));
+ DEBUG ((DEBUG_INFO, "+-------+--------------------------------------------------------------------------------------+\n"));
+
+ for (Index = 0; Index < CpuCacheInfoCount; Index++) {
+ DEBUG ((DEBUG_INFO, "| %4x | %4x %2x %2x %2x %4x ( %x| %x) %8x %4x |\n",
+ Index, CpuCacheInfo[Index].Package, CpuCacheInfo[Index].CoreType, CpuCacheInfo[Index].CacheLevel,
+ CpuCacheInfo[Index].CacheType, CpuCacheInfo[Index].CacheWays, CpuCacheInfo[Index].FullyAssociativeCache,
+ CpuCacheInfo[Index].DirectMappedCache, CpuCacheInfo[Index].CacheSizeinKB, CpuCacheInfo[Index].CacheCount));
+ }
+
+ DEBUG ((DEBUG_INFO, "+-------+--------------------------------------------------------------------------------------+\n"));
+}
+
+/**
+ Get the total number of package and package ID in the platform.
+
+ @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
+ @param[in] NumberOfProcessors Total number of logical processors in the platform.
+ @param[in, out] Package Pointer to the Package array.
+
+ @retval Return the total number of package and package ID in the platform.
+**/
+UINT32
+CpuCacheInfoGetNumberOfPackages (
+ IN CPUID_PROCESSOR_INFO *ProcessorInfo,
+ IN UINTN NumberOfProcessors,
+ IN OUT UINT32 *Package
+ )
+{
+ UINTN ProcessorIndex;
+ UINT32 PackageIndex;
+ UINT32 PackageCount;
+ UINT32 CurrentPackage;
+
+ PackageCount = 0;
+
+ for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {
+ CurrentPackage = ProcessorInfo[ProcessorIndex].Package;
+
+ //
+ // For the package that already exists in Package array, break out the loop.
+ //
+ for (PackageIndex = 0; PackageIndex < PackageCount; PackageIndex++) {
+ if (CurrentPackage == Package[PackageIndex]) {
+ break;
+ }
+ }
+
+ //
+ // For the new package, save it in Package array.
+ //
+ if (PackageIndex == PackageCount) {
+ ASSERT (PackageCount < MAX_NUM_OF_PACKAGE);
+ Package[PackageCount++] = CurrentPackage;
+ }
+ }
+
+ return PackageCount;
+}
+
+/**
+ Get the number of CoreType of requested package.
+
+ @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
+ @param[in] NumberOfProcessors Total number of logical processors in the platform.
+ @param[in] Package The requested package number.
+
+ @retval Return the number of CoreType of requested package.
+**/
+UINTN
+CpuCacheInfoGetNumberOfCoreTypePerPackage(
+ IN CPUID_PROCESSOR_INFO *ProcessorInfo,
+ IN UINTN NumberOfProcessors,
+ IN UINTN Package
+ )
+{
+ UINTN ProcessorIndex;
+ //
+ // Core Type value comes from CPUID.1Ah.EAX[31:24].
+ // So max number of core types should be MAX_UINT8.
+ //
+ UINT8 CoreType[MAX_UINT8];
+ UINTN CoreTypeIndex;
+ UINTN CoreTypeCount;
+ UINT8 CurrentCoreType;
+
+ //
+ // CoreType array is empty.
+ //
+ CoreTypeCount = 0;
+
+ for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {
+ CurrentCoreType = ProcessorInfo[ProcessorIndex].CoreType;
+
+ if (ProcessorInfo[ProcessorIndex].Package != Package) {
+ continue;
+ }
+
+ //
+ // For the type that already exists in CoreType array, break out the loop.
+ //
+ for (CoreTypeIndex = 0; CoreTypeIndex < CoreTypeCount; CoreTypeIndex++) {
+ if (CurrentCoreType == CoreType[CoreTypeIndex]) {
+ break;
+ }
+ }
+
+ //
+ // For the new type, save it in CoreType array.
+ //
+ if (CoreTypeIndex == CoreTypeCount) {
+ ASSERT (CoreTypeCount < MAX_UINT8);
+ CoreType[CoreTypeCount++] = CurrentCoreType;
+ }
+ }
+
+ return CoreTypeCount;
+}
+
+/**
+ Collect core and cache information of calling processor via CPUID instructions.
+
+ @param[in, out] Buffer The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CpuCacheInfoCollectCoreAndCacheData (
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN ProcessorIndex;
+ UINT32 CpuidMaxInput;
+ UINT8 CacheParamLeafIndex;
+ CPUID_CACHE_PARAMS_EAX CacheParamEax;
+ CPUID_CACHE_PARAMS_EBX CacheParamEbx;
+ UINT32 CacheParamEcx;
+ CPUID_CACHE_PARAMS_EDX CacheParamEdx;
+ CPUID_NATIVE_MODEL_ID_AND_CORE_TYPE_EAX NativeModelIdAndCoreTypeEax;
+ COLLECT_CPUID_CACHE_DATA_CONTEXT *Context;
+ CPUID_CACHE_DATA *CacheData;
+
+ Context = (COLLECT_CPUID_CACHE_DATA_CONTEXT *)Buffer;
+ ProcessorIndex = CpuCacheInfoWhoAmI (Context->MpServices);
+ CacheData = &Context->CacheData[MAX_NUM_OF_CACHE_PARAMS_LEAF * ProcessorIndex];
+
+ AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL);
+
+ //
+ // get CoreType if CPUID_HYBRID_INFORMATION leaf is supported.
+ //
+ Context->ProcessorInfo[ProcessorIndex].CoreType = 0;
+ if (CpuidMaxInput >= CPUID_HYBRID_INFORMATION) {
+ AsmCpuidEx (CPUID_HYBRID_INFORMATION, CPUID_HYBRID_INFORMATION_MAIN_LEAF, &NativeModelIdAndCoreTypeEax.Uint32, NULL, NULL, NULL);
+ Context->ProcessorInfo[ProcessorIndex].CoreType = (UINT8) NativeModelIdAndCoreTypeEax.Bits.CoreType;
+ }
+
+ //
+ // cache hierarchy starts with an index value of 0.
+ //
+ CacheParamLeafIndex = 0;
+
+ while (CacheParamLeafIndex < MAX_NUM_OF_CACHE_PARAMS_LEAF) {
+ AsmCpuidEx (CPUID_CACHE_PARAMS, CacheParamLeafIndex, &CacheParamEax.Uint32, &CacheParamEbx.Uint32, &CacheParamEcx, &CacheParamEdx.Uint32);
+
+ if (CacheParamEax.Bits.CacheType == 0) {
+ break;
+ }
+
+ CacheData[CacheParamLeafIndex].CacheLevel = (UINT8)CacheParamEax.Bits.CacheLevel;
+ CacheData[CacheParamLeafIndex].CacheType = (UINT8)CacheParamEax.Bits.CacheType;
+ CacheData[CacheParamLeafIndex].CacheWays = (UINT16)CacheParamEbx.Bits.Ways;
+ CacheData[CacheParamLeafIndex].FullyAssociativeCache = (UINT8)CacheParamEax.Bits.FullyAssociativeCache;
+ CacheData[CacheParamLeafIndex].DirectMappedCache = (UINT8)CacheParamEdx.Bits.ComplexCacheIndexing;
+ CacheData[CacheParamLeafIndex].CacheShareBits = (UINT16)CacheParamEax.Bits.MaximumAddressableIdsForLogicalProcessors;
+ CacheData[CacheParamLeafIndex].CacheSizeinKB = (CacheParamEbx.Bits.Ways + 1) *
+ (CacheParamEbx.Bits.LinePartitions + 1) * (CacheParamEbx.Bits.LineSize + 1) * (CacheParamEcx + 1) / SIZE_1KB;
+
+ CacheParamLeafIndex++;
+ }
+}
+
+/**
+ Collect CacheInfo data from the CacheData.
+
+ @param[in] CacheData Pointer to the CacheData array.
+ @param[in] ProcessorInfo Pointer to the ProcessorInfo array.
+ @param[in] NumberOfProcessors Total number of logical processors in the platform.
+ @param[in, out] CacheInfo Pointer to the CacheInfo array.
+ @param[in, out] CacheInfoCount As input, point to the length of response CacheInfo array.
+ As output, point to the actual length of response CacheInfo array.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
+ @retval EFI_BUFFER_TOO_SMALL CacheInfoCount is too small to hold the response CacheInfo
+ array. CacheInfoCount has been updated with the length needed
+ to complete the request.
+**/
+EFI_STATUS
+CpuCacheInfoCollectCpuCacheInfoData (
+ IN CPUID_CACHE_DATA *CacheData,
+ IN CPUID_PROCESSOR_INFO *ProcessorInfo,
+ IN UINTN NumberOfProcessors,
+ IN OUT CPU_CACHE_INFO *CacheInfo,
+ IN OUT UINTN *CacheInfoCount
+ )
+{
+ EFI_STATUS Status;
+ UINT32 NumberOfPackage;
+ UINT32 Package[MAX_NUM_OF_PACKAGE];
+ UINTN PackageIndex;
+ UINTN TotalNumberOfCoreType;
+ UINTN MaxCacheInfoCount;
+ CPU_CACHE_INFO *LocalCacheInfo;
+ UINTN CacheInfoIndex;
+ UINTN LocalCacheInfoCount;
+ UINTN Index;
+ UINTN NextIndex;
+
+ //
+ // Get number of Packages and Package ID.
+ //
+ NumberOfPackage = CpuCacheInfoGetNumberOfPackages (ProcessorInfo, NumberOfProcessors, Package);
+
+ //
+ // Get number of core types for each package and count the total number.
+ // E.g. If Package1 and Package2 both have 2 core types, the total number is 4.
+ //
+ TotalNumberOfCoreType = 0;
+ for (PackageIndex = 0; PackageIndex < NumberOfPackage; PackageIndex++) {
+ TotalNumberOfCoreType += CpuCacheInfoGetNumberOfCoreTypePerPackage (ProcessorInfo, NumberOfProcessors, Package[PackageIndex]);
+ }
+
+ MaxCacheInfoCount = TotalNumberOfCoreType * MAX_NUM_OF_CACHE_PARAMS_LEAF;
+ LocalCacheInfo = AllocatePages (EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo)));
+ ASSERT (LocalCacheInfo != NULL);
+ if (LocalCacheInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LocalCacheInfoCount = 0;
+
+ for (Index = 0; Index < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; Index++) {
+ if (CacheData[Index].CacheSizeinKB == 0) {
+ continue;
+ }
+
+ //
+ // For the sharing caches, clear their CacheSize.
+ //
+ for (NextIndex = Index + 1; NextIndex < NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF; NextIndex++) {
+ if (CacheData[NextIndex].CacheSizeinKB == 0) {
+ continue;
+ }
+
+ if (CacheData[Index].CacheLevel == CacheData[NextIndex].CacheLevel &&
+ CacheData[Index].CacheType == CacheData[NextIndex].CacheType &&
+ ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package &&
+ ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType == ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType &&
+ (ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[Index].CacheShareBits) ==
+ (ProcessorInfo[NextIndex / MAX_NUM_OF_CACHE_PARAMS_LEAF].ApicId & ~CacheData[NextIndex].CacheShareBits)) {
+ CacheData[NextIndex].CacheSizeinKB = 0; // uses the sharing cache
+ }
+ }
+
+ //
+ // For the cache that already exists in LocalCacheInfo, increase its CacheCount.
+ //
+ for (CacheInfoIndex = 0; CacheInfoIndex < LocalCacheInfoCount; CacheInfoIndex++) {
+ if (LocalCacheInfo[CacheInfoIndex].Package == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package &&
+ LocalCacheInfo[CacheInfoIndex].CoreType == ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType &&
+ LocalCacheInfo[CacheInfoIndex].CacheLevel == CacheData[Index].CacheLevel &&
+ LocalCacheInfo[CacheInfoIndex].CacheType == CacheData[Index].CacheType) {
+ LocalCacheInfo[CacheInfoIndex].CacheCount++;
+ break;
+ }
+ }
+
+ //
+ // For the new cache with different Package, CoreType, CacheLevel or CacheType, copy its
+ // data into LocalCacheInfo buffer.
+ //
+ if (CacheInfoIndex == LocalCacheInfoCount) {
+ ASSERT (LocalCacheInfoCount < MaxCacheInfoCount);
+
+ LocalCacheInfo[LocalCacheInfoCount].Package = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].Package;
+ LocalCacheInfo[LocalCacheInfoCount].CoreType = ProcessorInfo[Index / MAX_NUM_OF_CACHE_PARAMS_LEAF].CoreType;
+ LocalCacheInfo[LocalCacheInfoCount].CacheLevel = CacheData[Index].CacheLevel;
+ LocalCacheInfo[LocalCacheInfoCount].CacheType = CacheData[Index].CacheType;
+ LocalCacheInfo[LocalCacheInfoCount].CacheWays = CacheData[Index].CacheWays;
+ LocalCacheInfo[LocalCacheInfoCount].FullyAssociativeCache = CacheData[Index].FullyAssociativeCache;
+ LocalCacheInfo[LocalCacheInfoCount].DirectMappedCache = CacheData[Index].DirectMappedCache;
+ LocalCacheInfo[LocalCacheInfoCount].CacheSizeinKB = CacheData[Index].CacheSizeinKB;
+ LocalCacheInfo[LocalCacheInfoCount].CacheCount = 1;
+
+ LocalCacheInfoCount++;
+ }
+ }
+
+ if (*CacheInfoCount < LocalCacheInfoCount) {
+ Status = EFI_BUFFER_TOO_SMALL;
+ } else {
+ CopyMem (CacheInfo, LocalCacheInfo, sizeof (*CacheInfo) * LocalCacheInfoCount);
+ DEBUG_CODE (
+ CpuCacheInfoPrintCpuCacheInfoTable (CacheInfo, LocalCacheInfoCount);
+ );
+ Status = EFI_SUCCESS;
+ }
+
+ *CacheInfoCount = LocalCacheInfoCount;
+
+ FreePages (LocalCacheInfo, EFI_SIZE_TO_PAGES (MaxCacheInfoCount * sizeof (*LocalCacheInfo)));
+
+ return Status;
+}
+
+/**
+ Get CpuCacheInfo data array.
+
+ @param[in, out] CpuCacheInfo Pointer to the CpuCacheInfo array.
+ @param[in, out] CpuCacheInfoCount As input, point to the length of response CpuCacheInfo array.
+ As output, point to the actual length of response CpuCacheInfo array.
+
+ @retval EFI_SUCCESS Function completed successfully.
+ @retval EFI_INVALID_PARAMETER CpuCacheInfoCount is NULL.
+ @retval EFI_INVALID_PARAMETER CpuCacheInfo is NULL while CpuCacheInfoCount contains the value
+ greater than zero.
+ @retval EFI_UNSUPPORTED Processor does not support CPUID_CACHE_PARAMS Leaf.
+ @retval EFI_OUT_OF_RESOURCES Required resources could not be allocated.
+ @retval EFI_BUFFER_TOO_SMALL CpuCacheInfoCount is too small to hold the response CpuCacheInfo
+ array. CpuCacheInfoCount has been updated with the length needed
+ to complete the request.
+**/
+EFI_STATUS
+EFIAPI
+GetCpuCacheInfo (
+ IN OUT CPU_CACHE_INFO *CpuCacheInfo,
+ IN OUT UINTN *CpuCacheInfoCount
+ )
+{
+ EFI_STATUS Status;
+ UINT32 CpuidMaxInput;
+ UINT32 NumberOfProcessors;
+ UINTN CacheDataCount;
+ UINTN ProcessorIndex;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+ COLLECT_CPUID_CACHE_DATA_CONTEXT Context;
+
+ if (CpuCacheInfoCount == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (*CpuCacheInfoCount != 0 && CpuCacheInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ AsmCpuid (CPUID_SIGNATURE, &CpuidMaxInput, NULL, NULL, NULL);
+ if (CpuidMaxInput < CPUID_CACHE_PARAMS) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.MpServices.
+ //
+ CpuCacheInfoGetMpServices (&Context.MpServices);
+
+ NumberOfProcessors = CpuCacheInfoGetNumberOfProcessors (Context.MpServices);
+
+ //
+ // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.ProcessorInfo.
+ //
+ Context.ProcessorInfo = AllocatePages (EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));
+ ASSERT (Context.ProcessorInfo != NULL);
+ if (Context.ProcessorInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize COLLECT_CPUID_CACHE_DATA_CONTEXT.CacheData.
+ // CacheData array consists of CPUID_CACHE_DATA data structure for each Cpuid Cache Parameter Leaf
+ // per logical processor. The array begin with data of each Cache Parameter Leaf of processor 0, followed
+ // by data of each Cache Parameter Leaf of processor 1 ...
+ //
+ CacheDataCount = NumberOfProcessors * MAX_NUM_OF_CACHE_PARAMS_LEAF;
+ Context.CacheData = AllocatePages (EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData)));
+ ASSERT (Context.CacheData != NULL);
+ if (Context.CacheData == NULL) {
+ FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (Context.CacheData, CacheDataCount * sizeof (*Context.CacheData));
+
+ //
+ // Collect Package ID and APIC ID of all processors.
+ //
+ for (ProcessorIndex = 0; ProcessorIndex < NumberOfProcessors; ProcessorIndex++) {
+ CpuCacheInfoGetProcessorInfo (Context.MpServices, ProcessorIndex, &ProcessorInfo);
+ Context.ProcessorInfo[ProcessorIndex].Package = ProcessorInfo.Location.Package;
+ Context.ProcessorInfo[ProcessorIndex].ApicId = (UINT32) ProcessorInfo.ProcessorId;
+ }
+
+ //
+ // Wakeup all processors for CacheData(core type and cache data) collection.
+ //
+ CpuCacheInfoStartupAllCPUs (Context.MpServices, CpuCacheInfoCollectCoreAndCacheData, &Context);
+
+ //
+ // Collect CpuCacheInfo data from CacheData.
+ //
+ Status = CpuCacheInfoCollectCpuCacheInfoData (Context.CacheData, Context.ProcessorInfo, NumberOfProcessors, CpuCacheInfo, CpuCacheInfoCount);
+
+ FreePages (Context.CacheData, EFI_SIZE_TO_PAGES (CacheDataCount * sizeof (*Context.CacheData)));
+ FreePages (Context.ProcessorInfo, EFI_SIZE_TO_PAGES (NumberOfProcessors * sizeof (*Context.ProcessorInfo)));
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni
new file mode 100644
index 00000000..1bc801f1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/CpuCacheInfoLib.uni
@@ -0,0 +1,15 @@
+// /** @file
+// CPU Cache Info Library
+//
+// Provides cache info for each package, core type, cache level and cache type.
+//
+// Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Cache Info Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides cache info for each package, core type, cache level and cache type."
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c
new file mode 100644
index 00000000..aa00ddeb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.c
@@ -0,0 +1,127 @@
+/** @file
+ Provides cache info for each package, core type, cache level and cache type.
+
+ Copyright (c) 2020 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/CpuCacheInfoLib.h>
+#include <InternalCpuCacheInfoLib.h>
+
+/**
+ Get EFI_MP_SERVICES_PROTOCOL pointer.
+
+ @param[out] MpServices A pointer to the buffer where EFI_MP_SERVICES_PROTOCOL is stored
+
+ @retval EFI_SUCCESS EFI_MP_SERVICES_PROTOCOL interface is returned
+ @retval EFI_NOT_FOUND EFI_MP_SERVICES_PROTOCOL interface is not found
+**/
+EFI_STATUS
+CpuCacheInfoGetMpServices (
+ OUT MP_SERVICES *MpServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiMpServiceProtocolGuid, NULL, (VOID **)&MpServices->Protocol);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Activate all of the logical processors.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] Procedure A pointer to the function to be run on enabled logical processors.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors.
+**/
+VOID
+CpuCacheInfoStartupAllCPUs (
+ IN MP_SERVICES MpServices,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MpServices.Protocol->StartupAllAPs (MpServices.Protocol, Procedure, FALSE, NULL, 0, ProcedureArgument, NULL);
+ if (Status == EFI_NOT_STARTED) {
+ //
+ // EFI_NOT_STARTED is returned when there is no enabled AP.
+ // Treat this case as EFI_SUCCESS.
+ //
+ Status = EFI_SUCCESS;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ Procedure (ProcedureArgument);
+}
+
+/**
+ Get detailed information of the requested logical processor.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] ProcessorNum The requested logical processor number.
+ @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored
+**/
+VOID
+CpuCacheInfoGetProcessorInfo (
+ IN MP_SERVICES MpServices,
+ IN UINTN ProcessorNum,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MpServices.Protocol->GetProcessorInfo (MpServices.Protocol, ProcessorNum, ProcessorInfo);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the logical processor number.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the logical processor number.
+**/
+UINT32
+CpuCacheInfoWhoAmI (
+ IN MP_SERVICES MpServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorNum;
+
+ Status = MpServices.Protocol->WhoAmI (MpServices.Protocol, &ProcessorNum);
+ ASSERT_EFI_ERROR (Status);
+
+ return (UINT32)ProcessorNum;
+}
+
+/**
+ Get the total number of logical processors in the platform.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the total number of logical processors.
+**/
+UINT32
+CpuCacheInfoGetNumberOfProcessors (
+ IN MP_SERVICES MpServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfProcessor;
+ UINTN NumberOfEnabledProcessor;
+
+ Status = MpServices.Protocol->GetNumberOfProcessors (MpServices.Protocol, &NumberOfProcessor, &NumberOfEnabledProcessor);
+ ASSERT_EFI_ERROR (Status);
+
+ return (UINT32)NumberOfProcessor;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf
new file mode 100644
index 00000000..770e96e7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/DxeCpuCacheInfoLib.inf
@@ -0,0 +1,43 @@
+## @file
+# CPU Cache Info Library instance for DXE driver.
+#
+# Provides cache info for each package, core type, cache level and cache type.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuCacheInfoLib
+ FILE_GUID = B25C288F-C309-41F1-8325-37E64DC5EA3D
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuCacheInfoLib|DXE_DRIVER UEFI_APPLICATION
+ MODULE_UNI_FILE = CpuCacheInfoLib.uni
+
+[Sources]
+ InternalCpuCacheInfoLib.h
+ CpuCacheInfoLib.c
+ DxeCpuCacheInfoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiMpServiceProtocolGuid
+
+[Pcd]
+
+[Depex]
+ gEfiMpServiceProtocolGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h
new file mode 100644
index 00000000..df132e8d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/InternalCpuCacheInfoLib.h
@@ -0,0 +1,170 @@
+/** @file
+ Internal header file for CPU Cache info Library.
+
+ Copyright (c) 2020 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _INTERNAL_CPU_CACHE_INFO_LIB_H_
+#define _INTERNAL_CPU_CACHE_INFO_LIB_H_
+
+#include <PiPei.h>
+#include <Register/Cpuid.h>
+#include <Ppi/MpServices2.h>
+#include <Protocol/MpService.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CpuCacheInfoLib.h>
+
+typedef struct {
+ //
+ // Package ID, the information comes from
+ // EFI_CPU_PHYSICAL_LOCATION.Package
+ //
+ UINT32 Package;
+ //
+ // APIC ID, the information comes from
+ // EFI_PROCESSOR_INFORMATION.ProcessorId
+ //
+ UINT32 ApicId;
+ //
+ // Core type of logical processor.
+ // Value = CPUID.1Ah:EAX[31:24]
+ //
+ UINT8 CoreType;
+} CPUID_PROCESSOR_INFO;
+
+typedef struct {
+ //
+ // Level of the cache.
+ // Value = CPUID.04h:EAX[07:05]
+ //
+ UINT8 CacheLevel : 3;
+ //
+ // Type of the cache.
+ // Value = CPUID.04h:EAX[04:00]
+ //
+ UINT8 CacheType : 5;
+ //
+ // Ways of associativity.
+ // Value = CPUID.04h:EBX[31:22]
+ //
+ UINT16 CacheWays : 10;
+ //
+ // Fully associative cache.
+ // Value = CPUID.04h:EAX[09]
+ //
+ UINT16 FullyAssociativeCache : 1;
+ //
+ // Direct mapped cache.
+ // Value = CPUID.04h:EDX[02]
+ //
+ UINT16 DirectMappedCache : 1;
+ UINT16 Reserved : 4;
+ //
+ // Cache share bits.
+ // Value = CPUID.04h:EAX[25:14]
+ //
+ UINT16 CacheShareBits;
+ //
+ // Size of single cache.
+ // Value = (CPUID.04h:EBX[31:22] + 1) * (CPUID.04h:EBX[21:12] + 1) *
+ // (CPUID.04h:EBX[11:00] + 1) * (CPUID.04h:ECX[31:00] + 1)
+ //
+ UINT32 CacheSizeinKB;
+} CPUID_CACHE_DATA;
+
+typedef union {
+ EDKII_PEI_MP_SERVICES2_PPI *Ppi;
+ EFI_MP_SERVICES_PROTOCOL *Protocol;
+} MP_SERVICES;
+
+typedef struct {
+ MP_SERVICES MpServices;
+ CPUID_PROCESSOR_INFO *ProcessorInfo;
+ CPUID_CACHE_DATA *CacheData;
+} COLLECT_CPUID_CACHE_DATA_CONTEXT;
+
+
+/*
+ Defines the maximum count of Deterministic Cache Parameters Leaf of all APs and BSP.
+ To save boot time, skip starting up all APs to calculate each AP's count of Deterministic
+ Cache Parameters Leaf, so use a definition instead.
+ Anyway, definition value will be checked in CpuCacheInfoCollectCoreAndCacheData function.
+*/
+#define MAX_NUM_OF_CACHE_PARAMS_LEAF 6
+
+/*
+ Defines the maximum count of packages.
+*/
+#define MAX_NUM_OF_PACKAGE 100
+
+/**
+ Get EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL pointer.
+
+ @param[out] MpServices A pointer to the buffer where EDKII_PEI_MP_SERVICES2_PPI or
+ EFI_MP_SERVICES_PROTOCOL is stored
+
+ @retval EFI_SUCCESS EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface is returned
+ @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI or EFI_MP_SERVICES_PROTOCOL interface is not found
+**/
+EFI_STATUS
+CpuCacheInfoGetMpServices (
+ OUT MP_SERVICES *MpServices
+ );
+
+/**
+ Activate all of the logical processors.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] Procedure A pointer to the function to be run on enabled logical processors.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors.
+**/
+VOID
+CpuCacheInfoStartupAllCPUs (
+ IN MP_SERVICES MpServices,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ );
+
+/**
+ Get detailed information of the requested logical processor.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] ProcessorNum The requested logical processor number.
+ @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored
+**/
+VOID
+CpuCacheInfoGetProcessorInfo (
+ IN MP_SERVICES MpServices,
+ IN UINTN ProcessorNum,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo
+ );
+
+/**
+ Get the logical processor number.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the logical processor number.
+**/
+UINT32
+CpuCacheInfoWhoAmI (
+ IN MP_SERVICES MpServices
+ );
+
+/**
+ Get the total number of logical processors in the platform.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the total number of logical processors.
+**/
+UINT32
+CpuCacheInfoGetNumberOfProcessors (
+ IN MP_SERVICES MpServices
+ );
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c
new file mode 100644
index 00000000..382a54e2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.c
@@ -0,0 +1,119 @@
+/** @file
+ Provides cache info for each package, core type, cache level and cache type.
+
+ Copyright (c) 2020 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/CpuCacheInfoLib.h>
+#include <InternalCpuCacheInfoLib.h>
+
+/**
+ Get EDKII_PEI_MP_SERVICES2_PPI pointer.
+
+ @param[out] MpServices A pointer to the buffer where EDKII_PEI_MP_SERVICES2_PPI is stored
+
+ @retval EFI_SUCCESS EDKII_PEI_MP_SERVICES2_PPI interface is returned
+ @retval EFI_NOT_FOUND EDKII_PEI_MP_SERVICES2_PPI interface is not found
+**/
+EFI_STATUS
+CpuCacheInfoGetMpServices (
+ OUT MP_SERVICES *MpServices
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PeiServicesLocatePpi (&gEdkiiPeiMpServices2PpiGuid, 0, NULL, (VOID **)&MpServices->Ppi);
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Activate all of the logical processors.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] Procedure A pointer to the function to be run on enabled logical processors.
+ @param[in] ProcedureArgument The parameter passed into Procedure for all enabled logical processors.
+**/
+VOID
+CpuCacheInfoStartupAllCPUs (
+ IN MP_SERVICES MpServices,
+ IN EFI_AP_PROCEDURE Procedure,
+ IN VOID *ProcedureArgument
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MpServices.Ppi->StartupAllCPUs (MpServices.Ppi, Procedure, 0, ProcedureArgument);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get detailed information of the requested logical processor.
+
+ @param[in] MpServices MP_SERVICES structure.
+ @param[in] ProcessorNum The requested logical processor number.
+ @param[out] ProcessorInfo A pointer to the buffer where the processor information is stored
+**/
+VOID
+CpuCacheInfoGetProcessorInfo (
+ IN MP_SERVICES MpServices,
+ IN UINTN ProcessorNum,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfo
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MpServices.Ppi->GetProcessorInfo (MpServices.Ppi, ProcessorNum, ProcessorInfo);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Get the logical processor number.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the logical processor number.
+**/
+UINT32
+CpuCacheInfoWhoAmI (
+ IN MP_SERVICES MpServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorNum;
+
+ Status = MpServices.Ppi->WhoAmI (MpServices.Ppi, &ProcessorNum);
+ ASSERT_EFI_ERROR (Status);
+
+ return (UINT32)ProcessorNum;
+}
+
+/**
+ Get the total number of logical processors in the platform.
+
+ @param[in] MpServices MP_SERVICES structure.
+
+ @retval Return the total number of logical processors.
+**/
+UINT32
+CpuCacheInfoGetNumberOfProcessors (
+ IN MP_SERVICES MpServices
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfProcessor;
+ UINTN NumberOfEnabledProcessor;
+
+ Status = MpServices.Ppi->GetNumberOfProcessors (MpServices.Ppi, &NumberOfProcessor, &NumberOfEnabledProcessor);
+ ASSERT_EFI_ERROR (Status);
+
+ return (UINT32)NumberOfProcessor;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf
new file mode 100644
index 00000000..4b7bc54f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCacheInfoLib/PeiCpuCacheInfoLib.inf
@@ -0,0 +1,43 @@
+## @file
+# CPU Cache Info Library instance for PEI module.
+#
+# Provides cache info for each package, core type, cache level and cache type.
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuCacheInfoLib
+ FILE_GUID = CFEE2DBE-53B2-4916-84CA-0BA83C3DDA6E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CpuCacheInfoLib|PEIM
+ MODULE_UNI_FILE = CpuCacheInfoLib.uni
+
+[Sources]
+ InternalCpuCacheInfoLib.h
+ CpuCacheInfoLib.c
+ PeiCpuCacheInfoLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ PeiServicesTablePointerLib
+
+[Ppis]
+ gEdkiiPeiMpServices2PpiGuid
+
+[Pcd]
+
+[Depex]
+ gEdkiiPeiMpServices2PpiGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Aesni.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Aesni.c
new file mode 100644
index 00000000..1ba239b4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Aesni.c
@@ -0,0 +1,119 @@
+/** @file
+ AESNI feature.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+AesniGetConfigData (
+ IN UINTN NumberOfProcessors
+ )
+{
+ UINT64 *ConfigData;
+
+ ConfigData = AllocateZeroPool (sizeof (UINT64) * NumberOfProcessors);
+ ASSERT (ConfigData != NULL);
+ return ConfigData;
+}
+
+/**
+ Detects if AESNI feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE AESNI feature is supported.
+ @retval FALSE AESNI feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+AesniSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ MSR_SANDY_BRIDGE_FEATURE_CONFIG_REGISTER *MsrFeatureConfig;
+
+ if (CpuInfo->CpuIdVersionInfoEcx.Bits.AESNI == 1) {
+ MsrFeatureConfig = (MSR_SANDY_BRIDGE_FEATURE_CONFIG_REGISTER *) ConfigData;
+ ASSERT (MsrFeatureConfig != NULL);
+ MsrFeatureConfig[ProcessorNumber].Uint64 = AsmReadMsr64 (MSR_SANDY_BRIDGE_FEATURE_CONFIG);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Initializes AESNI feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the AESNI feature must be enabled.
+ If FALSE, then the AESNI feature must be disabled.
+
+ @retval RETURN_SUCCESS AESNI feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+AesniInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ MSR_SANDY_BRIDGE_FEATURE_CONFIG_REGISTER *MsrFeatureConfig;
+
+ //
+ // SANDY_BRIDGE, SILVERMONT, XEON_5600, XEON_7, and XEON_PHI have the same MSR index,
+ // Simply use MSR_SANDY_BRIDGE_FEATURE_CONFIG here
+ //
+ // The scope of the MSR_SANDY_BRIDGE_FEATURE_CONFIG is Core, only program MSR_FEATURE_CONFIG for thread 0
+ // of each core. Otherwise, once a thread in the core disabled AES, the other thread will cause GP when
+ // programming it.
+ //
+ if (CpuInfo->ProcessorInfo.Location.Thread == 0) {
+ MsrFeatureConfig = (MSR_SANDY_BRIDGE_FEATURE_CONFIG_REGISTER *) ConfigData;
+ ASSERT (MsrFeatureConfig != NULL);
+ if ((MsrFeatureConfig[ProcessorNumber].Bits.AESConfiguration & BIT0) == 0) {
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_SANDY_BRIDGE_FEATURE_CONFIG,
+ MSR_SANDY_BRIDGE_FEATURE_CONFIG_REGISTER,
+ Bits.AESConfiguration,
+ BIT0 | ((State) ? 0 : BIT1)
+ );
+ }
+ }
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/C1e.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/C1e.c
new file mode 100644
index 00000000..5969b2af
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/C1e.c
@@ -0,0 +1,81 @@
+/** @file
+ C1E feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if C1E feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE C1E feature is supported.
+ @retval FALSE C1E feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+C1eSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return IS_NEHALEM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel);
+}
+
+/**
+ Initializes C1E feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the C1E feature must be enabled.
+ If FALSE, then the C1E feature must be disabled.
+
+ @retval RETURN_SUCCESS C1E feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+C1eInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of C1EEnable bit in the MSR_NEHALEM_POWER_CTL is Package, only program
+ // MSR_FEATURE_CONFIG for thread 0 core 0 in each package.
+ //
+ if ((CpuInfo->ProcessorInfo.Location.Thread != 0) || (CpuInfo->ProcessorInfo.Location.Core != 0)) {
+ return RETURN_SUCCESS;
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_NEHALEM_POWER_CTL,
+ MSR_NEHALEM_POWER_CTL_REGISTER,
+ Bits.C1EEnable,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ClockModulation.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ClockModulation.c
new file mode 100644
index 00000000..2af0ec22
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ClockModulation.c
@@ -0,0 +1,131 @@
+/** @file
+ Clock Modulation feature.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+typedef struct {
+ CPUID_THERMAL_POWER_MANAGEMENT_EAX ThermalPowerManagementEax;
+ MSR_IA32_CLOCK_MODULATION_REGISTER ClockModulation;
+} CLOCK_MODULATION_CONFIG_DATA;
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+ClockModulationGetConfigData (
+ IN UINTN NumberOfProcessors
+ )
+{
+ UINT32 *ConfigData;
+
+ ConfigData = AllocateZeroPool (sizeof (CLOCK_MODULATION_CONFIG_DATA) * NumberOfProcessors);
+ ASSERT (ConfigData != NULL);
+ return ConfigData;
+}
+
+/**
+ Detects if Clock Modulation feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Clock Modulation feature is supported.
+ @retval FALSE Clock Modulation feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+ClockModulationSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ CLOCK_MODULATION_CONFIG_DATA *CmConfigData;
+
+ if (CpuInfo->CpuIdVersionInfoEdx.Bits.ACPI == 1) {
+ CmConfigData = (CLOCK_MODULATION_CONFIG_DATA *) ConfigData;
+ ASSERT (CmConfigData != NULL);
+ AsmCpuid (
+ CPUID_THERMAL_POWER_MANAGEMENT,
+ &CmConfigData[ProcessorNumber].ThermalPowerManagementEax.Uint32,
+ NULL,
+ NULL,
+ NULL
+ );
+ CmConfigData[ProcessorNumber].ClockModulation.Uint64 = AsmReadMsr64 (MSR_IA32_CLOCK_MODULATION);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Initializes Clock Modulation feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Clock Modulation feature must be enabled.
+ If FALSE, then the Clock Modulation feature must be disabled.
+
+ @retval RETURN_SUCCESS Clock Modulation feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+ClockModulationInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ CLOCK_MODULATION_CONFIG_DATA *CmConfigData;
+ MSR_IA32_CLOCK_MODULATION_REGISTER *ClockModulation;
+
+ CmConfigData = (CLOCK_MODULATION_CONFIG_DATA *) ConfigData;
+ ASSERT (CmConfigData != NULL);
+ ClockModulation = &CmConfigData[ProcessorNumber].ClockModulation;
+
+ if (State) {
+ ClockModulation->Bits.OnDemandClockModulationEnable = 1;
+ ClockModulation->Bits.OnDemandClockModulationDutyCycle = PcdGet8 (PcdCpuClockModulationDutyCycle) >> 1;
+ if (CmConfigData[ProcessorNumber].ThermalPowerManagementEax.Bits.ECMD == 1) {
+ ClockModulation->Bits.ExtendedOnDemandClockModulationDutyCycle = PcdGet8 (PcdCpuClockModulationDutyCycle) & BIT0;
+ }
+ } else {
+ ClockModulation->Bits.OnDemandClockModulationEnable = 0;
+ }
+
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_CLOCK_MODULATION,
+ ClockModulation->Uint64
+ );
+
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeatures.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeatures.h
new file mode 100644
index 00000000..fbefc726
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeatures.h
@@ -0,0 +1,1039 @@
+/** @file
+ CPU Common features library header file.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CPU_COMMON_FEATURES_H_
+#define _CPU_COMMON_FEATURES_H_
+
+#include <PiDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/RegisterCpuFeaturesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/LocalApicLib.h>
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Intel/Msr.h>
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+AesniGetConfigData (
+ IN UINTN NumberOfProcessors
+ );
+
+/**
+ Detects if AESNI feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE AESNI feature is supported.
+ @retval FALSE AESNI feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+AesniSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes AESNI feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the AESNI feature must be enabled.
+ If FALSE, then the AESNI feature must be disabled.
+
+ @retval RETURN_SUCCESS AESNI feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+AesniInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+ClockModulationGetConfigData (
+ IN UINTN NumberOfProcessors
+ );
+
+/**
+ Detects if Clock Modulation feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Clock Modulation feature is supported.
+ @retval FALSE Clock Modulation feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+ClockModulationSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Clock Modulation feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Clock Modulation feature must be enabled.
+ If FALSE, then the Clock Modulation feature must be disabled.
+
+ @retval RETURN_SUCCESS Clock Modulation feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+ClockModulationInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Enhanced Intel SpeedStep feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Enhanced Intel SpeedStep feature is supported.
+ @retval FALSE Enhanced Intel SpeedStep feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+EistSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Enhanced Intel SpeedStep feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Enhanced Intel SpeedStep feature
+ must be enabled.
+ If FALSE, then the Enhanced Intel SpeedStep feature
+ must be disabled.
+
+ @retval RETURN_SUCCESS Enhanced Intel SpeedStep feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+EistInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Execute Disable feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Execute Disable feature is supported.
+ @retval FALSE Execute Disable feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+ExecuteDisableSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Execute Disable feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Execute Disable feature must be enabled.
+ If FALSE, then the Execute Disable feature must be disabled.
+
+ @retval RETURN_SUCCESS Execute Disable feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+ExecuteDisableInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Initializes Fast-Strings feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Fast-Strings feature must be enabled.
+ If FALSE, then the Fast-Strings feature must be disabled.
+
+ @retval RETURN_SUCCESS Fast-Strings feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+FastStringsInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if MONITOR/MWAIT feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE MONITOR/MWAIT feature is supported.
+ @retval FALSE MONITOR/MWAIT feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+MonitorMwaitSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes MONITOR/MWAIT feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the MONITOR/MWAIT feature must be enabled.
+ If FALSE, then the MONITOR/MWAIT feature must be disabled.
+
+ @retval RETURN_SUCCESS MONITOR/MWAIT feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+MonitorMwaitInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if VMX feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE VMX feature is supported.
+ @retval FALSE VMX feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+VmxSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes VMX feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the VMX feature must be enabled.
+ If FALSE, then the VMX feature must be disabled.
+
+ @retval RETURN_SUCCESS VMX feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+VmxInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Lock Feature Control Register feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Lock Feature Control Register feature is supported.
+ @retval FALSE Lock Feature Control Register feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LockFeatureControlRegisterSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Lock Feature Control Register feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Lock Feature Control Register feature must be enabled.
+ If FALSE, then the Lock Feature Control Register feature must be disabled.
+
+ @retval RETURN_SUCCESS Lock Feature Control Register feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+LockFeatureControlRegisterInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if SMX feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE SMX feature is supported.
+ @retval FALSE SMX feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+SmxSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes SMX feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then SMX feature must be enabled.
+ If FALSE, then SMX feature must be disabled.
+
+ @retval RETURN_SUCCESS SMX feature is initialized.
+ @retval RETURN_UNSUPPORTED VMX not initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+SmxInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if LimitCpuidMaxval feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE LimitCpuidMaxval feature is supported.
+ @retval FALSE LimitCpuidMaxval feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LimitCpuidMaxvalSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes LimitCpuidMaxval feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the LimitCpuidMaxval feature must be enabled.
+ If FALSE, then the LimitCpuidMaxval feature must be disabled.
+
+ @retval RETURN_SUCCESS LimitCpuidMaxval feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+LimitCpuidMaxvalInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Machine Check Exception feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Machine Check Exception feature is supported.
+ @retval FALSE Machine Check Exception feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+MceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Machine Check Exception feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Machine Check Exception feature must be enabled.
+ If FALSE, then the Machine Check Exception feature must be disabled.
+
+ @retval RETURN_SUCCESS Machine Check Exception feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+MceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Machine Check Architecture feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Machine Check Architecture feature is supported.
+ @retval FALSE Machine Check Architecture feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+McaSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Machine Check Architecture feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Machine Check Architecture feature must be enabled.
+ If FALSE, then the Machine Check Architecture feature must be disabled.
+
+ @retval RETURN_SUCCESS Machine Check Architecture feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+McaInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if IA32_MCG_CTL feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE IA32_MCG_CTL feature is supported.
+ @retval FALSE IA32_MCG_CTL feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+McgCtlSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes IA32_MCG_CTL feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the IA32_MCG_CTL feature must be enabled.
+ If FALSE, then the IA32_MCG_CTL feature must be disabled.
+
+ @retval RETURN_SUCCESS IA32_MCG_CTL feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+McgCtlInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Pending Break feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Pending Break feature is supported.
+ @retval FALSE Pending Break feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+PendingBreakSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Pending Break feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Pending Break feature must be enabled.
+ If FALSE, then the Pending Break feature must be disabled.
+
+ @retval RETURN_SUCCESS Pending Break feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+PendingBreakInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if C1E feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE C1E feature is supported.
+ @retval FALSE C1E feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+C1eSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes C1E feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the C1E feature must be enabled.
+ If FALSE, then the C1E feature must be disabled.
+
+ @retval RETURN_SUCCESS C1E feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+C1eInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+X2ApicGetConfigData (
+ IN UINTN NumberOfProcessors
+ );
+
+/**
+ Detects if X2Apci feature supported on current processor.
+
+ Detect if X2Apci has been already enabled.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE X2Apci feature is supported.
+ @retval FALSE X2Apci feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+X2ApicSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes X2Apci feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the X2Apci feature must be enabled.
+ If FALSE, then the X2Apci feature must be disabled.
+
+ @retval RETURN_SUCCESS X2Apci feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+X2ApicInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+PpinGetConfigData (
+ IN UINTN NumberOfProcessors
+ );
+
+/**
+ Detects if Protected Processor Inventory Number feature supported on current
+ processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Protected Processor Inventory Number feature is supported.
+ @retval FALSE Protected Processor Inventory Number feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+PpinSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Protected Processor Inventory Number feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Protected Processor Inventory
+ Number feature must be enabled.
+ If FALSE, then the Protected Processor Inventory
+ Number feature must be disabled.
+
+ @retval RETURN_SUCCESS Protected Processor Inventory Number feature is
+ initialized.
+ @retval RETURN_DEVICE_ERROR Device can't change state because it has been
+ locked.
+
+**/
+RETURN_STATUS
+EFIAPI
+PpinInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Detects if Local machine check exception feature supported on current
+ processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Local machine check exception feature is supported.
+ @retval FALSE Local machine check exception feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LmceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Local machine check exception feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Local machine check exception
+ feature must be enabled.
+ If FALSE, then the Local machine check exception
+ feature must be disabled.
+
+ @retval RETURN_SUCCESS Local machine check exception feature is initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+LmceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+ProcTraceGetConfigData (
+ IN UINTN NumberOfProcessors
+ );
+
+/**
+ Detects if Intel Processor Trace feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Processor Trace feature is supported.
+ @retval FALSE Processor Trace feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+ProcTraceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ );
+
+/**
+ Initializes Intel Processor Trace feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Processor Trace feature must be
+ enabled.
+ If FALSE, then the Processor Trace feature must be
+ disabled.
+
+ @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+ProcTraceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c
new file mode 100644
index 00000000..654e08db
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.c
@@ -0,0 +1,231 @@
+/** @file
+ This library registers CPU features defined in Intel(R) 64 and IA-32
+ Architectures Software Developer's Manual.
+
+ Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Register CPU features.
+
+ @retval RETURN_SUCCESS Register successfully
+**/
+RETURN_STATUS
+EFIAPI
+CpuCommonFeaturesLibConstructor (
+ VOID
+ )
+{
+ RETURN_STATUS Status;
+
+ if (IsCpuFeatureSupported (CPU_FEATURE_AESNI)) {
+ Status = RegisterCpuFeature (
+ "AESNI",
+ AesniGetConfigData,
+ AesniSupport,
+ AesniInitialize,
+ CPU_FEATURE_AESNI,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_MWAIT)) {
+ Status = RegisterCpuFeature (
+ "MWAIT",
+ NULL,
+ MonitorMwaitSupport,
+ MonitorMwaitInitialize,
+ CPU_FEATURE_MWAIT,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_ACPI)) {
+ Status = RegisterCpuFeature (
+ "ACPI",
+ ClockModulationGetConfigData,
+ ClockModulationSupport,
+ ClockModulationInitialize,
+ CPU_FEATURE_ACPI,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_EIST)) {
+ Status = RegisterCpuFeature (
+ "EIST",
+ NULL,
+ EistSupport,
+ EistInitialize,
+ CPU_FEATURE_EIST,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_FASTSTRINGS)) {
+ Status = RegisterCpuFeature (
+ "FastStrings",
+ NULL,
+ NULL,
+ FastStringsInitialize,
+ CPU_FEATURE_FASTSTRINGS,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_LOCK_FEATURE_CONTROL_REGISTER)) {
+ Status = RegisterCpuFeature (
+ "Lock Feature Control Register",
+ NULL,
+ LockFeatureControlRegisterSupport,
+ LockFeatureControlRegisterInitialize,
+ CPU_FEATURE_LOCK_FEATURE_CONTROL_REGISTER,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_SMX)) {
+ Status = RegisterCpuFeature (
+ "SMX",
+ NULL,
+ SmxSupport,
+ SmxInitialize,
+ CPU_FEATURE_SMX,
+ CPU_FEATURE_LOCK_FEATURE_CONTROL_REGISTER | CPU_FEATURE_THREAD_BEFORE,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_VMX)) {
+ Status = RegisterCpuFeature (
+ "VMX",
+ NULL,
+ VmxSupport,
+ VmxInitialize,
+ CPU_FEATURE_VMX,
+ CPU_FEATURE_LOCK_FEATURE_CONTROL_REGISTER | CPU_FEATURE_THREAD_BEFORE,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_LIMIT_CPUID_MAX_VAL)) {
+ Status = RegisterCpuFeature (
+ "Limit CpuId Maximum Value",
+ NULL,
+ LimitCpuidMaxvalSupport,
+ LimitCpuidMaxvalInitialize,
+ CPU_FEATURE_LIMIT_CPUID_MAX_VAL,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_MCE)) {
+ Status = RegisterCpuFeature (
+ "Machine Check Enable",
+ NULL,
+ MceSupport,
+ MceInitialize,
+ CPU_FEATURE_MCE,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_MCA)) {
+ Status = RegisterCpuFeature (
+ "Machine Check Architect",
+ NULL,
+ McaSupport,
+ McaInitialize,
+ CPU_FEATURE_MCA,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_MCG_CTL)) {
+ Status = RegisterCpuFeature (
+ "MCG_CTL",
+ NULL,
+ McgCtlSupport,
+ McgCtlInitialize,
+ CPU_FEATURE_MCG_CTL,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_PENDING_BREAK)) {
+ Status = RegisterCpuFeature (
+ "Pending Break",
+ NULL,
+ PendingBreakSupport,
+ PendingBreakInitialize,
+ CPU_FEATURE_PENDING_BREAK,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_C1E)) {
+ Status = RegisterCpuFeature (
+ "C1E",
+ NULL,
+ C1eSupport,
+ C1eInitialize,
+ CPU_FEATURE_C1E,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_X2APIC)) {
+ Status = RegisterCpuFeature (
+ "X2Apic",
+ X2ApicGetConfigData,
+ X2ApicSupport,
+ X2ApicInitialize,
+ CPU_FEATURE_X2APIC,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_PPIN)) {
+ Status = RegisterCpuFeature (
+ "PPIN",
+ PpinGetConfigData,
+ PpinSupport,
+ PpinInitialize,
+ CPU_FEATURE_PPIN,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_LMCE)) {
+ Status = RegisterCpuFeature (
+ "LMCE",
+ NULL,
+ LmceSupport,
+ LmceInitialize,
+ CPU_FEATURE_LMCE,
+ CPU_FEATURE_LOCK_FEATURE_CONTROL_REGISTER | CPU_FEATURE_THREAD_BEFORE,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (IsCpuFeatureSupported (CPU_FEATURE_PROC_TRACE)) {
+ Status = RegisterCpuFeature (
+ "Proc Trace",
+ ProcTraceGetConfigData,
+ ProcTraceSupport,
+ ProcTraceInitialize,
+ CPU_FEATURE_PROC_TRACE,
+ CPU_FEATURE_END
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return RETURN_SUCCESS;
+}
+
+
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf
new file mode 100644
index 00000000..b7522abe
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.inf
@@ -0,0 +1,64 @@
+## @file
+# NULL instance to register CPU features.
+#
+# This library registers CPU features defined in Intel(R) 64 and IA-32
+# Architectures Software Developer's Manual.
+#
+# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuCommonFeaturesLib
+ MODULE_UNI_FILE = CpuCommonFeaturesLib.uni
+ FILE_GUID = 6D69F79F-9535-4893-9DD7-93929898252C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+
+ CONSTRUCTOR = CpuCommonFeaturesLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CpuCommonFeaturesLib.c
+ CpuCommonFeatures.h
+ Aesni.c
+ C1e.c
+ ClockModulation.c
+ Eist.c
+ FastStrings.c
+ FeatureControl.c
+ LimitCpuIdMaxval.c
+ MachineCheck.c
+ MonitorMwait.c
+ PendingBreak.c
+ X2Apic.c
+ Ppin.c
+ ProcTrace.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+ RegisterCpuFeaturesLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ LocalApicLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuClockModulationDutyCycle ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdIsPowerOnReset ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceOutputScheme ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuProcTraceMemSize ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.uni
new file mode 100644
index 00000000..7f799e89
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/CpuCommonFeaturesLib.uni
@@ -0,0 +1,20 @@
+// /** @file
+// Dxe Crc32 Guided Section Extract library.
+//
+// This library doesn't produce any library class. The constructor function uses
+// ExtractGuidedSectionLib service to register CRC32 guided section handler
+// that parses CRC32 encapsulation section and extracts raw data.
+//
+// It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value.
+//
+// Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Dxe Crc32 Guided Section Extract library."
+
+#string STR_MODULE_DESCRIPTION #language en-US "This library doesn't produce any library class. The constructor function uses ExtractGuidedSectionLib service to register CRC32 guided section handler that parses CRC32 encapsulation section and extracts raw data. It uses UEFI boot service CalculateCrc32 to authenticate 32 bit CRC value."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Eist.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Eist.c
new file mode 100644
index 00000000..8b208c7c
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Eist.c
@@ -0,0 +1,87 @@
+/** @file
+ Enhanced Intel SpeedStep feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if Enhanced Intel SpeedStep feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Enhanced Intel SpeedStep feature is supported.
+ @retval FALSE Enhanced Intel SpeedStep feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+EistSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return (CpuInfo->CpuIdVersionInfoEcx.Bits.EIST == 1);
+}
+
+/**
+ Initializes Enhanced Intel SpeedStep feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Enhanced Intel SpeedStep feature
+ must be enabled.
+ If FALSE, then the Enhanced Intel SpeedStep feature
+ must be disabled.
+
+ @retval RETURN_SUCCESS Enhanced Intel SpeedStep feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+EistInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of the MSR_IA32_MISC_ENABLE is core for below processor type, only program
+ // MSR_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ if (IS_ATOM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE2_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_REGISTER,
+ Bits.EIST,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FastStrings.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FastStrings.c
new file mode 100644
index 00000000..e0a17a70
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FastStrings.c
@@ -0,0 +1,58 @@
+/** @file
+ Fast-Strings feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Initializes Fast-Strings feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Fast-Strings feature must be enabled.
+ If FALSE, then the Fast-Strings feature must be disabled.
+
+ @retval RETURN_SUCCESS Fast-Strings feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+FastStringsInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of FastStrings bit in the MSR_IA32_MISC_ENABLE is core for below processor type, only program
+ // MSR_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_REGISTER,
+ Bits.FastStrings,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c
new file mode 100644
index 00000000..1735fe7d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/FeatureControl.c
@@ -0,0 +1,280 @@
+/** @file
+ Features in MSR_IA32_FEATURE_CONTROL register.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if VMX feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE VMX feature is supported.
+ @retval FALSE VMX feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+VmxSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return (CpuInfo->CpuIdVersionInfoEcx.Bits.VMX == 1);
+}
+
+/**
+ Initializes VMX feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the VMX feature must be enabled.
+ If FALSE, then the VMX feature must be disabled.
+
+ @retval RETURN_SUCCESS VMX feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+VmxInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of EnableVmxOutsideSmx bit in the MSR_IA32_FEATURE_CONTROL is core for
+ // below processor type, only program MSR_IA32_FEATURE_CONTROL for thread 0 in each
+ // core.
+ //
+ if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.EnableVmxOutsideSmx,
+ (State) ? 1 : 0
+ );
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Detects if Lock Feature Control Register feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Lock Feature Control Register feature is supported.
+ @retval FALSE Lock Feature Control Register feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LockFeatureControlRegisterSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return TRUE;
+}
+
+/**
+ Initializes Lock Feature Control Register feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Lock Feature Control Register feature must be enabled.
+ If FALSE, then the Lock Feature Control Register feature must be disabled.
+
+ @retval RETURN_SUCCESS Lock Feature Control Register feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+LockFeatureControlRegisterInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of Lock bit in the MSR_IA32_FEATURE_CONTROL is core for
+ // below processor type, only program MSR_IA32_FEATURE_CONTROL for thread 0 in each
+ // core.
+ //
+ if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.Lock,
+ 1
+ );
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Detects if SMX feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE SMX feature is supported.
+ @retval FALSE SMX feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+SmxSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return (CpuInfo->CpuIdVersionInfoEcx.Bits.SMX == 1);
+}
+
+/**
+ Initializes SMX feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then SMX feature must be enabled.
+ If FALSE, then SMX feature must be disabled.
+
+ @retval RETURN_SUCCESS SMX feature is initialized.
+ @retval RETURN_UNSUPPORTED VMX not initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+SmxInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ RETURN_STATUS Status;
+
+ //
+ // The scope of Lock bit in the MSR_IA32_FEATURE_CONTROL is core for
+ // below processor type, only program MSR_IA32_FEATURE_CONTROL for thread 0 in each
+ // core.
+ //
+ if (IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ Status = RETURN_SUCCESS;
+
+ if (State && (!IsCpuFeatureInSetting (CPU_FEATURE_VMX))) {
+ DEBUG ((DEBUG_WARN, "Warning :: Can't enable SMX feature when VMX feature not enabled, disable it.\n"));
+ State = FALSE;
+ Status = RETURN_UNSUPPORTED;
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ ControlRegister,
+ 4,
+ IA32_CR4,
+ Bits.SMXE,
+ (State) ? 1 : 0
+ )
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.SenterLocalFunctionEnables,
+ (State) ? 0x7F : 0
+ );
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.SenterGlobalEnable,
+ (State) ? 1 : 0
+ );
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.EnableVmxInsideSmx,
+ (State) ? 1 : 0
+ );
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/LimitCpuIdMaxval.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/LimitCpuIdMaxval.c
new file mode 100644
index 00000000..889a5f18
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/LimitCpuIdMaxval.c
@@ -0,0 +1,90 @@
+/** @file
+ LimitCpuidMaxval Feature.
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if LimitCpuidMaxval feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE LimitCpuidMaxval feature is supported.
+ @retval FALSE LimitCpuidMaxval feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LimitCpuidMaxvalSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ UINT32 Eax;
+
+ AsmCpuid (CPUID_SIGNATURE, &Eax, NULL, NULL, NULL);
+ return (Eax > 2);
+}
+
+/**
+ Initializes LimitCpuidMaxval feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the LimitCpuidMaxval feature must be enabled.
+ If FALSE, then the LimitCpuidMaxval feature must be disabled.
+
+ @retval RETURN_SUCCESS LimitCpuidMaxval feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+LimitCpuidMaxvalInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of LimitCpuidMaxval bit in the MSR_IA32_MISC_ENABLE is core for below
+ // processor type, only program MSR_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ if (IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE2_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_REGISTER,
+ Bits.LimitCpuidMaxval,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MachineCheck.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MachineCheck.c
new file mode 100644
index 00000000..59e213ce
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MachineCheck.c
@@ -0,0 +1,344 @@
+/** @file
+ Machine Check features.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if Machine Check Exception feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Machine Check Exception feature is supported.
+ @retval FALSE Machine Check Exception feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+MceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return (CpuInfo->CpuIdVersionInfoEdx.Bits.MCE == 1);
+}
+
+/**
+ Initializes Machine Check Exception feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Machine Check Exception feature must be enabled.
+ If FALSE, then the Machine Check Exception feature must be disabled.
+
+ @retval RETURN_SUCCESS Machine Check Exception feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+MceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // Set MCE bit in CR4
+ //
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ ControlRegister,
+ 4,
+ IA32_CR4,
+ Bits.MCE,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
+
+/**
+ Detects if Machine Check Architecture feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Machine Check Architecture feature is supported.
+ @retval FALSE Machine Check Architecture feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+McaSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ if (!MceSupport (ProcessorNumber, CpuInfo, ConfigData)) {
+ return FALSE;
+ }
+ return (CpuInfo->CpuIdVersionInfoEdx.Bits.MCA == 1);
+}
+
+/**
+ Initializes Machine Check Architecture feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Machine Check Architecture feature must be enabled.
+ If FALSE, then the Machine Check Architecture feature must be disabled.
+
+ @retval RETURN_SUCCESS Machine Check Architecture feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+McaInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ MSR_IA32_MCG_CAP_REGISTER McgCap;
+ UINT32 BankIndex;
+
+ //
+ // The scope of MSR_IA32_MC*_CTL/MSR_IA32_MC*_STATUS is core for below processor type, only program
+ // MSR_IA32_MC*_CTL/MSR_IA32_MC*_STATUS for thread 0 in each core.
+ //
+ if (IS_ATOM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_SANDY_BRIDGE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_SKYLAKE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_XEON_PHI_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ //
+ // The scope of MSR_IA32_MC*_CTL/MSR_IA32_MC*_STATUS is package for below processor type, only program
+ // MSR_IA32_MC*_CTL/MSR_IA32_MC*_STATUS for thread 0 core 0 in each package.
+ //
+ if (IS_NEHALEM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if ((CpuInfo->ProcessorInfo.Location.Thread != 0) || (CpuInfo->ProcessorInfo.Location.Core != 0)) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ if (State) {
+ McgCap.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_CAP);
+ for (BankIndex = 0; BankIndex < (UINT32) McgCap.Bits.Count; BankIndex++) {
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MC0_CTL + BankIndex * 4,
+ MAX_UINT64
+ );
+ }
+
+ if (PcdGetBool (PcdIsPowerOnReset)) {
+ for (BankIndex = 0; BankIndex < (UINTN) McgCap.Bits.Count; BankIndex++) {
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MC0_STATUS + BankIndex * 4,
+ 0
+ );
+ }
+ }
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Detects if IA32_MCG_CTL feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE IA32_MCG_CTL feature is supported.
+ @retval FALSE IA32_MCG_CTL feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+McgCtlSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ MSR_IA32_MCG_CAP_REGISTER McgCap;
+
+ if (!McaSupport (ProcessorNumber, CpuInfo, ConfigData)) {
+ return FALSE;
+ }
+ McgCap.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_CAP);
+ return (McgCap.Bits.MCG_CTL_P == 1);
+}
+
+/**
+ Initializes IA32_MCG_CTL feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the IA32_MCG_CTL feature must be enabled.
+ If FALSE, then the IA32_MCG_CTL feature must be disabled.
+
+ @retval RETURN_SUCCESS IA32_MCG_CTL feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+McgCtlInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MCG_CTL,
+ (State)? MAX_UINT64 : 0
+ );
+ return RETURN_SUCCESS;
+}
+
+/**
+ Detects if Local machine check exception feature supported on current
+ processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Local machine check exception feature is supported.
+ @retval FALSE Local machine check exception feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+LmceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ MSR_IA32_MCG_CAP_REGISTER McgCap;
+
+ if (!McaSupport (ProcessorNumber, CpuInfo, ConfigData)) {
+ return FALSE;
+ }
+
+ McgCap.Uint64 = AsmReadMsr64 (MSR_IA32_MCG_CAP);
+ if (ProcessorNumber == 0) {
+ DEBUG ((DEBUG_INFO, "LMCE enable = %x\n", (BOOLEAN) (McgCap.Bits.MCG_LMCE_P != 0)));
+ }
+ return (BOOLEAN) (McgCap.Bits.MCG_LMCE_P != 0);
+}
+
+/**
+ Initializes Local machine check exception feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Local machine check exception
+ feature must be enabled.
+ If FALSE, then the Local machine check exception
+ feature must be disabled.
+
+ @retval RETURN_SUCCESS Local machine check exception feature is initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+LmceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of LcmeOn bit in the MSR_IA32_MISC_ENABLE is core for below processor type, only program
+ // MSR_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_TEST_THEN_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_FEATURE_CONTROL,
+ MSR_IA32_FEATURE_CONTROL_REGISTER,
+ Bits.LmceOn,
+ (State) ? 1 : 0
+ );
+
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MonitorMwait.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MonitorMwait.c
new file mode 100644
index 00000000..fbff3da2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/MonitorMwait.c
@@ -0,0 +1,88 @@
+/** @file
+ MonitorMwait feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if MONITOR/MWAIT feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE MONITOR/MWAIT feature is supported.
+ @retval FALSE MONITOR/MWAIT feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+MonitorMwaitSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ return (CpuInfo->CpuIdVersionInfoEcx.Bits.MONITOR == 1);
+}
+
+/**
+ Initializes MONITOR/MWAIT feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the MONITOR/MWAIT feature must be enabled.
+ If FALSE, then the MONITOR/MWAIT feature must be disabled.
+
+ @retval RETURN_SUCCESS MONITOR/MWAIT feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+MonitorMwaitInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of the MSR_IA32_MISC_ENABLE is core for below processor type, only program
+ // MSR_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ if (IS_CORE2_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_ATOM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_MISC_ENABLE,
+ MSR_IA32_MISC_ENABLE_REGISTER,
+ Bits.MONITOR,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/PendingBreak.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/PendingBreak.c
new file mode 100644
index 00000000..eb9c689e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/PendingBreak.c
@@ -0,0 +1,95 @@
+/** @file
+ Pending Break feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Detects if Pending Break feature supported on current processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Pending Break feature is supported.
+ @retval FALSE Pending Break feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+PendingBreakSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ if (IS_ATOM_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE2_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_CORE_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_4_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_PENTIUM_M_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ return (CpuInfo->CpuIdVersionInfoEdx.Bits.PBE == 1);
+ }
+ return FALSE;
+}
+
+/**
+ Initializes Pending Break feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Pending Break feature must be enabled.
+ If FALSE, then the Pending Break feature must be disabled.
+
+ @retval RETURN_SUCCESS Pending Break feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+PendingBreakInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ //
+ // The scope of the MSR_ATOM_IA32_MISC_ENABLE is core for below processor type, only program
+ // MSR_ATOM_IA32_MISC_ENABLE for thread 0 in each core.
+ //
+ // Support function has check the processer type for this feature, no need to check again
+ // here.
+ //
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+
+ //
+ // ATOM, CORE2, CORE, PENTIUM_4 and IS_PENTIUM_M_PROCESSOR have the same MSR index,
+ // Simply use MSR_ATOM_IA32_MISC_ENABLE here
+ //
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_ATOM_IA32_MISC_ENABLE,
+ MSR_ATOM_IA32_MISC_ENABLE_REGISTER,
+ Bits.FERR,
+ (State) ? 1 : 0
+ );
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Ppin.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Ppin.c
new file mode 100644
index 00000000..4e3af46b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/Ppin.c
@@ -0,0 +1,164 @@
+/** @file
+ Protected Processor Inventory Number(PPIN) feature.
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+PpinGetConfigData (
+ IN UINTN NumberOfProcessors
+ )
+{
+ VOID *ConfigData;
+
+ ConfigData = AllocateZeroPool (sizeof (MSR_IVY_BRIDGE_PPIN_CTL_REGISTER) * NumberOfProcessors);
+ ASSERT (ConfigData != NULL);
+ return ConfigData;
+}
+
+/**
+ Detects if Protected Processor Inventory Number feature supported on current
+ processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Protected Processor Inventory Number feature is supported.
+ @retval FALSE Protected Processor Inventory Number feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+PpinSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ MSR_IVY_BRIDGE_PLATFORM_INFO_1_REGISTER PlatformInfo;
+ MSR_IVY_BRIDGE_PPIN_CTL_REGISTER *MsrPpinCtrl;
+
+ if ((CpuInfo->DisplayFamily == 0x06) &&
+ ((CpuInfo->DisplayModel == 0x3E) || // Xeon E5 V2
+ (CpuInfo->DisplayModel == 0x56) || // Xeon Processor D Product
+ (CpuInfo->DisplayModel == 0x4F) || // Xeon E5 v4, E7 v4
+ (CpuInfo->DisplayModel == 0x55) || // Xeon Processor Scalable
+ (CpuInfo->DisplayModel == 0x57) || // Xeon Phi processor 3200, 5200, 7200 series.
+ (CpuInfo->DisplayModel == 0x85) // Future Xeon phi processor
+ )) {
+ //
+ // Check whether platform support this feature.
+ //
+ PlatformInfo.Uint64 = AsmReadMsr64 (MSR_IVY_BRIDGE_PLATFORM_INFO_1);
+ if (PlatformInfo.Bits.PPIN_CAP != 0) {
+ MsrPpinCtrl = (MSR_IVY_BRIDGE_PPIN_CTL_REGISTER *) ConfigData;
+ ASSERT (MsrPpinCtrl != NULL);
+ MsrPpinCtrl[ProcessorNumber].Uint64 = AsmReadMsr64 (MSR_IVY_BRIDGE_PPIN_CTL);
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Initializes Protected Processor Inventory Number feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Protected Processor Inventory
+ Number feature must be enabled.
+ If FALSE, then the Protected Processor Inventory
+ Number feature must be disabled.
+
+ @retval RETURN_SUCCESS Protected Processor Inventory Number feature is
+ initialized.
+ @retval RETURN_DEVICE_ERROR Device can't change state because it has been
+ locked.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+PpinInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ MSR_IVY_BRIDGE_PPIN_CTL_REGISTER *MsrPpinCtrl;
+
+ MsrPpinCtrl = (MSR_IVY_BRIDGE_PPIN_CTL_REGISTER *) ConfigData;
+ ASSERT (MsrPpinCtrl != NULL);
+
+ //
+ // Check whether processor already lock this register.
+ // If already locked, just based on the request state and
+ // the current state to return the status.
+ //
+ if (MsrPpinCtrl[ProcessorNumber].Bits.LockOut != 0) {
+ return MsrPpinCtrl[ProcessorNumber].Bits.Enable_PPIN == State ? RETURN_SUCCESS : RETURN_DEVICE_ERROR;
+ }
+
+ //
+ // Support function already check the processor which support PPIN feature, so this function not need
+ // to check the processor again.
+ //
+ // The scope of the MSR_IVY_BRIDGE_PPIN_CTL is package level, only program MSR_IVY_BRIDGE_PPIN_CTL for
+ // thread 0 core 0 in each package.
+ //
+ if ((CpuInfo->ProcessorInfo.Location.Thread != 0) || (CpuInfo->ProcessorInfo.Location.Core != 0)) {
+ return RETURN_SUCCESS;
+ }
+
+ if (State) {
+ //
+ // Enable and Unlock.
+ // According to SDM, once Enable_PPIN is set, attempt to write 1 to LockOut will cause #GP.
+ //
+ MsrPpinCtrl[ProcessorNumber].Bits.Enable_PPIN = 1;
+ MsrPpinCtrl[ProcessorNumber].Bits.LockOut = 0;
+ } else {
+ //
+ // Disable and Lock.
+ // According to SDM, writing 1 to LockOut is permitted only if Enable_PPIN is clear.
+ //
+ MsrPpinCtrl[ProcessorNumber].Bits.Enable_PPIN = 0;
+ MsrPpinCtrl[ProcessorNumber].Bits.LockOut = 1;
+ }
+
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IVY_BRIDGE_PPIN_CTL,
+ MsrPpinCtrl[ProcessorNumber].Uint64
+ );
+
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c
new file mode 100644
index 00000000..f2ce9bcf
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/ProcTrace.c
@@ -0,0 +1,473 @@
+/** @file
+ Intel Processor Trace feature.
+
+ Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+///
+/// This macro define the max entries in the Topa table.
+/// Each entry in the table contains some attribute bits, a pointer to an output region, and the size of the region.
+/// The last entry in the table may hold a pointer to the next table. This pointer can either point to the top of the
+/// current table (for circular array) or to the base of another table.
+/// At least 2 entries are needed because the list of entries must
+/// be terminated by an entry with the END bit set to 1, so 2
+/// entries are required to use a single valid entry.
+///
+#define MAX_TOPA_ENTRY_COUNT 2
+
+
+///
+/// Processor trace output scheme selection.
+///
+typedef enum {
+ RtitOutputSchemeSingleRange = 0,
+ RtitOutputSchemeToPA
+} RTIT_OUTPUT_SCHEME;
+
+typedef struct {
+ BOOLEAN TopaSupported;
+ BOOLEAN SingleRangeSupported;
+ MSR_IA32_RTIT_CTL_REGISTER RtitCtrl;
+ MSR_IA32_RTIT_OUTPUT_BASE_REGISTER RtitOutputBase;
+ MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER RtitOutputMaskPtrs;
+} PROC_TRACE_PROCESSOR_DATA;
+
+typedef struct {
+ UINT32 NumberOfProcessors;
+
+ UINT8 ProcTraceOutputScheme;
+ UINT32 ProcTraceMemSize;
+
+ UINTN *ThreadMemRegionTable;
+ UINTN AllocatedThreads;
+
+ UINTN *TopaMemArray;
+
+ PROC_TRACE_PROCESSOR_DATA *ProcessorData;
+} PROC_TRACE_DATA;
+
+typedef struct {
+ RTIT_TOPA_TABLE_ENTRY TopaEntry[MAX_TOPA_ENTRY_COUNT];
+} PROC_TRACE_TOPA_TABLE;
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+ProcTraceGetConfigData (
+ IN UINTN NumberOfProcessors
+ )
+{
+ PROC_TRACE_DATA *ConfigData;
+
+ ConfigData = AllocateZeroPool (sizeof (PROC_TRACE_DATA) + sizeof (PROC_TRACE_PROCESSOR_DATA) * NumberOfProcessors);
+ ASSERT (ConfigData != NULL);
+ ConfigData->ProcessorData = (PROC_TRACE_PROCESSOR_DATA *) ((UINT8*) ConfigData + sizeof (PROC_TRACE_DATA));
+
+ ConfigData->NumberOfProcessors = (UINT32) NumberOfProcessors;
+ ConfigData->ProcTraceMemSize = PcdGet32 (PcdCpuProcTraceMemSize);
+ ConfigData->ProcTraceOutputScheme = PcdGet8 (PcdCpuProcTraceOutputScheme);
+
+ return ConfigData;
+}
+
+/**
+ Detects if Intel Processor Trace feature supported on current
+ processor.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE Processor Trace feature is supported.
+ @retval FALSE Processor Trace feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+ProcTraceSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ PROC_TRACE_DATA *ProcTraceData;
+ CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX Ebx;
+ CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF_ECX Ecx;
+
+ //
+ // Check if ProcTraceMemorySize option is enabled (0xFF means disable by user)
+ //
+ ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
+ ASSERT (ProcTraceData != NULL);
+ if ((ProcTraceData->ProcTraceMemSize > RtitTopaMemorySize128M) ||
+ (ProcTraceData->ProcTraceOutputScheme > RtitOutputSchemeToPA)) {
+ return FALSE;
+ }
+
+ //
+ // Check if Processor Trace is supported
+ //
+ AsmCpuidEx (CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS, 0, NULL, &Ebx.Uint32, NULL, NULL);
+ if (Ebx.Bits.IntelProcessorTrace == 0) {
+ return FALSE;
+ }
+
+ AsmCpuidEx (CPUID_INTEL_PROCESSOR_TRACE, CPUID_INTEL_PROCESSOR_TRACE_MAIN_LEAF, NULL, NULL, &Ecx.Uint32, NULL);
+ ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported = (BOOLEAN) (Ecx.Bits.RTIT == 1);
+ ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported = (BOOLEAN) (Ecx.Bits.SingleRangeOutput == 1);
+ if ((ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported && (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeToPA)) ||
+ (ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported && (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeSingleRange))) {
+ ProcTraceData->ProcessorData[ProcessorNumber].RtitCtrl.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_CTL);
+ ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_BASE);
+ ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64 = AsmReadMsr64 (MSR_IA32_RTIT_OUTPUT_MASK_PTRS);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Initializes Intel Processor Trace feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the Processor Trace feature must be
+ enabled.
+ If FALSE, then the Processor Trace feature must be
+ disabled.
+
+ @retval RETURN_SUCCESS Intel Processor Trace feature is initialized.
+
+**/
+RETURN_STATUS
+EFIAPI
+ProcTraceInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ UINT32 MemRegionSize;
+ UINTN Pages;
+ UINTN Alignment;
+ UINTN MemRegionBaseAddr;
+ UINTN *ThreadMemRegionTable;
+ UINTN Index;
+ UINTN TopaTableBaseAddr;
+ UINTN AlignedAddress;
+ UINTN *TopaMemArray;
+ PROC_TRACE_TOPA_TABLE *TopaTable;
+ PROC_TRACE_DATA *ProcTraceData;
+ BOOLEAN FirstIn;
+ MSR_IA32_RTIT_CTL_REGISTER CtrlReg;
+ MSR_IA32_RTIT_STATUS_REGISTER StatusReg;
+ MSR_IA32_RTIT_OUTPUT_BASE_REGISTER OutputBaseReg;
+ MSR_IA32_RTIT_OUTPUT_MASK_PTRS_REGISTER OutputMaskPtrsReg;
+ RTIT_TOPA_TABLE_ENTRY *TopaEntryPtr;
+
+ //
+ // The scope of the MSR_IA32_RTIT_* is core for below processor type, only program
+ // MSR_IA32_RTIT_* for thread 0 in each core.
+ //
+ if (IS_GOLDMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel) ||
+ IS_GOLDMONT_PLUS_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ ProcTraceData = (PROC_TRACE_DATA *) ConfigData;
+ ASSERT (ProcTraceData != NULL);
+
+ //
+ // Clear MSR_IA32_RTIT_CTL[0] and IA32_RTIT_STS only if MSR_IA32_RTIT_CTL[0]==1b
+ //
+ CtrlReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitCtrl.Uint64;
+ if (CtrlReg.Bits.TraceEn != 0) {
+ ///
+ /// Clear bit 0 in MSR IA32_RTIT_CTL (570)
+ ///
+ CtrlReg.Bits.TraceEn = 0;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_CTL,
+ CtrlReg.Uint64
+ );
+
+ ///
+ /// Clear MSR IA32_RTIT_STS (571h) to all zeros
+ ///
+ StatusReg.Uint64 = 0x0;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_STATUS,
+ StatusReg.Uint64
+ );
+ }
+
+ if (!State) {
+ return RETURN_SUCCESS;
+ }
+
+ MemRegionBaseAddr = 0;
+ FirstIn = FALSE;
+
+ if (ProcTraceData->ThreadMemRegionTable == NULL) {
+ FirstIn = TRUE;
+ DEBUG ((DEBUG_INFO, "Initialize Processor Trace\n"));
+ }
+
+ ///
+ /// Refer to PROC_TRACE_MEM_SIZE Table for Size Encoding
+ ///
+ MemRegionSize = (UINT32) (1 << (ProcTraceData->ProcTraceMemSize + 12));
+ if (FirstIn) {
+ DEBUG ((DEBUG_INFO, "ProcTrace: MemSize requested: 0x%X \n", MemRegionSize));
+ }
+
+ if (FirstIn) {
+ //
+ // Let BSP allocate and create the necessary memory region (Aligned to the size of
+ // the memory region from setup option(ProcTraceMemSize) which is an integral multiple of 4kB)
+ // for all the enabled threads to store Processor Trace debug data. Then Configure the trace
+ // address base in MSR, IA32_RTIT_OUTPUT_BASE (560h) bits 47:12. Note that all regions must be
+ // aligned based on their size, not just 4K. Thus a 2M region must have bits 20:12 cleared.
+ //
+ ThreadMemRegionTable = (UINTN *) AllocatePool (ProcTraceData->NumberOfProcessors * sizeof (UINTN *));
+ if (ThreadMemRegionTable == NULL) {
+ DEBUG ((DEBUG_ERROR, "Allocate ProcTrace ThreadMemRegionTable Failed\n"));
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ ProcTraceData->ThreadMemRegionTable = ThreadMemRegionTable;
+
+ for (Index = 0; Index < ProcTraceData->NumberOfProcessors; Index++, ProcTraceData->AllocatedThreads++) {
+ Pages = EFI_SIZE_TO_PAGES (MemRegionSize);
+ Alignment = MemRegionSize;
+ AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);
+ if (AlignedAddress == 0) {
+ DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocated only for %d threads\n", ProcTraceData->AllocatedThreads));
+ if (Index == 0) {
+ //
+ // Could not allocate for BSP even
+ //
+ FreePool ((VOID *) ThreadMemRegionTable);
+ ThreadMemRegionTable = NULL;
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ break;
+ }
+
+ ThreadMemRegionTable[Index] = AlignedAddress;
+ DEBUG ((DEBUG_INFO, "ProcTrace: PT MemRegionBaseAddr(aligned) for thread %d: 0x%llX \n", Index, (UINT64) ThreadMemRegionTable[Index]));
+ }
+
+ DEBUG ((DEBUG_INFO, "ProcTrace: Allocated PT mem for %d thread \n", ProcTraceData->AllocatedThreads));
+ }
+
+ if (ProcessorNumber < ProcTraceData->AllocatedThreads) {
+ MemRegionBaseAddr = ProcTraceData->ThreadMemRegionTable[ProcessorNumber];
+ } else {
+ return RETURN_SUCCESS;
+ }
+
+ ///
+ /// Check Processor Trace output scheme: Single Range output or ToPA table
+ ///
+
+ //
+ // Single Range output scheme
+ //
+ if (ProcTraceData->ProcessorData[ProcessorNumber].SingleRangeSupported &&
+ (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeSingleRange)) {
+ if (FirstIn) {
+ DEBUG ((DEBUG_INFO, "ProcTrace: Enabling Single Range Output scheme \n"));
+ }
+
+ //
+ // Clear MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
+ //
+ CtrlReg.Bits.ToPA = 0;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_CTL,
+ CtrlReg.Uint64
+ );
+
+ //
+ // Program MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with the allocated Memory Region
+ //
+ OutputBaseReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64;
+ OutputBaseReg.Bits.Base = (MemRegionBaseAddr >> 7) & 0x01FFFFFF;
+ OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64) MemRegionBaseAddr, 32) & 0xFFFFFFFF;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_OUTPUT_BASE,
+ OutputBaseReg.Uint64
+ );
+
+ //
+ // Program the Mask bits for the Memory Region to MSR IA32_RTIT_OUTPUT_MASK_PTRS (561h)
+ //
+ OutputMaskPtrsReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64;
+ OutputMaskPtrsReg.Bits.MaskOrTableOffset = ((MemRegionSize - 1) >> 7) & 0x01FFFFFF;
+ OutputMaskPtrsReg.Bits.OutputOffset = RShiftU64 (MemRegionSize - 1, 32) & 0xFFFFFFFF;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
+ OutputMaskPtrsReg.Uint64
+ );
+ }
+
+ //
+ // ToPA(Table of physical address) scheme
+ //
+ if (ProcTraceData->ProcessorData[ProcessorNumber].TopaSupported &&
+ (ProcTraceData->ProcTraceOutputScheme == RtitOutputSchemeToPA)) {
+ //
+ // Create ToPA structure aligned at 4KB for each logical thread
+ // with at least 2 entries by 8 bytes size each. The first entry
+ // should have the trace output base address in bits 47:12, 6:9
+ // for Size, bits 4,2 and 0 must be cleared. The second entry
+ // should have the base address of the table location in bits
+ // 47:12, bits 4 and 2 must be cleared and bit 0 must be set.
+ //
+ if (FirstIn) {
+ DEBUG ((DEBUG_INFO, "ProcTrace: Enabling ToPA scheme \n"));
+ //
+ // Let BSP allocate ToPA table mem for all threads
+ //
+ TopaMemArray = (UINTN *) AllocatePool (ProcTraceData->AllocatedThreads * sizeof (UINTN *));
+ if (TopaMemArray == NULL) {
+ DEBUG ((DEBUG_ERROR, "ProcTrace: Allocate mem for ToPA Failed\n"));
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ ProcTraceData->TopaMemArray = TopaMemArray;
+
+ for (Index = 0; Index < ProcTraceData->AllocatedThreads; Index++) {
+ Pages = EFI_SIZE_TO_PAGES (sizeof (PROC_TRACE_TOPA_TABLE));
+ Alignment = 0x1000;
+ AlignedAddress = (UINTN) AllocateAlignedReservedPages (Pages, Alignment);
+ if (AlignedAddress == 0) {
+ if (Index < ProcTraceData->AllocatedThreads) {
+ ProcTraceData->AllocatedThreads = Index;
+ }
+ DEBUG ((DEBUG_ERROR, "ProcTrace: Out of mem, allocated ToPA mem only for %d threads\n", ProcTraceData->AllocatedThreads));
+ if (Index == 0) {
+ //
+ // Could not allocate for BSP even
+ //
+ FreePool ((VOID *) TopaMemArray);
+ TopaMemArray = NULL;
+ return RETURN_OUT_OF_RESOURCES;
+ }
+ break;
+ }
+
+ TopaMemArray[Index] = AlignedAddress;
+ DEBUG ((DEBUG_INFO, "ProcTrace: Topa table address(aligned) for thread %d is 0x%llX \n", Index, (UINT64) TopaMemArray[Index]));
+ }
+
+ DEBUG ((DEBUG_INFO, "ProcTrace: Allocated ToPA mem for %d thread \n", ProcTraceData->AllocatedThreads));
+ }
+
+ if (ProcessorNumber < ProcTraceData->AllocatedThreads) {
+ TopaTableBaseAddr = ProcTraceData->TopaMemArray[ProcessorNumber];
+ } else {
+ return RETURN_SUCCESS;
+ }
+
+ TopaTable = (PROC_TRACE_TOPA_TABLE *) TopaTableBaseAddr;
+ TopaEntryPtr = &TopaTable->TopaEntry[0];
+ TopaEntryPtr->Uint64 = 0;
+ TopaEntryPtr->Bits.Base = (MemRegionBaseAddr >> 12) & 0x000FFFFF;
+ TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64) MemRegionBaseAddr, 32) & 0xFFFFFFFF;
+ TopaEntryPtr->Bits.Size = ProcTraceData->ProcTraceMemSize;
+ TopaEntryPtr->Bits.END = 0;
+
+ TopaEntryPtr = &TopaTable->TopaEntry[1];
+ TopaEntryPtr->Uint64 = 0;
+ TopaEntryPtr->Bits.Base = (TopaTableBaseAddr >> 12) & 0x000FFFFF;
+ TopaEntryPtr->Bits.BaseHi = RShiftU64 ((UINT64) TopaTableBaseAddr, 32) & 0xFFFFFFFF;
+ TopaEntryPtr->Bits.END = 1;
+
+ //
+ // Program the MSR IA32_RTIT_OUTPUT_BASE (0x560) bits[63:7] with ToPA base
+ //
+ OutputBaseReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputBase.Uint64;
+ OutputBaseReg.Bits.Base = (TopaTableBaseAddr >> 7) & 0x01FFFFFF;
+ OutputBaseReg.Bits.BaseHi = RShiftU64 ((UINT64) TopaTableBaseAddr, 32) & 0xFFFFFFFF;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_OUTPUT_BASE,
+ OutputBaseReg.Uint64
+ );
+
+ //
+ // Set the MSR IA32_RTIT_OUTPUT_MASK (0x561) bits[63:7] to 0
+ //
+ OutputMaskPtrsReg.Uint64 = ProcTraceData->ProcessorData[ProcessorNumber].RtitOutputMaskPtrs.Uint64;
+ OutputMaskPtrsReg.Bits.MaskOrTableOffset = 0;
+ OutputMaskPtrsReg.Bits.OutputOffset = 0;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_OUTPUT_MASK_PTRS,
+ OutputMaskPtrsReg.Uint64
+ );
+ //
+ // Enable ToPA output scheme by enabling MSR IA32_RTIT_CTL (0x570) ToPA (Bit 8)
+ //
+ CtrlReg.Bits.ToPA = 1;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_CTL,
+ CtrlReg.Uint64
+ );
+ }
+
+ ///
+ /// Enable the Processor Trace feature from MSR IA32_RTIT_CTL (570h)
+ ///
+ CtrlReg.Bits.OS = 1;
+ CtrlReg.Bits.User = 1;
+ CtrlReg.Bits.BranchEn = 1;
+ CtrlReg.Bits.TraceEn = 1;
+ CPU_REGISTER_TABLE_WRITE64 (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_RTIT_CTL,
+ CtrlReg.Uint64
+ );
+
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/X2Apic.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/X2Apic.c
new file mode 100644
index 00000000..e0ca6b9e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuCommonFeaturesLib/X2Apic.c
@@ -0,0 +1,137 @@
+/** @file
+ X2Apic feature.
+
+ Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuCommonFeatures.h"
+
+/**
+ Prepares for the data used by CPU feature detection and initialization.
+
+ @param[in] NumberOfProcessors The number of CPUs in the platform.
+
+ @return Pointer to a buffer of CPU related configuration data.
+
+ @note This service could be called by BSP only.
+**/
+VOID *
+EFIAPI
+X2ApicGetConfigData (
+ IN UINTN NumberOfProcessors
+ )
+{
+ BOOLEAN *ConfigData;
+
+ ConfigData = AllocateZeroPool (sizeof (BOOLEAN) * NumberOfProcessors);
+ ASSERT (ConfigData != NULL);
+ return ConfigData;
+}
+
+/**
+ Detects if X2Apci feature supported on current processor.
+
+ Detect if X2Apci has been already enabled.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+
+ @retval TRUE X2Apci feature is supported.
+ @retval FALSE X2Apci feature is not supported.
+
+ @note This service could be called by BSP/APs.
+**/
+BOOLEAN
+EFIAPI
+X2ApicSupport (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData OPTIONAL
+ )
+{
+ BOOLEAN *X2ApicEnabled;
+
+ ASSERT (ConfigData != NULL);
+ X2ApicEnabled = (BOOLEAN *) ConfigData;
+ //
+ // *ConfigData indicates if X2APIC enabled on current processor
+ //
+ X2ApicEnabled[ProcessorNumber] = (GetApicMode () == LOCAL_APIC_MODE_X2APIC) ? TRUE : FALSE;
+
+ return (CpuInfo->CpuIdVersionInfoEcx.Bits.x2APIC == 1);
+}
+
+/**
+ Initializes X2Apci feature to specific state.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+ @param[in] CpuInfo A pointer to the REGISTER_CPU_FEATURE_INFORMATION
+ structure for the CPU executing this function.
+ @param[in] ConfigData A pointer to the configuration buffer returned
+ by CPU_FEATURE_GET_CONFIG_DATA. NULL if
+ CPU_FEATURE_GET_CONFIG_DATA was not provided in
+ RegisterCpuFeature().
+ @param[in] State If TRUE, then the X2Apci feature must be enabled.
+ If FALSE, then the X2Apci feature must be disabled.
+
+ @retval RETURN_SUCCESS X2Apci feature is initialized.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+X2ApicInitialize (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_CPU_FEATURE_INFORMATION *CpuInfo,
+ IN VOID *ConfigData, OPTIONAL
+ IN BOOLEAN State
+ )
+{
+ BOOLEAN *X2ApicEnabled;
+
+ //
+ // The scope of the MSR_IA32_APIC_BASE is core for below processor type, only program
+ // MSR_IA32_APIC_BASE for thread 0 in each core.
+ //
+ if (IS_SILVERMONT_PROCESSOR (CpuInfo->DisplayFamily, CpuInfo->DisplayModel)) {
+ if (CpuInfo->ProcessorInfo.Location.Thread != 0) {
+ return RETURN_SUCCESS;
+ }
+ }
+
+ ASSERT (ConfigData != NULL);
+ X2ApicEnabled = (BOOLEAN *) ConfigData;
+ if (X2ApicEnabled[ProcessorNumber]) {
+ PRE_SMM_CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_APIC_BASE,
+ MSR_IA32_APIC_BASE_REGISTER,
+ Bits.EXTD,
+ 1
+ );
+ } else {
+ //
+ // Enable X2APIC mode only if X2APIC is not enabled,
+ // Needn't to disabe X2APIC mode again if X2APIC is not enabled
+ //
+ if (State) {
+ CPU_REGISTER_TABLE_WRITE_FIELD (
+ ProcessorNumber,
+ Msr,
+ MSR_IA32_APIC_BASE,
+ MSR_IA32_APIC_BASE_REGISTER,
+ Bits.EXTD,
+ 1
+ );
+ }
+ }
+ return RETURN_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
new file mode 100644
index 00000000..82823bb6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.c
@@ -0,0 +1,183 @@
+/** @file
+ CPU Exception Handler Library common functions.
+
+ Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuExceptionCommon.h"
+
+//
+// Error code flag indicating whether or not an error code will be
+// pushed on the stack if an exception occurs.
+//
+// 1 means an error code will be pushed, otherwise 0
+//
+CONST UINT32 mErrorCodeFlag = 0x20227d00;
+
+//
+// Define the maximum message length
+//
+#define MAX_DEBUG_MESSAGE_LENGTH 0x100
+
+CONST CHAR8 mExceptionReservedStr[] = "Reserved";
+CONST CHAR8 *mExceptionNameStr[] = {
+ "#DE - Divide Error",
+ "#DB - Debug",
+ "NMI Interrupt",
+ "#BP - Breakpoint",
+ "#OF - Overflow",
+ "#BR - BOUND Range Exceeded",
+ "#UD - Invalid Opcode",
+ "#NM - Device Not Available",
+ "#DF - Double Fault",
+ "Coprocessor Segment Overrun",
+ "#TS - Invalid TSS",
+ "#NP - Segment Not Present",
+ "#SS - Stack Fault Fault",
+ "#GP - General Protection",
+ "#PF - Page-Fault",
+ "Reserved",
+ "#MF - x87 FPU Floating-Point Error",
+ "#AC - Alignment Check",
+ "#MC - Machine-Check",
+ "#XM - SIMD floating-point",
+ "#VE - Virtualization",
+ "#CP - Control Protection",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "Reserved",
+ "#VC - VMM Communication",
+};
+
+#define EXCEPTION_KNOWN_NAME_NUM (sizeof (mExceptionNameStr) / sizeof (CHAR8 *))
+
+/**
+ Get ASCII format string exception name by exception type.
+
+ @param ExceptionType Exception type.
+
+ @return ASCII format string exception name.
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ )
+{
+ if ((UINTN) ExceptionType < EXCEPTION_KNOWN_NAME_NUM) {
+ return mExceptionNameStr[ExceptionType];
+ } else {
+ return mExceptionReservedStr;
+ }
+}
+
+/**
+ Prints a message to the serial port.
+
+ @param Format Format string for the message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ CHAR8 Buffer[MAX_DEBUG_MESSAGE_LENGTH];
+ VA_LIST Marker;
+
+ //
+ // Convert the message to an ASCII String
+ //
+ VA_START (Marker, Format);
+ AsciiVSPrint (Buffer, sizeof (Buffer), Format, Marker);
+ VA_END (Marker);
+
+ //
+ // Send the print string to a Serial Port
+ //
+ SerialPortWrite ((UINT8 *)Buffer, AsciiStrLen (Buffer));
+}
+
+/**
+ Find and display image base address and return image base and its entry point.
+
+ @param CurrentEip Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+ IN UINTN CurrentEip
+ )
+{
+ EFI_STATUS Status;
+ UINTN Pe32Data;
+ VOID *PdbPointer;
+ VOID *EntryPoint;
+
+ Pe32Data = PeCoffSearchImageBase (CurrentEip);
+ if (Pe32Data == 0) {
+ InternalPrintMessage ("!!!! Can't find image information. !!!!\n");
+ } else {
+ //
+ // Find Image Base entry point
+ //
+ Status = PeCoffLoaderGetEntryPoint ((VOID *) Pe32Data, &EntryPoint);
+ if (EFI_ERROR (Status)) {
+ EntryPoint = NULL;
+ }
+ InternalPrintMessage ("!!!! Find image based on IP(0x%x) ", CurrentEip);
+ PdbPointer = PeCoffLoaderGetPdbPointer ((VOID *) Pe32Data);
+ if (PdbPointer != NULL) {
+ InternalPrintMessage ("%a", PdbPointer);
+ } else {
+ InternalPrintMessage ("(No PDB) " );
+ }
+ InternalPrintMessage (
+ " (ImageBase=%016lp, EntryPoint=%016p) !!!!\n",
+ (VOID *) Pe32Data,
+ EntryPoint
+ );
+ }
+}
+
+/**
+ Read and save reserved vector information
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[out] ReservedVector Pointer to reserved vector data buffer.
+ @param[in] VectorCount Vector number to be updated.
+
+ @return EFI_SUCCESS Read and save vector info successfully.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+
+**/
+EFI_STATUS
+ReadAndVerifyVectorInfo (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo,
+ OUT RESERVED_VECTORS_DATA *ReservedVector,
+ IN UINTN VectorCount
+ )
+{
+ while (VectorInfo->Attribute != EFI_VECTOR_HANDOFF_LAST_ENTRY) {
+ if (VectorInfo->Attribute > EFI_VECTOR_HANDOFF_HOOK_AFTER) {
+ //
+ // If vector attrubute is invalid
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ if (VectorInfo->VectorNumber < VectorCount) {
+ ReservedVector[VectorInfo->VectorNumber].Attribute = VectorInfo->Attribute;
+ }
+ VectorInfo ++;
+ }
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
new file mode 100644
index 00000000..800a2abf
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/CpuExceptionCommon.h
@@ -0,0 +1,321 @@
+/** @file
+ Common header file for CPU Exception Handler Library.
+
+ Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _CPU_EXCEPTION_COMMON_H_
+#define _CPU_EXCEPTION_COMMON_H_
+
+#include <Ppi/VectorHandoffInfo.h>
+#include <Protocol/Cpu.h>
+#include <Library/BaseLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/PrintLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/CpuExceptionHandlerLib.h>
+
+#define CPU_EXCEPTION_NUM 32
+#define CPU_INTERRUPT_NUM 256
+#define HOOKAFTER_STUB_SIZE 16
+
+//
+// Exception Error Code of Page-Fault Exception
+//
+#define IA32_PF_EC_P BIT0
+#define IA32_PF_EC_WR BIT1
+#define IA32_PF_EC_US BIT2
+#define IA32_PF_EC_RSVD BIT3
+#define IA32_PF_EC_ID BIT4
+#define IA32_PF_EC_PK BIT5
+#define IA32_PF_EC_SS BIT6
+#define IA32_PF_EC_SGX BIT15
+
+#include "ArchInterruptDefs.h"
+
+#define CPU_STACK_SWITCH_EXCEPTION_NUMBER \
+ FixedPcdGetSize (PcdCpuStackSwitchExceptionList)
+
+#define CPU_STACK_SWITCH_EXCEPTION_LIST \
+ FixedPcdGetPtr (PcdCpuStackSwitchExceptionList)
+
+#define CPU_KNOWN_GOOD_STACK_SIZE \
+ FixedPcdGet32 (PcdCpuKnownGoodStackSize)
+
+#define CPU_TSS_GDT_SIZE (SIZE_2KB + CPU_TSS_DESC_SIZE + CPU_TSS_SIZE)
+
+//
+// Record exception handler information
+//
+typedef struct {
+ UINTN ExceptionStart;
+ UINTN ExceptionStubHeaderSize;
+ UINTN HookAfterStubHeaderStart;
+} EXCEPTION_HANDLER_TEMPLATE_MAP;
+
+typedef struct {
+ UINTN IdtEntryCount;
+ SPIN_LOCK DisplayMessageSpinLock;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
+} EXCEPTION_HANDLER_DATA;
+
+extern CONST UINT32 mErrorCodeFlag;
+extern CONST UINTN mDoFarReturnFlag;
+
+/**
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param AddressMap Pointer to a buffer where the address map is returned.
+**/
+VOID
+EFIAPI
+AsmGetTemplateAddressMap (
+ OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
+ );
+
+/**
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
+
+**/
+VOID
+ArchUpdateIdtEntry (
+ OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
+ );
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ );
+
+/**
+ Prints a message to the serial port.
+
+ @param Format Format string for the message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+InternalPrintMessage (
+ IN CONST CHAR8 *Format,
+ ...
+ );
+
+/**
+ Find and display image base address and return image base and its entry point.
+
+ @param CurrentEip Current instruction pointer.
+
+**/
+VOID
+DumpModuleImageInfo (
+ IN UINTN CurrentEip
+ );
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+DumpImageAndCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ );
+
+/**
+ Internal worker function to initialize exception handler.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in, out] ExceptionHandlerData Pointer to exception handler data.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+InitializeCpuExceptionHandlersWorker (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+RegisterCpuInterruptHandlerWorker (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Internal worker function to update IDT entries accordling to vector attributes.
+
+ @param[in] IdtTable Pointer to IDT table.
+ @param[in] TemplateMap Pointer to a buffer where the address map is
+ returned.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+
+**/
+VOID
+UpdateIdtTable (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
+ IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchRestoreExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Fix up the vector number and function address in the vector code.
+
+ @param[in] NewVectorAddr New vector handler address.
+ @param[in] VectorNum Index of vector.
+ @param[in] OldVectorAddr Old vector handler address.
+
+**/
+VOID
+EFIAPI
+AsmVectorNumFixup (
+ IN VOID *NewVectorAddr,
+ IN UINT8 VectorNum,
+ IN VOID *OldVectorAddr
+ );
+
+/**
+ Read and save reserved vector information
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[out] ReservedVector Pointer to reserved vector data buffer.
+ @param[in] VectorCount Vector number to be updated.
+
+ @return EFI_SUCCESS Read and save vector info successfully.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+
+**/
+EFI_STATUS
+ReadAndVerifyVectorInfo (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo,
+ OUT RESERVED_VECTORS_DATA *ReservedVector,
+ IN UINTN VectorCount
+ );
+
+/**
+ Get ASCII format string exception name by exception type.
+
+ @param ExceptionType Exception type.
+
+ @return ASCII format string exception name.
+**/
+CONST CHAR8 *
+GetExceptionNameStr (
+ IN EFI_EXCEPTION_TYPE ExceptionType
+ );
+
+/**
+ Internal worker function for common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+CommonExceptionHandlerWorker (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ );
+
+/**
+ Setup separate stack for specific exceptions.
+
+ @param[in] StackSwitchData Pointer to data required for setuping up
+ stack switch.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized with new stack.
+ @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
+**/
+EFI_STATUS
+ArchSetupExceptionStack (
+ IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
+ );
+
+/**
+ Return address map of exception handler template so that C code can generate
+ exception tables. The template is only for exceptions using task gate instead
+ of interrupt gate.
+
+ @param AddressMap Pointer to a buffer where the address map is returned.
+**/
+VOID
+EFIAPI
+AsmGetTssTemplateMap (
+ OUT EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
new file mode 100644
index 00000000..42cc04ea
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.inf
@@ -0,0 +1,63 @@
+## @file
+# CPU Exception Handler library instance for DXE modules.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCpuExceptionHandlerLib
+ MODULE_UNI_FILE = DxeCpuExceptionHandlerLib.uni
+ FILE_GUID = B6E9835A-EDCF-4748-98A8-27D3C722E02D
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_CORE DXE_DRIVER UEFI_APPLICATION
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.nasm
+ Ia32/ExceptionTssEntryAsm.nasm
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/Xcode5ExceptionHandlerAsm.nasm
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ PeiDxeSmmCpuException.c
+ DxeException.c
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuStackSwitchExceptionList
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuKnownGoodStackSize
+
+[FeaturePcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ SynchronizationLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ MemoryAllocationLib
+ DebugLib
+ VmgExitLib
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
new file mode 100644
index 00000000..e1850eee
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeCpuExceptionHandlerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// CPU Exception Handler library instance for DXE modules.
+//
+// CPU Exception Handler library instance for DXE modules.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for DXE modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for DXE modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
new file mode 100644
index 00000000..f27f005b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/DxeException.c
@@ -0,0 +1,287 @@
+/** @file
+ CPU exception handler library implemenation for DXE modules.
+
+ Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include "CpuExceptionCommon.h"
+#include <Library/DebugLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+CONST UINTN mDoFarReturnFlag = 0;
+
+RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];
+EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];
+UINTN mEnabledInterruptNum = 0;
+
+EXCEPTION_HANDLER_DATA mExceptionHandlerData;
+
+UINT8 mNewStack[CPU_STACK_SWITCH_EXCEPTION_NUMBER *
+ CPU_KNOWN_GOOD_STACK_SIZE];
+UINT8 mNewGdt[CPU_TSS_GDT_SIZE];
+
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CommonExceptionHandlerWorker (ExceptionType, SystemContext, &mExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ mExceptionHandlerData.ReservedVectors = mReservedVectorsData;
+ mExceptionHandlerData.ExternalInterruptHandler = mExternalInterruptHandlerTable;
+ InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);
+ return InitializeCpuExceptionHandlersWorker (VectorInfo, &mExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ UINTN Index;
+ UINTN InterruptEntry;
+ UINT8 *InterruptEntryCode;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesCode,
+ sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM,
+ (VOID **)&ReservedVectors
+ );
+ ASSERT (!EFI_ERROR (Status) && ReservedVectors != NULL);
+ SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_INTERRUPT_NUM, 0xff);
+ if (VectorInfo != NULL) {
+ Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_INTERRUPT_NUM);
+ if (EFI_ERROR (Status)) {
+ FreePool (ReservedVectors);
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ ExternalInterruptHandler = AllocateZeroPool (sizeof (EFI_CPU_INTERRUPT_HANDLER) * CPU_INTERRUPT_NUM);
+ ASSERT (ExternalInterruptHandler != NULL);
+
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_INTERRUPT_NUM) {
+ IdtEntryCount = CPU_INTERRUPT_NUM;
+ }
+ //
+ // Create Interrupt Descriptor Table and Copy the old IDT table in
+ //
+ IdtTable = AllocateZeroPool (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM);
+ ASSERT (IdtTable != NULL);
+ CopyMem (IdtTable, (VOID *)IdtDescriptor.Base, sizeof (IA32_IDT_GATE_DESCRIPTOR) * IdtEntryCount);
+
+ AsmGetTemplateAddressMap (&TemplateMap);
+ ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesCode,
+ TemplateMap.ExceptionStubHeaderSize * CPU_INTERRUPT_NUM,
+ (VOID **)&InterruptEntryCode
+ );
+ ASSERT (!EFI_ERROR (Status) && InterruptEntryCode != NULL);
+
+ InterruptEntry = (UINTN) InterruptEntryCode;
+ for (Index = 0; Index < CPU_INTERRUPT_NUM; Index ++) {
+ CopyMem (
+ (VOID *) InterruptEntry,
+ (VOID *) TemplateMap.ExceptionStart,
+ TemplateMap.ExceptionStubHeaderSize
+ );
+ AsmVectorNumFixup ((VOID *) InterruptEntry, (UINT8) Index, (VOID *) TemplateMap.ExceptionStart);
+ InterruptEntry += TemplateMap.ExceptionStubHeaderSize;
+ }
+
+ TemplateMap.ExceptionStart = (UINTN) InterruptEntryCode;
+ mExceptionHandlerData.IdtEntryCount = CPU_INTERRUPT_NUM;
+ mExceptionHandlerData.ReservedVectors = ReservedVectors;
+ mExceptionHandlerData.ExternalInterruptHandler = ExternalInterruptHandler;
+ InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);
+
+ UpdateIdtTable (IdtTable, &TemplateMap, &mExceptionHandlerData);
+
+ //
+ // Load Interrupt Descriptor Table
+ //
+ IdtDescriptor.Base = (UINTN) IdtTable;
+ IdtDescriptor.Limit = (UINT16) (sizeof (IA32_IDT_GATE_DESCRIPTOR) * CPU_INTERRUPT_NUM - 1);
+ AsmWriteIdtr ((IA32_DESCRIPTOR *) &IdtDescriptor);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler, &mExceptionHandlerData);
+}
+
+/**
+ Initializes CPU exceptions entries and setup stack switch for given exceptions.
+
+ This method will call InitializeCpuExceptionHandlers() to setup default
+ exception handlers unless indicated not to do it explicitly.
+
+ If InitData is passed with NULL, this method will use the resource reserved
+ by global variables to initialize it; Otherwise it will use data in InitData
+ to setup stack switch. This is for the different use cases in DxeCore and
+ Cpu MP exception initialization.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data required to setup stack switch for
+ given exceptions.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_EXCEPTION_INIT_DATA EssData;
+ IA32_DESCRIPTOR Idtr;
+ IA32_DESCRIPTOR Gdtr;
+
+ //
+ // To avoid repeat initialization of default handlers, the caller should pass
+ // an extended init data with InitDefaultHandlers set to FALSE. There's no
+ // need to call this method to just initialize default handlers. Call non-ex
+ // version instead; or this method must be implemented as a simple wrapper of
+ // non-ex version of it, if this version has to be called.
+ //
+ if (InitData == NULL || InitData->X64.InitDefaultHandlers) {
+ Status = InitializeCpuExceptionHandlers (VectorInfo);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Initializing stack switch is only necessary for Stack Guard functionality.
+ //
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ if (InitData == NULL) {
+ SetMem (mNewGdt, sizeof (mNewGdt), 0);
+
+ AsmReadIdtr (&Idtr);
+ AsmReadGdtr (&Gdtr);
+
+ EssData.X64.Revision = CPU_EXCEPTION_INIT_DATA_REV;
+ EssData.X64.KnownGoodStackTop = (UINTN)mNewStack + sizeof (mNewStack);
+ EssData.X64.KnownGoodStackSize = CPU_KNOWN_GOOD_STACK_SIZE;
+ EssData.X64.StackSwitchExceptions = CPU_STACK_SWITCH_EXCEPTION_LIST;
+ EssData.X64.StackSwitchExceptionNumber = CPU_STACK_SWITCH_EXCEPTION_NUMBER;
+ EssData.X64.IdtTable = (VOID *)Idtr.Base;
+ EssData.X64.IdtTableSize = Idtr.Limit + 1;
+ EssData.X64.GdtTable = mNewGdt;
+ EssData.X64.GdtTableSize = sizeof (mNewGdt);
+ EssData.X64.ExceptionTssDesc = mNewGdt + Gdtr.Limit + 1;
+ EssData.X64.ExceptionTssDescSize = CPU_TSS_DESC_SIZE;
+ EssData.X64.ExceptionTss = mNewGdt + Gdtr.Limit + 1 + CPU_TSS_DESC_SIZE;
+ EssData.X64.ExceptionTssSize = CPU_TSS_SIZE;
+
+ InitData = &EssData;
+ }
+ Status = ArchSetupExceptionStack (InitData);
+ }
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
new file mode 100644
index 00000000..2662551d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchExceptionHandler.c
@@ -0,0 +1,427 @@
+/** @file
+ IA32 CPU Exception Handler functons.
+
+ Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuExceptionCommon.h"
+
+/**
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
+
+**/
+VOID
+ArchUpdateIdtEntry (
+ OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
+ )
+{
+ IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ return (UINTN)IdtEntry->Bits.OffsetLow + (((UINTN)IdtEntry->Bits.OffsetHigh) << 16);
+}
+
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ IA32_EFLAGS32 Eflags;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ //
+ // Save Exception context in global variable in first entry of the exception handler.
+ // So when original exception handler returns to the new exception handler (second entry),
+ // the Eflags/Cs/Eip/ExceptionData can be used.
+ //
+ ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextIa32->Eflags;
+ ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextIa32->Cs;
+ ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextIa32->Eip;
+ ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextIa32->ExceptionData;
+ //
+ // Clear IF flag to avoid old IDT handler enable interrupt by IRET
+ //
+ Eflags.UintN = SystemContext.SystemContextIa32->Eflags;
+ Eflags.Bits.IF = 0;
+ SystemContext.SystemContextIa32->Eflags = Eflags.UintN;
+ //
+ // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
+ //
+ SystemContext.SystemContextIa32->Eip = (UINTN) ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
+}
+
+/**
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchRestoreExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ SystemContext.SystemContextIa32->Eflags = ReservedVectors[ExceptionType].OldFlags;
+ SystemContext.SystemContextIa32->Cs = ReservedVectors[ExceptionType].OldCs;
+ SystemContext.SystemContextIa32->Eip = ReservedVectors[ExceptionType].OldIp;
+ SystemContext.SystemContextIa32->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;
+}
+
+/**
+ Setup separate stack for given exceptions.
+
+ @param[in] StackSwitchData Pointer to data required for setuping up
+ stack switch.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized with new stack.
+ @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
+
+**/
+EFI_STATUS
+ArchSetupExceptionStack (
+ IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
+ )
+{
+ IA32_DESCRIPTOR Gdtr;
+ IA32_DESCRIPTOR Idtr;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ IA32_TSS_DESCRIPTOR *TssDesc;
+ IA32_TASK_STATE_SEGMENT *Tss;
+ UINTN StackTop;
+ UINTN Index;
+ UINTN Vector;
+ UINTN TssBase;
+ UINTN GdtSize;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+
+ if (StackSwitchData == NULL ||
+ StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV ||
+ StackSwitchData->Ia32.KnownGoodStackTop == 0 ||
+ StackSwitchData->Ia32.KnownGoodStackSize == 0 ||
+ StackSwitchData->Ia32.StackSwitchExceptions == NULL ||
+ StackSwitchData->Ia32.StackSwitchExceptionNumber == 0 ||
+ StackSwitchData->Ia32.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM ||
+ StackSwitchData->Ia32.GdtTable == NULL ||
+ StackSwitchData->Ia32.IdtTable == NULL ||
+ StackSwitchData->Ia32.ExceptionTssDesc == NULL ||
+ StackSwitchData->Ia32.ExceptionTss == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The caller is responsible for that the GDT table, no matter the existing
+ // one or newly allocated, has enough space to hold descriptors for exception
+ // task-state segments.
+ //
+ if (((UINTN)StackSwitchData->Ia32.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc < (UINTN)(StackSwitchData->Ia32.GdtTable)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINTN)StackSwitchData->Ia32.ExceptionTssDesc + StackSwitchData->Ia32.ExceptionTssDescSize >
+ ((UINTN)(StackSwitchData->Ia32.GdtTable) + StackSwitchData->Ia32.GdtTableSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // We need one descriptor and one TSS for current task and every exception
+ // specified.
+ //
+ if (StackSwitchData->Ia32.ExceptionTssDescSize <
+ sizeof (IA32_TSS_DESCRIPTOR) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StackSwitchData->Ia32.ExceptionTssSize <
+ sizeof (IA32_TASK_STATE_SEGMENT) * (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TssDesc = StackSwitchData->Ia32.ExceptionTssDesc;
+ Tss = StackSwitchData->Ia32.ExceptionTss;
+
+ //
+ // Initialize new GDT table and/or IDT table, if any
+ //
+ AsmReadIdtr (&Idtr);
+ AsmReadGdtr (&Gdtr);
+
+ GdtSize = (UINTN)TssDesc +
+ sizeof (IA32_TSS_DESCRIPTOR) *
+ (StackSwitchData->Ia32.StackSwitchExceptionNumber + 1) -
+ (UINTN)(StackSwitchData->Ia32.GdtTable);
+ if ((UINTN)StackSwitchData->Ia32.GdtTable != Gdtr.Base) {
+ CopyMem (StackSwitchData->Ia32.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
+ Gdtr.Base = (UINTN)StackSwitchData->Ia32.GdtTable;
+ Gdtr.Limit = (UINT16)GdtSize - 1;
+ }
+
+ if ((UINTN)StackSwitchData->Ia32.IdtTable != Idtr.Base) {
+ Idtr.Base = (UINTN)StackSwitchData->Ia32.IdtTable;
+ }
+ if (StackSwitchData->Ia32.IdtTableSize > 0) {
+ Idtr.Limit = (UINT16)(StackSwitchData->Ia32.IdtTableSize - 1);
+ }
+
+ //
+ // Fixup current task descriptor. Task-state segment for current task will
+ // be filled by processor during task switching.
+ //
+ TssBase = (UINTN)Tss;
+
+ TssDesc->Uint64 = 0;
+ TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
+ TssDesc->Bits.BaseLow = (UINT16)TssBase;
+ TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
+ TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
+ TssDesc->Bits.P = 1;
+ TssDesc->Bits.LimitHigh = 0;
+ TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+
+ //
+ // Fixup exception task descriptor and task-state segment
+ //
+ AsmGetTssTemplateMap (&TemplateMap);
+ StackTop = StackSwitchData->Ia32.KnownGoodStackTop - CPU_STACK_ALIGNMENT;
+ StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
+ IdtTable = StackSwitchData->Ia32.IdtTable;
+ for (Index = 0; Index < StackSwitchData->Ia32.StackSwitchExceptionNumber; ++Index) {
+ TssDesc += 1;
+ Tss += 1;
+
+ //
+ // Fixup TSS descriptor
+ //
+ TssBase = (UINTN)Tss;
+
+ TssDesc->Uint64 = 0;
+ TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
+ TssDesc->Bits.BaseLow = (UINT16)TssBase;
+ TssDesc->Bits.BaseMid = (UINT8)(TssBase >> 16);
+ TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
+ TssDesc->Bits.P = 1;
+ TssDesc->Bits.LimitHigh = 0;
+ TssDesc->Bits.BaseHigh = (UINT8)(TssBase >> 24);
+
+ //
+ // Fixup TSS
+ //
+ Vector = StackSwitchData->Ia32.StackSwitchExceptions[Index];
+ if (Vector >= CPU_EXCEPTION_NUM ||
+ Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {
+ continue;
+ }
+
+ ZeroMem (Tss, sizeof (*Tss));
+ Tss->EIP = (UINT32)(TemplateMap.ExceptionStart
+ + Vector * TemplateMap.ExceptionStubHeaderSize);
+ Tss->EFLAGS = 0x2;
+ Tss->ESP = StackTop;
+ Tss->CR3 = AsmReadCr3 ();
+ Tss->ES = AsmReadEs ();
+ Tss->CS = AsmReadCs ();
+ Tss->SS = AsmReadSs ();
+ Tss->DS = AsmReadDs ();
+ Tss->FS = AsmReadFs ();
+ Tss->GS = AsmReadGs ();
+
+ StackTop -= StackSwitchData->Ia32.KnownGoodStackSize;
+
+ //
+ // Update IDT to use Task Gate for given exception
+ //
+ IdtTable[Vector].Bits.OffsetLow = 0;
+ IdtTable[Vector].Bits.Selector = (UINT16)((UINTN)TssDesc - Gdtr.Base);
+ IdtTable[Vector].Bits.Reserved_0 = 0;
+ IdtTable[Vector].Bits.GateType = IA32_IDT_GATE_TYPE_TASK;
+ IdtTable[Vector].Bits.OffsetHigh = 0;
+ }
+
+ //
+ // Publish GDT
+ //
+ AsmWriteGdtr (&Gdtr);
+
+ //
+ // Load current task
+ //
+ AsmWriteTr ((UINT16)((UINTN)StackSwitchData->Ia32.ExceptionTssDesc - Gdtr.Base));
+
+ //
+ // Publish IDT
+ //
+ AsmWriteIdtr (&Idtr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Display processor context.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Processor context to be display.
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ InternalPrintMessage (
+ "!!!! IA32 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
+ ExceptionType,
+ GetExceptionNameStr (ExceptionType),
+ GetApicId ()
+ );
+ if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
+ InternalPrintMessage (
+ "ExceptionData - %08x",
+ SystemContext.SystemContextIa32->ExceptionData
+ );
+ if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
+ InternalPrintMessage (
+ " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_RSVD) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_US) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_WR) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_P) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_PK) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SS) != 0,
+ (SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_SGX) != 0
+ );
+ }
+ InternalPrintMessage ("\n");
+ }
+ InternalPrintMessage (
+ "EIP - %08x, CS - %08x, EFLAGS - %08x\n",
+ SystemContext.SystemContextIa32->Eip,
+ SystemContext.SystemContextIa32->Cs,
+ SystemContext.SystemContextIa32->Eflags
+ );
+ InternalPrintMessage (
+ "EAX - %08x, ECX - %08x, EDX - %08x, EBX - %08x\n",
+ SystemContext.SystemContextIa32->Eax,
+ SystemContext.SystemContextIa32->Ecx,
+ SystemContext.SystemContextIa32->Edx,
+ SystemContext.SystemContextIa32->Ebx
+ );
+ InternalPrintMessage (
+ "ESP - %08x, EBP - %08x, ESI - %08x, EDI - %08x\n",
+ SystemContext.SystemContextIa32->Esp,
+ SystemContext.SystemContextIa32->Ebp,
+ SystemContext.SystemContextIa32->Esi,
+ SystemContext.SystemContextIa32->Edi
+ );
+ InternalPrintMessage (
+ "DS - %08x, ES - %08x, FS - %08x, GS - %08x, SS - %08x\n",
+ SystemContext.SystemContextIa32->Ds,
+ SystemContext.SystemContextIa32->Es,
+ SystemContext.SystemContextIa32->Fs,
+ SystemContext.SystemContextIa32->Gs,
+ SystemContext.SystemContextIa32->Ss
+ );
+ InternalPrintMessage (
+ "CR0 - %08x, CR2 - %08x, CR3 - %08x, CR4 - %08x\n",
+ SystemContext.SystemContextIa32->Cr0,
+ SystemContext.SystemContextIa32->Cr2,
+ SystemContext.SystemContextIa32->Cr3,
+ SystemContext.SystemContextIa32->Cr4
+ );
+ InternalPrintMessage (
+ "DR0 - %08x, DR1 - %08x, DR2 - %08x, DR3 - %08x\n",
+ SystemContext.SystemContextIa32->Dr0,
+ SystemContext.SystemContextIa32->Dr1,
+ SystemContext.SystemContextIa32->Dr2,
+ SystemContext.SystemContextIa32->Dr3
+ );
+ InternalPrintMessage (
+ "DR6 - %08x, DR7 - %08x\n",
+ SystemContext.SystemContextIa32->Dr6,
+ SystemContext.SystemContextIa32->Dr7
+ );
+ InternalPrintMessage (
+ "GDTR - %08x %08x, IDTR - %08x %08x\n",
+ SystemContext.SystemContextIa32->Gdtr[0],
+ SystemContext.SystemContextIa32->Gdtr[1],
+ SystemContext.SystemContextIa32->Idtr[0],
+ SystemContext.SystemContextIa32->Idtr[1]
+ );
+ InternalPrintMessage (
+ "LDTR - %08x, TR - %08x\n",
+ SystemContext.SystemContextIa32->Ldtr,
+ SystemContext.SystemContextIa32->Tr
+ );
+ InternalPrintMessage (
+ "FXSAVE_STATE - %08x\n",
+ &SystemContext.SystemContextIa32->FxSaveState
+ );
+}
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+DumpImageAndCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ DumpCpuContext (ExceptionType, SystemContext);
+ //
+ // Dump module image base and module entry point by EIP
+ //
+ if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
+ ((SystemContext.SystemContextIa32->ExceptionData & IA32_PF_EC_ID) != 0)) {
+ //
+ // The EIP in SystemContext could not be used
+ // if it is page fault with I/D set.
+ //
+ DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextIa32->Esp));
+ } else {
+ DumpModuleImageInfo (SystemContext.SystemContextIa32->Eip);
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h
new file mode 100644
index 00000000..6e8f1a0d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ArchInterruptDefs.h
@@ -0,0 +1,46 @@
+/** @file
+ Ia32 arch definition for CPU Exception Handler Library.
+
+ Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_
+#define _ARCH_CPU_INTERRUPT_DEFS_H_
+
+typedef struct {
+ EFI_SYSTEM_CONTEXT_IA32 SystemContext;
+ BOOLEAN ExceptionDataFlag;
+ UINTN OldIdtHandler;
+} EXCEPTION_HANDLER_CONTEXT;
+
+//
+// Register Structure Definitions
+//
+typedef struct {
+ EFI_STATUS_CODE_DATA Header;
+ EFI_SYSTEM_CONTEXT_IA32 SystemContext;
+} CPU_STATUS_CODE_TEMPLATE;
+
+typedef struct {
+ SPIN_LOCK SpinLock;
+ UINT32 ApicId;
+ UINT32 Attribute;
+ UINTN ExceptonHandler;
+ UINTN OldFlags;
+ UINTN OldCs;
+ UINTN OldIp;
+ UINTN ExceptionData;
+ UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE];
+} RESERVED_VECTORS_DATA;
+
+#define CPU_TSS_DESC_SIZE \
+ (sizeof (IA32_TSS_DESCRIPTOR) * \
+ (FixedPcdGetSize (PcdCpuStackSwitchExceptionList) + 1))
+
+#define CPU_TSS_SIZE \
+ (sizeof (IA32_TASK_STATE_SEGMENT) * \
+ (FixedPcdGetSize (PcdCpuStackSwitchExceptionList) + 1))
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
new file mode 100644
index 00000000..c2b92d53
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionHandlerAsm.nasm
@@ -0,0 +1,456 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ExceptionHandlerAsm.Asm
+;
+; Abstract:
+;
+; IA32 CPU Exception Handler
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+;
+; CommonExceptionHandler()
+;
+extern ASM_PFX(CommonExceptionHandler)
+
+SECTION .data
+
+extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
+extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
+
+SECTION .text
+
+ALIGN 8
+
+;
+; exception handler stub table
+;
+AsmIdtVectorBegin:
+%rep 32
+ db 0x6a ; push #VectorNum
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
+ push eax
+ mov eax, ASM_PFX(CommonInterruptEntry)
+ jmp eax
+%endrep
+AsmIdtVectorEnd:
+
+HookAfterStubBegin:
+ db 0x6a ; push
+VectorNum:
+ db 0 ; 0 will be fixed
+ push eax
+ mov eax, HookAfterStubHeaderEnd
+ jmp eax
+HookAfterStubHeaderEnd:
+ pop eax
+ sub esp, 8 ; reserve room for filling exception data later
+ push dword [esp + 8]
+ xchg ecx, [esp] ; get vector number
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jnc .0
+ push dword [esp] ; addition push if exception data needed
+.0:
+ xchg ecx, [esp] ; restore ecx
+ push eax
+
+;----------------------------------------------------------------------------;
+; CommonInterruptEntry ;
+;----------------------------------------------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+; Entry from each interrupt with a push eax and eax=interrupt number
+; Stack:
+; +---------------------+
+; + EFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + EIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + EBP +
+; +---------------------+ <-- EBP
+global ASM_PFX(CommonInterruptEntry)
+ASM_PFX(CommonInterruptEntry):
+ cli
+ pop eax
+ ;
+ ; All interrupt handlers are invoked through interrupt gates, so
+ ; IF flag automatically cleared at the entry point
+ ;
+
+ ;
+ ; Get vector number from top of stack
+ ;
+ xchg ecx, [esp]
+ and ecx, 0xFF ; Vector number should be less than 256
+ cmp ecx, 32 ; Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jc HasErrorCode
+
+NoErrorCode:
+
+ ;
+ ; Stack:
+ ; +---------------------+
+ ; + EFlags +
+ ; +---------------------+
+ ; + CS +
+ ; +---------------------+
+ ; + EIP +
+ ; +---------------------+
+ ; + ECX +
+ ; +---------------------+ <-- ESP
+ ;
+ ; Registers:
+ ; ECX - Vector Number
+ ;
+
+ ;
+ ; Put Vector Number on stack
+ ;
+ push ecx
+
+ ;
+ ; Put 0 (dummy) error code on stack, and restore ECX
+ ;
+ xor ecx, ecx ; ECX = 0
+ xchg ecx, [esp+4]
+
+ jmp ErrorCodeAndVectorOnStack
+
+HasErrorCode:
+
+ ;
+ ; Stack:
+ ; +---------------------+
+ ; + EFlags +
+ ; +---------------------+
+ ; + CS +
+ ; +---------------------+
+ ; + EIP +
+ ; +---------------------+
+ ; + Error Code +
+ ; +---------------------+
+ ; + ECX +
+ ; +---------------------+ <-- ESP
+ ;
+ ; Registers:
+ ; ECX - Vector Number
+ ;
+
+ ;
+ ; Put Vector Number on stack and restore ECX
+ ;
+ xchg ecx, [esp]
+
+ErrorCodeAndVectorOnStack:
+ push ebp
+ mov ebp, esp
+
+ ;
+ ; Stack:
+ ; +---------------------+
+ ; + EFlags +
+ ; +---------------------+
+ ; + CS +
+ ; +---------------------+
+ ; + EIP +
+ ; +---------------------+
+ ; + Error Code +
+ ; +---------------------+
+ ; + Vector Number +
+ ; +---------------------+
+ ; + EBP +
+ ; +---------------------+ <-- EBP
+ ;
+
+ ;
+ ; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+ ; is 16-byte aligned
+ ;
+ and esp, 0xfffffff0
+ sub esp, 12
+
+ sub esp, 8
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ push eax
+ push ecx
+ push edx
+ push ebx
+ lea ecx, [ebp + 6 * 4]
+ push ecx ; ESP
+ push dword [ebp] ; EBP
+ push esi
+ push edi
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ mov eax, ss
+ push eax
+ movzx eax, word [ebp + 4 * 4]
+ push eax
+ mov eax, ds
+ push eax
+ mov eax, es
+ push eax
+ mov eax, fs
+ push eax
+ mov eax, gs
+ push eax
+
+;; UINT32 Eip;
+ mov eax, [ebp + 3 * 4]
+ push eax
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0xFFFF
+ mov [esp+4], eax
+
+ sub esp, 8
+ sgdt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0xFFFF
+ mov [esp+4], eax
+
+;; UINT32 Ldtr, Tr;
+ xor eax, eax
+ str ax
+ push eax
+ sldt ax
+ push eax
+
+;; UINT32 EFlags;
+ mov eax, [ebp + 5 * 4]
+ push eax
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ mov eax, 1
+ push ebx ; temporarily save value of ebx on stack
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR and DE
+ ; are supported
+ pop ebx ; retore value of ebx that was overwritten by CPUID
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .1
+ or eax, BIT9 ; Set CR4.OSFXSR
+.1:
+ test edx, BIT2 ; Test for Debugging Extensions support
+ jz .2
+ or eax, BIT3 ; Set CR4.DE
+.2:
+ mov cr4, eax
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ xor eax, eax
+ push eax
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+ mov eax, dr6
+ push eax
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ sub esp, 512
+ mov edi, esp
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
+ ; edx still contains result from CPUID above
+ jz .3
+ db 0xf, 0xae, 0x7 ;fxsave [edi]
+.3:
+
+;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push dword [ebp + 2 * 4]
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx
+ mov edx, dword [ebp + 1 * 4]
+ push edx
+
+ ;
+ ; Call External Exception Handler
+ ;
+ mov eax, ASM_PFX(CommonExceptionHandler)
+ call eax
+ add esp, 8
+
+ cli
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov esi, esp
+ mov eax, 1
+ cpuid ; use CPUID to determine if FXSAVE/FXRESTOR
+ ; are supported
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .4
+ db 0xf, 0xae, 0xe ; fxrstor [esi]
+.4:
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add esp, 4 * 6
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; not for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov cr3, eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ pop dword [ebp + 5 * 4]
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop dword [ebp + 3 * 4]
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+ pop gs
+ pop fs
+ pop es
+ pop ds
+ pop dword [ebp + 4 * 4]
+ pop ss
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pop edi
+ pop esi
+ add esp, 4 ; not for ebp
+ add esp, 4 ; not for esp
+ pop ebx
+ pop edx
+ pop ecx
+ pop eax
+
+ pop dword [ebp - 8]
+ pop dword [ebp - 4]
+ mov esp, ebp
+ pop ebp
+ add esp, 8
+ cmp dword [esp - 16], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmp dword [esp - 20], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp dword [esp - 16]
+ErrorCode:
+ sub esp, 4
+ jmp dword [esp - 12]
+
+DoReturn:
+ cmp dword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
+ jz DoIret
+ push dword [esp + 8] ; save EFLAGS
+ add esp, 16
+ push dword [esp - 8] ; save CS in new location
+ push dword [esp - 8] ; save EIP in new location
+ push dword [esp - 8] ; save EFLAGS in new location
+ popfd ; restore EFLAGS
+ retf ; far return
+
+DoIret:
+ iretd
+
+;---------------------------------------;
+; _AsmGetTemplateAddressMap ;
+;----------------------------------------------------------------------------;
+;
+; Protocol prototype
+; AsmGetTemplateAddressMap (
+; EXCEPTION_HANDLER_TEMPLATE_MAP *AddressMap
+; );
+;
+; Routine Description:
+;
+; Return address map of interrupt handler template so that C code can generate
+; interrupt table.
+;
+; Arguments:
+;
+;
+; Returns:
+;
+; Nothing
+;
+;
+; Input: [ebp][0] = Original ebp
+; [ebp][4] = Return address
+;
+; Output: Nothing
+;
+; Destroys: Nothing
+;-----------------------------------------------------------------------------;
+global ASM_PFX(AsmGetTemplateAddressMap)
+ASM_PFX(AsmGetTemplateAddressMap):
+ push ebp ; C prolog
+ mov ebp, esp
+ pushad
+
+ mov ebx, dword [ebp + 0x8]
+ mov dword [ebx], AsmIdtVectorBegin
+ mov dword [ebx + 0x4], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+ mov dword [ebx + 0x8], HookAfterStubBegin
+
+ popad
+ pop ebp
+ ret
+
+;-------------------------------------------------------------------------------------
+; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmVectorNumFixup)
+ASM_PFX(AsmVectorNumFixup):
+ mov eax, dword [esp + 8]
+ mov ecx, [esp + 4]
+ mov [ecx + (VectorNum - HookAfterStubBegin)], al
+ ret
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
new file mode 100644
index 00000000..da2aa2ba
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Ia32/ExceptionTssEntryAsm.nasm
@@ -0,0 +1,390 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ExceptionTssEntryAsm.Asm
+;
+; Abstract:
+;
+; IA32 CPU Exception Handler with Separate Stack
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+;
+; IA32 TSS Memory Layout Description
+;
+struc IA32_TSS
+ resw 1
+ resw 1
+ .ESP0: resd 1
+ .SS0: resw 1
+ resw 1
+ .ESP1: resd 1
+ .SS1: resw 1
+ resw 1
+ .ESP2: resd 1
+ .SS2: resw 1
+ resw 1
+ ._CR3: resd 1
+ .EIP: resd 1
+ .EFLAGS: resd 1
+ ._EAX: resd 1
+ ._ECX: resd 1
+ ._EDX: resd 1
+ ._EBX: resd 1
+ ._ESP: resd 1
+ ._EBP: resd 1
+ ._ESI: resd 1
+ ._EDI: resd 1
+ ._ES: resw 1
+ resw 1
+ ._CS: resw 1
+ resw 1
+ ._SS: resw 1
+ resw 1
+ ._DS: resw 1
+ resw 1
+ ._FS: resw 1
+ resw 1
+ ._GS: resw 1
+ resw 1
+ .LDT: resw 1
+ resw 1
+ resw 1
+ resw 1
+endstruc
+
+;
+; CommonExceptionHandler()
+;
+extern ASM_PFX(CommonExceptionHandler)
+
+SECTION .data
+
+SECTION .text
+
+ALIGN 8
+
+;
+; Exception handler stub table
+;
+AsmExceptionEntryBegin:
+%assign Vector 0
+%rep 32
+
+DoIret%[Vector]:
+ iretd
+ASM_PFX(ExceptionTaskSwtichEntry%[Vector]):
+ db 0x6a ; push #VectorNum
+ db %[Vector]
+ mov eax, ASM_PFX(CommonTaskSwtichEntryPoint)
+ call eax
+ mov esp, eax ; Restore stack top
+ jmp DoIret%[Vector]
+
+%assign Vector Vector+1
+%endrep
+AsmExceptionEntryEnd:
+
+;
+; Common part of exception handler
+;
+global ASM_PFX(CommonTaskSwtichEntryPoint)
+ASM_PFX(CommonTaskSwtichEntryPoint):
+ ;
+ ; Stack:
+ ; +---------------------+ <-- EBP - 8
+ ; + TSS Base +
+ ; +---------------------+ <-- EBP - 4
+ ; + CPUID.EDX +
+ ; +---------------------+ <-- EBP
+ ; + EIP +
+ ; +---------------------+ <-- EBP + 4
+ ; + Vector Number +
+ ; +---------------------+ <-- EBP + 8
+ ; + Error Code +
+ ; +---------------------+
+ ;
+
+ mov ebp, esp ; Stack frame
+
+; Use CPUID to determine if FXSAVE/FXRESTOR and DE are supported
+ mov eax, 1
+ cpuid
+ push edx
+
+; Get TSS base of interrupted task through PreviousTaskLink field in
+; current TSS base
+ sub esp, 8
+ sgdt [esp + 2]
+ mov eax, [esp + 4] ; GDT base
+ add esp, 8
+
+ xor ebx, ebx
+ str bx ; Current TR
+
+ mov ecx, [eax + ebx + 2]
+ shl ecx, 8
+ mov cl, [eax + ebx + 7]
+ ror ecx, 8 ; ecx = Current TSS base
+ push ecx ; keep it in stack for later use
+
+ movzx ebx, word [ecx] ; Previous Task Link
+ mov ecx, [eax + ebx + 2]
+ shl ecx, 8
+ mov cl, [eax + ebx + 7]
+ ror ecx, 8 ; ecx = Previous TSS base
+
+;
+; Align stack to make sure that EFI_FX_SAVE_STATE_IA32 of EFI_SYSTEM_CONTEXT_IA32
+; is 16-byte aligned
+;
+ and esp, 0xfffffff0
+ sub esp, 12
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ push dword [ecx + IA32_TSS._EAX]
+ push dword [ecx + IA32_TSS._ECX]
+ push dword [ecx + IA32_TSS._EDX]
+ push dword [ecx + IA32_TSS._EBX]
+ push dword [ecx + IA32_TSS._ESP]
+ push dword [ecx + IA32_TSS._EBP]
+ push dword [ecx + IA32_TSS._ESI]
+ push dword [ecx + IA32_TSS._EDI]
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+ movzx eax, word [ecx + IA32_TSS._SS]
+ push eax
+ movzx eax, word [ecx + IA32_TSS._CS]
+ push eax
+ movzx eax, word [ecx + IA32_TSS._DS]
+ push eax
+ movzx eax, word [ecx + IA32_TSS._ES]
+ push eax
+ movzx eax, word [ecx + IA32_TSS._FS]
+ push eax
+ movzx eax, word [ecx + IA32_TSS._GS]
+ push eax
+
+;; UINT32 Eip;
+ push dword [ecx + IA32_TSS.EIP]
+
+;; UINT32 Gdtr[2], Idtr[2];
+ sub esp, 8
+ sidt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0xFFFF
+ mov [esp+4], eax
+
+ sub esp, 8
+ sgdt [esp]
+ mov eax, [esp + 2]
+ xchg eax, [esp]
+ and eax, 0xFFFF
+ mov [esp+4], eax
+
+;; UINT32 Ldtr, Tr;
+ mov eax, ebx ; ebx still keeps selector of interrupted task
+ push eax
+ movzx eax, word [ecx + IA32_TSS.LDT]
+ push eax
+
+;; UINT32 EFlags;
+ push dword [ecx + IA32_TSS.EFLAGS]
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ mov eax, cr4
+ push eax ; push cr4 firstly
+
+ mov edx, [ebp - 4] ; cpuid.edx
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .1
+ or eax, BIT9 ; Set CR4.OSFXSR
+.1:
+ test edx, BIT2 ; Test for Debugging Extensions support
+ jz .2
+ or eax, BIT3 ; Set CR4.DE
+.2:
+ mov cr4, eax
+
+ mov eax, cr3
+ push eax
+ mov eax, cr2
+ push eax
+ xor eax, eax
+ push eax
+ mov eax, cr0
+ push eax
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ mov eax, dr7
+ push eax
+ mov eax, dr6
+ push eax
+ mov eax, dr3
+ push eax
+ mov eax, dr2
+ push eax
+ mov eax, dr1
+ push eax
+ mov eax, dr0
+ push eax
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+;; Clear TS bit in CR0 to avoid Device Not Available Exception (#NM)
+;; when executing fxsave/fxrstor instruction
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support.
+ ; edx still contains result from CPUID above
+ jz .3
+ clts
+ sub esp, 512
+ mov edi, esp
+ db 0xf, 0xae, 0x7 ;fxsave [edi]
+.3:
+
+;; UINT32 ExceptionData;
+ push dword [ebp + 8]
+
+;; UEFI calling convention for IA32 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; call into exception handler
+ mov esi, ecx ; Keep TSS base to avoid overwrite
+ mov eax, ASM_PFX(CommonExceptionHandler)
+
+;; Prepare parameter and call
+ mov edx, esp
+ push edx ; EFI_SYSTEM_CONTEXT
+ push dword [ebp + 4] ; EFI_EXCEPTION_TYPE (vector number)
+
+ ;
+ ; Call External Exception Handler
+ ;
+ call eax
+ add esp, 8 ; Restore stack before calling
+ mov ecx, esi ; Restore TSS base
+
+;; UINT32 ExceptionData;
+ add esp, 4
+
+;; FX_SAVE_STATE_IA32 FxSaveState;
+ mov edx, [ebp - 4] ; cpuid.edx
+ test edx, BIT24 ; Test for FXSAVE/FXRESTOR support
+ jz .4
+ mov esi, esp
+ db 0xf, 0xae, 0xe ; fxrstor [esi]
+.4:
+ add esp, 512
+
+;; UINT32 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support debuggers
+;; that set breakpoints in interrupt/exception context
+ add esp, 4 * 6
+
+;; UINT32 Cr0, Cr1, Cr2, Cr3, Cr4;
+ pop eax
+ mov cr0, eax
+ add esp, 4 ; not for Cr1
+ pop eax
+ mov cr2, eax
+ pop eax
+ mov dword [ecx + IA32_TSS._CR3], eax
+ pop eax
+ mov cr4, eax
+
+;; UINT32 EFlags;
+ pop dword [ecx + IA32_TSS.EFLAGS]
+ mov ebx, dword [ecx + IA32_TSS.EFLAGS]
+ btr ebx, 9 ; Do 'cli'
+ mov dword [ecx + IA32_TSS.EFLAGS], ebx
+
+;; UINT32 Ldtr, Tr;
+;; UINT32 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add esp, 24
+
+;; UINT32 Eip;
+ pop dword [ecx + IA32_TSS.EIP]
+
+;; UINT32 Gs, Fs, Es, Ds, Cs, Ss;
+;; NOTE - modified segment registers could hang the debugger... We
+;; could attempt to insulate ourselves against this possibility,
+;; but that poses risks as well.
+;;
+ pop eax
+o16 mov [ecx + IA32_TSS._GS], ax
+ pop eax
+o16 mov [ecx + IA32_TSS._FS], ax
+ pop eax
+o16 mov [ecx + IA32_TSS._ES], ax
+ pop eax
+o16 mov [ecx + IA32_TSS._DS], ax
+ pop eax
+o16 mov [ecx + IA32_TSS._CS], ax
+ pop eax
+o16 mov [ecx + IA32_TSS._SS], ax
+
+;; UINT32 Edi, Esi, Ebp, Esp, Ebx, Edx, Ecx, Eax;
+ pop dword [ecx + IA32_TSS._EDI]
+ pop dword [ecx + IA32_TSS._ESI]
+ add esp, 4 ; not for ebp
+ add esp, 4 ; not for esp
+ pop dword [ecx + IA32_TSS._EBX]
+ pop dword [ecx + IA32_TSS._EDX]
+ pop dword [ecx + IA32_TSS._ECX]
+ pop dword [ecx + IA32_TSS._EAX]
+
+; Set single step DB# to allow debugger to able to go back to the EIP
+; where the exception is triggered.
+
+;; Create return context for iretd in stub function
+ mov eax, dword [ecx + IA32_TSS._ESP] ; Get old stack pointer
+ mov ebx, dword [ecx + IA32_TSS.EIP]
+ mov [eax - 0xc], ebx ; create EIP in old stack
+ movzx ebx, word [ecx + IA32_TSS._CS]
+ mov [eax - 0x8], ebx ; create CS in old stack
+ mov ebx, dword [ecx + IA32_TSS.EFLAGS]
+ bts ebx, 8 ; Set TF
+ mov [eax - 0x4], ebx ; create eflags in old stack
+ sub eax, 0xc ; minus 12 byte
+ mov dword [ecx + IA32_TSS._ESP], eax ; Set new stack pointer
+
+;; Replace the EIP of interrupted task with stub function
+ mov eax, ASM_PFX(SingleStepStubFunction)
+ mov dword [ecx + IA32_TSS.EIP], eax
+
+ mov ecx, [ebp - 8] ; Get current TSS base
+ mov eax, dword [ecx + IA32_TSS._ESP] ; Return current stack top
+ mov esp, ebp
+
+ ret
+
+global ASM_PFX(SingleStepStubFunction)
+ASM_PFX(SingleStepStubFunction):
+;
+; we need clean TS bit in CR0 to execute
+; x87 FPU/MMX/SSE/SSE2/SSE3/SSSE3/SSE4 instructions.
+;
+ clts
+ iretd
+
+global ASM_PFX(AsmGetTssTemplateMap)
+ASM_PFX(AsmGetTssTemplateMap):
+ push ebp ; C prolog
+ mov ebp, esp
+ pushad
+
+ mov ebx, dword [ebp + 0x8]
+ mov dword [ebx], ASM_PFX(ExceptionTaskSwtichEntry0)
+ mov dword [ebx + 0x4], (AsmExceptionEntryEnd - AsmExceptionEntryBegin) / 32
+ mov dword [ebx + 0x8], 0
+
+ popad
+ pop ebp
+ ret
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
new file mode 100644
index 00000000..2bce3924
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuException.c
@@ -0,0 +1,262 @@
+/** @file
+ CPU exception handler library implementation for PEIM module.
+
+Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include "CpuExceptionCommon.h"
+#include <Library/DebugLib.h>
+#include <Library/HobLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+CONST UINTN mDoFarReturnFlag = 0;
+
+typedef struct {
+ UINT8 ExceptionStubHeader[HOOKAFTER_STUB_SIZE];
+ EXCEPTION_HANDLER_DATA *ExceptionHandlerData;
+} EXCEPTION0_STUB_HEADER;
+
+/**
+ Get exception handler data pointer from IDT[0].
+
+ The exception #0 stub header is duplicated in an allocated pool with extra 4-byte/8-byte to store the
+ exception handler data. The new allocated memory layout follows structure EXCEPTION0_STUB_HEADER.
+ The code assumes that all processors uses the same exception handler for #0 exception.
+
+ @return pointer to exception handler data.
+**/
+EXCEPTION_HANDLER_DATA *
+GetExceptionHandlerData (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ EXCEPTION0_STUB_HEADER *Exception0StubHeader;
+
+ AsmReadIdtr (&IdtDescriptor);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
+
+ Exception0StubHeader = (EXCEPTION0_STUB_HEADER *)ArchGetIdtHandler (&IdtTable[0]);
+ return Exception0StubHeader->ExceptionHandlerData;
+}
+
+/**
+ Set exception handler data pointer to IDT[0].
+
+ The exception #0 stub header is duplicated in an allocated pool with extra 4-byte/8-byte to store the
+ exception handler data. The new allocated memory layout follows structure EXCEPTION0_STUB_HEADER.
+ The code assumes that all processors uses the same exception handler for #0 exception.
+
+ @param ExceptionHandlerData pointer to exception handler data.
+**/
+VOID
+SetExceptionHandlerData (
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ EXCEPTION0_STUB_HEADER *Exception0StubHeader;
+ IA32_DESCRIPTOR IdtDescriptor;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ //
+ // Duplicate the exception #0 stub header in pool and cache the ExceptionHandlerData just after the stub header.
+ // So AP can get the ExceptionHandlerData by reading the IDT[0].
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
+
+ Exception0StubHeader = AllocatePool (sizeof (*Exception0StubHeader));
+ ASSERT (Exception0StubHeader != NULL);
+ CopyMem (
+ Exception0StubHeader->ExceptionStubHeader,
+ (VOID *)ArchGetIdtHandler (&IdtTable[0]),
+ sizeof (Exception0StubHeader->ExceptionStubHeader)
+ );
+ Exception0StubHeader->ExceptionHandlerData = ExceptionHandlerData;
+ ArchUpdateIdtEntry (&IdtTable[0], (UINTN)Exception0StubHeader->ExceptionStubHeader);
+}
+
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ EXCEPTION_HANDLER_DATA *ExceptionHandlerData;
+
+ ExceptionHandlerData = GetExceptionHandlerData ();
+ CommonExceptionHandlerWorker (ExceptionType, SystemContext, ExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+ Note: Before invoking this API, caller must allocate memory for IDT table and load
+ IDTR by AsmWriteIdtr().
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EXCEPTION_HANDLER_DATA *ExceptionHandlerData;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = AllocatePool (sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM);
+ ASSERT (ReservedVectors != NULL);
+
+ ExceptionHandlerData = AllocatePool (sizeof (EXCEPTION_HANDLER_DATA));
+ ASSERT (ExceptionHandlerData != NULL);
+ ExceptionHandlerData->ReservedVectors = ReservedVectors;
+ ExceptionHandlerData->ExternalInterruptHandler = NULL;
+ InitializeSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
+
+ Status = InitializeCpuExceptionHandlersWorker (VectorInfo, ExceptionHandlerData);
+ if (EFI_ERROR (Status)) {
+ FreePool (ReservedVectors);
+ FreePool (ExceptionHandlerData);
+ return Status;
+ }
+
+ SetExceptionHandlerData (ExceptionHandlerData);
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initializes all CPU exceptions entries with optional extra initializations.
+
+ By default, this method should include all functionalities implemented by
+ InitializeCpuExceptionHandlers(), plus extra initialization works, if any.
+ This could be done by calling InitializeCpuExceptionHandlers() directly
+ in this method besides the extra works.
+
+ InitData is optional and its use and content are processor arch dependent.
+ The typical usage of it is to convey resources which have to be reserved
+ elsewhere and are necessary for the extra initializations of exception.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data optional for extra initializations
+ of exception.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // To avoid repeat initialization of default handlers, the caller should pass
+ // an extended init data with InitDefaultHandlers set to FALSE. There's no
+ // need to call this method to just initialize default handlers. Call non-ex
+ // version instead; or this method must be implemented as a simple wrapper of
+ // non-ex version of it, if this version has to be called.
+ //
+ if (InitData == NULL || InitData->Ia32.InitDefaultHandlers) {
+ Status = InitializeCpuExceptionHandlers (VectorInfo);
+ } else {
+ Status = EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Initializing stack switch is only necessary for Stack Guard functionality.
+ //
+ if (PcdGetBool (PcdCpuStackGuard) && InitData != NULL) {
+ Status = ArchSetupExceptionStack (InitData);
+ }
+ }
+
+ return Status;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
new file mode 100644
index 00000000..53fbee20
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.inf
@@ -0,0 +1,62 @@
+## @file
+# CPU Exception Handler library instance for PEI module.
+#
+# Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiCpuExceptionHandlerLib
+ MODULE_UNI_FILE = PeiCpuExceptionHandlerLib.uni
+ FILE_GUID = 980DDA67-44A6-4897-99E6-275290B71F9E
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = CpuExceptionHandlerLib|PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.nasm
+ Ia32/ExceptionTssEntryAsm.nasm
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/Xcode5ExceptionHandlerAsm.nasm
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ PeiCpuException.c
+ PeiDxeSmmCpuException.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ HobLib
+ MemoryAllocationLib
+ SynchronizationLib
+ VmgExitLib
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard # CONSUMES
+
+[FeaturePcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.uni
new file mode 100644
index 00000000..300356c8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiCpuExceptionHandlerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// CPU Exception Handler library instance for PEI module.
+//
+// CPU Exception Handler library instance for PEI module.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for PEI module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for PEI module."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
new file mode 100644
index 00000000..a0a0860e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/PeiDxeSmmCpuException.c
@@ -0,0 +1,314 @@
+/** @file
+ CPU Exception Library provides PEI/DXE/SMM CPU common exception handler.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Library/DebugLib.h>
+#include <Library/VmgExitLib.h>
+#include "CpuExceptionCommon.h"
+
+/**
+ Internal worker function for common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+CommonExceptionHandlerWorker (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ EXCEPTION_HANDLER_CONTEXT *ExceptionHandlerContext;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
+
+ if (ExceptionType == VC_EXCEPTION) {
+ EFI_STATUS Status;
+ //
+ // #VC needs to be handled immediately upon enabling exception handling
+ // and therefore can't use the RegisterCpuInterruptHandler() interface.
+ //
+ // Handle the #VC:
+ // On EFI_SUCCESS - Exception has been handled, return
+ // On other - ExceptionType contains (possibly new) exception
+ // value
+ //
+ Status = VmgExitHandleVc (&ExceptionType, SystemContext);
+ if (!EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ ExceptionHandlerContext = (EXCEPTION_HANDLER_CONTEXT *) (UINTN) (SystemContext.SystemContextIa32);
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
+
+ switch (ReservedVectors[ExceptionType].Attribute) {
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
+ //
+ // The new exception handler registered by RegisterCpuInterruptHandler() is executed BEFORE original handler.
+ // Save the original handler to stack so the assembly code can jump to it instead of returning from handler.
+ //
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
+ ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
+ break;
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:
+ while (TRUE) {
+ //
+ // If spin-lock can be acquired, it's the first time entering here.
+ //
+ if (AcquireSpinLockOrFail (&ReservedVectors[ExceptionType].SpinLock)) {
+ //
+ // The new exception handler registered by RegisterCpuInterruptHandler() is executed AFTER original handler.
+ // Save the original handler to stack but skip running the new handler so the original handler is executed
+ // firstly.
+ //
+ ReservedVectors[ExceptionType].ApicId = GetApicId ();
+ ArchSaveExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
+ ExceptionHandlerContext->ExceptionDataFlag = (mErrorCodeFlag & (1 << ExceptionType)) ? TRUE : FALSE;
+ ExceptionHandlerContext->OldIdtHandler = ReservedVectors[ExceptionType].ExceptonHandler;
+ return;
+ }
+ //
+ // If spin-lock cannot be acquired, it's the second time entering here.
+ // 'break' instead of 'return' is used so the new exception handler can be executed.
+ //
+ if (ReservedVectors[ExceptionType].ApicId == GetApicId ()) {
+ //
+ // Old IDT handler has been executed, then restore CPU exception content to
+ // run new exception handler.
+ //
+ ArchRestoreExceptionContext (ExceptionType, SystemContext, ExceptionHandlerData);
+ //
+ // Release spin lock for ApicId
+ //
+ ReleaseSpinLock (&ReservedVectors[ExceptionType].SpinLock);
+ break;
+ }
+ CpuPause ();
+ }
+ break;
+ case 0xffffffff:
+ break;
+ default:
+ //
+ // It should never reach here
+ //
+ CpuDeadLoop ();
+ break;
+ }
+
+ if (ExternalInterruptHandler != NULL &&
+ ExternalInterruptHandler[ExceptionType] != NULL) {
+ (ExternalInterruptHandler[ExceptionType]) (ExceptionType, SystemContext);
+ } else if (ExceptionType < CPU_EXCEPTION_NUM) {
+ //
+ // Get Spinlock to display CPU information
+ //
+ while (!AcquireSpinLockOrFail (&ExceptionHandlerData->DisplayMessageSpinLock)) {
+ CpuPause ();
+ }
+ //
+ // Initialize the serial port before dumping.
+ //
+ SerialPortInitialize ();
+ //
+ // Display ExceptionType, CPU information and Image information
+ //
+ DumpImageAndCpuContent (ExceptionType, SystemContext);
+ //
+ // Release Spinlock of output message
+ //
+ ReleaseSpinLock (&ExceptionHandlerData->DisplayMessageSpinLock);
+ //
+ // Enter a dead loop if needn't to execute old IDT handler further
+ //
+ if (ReservedVectors[ExceptionType].Attribute != EFI_VECTOR_HANDOFF_HOOK_BEFORE) {
+ CpuDeadLoop ();
+ }
+ }
+}
+
+/**
+ Internal worker function to update IDT entries accordling to vector attributes.
+
+ @param[in] IdtTable Pointer to IDT table.
+ @param[in] TemplateMap Pointer to a buffer where the address map is
+ returned.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+
+**/
+VOID
+UpdateIdtTable (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtTable,
+ IN EXCEPTION_HANDLER_TEMPLATE_MAP *TemplateMap,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ UINT16 CodeSegment;
+ UINTN Index;
+ UINTN InterruptHandler;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ for (Index = 0; Index < ExceptionHandlerData->IdtEntryCount; Index ++) {
+ IdtTable[Index].Bits.Selector = CodeSegment;
+ //
+ // Check reserved vectors attributes
+ //
+ switch (ReservedVectors[Index].Attribute) {
+ case EFI_VECTOR_HANDOFF_DO_NOT_HOOK:
+ //
+ // Keep original IDT entry
+ //
+ continue;
+ case EFI_VECTOR_HANDOFF_HOOK_AFTER:
+ InitializeSpinLock (&ReservedVectors[Index].SpinLock);
+ CopyMem (
+ (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,
+ (VOID *) TemplateMap->HookAfterStubHeaderStart,
+ TemplateMap->ExceptionStubHeaderSize
+ );
+ AsmVectorNumFixup (
+ (VOID *) ReservedVectors[Index].HookAfterStubHeaderCode,
+ (UINT8) Index,
+ (VOID *) TemplateMap->HookAfterStubHeaderStart
+ );
+ //
+ // Go on the following code
+ //
+ case EFI_VECTOR_HANDOFF_HOOK_BEFORE:
+ //
+ // Save original IDT handler address
+ //
+ ReservedVectors[Index].ExceptonHandler = ArchGetIdtHandler (&IdtTable[Index]);
+ //
+ // Go on the following code
+ //
+ default:
+ //
+ // Update new IDT entry
+ //
+ InterruptHandler = TemplateMap->ExceptionStart + Index * TemplateMap->ExceptionStubHeaderSize;
+ ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
+ break;
+ }
+ }
+}
+
+/**
+ Internal worker function to initialize exception handler.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in, out] ExceptionHandlerData Pointer to exception handler data.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+InitializeCpuExceptionHandlersWorker (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN OUT EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ EFI_STATUS Status;
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ SetMem ((VOID *) ReservedVectors, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
+ if (VectorInfo != NULL) {
+ Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectors, CPU_EXCEPTION_NUM);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_EXCEPTION_NUM) {
+ //
+ // CPU exception library only setup CPU_EXCEPTION_NUM exception handler at most
+ //
+ IdtEntryCount = CPU_EXCEPTION_NUM;
+ }
+
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *) IdtDescriptor.Base;
+ AsmGetTemplateAddressMap (&TemplateMap);
+ ASSERT (TemplateMap.ExceptionStubHeaderSize <= HOOKAFTER_STUB_SIZE);
+
+ ExceptionHandlerData->IdtEntryCount = IdtEntryCount;
+ UpdateIdtTable (IdtTable, &TemplateMap, ExceptionHandlerData);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+RegisterCpuInterruptHandlerWorker (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ UINTN EnabledInterruptNum;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+ EFI_CPU_INTERRUPT_HANDLER *ExternalInterruptHandler;
+
+ EnabledInterruptNum = ExceptionHandlerData->IdtEntryCount;
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ ExternalInterruptHandler = ExceptionHandlerData->ExternalInterruptHandler;
+
+ if (InterruptType < 0 || InterruptType >= (EFI_EXCEPTION_TYPE)EnabledInterruptNum ||
+ ReservedVectors[InterruptType].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (InterruptHandler == NULL && ExternalInterruptHandler[InterruptType] == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (InterruptHandler != NULL && ExternalInterruptHandler[InterruptType] != NULL) {
+ return EFI_ALREADY_STARTED;
+ }
+
+ ExternalInterruptHandler[InterruptType] = InterruptHandler;
+ return EFI_SUCCESS;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
new file mode 100644
index 00000000..7cc87955
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuException.c
@@ -0,0 +1,228 @@
+/** @file
+ CPU exception handler library implemenation for SEC/PEIM modules.
+
+Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+#include <Library/VmgExitLib.h>
+#include "CpuExceptionCommon.h"
+
+CONST UINTN mDoFarReturnFlag = 0;
+
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ if (ExceptionType == VC_EXCEPTION) {
+ EFI_STATUS Status;
+ //
+ // #VC needs to be handled immediately upon enabling exception handling
+ // and therefore can't use the RegisterCpuInterruptHandler() interface
+ // (which isn't supported under Sec and Pei anyway).
+ //
+ // Handle the #VC:
+ // On EFI_SUCCESS - Exception has been handled, return
+ // On other - ExceptionType contains (possibly new) exception
+ // value
+ //
+ Status = VmgExitHandleVc (&ExceptionType, SystemContext);
+ if (!EFI_ERROR (Status)) {
+ return;
+ }
+ }
+
+ //
+ // Initialize the serial port before dumping.
+ //
+ SerialPortInitialize ();
+ //
+ // Display ExceptionType, CPU information and Image information
+ //
+ DumpImageAndCpuContent (ExceptionType, SystemContext);
+
+ //
+ // Enter a dead loop.
+ //
+ CpuDeadLoop ();
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+ Note: Before invoking this API, caller must allocate memory for IDT table and load
+ IDTR by AsmWriteIdtr().
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ RESERVED_VECTORS_DATA ReservedVectorData[CPU_EXCEPTION_NUM];
+ IA32_DESCRIPTOR IdtDescriptor;
+ UINTN IdtEntryCount;
+ UINT16 CodeSegment;
+ EXCEPTION_HANDLER_TEMPLATE_MAP TemplateMap;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ UINTN Index;
+ UINTN InterruptHandler;
+
+ if (VectorInfo != NULL) {
+ SetMem ((VOID *) ReservedVectorData, sizeof (RESERVED_VECTORS_DATA) * CPU_EXCEPTION_NUM, 0xff);
+ Status = ReadAndVerifyVectorInfo (VectorInfo, ReservedVectorData, CPU_EXCEPTION_NUM);
+ if (EFI_ERROR (Status)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Read IDT descriptor and calculate IDT size
+ //
+ AsmReadIdtr (&IdtDescriptor);
+ IdtEntryCount = (IdtDescriptor.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR);
+ if (IdtEntryCount > CPU_EXCEPTION_NUM) {
+ //
+ // CPU exception library only setup CPU_EXCEPTION_NUM exception handler at most
+ //
+ IdtEntryCount = CPU_EXCEPTION_NUM;
+ }
+ //
+ // Use current CS as the segment selector of interrupt gate in IDT
+ //
+ CodeSegment = AsmReadCs ();
+
+ AsmGetTemplateAddressMap (&TemplateMap);
+ IdtTable = (IA32_IDT_GATE_DESCRIPTOR *)IdtDescriptor.Base;
+ for (Index = 0; Index < IdtEntryCount; Index ++) {
+ IdtTable[Index].Bits.Selector = CodeSegment;
+ //
+ // Check reserved vectors attributes if has, only EFI_VECTOR_HANDOFF_DO_NOT_HOOK
+ // supported in this instance
+ //
+ if (VectorInfo != NULL) {
+ if (ReservedVectorData[Index].Attribute == EFI_VECTOR_HANDOFF_DO_NOT_HOOK) {
+ continue;
+ }
+ }
+ //
+ // Update IDT entry
+ //
+ InterruptHandler = TemplateMap.ExceptionStart + Index * TemplateMap.ExceptionStubHeaderSize;
+ ArchUpdateIdtEntry (&IdtTable[Index], InterruptHandler);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Initializes all CPU exceptions entries with optional extra initializations.
+
+ By default, this method should include all functionalities implemented by
+ InitializeCpuExceptionHandlers(), plus extra initialization works, if any.
+ This could be done by calling InitializeCpuExceptionHandlers() directly
+ in this method besides the extra works.
+
+ InitData is optional and its use and content are processor arch dependent.
+ The typical usage of it is to convey resources which have to be reserved
+ elsewhere and are necessary for the extra initializations of exception.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data optional for extra initializations
+ of exception.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ )
+{
+ return InitializeCpuExceptionHandlers (VectorInfo);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
new file mode 100644
index 00000000..4eaad47b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.inf
@@ -0,0 +1,55 @@
+## @file
+# CPU Exception Handler library instance for SEC/PEI modules.
+#
+# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecPeiCpuExceptionHandlerLib
+ MODULE_UNI_FILE = SecPeiCpuExceptionHandlerLib.uni
+ FILE_GUID = CA4BBC99-DFC6-4234-B553-8B6586B7B113
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.nasm
+ Ia32/ExceptionTssEntryAsm.nasm
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/ExceptionHandlerAsm.nasm
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ SecPeiCpuException.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ VmgExitLib
+
+[FeaturePcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
new file mode 100644
index 00000000..72300e51
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SecPeiCpuExceptionHandlerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// CPU Exception Handler library instance for SEC/PEI modules.
+//
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for SEC/PEI modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
new file mode 100644
index 00000000..3cdab318
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.inf
@@ -0,0 +1,58 @@
+## @file
+# CPU Exception Handler library instance for SMM modules.
+#
+# Copyright (c) 2013 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuExceptionHandlerLib
+ MODULE_UNI_FILE = SmmCpuExceptionHandlerLib.uni
+ FILE_GUID = 8D2C439B-3981-42ff-9CE5-1B50ECA502D6
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = CpuExceptionHandlerLib|DXE_SMM_DRIVER MM_STANDALONE MM_CORE_STANDALONE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.nasm
+ Ia32/ExceptionTssEntryAsm.nasm
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/Xcode5ExceptionHandlerAsm.nasm
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ PeiDxeSmmCpuException.c
+ SmmException.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ SynchronizationLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ DebugLib
+ VmgExitLib
+
+[FeaturePcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni
new file mode 100644
index 00000000..2ec2f793
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmCpuExceptionHandlerLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// CPU Exception Handler library instance for SMM modules.
+//
+// CPU Exception Handler library instance for SMM modules.
+//
+// Copyright (c) 2013 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for SMM modules."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for SMM modules."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c
new file mode 100644
index 00000000..8a4c540d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/SmmException.c
@@ -0,0 +1,154 @@
+/** @file
+ CPU exception handler library implementation for SMM modules.
+
+ Copyright (c) 2013 - 2017, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiSmm.h>
+#include "CpuExceptionCommon.h"
+
+CONST UINTN mDoFarReturnFlag = 1;
+
+//
+// Spin lock for CPU information display
+//
+SPIN_LOCK mDisplayMessageSpinLock;
+
+RESERVED_VECTORS_DATA mReservedVectorsData[CPU_EXCEPTION_NUM];
+EFI_CPU_INTERRUPT_HANDLER mExternalInterruptHandlerTable[CPU_EXCEPTION_NUM];
+EXCEPTION_HANDLER_DATA mExceptionHandlerData;
+/**
+ Common exception handler.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+CommonExceptionHandler (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ CommonExceptionHandlerWorker (ExceptionType, SystemContext, &mExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU exceptions entries and provides the default exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS CPU Exception Entries have been successfully initialized
+ with default exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ mExceptionHandlerData.ReservedVectors = mReservedVectorsData;
+ mExceptionHandlerData.ExternalInterruptHandler = mExternalInterruptHandlerTable;
+ InitializeSpinLock (&mExceptionHandlerData.DisplayMessageSpinLock);
+ return InitializeCpuExceptionHandlersWorker (VectorInfo, &mExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU interrupt/exceptions entries and provides the default interrupt/exception handlers.
+
+ Caller should try to get an array of interrupt and/or exception vectors that are in use and need to
+ persist by EFI_VECTOR_HANDOFF_INFO defined in PI 1.3 specification.
+ If caller cannot get reserved vector list or it does not exists, set VectorInfo to NULL.
+ If VectorInfo is not NULL, the exception vectors will be initialized per vector attribute accordingly.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+
+ @retval EFI_SUCCESS All CPU interrupt/exception entries have been successfully initialized
+ with default interrupt/exception handlers.
+ @retval EFI_INVALID_PARAMETER VectorInfo includes the invalid content if VectorInfo is not NULL.
+ @retval EFI_UNSUPPORTED This function is not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuInterruptHandlers (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Registers a function to be called from the processor interrupt handler.
+
+ This function registers and enables the handler specified by InterruptHandler for a processor
+ interrupt or exception type specified by InterruptType. If InterruptHandler is NULL, then the
+ handler for the processor interrupt or exception type specified by InterruptType is uninstalled.
+ The installed handler is called once for each processor interrupt or exception.
+ NOTE: This function should be invoked after InitializeCpuExceptionHandlers() or
+ InitializeCpuInterruptHandlers() invoked, otherwise EFI_UNSUPPORTED returned.
+
+ @param[in] InterruptType Defines which interrupt or exception to hook.
+ @param[in] InterruptHandler A pointer to a function of type EFI_CPU_INTERRUPT_HANDLER that is called
+ when a processor interrupt occurs. If this parameter is NULL, then the handler
+ will be uninstalled.
+
+ @retval EFI_SUCCESS The handler for the processor interrupt was successfully installed or uninstalled.
+ @retval EFI_ALREADY_STARTED InterruptHandler is not NULL, and a handler for InterruptType was
+ previously installed.
+ @retval EFI_INVALID_PARAMETER InterruptHandler is NULL, and a handler for InterruptType was not
+ previously installed.
+ @retval EFI_UNSUPPORTED The interrupt specified by InterruptType is not supported,
+ or this function is not supported.
+**/
+EFI_STATUS
+EFIAPI
+RegisterCpuInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_CPU_INTERRUPT_HANDLER InterruptHandler
+ )
+{
+ return RegisterCpuInterruptHandlerWorker (InterruptType, InterruptHandler, &mExceptionHandlerData);
+}
+
+/**
+ Initializes all CPU exceptions entries with optional extra initializations.
+
+ By default, this method should include all functionalities implemented by
+ InitializeCpuExceptionHandlers(), plus extra initialization works, if any.
+ This could be done by calling InitializeCpuExceptionHandlers() directly
+ in this method besides the extra works.
+
+ InitData is optional and its use and content are processor arch dependent.
+ The typical usage of it is to convey resources which have to be reserved
+ elsewhere and are necessary for the extra initializations of exception.
+
+ @param[in] VectorInfo Pointer to reserved vector list.
+ @param[in] InitData Pointer to data optional for extra initializations
+ of exception.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized.
+ @retval EFI_INVALID_PARAMETER VectorInfo or InitData contains invalid
+ content.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeCpuExceptionHandlersEx (
+ IN EFI_VECTOR_HANDOFF_INFO *VectorInfo OPTIONAL,
+ IN CPU_EXCEPTION_INIT_DATA *InitData OPTIONAL
+ )
+{
+ return InitializeCpuExceptionHandlers (VectorInfo);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
new file mode 100644
index 00000000..a0257aa8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchExceptionHandler.c
@@ -0,0 +1,427 @@
+/** @file
+ x64 CPU Exception Handler.
+
+ Copyright (c) 2012 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "CpuExceptionCommon.h"
+
+/**
+ Return address map of exception handler template so that C code can generate
+ exception tables.
+
+ @param IdtEntry Pointer to IDT entry to be updated.
+ @param InterruptHandler IDT handler value.
+**/
+VOID
+ArchUpdateIdtEntry (
+ OUT IA32_IDT_GATE_DESCRIPTOR *IdtEntry,
+ IN UINTN InterruptHandler
+ )
+{
+ IdtEntry->Bits.OffsetLow = (UINT16)(UINTN)InterruptHandler;
+ IdtEntry->Bits.OffsetHigh = (UINT16)((UINTN)InterruptHandler >> 16);
+ IdtEntry->Bits.OffsetUpper = (UINT32)((UINTN)InterruptHandler >> 32);
+ IdtEntry->Bits.GateType = IA32_IDT_GATE_TYPE_INTERRUPT_32;
+}
+
+/**
+ Read IDT handler value from IDT entry.
+
+ @param IdtEntry Pointer to IDT entry to be read.
+
+**/
+UINTN
+ArchGetIdtHandler (
+ IN IA32_IDT_GATE_DESCRIPTOR *IdtEntry
+ )
+{
+ return IdtEntry->Bits.OffsetLow + (((UINTN) IdtEntry->Bits.OffsetHigh) << 16) +
+ (((UINTN) IdtEntry->Bits.OffsetUpper) << 32);
+}
+
+/**
+ Save CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchSaveExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ IA32_EFLAGS32 Eflags;
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ //
+ // Save Exception context in global variable in first entry of the exception handler.
+ // So when original exception handler returns to the new exception handler (second entry),
+ // the Eflags/Cs/Eip/ExceptionData can be used.
+ //
+ ReservedVectors[ExceptionType].OldSs = SystemContext.SystemContextX64->Ss;
+ ReservedVectors[ExceptionType].OldSp = SystemContext.SystemContextX64->Rsp;
+ ReservedVectors[ExceptionType].OldFlags = SystemContext.SystemContextX64->Rflags;
+ ReservedVectors[ExceptionType].OldCs = SystemContext.SystemContextX64->Cs;
+ ReservedVectors[ExceptionType].OldIp = SystemContext.SystemContextX64->Rip;
+ ReservedVectors[ExceptionType].ExceptionData = SystemContext.SystemContextX64->ExceptionData;
+ //
+ // Clear IF flag to avoid old IDT handler enable interrupt by IRET
+ //
+ Eflags.UintN = SystemContext.SystemContextX64->Rflags;
+ Eflags.Bits.IF = 0;
+ SystemContext.SystemContextX64->Rflags = Eflags.UintN;
+ //
+ // Modify the EIP in stack, then old IDT handler will return to HookAfterStubBegin.
+ //
+ SystemContext.SystemContextX64->Rip = (UINTN) ReservedVectors[ExceptionType].HookAfterStubHeaderCode;
+}
+
+/**
+ Restore CPU exception context when handling EFI_VECTOR_HANDOFF_HOOK_AFTER case.
+
+ @param[in] ExceptionType Exception type.
+ @param[in] SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+ @param[in] ExceptionHandlerData Pointer to exception handler data.
+**/
+VOID
+ArchRestoreExceptionContext (
+ IN UINTN ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext,
+ IN EXCEPTION_HANDLER_DATA *ExceptionHandlerData
+ )
+{
+ RESERVED_VECTORS_DATA *ReservedVectors;
+
+ ReservedVectors = ExceptionHandlerData->ReservedVectors;
+ SystemContext.SystemContextX64->Ss = ReservedVectors[ExceptionType].OldSs;
+ SystemContext.SystemContextX64->Rsp = ReservedVectors[ExceptionType].OldSp;
+ SystemContext.SystemContextX64->Rflags = ReservedVectors[ExceptionType].OldFlags;
+ SystemContext.SystemContextX64->Cs = ReservedVectors[ExceptionType].OldCs;
+ SystemContext.SystemContextX64->Rip = ReservedVectors[ExceptionType].OldIp;
+ SystemContext.SystemContextX64->ExceptionData = ReservedVectors[ExceptionType].ExceptionData;
+}
+
+/**
+ Setup separate stack for given exceptions.
+
+ @param[in] StackSwitchData Pointer to data required for setuping up
+ stack switch.
+
+ @retval EFI_SUCCESS The exceptions have been successfully
+ initialized with new stack.
+ @retval EFI_INVALID_PARAMETER StackSwitchData contains invalid content.
+
+**/
+EFI_STATUS
+ArchSetupExceptionStack (
+ IN CPU_EXCEPTION_INIT_DATA *StackSwitchData
+ )
+{
+ IA32_DESCRIPTOR Gdtr;
+ IA32_DESCRIPTOR Idtr;
+ IA32_IDT_GATE_DESCRIPTOR *IdtTable;
+ IA32_TSS_DESCRIPTOR *TssDesc;
+ IA32_TASK_STATE_SEGMENT *Tss;
+ UINTN StackTop;
+ UINTN Index;
+ UINTN Vector;
+ UINTN TssBase;
+ UINTN GdtSize;
+
+ if (StackSwitchData == NULL ||
+ StackSwitchData->Ia32.Revision != CPU_EXCEPTION_INIT_DATA_REV ||
+ StackSwitchData->X64.KnownGoodStackTop == 0 ||
+ StackSwitchData->X64.KnownGoodStackSize == 0 ||
+ StackSwitchData->X64.StackSwitchExceptions == NULL ||
+ StackSwitchData->X64.StackSwitchExceptionNumber == 0 ||
+ StackSwitchData->X64.StackSwitchExceptionNumber > CPU_EXCEPTION_NUM ||
+ StackSwitchData->X64.GdtTable == NULL ||
+ StackSwitchData->X64.IdtTable == NULL ||
+ StackSwitchData->X64.ExceptionTssDesc == NULL ||
+ StackSwitchData->X64.ExceptionTss == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The caller is responsible for that the GDT table, no matter the existing
+ // one or newly allocated, has enough space to hold descriptors for exception
+ // task-state segments.
+ //
+ if (((UINTN)StackSwitchData->X64.GdtTable & (IA32_GDT_ALIGNMENT - 1)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINTN)StackSwitchData->X64.ExceptionTssDesc < (UINTN)(StackSwitchData->X64.GdtTable)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((UINTN)StackSwitchData->X64.ExceptionTssDesc + StackSwitchData->X64.ExceptionTssDescSize) >
+ ((UINTN)(StackSwitchData->X64.GdtTable) + StackSwitchData->X64.GdtTableSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // One task gate descriptor and one task-state segment are needed.
+ //
+ if (StackSwitchData->X64.ExceptionTssDescSize < sizeof (IA32_TSS_DESCRIPTOR)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (StackSwitchData->X64.ExceptionTssSize < sizeof (IA32_TASK_STATE_SEGMENT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Interrupt stack table supports only 7 vectors.
+ //
+ TssDesc = StackSwitchData->X64.ExceptionTssDesc;
+ Tss = StackSwitchData->X64.ExceptionTss;
+ if (StackSwitchData->X64.StackSwitchExceptionNumber > ARRAY_SIZE (Tss->IST)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize new GDT table and/or IDT table, if any
+ //
+ AsmReadIdtr (&Idtr);
+ AsmReadGdtr (&Gdtr);
+
+ GdtSize = (UINTN)TssDesc + sizeof (IA32_TSS_DESCRIPTOR) -
+ (UINTN)(StackSwitchData->X64.GdtTable);
+ if ((UINTN)StackSwitchData->X64.GdtTable != Gdtr.Base) {
+ CopyMem (StackSwitchData->X64.GdtTable, (VOID *)Gdtr.Base, Gdtr.Limit + 1);
+ Gdtr.Base = (UINTN)StackSwitchData->X64.GdtTable;
+ Gdtr.Limit = (UINT16)GdtSize - 1;
+ }
+
+ if ((UINTN)StackSwitchData->X64.IdtTable != Idtr.Base) {
+ Idtr.Base = (UINTN)StackSwitchData->X64.IdtTable;
+ }
+ if (StackSwitchData->X64.IdtTableSize > 0) {
+ Idtr.Limit = (UINT16)(StackSwitchData->X64.IdtTableSize - 1);
+ }
+
+ //
+ // Fixup current task descriptor. Task-state segment for current task will
+ // be filled by processor during task switching.
+ //
+ TssBase = (UINTN)Tss;
+
+ TssDesc->Uint128.Uint64 = 0;
+ TssDesc->Uint128.Uint64_1= 0;
+ TssDesc->Bits.LimitLow = sizeof(IA32_TASK_STATE_SEGMENT) - 1;
+ TssDesc->Bits.BaseLow = (UINT16)TssBase;
+ TssDesc->Bits.BaseMidl = (UINT8)(TssBase >> 16);
+ TssDesc->Bits.Type = IA32_GDT_TYPE_TSS;
+ TssDesc->Bits.P = 1;
+ TssDesc->Bits.LimitHigh = 0;
+ TssDesc->Bits.BaseMidh = (UINT8)(TssBase >> 24);
+ TssDesc->Bits.BaseHigh = (UINT32)(TssBase >> 32);
+
+ //
+ // Fixup exception task descriptor and task-state segment
+ //
+ ZeroMem (Tss, sizeof (*Tss));
+ StackTop = StackSwitchData->X64.KnownGoodStackTop - CPU_STACK_ALIGNMENT;
+ StackTop = (UINTN)ALIGN_POINTER (StackTop, CPU_STACK_ALIGNMENT);
+ IdtTable = StackSwitchData->X64.IdtTable;
+ for (Index = 0; Index < StackSwitchData->X64.StackSwitchExceptionNumber; ++Index) {
+ //
+ // Fixup IST
+ //
+ Tss->IST[Index] = StackTop;
+ StackTop -= StackSwitchData->X64.KnownGoodStackSize;
+
+ //
+ // Set the IST field to enable corresponding IST
+ //
+ Vector = StackSwitchData->X64.StackSwitchExceptions[Index];
+ if (Vector >= CPU_EXCEPTION_NUM ||
+ Vector >= (Idtr.Limit + 1) / sizeof (IA32_IDT_GATE_DESCRIPTOR)) {
+ continue;
+ }
+ IdtTable[Vector].Bits.Reserved_0 = (UINT8)(Index + 1);
+ }
+
+ //
+ // Publish GDT
+ //
+ AsmWriteGdtr (&Gdtr);
+
+ //
+ // Load current task
+ //
+ AsmWriteTr ((UINT16)((UINTN)StackSwitchData->X64.ExceptionTssDesc - Gdtr.Base));
+
+ //
+ // Publish IDT
+ //
+ AsmWriteIdtr (&Idtr);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+EFIAPI
+DumpCpuContext (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ InternalPrintMessage (
+ "!!!! X64 Exception Type - %02x(%a) CPU Apic ID - %08x !!!!\n",
+ ExceptionType,
+ GetExceptionNameStr (ExceptionType),
+ GetApicId ()
+ );
+ if ((mErrorCodeFlag & (1 << ExceptionType)) != 0) {
+ InternalPrintMessage (
+ "ExceptionData - %016lx",
+ SystemContext.SystemContextX64->ExceptionData
+ );
+ if (ExceptionType == EXCEPT_IA32_PAGE_FAULT) {
+ InternalPrintMessage (
+ " I:%x R:%x U:%x W:%x P:%x PK:%x SS:%x SGX:%x",
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_RSVD) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_US) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_WR) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_P) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_PK) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SS) != 0,
+ (SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_SGX) != 0
+ );
+ }
+ InternalPrintMessage ("\n");
+ }
+ InternalPrintMessage (
+ "RIP - %016lx, CS - %016lx, RFLAGS - %016lx\n",
+ SystemContext.SystemContextX64->Rip,
+ SystemContext.SystemContextX64->Cs,
+ SystemContext.SystemContextX64->Rflags
+ );
+ InternalPrintMessage (
+ "RAX - %016lx, RCX - %016lx, RDX - %016lx\n",
+ SystemContext.SystemContextX64->Rax,
+ SystemContext.SystemContextX64->Rcx,
+ SystemContext.SystemContextX64->Rdx
+ );
+ InternalPrintMessage (
+ "RBX - %016lx, RSP - %016lx, RBP - %016lx\n",
+ SystemContext.SystemContextX64->Rbx,
+ SystemContext.SystemContextX64->Rsp,
+ SystemContext.SystemContextX64->Rbp
+ );
+ InternalPrintMessage (
+ "RSI - %016lx, RDI - %016lx\n",
+ SystemContext.SystemContextX64->Rsi,
+ SystemContext.SystemContextX64->Rdi
+ );
+ InternalPrintMessage (
+ "R8 - %016lx, R9 - %016lx, R10 - %016lx\n",
+ SystemContext.SystemContextX64->R8,
+ SystemContext.SystemContextX64->R9,
+ SystemContext.SystemContextX64->R10
+ );
+ InternalPrintMessage (
+ "R11 - %016lx, R12 - %016lx, R13 - %016lx\n",
+ SystemContext.SystemContextX64->R11,
+ SystemContext.SystemContextX64->R12,
+ SystemContext.SystemContextX64->R13
+ );
+ InternalPrintMessage (
+ "R14 - %016lx, R15 - %016lx\n",
+ SystemContext.SystemContextX64->R14,
+ SystemContext.SystemContextX64->R15
+ );
+ InternalPrintMessage (
+ "DS - %016lx, ES - %016lx, FS - %016lx\n",
+ SystemContext.SystemContextX64->Ds,
+ SystemContext.SystemContextX64->Es,
+ SystemContext.SystemContextX64->Fs
+ );
+ InternalPrintMessage (
+ "GS - %016lx, SS - %016lx\n",
+ SystemContext.SystemContextX64->Gs,
+ SystemContext.SystemContextX64->Ss
+ );
+ InternalPrintMessage (
+ "CR0 - %016lx, CR2 - %016lx, CR3 - %016lx\n",
+ SystemContext.SystemContextX64->Cr0,
+ SystemContext.SystemContextX64->Cr2,
+ SystemContext.SystemContextX64->Cr3
+ );
+ InternalPrintMessage (
+ "CR4 - %016lx, CR8 - %016lx\n",
+ SystemContext.SystemContextX64->Cr4,
+ SystemContext.SystemContextX64->Cr8
+ );
+ InternalPrintMessage (
+ "DR0 - %016lx, DR1 - %016lx, DR2 - %016lx\n",
+ SystemContext.SystemContextX64->Dr0,
+ SystemContext.SystemContextX64->Dr1,
+ SystemContext.SystemContextX64->Dr2
+ );
+ InternalPrintMessage (
+ "DR3 - %016lx, DR6 - %016lx, DR7 - %016lx\n",
+ SystemContext.SystemContextX64->Dr3,
+ SystemContext.SystemContextX64->Dr6,
+ SystemContext.SystemContextX64->Dr7
+ );
+ InternalPrintMessage (
+ "GDTR - %016lx %016lx, LDTR - %016lx\n",
+ SystemContext.SystemContextX64->Gdtr[0],
+ SystemContext.SystemContextX64->Gdtr[1],
+ SystemContext.SystemContextX64->Ldtr
+ );
+ InternalPrintMessage (
+ "IDTR - %016lx %016lx, TR - %016lx\n",
+ SystemContext.SystemContextX64->Idtr[0],
+ SystemContext.SystemContextX64->Idtr[1],
+ SystemContext.SystemContextX64->Tr
+ );
+ InternalPrintMessage (
+ "FXSAVE_STATE - %016lx\n",
+ &SystemContext.SystemContextX64->FxSaveState
+ );
+}
+
+/**
+ Display CPU information.
+
+ @param ExceptionType Exception type.
+ @param SystemContext Pointer to EFI_SYSTEM_CONTEXT.
+**/
+VOID
+DumpImageAndCpuContent (
+ IN EFI_EXCEPTION_TYPE ExceptionType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ DumpCpuContext (ExceptionType, SystemContext);
+ //
+ // Dump module image base and module entry point by RIP
+ //
+ if ((ExceptionType == EXCEPT_IA32_PAGE_FAULT) &&
+ ((SystemContext.SystemContextX64->ExceptionData & IA32_PF_EC_ID) != 0)) {
+ //
+ // The RIP in SystemContext could not be used
+ // if it is page fault with I/D set.
+ //
+ DumpModuleImageInfo ((*(UINTN *)(UINTN)SystemContext.SystemContextX64->Rsp));
+ } else {
+ DumpModuleImageInfo (SystemContext.SystemContextX64->Rip);
+ }
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h
new file mode 100644
index 00000000..97271c04
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ArchInterruptDefs.h
@@ -0,0 +1,43 @@
+/** @file
+ X64 arch definition for CPU Exception Handler Library.
+
+ Copyright (c) 2013, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _ARCH_CPU_INTERRUPT_DEFS_H_
+#define _ARCH_CPU_INTERRUPT_DEFS_H_
+
+typedef struct {
+ EFI_SYSTEM_CONTEXT_X64 SystemContext;
+ BOOLEAN ExceptionDataFlag;
+ UINTN OldIdtHandler;
+} EXCEPTION_HANDLER_CONTEXT;
+
+//
+// Register Structure Definitions
+//
+typedef struct {
+ EFI_STATUS_CODE_DATA Header;
+ EFI_SYSTEM_CONTEXT_X64 SystemContext;
+} CPU_STATUS_CODE_TEMPLATE;
+
+typedef struct {
+ SPIN_LOCK SpinLock;
+ UINT32 ApicId;
+ UINT32 Attribute;
+ UINTN ExceptonHandler;
+ UINTN OldSs;
+ UINTN OldSp;
+ UINTN OldFlags;
+ UINTN OldCs;
+ UINTN OldIp;
+ UINTN ExceptionData;
+ UINT8 HookAfterStubHeaderCode[HOOKAFTER_STUB_SIZE];
+} RESERVED_VECTORS_DATA;
+
+#define CPU_TSS_DESC_SIZE sizeof (IA32_TSS_DESCRIPTOR)
+#define CPU_TSS_SIZE sizeof (IA32_TASK_STATE_SEGMENT)
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
new file mode 100644
index 00000000..1f112909
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/ExceptionHandlerAsm.nasm
@@ -0,0 +1,400 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ExceptionHandlerAsm.Asm
+;
+; Abstract:
+;
+; x64 CPU Exception Handler
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+
+;
+; CommonExceptionHandler()
+;
+
+%define VC_EXCEPTION 29
+
+extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
+extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
+extern ASM_PFX(CommonExceptionHandler)
+
+SECTION .data
+
+DEFAULT REL
+SECTION .text
+
+ALIGN 8
+
+AsmIdtVectorBegin:
+%rep 32
+ db 0x6a ; push #VectorNum
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
+ push rax
+ mov rax, ASM_PFX(CommonInterruptEntry)
+ jmp rax
+%endrep
+AsmIdtVectorEnd:
+
+HookAfterStubHeaderBegin:
+ db 0x6a ; push
+@VectorNum:
+ db 0 ; 0 will be fixed
+ push rax
+ mov rax, HookAfterStubHeaderEnd
+ jmp rax
+HookAfterStubHeaderEnd:
+ mov rax, rsp
+ and sp, 0xfff0 ; make sure 16-byte aligned for exception context
+ sub rsp, 0x18 ; reserve room for filling exception data later
+ push rcx
+ mov rcx, [rax + 8]
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jnc .0
+ push qword [rsp] ; push additional rcx to make stack alignment
+.0:
+ xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
+ push qword [rax] ; push rax into stack to keep code consistence
+
+;---------------------------------------;
+; CommonInterruptEntry ;
+;---------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+; Entry from each interrupt with a push eax and eax=interrupt number
+; Stack frame would be as follows as specified in IA32 manuals:
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+; The follow algorithm is used for the common interrupt routine.
+global ASM_PFX(CommonInterruptEntry)
+ASM_PFX(CommonInterruptEntry):
+ cli
+ pop rax
+ ;
+ ; All interrupt handlers are invoked through interrupt gates, so
+ ; IF flag automatically cleared at the entry point
+ ;
+ xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
+ and rcx, 0xFF
+ cmp ecx, 32 ; Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jc HasErrorCode
+
+NoErrorCode:
+
+ ;
+ ; Push a dummy error code on the stack
+ ; to maintain coherent stack map
+ ;
+ push qword [rsp]
+ mov qword [rsp + 8], 0
+HasErrorCode:
+ push rbp
+ mov rbp, rsp
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+
+ ;
+ ; Stack:
+ ; +---------------------+ <-- 16-byte aligned ensured by processor
+ ; + Old SS +
+ ; +---------------------+
+ ; + Old RSP +
+ ; +---------------------+
+ ; + RFlags +
+ ; +---------------------+
+ ; + CS +
+ ; +---------------------+
+ ; + RIP +
+ ; +---------------------+
+ ; + Error Code +
+ ; +---------------------+
+ ; + RCX / Vector Number +
+ ; +---------------------+
+ ; + RBP +
+ ; +---------------------+ <-- RBP, 16-byte aligned
+ ;
+
+ ;
+ ; Since here the stack pointer is 16-byte aligned, so
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ ; is 16-byte aligned
+ ;
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push qword [rbp + 8] ; RCX
+ push rdx
+ push rbx
+ push qword [rbp + 48] ; RSP
+ push qword [rbp] ; RBP
+ push rsi
+ push rdi
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ movzx rax, word [rbp + 56]
+ push rax ; for ss
+ movzx rax, word [rbp + 32]
+ push rax ; for cs
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+ mov [rbp + 8], rcx ; save vector number
+
+;; UINT64 Rip;
+ push qword [rbp + 24]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ xor rax, rax
+ push rax
+ push rax
+ sidt [rsp]
+ mov bx, word [rsp]
+ mov rax, qword [rsp + 2]
+ mov qword [rsp], rax
+ mov word [rsp + 8], bx
+
+ xor rax, rax
+ push rax
+ push rax
+ sgdt [rsp]
+ mov bx, word [rsp]
+ mov rax, qword [rsp + 2]
+ mov qword [rsp], rax
+ mov word [rsp + 8], bx
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+ push qword [rbp + 40]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 0x208
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ xor rax, rax
+ push rax
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ cmp qword [rbp + 8], VC_EXCEPTION
+ je VcDebugRegs ; For SEV-ES (#VC) Debug registers ignored
+
+ mov rax, dr7
+ push rax
+ mov rax, dr6
+ push rax
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+ jmp DrFinish
+
+VcDebugRegs:
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
+ xor rax, rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+
+DrFinish:
+;; FX_SAVE_STATE_X64 FxSaveState;
+ sub rsp, 512
+ mov rdi, rsp
+ db 0xf, 0xae, 0x7 ;fxsave [rdi]
+
+;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push qword [rbp + 16]
+
+;; Prepare parameter and call
+ mov rcx, [rbp + 8]
+ mov rdx, rsp
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 4 * 8 + 8
+ mov rax, ASM_PFX(CommonExceptionHandler)
+ call rax
+ add rsp, 4 * 8 + 8
+
+ cli
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ mov rsi, rsp
+ db 0xf, 0xae, 0xE ; fxrstor [rsi]
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add rsp, 8 * 6
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; not for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ pop qword [rbp + 40]
+
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add rsp, 48
+
+;; UINT64 Rip;
+ pop qword [rbp + 24]
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ pop rax
+ ; mov gs, rax ; not for gs
+ pop rax
+ ; mov fs, rax ; not for fs
+ ; (X64 will not use fs and gs, so we do not restore it)
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword [rbp + 32] ; for cs
+ pop qword [rbp + 56] ; for ss
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ add rsp, 8 ; not for rbp
+ pop qword [rbp + 48] ; for rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+ pop rbp
+ add rsp, 16
+ cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp qword [rsp - 32]
+ErrorCode:
+ sub rsp, 8
+ jmp qword [rsp - 24]
+
+DoReturn:
+ cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
+ jz DoIret
+ push rax
+ mov rax, rsp ; save old RSP to rax
+ mov rsp, [rsp + 0x20]
+ push qword [rax + 0x10] ; save CS in new location
+ push qword [rax + 0x8] ; save EIP in new location
+ push qword [rax + 0x18] ; save EFLAGS in new location
+ mov rax, [rax] ; restore rax
+ popfq ; restore EFLAGS
+ DB 0x48 ; prefix to composite "retq" with next "retf"
+ retf ; far return
+DoIret:
+ iretq
+
+;-------------------------------------------------------------------------------------
+; GetTemplateAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+; comments here for definition of address map
+global ASM_PFX(AsmGetTemplateAddressMap)
+ASM_PFX(AsmGetTemplateAddressMap):
+ mov rax, AsmIdtVectorBegin
+ mov qword [rcx], rax
+ mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+ mov rax, HookAfterStubHeaderBegin
+ mov qword [rcx + 0x10], rax
+ ret
+
+;-------------------------------------------------------------------------------------
+; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmVectorNumFixup)
+ASM_PFX(AsmVectorNumFixup):
+ mov rax, rdx
+ mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
+ ret
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm
new file mode 100644
index 00000000..a8edfc01
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/X64/Xcode5ExceptionHandlerAsm.nasm
@@ -0,0 +1,455 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; ExceptionHandlerAsm.Asm
+;
+; Abstract:
+;
+; x64 CPU Exception Handler
+;
+; Notes:
+;
+;------------------------------------------------------------------------------
+%include "Nasm.inc"
+
+;
+; CommonExceptionHandler()
+;
+
+%define VC_EXCEPTION 29
+
+extern ASM_PFX(mErrorCodeFlag) ; Error code flags for exceptions
+extern ASM_PFX(mDoFarReturnFlag) ; Do far return flag
+extern ASM_PFX(CommonExceptionHandler)
+extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+
+SECTION .data
+
+DEFAULT REL
+SECTION .text
+
+ALIGN 8
+
+AsmIdtVectorBegin:
+%rep 32
+ db 0x6a ; push #VectorNum
+ db ($ - AsmIdtVectorBegin) / ((AsmIdtVectorEnd - AsmIdtVectorBegin) / 32) ; VectorNum
+ push rax
+ mov rax, strict qword 0 ; mov rax, ASM_PFX(CommonInterruptEntry)
+ jmp rax
+%endrep
+AsmIdtVectorEnd:
+
+HookAfterStubHeaderBegin:
+ db 0x6a ; push
+@VectorNum:
+ db 0 ; 0 will be fixed
+ push rax
+ mov rax, strict qword 0 ; mov rax, HookAfterStubHeaderEnd
+JmpAbsoluteAddress:
+ jmp rax
+HookAfterStubHeaderEnd:
+ mov rax, rsp
+ and sp, 0xfff0 ; make sure 16-byte aligned for exception context
+ sub rsp, 0x18 ; reserve room for filling exception data later
+ push rcx
+ mov rcx, [rax + 8]
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jnc .0
+ push qword [rsp] ; push additional rcx to make stack alignment
+.0:
+ xchg rcx, [rsp] ; restore rcx, save Exception Number in stack
+ push qword [rax] ; push rax into stack to keep code consistence
+
+;---------------------------------------;
+; CommonInterruptEntry ;
+;---------------------------------------;
+; The follow algorithm is used for the common interrupt routine.
+; Entry from each interrupt with a push eax and eax=interrupt number
+; Stack frame would be as follows as specified in IA32 manuals:
+;
+; +---------------------+ <-- 16-byte aligned ensured by processor
+; + Old SS +
+; +---------------------+
+; + Old RSP +
+; +---------------------+
+; + RFlags +
+; +---------------------+
+; + CS +
+; +---------------------+
+; + RIP +
+; +---------------------+
+; + Error Code +
+; +---------------------+
+; + Vector Number +
+; +---------------------+
+; + RBP +
+; +---------------------+ <-- RBP, 16-byte aligned
+; The follow algorithm is used for the common interrupt routine.
+global ASM_PFX(CommonInterruptEntry)
+ASM_PFX(CommonInterruptEntry):
+ cli
+ pop rax
+ ;
+ ; All interrupt handlers are invoked through interrupt gates, so
+ ; IF flag automatically cleared at the entry point
+ ;
+ xchg rcx, [rsp] ; Save rcx into stack and save vector number into rcx
+ and rcx, 0xFF
+ cmp ecx, 32 ; Intel reserved vector for exceptions?
+ jae NoErrorCode
+ bt [ASM_PFX(mErrorCodeFlag)], ecx
+ jc HasErrorCode
+
+NoErrorCode:
+
+ ;
+ ; Push a dummy error code on the stack
+ ; to maintain coherent stack map
+ ;
+ push qword [rsp]
+ mov qword [rsp + 8], 0
+HasErrorCode:
+ push rbp
+ mov rbp, rsp
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ push 0 ; clear EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+
+ ;
+ ; Stack:
+ ; +---------------------+ <-- 16-byte aligned ensured by processor
+ ; + Old SS +
+ ; +---------------------+
+ ; + Old RSP +
+ ; +---------------------+
+ ; + RFlags +
+ ; +---------------------+
+ ; + CS +
+ ; +---------------------+
+ ; + RIP +
+ ; +---------------------+
+ ; + Error Code +
+ ; +---------------------+
+ ; + RCX / Vector Number +
+ ; +---------------------+
+ ; + RBP +
+ ; +---------------------+ <-- RBP, 16-byte aligned
+ ;
+
+ ;
+ ; Since here the stack pointer is 16-byte aligned, so
+ ; EFI_FX_SAVE_STATE_X64 of EFI_SYSTEM_CONTEXT_x64
+ ; is 16-byte aligned
+ ;
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ push r15
+ push r14
+ push r13
+ push r12
+ push r11
+ push r10
+ push r9
+ push r8
+ push rax
+ push qword [rbp + 8] ; RCX
+ push rdx
+ push rbx
+ push qword [rbp + 48] ; RSP
+ push qword [rbp] ; RBP
+ push rsi
+ push rdi
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss; insure high 16 bits of each is zero
+ movzx rax, word [rbp + 56]
+ push rax ; for ss
+ movzx rax, word [rbp + 32]
+ push rax ; for cs
+ mov rax, ds
+ push rax
+ mov rax, es
+ push rax
+ mov rax, fs
+ push rax
+ mov rax, gs
+ push rax
+
+ mov [rbp + 8], rcx ; save vector number
+
+;; UINT64 Rip;
+ push qword [rbp + 24]
+
+;; UINT64 Gdtr[2], Idtr[2];
+ xor rax, rax
+ push rax
+ push rax
+ sidt [rsp]
+ mov bx, word [rsp]
+ mov rax, qword [rsp + 2]
+ mov qword [rsp], rax
+ mov word [rsp + 8], bx
+
+ xor rax, rax
+ push rax
+ push rax
+ sgdt [rsp]
+ mov bx, word [rsp]
+ mov rax, qword [rsp + 2]
+ mov qword [rsp], rax
+ mov word [rsp + 8], bx
+
+;; UINT64 Ldtr, Tr;
+ xor rax, rax
+ str ax
+ push rax
+ sldt ax
+ push rax
+
+;; UINT64 RFlags;
+ push qword [rbp + 40]
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ mov rax, cr8
+ push rax
+ mov rax, cr4
+ or rax, 0x208
+ mov cr4, rax
+ push rax
+ mov rax, cr3
+ push rax
+ mov rax, cr2
+ push rax
+ xor rax, rax
+ push rax
+ mov rax, cr0
+ push rax
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+ cmp qword [rbp + 8], VC_EXCEPTION
+ je VcDebugRegs ; For SEV-ES (#VC) Debug registers ignored
+
+ mov rax, dr7
+ push rax
+ mov rax, dr6
+ push rax
+ mov rax, dr3
+ push rax
+ mov rax, dr2
+ push rax
+ mov rax, dr1
+ push rax
+ mov rax, dr0
+ push rax
+ jmp DrFinish
+
+VcDebugRegs:
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7 are skipped for #VC to avoid exception recursion
+ xor rax, rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+ push rax
+
+DrFinish:
+;; FX_SAVE_STATE_X64 FxSaveState;
+ sub rsp, 512
+ mov rdi, rsp
+ db 0xf, 0xae, 0x7 ;fxsave [rdi]
+
+;; UEFI calling convention for x64 requires that Direction flag in EFLAGs is clear
+ cld
+
+;; UINT32 ExceptionData;
+ push qword [rbp + 16]
+
+;; Prepare parameter and call
+ mov rcx, [rbp + 8]
+ mov rdx, rsp
+ ;
+ ; Per X64 calling convention, allocate maximum parameter stack space
+ ; and make sure RSP is 16-byte aligned
+ ;
+ sub rsp, 4 * 8 + 8
+ call ASM_PFX(CommonExceptionHandler)
+ add rsp, 4 * 8 + 8
+
+ cli
+;; UINT64 ExceptionData;
+ add rsp, 8
+
+;; FX_SAVE_STATE_X64 FxSaveState;
+
+ mov rsi, rsp
+ db 0xf, 0xae, 0xE ; fxrstor [rsi]
+ add rsp, 512
+
+;; UINT64 Dr0, Dr1, Dr2, Dr3, Dr6, Dr7;
+;; Skip restoration of DRx registers to support in-circuit emualators
+;; or debuggers set breakpoint in interrupt/exception context
+ add rsp, 8 * 6
+
+;; UINT64 Cr0, Cr1, Cr2, Cr3, Cr4, Cr8;
+ pop rax
+ mov cr0, rax
+ add rsp, 8 ; not for Cr1
+ pop rax
+ mov cr2, rax
+ pop rax
+ mov cr3, rax
+ pop rax
+ mov cr4, rax
+ pop rax
+ mov cr8, rax
+
+;; UINT64 RFlags;
+ pop qword [rbp + 40]
+
+;; UINT64 Ldtr, Tr;
+;; UINT64 Gdtr[2], Idtr[2];
+;; Best not let anyone mess with these particular registers...
+ add rsp, 48
+
+;; UINT64 Rip;
+ pop qword [rbp + 24]
+
+;; UINT64 Gs, Fs, Es, Ds, Cs, Ss;
+ pop rax
+ ; mov gs, rax ; not for gs
+ pop rax
+ ; mov fs, rax ; not for fs
+ ; (X64 will not use fs and gs, so we do not restore it)
+ pop rax
+ mov es, rax
+ pop rax
+ mov ds, rax
+ pop qword [rbp + 32] ; for cs
+ pop qword [rbp + 56] ; for ss
+
+;; UINT64 Rdi, Rsi, Rbp, Rsp, Rbx, Rdx, Rcx, Rax;
+;; UINT64 R8, R9, R10, R11, R12, R13, R14, R15;
+ pop rdi
+ pop rsi
+ add rsp, 8 ; not for rbp
+ pop qword [rbp + 48] ; for rsp
+ pop rbx
+ pop rdx
+ pop rcx
+ pop rax
+ pop r8
+ pop r9
+ pop r10
+ pop r11
+ pop r12
+ pop r13
+ pop r14
+ pop r15
+
+ mov rsp, rbp
+ pop rbp
+ add rsp, 16
+ cmp qword [rsp - 32], 0 ; check EXCEPTION_HANDLER_CONTEXT.OldIdtHandler
+ jz DoReturn
+ cmp qword [rsp - 40], 1 ; check EXCEPTION_HANDLER_CONTEXT.ExceptionDataFlag
+ jz ErrorCode
+ jmp qword [rsp - 32]
+ErrorCode:
+ sub rsp, 8
+ jmp qword [rsp - 24]
+
+DoReturn:
+ cmp qword [ASM_PFX(mDoFarReturnFlag)], 0 ; Check if need to do far return instead of IRET
+ jz DoIret
+ push rax
+ mov rax, rsp ; save old RSP to rax
+ mov rsp, [rsp + 0x20]
+ push qword [rax + 0x10] ; save CS in new location
+ push qword [rax + 0x8] ; save EIP in new location
+ push qword [rax + 0x18] ; save EFLAGS in new location
+ mov rax, [rax] ; restore rax
+ popfq ; restore EFLAGS
+
+ ; The follow algorithm is used for clear shadow stack token busy bit.
+ ; The comment is based on the sample shadow stack.
+ ; The sample shadow stack layout :
+ ; Address | Context
+ ; +-------------------------+
+ ; 0xFD0 | FREE | it is 0xFD8|0x02|(LMA & CS.L), after SAVEPREVSSP.
+ ; +-------------------------+
+ ; 0xFD8 | Prev SSP |
+ ; +-------------------------+
+ ; 0xFE0 | RIP |
+ ; +-------------------------+
+ ; 0xFE8 | CS |
+ ; +-------------------------+
+ ; 0xFF0 | 0xFF0 | BUSY | BUSY flag cleared after CLRSSBSY
+ ; +-------------------------+
+ ; 0xFF8 | 0xFD8|0x02|(LMA & CS.L) |
+ ; +-------------------------+
+ ; Instructions for Intel Control Flow Enforcement Technology (CET) are supported since NASM version 2.15.01.
+ push rax ; SSP should be 0xFD8 at this point
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0
+ jz CetDone
+ mov rax, cr4
+ and rax, 0x800000 ; check if CET is enabled
+ jz CetDone
+ mov rax, 0x04 ; advance past cs:lip:prevssp;supervisor shadow stack token
+ INCSSP_RAX ; After this SSP should be 0xFF8
+ SAVEPREVSSP ; now the shadow stack restore token will be created at 0xFD0
+ READSSP_RAX ; Read new SSP, SSP should be 0x1000
+ push rax
+ sub rax, 0x10
+ CLRSSBSY_RAX ; Clear token at 0xFF0, SSP should be 0 after this
+ sub rax, 0x20
+ RSTORSSP_RAX ; Restore to token at 0xFD0, new SSP will be 0xFD0
+ pop rax
+ mov rax, 0x01 ; Pop off the new save token created
+ INCSSP_RAX ; SSP should be 0xFD8 now
+CetDone:
+ pop rax ; restore rax
+
+ DB 0x48 ; prefix to composite "retq" with next "retf"
+ retf ; far return
+DoIret:
+ iretq
+
+;-------------------------------------------------------------------------------------
+; GetTemplateAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+; comments here for definition of address map
+global ASM_PFX(AsmGetTemplateAddressMap)
+ASM_PFX(AsmGetTemplateAddressMap):
+ lea rax, [AsmIdtVectorBegin]
+ mov qword [rcx], rax
+ mov qword [rcx + 0x8], (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+ lea rax, [HookAfterStubHeaderBegin]
+ mov qword [rcx + 0x10], rax
+
+; Fix up CommonInterruptEntry address
+ lea rax, [ASM_PFX(CommonInterruptEntry)]
+ lea rcx, [AsmIdtVectorBegin]
+%rep 32
+ mov qword [rcx + (JmpAbsoluteAddress - 8 - HookAfterStubHeaderBegin)], rax
+ add rcx, (AsmIdtVectorEnd - AsmIdtVectorBegin) / 32
+%endrep
+; Fix up HookAfterStubHeaderEnd
+ lea rax, [HookAfterStubHeaderEnd]
+ lea rcx, [JmpAbsoluteAddress]
+ mov qword [rcx - 8], rax
+
+ ret
+
+;-------------------------------------------------------------------------------------
+; AsmVectorNumFixup (*NewVectorAddr, VectorNum, *OldVectorAddr);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmVectorNumFixup)
+ASM_PFX(AsmVectorNumFixup):
+ mov rax, rdx
+ mov [rcx + (@VectorNum - HookAfterStubHeaderBegin)], al
+ ret
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
new file mode 100644
index 00000000..76616cc4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.inf
@@ -0,0 +1,60 @@
+## @file
+# CPU Exception Handler library instance for SEC/PEI modules.
+#
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+# Copyright (c) 2012 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+# This is the XCODE5 variant of the SEC/PEI CpuExceptionHandlerLib. This
+# variant performs binary patching to fix up addresses that allow the
+# XCODE5 toolchain to be used.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Xcode5SecPeiCpuExceptionHandlerLib
+ MODULE_UNI_FILE = Xcode5SecPeiCpuExceptionHandlerLib.uni
+ FILE_GUID = 49C481AF-1621-42F3-8FA1-27C64143E304
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = CpuExceptionHandlerLib|SEC PEI_CORE PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.Ia32]
+ Ia32/ExceptionHandlerAsm.nasm
+ Ia32/ExceptionTssEntryAsm.nasm
+ Ia32/ArchExceptionHandler.c
+ Ia32/ArchInterruptDefs.h
+
+[Sources.X64]
+ X64/Xcode5ExceptionHandlerAsm.nasm
+ X64/ArchExceptionHandler.c
+ X64/ArchInterruptDefs.h
+
+[Sources.common]
+ CpuExceptionCommon.h
+ CpuExceptionCommon.c
+ SecPeiCpuException.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ SerialPortLib
+ PrintLib
+ LocalApicLib
+ PeCoffGetEntryPointLib
+ VmgExitLib
+
+[FeaturePcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.uni
new file mode 100644
index 00000000..a63b25f3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuExceptionHandlerLib/Xcode5SecPeiCpuExceptionHandlerLib.uni
@@ -0,0 +1,18 @@
+// /** @file
+// XCODE5 CPU Exception Handler library instance for SEC/PEI modules.
+//
+// CPU Exception Handler library instance for SEC/PEI modules when built
+// using the XCODE5 toolchain.
+//
+// Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+// Copyright (c) 2012 - 2014, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Exception Handler library instance for SEC/PEI modules with the XCODE5 toolchain."
+
+#string STR_MODULE_DESCRIPTION #language en-US "CPU Exception Handler library instance for SEC/PEI modules with the XCODE5 toolchain."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
new file mode 100644
index 00000000..3b8d863a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.c
@@ -0,0 +1,41 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance as Base Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ );
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ )
+{
+ return CpuidCoreClockCalculateTscFrequency ();
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
new file mode 100644
index 00000000..658e28e8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.inf
@@ -0,0 +1,35 @@
+## @file
+# Base CPU Timer Library
+#
+# Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+# counter features are provided by the processors time stamp counter.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseCpuTimerLib
+ FILE_GUID = F10B5B91-D15A-496C-B044-B5235721AA08
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+ MODULE_UNI_FILE = BaseCpuTimerLib.uni
+
+[Sources]
+ CpuTimerLib.c
+ BaseCpuTimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuCoreCrystalClockFrequency ## CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
new file mode 100644
index 00000000..fcf2b0fb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/BaseCpuTimerLib.uni
@@ -0,0 +1,17 @@
+// /** @file
+// Base CPU Timer Library
+//
+// Provides basic timer support using CPUID Leaf 0x15 XTAL frequency. The performance
+// counter features are provided by the processors time stamp counter.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "CPU Timer Library"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Provides basic timer support using CPUID Leaf 0x15 XTAL frequency."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
new file mode 100644
index 00000000..89135bd1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/CpuTimerLib/CpuTimerLib.c
@@ -0,0 +1,279 @@
+/** @file
+ CPUID Leaf 0x15 for Core Crystal Clock frequency instance of Timer Library.
+
+ Copyright (c) 2019 Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Cpuid.h>
+
+GUID mCpuCrystalFrequencyHobGuid = { 0xe1ec5ad0, 0x8569, 0x46bd, { 0x8d, 0xcd, 0x3b, 0x9f, 0x6f, 0x45, 0x82, 0x7a } };
+
+/**
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ Internal function to retrieves the 64-bit frequency in Hz.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+InternalGetPerformanceCounterFrequency (
+ VOID
+ );
+
+/**
+ CPUID Leaf 0x15 for Core Crystal Clock Frequency.
+
+ The TSC counting frequency is determined by using CPUID leaf 0x15. Frequency in MHz = Core XTAL frequency * EBX/EAX.
+ In newer flavors of the CPU, core xtal frequency is returned in ECX or 0 if not supported.
+ @return The number of TSC counts per second.
+
+**/
+UINT64
+CpuidCoreClockCalculateTscFrequency (
+ VOID
+ )
+{
+ UINT64 TscFrequency;
+ UINT64 CoreXtalFrequency;
+ UINT32 RegEax;
+ UINT32 RegEbx;
+ UINT32 RegEcx;
+
+ //
+ // Use CPUID leaf 0x15 Time Stamp Counter and Nominal Core Crystal Clock Information
+ // EBX returns 0 if not supported. ECX, if non zero, provides Core Xtal Frequency in hertz.
+ // TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX.
+ //
+ AsmCpuid (CPUID_TIME_STAMP_COUNTER, &RegEax, &RegEbx, &RegEcx, NULL);
+
+ //
+ // If EAX or EBX returns 0, the XTAL ratio is not enumerated.
+ //
+ if (RegEax == 0 || RegEbx ==0 ) {
+ ASSERT (RegEax != 0);
+ ASSERT (RegEbx != 0);
+ return 0;
+ }
+ //
+ // If ECX returns 0, the XTAL frequency is not enumerated.
+ // And PcdCpuCoreCrystalClockFrequency defined should base on processor series.
+ //
+ if (RegEcx == 0) {
+ CoreXtalFrequency = PcdGet64 (PcdCpuCoreCrystalClockFrequency);
+ } else {
+ CoreXtalFrequency = (UINT64) RegEcx;
+ }
+
+ //
+ // Calculate TSC frequency = (ECX, Core Xtal Frequency) * EBX/EAX
+ //
+ TscFrequency = DivU64x32 (MultU64x32 (CoreXtalFrequency, RegEbx) + (UINT64)(RegEax >> 1), RegEax);
+
+ return TscFrequency;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+InternalCpuDelay (
+ IN UINT64 Delay
+ )
+{
+ UINT64 Ticks;
+
+ //
+ // The target timer count is calculated here
+ //
+ Ticks = AsmReadTsc() + Delay;
+
+ //
+ // Wait until time out
+ // Timer wrap-arounds are NOT handled correctly by this function.
+ // Thus, this function must be called within 10 years of reset since
+ // Intel guarantees a minimum of 10 years before the TSC wraps.
+ //
+ while (AsmReadTsc() <= Ticks) {
+ CpuPause();
+ }
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param[in] MicroSeconds The minimum number of microseconds to delay.
+
+ @return MicroSeconds
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ MicroSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000u
+ )
+ );
+
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return NanoSeconds
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+
+ InternalCpuDelay (
+ DivU64x32 (
+ MultU64x64 (
+ NanoSeconds,
+ InternalGetPerformanceCounterFrequency ()
+ ),
+ 1000000000u
+ )
+ );
+
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ Retrieves the current value of a 64-bit free running performance counter. The
+ counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return AsmReadTsc ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = 0;
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0xffffffffffffffffULL;
+ }
+ return InternalGetPerformanceCounterFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c
new file mode 100644
index 00000000..e2f1cfc2
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.c
@@ -0,0 +1,322 @@
+/** @file
+ Implementation of MicrocodeLib.
+
+ Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi/UefiBaseType.h>
+#include <Register/Intel/Cpuid.h>
+#include <Register/Intel/ArchitecturalMsr.h>
+#include <Register/Intel/Microcode.h>
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Ppi/ShadowMicrocode.h>
+
+/**
+ Get microcode update signature of currently loaded microcode update.
+
+ @return Microcode signature.
+**/
+UINT32
+EFIAPI
+GetProcessorMicrocodeSignature (
+ VOID
+ )
+{
+ MSR_IA32_BIOS_SIGN_ID_REGISTER BiosSignIdMsr;
+
+ AsmWriteMsr64 (MSR_IA32_BIOS_SIGN_ID, 0);
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, NULL);
+ BiosSignIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_BIOS_SIGN_ID);
+ return BiosSignIdMsr.Bits.MicrocodeUpdateSignature;
+}
+
+/**
+ Get the processor signature and platform ID for current processor.
+
+ @param MicrocodeCpuId Return the processor signature and platform ID.
+**/
+VOID
+EFIAPI
+GetProcessorMicrocodeCpuId (
+ EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId
+ )
+{
+ MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
+
+ ASSERT (MicrocodeCpuId != NULL);
+
+ PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
+ MicrocodeCpuId->PlatformId = (UINT8) PlatformIdMsr.Bits.PlatformId;
+ AsmCpuid (CPUID_VERSION_INFO, &MicrocodeCpuId->ProcessorSignature, NULL, NULL, NULL);
+}
+
+/**
+ Return the total size of the microcode entry.
+
+ Logic follows pseudo code in SDM as below:
+
+ N = 512
+ If (Update.DataSize != 00000000H)
+ N = Update.TotalSize / 4
+
+ If Microcode is NULL, then ASSERT.
+
+ @param Microcode Pointer to the microcode entry.
+
+ @return The microcode total size.
+**/
+UINT32
+EFIAPI
+GetMicrocodeLength (
+ IN CPU_MICROCODE_HEADER *Microcode
+ )
+{
+ UINT32 TotalSize;
+
+ ASSERT (Microcode != NULL);
+
+ TotalSize = 2048;
+ if (Microcode->DataSize != 0) {
+ TotalSize = Microcode->TotalSize;
+ }
+ return TotalSize;
+}
+
+/**
+ Load the microcode to the processor.
+
+ If Microcode is NULL, then ASSERT.
+
+ @param Microcode Pointer to the microcode entry.
+**/
+VOID
+EFIAPI
+LoadMicrocode (
+ IN CPU_MICROCODE_HEADER *Microcode
+ )
+{
+ ASSERT (Microcode != NULL);
+
+ AsmWriteMsr64 (MSR_IA32_BIOS_UPDT_TRIG, (UINT64) (UINTN) (Microcode + 1));
+}
+
+/**
+ Determine if a microcode patch matchs the specific processor signature and flag.
+
+ @param[in] ProcessorSignature The processor signature field value in a
+ microcode patch.
+ @param[in] ProcessorFlags The processor flags field value in a
+ microcode patch.
+ @param[in] MicrocodeCpuId A pointer to an array of EDKII_PEI_MICROCODE_CPU_ID
+ structures.
+ @param[in] MicrocodeCpuIdCount Number of elements in MicrocodeCpuId array.
+
+ @retval TRUE The specified microcode patch matches to one of the MicrocodeCpuId.
+ @retval FALSE The specified microcode patch doesn't match to any of the MicrocodeCpuId.
+**/
+BOOLEAN
+IsProcessorMatchedMicrocode (
+ IN UINT32 ProcessorSignature,
+ IN UINT32 ProcessorFlags,
+ IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId,
+ IN UINTN MicrocodeCpuIdCount
+ )
+{
+ UINTN Index;
+
+ if (MicrocodeCpuIdCount == 0) {
+ return TRUE;
+ }
+
+ for (Index = 0; Index < MicrocodeCpuIdCount; Index++) {
+ if ((ProcessorSignature == MicrocodeCpuId[Index].ProcessorSignature) &&
+ (ProcessorFlags & (1 << MicrocodeCpuId[Index].PlatformId)) != 0) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+ Microcode format is as below:
+ +----------------------------------------+-------------------------------------------------+
+ | CPU_MICROCODE_HEADER | |
+ +----------------------------------------+ V
+ | Update Data | CPU_MICROCODE_HEADER.Checksum
+ +----------------------------------------+-------+ ^
+ | CPU_MICROCODE_EXTENDED_TABLE_HEADER | | |
+ +----------------------------------------+ V |
+ | CPU_MICROCODE_EXTENDED_TABLE[0] | CPU_MICROCODE_EXTENDED_TABLE_HEADER.Checksum |
+ | CPU_MICROCODE_EXTENDED_TABLE[1] | ^ |
+ | ... | | |
+ +----------------------------------------+-------+-----------------------------------------+
+
+ There may by multiple CPU_MICROCODE_EXTENDED_TABLE in this format.
+ The count of CPU_MICROCODE_EXTENDED_TABLE is indicated by ExtendedSignatureCount
+ of CPU_MICROCODE_EXTENDED_TABLE_HEADER structure.
+
+ If Microcode is NULL, then ASSERT.
+
+ @param Microcode Pointer to a microcode entry.
+ @param MicrocodeLength The total length of the microcode entry.
+ @param MinimumRevision The microcode whose revision <= MinimumRevision is treated as invalid.
+ Caller can supply value get from GetProcessorMicrocodeSignature() to check
+ whether the microcode is newer than loaded one.
+ Caller can supply 0 to treat any revision (except 0) microcode as valid.
+ @param MicrocodeCpuIds Pointer to an array of processor signature and platform ID that represents
+ a set of processors.
+ Caller can supply zero-element array to skip the processor signature and
+ platform ID check.
+ @param MicrocodeCpuIdCount The number of elements in MicrocodeCpuIds.
+ @param VerifyChecksum FALSE to skip all the checksum verifications.
+
+ @retval TRUE The microcode is valid.
+ @retval FALSE The microcode is invalid.
+**/
+BOOLEAN
+EFIAPI
+IsValidMicrocode (
+ IN CPU_MICROCODE_HEADER *Microcode,
+ IN UINTN MicrocodeLength,
+ IN UINT32 MinimumRevision,
+ IN EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds,
+ IN UINTN MicrocodeCpuIdCount,
+ IN BOOLEAN VerifyChecksum
+ )
+{
+ UINTN Index;
+ UINT32 DataSize;
+ UINT32 TotalSize;
+ CPU_MICROCODE_EXTENDED_TABLE *ExtendedTable;
+ CPU_MICROCODE_EXTENDED_TABLE_HEADER *ExtendedTableHeader;
+ UINT32 ExtendedTableLength;
+ UINT32 Sum32;
+ BOOLEAN Match;
+
+ ASSERT (Microcode != NULL);
+
+ //
+ // It's invalid when:
+ // the input microcode buffer is so small that even cannot contain the header.
+ // the input microcode buffer is so large that exceeds MAX_ADDRESS.
+ //
+ if ((MicrocodeLength < sizeof (CPU_MICROCODE_HEADER)) || (MicrocodeLength > (MAX_ADDRESS - (UINTN) Microcode))) {
+ return FALSE;
+ }
+
+ //
+ // Per SDM, HeaderVersion and LoaderRevision should both be 1.
+ //
+ if ((Microcode->HeaderVersion != 1) || (Microcode->LoaderRevision != 1)) {
+ return FALSE;
+ }
+
+ //
+ // The microcode revision should be larger than the minimum revision.
+ //
+ if (Microcode->UpdateRevision <= MinimumRevision) {
+ return FALSE;
+ }
+
+ DataSize = Microcode->DataSize;
+ if (DataSize == 0) {
+ DataSize = 2000;
+ }
+
+ //
+ // Per SDM, DataSize should be multiple of DWORDs.
+ //
+ if ((DataSize % 4) != 0) {
+ return FALSE;
+ }
+
+ TotalSize = GetMicrocodeLength (Microcode);
+
+ //
+ // Check whether the whole microcode is within the buffer.
+ // TotalSize should be multiple of 1024.
+ //
+ if (((TotalSize % SIZE_1KB) != 0) || (TotalSize > MicrocodeLength)) {
+ return FALSE;
+ }
+
+ //
+ // The summation of all DWORDs in microcode should be zero.
+ //
+ if (VerifyChecksum && (CalculateSum32 ((UINT32 *) Microcode, TotalSize) != 0)) {
+ return FALSE;
+ }
+
+ Sum32 = Microcode->ProcessorSignature.Uint32 + Microcode->ProcessorFlags + Microcode->Checksum;
+
+ //
+ // Check the processor signature and platform ID in the primary header.
+ //
+ Match = IsProcessorMatchedMicrocode (
+ Microcode->ProcessorSignature.Uint32,
+ Microcode->ProcessorFlags,
+ MicrocodeCpuIds,
+ MicrocodeCpuIdCount
+ );
+ if (Match) {
+ return TRUE;
+ }
+
+ ExtendedTableLength = TotalSize - (DataSize + sizeof (CPU_MICROCODE_HEADER));
+ if ((ExtendedTableLength < sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) || ((ExtendedTableLength % 4) != 0)) {
+ return FALSE;
+ }
+ //
+ // Extended Table exist, check if the CPU in support list
+ //
+ ExtendedTableHeader = (CPU_MICROCODE_EXTENDED_TABLE_HEADER *) ((UINTN) (Microcode + 1) + DataSize);
+ if (ExtendedTableHeader->ExtendedSignatureCount > MAX_UINT32 / sizeof (CPU_MICROCODE_EXTENDED_TABLE)) {
+ return FALSE;
+ }
+ if (ExtendedTableHeader->ExtendedSignatureCount * sizeof (CPU_MICROCODE_EXTENDED_TABLE)
+ > ExtendedTableLength - sizeof (CPU_MICROCODE_EXTENDED_TABLE_HEADER)) {
+ return FALSE;
+ }
+ //
+ // Check the extended table checksum
+ //
+ if (VerifyChecksum && (CalculateSum32 ((UINT32 *) ExtendedTableHeader, ExtendedTableLength) != 0)) {
+ return FALSE;
+ }
+
+ ExtendedTable = (CPU_MICROCODE_EXTENDED_TABLE *) (ExtendedTableHeader + 1);
+ for (Index = 0; Index < ExtendedTableHeader->ExtendedSignatureCount; Index ++) {
+ if (VerifyChecksum &&
+ (ExtendedTable[Index].ProcessorSignature.Uint32 + ExtendedTable[Index].ProcessorFlag
+ + ExtendedTable[Index].Checksum != Sum32)) {
+ //
+ // The extended table entry is valid when the summation of Processor Signature, Processor Flags
+ // and Checksum equal to the coresponding summation from primary header. Because:
+ // CalculateSum32 (Header + Update Binary) == 0
+ // CalculateSum32 (Header + Update Binary)
+ // - (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
+ // + (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum) == 0
+ // So,
+ // (Header.ProcessorSignature + Header.ProcessorFlag + Header.Checksum)
+ // == (Extended.ProcessorSignature + Extended.ProcessorFlag + Extended.Checksum)
+ //
+ continue;
+ }
+ Match = IsProcessorMatchedMicrocode (
+ ExtendedTable[Index].ProcessorSignature.Uint32,
+ ExtendedTable[Index].ProcessorFlag,
+ MicrocodeCpuIds,
+ MicrocodeCpuIdCount
+ );
+ if (Match) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
new file mode 100644
index 00000000..f076eea7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MicrocodeLib/MicrocodeLib.inf
@@ -0,0 +1,32 @@
+## @file
+# Library for microcode verification and load.
+#
+# Copyright (c) 2021, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = MicrocodeLib
+ FILE_GUID = EB8C72BC-8A48-4F80-996B-E52F68416D57
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MicrocodeLib
+
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources.common]
+ MicrocodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
new file mode 100644
index 00000000..e260e17d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.inf
@@ -0,0 +1,78 @@
+## @file
+# MP Initialize Library instance for DXE driver.
+#
+# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeMpInitLib
+ MODULE_UNI_FILE = DxeMpInitLib.uni
+ FILE_GUID = B88F7146-9834-4c55-BFAC-481CC0C33736
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = MpInitLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.IA32]
+ Ia32/MpFuncs.nasm
+
+[Sources.X64]
+ X64/MpFuncs.nasm
+
+[Sources.common]
+ MpEqu.inc
+ DxeMpLib.c
+ MpLib.c
+ MpLib.h
+ Microcode.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ LocalApicLib
+ MemoryAllocationLib
+ HobLib
+ MtrrLib
+ CpuLib
+ UefiCpuLib
+ UefiBootServicesTableLib
+ DebugAgentLib
+ SynchronizationLib
+ PcdLib
+ VmgExitLib
+ MicrocodeLib
+
+[Protocols]
+ gEfiTimerArchProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEfiEventLegacyBootGuid ## SOMETIMES_CONSUMES ## Event
+ gEdkiiMicrocodePatchHobGuid ## SOMETIMES_CONSUMES ## HOB
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStatusCheckIntervalInMicroSeconds ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdCpuStackGuard ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.uni
new file mode 100644
index 00000000..27cfdd37
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpInitLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// MP Initialize Library instance for DXE driver.
+//
+// MP Initialize Library instance for DXE driver.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Library instance for DXE driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Library instance for DXE driver."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
new file mode 100644
index 00000000..16c8e9ca
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/DxeMpLib.c
@@ -0,0 +1,956 @@
+/** @file
+ MP initialize support functions for DXE phase.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DebugAgentLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/VmgExitLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
+
+#include <Protocol/Timer.h>
+
+#define AP_SAFE_STACK_SIZE 128
+
+CPU_MP_DATA *mCpuMpData = NULL;
+EFI_EVENT mCheckAllApsEvent = NULL;
+EFI_EVENT mMpInitExitBootServicesEvent = NULL;
+EFI_EVENT mLegacyBootEvent = NULL;
+volatile BOOLEAN mStopCheckAllApsStatus = TRUE;
+VOID *mReservedApLoopFunc = NULL;
+UINTN mReservedTopOfApStack;
+volatile UINT32 mNumberToFinish = 0;
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ )
+{
+ //
+ // Initialize Debug Agent to support source level debug in DXE phase
+ //
+ InitializeDebugAgent (DEBUG_AGENT_INIT_DXE_AP, NULL, NULL);
+}
+
+/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ ASSERT (mCpuMpData != NULL);
+ return mCpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ mCpuMpData = CpuMpData;
+}
+
+/**
+ Get available system memory below 0x88000 by specified size.
+
+ @param[in] WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ EFI_MEMORY_TYPE MemoryType;
+
+ if (PcdGetBool (PcdSevEsIsEnabled)) {
+ MemoryType = EfiReservedMemoryType;
+ } else {
+ MemoryType = EfiBootServicesData;
+ }
+
+ //
+ // Try to allocate buffer below 1M for waking vector.
+ // LegacyBios driver only reports warning when page allocation in range
+ // [0x60000, 0x88000) fails.
+ // This library is consumed by CpuDxe driver to produce CPU Arch protocol.
+ // LagacyBios driver depends on CPU Arch protocol which guarantees below
+ // allocation runs earlier than LegacyBios driver.
+ //
+ StartAddress = 0x88000;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ MemoryType,
+ EFI_SIZE_TO_PAGES (WakeupBufferSize),
+ &StartAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ if (EFI_ERROR (Status)) {
+ StartAddress = (EFI_PHYSICAL_ADDRESS) -1;
+ }
+
+ DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
+ (UINTN) StartAddress, WakeupBufferSize));
+
+ return (UINTN) StartAddress;
+}
+
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+
+ StartAddress = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (BufferSize),
+ &StartAddress
+ );
+ if (EFI_ERROR (Status)) {
+ StartAddress = 0;
+ }
+
+ return (UINTN)StartAddress;
+}
+
+/**
+ Return the address of the SEV-ES AP jump table.
+
+ This buffer is required in order for an SEV-ES guest to transition from
+ UEFI into an OS.
+
+ @return Return SEV-ES AP jump table buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+ BOOLEAN InterruptState;
+
+ //
+ // Allocate 1 page for AP jump table page
+ //
+ StartAddress = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ 1,
+ &StartAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "Dxe: SevEsAPMemory = %lx\n", (UINTN) StartAddress));
+
+ //
+ // Save the SevEsAPMemory as the AP jump table.
+ //
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ Ghcb = Msr.Ghcb;
+
+ VmgInit (Ghcb, &InterruptState);
+ VmgExit (Ghcb, SVM_EXIT_AP_JUMP_TABLE, 0, (UINT64) (UINTN) StartAddress);
+ VmgDone (Ghcb, InterruptState);
+
+ return (UINTN) StartAddress;
+}
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+ UINTN ProcessorNumber;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // First, check whether pending StartupAllAPs() exists.
+ //
+ if (CpuMpData->WaitEvent != NULL) {
+
+ Status = CheckAllAPs ();
+ //
+ // If all APs finish for StartupAllAPs(), signal the WaitEvent for it.
+ //
+ if (Status != EFI_NOT_READY) {
+ Status = gBS->SignalEvent (CpuMpData->WaitEvent);
+ CpuMpData->WaitEvent = NULL;
+ }
+ }
+
+ //
+ // Second, check whether pending StartupThisAPs() callings exist.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+
+ if (CpuMpData->CpuData[ProcessorNumber].WaitEvent == NULL) {
+ continue;
+ }
+
+ Status = CheckThisAP (ProcessorNumber);
+
+ if (Status != EFI_NOT_READY) {
+ gBS->SignalEvent (CpuMpData->CpuData[ProcessorNumber].WaitEvent);
+ CpuMpData->CpuData[ProcessorNumber].WaitEvent = NULL;
+ }
+ }
+}
+
+/**
+ Checks APs' status periodically.
+
+ This function is triggered by timer periodically to check the
+ state of APs for StartupAllAPs() and StartupThisAP() executed
+ in non-blocking mode.
+
+ @param[in] Event Event triggered.
+ @param[in] Context Parameter passed with the event.
+
+**/
+VOID
+EFIAPI
+CheckApsStatus (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // If CheckApsStatus() is not stopped, otherwise return immediately.
+ //
+ if (!mStopCheckAllApsStatus) {
+ CheckAndUpdateApsStatus ();
+ }
+}
+
+/**
+ Get Protected mode code segment with 16-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 16-bit code segment value.
+**/
+UINT16
+GetProtectedMode16CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0) {
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 0) {
+ break;
+ }
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Get Protected mode code segment from current GDT table.
+
+ @return Protected mode code segment value.
+**/
+UINT16
+GetProtectedModeCS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0) {
+ if (GdtEntry->Bits.Type > 8 && GdtEntry->Bits.DB == 1) {
+ break;
+ }
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Do sync on APs.
+
+ @param[in, out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+RelocateApLoop (
+ IN OUT VOID *Buffer
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ BOOLEAN MwaitSupport;
+ ASM_RELOCATE_AP_LOOP AsmRelocateApLoopFunc;
+ UINTN ProcessorNumber;
+ UINTN StackStart;
+
+ MpInitLibWhoAmI (&ProcessorNumber);
+ CpuMpData = GetCpuMpData ();
+ MwaitSupport = IsMwaitSupport ();
+ if (CpuMpData->SevEsIsEnabled) {
+ StackStart = CpuMpData->SevEsAPResetStackStart;
+ } else {
+ StackStart = mReservedTopOfApStack;
+ }
+ AsmRelocateApLoopFunc = (ASM_RELOCATE_AP_LOOP) (UINTN) mReservedApLoopFunc;
+ AsmRelocateApLoopFunc (
+ MwaitSupport,
+ CpuMpData->ApTargetCState,
+ CpuMpData->PmCodeSegment,
+ StackStart - ProcessorNumber * AP_SAFE_STACK_SIZE,
+ (UINTN) &mNumberToFinish,
+ CpuMpData->Pm16CodeSegment,
+ CpuMpData->SevEsAPBuffer,
+ CpuMpData->WakeupBuffer
+ );
+ //
+ // It should never reach here
+ //
+ ASSERT (FALSE);
+}
+
+/**
+ Callback function for ExitBootServices.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+MpInitChangeApLoopCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+ CpuMpData->PmCodeSegment = GetProtectedModeCS ();
+ CpuMpData->Pm16CodeSegment = GetProtectedMode16CS ();
+ CpuMpData->ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
+ mNumberToFinish = CpuMpData->CpuCount - 1;
+ WakeUpAP (CpuMpData, TRUE, 0, RelocateApLoop, NULL, TRUE);
+ while (mNumberToFinish > 0) {
+ CpuPause ();
+ }
+
+ if (CpuMpData->SevEsIsEnabled && (CpuMpData->WakeupBuffer != (UINTN) -1)) {
+ //
+ // There are APs present. Re-use reserved memory area below 1MB from
+ // WakeupBuffer as the area to be used for transitioning to 16-bit mode
+ // in support of booting of the AP by an OS.
+ //
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) (CpuMpData->AddressMap.RendezvousFunnelAddress +
+ CpuMpData->AddressMap.SwitchToRealPM16ModeOffset),
+ CpuMpData->AddressMap.SwitchToRealPM16ModeSize
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "%a() done!\n", __FUNCTION__));
+}
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN ApSafeBufferSize;
+ UINTN Index;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;
+ UINTN StackBase;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ SaveCpuMpData (CpuMpData);
+
+ if (CpuMpData->CpuCount == 1) {
+ //
+ // If only BSP exists, return
+ //
+ return;
+ }
+
+ if (PcdGetBool (PcdCpuStackGuard)) {
+ //
+ // One extra page at the bottom of the stack is needed for Guard page.
+ //
+ if (CpuMpData->CpuApStackSize <= EFI_PAGE_SIZE) {
+ DEBUG ((DEBUG_ERROR, "PcdCpuApStackSize is not big enough for Stack Guard!\n"));
+ ASSERT (FALSE);
+ }
+
+ //
+ // DXE will reuse stack allocated for APs at PEI phase if it's available.
+ // Let's check it here.
+ //
+ // Note: BSP's stack guard is set at DxeIpl phase. But for the sake of
+ // BSP/AP exchange, stack guard for ApTopOfStack of cpu 0 will still be
+ // set here.
+ //
+ CpuInfoInHob = (CPU_INFO_IN_HOB *)(UINTN)CpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; ++Index) {
+ if (CpuInfoInHob != NULL && CpuInfoInHob[Index].ApTopOfStack != 0) {
+ StackBase = (UINTN)CpuInfoInHob[Index].ApTopOfStack - CpuMpData->CpuApStackSize;
+ } else {
+ StackBase = CpuMpData->Buffer + Index * CpuMpData->CpuApStackSize;
+ }
+
+ Status = gDS->GetMemorySpaceDescriptor (StackBase, &MemDesc);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gDS->SetMemorySpaceAttributes (
+ StackBase,
+ EFI_PAGES_TO_SIZE (1),
+ MemDesc.Attributes | EFI_MEMORY_RP
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DEBUG ((DEBUG_INFO, "Stack Guard set at %lx [cpu%lu]!\n",
+ (UINT64)StackBase, (UINT64)Index));
+ }
+ }
+
+ //
+ // Avoid APs access invalid buffer data which allocated by BootServices,
+ // so we will allocate reserved data for AP loop code. We also need to
+ // allocate this buffer below 4GB due to APs may be transferred to 32bit
+ // protected mode on long mode DXE.
+ // Allocating it in advance since memory services are not available in
+ // Exit Boot Services callback function.
+ //
+ ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
+ CpuMpData->AddressMap.RelocateApLoopFuncSize
+ ));
+ Address = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (ApSafeBufferSize),
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mReservedApLoopFunc = (VOID *) (UINTN) Address;
+ ASSERT (mReservedApLoopFunc != NULL);
+
+ //
+ // Make sure that the buffer memory is executable if NX protection is enabled
+ // for EfiReservedMemoryType.
+ //
+ // TODO: Check EFI_MEMORY_XP bit set or not once it's available in DXE GCD
+ // service.
+ //
+ Status = gDS->GetMemorySpaceDescriptor (Address, &MemDesc);
+ if (!EFI_ERROR (Status)) {
+ gDS->SetMemorySpaceAttributes (
+ Address,
+ ApSafeBufferSize,
+ MemDesc.Attributes & (~EFI_MEMORY_XP)
+ );
+ }
+
+ ApSafeBufferSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (
+ CpuMpData->CpuCount * AP_SAFE_STACK_SIZE
+ ));
+ Address = BASE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (ApSafeBufferSize),
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mReservedTopOfApStack = (UINTN) Address + ApSafeBufferSize;
+ ASSERT ((mReservedTopOfApStack & (UINTN)(CPU_STACK_ALIGNMENT - 1)) == 0);
+ CopyMem (
+ mReservedApLoopFunc,
+ CpuMpData->AddressMap.RelocateApLoopFuncAddress,
+ CpuMpData->AddressMap.RelocateApLoopFuncSize
+ );
+
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ CheckApsStatus,
+ NULL,
+ &mCheckAllApsEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Set timer to check all APs status.
+ //
+ Status = gBS->SetTimer (
+ mCheckAllApsEvent,
+ TimerPeriodic,
+ EFI_TIMER_PERIOD_MICROSECONDS (
+ PcdGet32 (PcdCpuApStatusCheckIntervalInMicroSeconds)
+ )
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEvent (
+ EVT_SIGNAL_EXIT_BOOT_SERVICES,
+ TPL_CALLBACK,
+ MpInitChangeApLoopCallback,
+ NULL,
+ &mMpInitExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ MpInitChangeApLoopCallback,
+ NULL,
+ &gEfiEventLegacyBootGuid,
+ &mLegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This service executes a caller provided function on all enabled APs.
+
+ @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 MpInitLibStartupAllAPs() or
+ MPInitLibStartupThisAP().
+ 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 Initialization
+ library, 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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_NOT_READY MP Initialize Library is not initialized.
+ @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_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;
+
+ //
+ // Temporarily stop checkAllApsStatus for avoid resource dead-lock.
+ //
+ mStopCheckAllApsStatus = TRUE;
+
+ Status = StartupAllCPUsWorker (
+ Procedure,
+ SingleThread,
+ TRUE,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+
+ //
+ // Start checkAllApsStatus
+ //
+ mStopCheckAllApsStatus = FALSE;
+
+ return Status;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP 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
+ MpInitLibGetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP 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 this AP,
+ and go on executing immediately. If this AP
+ 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
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MpInitLibStartupThisAP().
+ 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 on the
+ specified AP.
+ @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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_READY MP Initialize Library is not initialized.
+ @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_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;
+
+ //
+ // temporarily stop checkAllApsStatus for avoid resource dead-lock.
+ //
+ mStopCheckAllApsStatus = TRUE;
+
+ Status = StartupThisAPWorker (
+ Procedure,
+ ProcessorNumber,
+ WaitEvent,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ Finished
+ );
+
+ mStopCheckAllApsStatus = FALSE;
+
+ return Status;
+}
+
+/**
+ 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] 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
+ MpInitLibGetNumberOfProcessors().
+ @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_DEVICE_ERROR 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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ EFI_STATUS Status;
+ EFI_TIMER_ARCH_PROTOCOL *Timer;
+ UINT64 TimerPeriod;
+
+ TimerPeriod = 0;
+ //
+ // Locate Timer Arch Protocol
+ //
+ Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Timer);
+ if (EFI_ERROR (Status)) {
+ Timer = NULL;
+ }
+
+ if (Timer != NULL) {
+ //
+ // Save current rate of DXE Timer
+ //
+ Timer->GetTimerPeriod (Timer, &TimerPeriod);
+ //
+ // Disable DXE Timer and drain pending interrupts
+ //
+ Timer->SetTimerPeriod (Timer, 0);
+ }
+
+ Status = SwitchBSPWorker (ProcessorNumber, EnableOldBSP);
+
+ if (Timer != NULL) {
+ //
+ // Enable and restore rate of DXE Timer
+ //
+ Timer->SetTimerPeriod (Timer, TimerPeriod);
+ }
+
+ return Status;
+}
+
+/**
+ 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] ProcessorNumber The handle number of 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
+ MpInitLibGetNumberOfProcessors().
+ @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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN TempStopCheckState;
+
+ TempStopCheckState = FALSE;
+ //
+ // temporarily stop checkAllAPsStatus for initialize parameters.
+ //
+ if (!mStopCheckAllApsStatus) {
+ mStopCheckAllApsStatus = TRUE;
+ TempStopCheckState = TRUE;
+ }
+
+ Status = EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
+
+ if (TempStopCheckState) {
+ mStopCheckAllApsStatus = FALSE;
+ }
+
+ return Status;
+}
+
+/**
+ This funtion will try to invoke platform specific microcode shadow logic to
+ relocate microcode update patches into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+
+ @retval EFI_SUCCESS Shadow microcode success.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
+ @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
+ PPI/Protocol.
+**/
+EFI_STATUS
+PlatformShadowMicrocode (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ //
+ // There is no DXE version of platform shadow microcode protocol so far.
+ // A platform which only uses DxeMpInitLib instance could only supports
+ // the PCD based microcode shadowing.
+ //
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
new file mode 100644
index 00000000..352c7b3d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Ia32/MpFuncs.nasm
@@ -0,0 +1,348 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)
+
+SECTION .text
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+BITS 16
+ mov ebp, eax ; save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (BufferStart)
+ mov ebx, [si]
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (DataSegment)
+ mov edx, [si]
+
+ ;
+ ; Get start address of 32-bit code in low memory (<1MB)
+ ;
+ mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeTransitionMemory)
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (GdtrProfile)
+o32 lgdt [cs:si]
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (IdtrProfile)
+o32 lidt [cs:si]
+
+ ;
+ ; Switch to protected mode
+ ;
+ mov eax, cr0 ; Get control register 0
+ or eax, 000000003h ; Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ ; Switch to 32-bit code in executable memory (>1MB)
+o32 jmp far [cs:di]
+
+;
+; Following code may be copied to memory with type of EfiBootServicesCode.
+; This is required at DXE phase if NX is enabled for EfiBootServicesCode of
+; memory.
+;
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ds, dx
+ mov es, dx
+ mov fs, dx
+ mov gs, dx
+ mov ss, dx
+
+ mov esi, ebx
+
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (EnableExecuteDisable)
+ cmp byte [edi], 0
+ jz SkipEnableExecuteDisable
+
+ ;
+ ; Enable IA32 PAE execute disable
+ ;
+
+ mov ecx, 0xc0000080
+ rdmsr
+ bts eax, 11
+ wrmsr
+
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (Cr3)
+ mov eax, dword [edi]
+ mov cr3, eax
+
+ mov eax, cr4
+ bts eax, 5
+ mov cr4, eax
+
+ mov eax, cr0
+ bts eax, 31
+ mov cr0, eax
+
+SkipEnableExecuteDisable:
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)
+ cmp dword [edi], 1 ; 1 == ApInitConfig
+ jnz GetApicId
+
+ ; Increment the number of APs executing here as early as possible
+ ; This is decremented in C code when AP is finished executing
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (NumApsExecuting)
+ lock inc dword [edi]
+
+ ; AP init
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (ApIndex)
+ mov ebx, 1
+ lock xadd dword [edi], ebx ; EBX = ApIndex++
+ inc ebx ; EBX is CpuNumber
+
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackSize)
+ mov eax, [edi]
+ mov ecx, ebx
+ inc ecx
+ mul ecx ; EAX = StackSize * (CpuNumber + 1)
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackStart)
+ add eax, [edi]
+ mov esp, eax
+ jmp CProcedureInvoke
+
+GetApicId:
+ mov eax, 0
+ cpuid
+ cmp eax, 0bh
+ jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY
+
+ mov eax, 0bh
+ xor ecx, ecx
+ cpuid
+ test ebx, 0ffffh
+ jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero
+
+ ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX
+ jmp GetProcessorNumber
+
+NoX2Apic:
+ ; Processor is not x2APIC capable, so get 8-bit APIC ID
+ mov eax, 1
+ cpuid
+ shr ebx, 24
+ mov edx, ebx
+
+GetProcessorNumber:
+ ;
+ ; Get processor number for this AP
+ ; Note that BSP may become an AP due to SwitchBsp()
+ ;
+ xor ebx, ebx
+ lea eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (CpuInfo)]
+ mov edi, [eax]
+
+GetNextProcNumber:
+ cmp dword [edi + CPU_INFO_IN_HOB.InitialApicId], edx ; APIC ID match?
+ jz ProgramStack
+ add edi, CPU_INFO_IN_HOB_size
+ inc ebx
+ jmp GetNextProcNumber
+
+ProgramStack:
+ mov esp, dword [edi + CPU_INFO_IN_HOB.ApTopOfStack]
+
+CProcedureInvoke:
+ push ebp ; push BIST data at top of AP stack
+ xor ebp, ebp ; clear ebp for call stack trace
+ push ebp
+ mov ebp, esp
+
+ mov eax, ASM_PFX(InitializeFloatingPointUnits)
+ call eax ; Call assembly function to initialize FPU per UEFI spec
+
+ push ebx ; Push ApIndex
+ mov eax, esi
+ add eax, MP_CPU_EXCHANGE_INFO_OFFSET
+ push eax ; push address of exchange info data buffer
+
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)
+ mov eax, [edi]
+
+ call eax ; Invoke C function
+
+ jmp $ ; Never reach here
+RendezvousFunnelProcEnd:
+
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;NOT USED IN 32 BIT MODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+ jmp $ ; Never reach here
+SwitchToRealProcEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);
+;
+; The last three parameters (Pm16CodeSegment, SevEsAPJumpTable and WakeupBuffer) are
+; specific to SEV-ES support and are not applicable on IA32.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmRelocateApLoop)
+ASM_PFX(AsmRelocateApLoop):
+AsmRelocateApLoopStart:
+ mov eax, esp
+ mov esp, [eax + 16] ; TopOfApStack
+ push dword [eax] ; push return address for stack trace
+ push ebp
+ mov ebp, esp
+ mov ebx, [eax + 8] ; ApTargetCState
+ mov ecx, [eax + 4] ; MwaitSupport
+ mov eax, [eax + 20] ; CountTofinish
+ lock dec dword [eax] ; (*CountTofinish)--
+ cmp cl, 1 ; Check mwait-monitor support
+ jnz HltLoop
+MwaitLoop:
+ cli
+ mov eax, esp
+ xor ecx, ecx
+ xor edx, edx
+ monitor
+ mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
+ shl eax, 4
+ mwait
+ jmp MwaitLoop
+HltLoop:
+ cli
+ hlt
+ jmp HltLoop
+AsmRelocateApLoopEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ pushad
+ mov ebp,esp
+
+ mov ebx, [ebp + 24h]
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], RendezvousFunnelProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], Flat32Start - RendezvousFunnelProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], AsmRelocateApLoopStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealSize], SwitchToRealProcEnd - SwitchToRealProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealOffset], SwitchToRealProcStart - RendezvousFunnelProcStart
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], 0
+ mov dword [ebx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], 0
+
+ popad
+ ret
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches it'stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+ pushad
+ mov ebp,esp
+
+ ; esi contains MyInfo pointer
+ mov esi, [ebp + 24h]
+
+ ; edi contains OthersInfo pointer
+ mov edi, [ebp + 28h]
+
+ ;Store EFLAGS, GDTR and IDTR register to stack
+ pushfd
+ mov eax, cr4
+ push eax ; push cr4 firstly
+ mov eax, cr0
+ push eax
+
+ sgdt [esi + CPU_EXCHANGE_ROLE_INFO.Gdtr]
+ sidt [esi + CPU_EXCHANGE_ROLE_INFO.Idtr]
+
+ ; Store the its StackPointer
+ mov [esi + CPU_EXCHANGE_ROLE_INFO.StackPointer],esp
+
+ ; update its switch state to STORED
+ mov byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [edi + CPU_EXCHANGE_ROLE_INFO.Gdtr]
+
+ ; load IDTR value
+ lidt [edi + CPU_EXCHANGE_ROLE_INFO.Idtr]
+
+ ; load its future StackPointer
+ mov esp, [edi + CPU_EXCHANGE_ROLE_INFO.StackPointer]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [edi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [esi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ pop eax
+ mov cr0, eax
+ pop eax
+ mov cr4, eax
+ popfd
+
+ popad
+ ret
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Microcode.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Microcode.c
new file mode 100644
index 00000000..a1043050
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/Microcode.c
@@ -0,0 +1,374 @@
+/** @file
+ Implementation of loading microcode on processors.
+
+ Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+ @param[in] ProcessorNumber The handle number of the processor. The range is
+ from 0 to the total number of logical processors
+ minus 1.
+**/
+VOID
+MicrocodeDetect (
+ IN CPU_MP_DATA *CpuMpData,
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MICROCODE_HEADER *Microcode;
+ UINTN MicrocodeEnd;
+ CPU_AP_DATA *BspData;
+ UINT32 LatestRevision;
+ CPU_MICROCODE_HEADER *LatestMicrocode;
+ UINT32 ThreadId;
+ EDKII_PEI_MICROCODE_CPU_ID MicrocodeCpuId;
+
+ if (CpuMpData->MicrocodePatchRegionSize == 0) {
+ //
+ // There is no microcode patches
+ //
+ return;
+ }
+
+ GetProcessorLocationByApicId (GetInitialApicId (), NULL, NULL, &ThreadId);
+ if (ThreadId != 0) {
+ //
+ // Skip loading microcode if it is not the first thread in one core.
+ //
+ return;
+ }
+
+ GetProcessorMicrocodeCpuId (&MicrocodeCpuId);
+
+ if (ProcessorNumber != (UINTN) CpuMpData->BspNumber) {
+ //
+ // Direct use microcode of BSP if AP is the same as BSP.
+ // Assume BSP calls this routine() before AP.
+ //
+ BspData = &(CpuMpData->CpuData[CpuMpData->BspNumber]);
+ if ((BspData->ProcessorSignature == MicrocodeCpuId.ProcessorSignature) &&
+ (BspData->PlatformId == MicrocodeCpuId.PlatformId) &&
+ (BspData->MicrocodeEntryAddr != 0)) {
+ LatestMicrocode = (CPU_MICROCODE_HEADER *)(UINTN) BspData->MicrocodeEntryAddr;
+ LatestRevision = LatestMicrocode->UpdateRevision;
+ goto LoadMicrocode;
+ }
+ }
+
+ //
+ // BSP or AP which is different from BSP runs here
+ // Use 0 as the starting revision to search for microcode because MicrocodePatchInfo HOB needs
+ // the latest microcode location even it's loaded to the processor.
+ //
+ LatestRevision = 0;
+ LatestMicrocode = NULL;
+ Microcode = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
+ MicrocodeEnd = (UINTN) Microcode + (UINTN) CpuMpData->MicrocodePatchRegionSize;
+
+ do {
+ if (!IsValidMicrocode (Microcode, MicrocodeEnd - (UINTN) Microcode, LatestRevision, &MicrocodeCpuId, 1, TRUE)) {
+ //
+ // It is the padding data between the microcode patches for microcode patches alignment.
+ // Because the microcode patch is the multiple of 1-KByte, the padding data should not
+ // exist if the microcode patch alignment value is not larger than 1-KByte. So, the microcode
+ // alignment value should be larger than 1-KByte. We could skip SIZE_1KB padding data to
+ // find the next possible microcode patch header.
+ //
+ Microcode = (CPU_MICROCODE_HEADER *) ((UINTN) Microcode + SIZE_1KB);
+ continue;
+ }
+ LatestMicrocode = Microcode;
+ LatestRevision = LatestMicrocode->UpdateRevision;
+
+ Microcode = (CPU_MICROCODE_HEADER *) (((UINTN) Microcode) + GetMicrocodeLength (Microcode));
+ } while ((UINTN) Microcode < MicrocodeEnd);
+
+LoadMicrocode:
+ if (LatestRevision != 0) {
+ //
+ // Save the detected microcode patch entry address (including the microcode
+ // patch header) for each processor even it's the same as the loaded one.
+ // It will be used when building the microcode patch cache HOB.
+ //
+ CpuMpData->CpuData[ProcessorNumber].MicrocodeEntryAddr = (UINTN) LatestMicrocode;
+ }
+
+ if (LatestRevision > GetProcessorMicrocodeSignature ()) {
+ //
+ // BIOS only authenticate updates that contain a numerically larger revision
+ // than the currently loaded revision, where Current Signature < New Update
+ // Revision. A processor with no loaded update is considered to have a
+ // revision equal to zero.
+ //
+ LoadMicrocode (LatestMicrocode);
+ }
+ //
+ // It's possible that the microcode fails to load. Just capture the CPU microcode revision after loading.
+ //
+ CpuMpData->CpuData[ProcessorNumber].MicrocodeRevision = GetProcessorMicrocodeSignature ();
+}
+
+/**
+ Actual worker function that shadows the required microcode patches into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+ @param[in] Patches The pointer to an array of information on
+ the microcode patches that will be loaded
+ into memory.
+ @param[in] PatchCount The number of microcode patches that will
+ be loaded into memory.
+ @param[in] TotalLoadSize The total size of all the microcode patches
+ to be loaded.
+**/
+VOID
+ShadowMicrocodePatchWorker (
+ IN OUT CPU_MP_DATA *CpuMpData,
+ IN MICROCODE_PATCH_INFO *Patches,
+ IN UINTN PatchCount,
+ IN UINTN TotalLoadSize
+ )
+{
+ UINTN Index;
+ VOID *MicrocodePatchInRam;
+ UINT8 *Walker;
+
+ ASSERT ((Patches != NULL) && (PatchCount != 0));
+
+ MicrocodePatchInRam = AllocatePages (EFI_SIZE_TO_PAGES (TotalLoadSize));
+ if (MicrocodePatchInRam == NULL) {
+ return;
+ }
+
+ //
+ // Load all the required microcode patches into memory
+ //
+ for (Walker = MicrocodePatchInRam, Index = 0; Index < PatchCount; Index++) {
+ CopyMem (
+ Walker,
+ (VOID *) Patches[Index].Address,
+ Patches[Index].Size
+ );
+ Walker += Patches[Index].Size;
+ }
+
+ //
+ // Update the microcode patch related fields in CpuMpData
+ //
+ CpuMpData->MicrocodePatchAddress = (UINTN) MicrocodePatchInRam;
+ CpuMpData->MicrocodePatchRegionSize = TotalLoadSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
+ __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
+ ));
+
+ return;
+}
+
+/**
+ Shadow the required microcode patches data into memory according to PCD
+ PcdCpuMicrocodePatchAddress and PcdCpuMicrocodePatchRegionSize.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+ShadowMicrocodePatchByPcd (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN Index;
+ CPU_MICROCODE_HEADER *MicrocodeEntryPoint;
+ UINTN MicrocodeEnd;
+ UINTN TotalSize;
+ MICROCODE_PATCH_INFO *PatchInfoBuffer;
+ UINTN MaxPatchNumber;
+ UINTN PatchCount;
+ UINTN TotalLoadSize;
+ EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuIds;
+ BOOLEAN Valid;
+
+ //
+ // Initialize the microcode patch related fields in CpuMpData as the values
+ // specified by the PCD pair. If the microcode patches are loaded into memory,
+ // these fields will be updated.
+ //
+ CpuMpData->MicrocodePatchAddress = PcdGet64 (PcdCpuMicrocodePatchAddress);
+ CpuMpData->MicrocodePatchRegionSize = PcdGet64 (PcdCpuMicrocodePatchRegionSize);
+
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (UINTN) CpuMpData->MicrocodePatchAddress;
+ MicrocodeEnd = (UINTN) MicrocodeEntryPoint +
+ (UINTN) CpuMpData->MicrocodePatchRegionSize;
+ if ((MicrocodeEntryPoint == NULL) || ((UINTN) MicrocodeEntryPoint == MicrocodeEnd)) {
+ //
+ // There is no microcode patches
+ //
+ return;
+ }
+
+ PatchCount = 0;
+ MaxPatchNumber = DEFAULT_MAX_MICROCODE_PATCH_NUM;
+ TotalLoadSize = 0;
+ PatchInfoBuffer = AllocatePool (MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO));
+ if (PatchInfoBuffer == NULL) {
+ return;
+ }
+
+ MicrocodeCpuIds = AllocatePages (
+ EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID))
+ );
+ if (MicrocodeCpuIds == NULL) {
+ FreePool (PatchInfoBuffer);
+ return;
+ }
+
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ MicrocodeCpuIds[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
+ MicrocodeCpuIds[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
+ }
+
+ //
+ // Process the header of each microcode patch within the region.
+ // The purpose is to decide which microcode patch(es) will be loaded into memory.
+ // Microcode checksum is not verified because it's slow when performing on flash.
+ //
+ do {
+ Valid = IsValidMicrocode (
+ MicrocodeEntryPoint,
+ MicrocodeEnd - (UINTN) MicrocodeEntryPoint,
+ 0,
+ MicrocodeCpuIds,
+ CpuMpData->CpuCount,
+ FALSE
+ );
+ if (!Valid) {
+ //
+ // Padding data between the microcode patches, skip 1KB to check next entry.
+ //
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) (((UINTN) MicrocodeEntryPoint) + SIZE_1KB);
+ continue;
+ }
+
+ PatchCount++;
+ if (PatchCount > MaxPatchNumber) {
+ //
+ // Current 'PatchInfoBuffer' cannot hold the information, double the size
+ // and allocate a new buffer.
+ //
+ if (MaxPatchNumber > MAX_UINTN / 2 / sizeof (MICROCODE_PATCH_INFO)) {
+ //
+ // Overflow check for MaxPatchNumber
+ //
+ goto OnExit;
+ }
+
+ PatchInfoBuffer = ReallocatePool (
+ MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
+ 2 * MaxPatchNumber * sizeof (MICROCODE_PATCH_INFO),
+ PatchInfoBuffer
+ );
+ if (PatchInfoBuffer == NULL) {
+ goto OnExit;
+ }
+ MaxPatchNumber = MaxPatchNumber * 2;
+ }
+
+ TotalSize = GetMicrocodeLength (MicrocodeEntryPoint);
+
+ //
+ // Store the information of this microcode patch
+ //
+ PatchInfoBuffer[PatchCount - 1].Address = (UINTN) MicrocodeEntryPoint;
+ PatchInfoBuffer[PatchCount - 1].Size = TotalSize;
+ TotalLoadSize += TotalSize;
+
+ //
+ // Process the next microcode patch
+ //
+ MicrocodeEntryPoint = (CPU_MICROCODE_HEADER *) ((UINTN) MicrocodeEntryPoint + TotalSize);
+ } while ((UINTN) MicrocodeEntryPoint < MicrocodeEnd);
+
+ if (PatchCount != 0) {
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: 0x%x microcode patches will be loaded into memory, with size 0x%x.\n",
+ __FUNCTION__, PatchCount, TotalLoadSize
+ ));
+
+ ShadowMicrocodePatchWorker (CpuMpData, PatchInfoBuffer, PatchCount, TotalLoadSize);
+ }
+
+OnExit:
+ if (PatchInfoBuffer != NULL) {
+ FreePool (PatchInfoBuffer);
+ }
+ FreePages (MicrocodeCpuIds, EFI_SIZE_TO_PAGES (CpuMpData->CpuCount * sizeof (EDKII_PEI_MICROCODE_CPU_ID)));
+}
+
+/**
+ Shadow the required microcode patches data into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+ShadowMicrocodeUpdatePatch (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PlatformShadowMicrocode (CpuMpData);
+ if (EFI_ERROR (Status)) {
+ ShadowMicrocodePatchByPcd (CpuMpData);
+ }
+}
+
+/**
+ Get the cached microcode patch base address and size from the microcode patch
+ information cache HOB.
+
+ @param[out] Address Base address of the microcode patches data.
+ It will be updated if the microcode patch
+ information cache HOB is found.
+ @param[out] RegionSize Size of the microcode patches data.
+ It will be updated if the microcode patch
+ information cache HOB is found.
+
+ @retval TRUE The microcode patch information cache HOB is found.
+ @retval FALSE The microcode patch information cache HOB is not found.
+
+**/
+BOOLEAN
+GetMicrocodePatchInfoFromHob (
+ UINT64 *Address,
+ UINT64 *RegionSize
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EDKII_MICROCODE_PATCH_HOB *MicrocodePathHob;
+
+ GuidHob = GetFirstGuidHob (&gEdkiiMicrocodePatchHobGuid);
+ if (GuidHob == NULL) {
+ DEBUG((DEBUG_INFO, "%a: Microcode patch cache HOB is not found.\n", __FUNCTION__));
+ return FALSE;
+ }
+
+ MicrocodePathHob = GET_GUID_HOB_DATA (GuidHob);
+
+ *Address = MicrocodePathHob->MicrocodePatchAddress;
+ *RegionSize = MicrocodePathHob->MicrocodePatchRegionSize;
+
+ DEBUG((
+ DEBUG_INFO, "%a: MicrocodeBase = 0x%lx, MicrocodeSize = 0x%lx\n",
+ __FUNCTION__, *Address, *RegionSize
+ ));
+
+ return TRUE;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpEqu.inc b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
new file mode 100644
index 00000000..b2e5d27f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpEqu.inc
@@ -0,0 +1,99 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; MpEqu.inc
+;
+; Abstract:
+;
+; This is the equates file for Multiple Processor support
+;
+;-------------------------------------------------------------------------------
+%include "Nasm.inc"
+
+CPU_SWITCH_STATE_IDLE equ 0
+CPU_SWITCH_STATE_STORED equ 1
+CPU_SWITCH_STATE_LOADED equ 2
+
+;
+; Equivalent NASM structure of MP_ASSEMBLY_ADDRESS_MAP
+;
+struc MP_ASSEMBLY_ADDRESS_MAP
+ .RendezvousFunnelAddress CTYPE_UINTN 1
+ .ModeEntryOffset CTYPE_UINTN 1
+ .RendezvousFunnelSize CTYPE_UINTN 1
+ .RelocateApLoopFuncAddress CTYPE_UINTN 1
+ .RelocateApLoopFuncSize CTYPE_UINTN 1
+ .ModeTransitionOffset CTYPE_UINTN 1
+ .SwitchToRealSize CTYPE_UINTN 1
+ .SwitchToRealOffset CTYPE_UINTN 1
+ .SwitchToRealNoNxOffset CTYPE_UINTN 1
+ .SwitchToRealPM16ModeOffset CTYPE_UINTN 1
+ .SwitchToRealPM16ModeSize CTYPE_UINTN 1
+endstruc
+
+;
+; Equivalent NASM structure of IA32_DESCRIPTOR
+;
+struc IA32_DESCRIPTOR
+ .Limit CTYPE_UINT16 1
+ .Base CTYPE_UINTN 1
+endstruc
+
+;
+; Equivalent NASM structure of CPU_EXCHANGE_ROLE_INFO
+;
+struc CPU_EXCHANGE_ROLE_INFO
+ ; State is defined as UINT8 in C header file
+ ; Define it as UINTN here to guarantee the fields that follow State
+ ; is naturally aligned. The structure layout doesn't change.
+ .State CTYPE_UINTN 1
+ .StackPointer CTYPE_UINTN 1
+ .Gdtr CTYPE_UINT8 IA32_DESCRIPTOR_size
+ .Idtr CTYPE_UINT8 IA32_DESCRIPTOR_size
+endstruc
+
+;
+; Equivalent NASM structure of CPU_INFO_IN_HOB
+;
+struc CPU_INFO_IN_HOB
+ .InitialApicId CTYPE_UINT32 1
+ .ApicId CTYPE_UINT32 1
+ .Health CTYPE_UINT32 1
+ .ApTopOfStack CTYPE_UINT64 1
+endstruc
+
+;
+; Equivalent NASM structure of MP_CPU_EXCHANGE_INFO
+;
+struc MP_CPU_EXCHANGE_INFO
+ .StackStart: CTYPE_UINTN 1
+ .StackSize: CTYPE_UINTN 1
+ .CFunction: CTYPE_UINTN 1
+ .GdtrProfile: CTYPE_UINT8 IA32_DESCRIPTOR_size
+ .IdtrProfile: CTYPE_UINT8 IA32_DESCRIPTOR_size
+ .BufferStart: CTYPE_UINTN 1
+ .ModeOffset: CTYPE_UINTN 1
+ .ApIndex: CTYPE_UINTN 1
+ .CodeSegment: CTYPE_UINTN 1
+ .DataSegment: CTYPE_UINTN 1
+ .EnableExecuteDisable: CTYPE_UINTN 1
+ .Cr3: CTYPE_UINTN 1
+ .InitFlag: CTYPE_UINTN 1
+ .CpuInfo: CTYPE_UINTN 1
+ .NumApsExecuting: CTYPE_UINTN 1
+ .CpuMpData: CTYPE_UINTN 1
+ .InitializeFloatingPointUnits: CTYPE_UINTN 1
+ .ModeTransitionMemory: CTYPE_UINT32 1
+ .ModeTransitionSegment: CTYPE_UINT16 1
+ .ModeHighMemory: CTYPE_UINT32 1
+ .ModeHighSegment: CTYPE_UINT16 1
+ .Enable5LevelPaging: CTYPE_BOOLEAN 1
+ .SevEsIsEnabled: CTYPE_BOOLEAN 1
+ .GhcbBase: CTYPE_UINTN 1
+endstruc
+
+MP_CPU_EXCHANGE_INFO_OFFSET equ (SwitchToRealProcEnd - RendezvousFunnelProcStart)
+%define MP_CPU_EXCHANGE_INFO_FIELD(Field) (MP_CPU_EXCHANGE_INFO_OFFSET + MP_CPU_EXCHANGE_INFO. %+ Field)
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.c
new file mode 100644
index 00000000..630d404f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.c
@@ -0,0 +1,2938 @@
+/** @file
+ CPU MP Initialize Library common functions.
+
+ Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include <Library/VmgExitLib.h>
+#include <Register/Amd/Fam17Msr.h>
+#include <Register/Amd/Ghcb.h>
+#ifdef VBOX
+# include <Library/IoLib.h>
+# include "../../../../DevEFI.h"
+#endif
+
+EFI_GUID mCpuInitMpLibHobGuid = CPU_INIT_MP_LIB_HOB_GUID;
+
+
+/**
+ The function will check if BSP Execute Disable is enabled.
+
+ DxeIpl may have enabled Execute Disable for BSP, APs need to
+ get the status and sync up the settings.
+ If BSP's CR0.Paging is not set, BSP execute Disble feature is
+ not working actually.
+
+ @retval TRUE BSP Execute Disable is enabled.
+ @retval FALSE BSP Execute Disable is not enabled.
+**/
+BOOLEAN
+IsBspExecuteDisableEnabled (
+ VOID
+ )
+{
+ UINT32 Eax;
+ CPUID_EXTENDED_CPU_SIG_EDX Edx;
+ MSR_IA32_EFER_REGISTER EferMsr;
+ BOOLEAN Enabled;
+ IA32_CR0 Cr0;
+
+ Enabled = FALSE;
+ Cr0.UintN = AsmReadCr0 ();
+ if (Cr0.Bits.PG != 0) {
+ //
+ // If CR0 Paging bit is set
+ //
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &Eax, NULL, NULL, NULL);
+ if (Eax >= CPUID_EXTENDED_CPU_SIG) {
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &Edx.Uint32);
+ //
+ // CPUID 0x80000001
+ // Bit 20: Execute Disable Bit available.
+ //
+ if (Edx.Bits.NX != 0) {
+ EferMsr.Uint64 = AsmReadMsr64 (MSR_IA32_EFER);
+ //
+ // MSR 0xC0000080
+ // Bit 11: Execute Disable Bit enable.
+ //
+ if (EferMsr.Bits.NXE != 0) {
+ Enabled = TRUE;
+ }
+ }
+ }
+ }
+
+ return Enabled;
+}
+
+/**
+ Worker function for SwitchBSP().
+
+ Worker function for SwitchBSP(), assigned to the AP which is intended
+ to become BSP.
+
+ @param[in] Buffer Pointer to CPU MP Data
+**/
+VOID
+EFIAPI
+FutureBSPProc (
+ IN VOID *Buffer
+ )
+{
+ CPU_MP_DATA *DataInHob;
+
+ DataInHob = (CPU_MP_DATA *) Buffer;
+ AsmExchangeRole (&DataInHob->APInfo, &DataInHob->BSPInfo);
+}
+
+/**
+ 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;
+}
+
+/**
+ Set the Application Processors state.
+
+ @param[in] CpuData The pointer to CPU_AP_DATA of specified AP
+ @param[in] State The AP status
+**/
+VOID
+SetApState (
+ IN CPU_AP_DATA *CpuData,
+ IN CPU_STATE State
+ )
+{
+ AcquireSpinLock (&CpuData->ApLock);
+ CpuData->State = State;
+ ReleaseSpinLock (&CpuData->ApLock);
+}
+
+/**
+ Save BSP's local APIC timer setting.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+**/
+VOID
+SaveLocalApicTimerSetting (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ //
+ // Record the current local APIC timer setting of BSP
+ //
+ GetApicTimerState (
+ &CpuMpData->DivideValue,
+ &CpuMpData->PeriodicMode,
+ &CpuMpData->Vector
+ );
+ CpuMpData->CurrentTimerCount = GetApicTimerCurrentCount ();
+ CpuMpData->TimerInterruptState = GetApicTimerInterruptState ();
+}
+
+/**
+ Sync local APIC timer setting from BSP to AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+**/
+VOID
+SyncLocalApicTimerSetting (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ //
+ // Sync local APIC timer setting from BSP to AP
+ //
+ InitializeApicTimer (
+ CpuMpData->DivideValue,
+ CpuMpData->CurrentTimerCount,
+ CpuMpData->PeriodicMode,
+ CpuMpData->Vector
+ );
+ //
+ // Disable AP's local APIC timer interrupt
+ //
+ DisableApicTimerInterrupt ();
+}
+
+/**
+ Save the volatile registers required to be restored following INIT IPI.
+
+ @param[out] VolatileRegisters Returns buffer saved the volatile resisters
+**/
+VOID
+SaveVolatileRegisters (
+ OUT CPU_VOLATILE_REGISTERS *VolatileRegisters
+ )
+{
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+
+ VolatileRegisters->Cr0 = AsmReadCr0 ();
+ VolatileRegisters->Cr3 = AsmReadCr3 ();
+ VolatileRegisters->Cr4 = AsmReadCr4 ();
+
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.DE != 0) {
+ //
+ // If processor supports Debugging Extensions feature
+ // by CPUID.[EAX=01H]:EDX.BIT2
+ //
+ VolatileRegisters->Dr0 = AsmReadDr0 ();
+ VolatileRegisters->Dr1 = AsmReadDr1 ();
+ VolatileRegisters->Dr2 = AsmReadDr2 ();
+ VolatileRegisters->Dr3 = AsmReadDr3 ();
+ VolatileRegisters->Dr6 = AsmReadDr6 ();
+ VolatileRegisters->Dr7 = AsmReadDr7 ();
+ }
+
+ AsmReadGdtr (&VolatileRegisters->Gdtr);
+ AsmReadIdtr (&VolatileRegisters->Idtr);
+ VolatileRegisters->Tr = AsmReadTr ();
+}
+
+/**
+ Restore the volatile registers following INIT IPI.
+
+ @param[in] VolatileRegisters Pointer to volatile resisters
+ @param[in] IsRestoreDr TRUE: Restore DRx if supported
+ FALSE: Do not restore DRx
+**/
+VOID
+RestoreVolatileRegisters (
+ IN CPU_VOLATILE_REGISTERS *VolatileRegisters,
+ IN BOOLEAN IsRestoreDr
+ )
+{
+ CPUID_VERSION_INFO_EDX VersionInfoEdx;
+ IA32_TSS_DESCRIPTOR *Tss;
+
+ AsmWriteCr3 (VolatileRegisters->Cr3);
+ AsmWriteCr4 (VolatileRegisters->Cr4);
+ AsmWriteCr0 (VolatileRegisters->Cr0);
+
+ if (IsRestoreDr) {
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &VersionInfoEdx.Uint32);
+ if (VersionInfoEdx.Bits.DE != 0) {
+ //
+ // If processor supports Debugging Extensions feature
+ // by CPUID.[EAX=01H]:EDX.BIT2
+ //
+ AsmWriteDr0 (VolatileRegisters->Dr0);
+ AsmWriteDr1 (VolatileRegisters->Dr1);
+ AsmWriteDr2 (VolatileRegisters->Dr2);
+ AsmWriteDr3 (VolatileRegisters->Dr3);
+ AsmWriteDr6 (VolatileRegisters->Dr6);
+ AsmWriteDr7 (VolatileRegisters->Dr7);
+ }
+ }
+
+ AsmWriteGdtr (&VolatileRegisters->Gdtr);
+ AsmWriteIdtr (&VolatileRegisters->Idtr);
+ if (VolatileRegisters->Tr != 0 &&
+ VolatileRegisters->Tr < VolatileRegisters->Gdtr.Limit) {
+ Tss = (IA32_TSS_DESCRIPTOR *)(VolatileRegisters->Gdtr.Base +
+ VolatileRegisters->Tr);
+ if (Tss->Bits.P == 1) {
+ Tss->Bits.Type &= 0xD; // 1101 - Clear busy bit just in case
+ AsmWriteTr (VolatileRegisters->Tr);
+ }
+ }
+}
+
+/**
+ Detect whether Mwait-monitor feature is supported.
+
+ @retval TRUE Mwait-monitor feature is supported.
+ @retval FALSE Mwait-monitor feature is not supported.
+**/
+BOOLEAN
+IsMwaitSupport (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_ECX VersionInfoEcx;
+
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &VersionInfoEcx.Uint32, NULL);
+ return (VersionInfoEcx.Bits.MONITOR == 1) ? TRUE : FALSE;
+}
+
+/**
+ Get AP loop mode.
+
+ @param[out] MonitorFilterSize Returns the largest monitor-line size in bytes.
+
+ @return The AP loop mode.
+**/
+UINT8
+GetApLoopMode (
+ OUT UINT32 *MonitorFilterSize
+ )
+{
+ UINT8 ApLoopMode;
+ CPUID_MONITOR_MWAIT_EBX MonitorMwaitEbx;
+
+ ASSERT (MonitorFilterSize != NULL);
+
+ ApLoopMode = PcdGet8 (PcdCpuApLoopMode);
+ ASSERT (ApLoopMode >= ApInHltLoop && ApLoopMode <= ApInRunLoop);
+ if (ApLoopMode == ApInMwaitLoop) {
+ if (!IsMwaitSupport ()) {
+ //
+ // If processor does not support MONITOR/MWAIT feature,
+ // force AP in Hlt-loop mode
+ //
+ ApLoopMode = ApInHltLoop;
+ }
+
+ if (PcdGetBool (PcdSevEsIsEnabled)) {
+ //
+ // For SEV-ES, force AP in Hlt-loop mode in order to use the GHCB
+ // protocol for starting APs
+ //
+ ApLoopMode = ApInHltLoop;
+ }
+ }
+
+ if (ApLoopMode != ApInMwaitLoop) {
+ *MonitorFilterSize = sizeof (UINT32);
+ } else {
+ //
+ // CPUID.[EAX=05H]:EBX.BIT0-15: Largest monitor-line size in bytes
+ // CPUID.[EAX=05H].EDX: C-states supported using MWAIT
+ //
+ AsmCpuid (CPUID_MONITOR_MWAIT, NULL, &MonitorMwaitEbx.Uint32, NULL, NULL);
+ *MonitorFilterSize = MonitorMwaitEbx.Bits.LargestMonitorLineSize;
+ }
+
+ return ApLoopMode;
+}
+
+/**
+ Sort the APIC ID of all processors.
+
+ This function sorts the APIC ID of all processors so that processor number is
+ assigned in the ascending order of APIC ID which eases MP debugging.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+**/
+VOID
+SortApicId (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Index3;
+ UINT32 ApicId;
+ CPU_INFO_IN_HOB CpuInfo;
+ UINT32 ApCount;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ volatile UINT32 *StartupApSignal;
+
+ ApCount = CpuMpData->CpuCount - 1;
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ if (ApCount != 0) {
+ for (Index1 = 0; Index1 < ApCount; Index1++) {
+ Index3 = Index1;
+ //
+ // Sort key is the hardware default APIC ID
+ //
+ ApicId = CpuInfoInHob[Index1].ApicId;
+ for (Index2 = Index1 + 1; Index2 <= ApCount; Index2++) {
+ if (ApicId > CpuInfoInHob[Index2].ApicId) {
+ Index3 = Index2;
+ ApicId = CpuInfoInHob[Index2].ApicId;
+ }
+ }
+ if (Index3 != Index1) {
+ CopyMem (&CpuInfo, &CpuInfoInHob[Index3], sizeof (CPU_INFO_IN_HOB));
+ CopyMem (
+ &CpuInfoInHob[Index3],
+ &CpuInfoInHob[Index1],
+ sizeof (CPU_INFO_IN_HOB)
+ );
+ CopyMem (&CpuInfoInHob[Index1], &CpuInfo, sizeof (CPU_INFO_IN_HOB));
+
+ //
+ // Also exchange the StartupApSignal.
+ //
+ StartupApSignal = CpuMpData->CpuData[Index3].StartupApSignal;
+ CpuMpData->CpuData[Index3].StartupApSignal =
+ CpuMpData->CpuData[Index1].StartupApSignal;
+ CpuMpData->CpuData[Index1].StartupApSignal = StartupApSignal;
+ }
+ }
+
+ //
+ // Get the processor number for the BSP
+ //
+ ApicId = GetInitialApicId ();
+ for (Index1 = 0; Index1 < CpuMpData->CpuCount; Index1++) {
+ if (CpuInfoInHob[Index1].ApicId == ApicId) {
+ CpuMpData->BspNumber = (UINT32) Index1;
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Enable x2APIC mode on APs.
+
+ @param[in, out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+ApFuncEnableX2Apic (
+ IN OUT VOID *Buffer
+ )
+{
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);
+}
+
+/**
+ Do sync on APs.
+
+ @param[in, out] Buffer Pointer to private data buffer.
+**/
+VOID
+EFIAPI
+ApInitializeSync (
+ IN OUT VOID *Buffer
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorNumber;
+ EFI_STATUS Status;
+
+ CpuMpData = (CPU_MP_DATA *) Buffer;
+ Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Load microcode on AP
+ //
+ MicrocodeDetect (CpuMpData, ProcessorNumber);
+ //
+ // Sync BSP's MTRR table to AP
+ //
+ MtrrSetAllMtrrs (&CpuMpData->MtrrTable);
+}
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+ @param[out] ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN CPU_MP_DATA *CpuMpData,
+ OUT UINTN *ProcessorNumber
+ )
+{
+ UINTN TotalProcessorNumber;
+ UINTN Index;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ UINT32 CurrentApicId;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+
+ TotalProcessorNumber = CpuMpData->CpuCount;
+ CurrentApicId = GetApicId ();
+ for (Index = 0; Index < TotalProcessorNumber; Index ++) {
+ if (CpuInfoInHob[Index].ApicId == CurrentApicId) {
+ *ProcessorNumber = Index;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+#ifdef VBOX
+/*
+ * @todo move this function to the library.
+ */
+UINT32 VBoxGetVmVariable(UINT32 Variable, CHAR8* Buffer, UINT32 Size)
+{
+ UINT32 VarLen, i;
+
+ IoWrite32(EFI_INFO_PORT, Variable);
+ VarLen = IoRead32(EFI_INFO_PORT);
+
+ for (i = 0; i < VarLen && i < Size; i++)
+ Buffer[i] = IoRead8(EFI_INFO_PORT);
+
+ return VarLen;
+}
+#endif
+
+/**
+ This function will get CPU count in the system.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+
+ @return CPU count detected
+**/
+UINTN
+CollectProcessorCount (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN Index;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ BOOLEAN X2Apic;
+#ifdef VBOX
+ CHAR8 u8ApicMode;
+#endif
+
+ //
+ // Send 1st broadcast IPI to APs to wakeup APs
+ //
+ CpuMpData->InitFlag = ApInitConfig;
+ WakeUpAP (CpuMpData, TRUE, 0, NULL, NULL, TRUE);
+ CpuMpData->InitFlag = ApInitDone;
+ //
+ // When InitFlag == ApInitConfig, WakeUpAP () guarantees all APs are checked in.
+ // FinishedCount is the number of check-in APs.
+ //
+ CpuMpData->CpuCount = CpuMpData->FinishedCount + 1;
+ ASSERT (CpuMpData->CpuCount <= PcdGet32 (PcdCpuMaxLogicalProcessorNumber));
+
+ //
+ // Enable x2APIC mode if
+ // 1. Number of CPU is greater than 255; or
+ // 2. There are any logical processors reporting an Initial APIC ID of 255 or greater.
+ //
+ X2Apic = FALSE;
+ if (CpuMpData->CpuCount > 255) {
+ //
+ // If there are more than 255 processor found, force to enable X2APIC
+ //
+ X2Apic = TRUE;
+ } else {
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (CpuInfoInHob[Index].InitialApicId >= 0xFF) {
+ X2Apic = TRUE;
+ break;
+ }
+ }
+ }
+#ifdef VBOX
+ /* Force x2APIC mode if the VM config forces it. */
+ VBoxGetVmVariable(EFI_INFO_INDEX_APIC_MODE, &u8ApicMode, sizeof(u8ApicMode));
+ if (u8ApicMode == EFI_APIC_MODE_X2APIC)
+ X2Apic = TRUE;
+#endif
+
+ if (X2Apic) {
+ DEBUG ((DEBUG_INFO, "Force x2APIC mode!\n"));
+ //
+ // Wakeup all APs to enable x2APIC mode
+ //
+ WakeUpAP (CpuMpData, TRUE, 0, ApFuncEnableX2Apic, NULL, TRUE);
+ //
+ // Wait for all known APs finished
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+ //
+ // Enable x2APIC on BSP
+ //
+ SetApicMode (LOCAL_APIC_MODE_X2APIC);
+ //
+ // Set BSP/Aps state to IDLE
+ //
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
+ }
+ }
+ DEBUG ((DEBUG_INFO, "APIC MODE is %d\n", GetApicMode ()));
+ //
+ // Sort BSP/Aps by CPU APIC ID in ascending order
+ //
+ SortApicId (CpuMpData);
+
+ DEBUG ((DEBUG_INFO, "MpInitLib: Find %d processors in system.\n", CpuMpData->CpuCount));
+
+ return CpuMpData->CpuCount;
+}
+
+/**
+ Initialize CPU AP Data when AP is wakeup at the first time.
+
+ @param[in, out] CpuMpData Pointer to PEI CPU MP Data
+ @param[in] ProcessorNumber The handle number of processor
+ @param[in] BistData Processor BIST data
+ @param[in] ApTopOfStack Top of AP stack
+
+**/
+VOID
+InitializeApData (
+ IN OUT CPU_MP_DATA *CpuMpData,
+ IN UINTN ProcessorNumber,
+ IN UINT32 BistData,
+ IN UINT64 ApTopOfStack
+ )
+{
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ MSR_IA32_PLATFORM_ID_REGISTER PlatformIdMsr;
+
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
+ CpuInfoInHob[ProcessorNumber].Health = BistData;
+ CpuInfoInHob[ProcessorNumber].ApTopOfStack = ApTopOfStack;
+
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy = (BistData == 0) ? TRUE : FALSE;
+
+ //
+ // NOTE: PlatformId is not relevant on AMD platforms.
+ //
+ if (!StandardSignatureIsAuthenticAMD ()) {
+ PlatformIdMsr.Uint64 = AsmReadMsr64 (MSR_IA32_PLATFORM_ID);
+ CpuMpData->CpuData[ProcessorNumber].PlatformId = (UINT8)PlatformIdMsr.Bits.PlatformId;
+ }
+
+ AsmCpuid (
+ CPUID_VERSION_INFO,
+ &CpuMpData->CpuData[ProcessorNumber].ProcessorSignature,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ InitializeSpinLock(&CpuMpData->CpuData[ProcessorNumber].ApLock);
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
+/**
+ Get Protected mode code segment with 16-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 16-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode16CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0 &&
+ GdtEntry->Bits.DB == 0 &&
+ GdtEntry->Bits.Type > 8) {
+ break;
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Get Protected mode code segment with 32-bit default addressing
+ from current GDT table.
+
+ @return Protected mode 32-bit code segment value.
+**/
+STATIC
+UINT16
+GetProtectedMode32CS (
+ VOID
+ )
+{
+ IA32_DESCRIPTOR GdtrDesc;
+ IA32_SEGMENT_DESCRIPTOR *GdtEntry;
+ UINTN GdtEntryCount;
+ UINT16 Index;
+
+ Index = (UINT16) -1;
+ AsmReadGdtr (&GdtrDesc);
+ GdtEntryCount = (GdtrDesc.Limit + 1) / sizeof (IA32_SEGMENT_DESCRIPTOR);
+ GdtEntry = (IA32_SEGMENT_DESCRIPTOR *) GdtrDesc.Base;
+ for (Index = 0; Index < GdtEntryCount; Index++) {
+ if (GdtEntry->Bits.L == 0 &&
+ GdtEntry->Bits.DB == 1 &&
+ GdtEntry->Bits.Type > 8) {
+ break;
+ }
+ GdtEntry++;
+ }
+ ASSERT (Index != GdtEntryCount);
+ return Index * 8;
+}
+
+/**
+ Reset an AP when in SEV-ES mode.
+
+ If successful, this function never returns.
+
+ @param[in] Ghcb Pointer to the GHCB
+ @param[in] CpuMpData Pointer to CPU MP Data
+
+**/
+STATIC
+VOID
+MpInitLibSevEsAPReset (
+ IN GHCB *Ghcb,
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorNumber;
+ UINT16 Code16, Code32;
+ AP_RESET *APResetFn;
+ UINTN BufferStart;
+ UINTN StackStart;
+
+ Status = GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ ASSERT_EFI_ERROR (Status);
+
+ Code16 = GetProtectedMode16CS ();
+ Code32 = GetProtectedMode32CS ();
+
+ if (CpuMpData->WakeupBufferHigh != 0) {
+ APResetFn = (AP_RESET *) (CpuMpData->WakeupBufferHigh + CpuMpData->AddressMap.SwitchToRealNoNxOffset);
+ } else {
+ APResetFn = (AP_RESET *) (CpuMpData->MpCpuExchangeInfo->BufferStart + CpuMpData->AddressMap.SwitchToRealOffset);
+ }
+
+ BufferStart = CpuMpData->MpCpuExchangeInfo->BufferStart;
+ StackStart = CpuMpData->SevEsAPResetStackStart -
+ (AP_RESET_STACK_SIZE * ProcessorNumber);
+
+ //
+ // This call never returns.
+ //
+ APResetFn (BufferStart, Code16, Code32, StackStart);
+}
+
+/**
+ This function will be called from AP reset code if BSP uses WakeUpAP.
+
+ @param[in] ExchangeInfo Pointer to the MP exchange info buffer
+ @param[in] ApIndex Number of current executing AP
+**/
+VOID
+EFIAPI
+ApWakeupFunction (
+ IN MP_CPU_EXCHANGE_INFO *ExchangeInfo,
+ IN UINTN ApIndex
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorNumber;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *Parameter;
+ UINT32 BistData;
+ volatile UINT32 *ApStartupSignalBuffer;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ UINT64 ApTopOfStack;
+ UINTN CurrentApicMode;
+
+ //
+ // AP finished assembly code and begin to execute C code
+ //
+ CpuMpData = ExchangeInfo->CpuMpData;
+
+ //
+ // AP's local APIC settings will be lost after received INIT IPI
+ // We need to re-initialize them at here
+ //
+ ProgramVirtualWireMode ();
+ //
+ // Mask the LINT0 and LINT1 so that AP doesn't enter the system timer interrupt handler.
+ //
+ DisableLvtInterrupts ();
+ SyncLocalApicTimerSetting (CpuMpData);
+
+ CurrentApicMode = GetApicMode ();
+ while (TRUE) {
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ ProcessorNumber = ApIndex;
+ //
+ // This is first time AP wakeup, get BIST information from AP stack
+ //
+ ApTopOfStack = CpuMpData->Buffer + (ProcessorNumber + 1) * CpuMpData->CpuApStackSize;
+ BistData = *(UINT32 *) ((UINTN) ApTopOfStack - sizeof (UINTN));
+ //
+ // CpuMpData->CpuData[0].VolatileRegisters is initialized based on BSP environment,
+ // to initialize AP in InitConfig path.
+ // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a different IDT shared by all APs.
+ //
+ RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
+ InitializeApData (CpuMpData, ProcessorNumber, BistData, ApTopOfStack);
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ } else {
+ //
+ // Execute AP function if AP is ready
+ //
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ //
+ // Clear AP start-up signal when AP waken up
+ //
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ InterlockedCompareExchange32 (
+ (UINT32 *) ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ 0
+ );
+
+ if (CpuMpData->InitFlag == ApInitReconfig) {
+ //
+ // ApInitReconfig happens when:
+ // 1. AP is re-enabled after it's disabled, in either PEI or DXE phase.
+ // 2. AP is initialized in DXE phase.
+ // In either case, use the volatile registers value derived from BSP.
+ // NOTE: IDTR.BASE stored in CpuMpData->CpuData[0].VolatileRegisters points to a
+ // different IDT shared by all APs.
+ //
+ RestoreVolatileRegisters (&CpuMpData->CpuData[0].VolatileRegisters, FALSE);
+ } else {
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ //
+ // Restore AP's volatile registers saved before AP is halted
+ //
+ RestoreVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters, TRUE);
+ } else {
+ //
+ // The CPU driver might not flush TLB for APs on spot after updating
+ // page attributes. AP in mwait loop mode needs to take care of it when
+ // woken up.
+ //
+ CpuFlushTlb ();
+ }
+ }
+
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateReady) {
+ Procedure = (EFI_AP_PROCEDURE)CpuMpData->CpuData[ProcessorNumber].ApFunction;
+ Parameter = (VOID *) CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument;
+ if (Procedure != NULL) {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateBusy);
+ //
+ // Enable source debugging on AP function
+ //
+ EnableDebugAgent ();
+ //
+ // Invoke AP function here
+ //
+ Procedure (Parameter);
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ if (CpuMpData->SwitchBspFlag) {
+ //
+ // Re-get the processor number due to BSP/AP maybe exchange in AP function
+ //
+ GetProcessorNumber (CpuMpData, &ProcessorNumber);
+ CpuMpData->CpuData[ProcessorNumber].ApFunction = 0;
+ CpuMpData->CpuData[ProcessorNumber].ApFunctionArgument = 0;
+ ApStartupSignalBuffer = CpuMpData->CpuData[ProcessorNumber].StartupApSignal;
+ CpuInfoInHob[ProcessorNumber].ApTopOfStack = CpuInfoInHob[CpuMpData->NewBspNumber].ApTopOfStack;
+ } else {
+ if (CpuInfoInHob[ProcessorNumber].ApicId != GetApicId () ||
+ CpuInfoInHob[ProcessorNumber].InitialApicId != GetInitialApicId ()) {
+ if (CurrentApicMode != GetApicMode ()) {
+ //
+ // If APIC mode change happened during AP function execution,
+ // we do not support APIC ID value changed.
+ //
+ ASSERT (FALSE);
+ CpuDeadLoop ();
+ } else {
+ //
+ // Re-get the CPU APICID and Initial APICID if they are changed
+ //
+ CpuInfoInHob[ProcessorNumber].ApicId = GetApicId ();
+ CpuInfoInHob[ProcessorNumber].InitialApicId = GetInitialApicId ();
+ }
+ }
+ }
+ }
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateFinished);
+ }
+ }
+
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ //
+ // Save AP volatile registers
+ //
+ SaveVolatileRegisters (&CpuMpData->CpuData[ProcessorNumber].VolatileRegisters);
+ }
+
+ //
+ // AP finished executing C code
+ //
+ InterlockedIncrement ((UINT32 *) &CpuMpData->FinishedCount);
+
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ //
+ // Delay decrementing the APs executing count when SEV-ES is enabled
+ // to allow the APs to issue an AP_RESET_HOLD before the BSP possibly
+ // performs another INIT-SIPI-SIPI sequence.
+ //
+ if (!CpuMpData->SevEsIsEnabled) {
+ InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
+ }
+ }
+
+ //
+ // Place AP is specified loop mode
+ //
+ if (CpuMpData->ApLoopMode == ApInHltLoop) {
+ //
+ // Place AP in HLT-loop
+ //
+ while (TRUE) {
+ DisableInterrupts ();
+ if (CpuMpData->SevEsIsEnabled) {
+ MSR_SEV_ES_GHCB_REGISTER Msr;
+ GHCB *Ghcb;
+ UINT64 Status;
+ BOOLEAN DoDecrement;
+ BOOLEAN InterruptState;
+
+ DoDecrement = (BOOLEAN) (CpuMpData->InitFlag == ApInitConfig);
+
+ while (TRUE) {
+ Msr.GhcbPhysicalAddress = AsmReadMsr64 (MSR_SEV_ES_GHCB);
+ Ghcb = Msr.Ghcb;
+
+ VmgInit (Ghcb, &InterruptState);
+
+ if (DoDecrement) {
+ DoDecrement = FALSE;
+
+ //
+ // Perform the delayed decrement just before issuing the first
+ // VMGEXIT with AP_RESET_HOLD.
+ //
+ InterlockedDecrement ((UINT32 *) &CpuMpData->MpCpuExchangeInfo->NumApsExecuting);
+ }
+
+ Status = VmgExit (Ghcb, SVM_EXIT_AP_RESET_HOLD, 0, 0);
+ if ((Status == 0) && (Ghcb->SaveArea.SwExitInfo2 != 0)) {
+ VmgDone (Ghcb, InterruptState);
+ break;
+ }
+
+ VmgDone (Ghcb, InterruptState);
+ }
+
+ //
+ // Awakened in a new phase? Use the new CpuMpData
+ //
+ if (CpuMpData->NewCpuMpData != NULL) {
+ CpuMpData = CpuMpData->NewCpuMpData;
+ }
+
+ MpInitLibSevEsAPReset (Ghcb, CpuMpData);
+ } else {
+ CpuSleep ();
+ }
+ CpuPause ();
+ }
+ }
+ while (TRUE) {
+ DisableInterrupts ();
+ if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
+ //
+ // Place AP in MWAIT-loop
+ //
+ AsmMonitor ((UINTN) ApStartupSignalBuffer, 0, 0);
+ if (*ApStartupSignalBuffer != WAKEUP_AP_SIGNAL) {
+ //
+ // Check AP start-up signal again.
+ // If AP start-up signal is not set, place AP into
+ // the specified C-state
+ //
+ AsmMwait (CpuMpData->ApTargetCState << 4, 0);
+ }
+ } else if (CpuMpData->ApLoopMode == ApInRunLoop) {
+ //
+ // Place AP in Run-loop
+ //
+ CpuPause ();
+ } else {
+ ASSERT (FALSE);
+ }
+
+ //
+ // If AP start-up signal is written, AP is waken up
+ // otherwise place AP in loop again
+ //
+ if (*ApStartupSignalBuffer == WAKEUP_AP_SIGNAL) {
+ break;
+ }
+ }
+ }
+}
+
+/**
+ Wait for AP wakeup and write AP start-up signal till AP is waken up.
+
+ @param[in] ApStartupSignalBuffer Pointer to AP wakeup signal
+**/
+VOID
+WaitApWakeup (
+ IN volatile UINT32 *ApStartupSignalBuffer
+ )
+{
+ //
+ // If AP is waken up, StartupApSignal should be cleared.
+ // Otherwise, write StartupApSignal again till AP waken up.
+ //
+ while (InterlockedCompareExchange32 (
+ (UINT32 *) ApStartupSignalBuffer,
+ WAKEUP_AP_SIGNAL,
+ WAKEUP_AP_SIGNAL
+ ) != 0) {
+ CpuPause ();
+ }
+}
+
+/**
+ This function will fill the exchange info structure.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+
+**/
+VOID
+FillExchangeInfoData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Size;
+ IA32_SEGMENT_DESCRIPTOR *Selector;
+ IA32_CR4 Cr4;
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+ ExchangeInfo->StackStart = CpuMpData->Buffer;
+ ExchangeInfo->StackSize = CpuMpData->CpuApStackSize;
+ ExchangeInfo->BufferStart = CpuMpData->WakeupBuffer;
+ ExchangeInfo->ModeOffset = CpuMpData->AddressMap.ModeEntryOffset;
+
+ ExchangeInfo->CodeSegment = AsmReadCs ();
+ ExchangeInfo->DataSegment = AsmReadDs ();
+
+ ExchangeInfo->Cr3 = AsmReadCr3 ();
+
+ ExchangeInfo->CFunction = (UINTN) ApWakeupFunction;
+ ExchangeInfo->ApIndex = 0;
+ ExchangeInfo->NumApsExecuting = 0;
+ ExchangeInfo->InitFlag = (UINTN) CpuMpData->InitFlag;
+ ExchangeInfo->CpuInfo = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ ExchangeInfo->CpuMpData = CpuMpData;
+
+ ExchangeInfo->EnableExecuteDisable = IsBspExecuteDisableEnabled ();
+
+ ExchangeInfo->InitializeFloatingPointUnitsAddress = (UINTN)InitializeFloatingPointUnits;
+
+ //
+ // We can check either CPUID(7).ECX[bit16] or check CR4.LA57[bit12]
+ // to determin whether 5-Level Paging is enabled.
+ // CPUID(7).ECX[bit16] shows CPU's capability, CR4.LA57[bit12] shows
+ // current system setting.
+ // Using latter way is simpler because it also eliminates the needs to
+ // check whether platform wants to enable it.
+ //
+ Cr4.UintN = AsmReadCr4 ();
+ ExchangeInfo->Enable5LevelPaging = (BOOLEAN) (Cr4.Bits.LA57 == 1);
+ DEBUG ((DEBUG_INFO, "%a: 5-Level Paging = %d\n", gEfiCallerBaseName, ExchangeInfo->Enable5LevelPaging));
+
+ ExchangeInfo->SevEsIsEnabled = CpuMpData->SevEsIsEnabled;
+ ExchangeInfo->GhcbBase = (UINTN) CpuMpData->GhcbBase;
+
+ //
+ // Get the BSP's data of GDT and IDT
+ //
+ AsmReadGdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->GdtrProfile);
+ AsmReadIdtr ((IA32_DESCRIPTOR *) &ExchangeInfo->IdtrProfile);
+
+ //
+ // Find a 32-bit code segment
+ //
+ Selector = (IA32_SEGMENT_DESCRIPTOR *)ExchangeInfo->GdtrProfile.Base;
+ Size = ExchangeInfo->GdtrProfile.Limit + 1;
+ while (Size > 0) {
+ if (Selector->Bits.L == 0 && Selector->Bits.Type >= 8) {
+ ExchangeInfo->ModeTransitionSegment =
+ (UINT16)((UINTN)Selector - ExchangeInfo->GdtrProfile.Base);
+ break;
+ }
+ Selector += 1;
+ Size -= sizeof (IA32_SEGMENT_DESCRIPTOR);
+ }
+
+ //
+ // Copy all 32-bit code and 64-bit code into memory with type of
+ // EfiBootServicesCode to avoid page fault if NX memory protection is enabled.
+ //
+ if (CpuMpData->WakeupBufferHigh != 0) {
+ Size = CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize -
+ CpuMpData->AddressMap.ModeTransitionOffset;
+ CopyMem (
+ (VOID *)CpuMpData->WakeupBufferHigh,
+ CpuMpData->AddressMap.RendezvousFunnelAddress +
+ CpuMpData->AddressMap.ModeTransitionOffset,
+ Size
+ );
+
+ ExchangeInfo->ModeTransitionMemory = (UINT32)CpuMpData->WakeupBufferHigh;
+ } else {
+ ExchangeInfo->ModeTransitionMemory = (UINT32)
+ (ExchangeInfo->BufferStart + CpuMpData->AddressMap.ModeTransitionOffset);
+ }
+
+ ExchangeInfo->ModeHighMemory = ExchangeInfo->ModeTransitionMemory +
+ (UINT32)ExchangeInfo->ModeOffset -
+ (UINT32)CpuMpData->AddressMap.ModeTransitionOffset;
+ ExchangeInfo->ModeHighSegment = (UINT16)ExchangeInfo->CodeSegment;
+}
+
+/**
+ Helper function that waits until the finished AP count reaches the specified
+ limit, or the specified timeout elapses (whichever comes first).
+
+ @param[in] CpuMpData Pointer to CPU MP Data.
+ @param[in] FinishedApLimit The number of finished APs to wait for.
+ @param[in] TimeLimit The number of microseconds to wait for.
+**/
+VOID
+TimedWaitForApFinish (
+ IN CPU_MP_DATA *CpuMpData,
+ IN UINT32 FinishedApLimit,
+ IN UINT32 TimeLimit
+ );
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+BackupAndPrepareWakeupBuffer(
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) CpuMpData->BackupBuffer,
+ (VOID *) CpuMpData->WakeupBuffer,
+ CpuMpData->BackupBufferSize
+ );
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->AddressMap.RendezvousFunnelAddress,
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize
+ );
+}
+
+/**
+ Restore wakeup buffer data.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+RestoreWakeupBuffer(
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ CopyMem (
+ (VOID *) CpuMpData->WakeupBuffer,
+ (VOID *) CpuMpData->BackupBuffer,
+ CpuMpData->BackupBufferSize
+ );
+}
+
+/**
+ Calculate the size of the reset vector.
+
+ @param[in] AddressMap The pointer to Address Map structure.
+
+ @return Total amount of memory required for the AP reset area
+**/
+STATIC
+UINTN
+GetApResetVectorSize (
+ IN MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ )
+{
+ UINTN Size;
+
+ Size = AddressMap->RendezvousFunnelSize +
+ AddressMap->SwitchToRealSize +
+ sizeof (MP_CPU_EXCHANGE_INFO);
+
+ //
+ // The AP reset stack is only used by SEV-ES guests. Do not add to the
+ // allocation if SEV-ES is not enabled.
+ //
+ if (PcdGetBool (PcdSevEsIsEnabled)) {
+ //
+ // Stack location is based on APIC ID, so use the total number of
+ // processors for calculating the total stack area.
+ //
+ Size += AP_RESET_STACK_SIZE * PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+
+ Size = ALIGN_VALUE (Size, CPU_STACK_ALIGNMENT);
+ }
+
+ return Size;
+}
+
+/**
+ Allocate reset vector buffer.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateResetVector (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ UINTN ApResetVectorSize;
+
+ if (CpuMpData->WakeupBuffer == (UINTN) -1) {
+ ApResetVectorSize = GetApResetVectorSize (&CpuMpData->AddressMap);
+
+ CpuMpData->WakeupBuffer = GetWakeupBuffer (ApResetVectorSize);
+ CpuMpData->MpCpuExchangeInfo = (MP_CPU_EXCHANGE_INFO *) (UINTN)
+ (CpuMpData->WakeupBuffer +
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize);
+ CpuMpData->WakeupBufferHigh = GetModeTransitionBuffer (
+ CpuMpData->AddressMap.RendezvousFunnelSize +
+ CpuMpData->AddressMap.SwitchToRealSize -
+ CpuMpData->AddressMap.ModeTransitionOffset
+ );
+ //
+ // The reset stack starts at the end of the buffer.
+ //
+ CpuMpData->SevEsAPResetStackStart = CpuMpData->WakeupBuffer + ApResetVectorSize;
+ }
+ BackupAndPrepareWakeupBuffer (CpuMpData);
+}
+
+/**
+ Free AP reset vector buffer.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+FreeResetVector (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ //
+ // If SEV-ES is enabled, the reset area is needed for AP parking and
+ // and AP startup in the OS, so the reset area is reserved. Do not
+ // perform the restore as this will overwrite memory which has data
+ // needed by SEV-ES.
+ //
+ if (!CpuMpData->SevEsIsEnabled) {
+ RestoreWakeupBuffer (CpuMpData);
+ }
+}
+
+/**
+ Allocate the SEV-ES AP jump table buffer.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+AllocateSevEsAPMemory (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ if (CpuMpData->SevEsAPBuffer == (UINTN) -1) {
+ CpuMpData->SevEsAPBuffer =
+ CpuMpData->SevEsIsEnabled ? GetSevEsAPMemory () : 0;
+ }
+}
+
+/**
+ Program the SEV-ES AP jump table buffer.
+
+ @param[in] SipiVector The SIPI vector used for the AP Reset
+**/
+VOID
+SetSevEsJumpTable (
+ IN UINTN SipiVector
+ )
+{
+ SEV_ES_AP_JMP_FAR *JmpFar;
+ UINT32 Offset, InsnByte;
+ UINT8 LoNib, HiNib;
+
+ JmpFar = (SEV_ES_AP_JMP_FAR *) (UINTN) FixedPcdGet32 (PcdSevEsWorkAreaBase);
+ ASSERT (JmpFar != NULL);
+
+ //
+ // Obtain the address of the Segment/Rip location in the workarea.
+ // This will be set to a value derived from the SIPI vector and will
+ // be the memory address used for the far jump below.
+ //
+ Offset = FixedPcdGet32 (PcdSevEsWorkAreaBase);
+ Offset += sizeof (JmpFar->InsnBuffer);
+ LoNib = (UINT8) Offset;
+ HiNib = (UINT8) (Offset >> 8);
+
+ //
+ // Program the workarea (which is the initial AP boot address) with
+ // far jump to the SIPI vector (where XX and YY represent the
+ // address of where the SIPI vector is stored.
+ //
+ // JMP FAR [CS:XXYY] => 2E FF 2E YY XX
+ //
+ InsnByte = 0;
+ JmpFar->InsnBuffer[InsnByte++] = 0x2E; // CS override prefix
+ JmpFar->InsnBuffer[InsnByte++] = 0xFF; // JMP (FAR)
+ JmpFar->InsnBuffer[InsnByte++] = 0x2E; // ModRM (JMP memory location)
+ JmpFar->InsnBuffer[InsnByte++] = LoNib; // YY offset ...
+ JmpFar->InsnBuffer[InsnByte++] = HiNib; // XX offset ...
+
+ //
+ // Program the Segment/Rip based on the SIPI vector (always at least
+ // 16-byte aligned, so Rip is set to 0).
+ //
+ JmpFar->Rip = 0;
+ JmpFar->Segment = (UINT16) (SipiVector >> 4);
+}
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+ @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument, OPTIONAL
+ IN BOOLEAN WakeUpDisabledAps
+ )
+{
+ volatile MP_CPU_EXCHANGE_INFO *ExchangeInfo;
+ UINTN Index;
+ CPU_AP_DATA *CpuData;
+ BOOLEAN ResetVectorRequired;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+
+ CpuMpData->FinishedCount = 0;
+ ResetVectorRequired = FALSE;
+
+ if (CpuMpData->WakeUpByInitSipiSipi ||
+ CpuMpData->InitFlag != ApInitDone) {
+ ResetVectorRequired = TRUE;
+ AllocateResetVector (CpuMpData);
+ AllocateSevEsAPMemory (CpuMpData);
+ FillExchangeInfoData (CpuMpData);
+ SaveLocalApicTimerSetting (CpuMpData);
+ }
+
+ if (CpuMpData->ApLoopMode == ApInMwaitLoop) {
+ //
+ // Get AP target C-state each time when waking up AP,
+ // for it maybe updated by platform again
+ //
+ CpuMpData->ApTargetCState = PcdGet8 (PcdCpuApTargetCstate);
+ }
+
+ ExchangeInfo = CpuMpData->MpCpuExchangeInfo;
+
+ if (Broadcast) {
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (Index != CpuMpData->BspNumber) {
+ CpuData = &CpuMpData->CpuData[Index];
+ //
+ // All AP(include disabled AP) will be woke up by INIT-SIPI-SIPI, but
+ // the AP procedure will be skipped for disabled AP because AP state
+ // is not CpuStateReady.
+ //
+ if (GetApState (CpuData) == CpuStateDisabled && !WakeUpDisabledAps) {
+ continue;
+ }
+
+ CpuData->ApFunction = (UINTN) Procedure;
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ if (CpuMpData->InitFlag != ApInitConfig) {
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+ }
+ }
+ }
+ if (ResetVectorRequired) {
+ //
+ // For SEV-ES, the initial AP boot address will be defined by
+ // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
+ // from the original INIT-SIPI-SIPI.
+ //
+ if (CpuMpData->SevEsIsEnabled) {
+ SetSevEsJumpTable (ExchangeInfo->BufferStart);
+ }
+
+ //
+ // Wakeup all APs
+ //
+ SendInitSipiSipiAllExcludingSelf ((UINT32) ExchangeInfo->BufferStart);
+ }
+ if (CpuMpData->InitFlag == ApInitConfig) {
+ if (PcdGet32 (PcdCpuBootLogicalProcessorNumber) > 0) {
+ //
+ // The AP enumeration algorithm below is suitable only when the
+ // platform can tell us the *exact* boot CPU count in advance.
+ //
+ // The wait below finishes only when the detected AP count reaches
+ // (PcdCpuBootLogicalProcessorNumber - 1), regardless of how long that
+ // takes. If at least one AP fails to check in (meaning a platform
+ // hardware bug), the detection hangs forever, by design. If the actual
+ // boot CPU count in the system is higher than
+ // PcdCpuBootLogicalProcessorNumber (meaning a platform
+ // misconfiguration), then some APs may complete initialization after
+ // the wait finishes, and cause undefined behavior.
+ //
+ TimedWaitForApFinish (
+ CpuMpData,
+ PcdGet32 (PcdCpuBootLogicalProcessorNumber) - 1,
+ MAX_UINT32 // approx. 71 minutes
+ );
+ } else {
+ //
+ // The AP enumeration algorithm below is suitable for two use cases.
+ //
+ // (1) The check-in time for an individual AP is bounded, and APs run
+ // through their initialization routines strongly concurrently. In
+ // particular, the number of concurrently running APs
+ // ("NumApsExecuting") is never expected to fall to zero
+ // *temporarily* -- it is expected to fall to zero only when all
+ // APs have checked-in.
+ //
+ // In this case, the platform is supposed to set
+ // PcdCpuApInitTimeOutInMicroSeconds to a low-ish value (just long
+ // enough for one AP to start initialization). The timeout will be
+ // reached soon, and remaining APs are collected by watching
+ // NumApsExecuting fall to zero. If NumApsExecuting falls to zero
+ // mid-process, while some APs have not completed initialization,
+ // the behavior is undefined.
+ //
+ // (2) The check-in time for an individual AP is unbounded, and/or APs
+ // may complete their initializations widely spread out. In
+ // particular, some APs may finish initialization before some APs
+ // even start.
+ //
+ // In this case, the platform is supposed to set
+ // PcdCpuApInitTimeOutInMicroSeconds to a high-ish value. The AP
+ // enumeration will always take that long (except when the boot CPU
+ // count happens to be maximal, that is,
+ // PcdCpuMaxLogicalProcessorNumber). All APs are expected to
+ // check-in before the timeout, and NumApsExecuting is assumed zero
+ // at timeout. APs that miss the time-out may cause undefined
+ // behavior.
+ //
+ TimedWaitForApFinish (
+ CpuMpData,
+ PcdGet32 (PcdCpuMaxLogicalProcessorNumber) - 1,
+ PcdGet32 (PcdCpuApInitTimeOutInMicroSeconds)
+ );
+
+ while (CpuMpData->MpCpuExchangeInfo->NumApsExecuting != 0) {
+ CpuPause();
+ }
+ }
+ } else {
+ //
+ // Wait all APs waken up if this is not the 1st broadcast of SIPI
+ //
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ CpuData = &CpuMpData->CpuData[Index];
+ if (Index != CpuMpData->BspNumber) {
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+ }
+ }
+ } else {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->ApFunction = (UINTN) Procedure;
+ CpuData->ApFunctionArgument = (UINTN) ProcedureArgument;
+ SetApState (CpuData, CpuStateReady);
+ //
+ // Wakeup specified AP
+ //
+ ASSERT (CpuMpData->InitFlag != ApInitConfig);
+ *(UINT32 *) CpuData->StartupApSignal = WAKEUP_AP_SIGNAL;
+ if (ResetVectorRequired) {
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+
+ //
+ // For SEV-ES, the initial AP boot address will be defined by
+ // PcdSevEsWorkAreaBase. The Segment/Rip must be the jump address
+ // from the original INIT-SIPI-SIPI.
+ //
+ if (CpuMpData->SevEsIsEnabled) {
+ SetSevEsJumpTable (ExchangeInfo->BufferStart);
+ }
+
+ SendInitSipiSipi (
+ CpuInfoInHob[ProcessorNumber].ApicId,
+ (UINT32) ExchangeInfo->BufferStart
+ );
+ }
+ //
+ // Wait specified AP waken up
+ //
+ WaitApWakeup (CpuData->StartupApSignal);
+ }
+
+ if (ResetVectorRequired) {
+ FreeResetVector (CpuMpData);
+ }
+
+ //
+ // After one round of Wakeup Ap actions, need to re-sync ApLoopMode with
+ // WakeUpByInitSipiSipi flag. WakeUpByInitSipiSipi flag maybe changed by
+ // S3SmmInitDone Ppi.
+ //
+ CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
+}
+
+/**
+ Calculate timeout value and return the current performance counter value.
+
+ Calculate the number of performance counter ticks required for a timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+ @param[in] TimeoutInMicroseconds Timeout value in microseconds.
+ @param[out] CurrentTime Returns the current value of the performance counter.
+
+ @return Expected time stamp counter for timeout.
+ If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ as infinity.
+
+**/
+UINT64
+CalculateTimeout (
+ IN UINTN TimeoutInMicroseconds,
+ OUT UINT64 *CurrentTime
+ )
+{
+ UINT64 TimeoutInSeconds;
+ UINT64 TimestampCounterFreq;
+
+ //
+ // Read the current value of the performance counter
+ //
+ *CurrentTime = GetPerformanceCounter ();
+
+ //
+ // If TimeoutInMicroseconds is 0, return value is also 0, which is recognized
+ // as infinity.
+ //
+ if (TimeoutInMicroseconds == 0) {
+ return 0;
+ }
+
+ //
+ // GetPerformanceCounterProperties () returns the timestamp counter's frequency
+ // in Hz.
+ //
+ TimestampCounterFreq = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Check the potential overflow before calculate the number of ticks for the timeout value.
+ //
+ if (DivU64x64Remainder (MAX_UINT64, TimeoutInMicroseconds, NULL) < TimestampCounterFreq) {
+ //
+ // Convert microseconds into seconds if direct multiplication overflows
+ //
+ TimeoutInSeconds = DivU64x32 (TimeoutInMicroseconds, 1000000);
+ //
+ // Assertion if the final tick count exceeds MAX_UINT64
+ //
+ ASSERT (DivU64x64Remainder (MAX_UINT64, TimeoutInSeconds, NULL) >= TimestampCounterFreq);
+ return MultU64x64 (TimestampCounterFreq, TimeoutInSeconds);
+ } else {
+ //
+ // No overflow case, multiply the return value with TimeoutInMicroseconds and then divide
+ // it by 1,000,000, to get the number of ticks for the timeout value.
+ //
+ return DivU64x32 (
+ MultU64x64 (
+ TimestampCounterFreq,
+ TimeoutInMicroseconds
+ ),
+ 1000000
+ );
+ }
+}
+
+/**
+ Checks whether timeout expires.
+
+ Check whether the number of elapsed performance counter ticks required for
+ a timeout condition has been reached.
+ If Timeout is zero, which means infinity, return value is always FALSE.
+
+ @param[in, out] PreviousTime On input, the value of the performance counter
+ when it was last read.
+ On output, the current value of the performance
+ counter
+ @param[in] TotalTime The total amount of elapsed time in performance
+ counter ticks.
+ @param[in] Timeout The number of performance counter ticks required
+ to reach a timeout condition.
+
+ @retval TRUE A timeout condition has been reached.
+ @retval FALSE A timeout condition has not been reached.
+
+**/
+BOOLEAN
+CheckTimeout (
+ IN OUT UINT64 *PreviousTime,
+ IN UINT64 *TotalTime,
+ IN UINT64 Timeout
+ )
+{
+ UINT64 Start;
+ UINT64 End;
+ UINT64 CurrentTime;
+ INT64 Delta;
+ INT64 Cycle;
+
+ if (Timeout == 0) {
+ return FALSE;
+ }
+ GetPerformanceCounterProperties (&Start, &End);
+ Cycle = End - Start;
+ if (Cycle < 0) {
+ Cycle = -Cycle;
+ }
+ Cycle++;
+ CurrentTime = GetPerformanceCounter();
+ Delta = (INT64) (CurrentTime - *PreviousTime);
+ if (Start > End) {
+ Delta = -Delta;
+ }
+ if (Delta < 0) {
+ Delta += Cycle;
+ }
+ *TotalTime += Delta;
+ *PreviousTime = CurrentTime;
+ if (*TotalTime > Timeout) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Helper function that waits until the finished AP count reaches the specified
+ limit, or the specified timeout elapses (whichever comes first).
+
+ @param[in] CpuMpData Pointer to CPU MP Data.
+ @param[in] FinishedApLimit The number of finished APs to wait for.
+ @param[in] TimeLimit The number of microseconds to wait for.
+**/
+VOID
+TimedWaitForApFinish (
+ IN CPU_MP_DATA *CpuMpData,
+ IN UINT32 FinishedApLimit,
+ IN UINT32 TimeLimit
+ )
+{
+ //
+ // CalculateTimeout() and CheckTimeout() consider a TimeLimit of 0
+ // "infinity", so check for (TimeLimit == 0) explicitly.
+ //
+ if (TimeLimit == 0) {
+ return;
+ }
+
+ CpuMpData->TotalTime = 0;
+ CpuMpData->ExpectedTime = CalculateTimeout (
+ TimeLimit,
+ &CpuMpData->CurrentTime
+ );
+ while (CpuMpData->FinishedCount < FinishedApLimit &&
+ !CheckTimeout (
+ &CpuMpData->CurrentTime,
+ &CpuMpData->TotalTime,
+ CpuMpData->ExpectedTime
+ )) {
+ CpuPause ();
+ }
+
+ if (CpuMpData->FinishedCount >= FinishedApLimit) {
+ DEBUG ((
+ DEBUG_VERBOSE,
+ "%a: reached FinishedApLimit=%u in %Lu microseconds\n",
+ __FUNCTION__,
+ FinishedApLimit,
+ DivU64x64Remainder (
+ MultU64x32 (CpuMpData->TotalTime, 1000000),
+ GetPerformanceCounterProperties (NULL, NULL),
+ NULL
+ )
+ ));
+ }
+}
+
+/**
+ Reset an AP to Idle state.
+
+ Any task being executed by the AP will be aborted and the AP
+ will be waiting for a new task in Wait-For-SIPI state.
+
+ @param[in] ProcessorNumber The handle number of processor.
+**/
+VOID
+ResetProcessorToIdleState (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ CpuMpData->InitFlag = ApInitReconfig;
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, NULL, NULL, TRUE);
+ while (CpuMpData->FinishedCount < 1) {
+ CpuPause ();
+ }
+ CpuMpData->InitFlag = ApInitDone;
+
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateIdle);
+}
+
+/**
+ Searches for the next waiting AP.
+
+ Search for the next AP that is put in waiting state by single-threaded StartupAllAPs().
+
+ @param[out] NextProcessorNumber Pointer to the processor number of the next waiting AP.
+
+ @retval EFI_SUCCESS The next waiting AP has been found.
+ @retval EFI_NOT_FOUND No waiting AP exists.
+
+**/
+EFI_STATUS
+GetNextWaitingProcessorNumber (
+ OUT UINTN *NextProcessorNumber
+ )
+{
+ UINTN ProcessorNumber;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ *NextProcessorNumber = ProcessorNumber;
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+
+ //
+ // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
+ // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+ // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
+ //
+ //
+ // If the AP finishes for StartupThisAP(), return EFI_SUCCESS.
+ //
+ if (GetApState(CpuData) == CpuStateFinished) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = TRUE;
+ }
+ SetApState (CpuData, CpuStateIdle);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If timeout expires for StartupThisAP(), report timeout.
+ //
+ if (CheckTimeout (&CpuData->CurrentTime, &CpuData->TotalTime, CpuData->ExpectedTime)) {
+ if (CpuData->Finished != NULL) {
+ *(CpuData->Finished) = FALSE;
+ }
+ //
+ // Reset failed AP to idle state
+ //
+ ResetProcessorToIdleState (ProcessorNumber);
+
+ return EFI_TIMEOUT;
+ }
+ }
+ return EFI_NOT_READY;
+}
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ )
+{
+ UINTN ProcessorNumber;
+ UINTN NextProcessorNumber;
+ UINTN ListIndex;
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+
+ CpuMpData = GetCpuMpData ();
+
+ NextProcessorNumber = 0;
+
+ //
+ // Go through all APs that are responsible for the StartupAllAPs().
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ if (!CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ continue;
+ }
+
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ //
+ // Check the CPU state of AP. If it is CpuStateIdle, then the AP has finished its task.
+ // Only BSP and corresponding AP access this unit of CPU Data. This means the AP will not modify the
+ // value of state after setting the it to CpuStateIdle, so BSP can safely make use of its value.
+ //
+ if (GetApState(CpuData) == CpuStateFinished) {
+ CpuMpData->RunningCount --;
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ SetApState(CpuData, CpuStateIdle);
+
+ //
+ // If in Single Thread mode, then search for the next waiting AP for execution.
+ //
+ if (CpuMpData->SingleThread) {
+ Status = GetNextWaitingProcessorNumber (&NextProcessorNumber);
+
+ if (!EFI_ERROR (Status)) {
+ WakeUpAP (
+ CpuMpData,
+ FALSE,
+ (UINT32) NextProcessorNumber,
+ CpuMpData->Procedure,
+ CpuMpData->ProcArguments,
+ TRUE
+ );
+ }
+ }
+ }
+ }
+
+ //
+ // If all APs finish, return EFI_SUCCESS.
+ //
+ if (CpuMpData->RunningCount == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // If timeout expires, report timeout.
+ //
+ if (CheckTimeout (
+ &CpuMpData->CurrentTime,
+ &CpuMpData->TotalTime,
+ CpuMpData->ExpectedTime)
+ ) {
+ //
+ // If FailedCpuList is not NULL, record all failed APs in it.
+ //
+ if (CpuMpData->FailedCpuList != NULL) {
+ *CpuMpData->FailedCpuList =
+ AllocatePool ((CpuMpData->RunningCount + 1) * sizeof (UINTN));
+ ASSERT (*CpuMpData->FailedCpuList != NULL);
+ }
+ ListIndex = 0;
+
+ for (ProcessorNumber = 0; ProcessorNumber < CpuMpData->CpuCount; ProcessorNumber++) {
+ //
+ // Check whether this processor is responsible for StartupAllAPs().
+ //
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ //
+ // Reset failed APs to idle state
+ //
+ ResetProcessorToIdleState (ProcessorNumber);
+ CpuMpData->CpuData[ProcessorNumber].Waiting = FALSE;
+ if (CpuMpData->FailedCpuList != NULL) {
+ (*CpuMpData->FailedCpuList)[ListIndex++] = ProcessorNumber;
+ }
+ }
+ }
+ if (CpuMpData->FailedCpuList != NULL) {
+ (*CpuMpData->FailedCpuList)[ListIndex] = END_OF_CPU_LIST;
+ }
+ return EFI_TIMEOUT;
+ }
+ return EFI_NOT_READY;
+}
+
+/**
+ MP Initialize Library initialization.
+
+ This service will allocate AP reset vector and wakeup all APs to do APs
+ initialization.
+
+ This service must be invoked before all other MP Initialize Library
+ service are invoked.
+
+ @retval EFI_SUCCESS MP initialization succeeds.
+ @retval Others MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibInitialize (
+ VOID
+ )
+{
+ CPU_MP_DATA *OldCpuMpData;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ UINT32 MaxLogicalProcessorNumber;
+ UINT32 ApStackSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+ CPU_VOLATILE_REGISTERS VolatileRegisters;
+ UINTN BufferSize;
+ UINT32 MonitorFilterSize;
+ VOID *MpBuffer;
+ UINTN Buffer;
+ CPU_MP_DATA *CpuMpData;
+ UINT8 ApLoopMode;
+ UINT8 *MonitorBuffer;
+ UINTN Index;
+ UINTN ApResetVectorSize;
+ UINTN BackupBufferAddr;
+ UINTN ApIdtBase;
+
+ OldCpuMpData = GetCpuMpDataFromGuidedHob ();
+ if (OldCpuMpData == NULL) {
+ MaxLogicalProcessorNumber = PcdGet32(PcdCpuMaxLogicalProcessorNumber);
+ } else {
+ MaxLogicalProcessorNumber = OldCpuMpData->CpuCount;
+ }
+ ASSERT (MaxLogicalProcessorNumber != 0);
+
+ AsmGetAddressMap (&AddressMap);
+ ApResetVectorSize = GetApResetVectorSize (&AddressMap);
+ ApStackSize = PcdGet32(PcdCpuApStackSize);
+ ApLoopMode = GetApLoopMode (&MonitorFilterSize);
+
+ //
+ // Save BSP's Control registers for APs.
+ //
+ SaveVolatileRegisters (&VolatileRegisters);
+
+ BufferSize = ApStackSize * MaxLogicalProcessorNumber;
+ BufferSize += MonitorFilterSize * MaxLogicalProcessorNumber;
+ BufferSize += ApResetVectorSize;
+ BufferSize = ALIGN_VALUE (BufferSize, 8);
+ BufferSize += VolatileRegisters.Idtr.Limit + 1;
+ BufferSize += sizeof (CPU_MP_DATA);
+ BufferSize += (sizeof (CPU_AP_DATA) + sizeof (CPU_INFO_IN_HOB))* MaxLogicalProcessorNumber;
+ MpBuffer = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
+ ASSERT (MpBuffer != NULL);
+ ZeroMem (MpBuffer, BufferSize);
+ Buffer = (UINTN) MpBuffer;
+
+ //
+ // The layout of the Buffer is as below:
+ //
+ // +--------------------+ <-- Buffer
+ // AP Stacks (N)
+ // +--------------------+ <-- MonitorBuffer
+ // AP Monitor Filters (N)
+ // +--------------------+ <-- BackupBufferAddr (CpuMpData->BackupBuffer)
+ // Backup Buffer
+ // +--------------------+
+ // Padding
+ // +--------------------+ <-- ApIdtBase (8-byte boundary)
+ // AP IDT All APs share one separate IDT. So AP can get address of CPU_MP_DATA from IDT Base.
+ // +--------------------+ <-- CpuMpData
+ // CPU_MP_DATA
+ // +--------------------+ <-- CpuMpData->CpuData
+ // CPU_AP_DATA (N)
+ // +--------------------+ <-- CpuMpData->CpuInfoInHob
+ // CPU_INFO_IN_HOB (N)
+ // +--------------------+
+ //
+ MonitorBuffer = (UINT8 *) (Buffer + ApStackSize * MaxLogicalProcessorNumber);
+ BackupBufferAddr = (UINTN) MonitorBuffer + MonitorFilterSize * MaxLogicalProcessorNumber;
+ ApIdtBase = ALIGN_VALUE (BackupBufferAddr + ApResetVectorSize, 8);
+ CpuMpData = (CPU_MP_DATA *) (ApIdtBase + VolatileRegisters.Idtr.Limit + 1);
+ CpuMpData->Buffer = Buffer;
+ CpuMpData->CpuApStackSize = ApStackSize;
+ CpuMpData->BackupBuffer = BackupBufferAddr;
+ CpuMpData->BackupBufferSize = ApResetVectorSize;
+ CpuMpData->WakeupBuffer = (UINTN) -1;
+ CpuMpData->CpuCount = 1;
+ CpuMpData->BspNumber = 0;
+ CpuMpData->WaitEvent = NULL;
+ CpuMpData->SwitchBspFlag = FALSE;
+ CpuMpData->CpuData = (CPU_AP_DATA *) (CpuMpData + 1);
+ CpuMpData->CpuInfoInHob = (UINT64) (UINTN) (CpuMpData->CpuData + MaxLogicalProcessorNumber);
+ InitializeSpinLock(&CpuMpData->MpLock);
+ CpuMpData->SevEsIsEnabled = PcdGetBool (PcdSevEsIsEnabled);
+ CpuMpData->SevEsAPBuffer = (UINTN) -1;
+ CpuMpData->GhcbBase = PcdGet64 (PcdGhcbBase);
+
+ //
+ // Make sure no memory usage outside of the allocated buffer.
+ //
+ ASSERT ((CpuMpData->CpuInfoInHob + sizeof (CPU_INFO_IN_HOB) * MaxLogicalProcessorNumber) ==
+ Buffer + BufferSize);
+
+ //
+ // Duplicate BSP's IDT to APs.
+ // All APs share one separate IDT. So AP can get the address of CpuMpData by using IDTR.BASE + IDTR.LIMIT + 1
+ //
+ CopyMem ((VOID *)ApIdtBase, (VOID *)VolatileRegisters.Idtr.Base, VolatileRegisters.Idtr.Limit + 1);
+ VolatileRegisters.Idtr.Base = ApIdtBase;
+ //
+ // Don't pass BSP's TR to APs to avoid AP init failure.
+ //
+ VolatileRegisters.Tr = 0;
+ CopyMem (&CpuMpData->CpuData[0].VolatileRegisters, &VolatileRegisters, sizeof (VolatileRegisters));
+ //
+ // Set BSP basic information
+ //
+ InitializeApData (CpuMpData, 0, 0, CpuMpData->Buffer + ApStackSize);
+ //
+ // Save assembly code information
+ //
+ CopyMem (&CpuMpData->AddressMap, &AddressMap, sizeof (MP_ASSEMBLY_ADDRESS_MAP));
+ //
+ // Finally set AP loop mode
+ //
+ CpuMpData->ApLoopMode = ApLoopMode;
+ DEBUG ((DEBUG_INFO, "AP Loop Mode is %d\n", CpuMpData->ApLoopMode));
+
+ CpuMpData->WakeUpByInitSipiSipi = (CpuMpData->ApLoopMode == ApInHltLoop);
+
+ //
+ // Set up APs wakeup signal buffer
+ //
+ for (Index = 0; Index < MaxLogicalProcessorNumber; Index++) {
+ CpuMpData->CpuData[Index].StartupApSignal =
+ (UINT32 *)(MonitorBuffer + MonitorFilterSize * Index);
+ }
+ //
+ // Enable the local APIC for Virtual Wire Mode.
+ //
+ ProgramVirtualWireMode ();
+
+ if (OldCpuMpData == NULL) {
+ if (MaxLogicalProcessorNumber > 1) {
+ //
+ // Wakeup all APs and calculate the processor count in system
+ //
+ CollectProcessorCount (CpuMpData);
+ }
+ } else {
+ //
+ // APs have been wakeup before, just get the CPU Information
+ // from HOB
+ //
+ OldCpuMpData->NewCpuMpData = CpuMpData;
+ CpuMpData->CpuCount = OldCpuMpData->CpuCount;
+ CpuMpData->BspNumber = OldCpuMpData->BspNumber;
+ CpuMpData->CpuInfoInHob = OldCpuMpData->CpuInfoInHob;
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ InitializeSpinLock(&CpuMpData->CpuData[Index].ApLock);
+ CpuMpData->CpuData[Index].CpuHealthy = (CpuInfoInHob[Index].Health == 0)? TRUE:FALSE;
+ CpuMpData->CpuData[Index].ApFunction = 0;
+ }
+ }
+
+ if (!GetMicrocodePatchInfoFromHob (
+ &CpuMpData->MicrocodePatchAddress,
+ &CpuMpData->MicrocodePatchRegionSize
+ )) {
+ //
+ // The microcode patch information cache HOB does not exist, which means
+ // the microcode patches data has not been loaded into memory yet
+ //
+ ShadowMicrocodeUpdatePatch (CpuMpData);
+ }
+
+ //
+ // Detect and apply Microcode on BSP
+ //
+ MicrocodeDetect (CpuMpData, CpuMpData->BspNumber);
+ //
+ // Store BSP's MTRR setting
+ //
+ MtrrGetAllMtrrs (&CpuMpData->MtrrTable);
+
+ //
+ // Wakeup APs to do some AP initialize sync (Microcode & MTRR)
+ //
+ if (CpuMpData->CpuCount > 1) {
+ if (OldCpuMpData != NULL) {
+ //
+ // Only needs to use this flag for DXE phase to update the wake up
+ // buffer. Wakeup buffer allocated in PEI phase is no longer valid
+ // in DXE.
+ //
+ CpuMpData->InitFlag = ApInitReconfig;
+ }
+ WakeUpAP (CpuMpData, TRUE, 0, ApInitializeSync, CpuMpData, TRUE);
+ //
+ // Wait for all APs finished initialization
+ //
+ while (CpuMpData->FinishedCount < (CpuMpData->CpuCount - 1)) {
+ CpuPause ();
+ }
+ if (OldCpuMpData != NULL) {
+ CpuMpData->InitFlag = ApInitDone;
+ }
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ SetApState (&CpuMpData->CpuData[Index], CpuStateIdle);
+ }
+ }
+
+ //
+ // Dump the microcode revision for each core.
+ //
+ DEBUG_CODE (
+ UINT32 ThreadId;
+ UINT32 ExpectedMicrocodeRevision;
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ GetProcessorLocationByApicId (CpuInfoInHob[Index].InitialApicId, NULL, NULL, &ThreadId);
+ if (ThreadId == 0) {
+ //
+ // MicrocodeDetect() loads microcode in first thread of each core, so,
+ // CpuMpData->CpuData[Index].MicrocodeEntryAddr is initialized only for first thread of each core.
+ //
+ ExpectedMicrocodeRevision = 0;
+ if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
+ ExpectedMicrocodeRevision = ((CPU_MICROCODE_HEADER *)(UINTN)CpuMpData->CpuData[Index].MicrocodeEntryAddr)->UpdateRevision;
+ }
+ DEBUG ((
+ DEBUG_INFO, "CPU[%04d]: Microcode revision = %08x, expected = %08x\n",
+ Index, CpuMpData->CpuData[Index].MicrocodeRevision, ExpectedMicrocodeRevision
+ ));
+ }
+ }
+ );
+ //
+ // Initialize global data for MP support
+ //
+ InitMpGlobalData (CpuMpData);
+
+ 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] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ CPU_INFO_IN_HOB *CpuInfoInHob;
+ UINTN OriginalProcessorNumber;
+
+ CpuMpData = GetCpuMpData ();
+ CpuInfoInHob = (CPU_INFO_IN_HOB *) (UINTN) CpuMpData->CpuInfoInHob;
+
+ //
+ // Lower 24 bits contains the actual processor number.
+ //
+ OriginalProcessorNumber = ProcessorNumber;
+ ProcessorNumber &= BIT24 - 1;
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ ProcessorInfoBuffer->ProcessorId = (UINT64) CpuInfoInHob[ProcessorNumber].ApicId;
+ ProcessorInfoBuffer->StatusFlag = 0;
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_AS_BSP_BIT;
+ }
+ if (CpuMpData->CpuData[ProcessorNumber].CpuHealthy) {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_HEALTH_STATUS_BIT;
+ }
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+ ProcessorInfoBuffer->StatusFlag &= ~PROCESSOR_ENABLED_BIT;
+ } else {
+ ProcessorInfoBuffer->StatusFlag |= PROCESSOR_ENABLED_BIT;
+ }
+
+ //
+ // Get processor location information
+ //
+ GetProcessorLocationByApicId (
+ CpuInfoInHob[ProcessorNumber].ApicId,
+ &ProcessorInfoBuffer->Location.Package,
+ &ProcessorInfoBuffer->Location.Core,
+ &ProcessorInfoBuffer->Location.Thread
+ );
+
+ if ((OriginalProcessorNumber & CPU_V2_EXTENDED_TOPOLOGY) != 0) {
+ GetProcessorLocation2ByApicId (
+ CpuInfoInHob[ProcessorNumber].ApicId,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Package,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Die,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Tile,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Module,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Core,
+ &ProcessorInfoBuffer->ExtendedInformation.Location2.Thread
+ );
+ }
+
+ if (HealthData != NULL) {
+ HealthData->Uint32 = CpuInfoInHob[ProcessorNumber].Health;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+ @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 others Failed to switch BSP.
+
+**/
+EFI_STATUS
+SwitchBSPWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ CPU_STATE State;
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+ BOOLEAN OldInterruptState;
+ BOOLEAN OldTimerInterruptState;
+
+ //
+ // Save and Disable Local APIC timer interrupt
+ //
+ OldTimerInterruptState = GetApicTimerInterruptState ();
+ DisableApicTimerInterrupt ();
+ //
+ // Before send both BSP and AP to a procedure to exchange their roles,
+ // interrupt must be disabled. This is because during the exchange role
+ // process, 2 CPU may use 1 stack. If interrupt happens, the stack will
+ // be corrupted, since interrupt return address will be pushed to stack
+ // by hardware.
+ //
+ OldInterruptState = SaveAndDisableInterrupts ();
+
+ //
+ // Mask LINT0 & LINT1 for the old BSP
+ //
+ DisableLvtInterrupts ();
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified AP is disabled
+ //
+ State = GetApState (&CpuMpData->CpuData[ProcessorNumber]);
+ if (State == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether ProcessorNumber specifies the current BSP
+ //
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether specified AP is busy
+ //
+ if (State == CpuStateBusy) {
+ return EFI_NOT_READY;
+ }
+
+ CpuMpData->BSPInfo.State = CPU_SWITCH_STATE_IDLE;
+ CpuMpData->APInfo.State = CPU_SWITCH_STATE_IDLE;
+ CpuMpData->SwitchBspFlag = TRUE;
+ CpuMpData->NewBspNumber = ProcessorNumber;
+
+ //
+ // Clear the BSP bit of MSR_IA32_APIC_BASE
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.BSP = 0;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+
+ //
+ // Need to wakeUp AP (future BSP).
+ //
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, FutureBSPProc, CpuMpData, TRUE);
+
+ AsmExchangeRole (&CpuMpData->BSPInfo, &CpuMpData->APInfo);
+
+ //
+ // Set the BSP bit of MSR_IA32_APIC_BASE on new BSP
+ //
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ ApicBaseMsr.Bits.BSP = 1;
+ AsmWriteMsr64 (MSR_IA32_APIC_BASE, ApicBaseMsr.Uint64);
+ ProgramVirtualWireMode ();
+
+ //
+ // Wait for old BSP finished AP task
+ //
+ while (GetApState (&CpuMpData->CpuData[CallerNumber]) != CpuStateFinished) {
+ CpuPause ();
+ }
+
+ CpuMpData->SwitchBspFlag = FALSE;
+ //
+ // Set old BSP enable state
+ //
+ if (!EnableOldBSP) {
+ SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateDisabled);
+ } else {
+ SetApState (&CpuMpData->CpuData[CallerNumber], CpuStateIdle);
+ }
+ //
+ // Save new BSP number
+ //
+ CpuMpData->BspNumber = (UINT32) ProcessorNumber;
+
+ //
+ // Restore interrupt state.
+ //
+ SetInterruptState (OldInterruptState);
+
+ if (OldTimerInterruptState) {
+ EnableApicTimerInterrupt ();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to let the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ @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.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval others Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (!EnableAP) {
+ SetApState (&CpuMpData->CpuData[ProcessorNumber], CpuStateDisabled);
+ } else {
+ ResetProcessorToIdleState (ProcessorNumber);
+ }
+
+ if (HealthFlag != NULL) {
+ CpuMpData->CpuData[ProcessorNumber].CpuHealthy =
+ (BOOLEAN) ((*HealthFlag & PROCESSOR_HEALTH_STATUS_BIT) != 0);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[out] ProcessorNumber Pointer to the handle number of 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
+ MpInitLibGetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ OUT UINTN *ProcessorNumber
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ CpuMpData = GetCpuMpData ();
+
+ return GetProcessorNumber (CpuMpData, ProcessorNumber);
+}
+
+/**
+ 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[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 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 and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ UINTN CallerNumber;
+ UINTN ProcessorNumber;
+ UINTN EnabledProcessorNumber;
+ UINTN Index;
+
+ CpuMpData = GetCpuMpData ();
+
+ if ((NumberOfProcessors == NULL) && (NumberOfEnabledProcessors == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ProcessorNumber = CpuMpData->CpuCount;
+ EnabledProcessorNumber = 0;
+ for (Index = 0; Index < ProcessorNumber; Index++) {
+ if (GetApState (&CpuMpData->CpuData[Index]) != CpuStateDisabled) {
+ EnabledProcessorNumber ++;
+ }
+ }
+
+ if (NumberOfProcessors != NULL) {
+ *NumberOfProcessors = ProcessorNumber;
+ }
+ if (NumberOfEnabledProcessors != NULL) {
+ *NumberOfEnabledProcessors = EnabledProcessorNumber;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @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] ExcludeBsp Whether let BSP also trig this task.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList 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.
+
+ @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 others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN BOOLEAN ExcludeBsp,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ CPU_MP_DATA *CpuMpData;
+ UINTN ProcessorCount;
+ UINTN ProcessorNumber;
+ UINTN CallerNumber;
+ CPU_AP_DATA *CpuData;
+ BOOLEAN HasEnabledAp;
+ CPU_STATE ApState;
+
+ CpuMpData = GetCpuMpData ();
+
+ if (FailedCpuList != NULL) {
+ *FailedCpuList = NULL;
+ }
+
+ if (CpuMpData->CpuCount == 1 && ExcludeBsp) {
+ return EFI_NOT_STARTED;
+ }
+
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Update AP state
+ //
+ CheckAndUpdateApsStatus ();
+
+ ProcessorCount = CpuMpData->CpuCount;
+ HasEnabledAp = FALSE;
+ //
+ // Check whether all enabled APs are idle.
+ // If any enabled AP is not idle, return EFI_NOT_READY.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ if (ProcessorNumber != CpuMpData->BspNumber) {
+ ApState = GetApState (CpuData);
+ if (ApState != CpuStateDisabled) {
+ HasEnabledAp = TRUE;
+ if (ApState != CpuStateIdle) {
+ //
+ // If any enabled APs are busy, return EFI_NOT_READY.
+ //
+ return EFI_NOT_READY;
+ }
+ }
+ }
+ }
+
+ if (!HasEnabledAp && ExcludeBsp) {
+ //
+ // If no enabled AP exists and not include Bsp to do the procedure, return EFI_NOT_STARTED.
+ //
+ return EFI_NOT_STARTED;
+ }
+
+ CpuMpData->RunningCount = 0;
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->Waiting = FALSE;
+ if (ProcessorNumber != CpuMpData->BspNumber) {
+ if (CpuData->State == CpuStateIdle) {
+ //
+ // Mark this processor as responsible for current calling.
+ //
+ CpuData->Waiting = TRUE;
+ CpuMpData->RunningCount++;
+ }
+ }
+ }
+
+ CpuMpData->Procedure = Procedure;
+ CpuMpData->ProcArguments = ProcedureArgument;
+ CpuMpData->SingleThread = SingleThread;
+ CpuMpData->FinishedCount = 0;
+ CpuMpData->FailedCpuList = FailedCpuList;
+ CpuMpData->ExpectedTime = CalculateTimeout (
+ TimeoutInMicroseconds,
+ &CpuMpData->CurrentTime
+ );
+ CpuMpData->TotalTime = 0;
+ CpuMpData->WaitEvent = WaitEvent;
+
+ if (!SingleThread) {
+ WakeUpAP (CpuMpData, TRUE, 0, Procedure, ProcedureArgument, FALSE);
+ } else {
+ for (ProcessorNumber = 0; ProcessorNumber < ProcessorCount; ProcessorNumber++) {
+ if (ProcessorNumber == CallerNumber) {
+ continue;
+ }
+ if (CpuMpData->CpuData[ProcessorNumber].Waiting) {
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
+ break;
+ }
+ }
+ }
+
+ if (!ExcludeBsp) {
+ //
+ // Start BSP.
+ //
+ Procedure (ProcedureArgument);
+ }
+
+ Status = EFI_SUCCESS;
+ if (WaitEvent == NULL) {
+ do {
+ Status = CheckAllAPs ();
+ } while (Status == EFI_NOT_READY);
+ }
+
+ return Status;
+}
+
+/**
+ Worker function to let the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] ProcessorNumber The handle number of the AP.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If AP returns from Procedure before the
+ timeout expires, its content is set to TRUE.
+ Otherwise, the value is set to FALSE.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval others Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+ 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;
+ CPU_MP_DATA *CpuMpData;
+ CPU_AP_DATA *CpuData;
+ UINTN CallerNumber;
+
+ CpuMpData = GetCpuMpData ();
+
+ if (Finished != NULL) {
+ *Finished = FALSE;
+ }
+
+ //
+ // Check whether caller processor is BSP
+ //
+ MpInitLibWhoAmI (&CallerNumber);
+ if (CallerNumber != CpuMpData->BspNumber) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check whether processor with the handle specified by ProcessorNumber exists
+ //
+ if (ProcessorNumber >= CpuMpData->CpuCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check whether specified processor is BSP
+ //
+ if (ProcessorNumber == CpuMpData->BspNumber) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check parameter Procedure
+ //
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Update AP state
+ //
+ CheckAndUpdateApsStatus ();
+
+ //
+ // Check whether specified AP is disabled
+ //
+ if (GetApState (&CpuMpData->CpuData[ProcessorNumber]) == CpuStateDisabled) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If WaitEvent is not NULL, execute in non-blocking mode.
+ // BSP saves data for CheckAPsStatus(), and returns EFI_SUCCESS.
+ // CheckAPsStatus() will check completion and timeout periodically.
+ //
+ CpuData = &CpuMpData->CpuData[ProcessorNumber];
+ CpuData->WaitEvent = WaitEvent;
+ CpuData->Finished = Finished;
+ CpuData->ExpectedTime = CalculateTimeout (TimeoutInMicroseconds, &CpuData->CurrentTime);
+ CpuData->TotalTime = 0;
+
+ WakeUpAP (CpuMpData, FALSE, ProcessorNumber, Procedure, ProcedureArgument, TRUE);
+
+ //
+ // If WaitEvent is NULL, execute in blocking mode.
+ // BSP checks AP's state until it finishes or TimeoutInMicrosecsond expires.
+ //
+ Status = EFI_SUCCESS;
+ if (WaitEvent == NULL) {
+ do {
+ Status = CheckThisAP (ProcessorNumber);
+ } while (Status == EFI_NOT_READY);
+ }
+
+ return Status;
+}
+
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = NULL;
+ GuidHob = GetFirstGuidHob (&mCpuInitMpLibHobGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuMpData = (CPU_MP_DATA *) (*(UINTN *) DataInHob);
+ }
+ return CpuMpData;
+}
+
+/**
+ This service executes a caller provided function on all enabled CPUs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @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. TimeoutInMicroseconds is ignored
+ for BSP.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS In blocking mode, all CPUs have finished before
+ the timeout expired.
+ @retval EFI_SUCCESS In non-blocking mode, function has been dispatched
+ to all enabled CPUs.
+ @retval EFI_DEVICE_ERROR Caller processor is AP.
+ @retval EFI_NOT_READY Any enabled APs are busy.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+ @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
+MpInitLibStartupAllCPUs (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ return StartupAllCPUsWorker (
+ Procedure,
+ FALSE,
+ FALSE,
+ NULL,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ NULL
+ );
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.h
new file mode 100644
index 00000000..aea1d27e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/MpLib.h
@@ -0,0 +1,745 @@
+/** @file
+ Common header file for MP Initialize Library.
+
+ Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+ Copyright (c) 2020, AMD Inc. All rights reserved.<BR>
+
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MP_LIB_H_
+#define _MP_LIB_H_
+
+#include <PiPei.h>
+
+#include <Register/Intel/Cpuid.h>
+#include <Register/Amd/Cpuid.h>
+#include <Register/Intel/Msr.h>
+#include <Register/Intel/LocalApic.h>
+#include <Register/Intel/Microcode.h>
+
+#include <Library/MpInitLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/CpuLib.h>
+#include <Library/UefiCpuLib.h>
+#include <Library/TimerLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MicrocodeLib.h>
+
+#include <Guid/MicrocodePatchHob.h>
+
+#define WAKEUP_AP_SIGNAL SIGNATURE_32 ('S', 'T', 'A', 'P')
+
+#define CPU_INIT_MP_LIB_HOB_GUID \
+ { \
+ 0x58eb6a19, 0x3699, 0x4c68, { 0xa8, 0x36, 0xda, 0xcd, 0x8e, 0xdc, 0xad, 0x4a } \
+ }
+
+//
+// The MP data for switch BSP
+//
+#define CPU_SWITCH_STATE_IDLE 0
+#define CPU_SWITCH_STATE_STORED 1
+#define CPU_SWITCH_STATE_LOADED 2
+
+//
+// Default maximum number of entries to store the microcode patches information
+//
+#define DEFAULT_MAX_MICROCODE_PATCH_NUM 8
+
+//
+// Data structure for microcode patch information
+//
+typedef struct {
+ UINTN Address;
+ UINTN Size;
+} MICROCODE_PATCH_INFO;
+
+//
+// CPU exchange information for switch BSP
+//
+typedef struct {
+ UINT8 State; // offset 0
+ UINTN StackPointer; // offset 4 / 8
+ IA32_DESCRIPTOR Gdtr; // offset 8 / 16
+ IA32_DESCRIPTOR Idtr; // offset 14 / 26
+} CPU_EXCHANGE_ROLE_INFO;
+
+//
+// AP loop state when APs are in idle state
+// It's value is the same with PcdCpuApLoopMode
+//
+typedef enum {
+ ApInHltLoop = 1,
+ ApInMwaitLoop = 2,
+ ApInRunLoop = 3
+} AP_LOOP_MODE;
+
+//
+// AP initialization state during APs wakeup
+//
+typedef enum {
+ ApInitConfig = 1,
+ ApInitReconfig = 2,
+ ApInitDone = 3
+} AP_INIT_STATE;
+
+//
+// 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,
+ CpuStateBusy,
+ CpuStateFinished,
+ CpuStateDisabled
+} CPU_STATE;
+
+//
+// CPU volatile registers around INIT-SIPI-SIPI
+//
+typedef struct {
+ UINTN Cr0;
+ UINTN Cr3;
+ UINTN Cr4;
+ UINTN Dr0;
+ UINTN Dr1;
+ UINTN Dr2;
+ UINTN Dr3;
+ UINTN Dr6;
+ UINTN Dr7;
+ IA32_DESCRIPTOR Gdtr;
+ IA32_DESCRIPTOR Idtr;
+ UINT16 Tr;
+} CPU_VOLATILE_REGISTERS;
+
+//
+// AP related data
+//
+typedef struct {
+ SPIN_LOCK ApLock;
+ volatile UINT32 *StartupApSignal;
+ volatile UINTN ApFunction;
+ volatile UINTN ApFunctionArgument;
+ BOOLEAN CpuHealthy;
+ volatile CPU_STATE State;
+ CPU_VOLATILE_REGISTERS VolatileRegisters;
+ BOOLEAN Waiting;
+ BOOLEAN *Finished;
+ UINT64 ExpectedTime;
+ UINT64 CurrentTime;
+ UINT64 TotalTime;
+ EFI_EVENT WaitEvent;
+ UINT32 ProcessorSignature;
+ UINT8 PlatformId;
+ UINT64 MicrocodeEntryAddr;
+ UINT32 MicrocodeRevision;
+} CPU_AP_DATA;
+
+//
+// Basic CPU information saved in Guided HOB.
+// Because the contents will be shard between PEI and DXE,
+// we need to make sure the each fields offset same in different
+// architecture.
+//
+#pragma pack (1)
+typedef struct {
+ UINT32 InitialApicId;
+ UINT32 ApicId;
+ UINT32 Health;
+ UINT64 ApTopOfStack;
+} CPU_INFO_IN_HOB;
+#pragma pack ()
+
+//
+// AP reset code information including code address and size,
+// this structure will be shared be C code and assembly code.
+// It is natural aligned by design.
+//
+typedef struct {
+ UINT8 *RendezvousFunnelAddress;
+ UINTN ModeEntryOffset;
+ UINTN RendezvousFunnelSize;
+ UINT8 *RelocateApLoopFuncAddress;
+ UINTN RelocateApLoopFuncSize;
+ UINTN ModeTransitionOffset;
+ UINTN SwitchToRealSize;
+ UINTN SwitchToRealOffset;
+ UINTN SwitchToRealNoNxOffset;
+ UINTN SwitchToRealPM16ModeOffset;
+ UINTN SwitchToRealPM16ModeSize;
+} MP_ASSEMBLY_ADDRESS_MAP;
+
+typedef struct _CPU_MP_DATA CPU_MP_DATA;
+
+#pragma pack(1)
+
+//
+// MP CPU exchange information for AP reset code
+// This structure is required to be packed because fixed field offsets
+// into this structure are used in assembly code in this module
+//
+typedef struct {
+ UINTN StackStart;
+ UINTN StackSize;
+ UINTN CFunction;
+ IA32_DESCRIPTOR GdtrProfile;
+ IA32_DESCRIPTOR IdtrProfile;
+ UINTN BufferStart;
+ UINTN ModeOffset;
+ UINTN ApIndex;
+ UINTN CodeSegment;
+ UINTN DataSegment;
+ UINTN EnableExecuteDisable;
+ UINTN Cr3;
+ UINTN InitFlag;
+ CPU_INFO_IN_HOB *CpuInfo;
+ UINTN NumApsExecuting;
+ CPU_MP_DATA *CpuMpData;
+ UINTN InitializeFloatingPointUnitsAddress;
+ UINT32 ModeTransitionMemory;
+ UINT16 ModeTransitionSegment;
+ UINT32 ModeHighMemory;
+ UINT16 ModeHighSegment;
+ //
+ // Enable5LevelPaging indicates whether 5-level paging is enabled in long mode.
+ //
+ BOOLEAN Enable5LevelPaging;
+ BOOLEAN SevEsIsEnabled;
+ UINTN GhcbBase;
+} MP_CPU_EXCHANGE_INFO;
+
+#pragma pack()
+
+//
+// CPU MP Data save in memory
+//
+struct _CPU_MP_DATA {
+ UINT64 CpuInfoInHob;
+ UINT32 CpuCount;
+ UINT32 BspNumber;
+ //
+ // The above fields data will be passed from PEI to DXE
+ // Please make sure the fields offset same in the different
+ // architecture.
+ //
+ SPIN_LOCK MpLock;
+ UINTN Buffer;
+ UINTN CpuApStackSize;
+ MP_ASSEMBLY_ADDRESS_MAP AddressMap;
+ UINTN WakeupBuffer;
+ UINTN WakeupBufferHigh;
+ UINTN BackupBuffer;
+ UINTN BackupBufferSize;
+
+ volatile UINT32 FinishedCount;
+ UINT32 RunningCount;
+ BOOLEAN SingleThread;
+ EFI_AP_PROCEDURE Procedure;
+ VOID *ProcArguments;
+ BOOLEAN *Finished;
+ UINT64 ExpectedTime;
+ UINT64 CurrentTime;
+ UINT64 TotalTime;
+ EFI_EVENT WaitEvent;
+ UINTN **FailedCpuList;
+
+ AP_INIT_STATE InitFlag;
+ BOOLEAN SwitchBspFlag;
+ UINTN NewBspNumber;
+ CPU_EXCHANGE_ROLE_INFO BSPInfo;
+ CPU_EXCHANGE_ROLE_INFO APInfo;
+ MTRR_SETTINGS MtrrTable;
+ UINT8 ApLoopMode;
+ UINT8 ApTargetCState;
+ UINT16 PmCodeSegment;
+ UINT16 Pm16CodeSegment;
+ CPU_AP_DATA *CpuData;
+ volatile MP_CPU_EXCHANGE_INFO *MpCpuExchangeInfo;
+
+ UINT32 CurrentTimerCount;
+ UINTN DivideValue;
+ UINT8 Vector;
+ BOOLEAN PeriodicMode;
+ BOOLEAN TimerInterruptState;
+ UINT64 MicrocodePatchAddress;
+ UINT64 MicrocodePatchRegionSize;
+
+ //
+ // Whether need to use Init-Sipi-Sipi to wake up the APs.
+ // Two cases need to set this value to TRUE. One is in HLT
+ // loop mode, the other is resume from S3 which loop mode
+ // will be hardcode change to HLT mode by PiSmmCpuDxeSmm
+ // driver.
+ //
+ BOOLEAN WakeUpByInitSipiSipi;
+
+ BOOLEAN SevEsIsEnabled;
+ UINTN SevEsAPBuffer;
+ UINTN SevEsAPResetStackStart;
+ CPU_MP_DATA *NewCpuMpData;
+
+ UINT64 GhcbBase;
+};
+
+#define AP_SAFE_STACK_SIZE 128
+#define AP_RESET_STACK_SIZE AP_SAFE_STACK_SIZE
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 InsnBuffer[8];
+ UINT16 Rip;
+ UINT16 Segment;
+} SEV_ES_AP_JMP_FAR;
+
+#pragma pack()
+
+/**
+ Assembly code to move an AP from long mode to real mode.
+
+ Move an AP from long mode to real mode in preparation to invoking
+ the reset vector. This is used for SEV-ES guests where a hypervisor
+ is not allowed to set the CS and RIP to point to the reset vector.
+
+ @param[in] BufferStart The reset vector target.
+ @param[in] Code16 16-bit protected mode code segment value.
+ @param[in] Code32 32-bit protected mode code segment value.
+ @param[in] StackStart The start of a stack to be used for transitioning
+ from long mode to real mode.
+**/
+typedef
+VOID
+(EFIAPI AP_RESET) (
+ IN UINTN BufferStart,
+ IN UINT16 Code16,
+ IN UINT16 Code32,
+ IN UINTN StackStart
+ );
+
+extern EFI_GUID mCpuInitMpLibHobGuid;
+
+/**
+ Assembly code to place AP into safe loop mode.
+
+ Place AP into targeted C-State if MONITOR is supported, otherwise
+ place AP into hlt state.
+ Place AP in protected mode if the current is long mode. Due to AP maybe
+ wakeup by some hardware event. It could avoid accessing page table that
+ may not available during booting to OS.
+
+ @param[in] MwaitSupport TRUE indicates MONITOR is supported.
+ FALSE indicates MONITOR is not supported.
+ @param[in] ApTargetCState Target C-State value.
+ @param[in] PmCodeSegment Protected mode code segment value.
+**/
+typedef
+VOID
+(EFIAPI * ASM_RELOCATE_AP_LOOP) (
+ IN BOOLEAN MwaitSupport,
+ IN UINTN ApTargetCState,
+ IN UINTN PmCodeSegment,
+ IN UINTN TopOfApStack,
+ IN UINTN NumberToFinish,
+ IN UINTN Pm16CodeSegment,
+ IN UINTN SevEsAPJumpTable,
+ IN UINTN WakeupBuffer
+ );
+
+/**
+ Assembly code to get starting address and size of the rendezvous entry for APs.
+ Information for fixing a jump instruction in the code is also returned.
+
+ @param[out] AddressMap Output buffer for address map information.
+**/
+VOID
+EFIAPI
+AsmGetAddressMap (
+ OUT MP_ASSEMBLY_ADDRESS_MAP *AddressMap
+ );
+
+/**
+ This function is called by both the BSP and the AP which is to become the BSP to
+ Exchange execution context including stack between them. After return from this
+ function, the BSP becomes AP and the AP becomes the BSP.
+
+ @param[in] MyInfo Pointer to buffer holding the exchanging information for the executing processor.
+ @param[in] OthersInfo Pointer to buffer holding the exchanging information for the peer.
+
+**/
+VOID
+EFIAPI
+AsmExchangeRole (
+ IN CPU_EXCHANGE_ROLE_INFO *MyInfo,
+ IN CPU_EXCHANGE_ROLE_INFO *OthersInfo
+ );
+
+/**
+ Get the pointer to CPU MP Data structure.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ );
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param[in] WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ );
+
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ );
+
+/**
+ Return the address of the SEV-ES AP jump table.
+
+ This buffer is required in order for an SEV-ES guest to transition from
+ UEFI into an OS.
+
+ @return Return SEV-ES AP jump table buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ );
+
+/**
+ This function will be called by BSP to wakeup AP.
+
+ @param[in] CpuMpData Pointer to CPU MP Data
+ @param[in] Broadcast TRUE: Send broadcast IPI to all APs
+ FALSE: Send IPI to AP by ApicId
+ @param[in] ProcessorNumber The handle number of specified processor
+ @param[in] Procedure The function to be invoked by AP
+ @param[in] ProcedureArgument The argument to be passed into AP function
+ @param[in] WakeUpDisabledAps Whether need to wake up disabled APs in broadcast mode.
+**/
+VOID
+WakeUpAP (
+ IN CPU_MP_DATA *CpuMpData,
+ IN BOOLEAN Broadcast,
+ IN UINTN ProcessorNumber,
+ IN EFI_AP_PROCEDURE Procedure, OPTIONAL
+ IN VOID *ProcedureArgument, OPTIONAL
+ IN BOOLEAN WakeUpDisabledAps OPTIONAL
+ );
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @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] ExcludeBsp Whether let BSP also trig this task.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] FailedCpuList 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.
+
+ @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 others Failed to Startup all APs.
+
+**/
+EFI_STATUS
+StartupAllCPUsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN BOOLEAN ExcludeBsp,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ );
+
+/**
+ Worker function to let the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] ProcessorNumber The handle number of the AP.
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service.
+ @param[in] TimeoutInMicroseconds Indicates the time limit in microseconds for
+ APs to return from Procedure, either for
+ blocking or non-blocking mode.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+ @param[out] Finished If AP returns from Procedure before the
+ timeout expires, its content is set to TRUE.
+ Otherwise, the value is set to FALSE.
+
+ @retval EFI_SUCCESS In blocking mode, specified AP finished before
+ the timeout expires.
+ @retval others Failed to Startup AP.
+
+**/
+EFI_STATUS
+StartupThisAPWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ );
+
+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+ @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 others Failed to switch BSP.
+
+**/
+EFI_STATUS
+SwitchBSPWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ );
+
+/**
+ Worker function to let the caller enable or disable an AP from this point onward.
+ This service may only be called from the BSP.
+
+ @param[in] ProcessorNumber The handle number of AP.
+ @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.
+
+ @retval EFI_SUCCESS The specified AP was enabled or disabled successfully.
+ @retval others Failed to Enable/Disable AP.
+
+**/
+EFI_STATUS
+EnableDisableApWorker (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ );
+
+/**
+ Get pointer to CPU MP Data structure from GUIDed HOB.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpDataFromGuidedHob (
+ VOID
+ );
+
+/** Checks status of specified AP.
+
+ This function checks whether the specified AP has finished the task assigned
+ by StartupThisAP(), and whether timeout expires.
+
+ @param[in] ProcessorNumber The handle number of processor.
+
+ @retval EFI_SUCCESS Specified AP has finished task assigned by StartupThisAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY Specified AP has not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckThisAP (
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Checks status of all APs.
+
+ This function checks whether all APs have finished task assigned by StartupAllAPs(),
+ and whether timeout expires.
+
+ @retval EFI_SUCCESS All APs have finished task assigned by StartupAllAPs().
+ @retval EFI_TIMEOUT The timeout expires.
+ @retval EFI_NOT_READY APs have not finished task and timeout has not expired.
+**/
+EFI_STATUS
+CheckAllAPs (
+ VOID
+ );
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ );
+
+/**
+ Detect whether specified processor can find matching microcode patch and load it.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+ @param[in] ProcessorNumber The handle number of the processor. The range is
+ from 0 to the total number of logical processors
+ minus 1.
+**/
+VOID
+MicrocodeDetect (
+ IN CPU_MP_DATA *CpuMpData,
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Shadow the required microcode patches data into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+ShadowMicrocodeUpdatePatch (
+ IN OUT CPU_MP_DATA *CpuMpData
+ );
+
+/**
+ Get the cached microcode patch base address and size from the microcode patch
+ information cache HOB.
+
+ @param[out] Address Base address of the microcode patches data.
+ It will be updated if the microcode patch
+ information cache HOB is found.
+ @param[out] RegionSize Size of the microcode patches data.
+ It will be updated if the microcode patch
+ information cache HOB is found.
+
+ @retval TRUE The microcode patch information cache HOB is found.
+ @retval FALSE The microcode patch information cache HOB is not found.
+
+**/
+BOOLEAN
+GetMicrocodePatchInfoFromHob (
+ UINT64 *Address,
+ UINT64 *RegionSize
+ );
+
+/**
+ Detect whether Mwait-monitor feature is supported.
+
+ @retval TRUE Mwait-monitor feature is supported.
+ @retval FALSE Mwait-monitor feature is not supported.
+**/
+BOOLEAN
+IsMwaitSupport (
+ VOID
+ );
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ );
+
+/**
+ Find the current Processor number by APIC ID.
+
+ @param[in] CpuMpData Pointer to PEI CPU MP Data
+ @param[out] ProcessorNumber Return the pocessor number found
+
+ @retval EFI_SUCCESS ProcessorNumber is found and returned.
+ @retval EFI_NOT_FOUND ProcessorNumber is not found.
+**/
+EFI_STATUS
+GetProcessorNumber (
+ IN CPU_MP_DATA *CpuMpData,
+ OUT UINTN *ProcessorNumber
+ );
+
+/**
+ This funtion will try to invoke platform specific microcode shadow logic to
+ relocate microcode update patches into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+
+ @retval EFI_SUCCESS Shadow microcode success.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
+ @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
+ PPI/Protocol.
+**/
+EFI_STATUS
+PlatformShadowMicrocode (
+ IN OUT CPU_MP_DATA *CpuMpData
+ );
+
+#endif
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
new file mode 100644
index 00000000..bd9a6b5f
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.inf
@@ -0,0 +1,74 @@
+## @file
+# MP Initialize Library instance for PEI driver.
+#
+# Copyright (c) 2016 - 2021, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiMpInitLib
+ MODULE_UNI_FILE = PeiMpInitLib.uni
+ FILE_GUID = B00F6090-7739-4830-B906-E0032D388987
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = MpInitLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.IA32]
+ Ia32/MpFuncs.nasm
+
+[Sources.X64]
+ X64/MpFuncs.nasm
+
+[Sources.common]
+ MpEqu.inc
+ PeiMpLib.c
+ MpLib.c
+ MpLib.h
+ Microcode.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ LocalApicLib
+ MemoryAllocationLib
+ HobLib
+ MtrrLib
+ CpuLib
+ UefiCpuLib
+ SynchronizationLib
+ PeiServicesLib
+ PcdLib
+ VmgExitLib
+ MicrocodeLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuBootLogicalProcessorNumber ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApInitTimeOutInMicroSeconds ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApStackSize ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMicrocodePatchRegionSize ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApLoopMode ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuApTargetCstate ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevEsIsEnabled ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdSevEsWorkAreaBase ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdGhcbBase ## CONSUMES
+
+[Ppis]
+ gEdkiiPeiShadowMicrocodePpiGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEdkiiS3SmmInitDoneGuid
+ gEdkiiMicrocodePatchHobGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.uni
new file mode 100644
index 00000000..81eca4e0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpInitLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// MP Initialize Library instance for PEI driver.
+//
+// MP Initialize Library instance for PEI driver.
+//
+// Copyright (c) 2016, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Library instance for PEI driver."
+
+#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Library instance for PEI driver."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
new file mode 100644
index 00000000..4ee7ef6a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/PeiMpLib.c
@@ -0,0 +1,729 @@
+/** @file
+ MP initialize support functions for PEI phase.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MpLib.h"
+#include <Library/PeiServicesLib.h>
+#include <Guid/S3SmmInitDone.h>
+#include <Ppi/ShadowMicrocode.h>
+
+/**
+ S3 SMM Init Done notification function.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDesc Address of the notification descriptor data structure.
+ @param InvokePpi Address of the PPI that was invoked.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyOnS3SmmInitDonePpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *InvokePpi
+ );
+
+
+//
+// Global function
+//
+EFI_PEI_NOTIFY_DESCRIPTOR mS3SmmInitDoneNotifyDesc = {
+ EFI_PEI_PPI_DESCRIPTOR_NOTIFY_CALLBACK | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEdkiiS3SmmInitDoneGuid,
+ NotifyOnS3SmmInitDonePpi
+};
+
+/**
+ S3 SMM Init Done notification function.
+
+ @param PeiServices Indirect reference to the PEI Services Table.
+ @param NotifyDesc Address of the notification descriptor data structure.
+ @param InvokePpi Address of the PPI that was invoked.
+
+ @retval EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+NotifyOnS3SmmInitDonePpi (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_NOTIFY_DESCRIPTOR *NotifyDesc,
+ IN VOID *InvokePpi
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+
+ CpuMpData = GetCpuMpData ();
+
+ //
+ // PiSmmCpuDxeSmm driver hardcode change the loop mode to HLT mode.
+ // So in this notify function, code need to check the current loop
+ // mode, if it is not HLT mode, code need to change loop mode back
+ // to the original mode.
+ //
+ if (CpuMpData->ApLoopMode != ApInHltLoop) {
+ CpuMpData->WakeUpByInitSipiSipi = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Enable Debug Agent to support source debugging on AP function.
+
+**/
+VOID
+EnableDebugAgent (
+ VOID
+ )
+{
+}
+
+/**
+ Get pointer to CPU MP Data structure.
+ For BSP, the pointer is retrieved from HOB.
+ For AP, the structure is just after IDT.
+
+ @return The pointer to CPU MP Data structure.
+**/
+CPU_MP_DATA *
+GetCpuMpData (
+ VOID
+ )
+{
+ CPU_MP_DATA *CpuMpData;
+ MSR_IA32_APIC_BASE_REGISTER ApicBaseMsr;
+ IA32_DESCRIPTOR Idtr;
+
+ ApicBaseMsr.Uint64 = AsmReadMsr64 (MSR_IA32_APIC_BASE);
+ if (ApicBaseMsr.Bits.BSP == 1) {
+ CpuMpData = GetCpuMpDataFromGuidedHob ();
+ ASSERT (CpuMpData != NULL);
+ } else {
+ AsmReadIdtr (&Idtr);
+ CpuMpData = (CPU_MP_DATA *) (Idtr.Base + Idtr.Limit + 1);
+ }
+ return CpuMpData;
+}
+
+/**
+ Save the pointer to CPU MP Data structure.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure will be saved.
+**/
+VOID
+SaveCpuMpData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ UINT64 Data64;
+ //
+ // Build location of CPU MP DATA buffer in HOB
+ //
+ Data64 = (UINT64) (UINTN) CpuMpData;
+ BuildGuidDataHob (
+ &mCpuInitMpLibHobGuid,
+ (VOID *) &Data64,
+ sizeof (UINT64)
+ );
+}
+
+/**
+ Check if AP wakeup buffer is overlapped with existing allocated buffer.
+
+ @param[in] WakeupBufferStart AP wakeup buffer start address.
+ @param[in] WakeupBufferEnd AP wakeup buffer end address.
+
+ @retval TRUE There is overlap.
+ @retval FALSE There is no overlap.
+**/
+BOOLEAN
+CheckOverlapWithAllocatedBuffer (
+ IN UINT64 WakeupBufferStart,
+ IN UINT64 WakeupBufferEnd
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_MEMORY_ALLOCATION *MemoryHob;
+ BOOLEAN Overlapped;
+ UINT64 MemoryStart;
+ UINT64 MemoryEnd;
+
+ Overlapped = FALSE;
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_MEMORY_ALLOCATION) {
+ MemoryHob = Hob.MemoryAllocation;
+ MemoryStart = MemoryHob->AllocDescriptor.MemoryBaseAddress;
+ MemoryEnd = MemoryHob->AllocDescriptor.MemoryBaseAddress + MemoryHob->AllocDescriptor.MemoryLength;
+ if (!((WakeupBufferStart >= MemoryEnd) || (WakeupBufferEnd <= MemoryStart))) {
+ Overlapped = TRUE;
+ break;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+ return Overlapped;
+}
+
+/**
+ Get available system memory below 1MB by specified size.
+
+ @param[in] WakeupBufferSize Wakeup buffer size required
+
+ @retval other Return wakeup buffer address below 1MB.
+ @retval -1 Cannot find free memory below 1MB.
+**/
+UINTN
+GetWakeupBuffer (
+ IN UINTN WakeupBufferSize
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ UINT64 WakeupBufferStart;
+ UINT64 WakeupBufferEnd;
+
+ WakeupBufferSize = (WakeupBufferSize + SIZE_4KB - 1) & ~(SIZE_4KB - 1);
+
+ //
+ // Get the HOB list for processing
+ //
+ Hob.Raw = GetHobList ();
+
+ //
+ // Collect memory ranges
+ //
+ while (!END_OF_HOB_LIST (Hob)) {
+ if (Hob.Header->HobType == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ if ((Hob.ResourceDescriptor->PhysicalStart < BASE_1MB) &&
+ (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) &&
+ ((Hob.ResourceDescriptor->ResourceAttribute &
+ (EFI_RESOURCE_ATTRIBUTE_READ_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_WRITE_PROTECTED |
+ EFI_RESOURCE_ATTRIBUTE_EXECUTION_PROTECTED
+ )) == 0)
+ ) {
+ //
+ // Need memory under 1MB to be collected here
+ //
+ WakeupBufferEnd = Hob.ResourceDescriptor->PhysicalStart + Hob.ResourceDescriptor->ResourceLength;
+ if (WakeupBufferEnd > BASE_1MB) {
+ //
+ // Wakeup buffer should be under 1MB
+ //
+ WakeupBufferEnd = BASE_1MB;
+ }
+ while (WakeupBufferEnd > WakeupBufferSize) {
+ //
+ // Wakeup buffer should be aligned on 4KB
+ //
+ WakeupBufferStart = (WakeupBufferEnd - WakeupBufferSize) & ~(SIZE_4KB - 1);
+ if (WakeupBufferStart < Hob.ResourceDescriptor->PhysicalStart) {
+ break;
+ }
+ if (CheckOverlapWithAllocatedBuffer (WakeupBufferStart, WakeupBufferEnd)) {
+ //
+ // If this range is overlapped with existing allocated buffer, skip it
+ // and find the next range
+ //
+ WakeupBufferEnd -= WakeupBufferSize;
+ continue;
+ }
+ DEBUG ((DEBUG_INFO, "WakeupBufferStart = %x, WakeupBufferSize = %x\n",
+ WakeupBufferStart, WakeupBufferSize));
+ return (UINTN)WakeupBufferStart;
+ }
+ }
+ }
+ //
+ // Find the next HOB
+ //
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ }
+
+ return (UINTN) -1;
+}
+
+/**
+ Get available EfiBootServicesCode memory below 4GB by specified size.
+
+ This buffer is required to safely transfer AP from real address mode to
+ protected mode or long mode, due to the fact that the buffer returned by
+ GetWakeupBuffer() may be marked as non-executable.
+
+ @param[in] BufferSize Wakeup transition buffer size.
+
+ @retval other Return wakeup transition buffer address below 4GB.
+ @retval 0 Cannot find free memory below 4GB.
+**/
+UINTN
+GetModeTransitionBuffer (
+ IN UINTN BufferSize
+ )
+{
+ //
+ // PEI phase doesn't need to do such transition. So simply return 0.
+ //
+ return 0;
+}
+
+/**
+ Return the address of the SEV-ES AP jump table.
+
+ This buffer is required in order for an SEV-ES guest to transition from
+ UEFI into an OS.
+
+ @return Return SEV-ES AP jump table buffer
+**/
+UINTN
+GetSevEsAPMemory (
+ VOID
+ )
+{
+ //
+ // PEI phase doesn't need to do such transition. So simply return 0.
+ //
+ return 0;
+}
+
+/**
+ Checks APs status and updates APs status if needed.
+
+**/
+VOID
+CheckAndUpdateApsStatus (
+ VOID
+ )
+{
+}
+
+/**
+ Build the microcode patch HOB that contains the base address and size of the
+ microcode patch stored in the memory.
+
+ @param[in] CpuMpData Pointer to the CPU_MP_DATA structure.
+
+**/
+VOID
+BuildMicrocodeCacheHob (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EDKII_MICROCODE_PATCH_HOB *MicrocodeHob;
+ UINTN HobDataLength;
+ UINT32 Index;
+
+ HobDataLength = sizeof (EDKII_MICROCODE_PATCH_HOB) +
+ sizeof (UINT64) * CpuMpData->CpuCount;
+
+ MicrocodeHob = AllocatePool (HobDataLength);
+ if (MicrocodeHob == NULL) {
+ ASSERT (FALSE);
+ return;
+ }
+
+ //
+ // Store the information of the memory region that holds the microcode patches.
+ //
+ MicrocodeHob->MicrocodePatchAddress = CpuMpData->MicrocodePatchAddress;
+ MicrocodeHob->MicrocodePatchRegionSize = CpuMpData->MicrocodePatchRegionSize;
+
+ //
+ // Store the detected microcode patch for each processor as well.
+ //
+ MicrocodeHob->ProcessorCount = CpuMpData->CpuCount;
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ if (CpuMpData->CpuData[Index].MicrocodeEntryAddr != 0) {
+ MicrocodeHob->ProcessorSpecificPatchOffset[Index] =
+ CpuMpData->CpuData[Index].MicrocodeEntryAddr - CpuMpData->MicrocodePatchAddress;
+ } else {
+ MicrocodeHob->ProcessorSpecificPatchOffset[Index] = MAX_UINT64;
+ }
+ }
+
+ BuildGuidDataHob (
+ &gEdkiiMicrocodePatchHobGuid,
+ MicrocodeHob,
+ HobDataLength
+ );
+
+ return;
+}
+
+/**
+ Initialize global data for MP support.
+
+ @param[in] CpuMpData The pointer to CPU MP Data structure.
+**/
+VOID
+InitMpGlobalData (
+ IN CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+
+ BuildMicrocodeCacheHob (CpuMpData);
+ SaveCpuMpData (CpuMpData);
+
+ ///
+ /// Install Notify
+ ///
+ Status = PeiServicesNotifyPpi (&mS3SmmInitDoneNotifyDesc);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ This service executes a caller provided function on all enabled APs.
+
+ @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 MpInitLibStartupAllAPs() or
+ MPInitLibStartupThisAP().
+ 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 Initialization
+ library, 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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_NOT_READY MP Initialize Library is not initialized.
+ @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_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ if (WaitEvent != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return StartupAllCPUsWorker (
+ Procedure,
+ SingleThread,
+ TRUE,
+ NULL,
+ TimeoutInMicroseconds,
+ ProcedureArgument,
+ FailedCpuList
+ );
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP 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
+ MpInitLibGetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP 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 this AP,
+ and go on executing immediately. If this AP
+ 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
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MpInitLibStartupThisAP().
+ 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 on the
+ specified AP.
+ @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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_READY MP Initialize Library is not initialized.
+ @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_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ if (WaitEvent != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return StartupThisAPWorker (
+ Procedure,
+ ProcessorNumber,
+ NULL,
+ 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.
+
+ @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
+ MpInitLibGetNumberOfProcessors().
+ @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_DEVICE_ERROR 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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return SwitchBSPWorker (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.
+
+ @param[in] ProcessorNumber The handle number of 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
+ MpInitLibGetNumberOfProcessors().
+ @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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return EnableDisableApWorker (ProcessorNumber, EnableAP, HealthFlag);
+}
+
+/**
+ This funtion will try to invoke platform specific microcode shadow logic to
+ relocate microcode update patches into memory.
+
+ @param[in, out] CpuMpData The pointer to CPU MP Data structure.
+
+ @retval EFI_SUCCESS Shadow microcode success.
+ @retval EFI_OUT_OF_RESOURCES No enough resource to complete the operation.
+ @retval EFI_UNSUPPORTED Can't find platform specific microcode shadow
+ PPI/Protocol.
+**/
+EFI_STATUS
+PlatformShadowMicrocode (
+ IN OUT CPU_MP_DATA *CpuMpData
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_SHADOW_MICROCODE_PPI *ShadowMicrocodePpi;
+ UINTN CpuCount;
+ EDKII_PEI_MICROCODE_CPU_ID *MicrocodeCpuId;
+ UINTN Index;
+ UINTN BufferSize;
+ VOID *Buffer;
+
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiShadowMicrocodePpiGuid,
+ 0,
+ NULL,
+ (VOID **) &ShadowMicrocodePpi
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CpuCount = CpuMpData->CpuCount;
+ MicrocodeCpuId = (EDKII_PEI_MICROCODE_CPU_ID *) AllocateZeroPool (sizeof (EDKII_PEI_MICROCODE_CPU_ID) * CpuCount);
+ if (MicrocodeCpuId == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < CpuMpData->CpuCount; Index++) {
+ MicrocodeCpuId[Index].ProcessorSignature = CpuMpData->CpuData[Index].ProcessorSignature;
+ MicrocodeCpuId[Index].PlatformId = CpuMpData->CpuData[Index].PlatformId;
+ }
+
+ Status = ShadowMicrocodePpi->ShadowMicrocode (
+ ShadowMicrocodePpi,
+ CpuCount,
+ MicrocodeCpuId,
+ &BufferSize,
+ &Buffer
+ );
+ FreePool (MicrocodeCpuId);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ CpuMpData->MicrocodePatchAddress = (UINTN) Buffer;
+ CpuMpData->MicrocodePatchRegionSize = BufferSize;
+
+ DEBUG ((
+ DEBUG_INFO,
+ "%a: Required microcode patches have been loaded at 0x%lx, with size 0x%lx.\n",
+ __FUNCTION__, CpuMpData->MicrocodePatchAddress, CpuMpData->MicrocodePatchRegionSize
+ ));
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
new file mode 100644
index 00000000..cfc3085d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLib/X64/MpFuncs.nasm
@@ -0,0 +1,778 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2015 - 2021, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; MpFuncs.nasm
+;
+; Abstract:
+;
+; This is the assembly code for MP support
+;
+;-------------------------------------------------------------------------------
+
+%include "MpEqu.inc"
+extern ASM_PFX(InitializeFloatingPointUnits)
+
+DEFAULT REL
+
+SECTION .text
+
+;-------------------------------------------------------------------------------------
+;RendezvousFunnelProc procedure follows. All APs execute their procedure. This
+;procedure serializes all the AP processors through an Init sequence. It must be
+;noted that APs arrive here very raw...ie: real mode, no stack.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs ONLY ON 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+;-------------------------------------------------------------------------------------
+global ASM_PFX(RendezvousFunnelProc)
+ASM_PFX(RendezvousFunnelProc):
+RendezvousFunnelProcStart:
+; At this point CS = 0x(vv00) and ip= 0x0.
+; Save BIST information to ebp firstly
+
+BITS 16
+ mov ebp, eax ; Save BIST information
+
+ mov ax, cs
+ mov ds, ax
+ mov es, ax
+ mov ss, ax
+ xor ax, ax
+ mov fs, ax
+ mov gs, ax
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (BufferStart)
+ mov ebx, [si]
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (DataSegment)
+ mov edx, [si]
+
+ ;
+ ; Get start address of 32-bit code in low memory (<1MB)
+ ;
+ mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeTransitionMemory)
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (GdtrProfile)
+o32 lgdt [cs:si]
+
+ mov si, MP_CPU_EXCHANGE_INFO_FIELD (IdtrProfile)
+o32 lidt [cs:si]
+
+ ;
+ ; Switch to protected mode
+ ;
+ mov eax, cr0 ; Get control register 0
+ or eax, 000000003h ; Set PE bit (bit #0) & MP
+ mov cr0, eax
+
+ ; Switch to 32-bit code (>1MB)
+o32 jmp far [cs:di]
+
+;
+; Following code must be copied to memory with type of EfiBootServicesCode.
+; This is required if NX is enabled for EfiBootServicesCode of memory.
+;
+BITS 32
+Flat32Start: ; protected mode entry point
+ mov ds, dx
+ mov es, dx
+ mov fs, dx
+ mov gs, dx
+ mov ss, dx
+
+ ;
+ ; Enable execute disable bit
+ ;
+ mov esi, MP_CPU_EXCHANGE_INFO_FIELD (EnableExecuteDisable)
+ cmp byte [ebx + esi], 0
+ jz SkipEnableExecuteDisableBit
+
+ mov ecx, 0c0000080h ; EFER MSR number
+ rdmsr ; Read EFER
+ bts eax, 11 ; Enable Execute Disable Bit
+ wrmsr ; Write EFER
+
+SkipEnableExecuteDisableBit:
+ ;
+ ; Enable PAE
+ ;
+ mov eax, cr4
+ bts eax, 5
+
+ mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Enable5LevelPaging)
+ cmp byte [ebx + esi], 0
+ jz SkipEnable5LevelPaging
+
+ ;
+ ; Enable 5 Level Paging
+ ;
+ bts eax, 12 ; Set LA57=1.
+
+SkipEnable5LevelPaging:
+
+ mov cr4, eax
+
+ ;
+ ; Load page table
+ ;
+ mov esi, MP_CPU_EXCHANGE_INFO_FIELD (Cr3) ; Save CR3 in ecx
+ mov ecx, [ebx + esi]
+ mov cr3, ecx ; Load CR3
+
+ ;
+ ; Enable long mode
+ ;
+ mov ecx, 0c0000080h ; EFER MSR number
+ rdmsr ; Read EFER
+ bts eax, 8 ; Set LME=1
+ wrmsr ; Write EFER
+
+ ;
+ ; Enable paging
+ ;
+ mov eax, cr0 ; Read CR0
+ bts eax, 31 ; Set PG=1
+ mov cr0, eax ; Write CR0
+
+ ;
+ ; Far jump to 64-bit code
+ ;
+ mov edi, MP_CPU_EXCHANGE_INFO_FIELD (ModeHighMemory)
+ add edi, ebx
+ jmp far [edi]
+
+BITS 64
+LongModeStart:
+ mov esi, ebx
+ lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitFlag)]
+ cmp qword [edi], 1 ; ApInitConfig
+ jnz GetApicId
+
+ ; Increment the number of APs executing here as early as possible
+ ; This is decremented in C code when AP is finished executing
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (NumApsExecuting)
+ lock inc dword [edi]
+
+ ; AP init
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (ApIndex)
+ mov ebx, 1
+ lock xadd dword [edi], ebx ; EBX = ApIndex++
+ inc ebx ; EBX is CpuNumber
+
+ ; program stack
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackSize)
+ mov eax, dword [edi]
+ mov ecx, ebx
+ inc ecx
+ mul ecx ; EAX = StackSize * (CpuNumber + 1)
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (StackStart)
+ add rax, qword [edi]
+ mov rsp, rax
+
+ lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
+ cmp byte [edi], 1 ; SevEsIsEnabled
+ jne CProcedureInvoke
+
+ ;
+ ; program GHCB
+ ; Each page after the GHCB is a per-CPU page, so the calculation programs
+ ; a GHCB to be every 8KB.
+ ;
+ mov eax, SIZE_4KB
+ shl eax, 1 ; EAX = SIZE_4K * 2
+ mov ecx, ebx
+ mul ecx ; EAX = SIZE_4K * 2 * CpuNumber
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (GhcbBase)
+ add rax, qword [edi]
+ mov rdx, rax
+ shr rdx, 32
+ mov rcx, 0xc0010130
+ wrmsr
+ jmp CProcedureInvoke
+
+GetApicId:
+ lea edi, [esi + MP_CPU_EXCHANGE_INFO_FIELD (SevEsIsEnabled)]
+ cmp byte [edi], 1 ; SevEsIsEnabled
+ jne DoCpuid
+
+ ;
+ ; Since we don't have a stack yet, we can't take a #VC
+ ; exception. Use the GHCB protocol to perform the CPUID
+ ; calls.
+ ;
+ mov rcx, 0xc0010130
+ rdmsr
+ shl rdx, 32
+ or rax, rdx
+ mov rdi, rax ; RDI now holds the original GHCB GPA
+
+ mov rdx, 0 ; CPUID function 0
+ mov rax, 0 ; RAX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ cmp edx, 0bh
+ jb NoX2ApicSevEs ; CPUID level below CPUID_EXTENDED_TOPOLOGY
+
+ mov rdx, 0bh ; CPUID function 0x0b
+ mov rax, 040000000h ; RBX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ test edx, 0ffffh
+ jz NoX2ApicSevEs ; CPUID.0BH:EBX[15:0] is zero
+
+ mov rdx, 0bh ; CPUID function 0x0b
+ mov rax, 0c0000000h ; RDX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+
+ ; Processor is x2APIC capable; 32-bit x2APIC ID is now in EDX
+ jmp RestoreGhcb
+
+NoX2ApicSevEs:
+ ; Processor is not x2APIC capable, so get 8-bit APIC ID
+ mov rdx, 1 ; CPUID function 1
+ mov rax, 040000000h ; RBX register requested
+ or rax, 4
+ wrmsr
+ rep vmmcall
+ rdmsr
+ shr edx, 24
+
+RestoreGhcb:
+ mov rbx, rdx ; Save x2APIC/APIC ID
+
+ mov rdx, rdi ; RDI holds the saved GHCB GPA
+ shr rdx, 32
+ mov eax, edi
+ wrmsr
+
+ mov rdx, rbx
+
+ ; x2APIC ID or APIC ID is in EDX
+ jmp GetProcessorNumber
+
+DoCpuid:
+ mov eax, 0
+ cpuid
+ cmp eax, 0bh
+ jb NoX2Apic ; CPUID level below CPUID_EXTENDED_TOPOLOGY
+
+ mov eax, 0bh
+ xor ecx, ecx
+ cpuid
+ test ebx, 0ffffh
+ jz NoX2Apic ; CPUID.0BH:EBX[15:0] is zero
+
+ ; Processor is x2APIC capable; 32-bit x2APIC ID is already in EDX
+ jmp GetProcessorNumber
+
+NoX2Apic:
+ ; Processor is not x2APIC capable, so get 8-bit APIC ID
+ mov eax, 1
+ cpuid
+ shr ebx, 24
+ mov edx, ebx
+
+GetProcessorNumber:
+ ;
+ ; Get processor number for this AP
+ ; Note that BSP may become an AP due to SwitchBsp()
+ ;
+ xor ebx, ebx
+ lea eax, [esi + MP_CPU_EXCHANGE_INFO_FIELD (CpuInfo)]
+ mov rdi, [eax]
+
+GetNextProcNumber:
+ cmp dword [rdi + CPU_INFO_IN_HOB.InitialApicId], edx ; APIC ID match?
+ jz ProgramStack
+ add rdi, CPU_INFO_IN_HOB_size
+ inc ebx
+ jmp GetNextProcNumber
+
+ProgramStack:
+ mov rsp, qword [rdi + CPU_INFO_IN_HOB.ApTopOfStack]
+
+CProcedureInvoke:
+ push rbp ; Push BIST data at top of AP stack
+ xor rbp, rbp ; Clear ebp for call stack trace
+ push rbp
+ mov rbp, rsp
+
+ mov rax, qword [esi + MP_CPU_EXCHANGE_INFO_FIELD (InitializeFloatingPointUnits)]
+ sub rsp, 20h
+ call rax ; Call assembly function to initialize FPU per UEFI spec
+ add rsp, 20h
+
+ mov edx, ebx ; edx is ApIndex
+ mov ecx, esi
+ add ecx, MP_CPU_EXCHANGE_INFO_OFFSET ; rcx is address of exchange info data buffer
+
+ mov edi, esi
+ add edi, MP_CPU_EXCHANGE_INFO_FIELD (CFunction)
+ mov rax, qword [edi]
+
+ sub rsp, 20h
+ call rax ; Invoke C function
+ add rsp, 20h
+ jmp $ ; Should never reach here
+
+RendezvousFunnelProcEnd:
+
+;-------------------------------------------------------------------------------------
+;SwitchToRealProc procedure follows.
+;ALSO THIS PROCEDURE IS EXECUTED BY APs TRANSITIONING TO 16 BIT MODE. HENCE THIS PROC
+;IS IN MACHINE CODE.
+; SwitchToRealProc (UINTN BufferStart, UINT16 Code16, UINT16 Code32, UINTN StackStart)
+; rcx - Buffer Start
+; rdx - Code16 Selector Offset
+; r8 - Code32 Selector Offset
+; r9 - Stack Start
+;-------------------------------------------------------------------------------------
+global ASM_PFX(SwitchToRealProc)
+ASM_PFX(SwitchToRealProc):
+SwitchToRealProcStart:
+BITS 64
+ cli
+
+ ;
+ ; Get RDX reset value before changing stacks since the
+ ; new stack won't be able to accomodate a #VC exception.
+ ;
+ push rax
+ push rbx
+ push rcx
+ push rdx
+
+ mov rax, 1
+ cpuid
+ mov rsi, rax ; Save off the reset value for RDX
+
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ;
+ ; Establish stack below 1MB
+ ;
+ mov rsp, r9
+
+ ;
+ ; Push ultimate Reset Vector onto the stack
+ ;
+ mov rax, rcx
+ shr rax, 4
+ push word 0x0002 ; RFLAGS
+ push ax ; CS
+ push word 0x0000 ; RIP
+ push word 0x0000 ; For alignment, will be discarded
+
+ ;
+ ; Get address of "16-bit operand size" label
+ ;
+ lea rbx, [PM16Mode]
+
+ ;
+ ; Push addresses used to change to compatibility mode
+ ;
+ lea rax, [CompatMode]
+ push r8
+ push rax
+
+ ;
+ ; Clear R8 - R15, for reset, before going into 32-bit mode
+ ;
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ xor r12, r12
+ xor r13, r13
+ xor r14, r14
+ xor r15, r15
+
+ ;
+ ; Far return into 32-bit mode
+ ;
+o64 retf
+
+BITS 32
+CompatMode:
+ ;
+ ; Set up stack to prepare for exiting protected mode
+ ;
+ push edx ; Code16 CS
+ push ebx ; PM16Mode label address
+
+ ;
+ ; Disable paging
+ ;
+ mov eax, cr0 ; Read CR0
+ btr eax, 31 ; Set PG=0
+ mov cr0, eax ; Write CR0
+
+ ;
+ ; Disable long mode
+ ;
+ mov ecx, 0c0000080h ; EFER MSR number
+ rdmsr ; Read EFER
+ btr eax, 8 ; Set LME=0
+ wrmsr ; Write EFER
+
+ ;
+ ; Disable PAE
+ ;
+ mov eax, cr4 ; Read CR4
+ btr eax, 5 ; Set PAE=0
+ mov cr4, eax ; Write CR4
+
+ mov edx, esi ; Restore RDX reset value
+
+ ;
+ ; Switch to 16-bit operand size
+ ;
+ retf
+
+BITS 16
+ ;
+ ; At entry to this label
+ ; - RDX will have its reset value
+ ; - On the top of the stack
+ ; - Alignment data (two bytes) to be discarded
+ ; - IP for Real Mode (two bytes)
+ ; - CS for Real Mode (two bytes)
+ ;
+ ; This label is also used with AsmRelocateApLoop. During MP finalization,
+ ; the code from PM16Mode to SwitchToRealProcEnd is copied to the start of
+ ; the WakeupBuffer, allowing a parked AP to be booted by an OS.
+ ;
+PM16Mode:
+ mov eax, cr0 ; Read CR0
+ btr eax, 0 ; Set PE=0
+ mov cr0, eax ; Write CR0
+
+ pop ax ; Discard alignment data
+
+ ;
+ ; Clear registers (except RDX and RSP) before going into 16-bit mode
+ ;
+ xor eax, eax
+ xor ebx, ebx
+ xor ecx, ecx
+ xor esi, esi
+ xor edi, edi
+ xor ebp, ebp
+
+ iret
+
+SwitchToRealProcEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmRelocateApLoop (MwaitSupport, ApTargetCState, PmCodeSegment, TopOfApStack, CountTofinish, Pm16CodeSegment, SevEsAPJumpTable, WakeupBuffer);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmRelocateApLoop)
+ASM_PFX(AsmRelocateApLoop):
+AsmRelocateApLoopStart:
+BITS 64
+ cmp qword [rsp + 56], 0 ; SevEsAPJumpTable
+ je NoSevEs
+
+ ;
+ ; Perform some SEV-ES related setup before leaving 64-bit mode
+ ;
+ push rcx
+ push rdx
+
+ ;
+ ; Get the RDX reset value using CPUID
+ ;
+ mov rax, 1
+ cpuid
+ mov rsi, rax ; Save off the reset value for RDX
+
+ ;
+ ; Prepare the GHCB for the AP_HLT_LOOP VMGEXIT call
+ ; - Must be done while in 64-bit long mode so that writes to
+ ; the GHCB memory will be unencrypted.
+ ; - No NAE events can be generated once this is set otherwise
+ ; the AP_RESET_HOLD SW_EXITCODE will be overwritten.
+ ;
+ mov rcx, 0xc0010130
+ rdmsr ; Retrieve current GHCB address
+ shl rdx, 32
+ or rdx, rax
+
+ mov rdi, rdx
+ xor rax, rax
+ mov rcx, 0x800
+ shr rcx, 3
+ rep stosq ; Clear the GHCB
+
+ mov rax, 0x80000004 ; VMGEXIT AP_RESET_HOLD
+ mov [rdx + 0x390], rax
+ mov rax, 114 ; Set SwExitCode valid bit
+ bts [rdx + 0x3f0], rax
+ inc rax ; Set SwExitInfo1 valid bit
+ bts [rdx + 0x3f0], rax
+ inc rax ; Set SwExitInfo2 valid bit
+ bts [rdx + 0x3f0], rax
+
+ pop rdx
+ pop rcx
+
+NoSevEs:
+ cli ; Disable interrupt before switching to 32-bit mode
+ mov rax, [rsp + 40] ; CountTofinish
+ lock dec dword [rax] ; (*CountTofinish)--
+
+ mov r10, [rsp + 48] ; Pm16CodeSegment
+ mov rax, [rsp + 56] ; SevEsAPJumpTable
+ mov rbx, [rsp + 64] ; WakeupBuffer
+ mov rsp, r9 ; TopOfApStack
+
+ push rax ; Save SevEsAPJumpTable
+ push rbx ; Save WakeupBuffer
+ push r10 ; Save Pm16CodeSegment
+ push rcx ; Save MwaitSupport
+ push rdx ; Save ApTargetCState
+
+ lea rax, [PmEntry] ; rax <- The start address of transition code
+
+ push r8
+ push rax
+
+ ;
+ ; Clear R8 - R15, for reset, before going into 32-bit mode
+ ;
+ xor r8, r8
+ xor r9, r9
+ xor r10, r10
+ xor r11, r11
+ xor r12, r12
+ xor r13, r13
+ xor r14, r14
+ xor r15, r15
+
+ ;
+ ; Far return into 32-bit mode
+ ;
+o64 retf
+
+BITS 32
+PmEntry:
+ mov eax, cr0
+ btr eax, 31 ; Clear CR0.PG
+ mov cr0, eax ; Disable paging and caches
+
+ mov ecx, 0xc0000080
+ rdmsr
+ and ah, ~ 1 ; Clear LME
+ wrmsr
+ mov eax, cr4
+ and al, ~ (1 << 5) ; Clear PAE
+ mov cr4, eax
+
+ pop edx
+ add esp, 4
+ pop ecx,
+ add esp, 4
+
+MwaitCheck:
+ cmp cl, 1 ; Check mwait-monitor support
+ jnz HltLoop
+ mov ebx, edx ; Save C-State to ebx
+MwaitLoop:
+ cli
+ mov eax, esp ; Set Monitor Address
+ xor ecx, ecx ; ecx = 0
+ xor edx, edx ; edx = 0
+ monitor
+ mov eax, ebx ; Mwait Cx, Target C-State per eax[7:4]
+ shl eax, 4
+ mwait
+ jmp MwaitLoop
+
+HltLoop:
+ pop edx ; PM16CodeSegment
+ add esp, 4
+ pop ebx ; WakeupBuffer
+ add esp, 4
+ pop eax ; SevEsAPJumpTable
+ add esp, 4
+ cmp eax, 0 ; Check for SEV-ES
+ je DoHlt
+
+ cli
+ ;
+ ; SEV-ES is enabled, use VMGEXIT (GHCB information already
+ ; set by caller)
+ ;
+BITS 64
+ rep vmmcall
+BITS 32
+
+ ;
+ ; Back from VMGEXIT AP_HLT_LOOP
+ ; Push the FLAGS/CS/IP values to use
+ ;
+ push word 0x0002 ; EFLAGS
+ xor ecx, ecx
+ mov cx, [eax + 2] ; CS
+ push cx
+ mov cx, [eax] ; IP
+ push cx
+ push word 0x0000 ; For alignment, will be discarded
+
+ push edx
+ push ebx
+
+ mov edx, esi ; Restore RDX reset value
+
+ retf
+
+DoHlt:
+ cli
+ hlt
+ jmp DoHlt
+
+BITS 64
+AsmRelocateApLoopEnd:
+
+;-------------------------------------------------------------------------------------
+; AsmGetAddressMap (&AddressMap);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmGetAddressMap)
+ASM_PFX(AsmGetAddressMap):
+ lea rax, [ASM_PFX(RendezvousFunnelProc)]
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelAddress], rax
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeEntryOffset], LongModeStart - RendezvousFunnelProcStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RendezvousFunnelSize], RendezvousFunnelProcEnd - RendezvousFunnelProcStart
+ lea rax, [ASM_PFX(AsmRelocateApLoop)]
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncAddress], rax
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.RelocateApLoopFuncSize], AsmRelocateApLoopEnd - AsmRelocateApLoopStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.ModeTransitionOffset], Flat32Start - RendezvousFunnelProcStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealSize], SwitchToRealProcEnd - SwitchToRealProcStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealOffset], SwitchToRealProcStart - RendezvousFunnelProcStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealNoNxOffset], SwitchToRealProcStart - Flat32Start
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeOffset], PM16Mode - RendezvousFunnelProcStart
+ mov qword [rcx + MP_ASSEMBLY_ADDRESS_MAP.SwitchToRealPM16ModeSize], SwitchToRealProcEnd - PM16Mode
+ ret
+
+;-------------------------------------------------------------------------------------
+;AsmExchangeRole procedure follows. This procedure executed by current BSP, that is
+;about to become an AP. It switches its stack with the current AP.
+;AsmExchangeRole (IN CPU_EXCHANGE_INFO *MyInfo, IN CPU_EXCHANGE_INFO *OthersInfo);
+;-------------------------------------------------------------------------------------
+global ASM_PFX(AsmExchangeRole)
+ASM_PFX(AsmExchangeRole):
+ ; DO NOT call other functions in this function, since 2 CPU may use 1 stack
+ ; at the same time. If 1 CPU try to call a function, stack will be corrupted.
+
+ push rax
+ push rbx
+ push rcx
+ push rdx
+ push rsi
+ push rdi
+ push rbp
+ push r8
+ push r9
+ push r10
+ push r11
+ push r12
+ push r13
+ push r14
+ push r15
+
+ mov rax, cr0
+ push rax
+
+ mov rax, cr4
+ push rax
+
+ ; rsi contains MyInfo pointer
+ mov rsi, rcx
+
+ ; rdi contains OthersInfo pointer
+ mov rdi, rdx
+
+ ;Store EFLAGS, GDTR and IDTR regiter to stack
+ pushfq
+ sgdt [rsi + CPU_EXCHANGE_ROLE_INFO.Gdtr]
+ sidt [rsi + CPU_EXCHANGE_ROLE_INFO.Idtr]
+
+ ; Store the its StackPointer
+ mov [rsi + CPU_EXCHANGE_ROLE_INFO.StackPointer], rsp
+
+ ; update its switch state to STORED
+ mov byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
+
+WaitForOtherStored:
+ ; wait until the other CPU finish storing its state
+ cmp byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_STORED
+ jz OtherStored
+ pause
+ jmp WaitForOtherStored
+
+OtherStored:
+ ; Since another CPU already stored its state, load them
+ ; load GDTR value
+ lgdt [rdi + CPU_EXCHANGE_ROLE_INFO.Gdtr]
+
+ ; load IDTR value
+ lidt [rdi + CPU_EXCHANGE_ROLE_INFO.Idtr]
+
+ ; load its future StackPointer
+ mov rsp, [rdi + CPU_EXCHANGE_ROLE_INFO.StackPointer]
+
+ ; update the other CPU's switch state to LOADED
+ mov byte [rdi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
+
+WaitForOtherLoaded:
+ ; wait until the other CPU finish loading new state,
+ ; otherwise the data in stack may corrupt
+ cmp byte [rsi + CPU_EXCHANGE_ROLE_INFO.State], CPU_SWITCH_STATE_LOADED
+ jz OtherLoaded
+ pause
+ jmp WaitForOtherLoaded
+
+OtherLoaded:
+ ; since the other CPU already get the data it want, leave this procedure
+ popfq
+
+ pop rax
+ mov cr4, rax
+
+ pop rax
+ mov cr0, rax
+
+ pop r15
+ pop r14
+ pop r13
+ pop r12
+ pop r11
+ pop r10
+ pop r9
+ pop r8
+ pop rbp
+ pop rdi
+ pop rsi
+ pop rdx
+ pop rcx
+ pop rbx
+ pop rax
+
+ ret
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.c
new file mode 100644
index 00000000..df1e2ce5
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.c
@@ -0,0 +1,442 @@
+/** @file
+ Multiple-Processor initialization Library for uniprocessor platforms.
+
+ Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+#include <Ppi/SecPlatformInformation.h>
+#include <Protocol/MpService.h>
+#include <Library/DebugLib.h>
+#include <Library/LocalApicLib.h>
+#include <Library/HobLib.h>
+
+/**
+ MP Initialize Library initialization.
+
+ This service will allocate AP reset vector and wakeup all APs to do APs
+ initialization.
+
+ This service must be invoked before all other MP Initialize Library
+ service are invoked.
+
+ @retval EFI_SUCCESS MP initialization succeeds.
+ @retval Others MP initialization fails.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibInitialize (
+ VOID
+ )
+{
+ //
+ // Enable the local APIC for Virtual Wire Mode.
+ //
+ ProgramVirtualWireMode ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ 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[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 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 and NumberOfEnabledProcessors
+ is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetNumberOfProcessors (
+ OUT UINTN *NumberOfProcessors, OPTIONAL
+ OUT UINTN *NumberOfEnabledProcessors OPTIONAL
+ )
+{
+ *NumberOfProcessors = 1;
+ *NumberOfEnabledProcessors = 1;
+ 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] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+ @param[out] HealthData Return processor health data.
+
+ @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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibGetProcessorInfo (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer,
+ OUT EFI_HEALTH_FLAGS *HealthData OPTIONAL
+ )
+{
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_SEC_PLATFORM_INFORMATION_RECORD *SecPlatformInformation;
+
+ if (ProcessorInfoBuffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (ProcessorNumber != 0) {
+ return EFI_NOT_FOUND;
+ }
+ ProcessorInfoBuffer->ProcessorId = 0;
+ ProcessorInfoBuffer->StatusFlag = PROCESSOR_AS_BSP_BIT |
+ PROCESSOR_ENABLED_BIT |
+ PROCESSOR_HEALTH_STATUS_BIT;
+ ProcessorInfoBuffer->Location.Package = 0;
+ ProcessorInfoBuffer->Location.Core = 0;
+ ProcessorInfoBuffer->Location.Thread = 0;
+ if (HealthData != NULL) {
+ GuidHob = GetFirstGuidHob (&gEfiSecPlatformInformationPpiGuid);
+ if (GuidHob != NULL) {
+ SecPlatformInformation = GET_GUID_HOB_DATA (GuidHob);
+ HealthData->Uint32 = SecPlatformInformation->IA32HealthFlags.Uint32;
+ } else {
+ DEBUG ((DEBUG_INFO, "Does not find any HOB stored CPU BIST information!\n"));
+ HealthData->Uint32 = 0;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This service executes a caller provided function on all enabled APs.
+
+ @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 MpInitLibStartupAllAPs() or
+ MPInitLibStartupThisAP().
+ 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 Initialization
+ library, 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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_NOT_READY MP Initialize Library is not initialized.
+ @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_AP_PROCEDURE Procedure,
+ IN BOOLEAN SingleThread,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT UINTN **FailedCpuList OPTIONAL
+ )
+{
+ return EFI_NOT_STARTED;
+}
+
+/**
+ This service lets the caller get one enabled AP to execute a caller-provided
+ function.
+
+ @param[in] Procedure A pointer to the function to be run on the
+ designated AP 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
+ MpInitLibGetNumberOfProcessors().
+ @param[in] WaitEvent The event created by the caller with CreateEvent()
+ service. If it is NULL, then execute in
+ blocking mode. BSP waits until this AP 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 this AP,
+ and go on executing immediately. If this AP
+ 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
+ this AP to finish this Procedure, either for
+ blocking or non-blocking mode. Zero means
+ infinity. If the timeout expires before
+ this AP returns from Procedure, then Procedure
+ on the AP is terminated. The
+ AP is available for next function assigned
+ by MpInitLibStartupAllAPs() or
+ MpInitLibStartupThisAP().
+ 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 on the
+ specified AP.
+ @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_UNSUPPORTED WaitEvent is not NULL if non-blocking mode is not
+ supported.
+ @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_READY MP Initialize Library is not initialized.
+ @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_AP_PROCEDURE Procedure,
+ IN UINTN ProcessorNumber,
+ IN EFI_EVENT WaitEvent OPTIONAL,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL,
+ OUT BOOLEAN *Finished OPTIONAL
+ )
+{
+ return EFI_INVALID_PARAMETER;
+}
+
+/**
+ 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] 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
+ MpInitLibGetNumberOfProcessors().
+ @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_DEVICE_ERROR 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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibSwitchBSP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableOldBSP
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ 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] ProcessorNumber The handle number of 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
+ MpInitLibGetNumberOfProcessors().
+ @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.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibEnableDisableAP (
+ IN UINTN ProcessorNumber,
+ IN BOOLEAN EnableAP,
+ IN UINT32 *HealthFlag OPTIONAL
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This return the handle number for the calling processor. This service may be
+ called from the BSP and APs.
+
+ @param[out] ProcessorNumber Pointer to the handle number of 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
+ MpInitLibGetNumberOfProcessors().
+
+ @retval EFI_SUCCESS The current processor handle number was returned
+ in ProcessorNumber.
+ @retval EFI_INVALID_PARAMETER ProcessorNumber is NULL.
+ @retval EFI_NOT_READY MP Initialize Library is not initialized.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibWhoAmI (
+ OUT UINTN *ProcessorNumber
+ )
+{
+ if (ProcessorNumber == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *ProcessorNumber = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ This service executes a caller provided function on all enabled CPUs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system. See type
+ EFI_AP_PROCEDURE.
+ @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. TimeoutInMicroseconds is ignored
+ for BSP.
+ @param[in] ProcedureArgument The parameter passed into Procedure for
+ all APs.
+
+ @retval EFI_SUCCESS CPU have finished the procedure.
+ @retval EFI_INVALID_PARAMETER Procedure is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+MpInitLibStartupAllCPUs (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN UINTN TimeoutInMicroseconds,
+ IN VOID *ProcedureArgument OPTIONAL
+ )
+{
+ if (Procedure == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Procedure (ProcedureArgument);
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf
new file mode 100644
index 00000000..7f2d68e6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.inf
@@ -0,0 +1,37 @@
+## @file
+# MP Initialize Library instance for uniprocessor platforms.
+#
+# Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MpInitLibUp
+ MODULE_UNI_FILE = MpInitLibUp.uni
+ FILE_GUID = 70E9818C-A4F0-4061-9FA2-2DFFC7016D6E
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.1
+ LIBRARY_CLASS = MpInitLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MpInitLibUp.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ DebugLib
+ LocalApicLib
+ HobLib
+
+[Ppis]
+ gEfiSecPlatformInformationPpiGuid ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.uni
new file mode 100644
index 00000000..ca1ab943
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MpInitLibUp/MpInitLibUp.uni
@@ -0,0 +1,14 @@
+// /** @file
+// MP Initialize Library instance for uniprocessor platforms.
+//
+// MP Initialize Library instance for uniprocessor platforms.
+//
+// Copyright (c) 2019, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "MP Initialize Library instance for uniprocessor platforms."
+
+#string STR_MODULE_DESCRIPTION #language en-US "MP Initialize Library instance for uniprocessor platforms."
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
new file mode 100644
index 00000000..85ae1700
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.c
@@ -0,0 +1,2815 @@
+/** @file
+ MTRR setting library
+
+ @par Note:
+ Most of services in this library instance are suggested to be invoked by BSP only,
+ except for MtrrSetAllMtrrs() which is used to sync BSP's MTRR setting to APs.
+
+ Copyright (c) 2008 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Uefi.h>
+#include <Register/Intel/Cpuid.h>
+#include <Register/Intel/Msr.h>
+
+#include <Library/MtrrLib.h>
+#include <Library/BaseLib.h>
+#include <Library/CpuLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+
+#define OR_SEED 0x0101010101010101ull
+#define CLEAR_SEED 0xFFFFFFFFFFFFFFFFull
+#define MAX_WEIGHT MAX_UINT8
+#define SCRATCH_BUFFER_SIZE (4 * SIZE_4KB)
+#define MTRR_LIB_ASSERT_ALIGNED(B, L) ASSERT ((B & ~(L - 1)) == B);
+
+#define M(x,y) ((x) * VertexCount + (y))
+#define O(x,y) ((y) * VertexCount + (x))
+
+//
+// Context to save and restore when MTRRs are programmed
+//
+typedef struct {
+ UINTN Cr4;
+ BOOLEAN InterruptState;
+} MTRR_CONTEXT;
+
+typedef struct {
+ UINT64 Address;
+ UINT64 Alignment;
+ UINT64 Length;
+ MTRR_MEMORY_CACHE_TYPE Type : 7;
+
+ //
+ // Temprary use for calculating the best MTRR settings.
+ //
+ BOOLEAN Visited : 1;
+ UINT8 Weight;
+ UINT16 Previous;
+} MTRR_LIB_ADDRESS;
+
+//
+// This table defines the offset, base and length of the fixed MTRRs
+//
+CONST FIXED_MTRR mMtrrLibFixedMtrrTable[] = {
+ {
+ MSR_IA32_MTRR_FIX64K_00000,
+ 0,
+ SIZE_64KB
+ },
+ {
+ MSR_IA32_MTRR_FIX16K_80000,
+ 0x80000,
+ SIZE_16KB
+ },
+ {
+ MSR_IA32_MTRR_FIX16K_A0000,
+ 0xA0000,
+ SIZE_16KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_C0000,
+ 0xC0000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_C8000,
+ 0xC8000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_D0000,
+ 0xD0000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_D8000,
+ 0xD8000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_E0000,
+ 0xE0000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_E8000,
+ 0xE8000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_F0000,
+ 0xF0000,
+ SIZE_4KB
+ },
+ {
+ MSR_IA32_MTRR_FIX4K_F8000,
+ 0xF8000,
+ SIZE_4KB
+ }
+};
+
+//
+// Lookup table used to print MTRRs
+//
+GLOBAL_REMOVE_IF_UNREFERENCED CONST CHAR8 *mMtrrMemoryCacheTypeShortName[] = {
+ "UC", // CacheUncacheable
+ "WC", // CacheWriteCombining
+ "R*", // Invalid
+ "R*", // Invalid
+ "WT", // CacheWriteThrough
+ "WP", // CacheWriteProtected
+ "WB", // CacheWriteBack
+ "R*" // Invalid
+};
+
+
+/**
+ Worker function prints all MTRRs for debugging.
+
+ If MtrrSetting is not NULL, print MTRR settings from input MTRR
+ settings buffer.
+ If MtrrSetting is NULL, print MTRR settings from MTRRs.
+
+ @param MtrrSetting A buffer holding all MTRRs content.
+**/
+VOID
+MtrrDebugPrintAllMtrrsWorker (
+ IN MTRR_SETTINGS *MtrrSetting
+ );
+
+/**
+ Worker function returns the variable MTRR count for the CPU.
+
+ @return Variable MTRR count
+
+**/
+UINT32
+GetVariableMtrrCountWorker (
+ VOID
+ )
+{
+ MSR_IA32_MTRRCAP_REGISTER MtrrCap;
+
+ MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
+ ASSERT (MtrrCap.Bits.VCNT <= ARRAY_SIZE (((MTRR_VARIABLE_SETTINGS *) 0)->Mtrr));
+ return MtrrCap.Bits.VCNT;
+}
+
+/**
+ Returns the variable MTRR count for the CPU.
+
+ @return Variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetVariableMtrrCount (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+ return GetVariableMtrrCountWorker ();
+}
+
+/**
+ Worker function returns the firmware usable variable MTRR count for the CPU.
+
+ @return Firmware usable variable MTRR count
+
+**/
+UINT32
+GetFirmwareVariableMtrrCountWorker (
+ VOID
+ )
+{
+ UINT32 VariableMtrrCount;
+ UINT32 ReservedMtrrNumber;
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ReservedMtrrNumber = PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
+ if (VariableMtrrCount < ReservedMtrrNumber) {
+ return 0;
+ }
+
+ return VariableMtrrCount - ReservedMtrrNumber;
+}
+
+/**
+ Returns the firmware usable variable MTRR count for the CPU.
+
+ @return Firmware usable variable MTRR count
+
+**/
+UINT32
+EFIAPI
+GetFirmwareVariableMtrrCount (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+ return GetFirmwareVariableMtrrCountWorker ();
+}
+
+/**
+ Worker function returns the default MTRR cache type for the system.
+
+ If MtrrSetting is not NULL, returns the default MTRR cache type from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, returns the default MTRR cache type from MSR.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+
+ @return The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetDefaultMemoryTypeWorker (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
+
+ if (MtrrSetting == NULL) {
+ DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
+ } else {
+ DefType.Uint64 = MtrrSetting->MtrrDefType;
+ }
+
+ return (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;
+}
+
+
+/**
+ Returns the default MTRR cache type for the system.
+
+ @return The default MTRR cache type.
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetDefaultMemoryType (
+ VOID
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return CacheUncacheable;
+ }
+ return MtrrGetDefaultMemoryTypeWorker (NULL);
+}
+
+/**
+ Preparation before programming MTRR.
+
+ This function will do some preparation for programming MTRRs:
+ disable cache, invalid cache and disable MTRR caching functionality
+
+ @param[out] MtrrContext Pointer to context to save
+
+**/
+VOID
+MtrrLibPreMtrrChange (
+ OUT MTRR_CONTEXT *MtrrContext
+ )
+{
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
+ //
+ // Disable interrupts and save current interrupt state
+ //
+ MtrrContext->InterruptState = SaveAndDisableInterrupts();
+
+ //
+ // Enter no fill cache mode, CD=1(Bit30), NW=0 (Bit29)
+ //
+ AsmDisableCache ();
+
+ //
+ // Save original CR4 value and clear PGE flag (Bit 7)
+ //
+ MtrrContext->Cr4 = AsmReadCr4 ();
+ AsmWriteCr4 (MtrrContext->Cr4 & (~BIT7));
+
+ //
+ // Flush all TLBs
+ //
+ CpuFlushTlb ();
+
+ //
+ // Disable MTRRs
+ //
+ DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
+ DefType.Bits.E = 0;
+ AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);
+}
+
+/**
+ Cleaning up after programming MTRRs.
+
+ This function will do some clean up after programming MTRRs:
+ Flush all TLBs, re-enable caching, restore CR4.
+
+ @param[in] MtrrContext Pointer to context to restore
+
+**/
+VOID
+MtrrLibPostMtrrChangeEnableCache (
+ IN MTRR_CONTEXT *MtrrContext
+ )
+{
+ //
+ // Flush all TLBs
+ //
+ CpuFlushTlb ();
+
+ //
+ // Enable Normal Mode caching CD=NW=0, CD(Bit30), NW(Bit29)
+ //
+ AsmEnableCache ();
+
+ //
+ // Restore original CR4 value
+ //
+ AsmWriteCr4 (MtrrContext->Cr4);
+
+ //
+ // Restore original interrupt state
+ //
+ SetInterruptState (MtrrContext->InterruptState);
+}
+
+/**
+ Cleaning up after programming MTRRs.
+
+ This function will do some clean up after programming MTRRs:
+ enable MTRR caching functionality, and enable cache
+
+ @param[in] MtrrContext Pointer to context to restore
+
+**/
+VOID
+MtrrLibPostMtrrChange (
+ IN MTRR_CONTEXT *MtrrContext
+ )
+{
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
+ //
+ // Enable Cache MTRR
+ //
+ DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
+ DefType.Bits.E = 1;
+ DefType.Bits.FE = 1;
+ AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, DefType.Uint64);
+
+ MtrrLibPostMtrrChangeEnableCache (MtrrContext);
+}
+
+/**
+ Worker function gets the content in fixed MTRRs
+
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.
+
+ @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+MtrrGetFixedMtrrWorker (
+ OUT MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ FixedSettings->Mtrr[Index] =
+ AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
+ }
+
+ return FixedSettings;
+}
+
+
+/**
+ This function gets the content in fixed MTRRs
+
+ @param[out] FixedSettings A buffer to hold fixed MTRRs content.
+
+ @retval The pointer of FixedSettings
+
+**/
+MTRR_FIXED_SETTINGS*
+EFIAPI
+MtrrGetFixedMtrr (
+ OUT MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return FixedSettings;
+ }
+
+ return MtrrGetFixedMtrrWorker (FixedSettings);
+}
+
+
+/**
+ Worker function will get the raw value in variable MTRRs
+
+ If MtrrSetting is not NULL, gets the variable MTRRs raw value from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, gets the variable MTRRs raw value from MTRRs.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] VariableMtrrCount Number of variable MTRRs.
+ @param[out] VariableSettings A buffer to hold variable MTRRs content.
+
+ @return The VariableSettings input pointer
+
+**/
+MTRR_VARIABLE_SETTINGS*
+MtrrGetVariableMtrrWorker (
+ IN MTRR_SETTINGS *MtrrSetting,
+ IN UINT32 VariableMtrrCount,
+ OUT MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ UINT32 Index;
+
+ ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (MtrrSetting == NULL) {
+ VariableSettings->Mtrr[Index].Base =
+ AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1));
+ VariableSettings->Mtrr[Index].Mask =
+ AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1));
+ } else {
+ VariableSettings->Mtrr[Index].Base = MtrrSetting->Variables.Mtrr[Index].Base;
+ VariableSettings->Mtrr[Index].Mask = MtrrSetting->Variables.Mtrr[Index].Mask;
+ }
+ }
+
+ return VariableSettings;
+}
+
+/**
+ Programs fixed MTRRs registers.
+
+ @param[in] Type The memory type to set.
+ @param[in, out] Base The base address of memory range.
+ @param[in, out] Length The length of memory range.
+ @param[in, out] LastMsrIndex On input, the last index of the fixed MTRR MSR to program.
+ On return, the current index of the fixed MTRR MSR to program.
+ @param[out] ClearMask The bits to clear in the fixed MTRR MSR.
+ @param[out] OrMask The bits to set in the fixed MTRR MSR.
+
+ @retval RETURN_SUCCESS The cache type was updated successfully
+ @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
+ for the fixed MTRRs.
+
+**/
+RETURN_STATUS
+MtrrLibProgramFixedMtrr (
+ IN MTRR_MEMORY_CACHE_TYPE Type,
+ IN OUT UINT64 *Base,
+ IN OUT UINT64 *Length,
+ IN OUT UINT32 *LastMsrIndex,
+ OUT UINT64 *ClearMask,
+ OUT UINT64 *OrMask
+ )
+{
+ UINT32 MsrIndex;
+ UINT32 LeftByteShift;
+ UINT32 RightByteShift;
+ UINT64 SubLength;
+
+ //
+ // Find the fixed MTRR index to be programmed
+ //
+ for (MsrIndex = *LastMsrIndex + 1; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
+ if ((*Base >= mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) &&
+ (*Base <
+ (
+ mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress +
+ (8 * mMtrrLibFixedMtrrTable[MsrIndex].Length)
+ )
+ )
+ ) {
+ break;
+ }
+ }
+
+ ASSERT (MsrIndex != ARRAY_SIZE (mMtrrLibFixedMtrrTable));
+
+ //
+ // Find the begin offset in fixed MTRR and calculate byte offset of left shift
+ //
+ if ((((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
+ //
+ // Base address should be aligned to the begin of a certain Fixed MTRR range.
+ //
+ return RETURN_UNSUPPORTED;
+ }
+ LeftByteShift = ((UINT32)*Base - mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
+ ASSERT (LeftByteShift < 8);
+
+ //
+ // Find the end offset in fixed MTRR and calculate byte offset of right shift
+ //
+ SubLength = mMtrrLibFixedMtrrTable[MsrIndex].Length * (8 - LeftByteShift);
+ if (*Length >= SubLength) {
+ RightByteShift = 0;
+ } else {
+ if (((UINT32)(*Length) % mMtrrLibFixedMtrrTable[MsrIndex].Length) != 0) {
+ //
+ // Length should be aligned to the end of a certain Fixed MTRR range.
+ //
+ return RETURN_UNSUPPORTED;
+ }
+ RightByteShift = 8 - LeftByteShift - (UINT32)(*Length) / mMtrrLibFixedMtrrTable[MsrIndex].Length;
+ //
+ // Update SubLength by actual length
+ //
+ SubLength = *Length;
+ }
+
+ *ClearMask = CLEAR_SEED;
+ *OrMask = MultU64x32 (OR_SEED, (UINT32) Type);
+
+ if (LeftByteShift != 0) {
+ //
+ // Clear the low bits by LeftByteShift
+ //
+ *ClearMask &= LShiftU64 (*ClearMask, LeftByteShift * 8);
+ *OrMask &= LShiftU64 (*OrMask, LeftByteShift * 8);
+ }
+
+ if (RightByteShift != 0) {
+ //
+ // Clear the high bits by RightByteShift
+ //
+ *ClearMask &= RShiftU64 (*ClearMask, RightByteShift * 8);
+ *OrMask &= RShiftU64 (*OrMask, RightByteShift * 8);
+ }
+
+ *Length -= SubLength;
+ *Base += SubLength;
+
+ *LastMsrIndex = MsrIndex;
+
+ return RETURN_SUCCESS;
+}
+
+
+/**
+ Worker function gets the attribute of variable MTRRs.
+
+ This function shadows the content of variable MTRRs into an
+ internal array: VariableMtrr.
+
+ @param[in] VariableSettings The variable MTRR values to shadow
+ @param[in] VariableMtrrCount The number of variable MTRRs
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+ @param[out] VariableMtrr The array to shadow variable MTRRs content
+
+ @return Number of MTRRs which has been used.
+
+**/
+UINT32
+MtrrGetMemoryAttributeInVariableMtrrWorker (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings,
+ IN UINTN VariableMtrrCount,
+ IN UINT64 MtrrValidBitsMask,
+ IN UINT64 MtrrValidAddressMask,
+ OUT VARIABLE_MTRR *VariableMtrr
+ )
+{
+ UINTN Index;
+ UINT32 UsedMtrr;
+
+ ZeroMem (VariableMtrr, sizeof (VARIABLE_MTRR) * ARRAY_SIZE (VariableSettings->Mtrr));
+ for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
+ if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
+ VariableMtrr[Index].Msr = (UINT32)Index;
+ VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
+ VariableMtrr[Index].Length =
+ ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
+ VariableMtrr[Index].Type = (VariableSettings->Mtrr[Index].Base & 0x0ff);
+ VariableMtrr[Index].Valid = TRUE;
+ VariableMtrr[Index].Used = TRUE;
+ UsedMtrr++;
+ }
+ }
+ return UsedMtrr;
+}
+
+/**
+ Convert variable MTRRs to a RAW MTRR_MEMORY_RANGE array.
+ One MTRR_MEMORY_RANGE element is created for each MTRR setting.
+ The routine doesn't remove the overlap or combine the near-by region.
+
+ @param[in] VariableSettings The variable MTRR values to shadow
+ @param[in] VariableMtrrCount The number of variable MTRRs
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+ @param[out] VariableMtrr The array to shadow variable MTRRs content
+
+ @return Number of MTRRs which has been used.
+
+**/
+UINT32
+MtrrLibGetRawVariableRanges (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings,
+ IN UINTN VariableMtrrCount,
+ IN UINT64 MtrrValidBitsMask,
+ IN UINT64 MtrrValidAddressMask,
+ OUT MTRR_MEMORY_RANGE *VariableMtrr
+ )
+{
+ UINTN Index;
+ UINT32 UsedMtrr;
+
+ ZeroMem (VariableMtrr, sizeof (MTRR_MEMORY_RANGE) * ARRAY_SIZE (VariableSettings->Mtrr));
+ for (Index = 0, UsedMtrr = 0; Index < VariableMtrrCount; Index++) {
+ if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &VariableSettings->Mtrr[Index].Mask)->Bits.V != 0) {
+ VariableMtrr[Index].BaseAddress = (VariableSettings->Mtrr[Index].Base & MtrrValidAddressMask);
+ VariableMtrr[Index].Length =
+ ((~(VariableSettings->Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
+ VariableMtrr[Index].Type = (MTRR_MEMORY_CACHE_TYPE)(VariableSettings->Mtrr[Index].Base & 0x0ff);
+ UsedMtrr++;
+ }
+ }
+ return UsedMtrr;
+}
+
+/**
+ Gets the attribute of variable MTRRs.
+
+ This function shadows the content of variable MTRRs into an
+ internal array: VariableMtrr.
+
+ @param[in] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[in] MtrrValidAddressMask The valid address mask for MTRR
+ @param[out] VariableMtrr The array to shadow variable MTRRs content
+
+ @return The return value of this parameter indicates the
+ number of MTRRs which has been used.
+
+**/
+UINT32
+EFIAPI
+MtrrGetMemoryAttributeInVariableMtrr (
+ IN UINT64 MtrrValidBitsMask,
+ IN UINT64 MtrrValidAddressMask,
+ OUT VARIABLE_MTRR *VariableMtrr
+ )
+{
+ MTRR_VARIABLE_SETTINGS VariableSettings;
+
+ if (!IsMtrrSupported ()) {
+ return 0;
+ }
+
+ MtrrGetVariableMtrrWorker (
+ NULL,
+ GetVariableMtrrCountWorker (),
+ &VariableSettings
+ );
+
+ return MtrrGetMemoryAttributeInVariableMtrrWorker (
+ &VariableSettings,
+ GetFirmwareVariableMtrrCountWorker (),
+ MtrrValidBitsMask,
+ MtrrValidAddressMask,
+ VariableMtrr
+ );
+}
+
+/**
+ Return the biggest alignment (lowest set bit) of address.
+ The function is equivalent to: 1 << LowBitSet64 (Address).
+
+ @param Address The address to return the alignment.
+ @param Alignment0 The alignment to return when Address is 0.
+
+ @return The least alignment of the Address.
+**/
+UINT64
+MtrrLibBiggestAlignment (
+ UINT64 Address,
+ UINT64 Alignment0
+)
+{
+ if (Address == 0) {
+ return Alignment0;
+ }
+
+ return Address & ((~Address) + 1);
+}
+
+/**
+ Return whether the left MTRR type precedes the right MTRR type.
+
+ The MTRR type precedence rules are:
+ 1. UC precedes any other type
+ 2. WT precedes WB
+ For further details, please refer the IA32 Software Developer's Manual,
+ Volume 3, Section "MTRR Precedences".
+
+ @param Left The left MTRR type.
+ @param Right The right MTRR type.
+
+ @retval TRUE Left precedes Right.
+ @retval FALSE Left doesn't precede Right.
+**/
+BOOLEAN
+MtrrLibTypeLeftPrecedeRight (
+ IN MTRR_MEMORY_CACHE_TYPE Left,
+ IN MTRR_MEMORY_CACHE_TYPE Right
+)
+{
+ return (BOOLEAN) (Left == CacheUncacheable || (Left == CacheWriteThrough && Right == CacheWriteBack));
+}
+
+/**
+ Initializes the valid bits mask and valid address mask for MTRRs.
+
+ This function initializes the valid bits mask and valid address mask for MTRRs.
+
+ @param[out] MtrrValidBitsMask The mask for the valid bit of the MTRR
+ @param[out] MtrrValidAddressMask The valid address mask for the MTRR
+
+**/
+VOID
+MtrrLibInitializeMtrrMask (
+ OUT UINT64 *MtrrValidBitsMask,
+ OUT UINT64 *MtrrValidAddressMask
+ )
+{
+ UINT32 MaxExtendedFunction;
+ CPUID_VIR_PHY_ADDRESS_SIZE_EAX VirPhyAddressSize;
+
+
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &MaxExtendedFunction, NULL, NULL, NULL);
+
+ if (MaxExtendedFunction >= CPUID_VIR_PHY_ADDRESS_SIZE) {
+ AsmCpuid (CPUID_VIR_PHY_ADDRESS_SIZE, &VirPhyAddressSize.Uint32, NULL, NULL, NULL);
+ } else {
+ VirPhyAddressSize.Bits.PhysicalAddressBits = 36;
+ }
+
+ *MtrrValidBitsMask = LShiftU64 (1, VirPhyAddressSize.Bits.PhysicalAddressBits) - 1;
+ *MtrrValidAddressMask = *MtrrValidBitsMask & 0xfffffffffffff000ULL;
+}
+
+
+/**
+ Determines the real attribute of a memory range.
+
+ This function is to arbitrate the real attribute of the memory when
+ there are 2 MTRRs covers the same memory range. For further details,
+ please refer the IA32 Software Developer's Manual, Volume 3,
+ Section "MTRR Precedences".
+
+ @param[in] MtrrType1 The first kind of Memory type
+ @param[in] MtrrType2 The second kind of memory type
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrLibPrecedence (
+ IN MTRR_MEMORY_CACHE_TYPE MtrrType1,
+ IN MTRR_MEMORY_CACHE_TYPE MtrrType2
+ )
+{
+ if (MtrrType1 == MtrrType2) {
+ return MtrrType1;
+ }
+
+ ASSERT (
+ MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2) ||
+ MtrrLibTypeLeftPrecedeRight (MtrrType2, MtrrType1)
+ );
+
+ if (MtrrLibTypeLeftPrecedeRight (MtrrType1, MtrrType2)) {
+ return MtrrType1;
+ } else {
+ return MtrrType2;
+ }
+}
+
+/**
+ Worker function will get the memory cache type of the specific address.
+
+ If MtrrSetting is not NULL, gets the memory cache type from input
+ MTRR settings buffer.
+ If MtrrSetting is NULL, gets the memory cache type from MTRRs.
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+ @param[in] Address The specific address
+
+ @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrGetMemoryAttributeByAddressWorker (
+ IN MTRR_SETTINGS *MtrrSetting,
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER DefType;
+ UINT64 FixedMtrr;
+ UINTN Index;
+ UINTN SubIndex;
+ MTRR_MEMORY_CACHE_TYPE MtrrType;
+ MTRR_MEMORY_RANGE VariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ UINT32 VariableMtrrCount;
+ MTRR_VARIABLE_SETTINGS VariableSettings;
+
+ //
+ // Check if MTRR is enabled, if not, return UC as attribute
+ //
+ if (MtrrSetting == NULL) {
+ DefType.Uint64 = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
+ } else {
+ DefType.Uint64 = MtrrSetting->MtrrDefType;
+ }
+
+ if (DefType.Bits.E == 0) {
+ return CacheUncacheable;
+ }
+
+ //
+ // If address is less than 1M, then try to go through the fixed MTRR
+ //
+ if (Address < BASE_1MB) {
+ if (DefType.Bits.FE != 0) {
+ //
+ // Go through the fixed MTRR
+ //
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ if (Address >= mMtrrLibFixedMtrrTable[Index].BaseAddress &&
+ Address < mMtrrLibFixedMtrrTable[Index].BaseAddress +
+ (mMtrrLibFixedMtrrTable[Index].Length * 8)) {
+ SubIndex =
+ ((UINTN) Address - mMtrrLibFixedMtrrTable[Index].BaseAddress) /
+ mMtrrLibFixedMtrrTable[Index].Length;
+ if (MtrrSetting == NULL) {
+ FixedMtrr = AsmReadMsr64 (mMtrrLibFixedMtrrTable[Index].Msr);
+ } else {
+ FixedMtrr = MtrrSetting->Fixed.Mtrr[Index];
+ }
+ return (MTRR_MEMORY_CACHE_TYPE) (RShiftU64 (FixedMtrr, SubIndex * 8) & 0xFF);
+ }
+ }
+ }
+ }
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ASSERT (VariableMtrrCount <= ARRAY_SIZE (MtrrSetting->Variables.Mtrr));
+ MtrrGetVariableMtrrWorker (MtrrSetting, VariableMtrrCount, &VariableSettings);
+
+ MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
+ MtrrLibGetRawVariableRanges (
+ &VariableSettings,
+ VariableMtrrCount,
+ MtrrValidBitsMask,
+ MtrrValidAddressMask,
+ VariableMtrr
+ );
+
+ //
+ // Go through the variable MTRR
+ //
+ MtrrType = CacheInvalid;
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (VariableMtrr[Index].Length != 0) {
+ if (Address >= VariableMtrr[Index].BaseAddress &&
+ Address < VariableMtrr[Index].BaseAddress + VariableMtrr[Index].Length) {
+ if (MtrrType == CacheInvalid) {
+ MtrrType = (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type;
+ } else {
+ MtrrType = MtrrLibPrecedence (MtrrType, (MTRR_MEMORY_CACHE_TYPE) VariableMtrr[Index].Type);
+ }
+ }
+ }
+ }
+
+ //
+ // If there is no MTRR which covers the Address, use the default MTRR type.
+ //
+ if (MtrrType == CacheInvalid) {
+ MtrrType = (MTRR_MEMORY_CACHE_TYPE) DefType.Bits.Type;
+ }
+
+ return MtrrType;
+}
+
+
+/**
+ This function will get the memory cache type of the specific address.
+
+ This function is mainly for debug purpose.
+
+ @param[in] Address The specific address
+
+ @return Memory cache type of the specific address
+
+**/
+MTRR_MEMORY_CACHE_TYPE
+EFIAPI
+MtrrGetMemoryAttribute (
+ IN PHYSICAL_ADDRESS Address
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return CacheUncacheable;
+ }
+
+ return MtrrGetMemoryAttributeByAddressWorker (NULL, Address);
+}
+
+/**
+ Update the Ranges array to change the specified range identified by
+ BaseAddress and Length to Type.
+
+ @param Ranges Array holding memory type settings for all memory regions.
+ @param Capacity The maximum count of memory ranges the array can hold.
+ @param Count Return the new memory range count in the array.
+ @param BaseAddress The base address of the memory range to change type.
+ @param Length The length of the memory range to change type.
+ @param Type The new type of the specified memory range.
+
+ @retval RETURN_SUCCESS The type of the specified memory range is
+ changed successfully.
+ @retval RETURN_ALREADY_STARTED The type of the specified memory range equals
+ to the desired type.
+ @retval RETURN_OUT_OF_RESOURCES The new type set causes the count of memory
+ range exceeds capacity.
+**/
+RETURN_STATUS
+MtrrLibSetMemoryType (
+ IN MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN Capacity,
+ IN OUT UINTN *Count,
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Type
+ )
+{
+ UINTN Index;
+ UINT64 Limit;
+ UINT64 LengthLeft;
+ UINT64 LengthRight;
+ UINTN StartIndex;
+ UINTN EndIndex;
+ UINTN DeltaCount;
+
+ LengthRight = 0;
+ LengthLeft = 0;
+ Limit = BaseAddress + Length;
+ StartIndex = *Count;
+ EndIndex = *Count;
+ for (Index = 0; Index < *Count; Index++) {
+ if ((StartIndex == *Count) &&
+ (Ranges[Index].BaseAddress <= BaseAddress) &&
+ (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)) {
+ StartIndex = Index;
+ LengthLeft = BaseAddress - Ranges[Index].BaseAddress;
+ }
+
+ if ((EndIndex == *Count) &&
+ (Ranges[Index].BaseAddress < Limit) &&
+ (Limit <= Ranges[Index].BaseAddress + Ranges[Index].Length)) {
+ EndIndex = Index;
+ LengthRight = Ranges[Index].BaseAddress + Ranges[Index].Length - Limit;
+ break;
+ }
+ }
+
+ ASSERT (StartIndex != *Count && EndIndex != *Count);
+ if (StartIndex == EndIndex && Ranges[StartIndex].Type == Type) {
+ return RETURN_ALREADY_STARTED;
+ }
+
+ //
+ // The type change may cause merging with previous range or next range.
+ // Update the StartIndex, EndIndex, BaseAddress, Length so that following
+ // logic doesn't need to consider merging.
+ //
+ if (StartIndex != 0) {
+ if (LengthLeft == 0 && Ranges[StartIndex - 1].Type == Type) {
+ StartIndex--;
+ Length += Ranges[StartIndex].Length;
+ BaseAddress -= Ranges[StartIndex].Length;
+ }
+ }
+ if (EndIndex != (*Count) - 1) {
+ if (LengthRight == 0 && Ranges[EndIndex + 1].Type == Type) {
+ EndIndex++;
+ Length += Ranges[EndIndex].Length;
+ }
+ }
+
+ //
+ // |- 0 -|- 1 -|- 2 -|- 3 -| StartIndex EndIndex DeltaCount Count (Count = 4)
+ // |++++++++++++++++++| 0 3 1=3-0-2 3
+ // |+++++++| 0 1 -1=1-0-2 5
+ // |+| 0 0 -2=0-0-2 6
+ // |+++| 0 0 -1=0-0-2+1 5
+ //
+ //
+ DeltaCount = EndIndex - StartIndex - 2;
+ if (LengthLeft == 0) {
+ DeltaCount++;
+ }
+ if (LengthRight == 0) {
+ DeltaCount++;
+ }
+ if (*Count - DeltaCount > Capacity) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Reserve (-DeltaCount) space
+ //
+ CopyMem (&Ranges[EndIndex + 1 - DeltaCount], &Ranges[EndIndex + 1], (*Count - EndIndex - 1) * sizeof (Ranges[0]));
+ *Count -= DeltaCount;
+
+ if (LengthLeft != 0) {
+ Ranges[StartIndex].Length = LengthLeft;
+ StartIndex++;
+ }
+ if (LengthRight != 0) {
+ Ranges[EndIndex - DeltaCount].BaseAddress = BaseAddress + Length;
+ Ranges[EndIndex - DeltaCount].Length = LengthRight;
+ Ranges[EndIndex - DeltaCount].Type = Ranges[EndIndex].Type;
+ }
+ Ranges[StartIndex].BaseAddress = BaseAddress;
+ Ranges[StartIndex].Length = Length;
+ Ranges[StartIndex].Type = Type;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Return the number of memory types in range [BaseAddress, BaseAddress + Length).
+
+ @param Ranges Array holding memory type settings for all memory regions.
+ @param RangeCount The count of memory ranges the array holds.
+ @param BaseAddress Base address.
+ @param Length Length.
+ @param Types Return bit mask to indicate all memory types in the specified range.
+
+ @retval Number of memory types.
+**/
+UINT8
+MtrrLibGetNumberOfTypes (
+ IN CONST MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount,
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN OUT UINT8 *Types OPTIONAL
+ )
+{
+ UINTN Index;
+ UINT8 TypeCount;
+ UINT8 LocalTypes;
+
+ TypeCount = 0;
+ LocalTypes = 0;
+ for (Index = 0; Index < RangeCount; Index++) {
+ if ((Ranges[Index].BaseAddress <= BaseAddress) &&
+ (BaseAddress < Ranges[Index].BaseAddress + Ranges[Index].Length)
+ ) {
+ if ((LocalTypes & (1 << Ranges[Index].Type)) == 0) {
+ LocalTypes |= (UINT8)(1 << Ranges[Index].Type);
+ TypeCount++;
+ }
+
+ if (BaseAddress + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
+ Length -= Ranges[Index].BaseAddress + Ranges[Index].Length - BaseAddress;
+ BaseAddress = Ranges[Index].BaseAddress + Ranges[Index].Length;
+ } else {
+ break;
+ }
+ }
+ }
+
+ if (Types != NULL) {
+ *Types = LocalTypes;
+ }
+ return TypeCount;
+}
+
+/**
+ Calculate the least MTRR number from vertex Start to Stop and update
+ the Previous of all vertices from Start to Stop is updated to reflect
+ how the memory range is covered by MTRR.
+
+ @param VertexCount The count of vertices in the graph.
+ @param Vertices Array holding all vertices.
+ @param Weight 2-dimention array holding weights between vertices.
+ @param Start Start vertex.
+ @param Stop Stop vertex.
+ @param IncludeOptional TRUE to count the optional weight.
+**/
+VOID
+MtrrLibCalculateLeastMtrrs (
+ IN UINT16 VertexCount,
+ IN MTRR_LIB_ADDRESS *Vertices,
+ IN OUT CONST UINT8 *Weight,
+ IN UINT16 Start,
+ IN UINT16 Stop,
+ IN BOOLEAN IncludeOptional
+ )
+{
+ UINT16 Index;
+ UINT8 MinWeight;
+ UINT16 MinI;
+ UINT8 Mandatory;
+ UINT8 Optional;
+
+ for (Index = Start; Index <= Stop; Index++) {
+ Vertices[Index].Visited = FALSE;
+ Mandatory = Weight[M(Start,Index)];
+ Vertices[Index].Weight = Mandatory;
+ if (Mandatory != MAX_WEIGHT) {
+ Optional = IncludeOptional ? Weight[O(Start, Index)] : 0;
+ Vertices[Index].Weight += Optional;
+ ASSERT (Vertices[Index].Weight >= Optional);
+ }
+ }
+
+ MinI = Start;
+ MinWeight = 0;
+ while (!Vertices[Stop].Visited) {
+ //
+ // Update the weight from the shortest vertex to other unvisited vertices
+ //
+ for (Index = Start + 1; Index <= Stop; Index++) {
+ if (!Vertices[Index].Visited) {
+ Mandatory = Weight[M(MinI, Index)];
+ if (Mandatory != MAX_WEIGHT) {
+ Optional = IncludeOptional ? Weight[O(MinI, Index)] : 0;
+ if (MinWeight + Mandatory + Optional <= Vertices[Index].Weight) {
+ Vertices[Index].Weight = MinWeight + Mandatory + Optional;
+ Vertices[Index].Previous = MinI; // Previous is Start based.
+ }
+ }
+ }
+ }
+
+ //
+ // Find the shortest vertex from Start
+ //
+ MinI = VertexCount;
+ MinWeight = MAX_WEIGHT;
+ for (Index = Start + 1; Index <= Stop; Index++) {
+ if (!Vertices[Index].Visited && MinWeight > Vertices[Index].Weight) {
+ MinI = Index;
+ MinWeight = Vertices[Index].Weight;
+ }
+ }
+
+ //
+ // Mark the shortest vertex from Start as visited
+ //
+ Vertices[MinI].Visited = TRUE;
+ }
+}
+
+/**
+ Append the MTRR setting to MTRR setting array.
+
+ @param Mtrrs Array holding all MTRR settings.
+ @param MtrrCapacity Capacity of the MTRR array.
+ @param MtrrCount The count of MTRR settings in array.
+ @param BaseAddress Base address.
+ @param Length Length.
+ @param Type Memory type.
+
+ @retval RETURN_SUCCESS MTRR setting is appended to array.
+ @retval RETURN_OUT_OF_RESOURCES Array is full.
+**/
+RETURN_STATUS
+MtrrLibAppendVariableMtrr (
+ IN OUT MTRR_MEMORY_RANGE *Mtrrs,
+ IN UINT32 MtrrCapacity,
+ IN OUT UINT32 *MtrrCount,
+ IN UINT64 BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Type
+ )
+{
+ if (*MtrrCount == MtrrCapacity) {
+ return RETURN_OUT_OF_RESOURCES;
+ }
+
+ Mtrrs[*MtrrCount].BaseAddress = BaseAddress;
+ Mtrrs[*MtrrCount].Length = Length;
+ Mtrrs[*MtrrCount].Type = Type;
+ (*MtrrCount)++;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Return the memory type that has the least precedence.
+
+ @param TypeBits Bit mask of memory type.
+
+ @retval Memory type that has the least precedence.
+**/
+MTRR_MEMORY_CACHE_TYPE
+MtrrLibLowestType (
+ IN UINT8 TypeBits
+)
+{
+ INT8 Type;
+
+ ASSERT (TypeBits != 0);
+ for (Type = 7; (INT8)TypeBits > 0; Type--, TypeBits <<= 1);
+ return (MTRR_MEMORY_CACHE_TYPE)Type;
+}
+
+/**
+ Return TRUE when the Operand is exactly power of 2.
+
+ @retval TRUE Operand is exactly power of 2.
+ @retval FALSE Operand is not power of 2.
+**/
+BOOLEAN
+MtrrLibIsPowerOfTwo (
+ IN UINT64 Operand
+)
+{
+ ASSERT (Operand != 0);
+ return (BOOLEAN) ((Operand & (Operand - 1)) == 0);
+}
+
+/**
+ Calculate the subtractive path from vertex Start to Stop.
+
+ @param DefaultType Default memory type.
+ @param A0 Alignment to use when base address is 0.
+ @param Ranges Array holding memory type settings for all memory regions.
+ @param RangeCount The count of memory ranges the array holds.
+ @param VertexCount The count of vertices in the graph.
+ @param Vertices Array holding all vertices.
+ @param Weight 2-dimention array holding weights between vertices.
+ @param Start Start vertex.
+ @param Stop Stop vertex.
+ @param Types Type bit mask of memory range from Start to Stop.
+ @param TypeCount Number of different memory types from Start to Stop.
+ @param Mtrrs Array holding all MTRR settings.
+ @param MtrrCapacity Capacity of the MTRR array.
+ @param MtrrCount The count of MTRR settings in array.
+
+ @retval RETURN_SUCCESS The subtractive path is calculated successfully.
+ @retval RETURN_OUT_OF_RESOURCES The MTRR setting array is full.
+
+**/
+RETURN_STATUS
+MtrrLibCalculateSubtractivePath (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT64 A0,
+ IN CONST MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount,
+ IN UINT16 VertexCount,
+ IN MTRR_LIB_ADDRESS *Vertices,
+ IN OUT UINT8 *Weight,
+ IN UINT16 Start,
+ IN UINT16 Stop,
+ IN UINT8 Types,
+ IN UINT8 TypeCount,
+ IN OUT MTRR_MEMORY_RANGE *Mtrrs, OPTIONAL
+ IN UINT32 MtrrCapacity, OPTIONAL
+ IN OUT UINT32 *MtrrCount OPTIONAL
+ )
+{
+ RETURN_STATUS Status;
+ UINT64 Base;
+ UINT64 Length;
+ UINT8 PrecedentTypes;
+ UINTN Index;
+ UINT64 HBase;
+ UINT64 HLength;
+ UINT64 SubLength;
+ UINT16 SubStart;
+ UINT16 SubStop;
+ UINT16 Cur;
+ UINT16 Pre;
+ MTRR_MEMORY_CACHE_TYPE LowestType;
+ MTRR_MEMORY_CACHE_TYPE LowestPrecedentType;
+
+ Base = Vertices[Start].Address;
+ Length = Vertices[Stop].Address - Base;
+
+ LowestType = MtrrLibLowestType (Types);
+
+ //
+ // Clear the lowest type (highest bit) to get the precedent types
+ //
+ PrecedentTypes = ~(1 << LowestType) & Types;
+ LowestPrecedentType = MtrrLibLowestType (PrecedentTypes);
+
+ if (Mtrrs == NULL) {
+ Weight[M(Start, Stop)] = ((LowestType == DefaultType) ? 0 : 1);
+ Weight[O(Start, Stop)] = ((LowestType == DefaultType) ? 1 : 0);
+ }
+
+ // Add all high level ranges
+ HBase = MAX_UINT64;
+ HLength = 0;
+ for (Index = 0; Index < RangeCount; Index++) {
+ if (Length == 0) {
+ break;
+ }
+ if ((Base < Ranges[Index].BaseAddress) || (Ranges[Index].BaseAddress + Ranges[Index].Length <= Base)) {
+ continue;
+ }
+
+ //
+ // Base is in the Range[Index]
+ //
+ if (Base + Length > Ranges[Index].BaseAddress + Ranges[Index].Length) {
+ SubLength = Ranges[Index].BaseAddress + Ranges[Index].Length - Base;
+ } else {
+ SubLength = Length;
+ }
+ if (((1 << Ranges[Index].Type) & PrecedentTypes) != 0) {
+ //
+ // Meet a range whose types take precedence.
+ // Update the [HBase, HBase + HLength) to include the range,
+ // [HBase, HBase + HLength) may contain sub ranges with 2 different types, and both take precedence.
+ //
+ if (HBase == MAX_UINT64) {
+ HBase = Base;
+ }
+ HLength += SubLength;
+ }
+
+ Base += SubLength;
+ Length -= SubLength;
+
+ if (HLength == 0) {
+ continue;
+ }
+
+ if ((Ranges[Index].Type == LowestType) || (Length == 0)) { // meet low type or end
+
+ //
+ // Add the MTRRs for each high priority type range
+ // the range[HBase, HBase + HLength) contains only two types.
+ // We might use positive or subtractive, depending on which way uses less MTRR
+ //
+ for (SubStart = Start; SubStart <= Stop; SubStart++) {
+ if (Vertices[SubStart].Address == HBase) {
+ break;
+ }
+ }
+
+ for (SubStop = SubStart; SubStop <= Stop; SubStop++) {
+ if (Vertices[SubStop].Address == HBase + HLength) {
+ break;
+ }
+ }
+ ASSERT (Vertices[SubStart].Address == HBase);
+ ASSERT (Vertices[SubStop].Address == HBase + HLength);
+
+ if ((TypeCount == 2) || (SubStart == SubStop - 1)) {
+ //
+ // add subtractive MTRRs for [HBase, HBase + HLength)
+ // [HBase, HBase + HLength) contains only one type.
+ // while - loop is to split the range to MTRR - compliant aligned range.
+ //
+ if (Mtrrs == NULL) {
+ Weight[M (Start, Stop)] += (UINT8)(SubStop - SubStart);
+ } else {
+ while (SubStart != SubStop) {
+ Status = MtrrLibAppendVariableMtrr (
+ Mtrrs, MtrrCapacity, MtrrCount,
+ Vertices[SubStart].Address, Vertices[SubStart].Length, Vertices[SubStart].Type
+ );
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ SubStart++;
+ }
+ }
+ } else {
+ ASSERT (TypeCount == 3);
+ MtrrLibCalculateLeastMtrrs (VertexCount, Vertices, Weight, SubStart, SubStop, TRUE);
+
+ if (Mtrrs == NULL) {
+ Weight[M (Start, Stop)] += Vertices[SubStop].Weight;
+ } else {
+ // When we need to collect the optimal path from SubStart to SubStop
+ while (SubStop != SubStart) {
+ Cur = SubStop;
+ Pre = Vertices[Cur].Previous;
+ SubStop = Pre;
+
+ if (Weight[M (Pre, Cur)] + Weight[O (Pre, Cur)] != 0) {
+ Status = MtrrLibAppendVariableMtrr (
+ Mtrrs, MtrrCapacity, MtrrCount,
+ Vertices[Pre].Address, Vertices[Cur].Address - Vertices[Pre].Address,
+ (Pre != Cur - 1) ? LowestPrecedentType : Vertices[Pre].Type
+ );
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ }
+ if (Pre != Cur - 1) {
+ Status = MtrrLibCalculateSubtractivePath (
+ DefaultType, A0,
+ Ranges, RangeCount,
+ VertexCount, Vertices, Weight,
+ Pre, Cur, PrecedentTypes, 2,
+ Mtrrs, MtrrCapacity, MtrrCount
+ );
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+ }
+
+ }
+ //
+ // Reset HBase, HLength
+ //
+ HBase = MAX_UINT64;
+ HLength = 0;
+ }
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Calculate MTRR settings to cover the specified memory ranges.
+
+ @param DefaultType Default memory type.
+ @param A0 Alignment to use when base address is 0.
+ @param Ranges Memory range array holding the memory type
+ settings for all memory address.
+ @param RangeCount Count of memory ranges.
+ @param Scratch A temporary scratch buffer that is used to perform the calculation.
+ This is an optional parameter that may be NULL.
+ @param ScratchSize Pointer to the size in bytes of the scratch buffer.
+ It may be updated to the actual required size when the calculation
+ needs more scratch buffer.
+ @param Mtrrs Array holding all MTRR settings.
+ @param MtrrCapacity Capacity of the MTRR array.
+ @param MtrrCount The count of MTRR settings in array.
+
+ @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
+ @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
+ @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
+**/
+RETURN_STATUS
+MtrrLibCalculateMtrrs (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT64 A0,
+ IN CONST MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount,
+ IN VOID *Scratch,
+ IN OUT UINTN *ScratchSize,
+ IN OUT MTRR_MEMORY_RANGE *Mtrrs,
+ IN UINT32 MtrrCapacity,
+ IN OUT UINT32 *MtrrCount
+ )
+{
+ UINT64 Base0;
+ UINT64 Base1;
+ UINTN Index;
+ UINT64 Base;
+ UINT64 Length;
+ UINT64 Alignment;
+ UINT64 SubLength;
+ MTRR_LIB_ADDRESS *Vertices;
+ UINT8 *Weight;
+ UINT32 VertexIndex;
+ UINT32 VertexCount;
+ UINTN RequiredScratchSize;
+ UINT8 TypeCount;
+ UINT16 Start;
+ UINT16 Stop;
+ UINT8 Type;
+ RETURN_STATUS Status;
+
+ Base0 = Ranges[0].BaseAddress;
+ Base1 = Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length;
+ MTRR_LIB_ASSERT_ALIGNED (Base0, Base1 - Base0);
+
+ //
+ // Count the number of vertices.
+ //
+ Vertices = (MTRR_LIB_ADDRESS*)Scratch;
+ for (VertexIndex = 0, Index = 0; Index < RangeCount; Index++) {
+ Base = Ranges[Index].BaseAddress;
+ Length = Ranges[Index].Length;
+ while (Length != 0) {
+ Alignment = MtrrLibBiggestAlignment (Base, A0);
+ SubLength = Alignment;
+ if (SubLength > Length) {
+ SubLength = GetPowerOfTwo64 (Length);
+ }
+ if (VertexIndex < *ScratchSize / sizeof (*Vertices)) {
+ Vertices[VertexIndex].Address = Base;
+ Vertices[VertexIndex].Alignment = Alignment;
+ Vertices[VertexIndex].Type = Ranges[Index].Type;
+ Vertices[VertexIndex].Length = SubLength;
+ }
+ Base += SubLength;
+ Length -= SubLength;
+ VertexIndex++;
+ }
+ }
+ //
+ // Vertices[VertexIndex] = Base1, so whole vertex count is (VertexIndex + 1).
+ //
+ VertexCount = VertexIndex + 1;
+ DEBUG ((
+ DEBUG_CACHE, " Count of vertices (%016llx - %016llx) = %d\n",
+ Ranges[0].BaseAddress, Ranges[RangeCount - 1].BaseAddress + Ranges[RangeCount - 1].Length, VertexCount
+ ));
+ ASSERT (VertexCount < MAX_UINT16);
+
+ RequiredScratchSize = VertexCount * sizeof (*Vertices) + VertexCount * VertexCount * sizeof (*Weight);
+ if (*ScratchSize < RequiredScratchSize) {
+ *ScratchSize = RequiredScratchSize;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ Vertices[VertexCount - 1].Address = Base1;
+
+ Weight = (UINT8 *) &Vertices[VertexCount];
+ for (VertexIndex = 0; VertexIndex < VertexCount; VertexIndex++) {
+ //
+ // Set optional weight between vertices and self->self to 0
+ //
+ SetMem (&Weight[M(VertexIndex, 0)], VertexIndex + 1, 0);
+ //
+ // Set mandatory weight between vertices to MAX_WEIGHT
+ //
+ SetMem (&Weight[M (VertexIndex, VertexIndex + 1)], VertexCount - VertexIndex - 1, MAX_WEIGHT);
+
+ // Final result looks like:
+ // 00 FF FF FF
+ // 00 00 FF FF
+ // 00 00 00 FF
+ // 00 00 00 00
+ }
+
+ //
+ // Set mandatory weight and optional weight for adjacent vertices
+ //
+ for (VertexIndex = 0; VertexIndex < VertexCount - 1; VertexIndex++) {
+ if (Vertices[VertexIndex].Type != DefaultType) {
+ Weight[M (VertexIndex, VertexIndex + 1)] = 1;
+ Weight[O (VertexIndex, VertexIndex + 1)] = 0;
+ } else {
+ Weight[M (VertexIndex, VertexIndex + 1)] = 0;
+ Weight[O (VertexIndex, VertexIndex + 1)] = 1;
+ }
+ }
+
+ for (TypeCount = 2; TypeCount <= 3; TypeCount++) {
+ for (Start = 0; Start < VertexCount; Start++) {
+ for (Stop = Start + 2; Stop < VertexCount; Stop++) {
+ ASSERT (Vertices[Stop].Address > Vertices[Start].Address);
+ Length = Vertices[Stop].Address - Vertices[Start].Address;
+ if (Length > Vertices[Start].Alignment) {
+ //
+ // Pickup a new Start when [Start, Stop) cannot be described by one MTRR.
+ //
+ break;
+ }
+ if ((Weight[M(Start, Stop)] == MAX_WEIGHT) && MtrrLibIsPowerOfTwo (Length)) {
+ if (MtrrLibGetNumberOfTypes (
+ Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
+ ) == TypeCount) {
+ //
+ // Update the Weight[Start, Stop] using subtractive path.
+ //
+ MtrrLibCalculateSubtractivePath (
+ DefaultType, A0,
+ Ranges, RangeCount,
+ (UINT16)VertexCount, Vertices, Weight,
+ Start, Stop, Type, TypeCount,
+ NULL, 0, NULL
+ );
+ } else if (TypeCount == 2) {
+ //
+ // Pick up a new Start when we expect 2-type range, but 3-type range is met.
+ // Because no matter how Stop is increased, we always meet 3-type range.
+ //
+ break;
+ }
+ }
+ }
+ }
+ }
+
+ Status = RETURN_SUCCESS;
+ MtrrLibCalculateLeastMtrrs ((UINT16) VertexCount, Vertices, Weight, 0, (UINT16) VertexCount - 1, FALSE);
+ Stop = (UINT16) VertexCount - 1;
+ while (Stop != 0) {
+ Start = Vertices[Stop].Previous;
+ TypeCount = MAX_UINT8;
+ Type = 0;
+ if (Weight[M(Start, Stop)] != 0) {
+ TypeCount = MtrrLibGetNumberOfTypes (Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type);
+ Status = MtrrLibAppendVariableMtrr (
+ Mtrrs, MtrrCapacity, MtrrCount,
+ Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address,
+ MtrrLibLowestType (Type)
+ );
+ if (RETURN_ERROR (Status)) {
+ break;
+ }
+ }
+
+ if (Start != Stop - 1) {
+ //
+ // substractive path
+ //
+ if (TypeCount == MAX_UINT8) {
+ TypeCount = MtrrLibGetNumberOfTypes (
+ Ranges, RangeCount, Vertices[Start].Address, Vertices[Stop].Address - Vertices[Start].Address, &Type
+ );
+ }
+ Status = MtrrLibCalculateSubtractivePath (
+ DefaultType, A0,
+ Ranges, RangeCount,
+ (UINT16) VertexCount, Vertices, Weight, Start, Stop,
+ Type, TypeCount,
+ Mtrrs, MtrrCapacity, MtrrCount
+ );
+ if (RETURN_ERROR (Status)) {
+ break;
+ }
+ }
+ Stop = Start;
+ }
+ return Status;
+}
+
+
+/**
+ Apply the fixed MTRR settings to memory range array.
+
+ @param Fixed The fixed MTRR settings.
+ @param Ranges Return the memory range array holding memory type
+ settings for all memory address.
+ @param RangeCapacity The capacity of memory range array.
+ @param RangeCount Return the count of memory range.
+
+ @retval RETURN_SUCCESS The memory range array is returned successfully.
+ @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
+**/
+RETURN_STATUS
+MtrrLibApplyFixedMtrrs (
+ IN MTRR_FIXED_SETTINGS *Fixed,
+ IN OUT MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCapacity,
+ IN OUT UINTN *RangeCount
+ )
+{
+ RETURN_STATUS Status;
+ UINTN MsrIndex;
+ UINTN Index;
+ MTRR_MEMORY_CACHE_TYPE MemoryType;
+ UINT64 Base;
+
+ Base = 0;
+ for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mMtrrLibFixedMtrrTable); MsrIndex++) {
+ ASSERT (Base == mMtrrLibFixedMtrrTable[MsrIndex].BaseAddress);
+ for (Index = 0; Index < sizeof (UINT64); Index++) {
+ MemoryType = (MTRR_MEMORY_CACHE_TYPE)((UINT8 *)(&Fixed->Mtrr[MsrIndex]))[Index];
+ Status = MtrrLibSetMemoryType (
+ Ranges, RangeCapacity, RangeCount, Base, mMtrrLibFixedMtrrTable[MsrIndex].Length, MemoryType
+ );
+ if (Status == RETURN_OUT_OF_RESOURCES) {
+ return Status;
+ }
+ Base += mMtrrLibFixedMtrrTable[MsrIndex].Length;
+ }
+ }
+ ASSERT (Base == BASE_1MB);
+ return RETURN_SUCCESS;
+}
+
+/**
+ Apply the variable MTRR settings to memory range array.
+
+ @param VariableMtrr The variable MTRR array.
+ @param VariableMtrrCount The count of variable MTRRs.
+ @param Ranges Return the memory range array with new MTRR settings applied.
+ @param RangeCapacity The capacity of memory range array.
+ @param RangeCount Return the count of memory range.
+
+ @retval RETURN_SUCCESS The memory range array is returned successfully.
+ @retval RETURN_OUT_OF_RESOURCES The count of memory ranges exceeds capacity.
+**/
+RETURN_STATUS
+MtrrLibApplyVariableMtrrs (
+ IN CONST MTRR_MEMORY_RANGE *VariableMtrr,
+ IN UINT32 VariableMtrrCount,
+ IN OUT MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCapacity,
+ IN OUT UINTN *RangeCount
+ )
+{
+ RETURN_STATUS Status;
+ UINTN Index;
+
+ //
+ // WT > WB
+ // UC > *
+ // UC > * (except WB, UC) > WB
+ //
+
+ //
+ // 1. Set WB
+ //
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if ((VariableMtrr[Index].Length != 0) && (VariableMtrr[Index].Type == CacheWriteBack)) {
+ Status = MtrrLibSetMemoryType (
+ Ranges, RangeCapacity, RangeCount,
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
+ );
+ if (Status == RETURN_OUT_OF_RESOURCES) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // 2. Set other types than WB or UC
+ //
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if ((VariableMtrr[Index].Length != 0) &&
+ (VariableMtrr[Index].Type != CacheWriteBack) && (VariableMtrr[Index].Type != CacheUncacheable)) {
+ Status = MtrrLibSetMemoryType (
+ Ranges, RangeCapacity, RangeCount,
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
+ );
+ if (Status == RETURN_OUT_OF_RESOURCES) {
+ return Status;
+ }
+ }
+ }
+
+ //
+ // 3. Set UC
+ //
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (VariableMtrr[Index].Length != 0 && VariableMtrr[Index].Type == CacheUncacheable) {
+ Status = MtrrLibSetMemoryType (
+ Ranges, RangeCapacity, RangeCount,
+ VariableMtrr[Index].BaseAddress, VariableMtrr[Index].Length, VariableMtrr[Index].Type
+ );
+ if (Status == RETURN_OUT_OF_RESOURCES) {
+ return Status;
+ }
+ }
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Return the memory type bit mask that's compatible to first type in the Ranges.
+
+ @param Ranges Memory range array holding the memory type
+ settings for all memory address.
+ @param RangeCount Count of memory ranges.
+
+ @return Compatible memory type bit mask.
+**/
+UINT8
+MtrrLibGetCompatibleTypes (
+ IN CONST MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount
+ )
+{
+ ASSERT (RangeCount != 0);
+
+ switch (Ranges[0].Type) {
+ case CacheWriteBack:
+ case CacheWriteThrough:
+ return (1 << CacheWriteBack) | (1 << CacheWriteThrough) | (1 << CacheUncacheable);
+ break;
+
+ case CacheWriteCombining:
+ case CacheWriteProtected:
+ return (1 << Ranges[0].Type) | (1 << CacheUncacheable);
+ break;
+
+ case CacheUncacheable:
+ if (RangeCount == 1) {
+ return (1 << CacheUncacheable);
+ }
+ return MtrrLibGetCompatibleTypes (&Ranges[1], RangeCount - 1);
+ break;
+
+ case CacheInvalid:
+ default:
+ ASSERT (FALSE);
+ break;
+ }
+ return 0;
+}
+
+/**
+ Overwrite the destination MTRR settings with the source MTRR settings.
+ This routine is to make sure the modification to destination MTRR settings
+ is as small as possible.
+
+ @param DstMtrrs Destination MTRR settings.
+ @param DstMtrrCount Count of destination MTRR settings.
+ @param SrcMtrrs Source MTRR settings.
+ @param SrcMtrrCount Count of source MTRR settings.
+ @param Modified Flag array to indicate which destination MTRR setting is modified.
+**/
+VOID
+MtrrLibMergeVariableMtrr (
+ MTRR_MEMORY_RANGE *DstMtrrs,
+ UINT32 DstMtrrCount,
+ MTRR_MEMORY_RANGE *SrcMtrrs,
+ UINT32 SrcMtrrCount,
+ BOOLEAN *Modified
+ )
+{
+ UINT32 DstIndex;
+ UINT32 SrcIndex;
+
+ ASSERT (SrcMtrrCount <= DstMtrrCount);
+
+ for (DstIndex = 0; DstIndex < DstMtrrCount; DstIndex++) {
+ Modified[DstIndex] = FALSE;
+
+ if (DstMtrrs[DstIndex].Length == 0) {
+ continue;
+ }
+ for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
+ if (DstMtrrs[DstIndex].BaseAddress == SrcMtrrs[SrcIndex].BaseAddress &&
+ DstMtrrs[DstIndex].Length == SrcMtrrs[SrcIndex].Length &&
+ DstMtrrs[DstIndex].Type == SrcMtrrs[SrcIndex].Type) {
+ break;
+ }
+ }
+
+ if (SrcIndex == SrcMtrrCount) {
+ //
+ // Remove the one from DstMtrrs which is not in SrcMtrrs
+ //
+ DstMtrrs[DstIndex].Length = 0;
+ Modified[DstIndex] = TRUE;
+ } else {
+ //
+ // Remove the one from SrcMtrrs which is also in DstMtrrs
+ //
+ SrcMtrrs[SrcIndex].Length = 0;
+ }
+ }
+
+ //
+ // Now valid MTRR only exists in either DstMtrrs or SrcMtrrs.
+ // Merge MTRRs from SrcMtrrs to DstMtrrs
+ //
+ DstIndex = 0;
+ for (SrcIndex = 0; SrcIndex < SrcMtrrCount; SrcIndex++) {
+ if (SrcMtrrs[SrcIndex].Length != 0) {
+
+ //
+ // Find the empty slot in DstMtrrs
+ //
+ while (DstIndex < DstMtrrCount) {
+ if (DstMtrrs[DstIndex].Length == 0) {
+ break;
+ }
+ DstIndex++;
+ }
+ ASSERT (DstIndex < DstMtrrCount);
+ CopyMem (&DstMtrrs[DstIndex], &SrcMtrrs[SrcIndex], sizeof (SrcMtrrs[0]));
+ Modified[DstIndex] = TRUE;
+ }
+ }
+}
+
+/**
+ Calculate the variable MTRR settings for all memory ranges.
+
+ @param DefaultType Default memory type.
+ @param A0 Alignment to use when base address is 0.
+ @param Ranges Memory range array holding the memory type
+ settings for all memory address.
+ @param RangeCount Count of memory ranges.
+ @param Scratch Scratch buffer to be used in MTRR calculation.
+ @param ScratchSize Pointer to the size of scratch buffer.
+ @param VariableMtrr Array holding all MTRR settings.
+ @param VariableMtrrCapacity Capacity of the MTRR array.
+ @param VariableMtrrCount The count of MTRR settings in array.
+
+ @retval RETURN_SUCCESS Variable MTRRs are allocated successfully.
+ @retval RETURN_OUT_OF_RESOURCES Count of variable MTRRs exceeds capacity.
+ @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
+ The required scratch buffer size is returned through ScratchSize.
+**/
+RETURN_STATUS
+MtrrLibSetMemoryRanges (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT64 A0,
+ IN MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount,
+ IN VOID *Scratch,
+ IN OUT UINTN *ScratchSize,
+ OUT MTRR_MEMORY_RANGE *VariableMtrr,
+ IN UINT32 VariableMtrrCapacity,
+ OUT UINT32 *VariableMtrrCount
+ )
+{
+ RETURN_STATUS Status;
+ UINT32 Index;
+ UINT64 Base0;
+ UINT64 Base1;
+ UINT64 Alignment;
+ UINT8 CompatibleTypes;
+ UINT64 Length;
+ UINT32 End;
+ UINTN ActualScratchSize;
+ UINTN BiggestScratchSize;
+
+ *VariableMtrrCount = 0;
+
+ //
+ // Since the whole ranges need multiple calls of MtrrLibCalculateMtrrs().
+ // Each call needs different scratch buffer size.
+ // When the provided scratch buffer size is not sufficient in any call,
+ // set the GetActualScratchSize to TRUE, and following calls will only
+ // calculate the actual scratch size for the caller.
+ //
+ BiggestScratchSize = 0;
+
+ for (Index = 0; Index < RangeCount;) {
+ Base0 = Ranges[Index].BaseAddress;
+
+ //
+ // Full step is optimal
+ //
+ while (Index < RangeCount) {
+ ASSERT (Ranges[Index].BaseAddress == Base0);
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);
+ while (Base0 + Alignment <= Ranges[Index].BaseAddress + Ranges[Index].Length) {
+ if ((BiggestScratchSize <= *ScratchSize) && (Ranges[Index].Type != DefaultType)) {
+ Status = MtrrLibAppendVariableMtrr (
+ VariableMtrr, VariableMtrrCapacity, VariableMtrrCount,
+ Base0, Alignment, Ranges[Index].Type
+ );
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ }
+ Base0 += Alignment;
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);
+ }
+
+ //
+ // Remove the above range from Ranges[Index]
+ //
+ Ranges[Index].Length -= Base0 - Ranges[Index].BaseAddress;
+ Ranges[Index].BaseAddress = Base0;
+ if (Ranges[Index].Length != 0) {
+ break;
+ } else {
+ Index++;
+ }
+ }
+
+ if (Index == RangeCount) {
+ break;
+ }
+
+ //
+ // Find continous ranges [Base0, Base1) which could be combined by MTRR.
+ // Per SDM, the compatible types between[B0, B1) are:
+ // UC, *
+ // WB, WT
+ // UC, WB, WT
+ //
+ CompatibleTypes = MtrrLibGetCompatibleTypes (&Ranges[Index], RangeCount - Index);
+
+ End = Index; // End points to last one that matches the CompatibleTypes.
+ while (End + 1 < RangeCount) {
+ if (((1 << Ranges[End + 1].Type) & CompatibleTypes) == 0) {
+ break;
+ }
+ End++;
+ }
+ Alignment = MtrrLibBiggestAlignment (Base0, A0);
+ Length = GetPowerOfTwo64 (Ranges[End].BaseAddress + Ranges[End].Length - Base0);
+ Base1 = Base0 + MIN (Alignment, Length);
+
+ //
+ // Base1 may not in Ranges[End]. Update End to the range Base1 belongs to.
+ //
+ End = Index;
+ while (End + 1 < RangeCount) {
+ if (Base1 <= Ranges[End + 1].BaseAddress) {
+ break;
+ }
+ End++;
+ }
+
+ Length = Ranges[End].Length;
+ Ranges[End].Length = Base1 - Ranges[End].BaseAddress;
+ ActualScratchSize = *ScratchSize;
+ Status = MtrrLibCalculateMtrrs (
+ DefaultType, A0,
+ &Ranges[Index], End + 1 - Index,
+ Scratch, &ActualScratchSize,
+ VariableMtrr, VariableMtrrCapacity, VariableMtrrCount
+ );
+ if (Status == RETURN_BUFFER_TOO_SMALL) {
+ BiggestScratchSize = MAX (BiggestScratchSize, ActualScratchSize);
+ //
+ // Ignore this error, because we need to calculate the biggest
+ // scratch buffer size.
+ //
+ Status = RETURN_SUCCESS;
+ }
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Length != Ranges[End].Length) {
+ Ranges[End].BaseAddress = Base1;
+ Ranges[End].Length = Length - Ranges[End].Length;
+ Index = End;
+ } else {
+ Index = End + 1;
+ }
+ }
+
+ if (*ScratchSize < BiggestScratchSize) {
+ *ScratchSize = BiggestScratchSize;
+ return RETURN_BUFFER_TOO_SMALL;
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ Set the below-1MB memory attribute to fixed MTRR buffer.
+ Modified flag array indicates which fixed MTRR is modified.
+
+ @param [in, out] ClearMasks The bits (when set) to clear in the fixed MTRR MSR.
+ @param [in, out] OrMasks The bits to set in the fixed MTRR MSR.
+ @param [in] BaseAddress Base address.
+ @param [in] Length Length.
+ @param [in] Type Memory type.
+
+ @retval RETURN_SUCCESS The memory attribute is set successfully.
+ @retval RETURN_UNSUPPORTED The requested range or cache type was invalid
+ for the fixed MTRRs.
+**/
+RETURN_STATUS
+MtrrLibSetBelow1MBMemoryAttribute (
+ IN OUT UINT64 *ClearMasks,
+ IN OUT UINT64 *OrMasks,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Type
+ )
+{
+ RETURN_STATUS Status;
+ UINT32 MsrIndex;
+ UINT64 ClearMask;
+ UINT64 OrMask;
+
+ ASSERT (BaseAddress < BASE_1MB);
+
+ MsrIndex = (UINT32)-1;
+ while ((BaseAddress < BASE_1MB) && (Length != 0)) {
+ Status = MtrrLibProgramFixedMtrr (Type, &BaseAddress, &Length, &MsrIndex, &ClearMask, &OrMask);
+ if (RETURN_ERROR (Status)) {
+ return Status;
+ }
+ ClearMasks[MsrIndex] = ClearMasks[MsrIndex] | ClearMask;
+ OrMasks[MsrIndex] = (OrMasks[MsrIndex] & ~ClearMask) | OrMask;
+ }
+ return RETURN_SUCCESS;
+}
+
+/**
+ This function attempts to set the attributes into MTRR setting buffer for multiple memory ranges.
+
+ @param[in, out] MtrrSetting MTRR setting buffer to be set.
+ @param[in] Scratch A temporary scratch buffer that is used to perform the calculation.
+ @param[in, out] ScratchSize Pointer to the size in bytes of the scratch buffer.
+ It may be updated to the actual required size when the calculation
+ needs more scratch buffer.
+ @param[in] Ranges Pointer to an array of MTRR_MEMORY_RANGE.
+ When range overlap happens, the last one takes higher priority.
+ When the function returns, either all the attributes are set successfully,
+ or none of them is set.
+ @param[in] RangeCount Count of MTRR_MEMORY_RANGE.
+
+ @retval RETURN_SUCCESS The attributes were set for all the memory ranges.
+ @retval RETURN_INVALID_PARAMETER Length in any range is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
+ memory resource range specified by BaseAddress and Length in any range.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length in any range.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource ranges.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval RETURN_BUFFER_TOO_SMALL The scratch buffer is too small for MTRR calculation.
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttributesInMtrrSettings (
+ IN OUT MTRR_SETTINGS *MtrrSetting,
+ IN VOID *Scratch,
+ IN OUT UINTN *ScratchSize,
+ IN CONST MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount
+ )
+{
+ RETURN_STATUS Status;
+ UINT32 Index;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ BOOLEAN Above1MbExist;
+
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ MTRR_MEMORY_CACHE_TYPE DefaultType;
+ MTRR_VARIABLE_SETTINGS VariableSettings;
+ MTRR_MEMORY_RANGE WorkingRanges[2 * ARRAY_SIZE (MtrrSetting->Variables.Mtrr) + 2];
+ UINTN WorkingRangeCount;
+ BOOLEAN Modified;
+ MTRR_VARIABLE_SETTING VariableSetting;
+ UINT32 OriginalVariableMtrrCount;
+ UINT32 FirmwareVariableMtrrCount;
+ UINT32 WorkingVariableMtrrCount;
+ MTRR_MEMORY_RANGE OriginalVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
+ MTRR_MEMORY_RANGE WorkingVariableMtrr[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
+ BOOLEAN VariableSettingModified[ARRAY_SIZE (MtrrSetting->Variables.Mtrr)];
+
+ UINT64 ClearMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
+ UINT64 OrMasks[ARRAY_SIZE (mMtrrLibFixedMtrrTable)];
+
+ MTRR_CONTEXT MtrrContext;
+ BOOLEAN MtrrContextValid;
+
+ Status = RETURN_SUCCESS;
+ MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
+
+ //
+ // TRUE indicating the accordingly Variable setting needs modificaiton in OriginalVariableMtrr.
+ //
+ SetMem (VariableSettingModified, ARRAY_SIZE (VariableSettingModified), FALSE);
+
+ //
+ // TRUE indicating the caller requests to set variable MTRRs.
+ //
+ Above1MbExist = FALSE;
+ OriginalVariableMtrrCount = 0;
+
+ //
+ // 0. Dump the requests.
+ //
+ DEBUG_CODE (
+ DEBUG ((DEBUG_CACHE, "Mtrr: Set Mem Attribute to %a, ScratchSize = %x%a",
+ (MtrrSetting == NULL) ? "Hardware" : "Buffer", *ScratchSize,
+ (RangeCount <= 1) ? "," : "\n"
+ ));
+ for (Index = 0; Index < RangeCount; Index++) {
+ DEBUG ((DEBUG_CACHE, " %a: [%016lx, %016lx)\n",
+ mMtrrMemoryCacheTypeShortName[MIN (Ranges[Index].Type, CacheInvalid)],
+ Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length
+ ));
+ }
+ );
+
+ //
+ // 1. Validate the parameters.
+ //
+ if (!IsMtrrSupported ()) {
+ Status = RETURN_UNSUPPORTED;
+ goto Exit;
+ }
+
+ for (Index = 0; Index < RangeCount; Index++) {
+ if (Ranges[Index].Length == 0) {
+ Status = RETURN_INVALID_PARAMETER;
+ goto Exit;
+ }
+ if (((Ranges[Index].BaseAddress & ~MtrrValidAddressMask) != 0) ||
+ ((((Ranges[Index].BaseAddress + Ranges[Index].Length) & ~MtrrValidAddressMask) != 0) &&
+ (Ranges[Index].BaseAddress + Ranges[Index].Length) != MtrrValidBitsMask + 1)
+ ) {
+ //
+ // Either the BaseAddress or the Limit doesn't follow the alignment requirement.
+ // Note: It's still valid if Limit doesn't follow the alignment requirement but equals to MAX Address.
+ //
+ Status = RETURN_UNSUPPORTED;
+ goto Exit;
+ }
+ if ((Ranges[Index].Type != CacheUncacheable) &&
+ (Ranges[Index].Type != CacheWriteCombining) &&
+ (Ranges[Index].Type != CacheWriteThrough) &&
+ (Ranges[Index].Type != CacheWriteProtected) &&
+ (Ranges[Index].Type != CacheWriteBack)) {
+ Status = RETURN_INVALID_PARAMETER;
+ goto Exit;
+ }
+ if (Ranges[Index].BaseAddress + Ranges[Index].Length > BASE_1MB) {
+ Above1MbExist = TRUE;
+ }
+ }
+
+ //
+ // 2. Apply the above-1MB memory attribute settings.
+ //
+ if (Above1MbExist) {
+ //
+ // 2.1. Read all variable MTRRs and convert to Ranges.
+ //
+ OriginalVariableMtrrCount = GetVariableMtrrCountWorker ();
+ MtrrGetVariableMtrrWorker (MtrrSetting, OriginalVariableMtrrCount, &VariableSettings);
+ MtrrLibGetRawVariableRanges (
+ &VariableSettings, OriginalVariableMtrrCount,
+ MtrrValidBitsMask, MtrrValidAddressMask, OriginalVariableMtrr
+ );
+
+ DefaultType = MtrrGetDefaultMemoryTypeWorker (MtrrSetting);
+ WorkingRangeCount = 1;
+ WorkingRanges[0].BaseAddress = 0;
+ WorkingRanges[0].Length = MtrrValidBitsMask + 1;
+ WorkingRanges[0].Type = DefaultType;
+
+ Status = MtrrLibApplyVariableMtrrs (
+ OriginalVariableMtrr, OriginalVariableMtrrCount,
+ WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount);
+ ASSERT_RETURN_ERROR (Status);
+
+ ASSERT (OriginalVariableMtrrCount >= PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs));
+ FirmwareVariableMtrrCount = OriginalVariableMtrrCount - PcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
+ ASSERT (WorkingRangeCount <= 2 * FirmwareVariableMtrrCount + 1);
+
+ //
+ // 2.2. Force [0, 1M) to UC, so that it doesn't impact subtraction algorithm.
+ //
+ Status = MtrrLibSetMemoryType (
+ WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
+ 0, SIZE_1MB, CacheUncacheable
+ );
+ ASSERT (Status != RETURN_OUT_OF_RESOURCES);
+
+ //
+ // 2.3. Apply the new memory attribute settings to Ranges.
+ //
+ Modified = FALSE;
+ for (Index = 0; Index < RangeCount; Index++) {
+ BaseAddress = Ranges[Index].BaseAddress;
+ Length = Ranges[Index].Length;
+ if (BaseAddress < BASE_1MB) {
+ if (Length <= BASE_1MB - BaseAddress) {
+ continue;
+ }
+ Length -= BASE_1MB - BaseAddress;
+ BaseAddress = BASE_1MB;
+ }
+ Status = MtrrLibSetMemoryType (
+ WorkingRanges, ARRAY_SIZE (WorkingRanges), &WorkingRangeCount,
+ BaseAddress, Length, Ranges[Index].Type
+ );
+ if (Status == RETURN_ALREADY_STARTED) {
+ Status = RETURN_SUCCESS;
+ } else if (Status == RETURN_OUT_OF_RESOURCES) {
+ goto Exit;
+ } else {
+ ASSERT_RETURN_ERROR (Status);
+ Modified = TRUE;
+ }
+ }
+
+ if (Modified) {
+ //
+ // 2.4. Calculate the Variable MTRR settings based on the Ranges.
+ // Buffer Too Small may be returned if the scratch buffer size is insufficient.
+ //
+ Status = MtrrLibSetMemoryRanges (
+ DefaultType, LShiftU64 (1, (UINTN)HighBitSet64 (MtrrValidBitsMask)), WorkingRanges, WorkingRangeCount,
+ Scratch, ScratchSize,
+ WorkingVariableMtrr, FirmwareVariableMtrrCount + 1, &WorkingVariableMtrrCount
+ );
+ if (RETURN_ERROR (Status)) {
+ goto Exit;
+ }
+
+ //
+ // 2.5. Remove the [0, 1MB) MTRR if it still exists (not merged with other range)
+ //
+ for (Index = 0; Index < WorkingVariableMtrrCount; Index++) {
+ if (WorkingVariableMtrr[Index].BaseAddress == 0 && WorkingVariableMtrr[Index].Length == SIZE_1MB) {
+ ASSERT (WorkingVariableMtrr[Index].Type == CacheUncacheable);
+ WorkingVariableMtrrCount--;
+ CopyMem (
+ &WorkingVariableMtrr[Index], &WorkingVariableMtrr[Index + 1],
+ (WorkingVariableMtrrCount - Index) * sizeof (WorkingVariableMtrr[0])
+ );
+ break;
+ }
+ }
+
+ if (WorkingVariableMtrrCount > FirmwareVariableMtrrCount) {
+ Status = RETURN_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // 2.6. Merge the WorkingVariableMtrr to OriginalVariableMtrr
+ // Make sure least modification is made to OriginalVariableMtrr.
+ //
+ MtrrLibMergeVariableMtrr (
+ OriginalVariableMtrr, OriginalVariableMtrrCount,
+ WorkingVariableMtrr, WorkingVariableMtrrCount,
+ VariableSettingModified
+ );
+ }
+ }
+
+ //
+ // 3. Apply the below-1MB memory attribute settings.
+ //
+ // (Value & ~0 | 0) still equals to (Value)
+ //
+ ZeroMem (ClearMasks, sizeof (ClearMasks));
+ ZeroMem (OrMasks, sizeof (OrMasks));
+ for (Index = 0; Index < RangeCount; Index++) {
+ if (Ranges[Index].BaseAddress >= BASE_1MB) {
+ continue;
+ }
+
+ Status = MtrrLibSetBelow1MBMemoryAttribute (
+ ClearMasks, OrMasks,
+ Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type
+ );
+ if (RETURN_ERROR (Status)) {
+ goto Exit;
+ }
+ }
+
+ MtrrContextValid = FALSE;
+ //
+ // 4. Write fixed MTRRs that have been modified
+ //
+ for (Index = 0; Index < ARRAY_SIZE (ClearMasks); Index++) {
+ if (ClearMasks[Index] != 0) {
+ if (MtrrSetting != NULL) {
+ MtrrSetting->Fixed.Mtrr[Index] = (MtrrSetting->Fixed.Mtrr[Index] & ~ClearMasks[Index]) | OrMasks[Index];
+ } else {
+ if (!MtrrContextValid) {
+ MtrrLibPreMtrrChange (&MtrrContext);
+ MtrrContextValid = TRUE;
+ }
+ AsmMsrAndThenOr64 (mMtrrLibFixedMtrrTable[Index].Msr, ~ClearMasks[Index], OrMasks[Index]);
+ }
+ }
+ }
+
+ //
+ // 5. Write variable MTRRs that have been modified
+ //
+ for (Index = 0; Index < OriginalVariableMtrrCount; Index++) {
+ if (VariableSettingModified[Index]) {
+ if (OriginalVariableMtrr[Index].Length != 0) {
+ VariableSetting.Base = (OriginalVariableMtrr[Index].BaseAddress & MtrrValidAddressMask)
+ | (UINT8)OriginalVariableMtrr[Index].Type;
+ VariableSetting.Mask = ((~(OriginalVariableMtrr[Index].Length - 1)) & MtrrValidAddressMask) | BIT11;
+ } else {
+ VariableSetting.Base = 0;
+ VariableSetting.Mask = 0;
+ }
+ if (MtrrSetting != NULL) {
+ CopyMem (&MtrrSetting->Variables.Mtrr[Index], &VariableSetting, sizeof (VariableSetting));
+ } else {
+ if (!MtrrContextValid) {
+ MtrrLibPreMtrrChange (&MtrrContext);
+ MtrrContextValid = TRUE;
+ }
+ AsmWriteMsr64 (
+ MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
+ VariableSetting.Base
+ );
+ AsmWriteMsr64 (
+ MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
+ VariableSetting.Mask
+ );
+ }
+ }
+ }
+
+ if (MtrrSetting != NULL) {
+ ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.E = 1;
+ ((MSR_IA32_MTRR_DEF_TYPE_REGISTER *)&MtrrSetting->MtrrDefType)->Bits.FE = 1;
+ } else {
+ if (MtrrContextValid) {
+ MtrrLibPostMtrrChange (&MtrrContext);
+ }
+ }
+
+Exit:
+ DEBUG ((DEBUG_CACHE, " Result = %r\n", Status));
+ if (!RETURN_ERROR (Status)) {
+ MtrrDebugPrintAllMtrrsWorker (MtrrSetting);
+ }
+ return Status;
+}
+
+/**
+ This function attempts to set the attributes into MTRR setting buffer for a memory range.
+
+ @param[in, out] MtrrSetting MTRR setting buffer to be set.
+ @param[in] BaseAddress The physical address that is the start address
+ of a memory range.
+ @param[in] Length The size in bytes of the memory range.
+ @param[in] Attribute The bit mask of attributes to set for the
+ memory range.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory range.
+ @retval RETURN_INVALID_PARAMETER Length is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or more bytes of the
+ memory resource range specified by BaseAddress and Length.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support for the memory resource
+ range specified by BaseAddress and Length.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource range specified by
+ BaseAddress and Length cannot be modified.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to modify the attributes of
+ the memory resource range.
+ Multiple memory range attributes setting by calling this API multiple
+ times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
+ the number of CPU MTRRs are too small to set such memory attributes.
+ Pass the multiple memory range attributes to one call of
+ MtrrSetMemoryAttributesInMtrrSettings() may succeed.
+ @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
+ Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
+ external scratch buffer.
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttributeInMtrrSettings (
+ IN OUT MTRR_SETTINGS *MtrrSetting,
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Attribute
+ )
+{
+ UINT8 Scratch[SCRATCH_BUFFER_SIZE];
+ UINTN ScratchSize;
+ MTRR_MEMORY_RANGE Range;
+
+ Range.BaseAddress = BaseAddress;
+ Range.Length = Length;
+ Range.Type = Attribute;
+ ScratchSize = sizeof (Scratch);
+ return MtrrSetMemoryAttributesInMtrrSettings (MtrrSetting, Scratch, &ScratchSize, &Range, 1);
+}
+
+/**
+ This function attempts to set the attributes for a memory range.
+
+ @param[in] BaseAddress The physical address that is the start
+ address of a memory range.
+ @param[in] Length The size in bytes of the memory range.
+ @param[in] Attributes The bit mask of attributes to set for the
+ memory range.
+
+ @retval RETURN_SUCCESS The attributes were set for the memory
+ range.
+ @retval RETURN_INVALID_PARAMETER Length is zero.
+ @retval RETURN_UNSUPPORTED The processor does not support one or
+ more bytes of the memory resource range
+ specified by BaseAddress and Length.
+ @retval RETURN_UNSUPPORTED The bit mask of attributes is not support
+ for the memory resource range specified
+ by BaseAddress and Length.
+ @retval RETURN_ACCESS_DENIED The attributes for the memory resource
+ range specified by BaseAddress and Length
+ cannot be modified.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough system resources to
+ modify the attributes of the memory
+ resource range.
+ Multiple memory range attributes setting by calling this API multiple
+ times may fail with status RETURN_OUT_OF_RESOURCES. It may not mean
+ the number of CPU MTRRs are too small to set such memory attributes.
+ Pass the multiple memory range attributes to one call of
+ MtrrSetMemoryAttributesInMtrrSettings() may succeed.
+ @retval RETURN_BUFFER_TOO_SMALL The fixed internal scratch buffer is too small for MTRR calculation.
+ Caller should use MtrrSetMemoryAttributesInMtrrSettings() to specify
+ external scratch buffer.
+**/
+RETURN_STATUS
+EFIAPI
+MtrrSetMemoryAttribute (
+ IN PHYSICAL_ADDRESS BaseAddress,
+ IN UINT64 Length,
+ IN MTRR_MEMORY_CACHE_TYPE Attribute
+ )
+{
+ return MtrrSetMemoryAttributeInMtrrSettings (NULL, BaseAddress, Length, Attribute);
+}
+
+/**
+ Worker function setting variable MTRRs
+
+ @param[in] VariableSettings A buffer to hold variable MTRRs content.
+
+**/
+VOID
+MtrrSetVariableMtrrWorker (
+ IN MTRR_VARIABLE_SETTINGS *VariableSettings
+ )
+{
+ UINT32 Index;
+ UINT32 VariableMtrrCount;
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+ ASSERT (VariableMtrrCount <= ARRAY_SIZE (VariableSettings->Mtrr));
+
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ AsmWriteMsr64 (
+ MSR_IA32_MTRR_PHYSBASE0 + (Index << 1),
+ VariableSettings->Mtrr[Index].Base
+ );
+ AsmWriteMsr64 (
+ MSR_IA32_MTRR_PHYSMASK0 + (Index << 1),
+ VariableSettings->Mtrr[Index].Mask
+ );
+ }
+}
+
+/**
+ Worker function setting fixed MTRRs
+
+ @param[in] FixedSettings A buffer to hold fixed MTRRs content.
+
+**/
+VOID
+MtrrSetFixedMtrrWorker (
+ IN MTRR_FIXED_SETTINGS *FixedSettings
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < MTRR_NUMBER_OF_FIXED_MTRR; Index++) {
+ AsmWriteMsr64 (
+ mMtrrLibFixedMtrrTable[Index].Msr,
+ FixedSettings->Mtrr[Index]
+ );
+ }
+}
+
+
+/**
+ This function gets the content in all MTRRs (variable and fixed)
+
+ @param[out] MtrrSetting A buffer to hold all MTRRs content.
+
+ @retval the pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrGetAllMtrrs (
+ OUT MTRR_SETTINGS *MtrrSetting
+ )
+{
+ if (!IsMtrrSupported ()) {
+ return MtrrSetting;
+ }
+
+ //
+ // Get fixed MTRRs
+ //
+ MtrrGetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+ //
+ // Get variable MTRRs
+ //
+ MtrrGetVariableMtrrWorker (
+ NULL,
+ GetVariableMtrrCountWorker (),
+ &MtrrSetting->Variables
+ );
+
+ //
+ // Get MTRR_DEF_TYPE value
+ //
+ MtrrSetting->MtrrDefType = AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE);
+
+ return MtrrSetting;
+}
+
+
+/**
+ This function sets all MTRRs (variable and fixed)
+
+ @param[in] MtrrSetting A buffer holding all MTRRs content.
+
+ @retval The pointer of MtrrSetting
+
+**/
+MTRR_SETTINGS *
+EFIAPI
+MtrrSetAllMtrrs (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ MTRR_CONTEXT MtrrContext;
+
+ if (!IsMtrrSupported ()) {
+ return MtrrSetting;
+ }
+
+ MtrrLibPreMtrrChange (&MtrrContext);
+
+ //
+ // Set fixed MTRRs
+ //
+ MtrrSetFixedMtrrWorker (&MtrrSetting->Fixed);
+
+ //
+ // Set variable MTRRs
+ //
+ MtrrSetVariableMtrrWorker (&MtrrSetting->Variables);
+
+ //
+ // Set MTRR_DEF_TYPE value
+ //
+ AsmWriteMsr64 (MSR_IA32_MTRR_DEF_TYPE, MtrrSetting->MtrrDefType);
+
+ MtrrLibPostMtrrChangeEnableCache (&MtrrContext);
+
+ return MtrrSetting;
+}
+
+
+/**
+ Checks if MTRR is supported.
+
+ @retval TRUE MTRR is supported.
+ @retval FALSE MTRR is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+IsMtrrSupported (
+ VOID
+ )
+{
+ CPUID_VERSION_INFO_EDX Edx;
+ MSR_IA32_MTRRCAP_REGISTER MtrrCap;
+
+ //
+ // Check CPUID(1).EDX[12] for MTRR capability
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, NULL, &Edx.Uint32);
+ if (Edx.Bits.MTRR == 0) {
+ return FALSE;
+ }
+
+ //
+ // Check number of variable MTRRs and fixed MTRRs existence.
+ // If number of variable MTRRs is zero, or fixed MTRRs do not
+ // exist, return false.
+ //
+ MtrrCap.Uint64 = AsmReadMsr64 (MSR_IA32_MTRRCAP);
+ if ((MtrrCap.Bits.VCNT == 0) || (MtrrCap.Bits.FIX == 0)) {
+ return FALSE;
+ }
+ return TRUE;
+}
+
+
+/**
+ Worker function prints all MTRRs for debugging.
+
+ If MtrrSetting is not NULL, print MTRR settings from input MTRR
+ settings buffer.
+ If MtrrSetting is NULL, print MTRR settings from MTRRs.
+
+ @param MtrrSetting A buffer holding all MTRRs content.
+**/
+VOID
+MtrrDebugPrintAllMtrrsWorker (
+ IN MTRR_SETTINGS *MtrrSetting
+ )
+{
+ DEBUG_CODE (
+ MTRR_SETTINGS LocalMtrrs;
+ MTRR_SETTINGS *Mtrrs;
+ UINTN Index;
+ UINTN RangeCount;
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ UINT32 VariableMtrrCount;
+ BOOLEAN ContainVariableMtrr;
+ MTRR_MEMORY_RANGE Ranges[
+ ARRAY_SIZE (mMtrrLibFixedMtrrTable) * sizeof (UINT64) + 2 * ARRAY_SIZE (Mtrrs->Variables.Mtrr) + 1
+ ];
+ MTRR_MEMORY_RANGE RawVariableRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
+
+ if (!IsMtrrSupported ()) {
+ return;
+ }
+
+ VariableMtrrCount = GetVariableMtrrCountWorker ();
+
+ if (MtrrSetting != NULL) {
+ Mtrrs = MtrrSetting;
+ } else {
+ MtrrGetAllMtrrs (&LocalMtrrs);
+ Mtrrs = &LocalMtrrs;
+ }
+
+ //
+ // Dump RAW MTRR contents
+ //
+ DEBUG ((DEBUG_CACHE, "MTRR Settings:\n"));
+ DEBUG ((DEBUG_CACHE, "=============\n"));
+ DEBUG ((DEBUG_CACHE, "MTRR Default Type: %016lx\n", Mtrrs->MtrrDefType));
+ for (Index = 0; Index < ARRAY_SIZE (mMtrrLibFixedMtrrTable); Index++) {
+ DEBUG ((DEBUG_CACHE, "Fixed MTRR[%02d] : %016lx\n", Index, Mtrrs->Fixed.Mtrr[Index]));
+ }
+ ContainVariableMtrr = FALSE;
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if ((Mtrrs->Variables.Mtrr[Index].Mask & BIT11) == 0) {
+ //
+ // If mask is not valid, then do not display range
+ //
+ continue;
+ }
+ ContainVariableMtrr = TRUE;
+ DEBUG ((DEBUG_CACHE, "Variable MTRR[%02d]: Base=%016lx Mask=%016lx\n",
+ Index,
+ Mtrrs->Variables.Mtrr[Index].Base,
+ Mtrrs->Variables.Mtrr[Index].Mask
+ ));
+ }
+ if (!ContainVariableMtrr) {
+ DEBUG ((DEBUG_CACHE, "Variable MTRR : None.\n"));
+ }
+ DEBUG((DEBUG_CACHE, "\n"));
+
+ //
+ // Dump MTRR setting in ranges
+ //
+ DEBUG((DEBUG_CACHE, "Memory Ranges:\n"));
+ DEBUG((DEBUG_CACHE, "====================================\n"));
+ MtrrLibInitializeMtrrMask (&MtrrValidBitsMask, &MtrrValidAddressMask);
+ Ranges[0].BaseAddress = 0;
+ Ranges[0].Length = MtrrValidBitsMask + 1;
+ Ranges[0].Type = MtrrGetDefaultMemoryTypeWorker (Mtrrs);
+ RangeCount = 1;
+
+ MtrrLibGetRawVariableRanges (
+ &Mtrrs->Variables, VariableMtrrCount,
+ MtrrValidBitsMask, MtrrValidAddressMask, RawVariableRanges
+ );
+ MtrrLibApplyVariableMtrrs (
+ RawVariableRanges, VariableMtrrCount,
+ Ranges, ARRAY_SIZE (Ranges), &RangeCount
+ );
+
+ MtrrLibApplyFixedMtrrs (&Mtrrs->Fixed, Ranges, ARRAY_SIZE (Ranges), &RangeCount);
+
+ for (Index = 0; Index < RangeCount; Index++) {
+ DEBUG ((DEBUG_CACHE, "%a:%016lx-%016lx\n",
+ mMtrrMemoryCacheTypeShortName[Ranges[Index].Type],
+ Ranges[Index].BaseAddress, Ranges[Index].BaseAddress + Ranges[Index].Length - 1
+ ));
+ }
+ );
+}
+
+/**
+ This function prints all MTRRs for debugging.
+**/
+VOID
+EFIAPI
+MtrrDebugPrintAllMtrrs (
+ VOID
+ )
+{
+ MtrrDebugPrintAllMtrrsWorker (NULL);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
new file mode 100644
index 00000000..f92b8d02
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.inf
@@ -0,0 +1,40 @@
+## @file
+# MTRR library provides APIs for MTRR operation.
+#
+# Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = MtrrLib
+ MODULE_UNI_FILE = MtrrLib.uni
+ FILE_GUID = 6826b408-f4f3-47ee-917f-af7047f9d937
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = MtrrLib
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MtrrLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ BaseLib
+ CpuLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.uni
new file mode 100644
index 00000000..646ec2a3
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/MtrrLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// MTRR library provides APIs for MTRR operation.
+//
+// MTRR library provides APIs for MTRR operation.
+//
+// Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "MTRR library provides APIs for MTRR operation"
+
+#string STR_MODULE_DESCRIPTION #language en-US "MTRR library provides APIs for MTRR operation."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c
new file mode 100644
index 00000000..d978a1a8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.c
@@ -0,0 +1,1163 @@
+/** @file
+ Unit tests of the MtrrLib instance of the MtrrLib class
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MtrrLibUnitTest.h"
+
+STATIC CONST MTRR_LIB_SYSTEM_PARAMETER mDefaultSystemParameter = {
+ 42, TRUE, TRUE, CacheUncacheable, 12
+};
+
+STATIC MTRR_LIB_SYSTEM_PARAMETER mSystemParameters[] = {
+ { 38, TRUE, TRUE, CacheUncacheable, 12 },
+ { 38, TRUE, TRUE, CacheWriteBack, 12 },
+ { 38, TRUE, TRUE, CacheWriteThrough, 12 },
+ { 38, TRUE, TRUE, CacheWriteProtected, 12 },
+ { 38, TRUE, TRUE, CacheWriteCombining, 12 },
+
+ { 42, TRUE, TRUE, CacheUncacheable, 12 },
+ { 42, TRUE, TRUE, CacheWriteBack, 12 },
+ { 42, TRUE, TRUE, CacheWriteThrough, 12 },
+ { 42, TRUE, TRUE, CacheWriteProtected, 12 },
+ { 42, TRUE, TRUE, CacheWriteCombining, 12 },
+
+ { 48, TRUE, TRUE, CacheUncacheable, 12 },
+ { 48, TRUE, TRUE, CacheWriteBack, 12 },
+ { 48, TRUE, TRUE, CacheWriteThrough, 12 },
+ { 48, TRUE, TRUE, CacheWriteProtected, 12 },
+ { 48, TRUE, TRUE, CacheWriteCombining, 12 },
+};
+
+UINT32 mFixedMtrrsIndex[] = {
+ MSR_IA32_MTRR_FIX64K_00000,
+ MSR_IA32_MTRR_FIX16K_80000,
+ MSR_IA32_MTRR_FIX16K_A0000,
+ MSR_IA32_MTRR_FIX4K_C0000,
+ MSR_IA32_MTRR_FIX4K_C8000,
+ MSR_IA32_MTRR_FIX4K_D0000,
+ MSR_IA32_MTRR_FIX4K_D8000,
+ MSR_IA32_MTRR_FIX4K_E0000,
+ MSR_IA32_MTRR_FIX4K_E8000,
+ MSR_IA32_MTRR_FIX4K_F0000,
+ MSR_IA32_MTRR_FIX4K_F8000
+};
+STATIC_ASSERT (
+ (ARRAY_SIZE (mFixedMtrrsIndex) == MTRR_NUMBER_OF_FIXED_MTRR),
+ "gFixedMtrrIndex does NOT contain all the fixed MTRRs!"
+ );
+
+//
+// Context structure to be used for most of the test cases.
+//
+typedef struct {
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;
+} MTRR_LIB_TEST_CONTEXT;
+
+//
+// Context structure to be used for GetFirmwareVariableMtrrCount() test.
+//
+typedef struct {
+ UINT32 NumberOfReservedVariableMtrrs;
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;
+} MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT;
+
+STATIC CHAR8 *mCacheDescription[] = { "UC", "WC", "N/A", "N/A", "WT", "WP", "WB" };
+
+/**
+ Compare the actual memory ranges against expected memory ranges and return PASS when they match.
+
+ @param ExpectedMemoryRanges Expected memory ranges.
+ @param ExpectedMemoryRangeCount Count of expected memory ranges.
+ @param ActualRanges Actual memory ranges.
+ @param ActualRangeCount Count of actual memory ranges.
+
+ @retval UNIT_TEST_PASSED Test passed.
+ @retval others Test failed.
+**/
+UNIT_TEST_STATUS
+VerifyMemoryRanges (
+ IN MTRR_MEMORY_RANGE *ExpectedMemoryRanges,
+ IN UINTN ExpectedMemoryRangeCount,
+ IN MTRR_MEMORY_RANGE *ActualRanges,
+ IN UINTN ActualRangeCount
+ )
+{
+ UINTN Index;
+ UT_ASSERT_EQUAL (ExpectedMemoryRangeCount, ActualRangeCount);
+ for (Index = 0; Index < ExpectedMemoryRangeCount; Index++) {
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].BaseAddress, ActualRanges[Index].BaseAddress);
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Length, ActualRanges[Index].Length);
+ UT_ASSERT_EQUAL (ExpectedMemoryRanges[Index].Type, ActualRanges[Index].Type);
+ }
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Dump the memory ranges.
+
+ @param Ranges Memory ranges to dump.
+ @param RangeCount Count of memory ranges.
+**/
+VOID
+DumpMemoryRanges (
+ MTRR_MEMORY_RANGE *Ranges,
+ UINTN RangeCount
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < RangeCount; Index++) {
+ UT_LOG_INFO ("\t{ 0x%016llx, 0x%016llx, %a },\n", Ranges[Index].BaseAddress, Ranges[Index].Length, mCacheDescription[Ranges[Index].Type]);
+ }
+}
+
+/**
+**/
+
+/**
+ Generate random count of MTRRs for each cache type.
+
+ @param TotalCount Total MTRR count.
+ @param UcCount Return count of Uncacheable type.
+ @param WtCount Return count of Write Through type.
+ @param WbCount Return count of Write Back type.
+ @param WpCount Return count of Write Protected type.
+ @param WcCount Return count of Write Combining type.
+**/
+VOID
+GenerateRandomMemoryTypeCombination (
+ IN UINT32 TotalCount,
+ OUT UINT32 *UcCount,
+ OUT UINT32 *WtCount,
+ OUT UINT32 *WbCount,
+ OUT UINT32 *WpCount,
+ OUT UINT32 *WcCount
+ )
+{
+ UINTN Index;
+ UINT32 TotalMtrrCount;
+ UINT32 *CountPerType[5];
+
+ CountPerType[0] = UcCount;
+ CountPerType[1] = WtCount;
+ CountPerType[2] = WbCount;
+ CountPerType[3] = WpCount;
+ CountPerType[4] = WcCount;
+
+ //
+ // Initialize the count of each cache type to 0.
+ //
+ for (Index = 0; Index < ARRAY_SIZE (CountPerType); Index++) {
+ *(CountPerType[Index]) = 0;
+ }
+
+ //
+ // Pick a random count of MTRRs
+ //
+ TotalMtrrCount = Random32 (1, TotalCount);
+ for (Index = 0; Index < TotalMtrrCount; Index++) {
+ //
+ // For each of them, pick a random cache type.
+ //
+ (*(CountPerType[Random32 (0, ARRAY_SIZE (CountPerType) - 1)]))++;
+ }
+}
+
+/**
+ Unit test of MtrrLib service MtrrSetMemoryAttribute()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrSetMemoryAttributesInMtrrSettings (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;
+ RETURN_STATUS Status;
+ UINT32 UcCount;
+ UINT32 WtCount;
+ UINT32 WbCount;
+ UINT32 WpCount;
+ UINT32 WcCount;
+
+ UINT32 MtrrIndex;
+ UINT8 *Scratch;
+ UINTN ScratchSize;
+ MTRR_SETTINGS LocalMtrrs;
+
+ MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];
+ UINT32 ExpectedVariableMtrrUsage;
+ UINTN ExpectedMemoryRangesCount;
+
+ MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];
+ UINT32 ActualVariableMtrrUsage;
+ UINTN ActualMemoryRangesCount;
+
+ MTRR_SETTINGS *Mtrrs[2];
+
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;
+ GenerateRandomMemoryTypeCombination (
+ SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs),
+ &UcCount, &WtCount, &WbCount, &WpCount, &WcCount
+ );
+ GenerateValidAndConfigurableMtrrPairs (
+ SystemParameter->PhysicalAddressBits, RawMtrrRange,
+ UcCount, WtCount, WbCount, WpCount, WcCount
+ );
+
+ ExpectedVariableMtrrUsage = UcCount + WtCount + WbCount + WpCount + WcCount;
+ ExpectedMemoryRangesCount = ARRAY_SIZE (ExpectedMemoryRanges);
+ GetEffectiveMemoryRanges (
+ SystemParameter->DefaultCacheType,
+ SystemParameter->PhysicalAddressBits,
+ RawMtrrRange, ExpectedVariableMtrrUsage,
+ ExpectedMemoryRanges, &ExpectedMemoryRangesCount
+ );
+
+ UT_LOG_INFO (
+ "Total MTRR [%d]: UC=%d, WT=%d, WB=%d, WP=%d, WC=%d\n",
+ ExpectedVariableMtrrUsage, UcCount, WtCount, WbCount, WpCount, WcCount
+ );
+ UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRangesCount);
+ DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount);
+
+ //
+ // Default cache type is always an INPUT
+ //
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ LocalMtrrs.MtrrDefType = MtrrGetDefaultMemoryType ();
+ ScratchSize = SCRATCH_BUFFER_SIZE;
+ Mtrrs[0] = &LocalMtrrs;
+ Mtrrs[1] = NULL;
+
+ for (MtrrIndex = 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) {
+ Scratch = calloc (ScratchSize, sizeof (UINT8));
+ Status = MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex], Scratch, &ScratchSize, ExpectedMemoryRanges, ExpectedMemoryRangesCount);
+ if (Status == RETURN_BUFFER_TOO_SMALL) {
+ Scratch = realloc (Scratch, ScratchSize);
+ Status = MtrrSetMemoryAttributesInMtrrSettings (Mtrrs[MtrrIndex], Scratch, &ScratchSize, ExpectedMemoryRanges, ExpectedMemoryRangesCount);
+ }
+ UT_ASSERT_STATUS_EQUAL (Status, RETURN_SUCCESS);
+
+ if (Mtrrs[MtrrIndex] == NULL) {
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ MtrrGetAllMtrrs (&LocalMtrrs);
+ }
+ ActualMemoryRangesCount = ARRAY_SIZE (ActualMemoryRanges);
+ CollectTestResult (
+ SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddressBits, SystemParameter->VariableMtrrCount,
+ &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &ActualVariableMtrrUsage
+ );
+
+ UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRangesCount);
+ DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount);
+ VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount, ActualMemoryRanges, ActualMemoryRangesCount);
+ UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >= ActualVariableMtrrUsage);
+
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ }
+
+ free (Scratch);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Test routine to check whether invalid base/size can be rejected.
+
+ @param Context Pointer to MTRR_LIB_SYSTEM_PARAMETER.
+
+ @return Test status.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestInvalidMemoryLayouts (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;
+ MTRR_MEMORY_RANGE Ranges[MTRR_NUMBER_OF_VARIABLE_MTRR * 2 + 1];
+ UINTN RangeCount;
+ UINT64 MaxAddress;
+ UINT32 Index;
+ UINT64 BaseAddress;
+ UINT64 Length;
+ RETURN_STATUS Status;
+ UINTN ScratchSize;
+
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;
+
+ RangeCount = Random32 (1, ARRAY_SIZE (Ranges));
+ MaxAddress = 1ull << SystemParameter->PhysicalAddressBits;
+
+ for (Index = 0; Index < RangeCount; Index++) {
+ do {
+ BaseAddress = Random64 (0, MaxAddress);
+ Length = Random64 (1, MaxAddress - BaseAddress);
+ } while (((BaseAddress & 0xFFF) == 0) || ((Length & 0xFFF) == 0));
+
+ Ranges[Index].BaseAddress = BaseAddress;
+ Ranges[Index].Length = Length;
+ Ranges[Index].Type = GenerateRandomCacheType ();
+
+ Status = MtrrSetMemoryAttribute (
+ Ranges[Index].BaseAddress, Ranges[Index].Length, Ranges[Index].Type
+ );
+ UT_ASSERT_TRUE (RETURN_ERROR (Status));
+ }
+
+ ScratchSize = 0;
+ Status = MtrrSetMemoryAttributesInMtrrSettings (NULL, NULL, &ScratchSize, Ranges, RangeCount);
+ UT_ASSERT_TRUE (RETURN_ERROR (Status));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service IsMtrrSupported()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestIsMtrrSupported (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ //
+ // MTRR capability off in CPUID leaf.
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_ASSERT_FALSE (IsMtrrSupported ());
+
+ //
+ // MTRR capability on in CPUID leaf, but no variable or fixed MTRRs.
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = 0;
+ SystemParameter.FixedMtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_ASSERT_FALSE (IsMtrrSupported ());
+
+ //
+ // MTRR capability on in CPUID leaf, but no variable MTRRs.
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = 0;
+ SystemParameter.FixedMtrrSupported = TRUE;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_ASSERT_FALSE (IsMtrrSupported ());
+
+ //
+ // MTRR capability on in CPUID leaf, but no fixed MTRRs.
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = 7;
+ SystemParameter.FixedMtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_ASSERT_FALSE (IsMtrrSupported ());
+
+ //
+ // MTRR capability on in CPUID leaf with both variable and fixed MTRRs.
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = 7;
+ SystemParameter.FixedMtrrSupported = TRUE;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_ASSERT_TRUE (IsMtrrSupported ());
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service GetVariableMtrrCount()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestGetVariableMtrrCount (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 Result;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ //
+ // If MTRR capability off in CPUID leaf, then the count is always 0.
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ for (SystemParameter.VariableMtrrCount = 1; SystemParameter.VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) {
+ InitializeMtrrRegs (&SystemParameter);
+ Result = GetVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, 0);
+ }
+
+ //
+ // Try all supported variable MTRR counts.
+ // If variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR, then an ASSERT()
+ // is generated.
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ for (SystemParameter.VariableMtrrCount = 1; SystemParameter.VariableMtrrCount <= MTRR_NUMBER_OF_VARIABLE_MTRR; SystemParameter.VariableMtrrCount++) {
+ InitializeMtrrRegs (&SystemParameter);
+ Result = GetVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount);
+ }
+
+ //
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR
+ //
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL);
+
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = MAX_UINT8;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_EXPECT_ASSERT_FAILURE (GetVariableMtrrCount (), NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service GetFirmwareVariableMtrrCount()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestGetFirmwareVariableMtrrCount (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ UINT32 Result;
+ UINT32 ReservedMtrrs;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+
+ InitializeMtrrRegs (&SystemParameter);
+ //
+ // Positive test cases for VCNT = 10 and Reserved PCD in range 0..10
+ //
+ for (ReservedMtrrs = 0; ReservedMtrrs <= SystemParameter.VariableMtrrCount; ReservedMtrrs++) {
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs);
+ Result = GetFirmwareVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount - ReservedMtrrs);
+ }
+
+ //
+ // Negative test cases when Reserved PCD is larger than VCNT
+ //
+ for (ReservedMtrrs = SystemParameter.VariableMtrrCount + 1; ReservedMtrrs <= 255; ReservedMtrrs++) {
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, ReservedMtrrs);
+ Result = GetFirmwareVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, 0);
+ }
+
+ //
+ // Negative test cases when Reserved PCD is larger than VCNT
+ //
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, MAX_UINT32);
+ Result = GetFirmwareVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, 0);
+
+ //
+ // Negative test case when MTRRs are not supported
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2);
+ Result = GetFirmwareVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, 0);
+
+ //
+ // Negative test case when Fixed MTRRs are not supported
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.FixedMtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, 2);
+ Result = GetFirmwareVariableMtrrCount ();
+ UT_ASSERT_EQUAL (Result, 0);
+
+ //
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR
+ //
+ SystemParameter.FixedMtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_EXPECT_ASSERT_FAILURE (GetFirmwareVariableMtrrCount (), NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrGetMemoryAttribute()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrGetMemoryAttribute (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrGetFixedMtrr()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrGetFixedMtrr (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_FIXED_SETTINGS *Result;
+ MTRR_FIXED_SETTINGS ExpectedFixedSettings;
+ MTRR_FIXED_SETTINGS FixedSettings;
+ UINTN Index;
+ UINTN MsrIndex;
+ UINTN ByteIndex;
+ UINT64 MsrValue;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ InitializeMtrrRegs (&SystemParameter);
+ //
+ // Set random cache type to different ranges under 1MB and make sure
+ // the fixed MTRR settings are expected.
+ // Try 100 times.
+ //
+ for (Index = 0; Index < 100; Index++) {
+ for (MsrIndex = 0; MsrIndex < ARRAY_SIZE (mFixedMtrrsIndex); MsrIndex++) {
+ MsrValue = 0;
+ for (ByteIndex = 0; ByteIndex < sizeof (UINT64); ByteIndex++) {
+ MsrValue = MsrValue | LShiftU64 (GenerateRandomCacheType (), ByteIndex * 8);
+ }
+ ExpectedFixedSettings.Mtrr[MsrIndex] = MsrValue;
+ AsmWriteMsr64 (mFixedMtrrsIndex[MsrIndex], MsrValue);
+ }
+
+ Result = MtrrGetFixedMtrr (&FixedSettings);
+ UT_ASSERT_EQUAL (Result, &FixedSettings);
+ UT_ASSERT_MEM_EQUAL (&FixedSettings, &ExpectedFixedSettings, sizeof (FixedSettings));
+ }
+
+ //
+ // Negative test case when MTRRs are not supported
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+
+ ZeroMem (&FixedSettings, sizeof (FixedSettings));
+ ZeroMem (&ExpectedFixedSettings, sizeof (ExpectedFixedSettings));
+ Result = MtrrGetFixedMtrr (&FixedSettings);
+ UT_ASSERT_EQUAL (Result, &FixedSettings);
+ UT_ASSERT_MEM_EQUAL (&ExpectedFixedSettings, &FixedSettings, sizeof (ExpectedFixedSettings));
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrGetAllMtrrs()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrGetAllMtrrs (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_SETTINGS *Result;
+ MTRR_SETTINGS Mtrrs;
+ MTRR_SETTINGS ExpectedMtrrs;
+ MTRR_VARIABLE_SETTING VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ UINT32 Index;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ InitializeMtrrRegs (&SystemParameter);
+
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &VariableMtrr[Index], NULL);
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableMtrr[Index].Base);
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableMtrr[Index].Mask);
+ }
+ Result = MtrrGetAllMtrrs (&Mtrrs);
+ UT_ASSERT_EQUAL (Result, &Mtrrs);
+ UT_ASSERT_MEM_EQUAL (Mtrrs.Variables.Mtrr, VariableMtrr, sizeof (MTRR_VARIABLE_SETTING) * SystemParameter.VariableMtrrCount);
+
+ //
+ // Negative test case when MTRRs are not supported
+ //
+ ZeroMem (&ExpectedMtrrs, sizeof (ExpectedMtrrs));
+ ZeroMem (&Mtrrs, sizeof (Mtrrs));
+
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetAllMtrrs (&Mtrrs);
+ UT_ASSERT_EQUAL (Result, &Mtrrs);
+ UT_ASSERT_MEM_EQUAL (&ExpectedMtrrs, &Mtrrs, sizeof (ExpectedMtrrs));
+
+ //
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_EXPECT_ASSERT_FAILURE (MtrrGetAllMtrrs (&Mtrrs), NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrSetAllMtrrs()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrSetAllMtrrs (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_SETTINGS *Result;
+ MTRR_SETTINGS Mtrrs;
+ UINT32 Index;
+ MSR_IA32_MTRR_DEF_TYPE_REGISTER Default;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ InitializeMtrrRegs (&SystemParameter);
+
+ Default.Uint64 = 0;
+ Default.Bits.E = 1;
+ Default.Bits.FE = 1;
+ Default.Bits.Type = GenerateRandomCacheType ();
+
+ ZeroMem (&Mtrrs, sizeof (Mtrrs));
+ Mtrrs.MtrrDefType = Default.Uint64;
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &Mtrrs.Variables.Mtrr[Index], NULL);
+ }
+ Result = MtrrSetAllMtrrs (&Mtrrs);
+ UT_ASSERT_EQUAL (Result, &Mtrrs);
+
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_DEF_TYPE), Mtrrs.MtrrDefType);
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1)), Mtrrs.Variables.Mtrr[Index].Base);
+ UT_ASSERT_EQUAL (AsmReadMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1)), Mtrrs.Variables.Mtrr[Index].Mask);
+ }
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrGetMemoryAttributeInVariableMtrr()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrGetMemoryAttributeInVariableMtrr (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ UINT32 Result;
+ MTRR_VARIABLE_SETTING VariableSetting[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ VARIABLE_MTRR VariableMtrr[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ UINT64 ValidMtrrBitsMask;
+ UINT64 ValidMtrrAddressMask;
+ UINT32 Index;
+ MSR_IA32_MTRR_PHYSBASE_REGISTER Base;
+ MSR_IA32_MTRR_PHYSMASK_REGISTER Mask;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+
+ InitializeMtrrRegs (&SystemParameter);
+
+ ValidMtrrBitsMask = (1ull << SystemParameter.PhysicalAddressBits) - 1;
+ ValidMtrrAddressMask = ValidMtrrBitsMask & 0xfffffffffffff000ULL;
+
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {
+ GenerateRandomMtrrPair (SystemParameter.PhysicalAddressBits, GenerateRandomCacheType (), &VariableSetting[Index], NULL);
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSBASE0 + (Index << 1), VariableSetting[Index].Base);
+ AsmWriteMsr64 (MSR_IA32_MTRR_PHYSMASK0 + (Index << 1), VariableSetting[Index].Mask);
+ }
+ Result = MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr);
+ UT_ASSERT_EQUAL (Result, SystemParameter.VariableMtrrCount);
+
+ for (Index = 0; Index < SystemParameter.VariableMtrrCount; Index++) {
+ Base.Uint64 = VariableMtrr[Index].BaseAddress;
+ Base.Bits.Type = (UINT32) VariableMtrr[Index].Type;
+ UT_ASSERT_EQUAL (Base.Uint64, VariableSetting[Index].Base);
+
+ Mask.Uint64 = ~(VariableMtrr[Index].Length - 1) & ValidMtrrBitsMask;
+ Mask.Bits.V = 1;
+ UT_ASSERT_EQUAL (Mask.Uint64, VariableSetting[Index].Mask);
+ }
+
+ //
+ // Negative test case when MTRRs are not supported
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr);
+ UT_ASSERT_EQUAL (Result, 0);
+
+ //
+ // Expect ASSERT() if variable MTRR count is > MTRR_NUMBER_OF_VARIABLE_MTRR
+ //
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = MTRR_NUMBER_OF_VARIABLE_MTRR + 1;
+ InitializeMtrrRegs (&SystemParameter);
+ UT_EXPECT_ASSERT_FAILURE (MtrrGetMemoryAttributeInVariableMtrr (ValidMtrrBitsMask, ValidMtrrAddressMask, VariableMtrr), NULL);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrDebugPrintAllMtrrs()
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrDebugPrintAllMtrrs (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrGetDefaultMemoryType().
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrGetDefaultMemoryType (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_LIB_TEST_CONTEXT *LocalContext;
+ UINTN Index;
+ MTRR_MEMORY_CACHE_TYPE Result;
+ MTRR_LIB_SYSTEM_PARAMETER SystemParameter;
+ MTRR_MEMORY_CACHE_TYPE CacheType[5];
+
+ CacheType[0] = CacheUncacheable;
+ CacheType[1] = CacheWriteCombining;
+ CacheType[2] = CacheWriteThrough;
+ CacheType[3] = CacheWriteProtected;
+ CacheType[4] = CacheWriteBack;
+
+ LocalContext = (MTRR_LIB_TEST_CONTEXT *) Context;
+
+ CopyMem (&SystemParameter, LocalContext->SystemParameter, sizeof (SystemParameter));
+ //
+ // If MTRRs are supported, then always return the cache type in the MSR
+ // MSR_IA32_MTRR_DEF_TYPE
+ //
+ for (Index = 0; Index < ARRAY_SIZE (CacheType); Index++) {
+ SystemParameter.DefaultCacheType = CacheType[Index];
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetDefaultMemoryType ();
+ UT_ASSERT_EQUAL (Result, SystemParameter.DefaultCacheType);
+ }
+
+ //
+ // If MTRRs are not supported, then always return CacheUncacheable
+ //
+ SystemParameter.MtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetDefaultMemoryType ();
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);
+
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.FixedMtrrSupported = FALSE;
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetDefaultMemoryType ();
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);
+
+ SystemParameter.MtrrSupported = TRUE;
+ SystemParameter.FixedMtrrSupported = TRUE;
+ SystemParameter.VariableMtrrCount = 0;
+ InitializeMtrrRegs (&SystemParameter);
+ Result = MtrrGetDefaultMemoryType ();
+ UT_ASSERT_EQUAL (Result, CacheUncacheable);
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Unit test of MtrrLib service MtrrSetMemoryAttributeInMtrrSettings().
+
+ @param[in] Context Ignored
+
+ @retval UNIT_TEST_PASSED The Unit test has completed and the test
+ case was successful.
+ @retval UNIT_TEST_ERROR_TEST_FAILED A test case assertion has failed.
+
+**/
+UNIT_TEST_STATUS
+EFIAPI
+UnitTestMtrrSetMemoryAttributeInMtrrSettings (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ CONST MTRR_LIB_SYSTEM_PARAMETER *SystemParameter;
+ RETURN_STATUS Status;
+ UINT32 UcCount;
+ UINT32 WtCount;
+ UINT32 WbCount;
+ UINT32 WpCount;
+ UINT32 WcCount;
+
+ UINTN MtrrIndex;
+ UINTN Index;
+ MTRR_SETTINGS LocalMtrrs;
+
+ MTRR_MEMORY_RANGE RawMtrrRange[MTRR_NUMBER_OF_VARIABLE_MTRR];
+ MTRR_MEMORY_RANGE ExpectedMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];
+ UINT32 ExpectedVariableMtrrUsage;
+ UINTN ExpectedMemoryRangesCount;
+
+ MTRR_MEMORY_RANGE ActualMemoryRanges[MTRR_NUMBER_OF_FIXED_MTRR * sizeof (UINT64) + 2 * MTRR_NUMBER_OF_VARIABLE_MTRR + 1];
+ UINT32 ActualVariableMtrrUsage;
+ UINTN ActualMemoryRangesCount;
+
+ MTRR_SETTINGS *Mtrrs[2];
+
+ SystemParameter = (MTRR_LIB_SYSTEM_PARAMETER *) Context;
+ GenerateRandomMemoryTypeCombination (
+ SystemParameter->VariableMtrrCount - PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs),
+ &UcCount, &WtCount, &WbCount, &WpCount, &WcCount
+ );
+ GenerateValidAndConfigurableMtrrPairs (
+ SystemParameter->PhysicalAddressBits, RawMtrrRange,
+ UcCount, WtCount, WbCount, WpCount, WcCount
+ );
+
+ ExpectedVariableMtrrUsage = UcCount + WtCount + WbCount + WpCount + WcCount;
+ ExpectedMemoryRangesCount = ARRAY_SIZE (ExpectedMemoryRanges);
+ GetEffectiveMemoryRanges (
+ SystemParameter->DefaultCacheType,
+ SystemParameter->PhysicalAddressBits,
+ RawMtrrRange, ExpectedVariableMtrrUsage,
+ ExpectedMemoryRanges, &ExpectedMemoryRangesCount
+ );
+
+ UT_LOG_INFO ("--- Expected Memory Ranges [%d] ---\n", ExpectedMemoryRangesCount);
+ DumpMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount);
+ //
+ // Default cache type is always an INPUT
+ //
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ LocalMtrrs.MtrrDefType = MtrrGetDefaultMemoryType ();
+ Mtrrs[0] = &LocalMtrrs;
+ Mtrrs[1] = NULL;
+
+ for (MtrrIndex = 0; MtrrIndex < ARRAY_SIZE (Mtrrs); MtrrIndex++) {
+ for (Index = 0; Index < ExpectedMemoryRangesCount; Index++) {
+ Status = MtrrSetMemoryAttributeInMtrrSettings (
+ Mtrrs[MtrrIndex],
+ ExpectedMemoryRanges[Index].BaseAddress,
+ ExpectedMemoryRanges[Index].Length,
+ ExpectedMemoryRanges[Index].Type
+ );
+ UT_ASSERT_TRUE (Status == RETURN_SUCCESS || Status == RETURN_OUT_OF_RESOURCES || Status == RETURN_BUFFER_TOO_SMALL);
+ if (Status == RETURN_OUT_OF_RESOURCES || Status == RETURN_BUFFER_TOO_SMALL) {
+ return UNIT_TEST_SKIPPED;
+ }
+ }
+
+ if (Mtrrs[MtrrIndex] == NULL) {
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ MtrrGetAllMtrrs (&LocalMtrrs);
+ }
+ ActualMemoryRangesCount = ARRAY_SIZE (ActualMemoryRanges);
+ CollectTestResult (
+ SystemParameter->DefaultCacheType, SystemParameter->PhysicalAddressBits, SystemParameter->VariableMtrrCount,
+ &LocalMtrrs, ActualMemoryRanges, &ActualMemoryRangesCount, &ActualVariableMtrrUsage
+ );
+ UT_LOG_INFO ("--- Actual Memory Ranges [%d] ---\n", ActualMemoryRangesCount);
+ DumpMemoryRanges (ActualMemoryRanges, ActualMemoryRangesCount);
+ VerifyMemoryRanges (ExpectedMemoryRanges, ExpectedMemoryRangesCount, ActualMemoryRanges, ActualMemoryRangesCount);
+ UT_ASSERT_TRUE (ExpectedVariableMtrrUsage >= ActualVariableMtrrUsage);
+
+ ZeroMem (&LocalMtrrs, sizeof (LocalMtrrs));
+ }
+
+ return UNIT_TEST_PASSED;
+}
+
+
+/**
+ Prep routine for UnitTestGetFirmwareVariableMtrrCount().
+
+ @param Context Point to a UINT32 data to save the PcdCpuNumberOfReservedVariableMtrrs.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+SavePcdValue (
+ UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;
+ LocalContext->NumberOfReservedVariableMtrrs = PatchPcdGet32 (PcdCpuNumberOfReservedVariableMtrrs);
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Clean up routine for UnitTestGetFirmwareVariableMtrrCount().
+
+ @param Context Point to a UINT32 data to save the PcdCpuNumberOfReservedVariableMtrrs.
+**/
+VOID
+EFIAPI
+RestorePcdValue (
+ UNIT_TEST_CONTEXT Context
+ )
+{
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *LocalContext;
+
+ LocalContext = (MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT *) Context;
+ PatchPcdSet32 (PcdCpuNumberOfReservedVariableMtrrs, LocalContext->NumberOfReservedVariableMtrrs);
+}
+
+/**
+ Initialize the unit test framework, suite, and unit tests for the
+ ResetSystemLib and run the ResetSystemLib unit test.
+
+ @param Iteration Iteration of testing MtrrSetMemoryAttributeInMtrrSettings
+ and MtrrSetMemoryAttributesInMtrrSettings using random inputs.
+
+ @retval EFI_SUCCESS All test cases were dispatched.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to
+ initialize the unit tests.
+**/
+STATIC
+EFI_STATUS
+EFIAPI
+UnitTestingEntry (
+ UINTN Iteration
+ )
+{
+ EFI_STATUS Status;
+ UNIT_TEST_FRAMEWORK_HANDLE Framework;
+ UNIT_TEST_SUITE_HANDLE MtrrApiTests;
+ UINTN Index;
+ UINTN SystemIndex;
+ MTRR_LIB_TEST_CONTEXT Context;
+ MTRR_LIB_GET_FIRMWARE_VARIABLE_MTRR_COUNT_CONTEXT GetFirmwareVariableMtrrCountContext;
+
+ Context.SystemParameter = &mDefaultSystemParameter;
+ GetFirmwareVariableMtrrCountContext.SystemParameter = &mDefaultSystemParameter;
+ Framework = NULL;
+
+ //
+ // Setup the test framework for running the tests.
+ //
+ Status = InitUnitTestFramework (&Framework, UNIT_TEST_APP_NAME, gEfiCallerBaseName, UNIT_TEST_APP_VERSION);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in InitUnitTestFramework. Status = %r\n", Status));
+ goto EXIT;
+ }
+
+ //
+ // --------------Suite-----------Description--------------Name----------Function--------Pre---Post-------------------Context-----------
+ //
+
+ //
+ // Populate the MtrrLib API Unit Test Suite.
+ //
+ Status = CreateUnitTestSuite (&MtrrApiTests, Framework, "MtrrLib API Tests", "MtrrLib.MtrrLib", NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed in CreateUnitTestSuite for MtrrLib API Tests\n"));
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+ AddTestCase (MtrrApiTests, "Test IsMtrrSupported", "MtrrSupported", UnitTestIsMtrrSupported, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test GetVariableMtrrCount", "GetVariableMtrrCount", UnitTestGetVariableMtrrCount, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test GetFirmwareVariableMtrrCount", "GetFirmwareVariableMtrrCount", UnitTestGetFirmwareVariableMtrrCount, SavePcdValue, RestorePcdValue, &GetFirmwareVariableMtrrCountContext);
+ AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttribute", "MtrrGetMemoryAttribute", UnitTestMtrrGetMemoryAttribute, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrGetFixedMtrr", "MtrrGetFixedMtrr", UnitTestMtrrGetFixedMtrr, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrGetAllMtrrs", "MtrrGetAllMtrrs", UnitTestMtrrGetAllMtrrs, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrSetAllMtrrs", "MtrrSetAllMtrrs", UnitTestMtrrSetAllMtrrs, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrGetMemoryAttributeInVariableMtrr", "MtrrGetMemoryAttributeInVariableMtrr", UnitTestMtrrGetMemoryAttributeInVariableMtrr, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrDebugPrintAllMtrrs", "MtrrDebugPrintAllMtrrs", UnitTestMtrrDebugPrintAllMtrrs, NULL, NULL, &Context);
+ AddTestCase (MtrrApiTests, "Test MtrrGetDefaultMemoryType", "MtrrGetDefaultMemoryType", UnitTestMtrrGetDefaultMemoryType, NULL, NULL, &Context);
+
+ for (SystemIndex = 0; SystemIndex < ARRAY_SIZE (mSystemParameters); SystemIndex++) {
+ for (Index = 0; Index < Iteration; Index++) {
+ AddTestCase (MtrrApiTests, "Test InvalidMemoryLayouts", "InvalidMemoryLayouts", UnitTestInvalidMemoryLayouts, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);
+ AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributeInMtrrSettings", "MtrrSetMemoryAttributeInMtrrSettings", UnitTestMtrrSetMemoryAttributeInMtrrSettings, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);
+ AddTestCase (MtrrApiTests, "Test MtrrSetMemoryAttributesInMtrrSettings", "MtrrSetMemoryAttributesInMtrrSettings", UnitTestMtrrSetMemoryAttributesInMtrrSettings, InitializeSystem, NULL, &mSystemParameters[SystemIndex]);
+ }
+ }
+ //
+ // Execute the tests.
+ //
+ Status = RunAllTestSuites (Framework);
+
+EXIT:
+ if (Framework != NULL) {
+ FreeUnitTestFramework (Framework);
+ }
+
+ return Status;
+}
+
+/**
+ Standard POSIX C entry point for host based unit test execution.
+
+ @param Argc Number of arguments.
+ @param Argv Array of arguments.
+
+ @return Test application exit code.
+**/
+INT32
+main (
+ INT32 Argc,
+ CHAR8 *Argv[]
+ )
+{
+ UINTN Count;
+
+ DEBUG ((DEBUG_INFO, "%a v%a\n", UNIT_TEST_APP_NAME, UNIT_TEST_APP_VERSION));
+ srand ((unsigned int) time (NULL));
+
+ //
+ // MtrrLibUnitTest generate-random-numbers <path to MtrrLib/UnitTest/RandomNumber.c> <random-number count>
+ //
+ if ((Argc == 4) && (AsciiStriCmp ("generate-random-numbers", Argv[1]) == 0)) {
+ Count = atoi (Argv[3]);
+ DEBUG ((DEBUG_INFO, "Generate %d random numbers to %a.\n", Count, Argv[2]));
+ GenerateRandomNumbers (Argv[2], Count);
+ return 0;
+ }
+
+ //
+ // MtrrLibUnitTest [<iterations>]
+ // <iterations> [fixed|random]
+ // Default <iterations> is 10.
+ // Default uses fixed inputs.
+ //
+ Count = 10;
+ mRandomInput = FALSE;
+ if ((Argc == 2) || (Argc == 3)) {
+ Count = atoi (Argv[1]);
+ if (Argc == 3) {
+ if (AsciiStriCmp ("fixed", Argv[2]) == 0) {
+ mRandomInput = FALSE;
+ } else if (AsciiStriCmp ("random", Argv[2]) == 0) {
+ mRandomInput = TRUE;
+ }
+ }
+ }
+
+ DEBUG ((DEBUG_INFO, "Iterations = %d\n", Count));
+ DEBUG ((DEBUG_INFO, "Input = %a\n", mRandomInput ? "random" : "fixed"));
+
+ return UnitTestingEntry (Count);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h
new file mode 100644
index 00000000..ffde1681
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTest.h
@@ -0,0 +1,195 @@
+/** @file
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _MTRR_SUPPORT_H_
+#define _MTRR_SUPPORT_H_
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stddef.h>
+#include <setjmp.h>
+#include <cmocka.h>
+#include <time.h>
+
+#include <Uefi.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UnitTestLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/UnitTestHostBaseLib.h>
+
+#include <Register/ArchitecturalMsr.h>
+#include <Register/Cpuid.h>
+#include <Register/Msr.h>
+
+#define UNIT_TEST_APP_NAME "MtrrLib Unit Tests"
+#define UNIT_TEST_APP_VERSION "1.0"
+
+#define SCRATCH_BUFFER_SIZE SIZE_16KB
+
+typedef struct {
+ UINT8 PhysicalAddressBits;
+ BOOLEAN MtrrSupported;
+ BOOLEAN FixedMtrrSupported;
+ MTRR_MEMORY_CACHE_TYPE DefaultCacheType;
+ UINT32 VariableMtrrCount;
+} MTRR_LIB_SYSTEM_PARAMETER;
+
+extern UINT32 mFixedMtrrsIndex[];
+extern BOOLEAN mRandomInput;
+
+/**
+ Initialize the MTRR registers.
+
+ @param SystemParameter System parameter that controls the MTRR registers initialization.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+InitializeMtrrRegs (
+ IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter
+ );
+
+/**
+ Initialize the MTRR registers.
+
+ @param Context System parameter that controls the MTRR registers initialization.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+InitializeSystem (
+ IN UNIT_TEST_CONTEXT Context
+ );
+
+/**
+ Return a random memory cache type.
+**/
+MTRR_MEMORY_CACHE_TYPE
+GenerateRandomCacheType (
+ VOID
+ );
+
+/**
+ Generate random MTRRs.
+
+ @param PhysicalAddressBits Physical address bits.
+ @param RawMemoryRanges Return the randomly generated MTRRs.
+ @param UcCount Count of Uncacheable MTRRs.
+ @param WtCount Count of Write Through MTRRs.
+ @param WbCount Count of Write Back MTRRs.
+ @param WpCount Count of Write Protected MTRRs.
+ @param WcCount Count of Write Combining MTRRs.
+**/
+VOID
+GenerateValidAndConfigurableMtrrPairs (
+ IN UINT32 PhysicalAddressBits,
+ IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 UcCount,
+ IN UINT32 WtCount,
+ IN UINT32 WbCount,
+ IN UINT32 WpCount,
+ IN UINT32 WcCount
+ );
+
+/**
+ Convert the MTRR BASE/MASK array to memory ranges.
+
+ @param DefaultType Default memory type.
+ @param PhysicalAddressBits Physical address bits.
+ @param RawMemoryRanges Raw memory ranges.
+ @param RawMemoryRangeCount Count of raw memory ranges.
+ @param MemoryRanges Memory ranges.
+ @param MemoryRangeCount Count of memory ranges.
+**/
+VOID
+GetEffectiveMemoryRanges (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT32 PhysicalAddressBits,
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 RawMemoryRangeCount,
+ OUT MTRR_MEMORY_RANGE *MemoryRanges,
+ OUT UINTN *MemoryRangeCount
+ );
+
+/**
+ Generate random MTRR BASE/MASK for a specified type.
+
+ @param PhysicalAddressBits Physical address bits.
+ @param CacheType Cache type.
+ @param MtrrPair Return the random MTRR.
+ @param MtrrMemoryRange Return the random memory range.
+**/
+VOID
+GenerateRandomMtrrPair (
+ IN UINT32 PhysicalAddressBits,
+ IN MTRR_MEMORY_CACHE_TYPE CacheType,
+ OUT MTRR_VARIABLE_SETTING *MtrrPair, OPTIONAL
+ OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL
+ );
+
+/**
+ Collect the test result.
+
+ @param DefaultType Default memory type.
+ @param PhysicalAddressBits Physical address bits.
+ @param VariableMtrrCount Count of variable MTRRs.
+ @param Mtrrs MTRR settings to collect from.
+ @param Ranges Return the memory ranges.
+ @param RangeCount Return the count of memory ranges.
+ @param MtrrCount Return the count of variable MTRRs being used.
+**/
+VOID
+CollectTestResult (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT32 PhysicalAddressBits,
+ IN UINT32 VariableMtrrCount,
+ IN MTRR_SETTINGS *Mtrrs,
+ OUT MTRR_MEMORY_RANGE *Ranges,
+ IN OUT UINTN *RangeCount,
+ OUT UINT32 *MtrrCount
+ );
+
+/**
+ Return a 64bit random number.
+
+ @param Start Start of the random number range.
+ @param Limit Limit of the random number range.
+ @return 64bit random number
+**/
+UINT64
+Random64 (
+ UINT64 Start,
+ UINT64 Limit
+ );
+
+/**
+ Return a 32bit random number.
+
+ @param Start Start of the random number range.
+ @param Limit Limit of the random number range.
+ @return 32bit random number
+**/
+UINT32
+Random32 (
+ UINT32 Start,
+ UINT32 Limit
+ );
+
+/**
+ Generate Count random numbers in FilePath.
+
+ @param FilePath The file path to put the generated random numbers.
+ @param Count Count of random numbers.
+**/
+VOID
+GenerateRandomNumbers (
+ CHAR8 *FilePath,
+ UINTN Count
+ );
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf
new file mode 100644
index 00000000..c3ee21eb
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/MtrrLibUnitTestHost.inf
@@ -0,0 +1,43 @@
+## @file
+# Unit tests of the MtrrLib instance of the MtrrLib class
+#
+# Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+##
+
+[Defines]
+ INF_VERSION = 0x00010006
+ BASE_NAME = MtrrLibUnitTestHost
+ FILE_GUID = A1542D84-B64D-4847-885E-0509084376AB
+ MODULE_TYPE = HOST_APPLICATION
+ VERSION_STRING = 1.0
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ MtrrLibUnitTest.c
+ MtrrLibUnitTest.h
+ Support.c
+ RandomNumber.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+ UnitTestFrameworkPkg/UnitTestFrameworkPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ DebugLib
+ MtrrLib
+ UnitTestLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuNumberOfReservedVariableMtrrs ## SOMETIMES_CONSUMES
+
+[BuildOptions]
+ MSFT:*_*_*_CC_FLAGS = -D _CRT_SECURE_NO_WARNINGS
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/RandomNumber.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/RandomNumber.c
new file mode 100644
index 00000000..e75859f7
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/RandomNumber.c
@@ -0,0 +1,5009 @@
+/** @file
+ Pre-generated random number used by MtrrLib test.
+
+ Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+**/
+UINTN mNumberCount = 50000;
+UINTN mNumbers[] = {
+ 7791, 9427, 6867, 23807, 10984, 16661, 1863, 16690, 14810, 14550,
+ 11382, 15755, 19806, 32737, 209, 14661, 4112, 13680, 2425, 15502,
+ 25268, 2882, 29953, 12346, 27936, 8942, 21365, 17849, 13910, 21879,
+ 3995, 6982, 2032, 6432, 3448, 28770, 8385, 31106, 4630, 32385,
+ 31417, 21979, 22661, 18947, 10249, 22953, 30752, 32613, 2952, 25464,
+ 17, 12473, 28757, 19960, 27672, 1875, 17598, 20306, 22152, 15814,
+ 31841, 25276, 2962, 30223, 23953, 28748, 25029, 16399, 15868, 9993,
+ 31702, 25663, 29322, 15688, 22429, 18079, 30344, 2870, 20065, 30191,
+ 3589, 13233, 27221, 15138, 26492, 20316, 13666, 15632, 180, 19954,
+ 25895, 3179, 21221, 474, 2111, 11252, 2588, 2556, 6338, 26862,
+ 19424, 3540, 6158, 6099, 20758, 32708, 6087, 2375, 22306, 22959,
+ 21532, 19274, 11343, 1987, 17228, 2737, 23409, 30102, 15977, 10455,
+ 15049, 29045, 10077, 22928, 25128, 23033, 12330, 23902, 19543, 18906,
+ 10102, 11240, 10167, 13832, 28230, 8871, 6693, 12792, 31498, 3043,
+ 31776, 20028, 3546, 4574, 20270, 17751, 31231, 29263, 29563, 27343,
+ 10421, 1553, 24772, 4228, 14639, 28957, 26227, 22079, 25052, 3766,
+ 14092, 6030, 30441, 28131, 17095, 27600, 14855, 29218, 9599, 27788,
+ 22382, 27739, 11210, 13831, 13345, 16403, 13162, 22037, 29044, 26850,
+ 27364, 7471, 18892, 29735, 13422, 1478, 10919, 17146, 12302, 9687,
+ 12252, 10338, 12545, 24256, 25635, 14280, 8794, 16210, 27351, 22444,
+ 7915, 19495, 30459, 27799, 16488, 8757, 13180, 12369, 27082, 10148,
+ 181, 2387, 4338, 16093, 11064, 30335, 19343, 12260, 32716, 25359,
+ 9025, 15335, 24754, 30412, 29951, 3863, 16429, 13952, 24502, 1206,
+ 9281, 2221, 1586, 29041, 6074, 29311, 10306, 26609, 11376, 8448,
+ 22295, 11181, 29386, 4747, 18670, 17922, 2689, 29827, 4079, 29061,
+ 12454, 2372, 14420, 20376, 28391, 10842, 4557, 7227, 20494, 15090,
+ 10275, 21541, 15818, 7821, 12060, 276, 27570, 2044, 26016, 8289,
+ 29575, 13448, 13337, 22487, 1721, 26481, 2592, 27845, 22829, 14746,
+ 16213, 12626, 10558, 4482, 31630, 23569, 2306, 22390, 27189, 32213,
+ 19662, 14853, 15595, 2503, 17148, 5813, 16753, 9141, 6379, 23284,
+ 3785, 10413, 4424, 29009, 3480, 9675, 28556, 3820, 24527, 12623,
+ 15558, 29995, 27530, 23026, 18843, 31663, 3385, 8315, 4491, 30343,
+ 13565, 12173, 25462, 19619, 29525, 17859, 29534, 21131, 14585, 1535,
+ 14702, 15697, 19974, 8702, 16955, 16835, 17500, 4912, 21579, 13286,
+ 26948, 21959, 3796, 15008, 31319, 23054, 26053, 27573, 8603, 8189,
+ 7946, 25589, 31982, 12554, 13580, 12211, 13480, 27713, 17016, 6008,
+ 25980, 22679, 23362, 9465, 24991, 29052, 30441, 29767, 3372, 8623,
+ 20476, 9542, 22984, 24662, 23773, 352, 9602, 9294, 17861, 10618,
+ 252, 8640, 31752, 24615, 8400, 1525, 22171, 17436, 32301, 9579,
+ 22483, 3813, 27329, 20520, 111, 11222, 7132, 16462, 21465, 15171,
+ 28882, 22256, 29097, 22004, 30881, 6948, 26731, 9427, 31443, 12121,
+ 9634, 8424, 1958, 12523, 9997, 3975, 21355, 13813, 20776, 3784,
+ 24876, 23911, 3830, 17976, 16529, 9560, 7934, 4046, 25348, 31645,
+ 12691, 11553, 19476, 15514, 15449, 23767, 8471, 5208, 9989, 25697,
+ 23572, 30168, 13668, 25062, 9696, 7335, 21151, 31356, 7046, 19635,
+ 8637, 14494, 748, 17501, 30569, 11995, 12980, 5327, 8438, 13003,
+ 12641, 21648, 7328, 17479, 20411, 24661, 10005, 29913, 17012, 7707,
+ 16948, 25458, 32523, 30322, 6420, 8283, 24561, 30748, 25928, 3438,
+ 21483, 22998, 14689, 3718, 7351, 20086, 21685, 7732, 24818, 24374,
+ 25695, 6836, 5433, 16464, 21895, 24351, 143, 21451, 7396, 31969,
+ 24574, 20116, 6014, 10606, 28033, 13264, 26809, 13361, 20002, 6769,
+ 31119, 6341, 11104, 28935, 32029, 360, 31699, 13273, 7777, 19885,
+ 16147, 18741, 15170, 29041, 12501, 30724, 20688, 16399, 14167, 11425,
+ 31950, 30680, 4351, 32748, 14446, 8637, 1343, 13466, 12379, 6479,
+ 7355, 7887, 24060, 20714, 9390, 10734, 17912, 9772, 393, 28848,
+ 32757, 23212, 5342, 7027, 27558, 1257, 14973, 30933, 14084, 3457,
+ 8413, 1154, 6619, 3236, 189, 20554, 27273, 7111, 30730, 887,
+ 28674, 28573, 3076, 25693, 5400, 20035, 5789, 8242, 24826, 13755,
+ 8993, 17696, 22778, 18075, 32284, 8857, 12179, 18182, 31865, 1003,
+ 25770, 20956, 15847, 30996, 15124, 1582, 28289, 8663, 10073, 19189,
+ 19373, 12047, 7095, 31491, 28740, 3652, 21866, 3385, 11252, 29564,
+ 3883, 3323, 27107, 13651, 15607, 30433, 27285, 12110, 13585, 19887,
+ 21776, 7789, 27210, 31624, 25406, 11263, 7040, 21342, 11666, 6842,
+ 7269, 18093, 23022, 18955, 7041, 9065, 12741, 939, 2427, 28213,
+ 25469, 18291, 1428, 11477, 29463, 2417, 29556, 13542, 7697, 5691,
+ 7721, 21196, 13963, 4483, 3181, 23789, 14762, 17132, 27175, 1821,
+ 9530, 9500, 11061, 2648, 20631, 27411, 19305, 29879, 19661, 28603,
+ 20433, 13725, 4094, 17344, 27964, 14897, 28676, 19873, 30713, 11794,
+ 12376, 12296, 226, 13382, 10034, 27223, 17306, 11379, 15858, 26499,
+ 18962, 22609, 20671, 28453, 26962, 30047, 12654, 11470, 31606, 7893,
+ 20901, 16795, 31478, 3034, 22592, 5130, 25387, 32248, 9715, 21004,
+ 31247, 29645, 3377, 22876, 26437, 29699, 16717, 31246, 15449, 1154,
+ 16608, 18283, 21064, 8675, 16234, 27388, 8259, 19240, 21052, 11749,
+ 28592, 30123, 25749, 11381, 4466, 32085, 14091, 26618, 30826, 25872,
+ 28204, 10970, 23869, 31615, 29798, 29407, 20312, 14316, 13092, 21971,
+ 22322, 25474, 26426, 5197, 3537, 25276, 5251, 20170, 19856, 13085,
+ 23752, 4351, 24607, 28962, 15844, 10094, 19915, 31349, 31526, 29496,
+ 12800, 99, 13815, 12338, 14604, 7824, 31165, 24890, 11045, 18921,
+ 16127, 22220, 10414, 11227, 10697, 976, 31670, 15810, 1874, 5302,
+ 8898, 14501, 20188, 31941, 30924, 11552, 10716, 28080, 7819, 22433,
+ 18267, 28011, 2293, 1240, 32412, 32316, 22787, 6760, 1279, 3349,
+ 24756, 6115, 15141, 6689, 31060, 9205, 21845, 20381, 3838, 31199,
+ 25374, 31465, 1376, 19239, 31294, 7135, 22974, 27022, 2243, 32355,
+ 9785, 19779, 4720, 4667, 27218, 19286, 23906, 29986, 15530, 4207,
+ 20980, 25367, 18955, 13248, 4575, 251, 17836, 30264, 2726, 13659,
+ 11953, 506, 1841, 907, 3826, 15885, 1207, 7412, 5885, 2645,
+ 20194, 7342, 15198, 30658, 10030, 8530, 14110, 20679, 31635, 14601,
+ 6025, 1550, 28771, 21481, 13620, 21354, 16757, 12418, 15935, 12557,
+ 16003, 30387, 13784, 25851, 26321, 29891, 3328, 18622, 26639, 12972,
+ 14482, 5979, 1153, 20410, 26753, 22406, 9309, 24149, 17505, 13842,
+ 5749, 12827, 20777, 25771, 17429, 21555, 25655, 20679, 23599, 4573,
+ 18324, 18138, 14773, 22861, 29562, 21961, 2375, 22713, 275, 1698,
+ 29198, 5041, 14980, 15498, 17896, 25263, 27690, 20727, 31941, 4335,
+ 23331, 16415, 32593, 3200, 1297, 31152, 1235, 23708, 3354, 10689,
+ 2132, 21045, 31284, 3592, 6405, 9936, 10911, 11086, 2523, 32150,
+ 8370, 30497, 17532, 31400, 3291, 18889, 17246, 25780, 14562, 11389,
+ 30509, 1222, 14445, 22486, 7022, 14432, 713, 30339, 15971, 27084,
+ 23015, 63, 46, 25265, 8869, 16640, 19768, 11493, 4687, 24689,
+ 6100, 30082, 21862, 32163, 21792, 9788, 5024, 13055, 16684, 10481,
+ 29999, 5760, 11871, 2434, 3398, 2591, 25622, 27106, 19930, 28814,
+ 20621, 31852, 26790, 6696, 4611, 30842, 16753, 32297, 6937, 15667,
+ 21907, 5146, 30332, 5796, 15542, 24976, 28099, 22803, 9946, 4118,
+ 6043, 18063, 31644, 8040, 4385, 29388, 32439, 2018, 26255, 6446,
+ 7627, 24887, 28443, 6436, 19293, 24934, 8220, 3255, 2847, 18410,
+ 7023, 11619, 4978, 2353, 32025, 31525, 10282, 20048, 11309, 22997,
+ 4753, 7413, 13041, 6326, 23214, 15261, 25148, 6220, 9671, 9735,
+ 17442, 621, 24100, 9704, 8659, 18587, 2070, 25568, 8385, 23697,
+ 26680, 1197, 15105, 22300, 24309, 9887, 5876, 300, 7498, 21323,
+ 550, 29483, 5837, 14724, 4982, 16013, 21743, 17287, 14456, 21929,
+ 3966, 23926, 12823, 9671, 11886, 8, 17535, 6010, 6360, 21374,
+ 7738, 26928, 30019, 32473, 15000, 6151, 16163, 30538, 17237, 19170,
+ 21919, 25578, 13686, 29629, 26519, 27051, 19828, 6973, 24806, 29582,
+ 32412, 2699, 15588, 19223, 31158, 18275, 25135, 5375, 1765, 5736,
+ 27564, 1576, 14030, 30651, 712, 25814, 12028, 20939, 12036, 10779,
+ 5507, 15983, 16048, 22419, 24548, 11826, 11510, 21842, 2353, 21997,
+ 10523, 27675, 29554, 6812, 8962, 12242, 30790, 28522, 242, 28212,
+ 27854, 23054, 25240, 30150, 7366, 4442, 5456, 18699, 245, 27153,
+ 7584, 4602, 13512, 1530, 31237, 27055, 28474, 31026, 755, 18529,
+ 758, 22982, 3095, 12692, 10688, 28033, 10975, 28816, 7953, 27139,
+ 17980, 30993, 19969, 31507, 21415, 16448, 5738, 823, 25954, 8674,
+ 27979, 19073, 28160, 9680, 23658, 4011, 23847, 14759, 9534, 12135,
+ 31125, 12992, 2827, 22000, 7265, 11363, 2127, 28389, 12675, 5687,
+ 29533, 18263, 8599, 1789, 22088, 5665, 2270, 10110, 32258, 24183,
+ 24454, 18882, 1221, 24770, 30507, 131, 23474, 3499, 29085, 19169,
+ 6073, 12150, 5348, 10328, 1464, 15762, 8321, 10478, 18919, 3694,
+ 2039, 19889, 3699, 23438, 13962, 19808, 1385, 19421, 16455, 4457,
+ 16854, 30789, 9284, 32531, 11309, 7805, 1065, 24829, 5608, 30242,
+ 29935, 1223, 12402, 23562, 19688, 24847, 27461, 18389, 4864, 22431,
+ 32079, 16324, 29506, 26596, 7579, 16079, 23710, 26019, 12077, 16625,
+ 11241, 2023, 25646, 27079, 2085, 25662, 7241, 31065, 21507, 10788,
+ 596, 824, 22694, 12992, 11571, 7113, 3498, 14542, 18425, 28640,
+ 8805, 19677, 1361, 31376, 11372, 22970, 25117, 19778, 8025, 19756,
+ 31580, 7685, 29132, 14561, 31569, 4133, 5040, 32681, 25058, 27391,
+ 6592, 25314, 11326, 13075, 16969, 1075, 8130, 22875, 14129, 12158,
+ 15390, 29916, 12600, 271, 6323, 14970, 24702, 15386, 12608, 10000,
+ 15942, 25956, 26046, 4032, 11257, 30272, 12680, 3208, 878, 15293,
+ 23999, 28950, 31848, 13854, 13037, 18398, 2912, 3210, 28136, 873,
+ 7557, 26885, 31738, 23024, 22018, 20639, 16958, 32553, 12415, 19435,
+ 29773, 12385, 11498, 29619, 15898, 18123, 26743, 13802, 17691, 17432,
+ 18405, 26338, 17578, 3399, 5892, 29376, 18858, 18367, 16756, 17196,
+ 20845, 3227, 2223, 11597, 20437, 26181, 23369, 31732, 24762, 19526,
+ 12663, 27159, 10380, 4444, 4815, 8578, 10298, 30669, 10574, 4553,
+ 2130, 24572, 1439, 13185, 8041, 17722, 30874, 2991, 14269, 31966,
+ 9740, 897, 22553, 27544, 13494, 26684, 5113, 9474, 16280, 10102,
+ 9967, 10616, 27759, 7045, 24389, 13866, 19324, 31799, 7140, 23407,
+ 25735, 18372, 24948, 19805, 5412, 14336, 19141, 8854, 9269, 6101,
+ 22638, 30052, 11952, 3313, 25524, 6921, 20898, 10684, 14509, 25936,
+ 13684, 23437, 7077, 8808, 24173, 2333, 15808, 20210, 26233, 30012,
+ 25825, 11865, 1065, 14786, 19147, 15714, 762, 28361, 30598, 13060,
+ 4314, 21017, 6917, 889, 1256, 740, 10757, 6549, 892, 9652,
+ 16952, 14935, 9063, 1185, 6563, 18110, 30844, 32711, 32068, 20445,
+ 10063, 25079, 8953, 12594, 26172, 28077, 21149, 9524, 4011, 13890,
+ 10868, 2091, 10643, 6499, 713, 15684, 1597, 27842, 13525, 27109,
+ 25163, 13323, 18659, 31550, 9208, 29466, 20402, 10785, 8097, 28779,
+ 27419, 28947, 1413, 31698, 18931, 10403, 23753, 3436, 6963, 15866,
+ 12223, 20693, 15446, 14260, 19815, 28827, 9987, 31982, 17462, 13811,
+ 25068, 4768, 31255, 20651, 30966, 17198, 1456, 23392, 16538, 25657,
+ 11494, 28657, 26763, 11963, 11427, 24627, 8601, 23891, 11734, 26343,
+ 23253, 1245, 3004, 25833, 23030, 23366, 20319, 32426, 13051, 24734,
+ 1116, 11743, 25362, 7791, 19176, 7035, 4793, 29006, 19221, 21979,
+ 17187, 4271, 27986, 14145, 27357, 18686, 31793, 4228, 17841, 7147,
+ 4974, 27654, 23499, 15109, 44, 31973, 1050, 4234, 30337, 3702,
+ 26105, 19069, 16437, 2031, 15887, 7162, 18631, 22627, 27251, 10439,
+ 10929, 24308, 532, 20267, 8685, 9028, 31577, 17411, 1976, 29228,
+ 9732, 13586, 15254, 12977, 31836, 26009, 7574, 1843, 3979, 31015,
+ 32215, 3816, 4933, 24755, 9547, 23433, 19626, 7656, 23483, 28491,
+ 26734, 20672, 3852, 22289, 31799, 17236, 32704, 13536, 14150, 26611,
+ 5824, 20115, 1626, 32113, 18520, 29904, 11985, 19905, 10371, 22074,
+ 9489, 15046, 5225, 4840, 8742, 3431, 5414, 9239, 15532, 15074,
+ 24525, 27675, 2288, 5218, 5804, 668, 1106, 5331, 12242, 4350,
+ 20462, 16629, 9423, 21281, 32379, 19887, 20411, 4171, 31090, 167,
+ 6522, 8290, 16755, 32527, 23869, 20831, 3558, 32450, 9548, 16639,
+ 4062, 3471, 9476, 32443, 23618, 25300, 5147, 2555, 16686, 28495,
+ 20268, 135, 2711, 7986, 24943, 4414, 31278, 629, 23495, 1802,
+ 30343, 20336, 7427, 19, 13691, 29609, 28509, 9523, 26059, 9963,
+ 8007, 30123, 7173, 13464, 28520, 31508, 1708, 28479, 3553, 31128,
+ 11667, 625, 28372, 28769, 16522, 5841, 12327, 32338, 14652, 31851,
+ 27269, 32501, 21592, 20295, 5030, 29621, 9711, 19005, 21969, 3406,
+ 19742, 15370, 159, 27009, 2796, 21156, 30465, 22796, 16501, 12491,
+ 16004, 16857, 6217, 481, 5076, 29046, 24335, 32763, 10367, 29637,
+ 20334, 8248, 28156, 16885, 21805, 22866, 4588, 23984, 2968, 14450,
+ 3999, 11414, 31526, 14409, 31450, 10219, 23130, 3676, 26584, 13452,
+ 21991, 25247, 5262, 14120, 9239, 9542, 14132, 14508, 26477, 30424,
+ 5632, 12031, 9354, 22149, 19509, 15856, 20301, 2745, 24668, 1133,
+ 13118, 30705, 4049, 18933, 15149, 22990, 29570, 8271, 23574, 4711,
+ 25076, 19837, 10056, 996, 12935, 4588, 18374, 10313, 17914, 7917,
+ 28398, 23439, 30769, 20841, 29784, 3065, 24374, 1231, 11521, 17573,
+ 31615, 4690, 15785, 18018, 15727, 20562, 27769, 8897, 1054, 9751,
+ 13801, 3439, 31069, 1989, 10465, 22465, 28405, 28300, 19998, 19089,
+ 8496, 8480, 7896, 21065, 667, 24681, 20130, 12605, 29961, 19579,
+ 27793, 11326, 5083, 5576, 8096, 25963, 29567, 20116, 595, 22859,
+ 31287, 28842, 24987, 12825, 13852, 27470, 25338, 25951, 21602, 19826,
+ 21991, 20423, 7645, 24621, 13428, 17197, 7364, 17768, 5934, 15096,
+ 20406, 28379, 8261, 10923, 3578, 312, 8685, 6839, 267, 30629,
+ 1027, 1940, 22356, 7024, 11508, 14095, 5176, 9214, 29147, 30694,
+ 8533, 4869, 20969, 32658, 1290, 8443, 266, 23140, 25142, 19919,
+ 1477, 8659, 9539, 27094, 28260, 27925, 612, 11016, 24918, 12268,
+ 10522, 8812, 3281, 31683, 20733, 9681, 14780, 22265, 953, 447,
+ 1483, 7805, 18519, 1965, 2284, 9627, 5054, 19572, 27106, 2069,
+ 8825, 11012, 9775, 25206, 8122, 24406, 4408, 25763, 15775, 19874,
+ 20132, 29363, 8885, 18897, 19461, 18432, 20667, 29493, 32186, 20606,
+ 26792, 30840, 25364, 11340, 28655, 22482, 5559, 4489, 31489, 28543,
+ 26691, 105, 24851, 29297, 22580, 32136, 23842, 5442, 22279, 18046,
+ 16437, 1900, 11935, 13491, 6371, 3260, 1254, 17013, 29716, 19204,
+ 17079, 26183, 6924, 8209, 25084, 14460, 29349, 5084, 26387, 5893,
+ 24539, 15108, 2423, 15240, 21902, 7548, 20380, 30642, 28548, 30081,
+ 8730, 3021, 16046, 23248, 6670, 19349, 10924, 11797, 3773, 1351,
+ 3218, 22694, 9851, 24316, 26349, 13425, 28364, 7733, 24321, 12340,
+ 16328, 3511, 23381, 1004, 28356, 30105, 27506, 2447, 5166, 22939,
+ 23783, 3581, 26809, 29113, 8592, 11828, 32186, 4352, 27416, 5316,
+ 21714, 28321, 8125, 11140, 6862, 1348, 3155, 5506, 2507, 31902,
+ 30604, 1344, 13982, 20806, 31350, 17181, 19827, 11972, 16965, 30737,
+ 435, 12267, 8019, 4253, 13612, 31082, 1381, 19458, 6764, 25245,
+ 24880, 19378, 22125, 8361, 26396, 14084, 25976, 10183, 16199, 18219,
+ 18243, 14048, 13005, 20329, 13917, 16731, 15943, 5504, 28363, 11059,
+ 11665, 3690, 18420, 2892, 9425, 21321, 9658, 26631, 15028, 25249,
+ 1258, 8724, 2043, 453, 9942, 391, 20535, 21135, 8256, 6446,
+ 10192, 29012, 20346, 29730, 15180, 12055, 32204, 16797, 7118, 15357,
+ 12310, 29451, 13533, 22017, 27318, 100, 20327, 20457, 27820, 18104,
+ 17926, 1145, 9724, 13580, 20097, 2534, 27988, 15204, 31894, 14734,
+ 14575, 12321, 25079, 24549, 24249, 8077, 28562, 10419, 8116, 14773,
+ 31765, 7037, 666, 21111, 5042, 15424, 16836, 10203, 29984, 9318,
+ 20554, 25255, 24546, 10226, 14956, 1325, 6091, 23294, 25905, 15464,
+ 16834, 2919, 29005, 18247, 32195, 711, 17736, 26697, 25126, 9379,
+ 733, 5450, 15396, 15590, 27553, 22941, 14743, 4750, 30949, 7770,
+ 24577, 4774, 10972, 19705, 29904, 10100, 21249, 32, 15072, 4083,
+ 23987, 14010, 10562, 19332, 24354, 15689, 32572, 28128, 26479, 16765,
+ 22928, 28497, 25103, 17413, 11521, 19746, 1137, 23717, 18964, 3667,
+ 4064, 1161, 19988, 146, 27306, 23257, 9560, 16743, 21634, 6029,
+ 713, 26543, 14883, 8323, 28830, 24907, 27702, 29902, 24170, 22809,
+ 15734, 25170, 20569, 14627, 19474, 14734, 5046, 7447, 31314, 29624,
+ 7345, 18680, 23166, 32527, 29024, 30738, 4604, 9581, 17923, 6195,
+ 30648, 16667, 11916, 17688, 29129, 13290, 2399, 6182, 22097, 21631,
+ 1878, 8283, 21412, 17903, 29960, 5763, 9133, 28044, 10571, 8623,
+ 3726, 31486, 15607, 16355, 135, 13973, 28653, 9999, 14105, 2525,
+ 24408, 12864, 18795, 30323, 28979, 12056, 4076, 28440, 6412, 8060,
+ 12090, 18180, 23047, 17292, 19011, 11132, 10789, 32728, 8106, 23463,
+ 6854, 29648, 5740, 4766, 27245, 21629, 32195, 22466, 25540, 24431,
+ 1098, 10578, 11744, 31223, 10850, 13629, 29125, 20630, 13269, 5172,
+ 31021, 2740, 23738, 15108, 10885, 26261, 21913, 5667, 1593, 20874,
+ 19151, 904, 2353, 20580, 31539, 7872, 6300, 19502, 8697, 4927,
+ 23276, 5916, 14295, 26868, 8737, 15806, 20327, 32544, 19275, 30841,
+ 4301, 10599, 14154, 20792, 6297, 9000, 16601, 20831, 15855, 19722,
+ 21451, 19457, 997, 26839, 2451, 6226, 14892, 18318, 28426, 20575,
+ 4339, 7603, 22381, 26620, 9224, 29162, 24741, 12286, 16704, 22980,
+ 3276, 6571, 28186, 30937, 5356, 20079, 28831, 30231, 22794, 28625,
+ 24460, 23385, 4451, 5028, 32179, 4923, 9461, 20610, 25759, 31021,
+ 18753, 28278, 17015, 12231, 20304, 4089, 12068, 12637, 16884, 26400,
+ 23734, 20178, 14672, 19219, 9988, 4273, 1946, 16833, 18067, 11897,
+ 8992, 20946, 10938, 4153, 29065, 12509, 16131, 3677, 22622, 8668,
+ 8147, 25544, 14025, 6109, 590, 1571, 11420, 28922, 21365, 22644,
+ 21140, 23946, 21137, 27634, 18400, 18329, 10965, 17176, 14557, 20118,
+ 20543, 19192, 17188, 11084, 9151, 32466, 23238, 4116, 8859, 27109,
+ 5334, 22856, 9490, 31621, 31528, 8698, 28736, 24942, 19801, 4326,
+ 8001, 23640, 21263, 29094, 10137, 17099, 9090, 28197, 31955, 9781,
+ 1596, 31830, 5993, 20026, 20765, 21542, 25316, 32331, 26529, 431,
+ 22340, 14714, 16230, 26542, 16802, 30860, 3560, 17975, 20, 1616,
+ 911, 6567, 13521, 30256, 14317, 26075, 13462, 26886, 11072, 16799,
+ 13384, 5169, 319, 13929, 31194, 16103, 22803, 18504, 5233, 10700,
+ 26275, 14871, 24518, 5316, 12564, 25078, 22220, 22278, 6800, 8699,
+ 31124, 15731, 5447, 22820, 19053, 8997, 10676, 24720, 9807, 30794,
+ 12834, 26863, 31866, 11059, 28526, 19512, 10586, 10152, 23310, 10138,
+ 30894, 24703, 23122, 20916, 4841, 5997, 14058, 264, 23000, 22299,
+ 169, 13997, 30854, 21372, 15497, 16709, 10845, 9311, 1262, 27695,
+ 32141, 3648, 32559, 12030, 5298, 19812, 19026, 28969, 11185, 5925,
+ 19223, 13827, 25570, 17802, 31033, 17646, 7029, 24858, 4592, 8652,
+ 21518, 31986, 21434, 27063, 27827, 6422, 10075, 26610, 13032, 32517,
+ 23074, 30495, 3864, 19600, 19823, 690, 20535, 8427, 16242, 15525,
+ 23206, 8197, 4405, 23406, 15959, 16405, 11741, 29742, 30769, 5493,
+ 30509, 17707, 25270, 4276, 23371, 1152, 6627, 25319, 30663, 1811,
+ 22103, 31807, 28121, 21448, 952, 22753, 19434, 30452, 5715, 4081,
+ 12374, 10773, 25602, 22768, 2417, 9152, 1107, 31561, 5832, 9178,
+ 31718, 23590, 4009, 4107, 14103, 7816, 4837, 13424, 6109, 2455,
+ 17364, 31888, 6898, 10551, 14490, 14482, 22581, 23771, 7593, 17069,
+ 25164, 18590, 12935, 6367, 18829, 23696, 978, 16098, 17951, 26189,
+ 1665, 31836, 19804, 24789, 30828, 19286, 5754, 30359, 10767, 2799,
+ 21099, 27087, 5514, 19025, 6913, 22290, 26349, 16357, 23894, 1575,
+ 22963, 16579, 17259, 15641, 3980, 19565, 24847, 18826, 17504, 188,
+ 10243, 13386, 912, 2586, 26459, 21289, 17023, 25586, 23079, 11529,
+ 1105, 32101, 2387, 25655, 27378, 5695, 1228, 6907, 22874, 26665,
+ 14308, 1645, 2832, 28704, 23800, 9099, 17645, 27685, 21584, 17033,
+ 803, 24886, 25158, 23656, 18558, 15742, 6315, 26314, 29417, 27337,
+ 28518, 6661, 14643, 25914, 20574, 23926, 13843, 10816, 6811, 19992,
+ 9322, 5062, 24744, 4948, 12489, 29610, 26171, 30235, 1075, 881,
+ 8471, 28211, 27684, 31801, 16690, 6606, 17361, 27374, 1043, 21345,
+ 690, 5313, 22399, 22963, 5182, 32726, 3924, 15925, 23798, 29757,
+ 12981, 3473, 4260, 2340, 9319, 26245, 15845, 4683, 10875, 29426,
+ 13029, 440, 6446, 30512, 8042, 4523, 9485, 27557, 6164, 19156,
+ 8285, 21654, 24291, 15044, 10169, 19516, 5369, 28322, 509, 29467,
+ 14753, 1567, 14179, 14991, 6801, 29355, 9196, 15784, 6508, 14058,
+ 2306, 7223, 27275, 14945, 25179, 3113, 12541, 1398, 544, 5396,
+ 7116, 31127, 14415, 10768, 26754, 22969, 2398, 5576, 28396, 14084,
+ 14369, 27857, 6686, 5580, 9965, 31290, 29367, 24260, 21502, 23140,
+ 7783, 28782, 29974, 14355, 30894, 25814, 30311, 24518, 10470, 24448,
+ 24755, 7492, 22915, 30623, 27314, 6008, 29850, 4743, 14772, 7806,
+ 2464, 16997, 5511, 8190, 16501, 32046, 5019, 13753, 32160, 16341,
+ 32100, 609, 7133, 29121, 30208, 20654, 24277, 7294, 8986, 10414,
+ 812, 19379, 23822, 20317, 4032, 10580, 10829, 25717, 19504, 10776,
+ 2564, 4743, 156, 24110, 20984, 1355, 25260, 14892, 9140, 6709,
+ 21460, 27720, 15591, 32584, 21718, 4554, 9992, 13359, 21128, 24769,
+ 2619, 8586, 12247, 6645, 10104, 14982, 12556, 22302, 15850, 23728,
+ 11342, 2387, 24469, 25099, 9064, 15301, 31036, 6495, 10957, 28333,
+ 4482, 6357, 16857, 7811, 847, 7873, 90, 19313, 14197, 29887,
+ 15695, 5383, 8596, 2305, 4848, 15920, 1083, 12775, 25582, 11621,
+ 16463, 20432, 17915, 15648, 13233, 16689, 30093, 28820, 27419, 23780,
+ 14047, 24731, 11083, 26306, 18489, 29936, 5476, 12915, 18802, 15774,
+ 27281, 26757, 15539, 184, 13035, 8636, 1149, 20555, 19357, 19625,
+ 750, 15505, 8261, 4478, 15936, 30311, 5022, 10273, 11922, 30209,
+ 23389, 21631, 6379, 31197, 21336, 32035, 7036, 29173, 3053, 4103,
+ 20261, 11065, 6050, 10666, 8763, 20284, 23561, 12898, 20617, 3118,
+ 27111, 26100, 7316, 30986, 8340, 31074, 11812, 2576, 8357, 21252,
+ 14847, 10614, 20937, 2266, 22264, 18523, 32753, 6433, 9256, 31740,
+ 21428, 4388, 9340, 31530, 10737, 5717, 29552, 4092, 3766, 1436,
+ 14105, 20929, 24416, 7407, 29545, 15160, 22532, 25379, 8879, 28932,
+ 4110, 16898, 14173, 19546, 10792, 1693, 27406, 32253, 15198, 15332,
+ 32455, 23916, 11647, 4979, 20605, 14425, 8390, 20655, 27096, 13918,
+ 4281, 27154, 27703, 9452, 16466, 21699, 32244, 16260, 12637, 11882,
+ 7401, 18473, 11041, 14658, 31283, 1045, 5186, 24176, 17205, 28843,
+ 9190, 10899, 31712, 17581, 11799, 30876, 20018, 4527, 3945, 16096,
+ 29437, 6603, 31708, 12907, 6122, 11671, 13571, 13463, 26301, 9812,
+ 27494, 16094, 4571, 20584, 20262, 16621, 2569, 23055, 5087, 9465,
+ 16758, 6733, 27602, 28246, 8188, 17447, 15940, 9798, 3235, 23058,
+ 7457, 2831, 12391, 30124, 15845, 13648, 22075, 14250, 31164, 10132,
+ 3149, 29713, 6376, 31784, 27276, 28330, 28004, 9514, 8808, 15279,
+ 199, 29411, 15320, 6347, 22890, 21591, 9122, 21058, 6861, 1561,
+ 28375, 2155, 1335, 9060, 30620, 26983, 6301, 19816, 14128, 13069,
+ 24261, 23778, 299, 4388, 8364, 20975, 1028, 11221, 2852, 30242,
+ 13014, 31327, 1729, 25812, 31844, 11789, 18166, 28091, 29530, 18790,
+ 21628, 1471, 19414, 14243, 5875, 14856, 21030, 30822, 8652, 22876,
+ 16084, 13224, 18534, 18344, 3039, 18931, 15735, 12252, 12108, 13522,
+ 16814, 2044, 24285, 19335, 9623, 7028, 16673, 16379, 8894, 4013,
+ 12205, 26619, 20503, 5853, 28328, 9888, 13725, 17699, 32141, 2575,
+ 17210, 15315, 25900, 29027, 12007, 7951, 9970, 20200, 32276, 2455,
+ 12651, 23178, 15946, 29409, 32261, 18573, 12559, 15213, 15383, 22654,
+ 28426, 21331, 11553, 20585, 18023, 12062, 5718, 14412, 22653, 32476,
+ 27479, 27084, 15022, 23414, 5698, 18471, 7823, 24126, 235, 13418,
+ 17737, 22215, 17257, 4580, 16960, 4857, 7125, 28378, 20722, 28004,
+ 4942, 9596, 16929, 5589, 29760, 2328, 17460, 18471, 30182, 29582,
+ 2779, 25948, 16654, 18180, 6642, 8941, 12829, 14298, 14248, 17501,
+ 31826, 29408, 18912, 4884, 4687, 29639, 8919, 2155, 30677, 8150,
+ 263, 24068, 24783, 30942, 17996, 30812, 16786, 31856, 10822, 24483,
+ 13411, 845, 27646, 15051, 22585, 13598, 18124, 223, 3269, 25702,
+ 11896, 21654, 12208, 26292, 5791, 15912, 16164, 15645, 18776, 14176,
+ 1421, 8425, 4376, 15858, 12961, 18573, 14803, 24592, 1438, 30938,
+ 11620, 30520, 27858, 13939, 12079, 1360, 15969, 11140, 31493, 26612,
+ 28227, 5553, 19272, 22031, 25996, 20557, 2639, 23464, 24304, 20173,
+ 13067, 18431, 27782, 7036, 9451, 16857, 2764, 11888, 28414, 30232,
+ 25836, 12476, 22104, 5262, 11837, 32743, 7094, 3859, 13581, 1437,
+ 17509, 20181, 4766, 14245, 27231, 21488, 7278, 21523, 22456, 29503,
+ 31419, 11711, 28984, 9841, 2119, 7413, 13386, 8799, 24409, 26734,
+ 19476, 10140, 14340, 14975, 488, 16718, 31659, 30353, 3291, 26173,
+ 12741, 721, 1203, 12330, 10718, 23081, 31751, 7522, 1758, 31342,
+ 1441, 4243, 3982, 731, 10535, 733, 26712, 5822, 2811, 7212,
+ 6735, 22641, 19295, 9670, 2927, 4236, 24797, 2848, 19493, 21849,
+ 29158, 23798, 24082, 18056, 29113, 2714, 22540, 12580, 1158, 17805,
+ 2917, 12230, 28371, 17228, 3696, 6921, 5152, 20844, 20546, 24125,
+ 18630, 28649, 6582, 1120, 31525, 26044, 8116, 4426, 30718, 939,
+ 2738, 31527, 19998, 2405, 6010, 22570, 5437, 24782, 13614, 5248,
+ 7205, 9112, 17546, 17539, 16919, 7955, 23658, 26417, 32618, 19014,
+ 14220, 11484, 24949, 25150, 12182, 5666, 32175, 8358, 26971, 32544,
+ 8213, 16536, 5722, 27363, 14540, 17843, 28551, 8991, 19720, 14702,
+ 19791, 36, 28460, 21163, 214, 27917, 563, 15248, 21123, 31803,
+ 19534, 27026, 18878, 8194, 7374, 15314, 8696, 23457, 2373, 21421,
+ 4332, 120, 1512, 23438, 16933, 19317, 23864, 12295, 11201, 30416,
+ 19170, 7969, 8308, 5112, 15843, 12784, 17104, 16845, 1519, 13418,
+ 15811, 4879, 28692, 28537, 26209, 14614, 5787, 18766, 10979, 18116,
+ 26671, 16377, 29424, 8121, 10817, 29238, 21788, 26565, 31402, 10890,
+ 17839, 1699, 5266, 8335, 8871, 5092, 23697, 25740, 16640, 16169,
+ 30741, 10569, 24370, 2197, 29700, 24610, 8444, 23938, 16034, 23385,
+ 30816, 28019, 30900, 27313, 8175, 19274, 25062, 9784, 2630, 11964,
+ 25706, 23396, 27353, 27137, 994, 20577, 15343, 26576, 13184, 20906,
+ 26094, 17802, 22379, 15831, 27609, 23990, 30053, 949, 16663, 22189,
+ 22700, 18076, 11382, 2454, 11549, 7421, 23663, 21909, 21919, 7483,
+ 4268, 13120, 447, 11452, 31943, 7251, 18072, 17727, 18517, 7076,
+ 16118, 9328, 20515, 6489, 30395, 6585, 3263, 14168, 9601, 26204,
+ 16954, 20991, 31872, 25535, 23853, 30998, 2994, 25606, 8442, 29953,
+ 566, 231, 2900, 11322, 19955, 19642, 4354, 31999, 24189, 6608,
+ 6111, 24392, 3900, 19462, 21030, 25340, 31947, 26778, 24300, 24164,
+ 18846, 22589, 21486, 24800, 5608, 3945, 5261, 15833, 11963, 4340,
+ 6679, 17398, 14449, 32486, 4424, 29843, 22604, 11656, 28945, 20335,
+ 8537, 27837, 28311, 1700, 18586, 31637, 29311, 11997, 25699, 23072,
+ 29545, 16323, 15109, 28032, 22970, 30904, 25770, 10818, 20639, 32200,
+ 17536, 14575, 10319, 16604, 7450, 18653, 11664, 2865, 17427, 1355,
+ 6780, 15113, 14580, 24749, 1157, 2465, 9047, 10821, 27575, 28002,
+ 31821, 8691, 20285, 27739, 26366, 32334, 27431, 29423, 31887, 6387,
+ 874, 715, 3913, 13598, 24616, 19996, 10487, 5239, 24370, 4862,
+ 18575, 20014, 16076, 19255, 8981, 7241, 1456, 1061, 27581, 4925,
+ 11349, 29429, 26448, 30652, 27504, 6422, 20176, 9935, 21436, 3309,
+ 17759, 17444, 4854, 15051, 25949, 8873, 2604, 12828, 10449, 7002,
+ 6456, 21217, 12554, 18006, 17288, 28512, 12678, 19001, 4640, 13849,
+ 530, 13734, 22241, 30717, 7219, 5923, 13579, 7899, 1989, 18218,
+ 4865, 26651, 31458, 6268, 22860, 14254, 12549, 25273, 8931, 5957,
+ 15727, 6958, 17065, 13761, 23754, 28654, 16952, 31467, 2573, 6436,
+ 15837, 870, 23199, 21671, 16867, 6370, 26047, 16335, 3349, 31377,
+ 15139, 904, 23678, 2527, 11487, 1700, 9331, 12126, 28809, 6774,
+ 23252, 3071, 23451, 21916, 13966, 19080, 16152, 4380, 2148, 9538,
+ 9843, 15283, 4336, 29682, 32172, 30569, 30692, 22027, 25276, 13673,
+ 18582, 19746, 9779, 17424, 6076, 23458, 16160, 836, 13939, 31681,
+ 13873, 13063, 5767, 691, 19483, 4171, 17390, 17437, 24380, 13320,
+ 6037, 2508, 21631, 26765, 1888, 13223, 1921, 26900, 14188, 5090,
+ 1522, 16280, 12439, 23413, 6717, 13547, 24642, 10957, 26987, 1795,
+ 17749, 6849, 10308, 22932, 28292, 20935, 11192, 5349, 11729, 31080,
+ 22654, 9948, 9554, 10225, 13819, 23130, 4405, 4716, 10341, 14543,
+ 29441, 6862, 5672, 10757, 542, 3698, 31881, 17984, 1432, 10438,
+ 14217, 3721, 31520, 11845, 268, 32583, 12116, 13221, 27450, 12559,
+ 11072, 25937, 23078, 31677, 6948, 25369, 16557, 20420, 4727, 1064,
+ 9378, 14786, 20781, 5943, 11816, 17496, 28214, 29441, 18014, 11320,
+ 2887, 27383, 2370, 6783, 30172, 31796, 3791, 22854, 22910, 18099,
+ 20329, 13939, 26433, 9920, 10107, 2261, 5778, 684, 15967, 2929,
+ 25391, 8389, 21630, 790, 11383, 6533, 15544, 25144, 6628, 14858,
+ 1286, 24315, 10454, 27334, 4701, 12173, 18322, 28280, 13270, 24761,
+ 8586, 3419, 28941, 31417, 223, 157, 6086, 26700, 26916, 12818,
+ 19671, 21513, 20325, 9258, 9282, 28659, 4967, 5665, 1185, 23373,
+ 7730, 14453, 22983, 6832, 18893, 1437, 23204, 22106, 30281, 4856,
+ 26217, 21193, 28672, 28164, 15597, 22409, 2847, 22992, 5711, 30794,
+ 6242, 180, 24030, 29749, 5919, 28223, 5173, 8064, 18566, 25969,
+ 7338, 2880, 2087, 26410, 31210, 24447, 3509, 31971, 15837, 7055,
+ 31753, 7068, 12496, 12445, 24937, 13077, 29650, 10889, 3339, 15681,
+ 8798, 23286, 24021, 25080, 14139, 15005, 28263, 748, 14497, 29926,
+ 16987, 17374, 28573, 20921, 22731, 25362, 11958, 29073, 18452, 30208,
+ 27601, 4051, 18138, 24140, 12626, 16223, 17997, 2808, 10884, 21860,
+ 426, 23001, 20283, 30328, 9988, 11591, 29368, 31208, 32068, 2585,
+ 14796, 5964, 11119, 20945, 15425, 4703, 1319, 27923, 21877, 22798,
+ 117, 31324, 26696, 18383, 14533, 21744, 6712, 2100, 9010, 2068,
+ 18891, 15808, 22532, 638, 17454, 29945, 5495, 7690, 32283, 2238,
+ 24511, 20398, 21503, 29147, 25160, 5040, 5469, 13531, 30274, 27158,
+ 24429, 25118, 29277, 30559, 2826, 23595, 10193, 7536, 12747, 22598,
+ 12450, 8401, 3695, 19782, 29474, 11801, 15486, 17569, 32439, 21415,
+ 6957, 16841, 9694, 17299, 22402, 13243, 31088, 29156, 25018, 9428,
+ 2341, 25348, 20968, 7399, 3414, 15985, 32734, 27022, 24071, 31156,
+ 21072, 16573, 23332, 12183, 2359, 29085, 10763, 30611, 1908, 6039,
+ 27723, 20872, 24502, 942, 21419, 31153, 10397, 20499, 14191, 14550,
+ 23584, 20979, 3798, 1219, 17964, 23956, 29927, 1274, 18061, 4256,
+ 6509, 20389, 27154, 5825, 17217, 29390, 7916, 7277, 18375, 7634,
+ 2136, 25604, 7099, 32531, 13694, 12568, 24878, 10734, 16280, 32267,
+ 5835, 6381, 4950, 12256, 19551, 8253, 27009, 15435, 153, 25698,
+ 13024, 30218, 3086, 10537, 31576, 29560, 15743, 3294, 2134, 17248,
+ 2911, 960, 13938, 25615, 32400, 10162, 23116, 12461, 14958, 12339,
+ 10426, 14541, 17934, 9872, 27174, 13890, 31431, 10840, 32049, 5428,
+ 15346, 23057, 27804, 17012, 23535, 13353, 7273, 13325, 21097, 1072,
+ 21053, 24604, 10202, 12356, 7433, 5601, 14929, 31436, 24553, 27925,
+ 16243, 3177, 1101, 16254, 10175, 23081, 5974, 24770, 18199, 15358,
+ 22147, 2169, 26236, 18287, 28556, 8837, 8986, 17038, 30606, 31142,
+ 16004, 17194, 23913, 28745, 17472, 20037, 23398, 15265, 10374, 3016,
+ 11294, 21753, 17477, 25206, 1687, 5449, 21095, 4127, 9647, 12039,
+ 21078, 4630, 24254, 31295, 29631, 29157, 2935, 18150, 28566, 19006,
+ 19215, 10604, 29274, 6197, 24226, 30096, 31642, 11437, 9426, 23416,
+ 22200, 21008, 30897, 23297, 4333, 31300, 30689, 340, 4237, 2266,
+ 29689, 9402, 12684, 3464, 4907, 4785, 2882, 729, 25636, 25663,
+ 17259, 25891, 26932, 27782, 4722, 13754, 24239, 30105, 23791, 15971,
+ 16531, 16270, 1646, 10507, 21354, 30164, 24946, 16313, 13426, 3783,
+ 24761, 26818, 13564, 18818, 28098, 13116, 1298, 15860, 2189, 1972,
+ 29020, 13111, 5282, 20772, 14405, 12316, 30548, 12831, 14937, 31243,
+ 27463, 6735, 2545, 30218, 11568, 20513, 7699, 8219, 26076, 17087,
+ 11412, 3275, 30068, 14399, 28543, 10504, 1023, 11289, 22971, 11315,
+ 31528, 29151, 32487, 28790, 19777, 28712, 12937, 9560, 11657, 1998,
+ 8808, 4238, 7594, 31577, 28726, 20756, 29830, 27322, 3698, 22653,
+ 16947, 14141, 25741, 3720, 13636, 25529, 32332, 21235, 25931, 17673,
+ 19053, 20884, 9884, 5824, 11405, 23717, 19283, 18457, 26185, 16736,
+ 30104, 5421, 7076, 19148, 24353, 16489, 30376, 26326, 14841, 62,
+ 11857, 8611, 3712, 29978, 29862, 27429, 15028, 15256, 4137, 23276,
+ 30382, 28404, 9329, 26175, 623, 12225, 28182, 15468, 24797, 734,
+ 30157, 15708, 17417, 7334, 32468, 15978, 3763, 27751, 13457, 4469,
+ 3856, 31765, 23414, 564, 22219, 30784, 2343, 15818, 21577, 29764,
+ 10207, 22683, 4401, 16064, 18704, 26205, 14892, 23113, 2889, 22642,
+ 21481, 28255, 5981, 5749, 16741, 17567, 30914, 1299, 32617, 9787,
+ 21815, 28444, 14676, 11688, 18345, 1241, 6938, 24726, 25176, 26017,
+ 1165, 9765, 7222, 26535, 475, 27990, 11663, 4630, 11608, 6079,
+ 8175, 32096, 24190, 31876, 5441, 3538, 18994, 6018, 2612, 15469,
+ 30793, 14541, 6115, 25073, 12875, 18525, 30900, 14394, 20343, 29188,
+ 21632, 1487, 519, 19875, 6133, 10169, 2485, 22430, 23353, 28049,
+ 28541, 19853, 7120, 31709, 11941, 17205, 19904, 10397, 28411, 950,
+ 2035, 1568, 13406, 4869, 20444, 4124, 10111, 25501, 18526, 12030,
+ 23529, 5234, 18409, 1407, 14143, 19239, 6630, 15480, 24005, 32384,
+ 28501, 16631, 18466, 17690, 17076, 10386, 26213, 31834, 13091, 12283,
+ 29765, 23459, 6855, 2005, 25261, 18380, 25708, 25542, 31352, 31441,
+ 25710, 32718, 7289, 21448, 14553, 4055, 17086, 25367, 29903, 19853,
+ 10005, 1765, 6954, 6255, 13008, 11214, 11363, 23590, 7110, 1499,
+ 19379, 12566, 21146, 21937, 16247, 27444, 9792, 3592, 20697, 2839,
+ 16572, 27999, 20141, 17745, 24877, 24558, 14233, 5119, 30475, 15837,
+ 20345, 1695, 685, 14771, 9217, 17442, 24334, 4881, 17572, 29506,
+ 22736, 24992, 12725, 32022, 13953, 3144, 18125, 24036, 5662, 16547,
+ 9324, 30774, 17365, 32433, 23779, 7728, 28175, 3277, 26737, 17696,
+ 23214, 26591, 9388, 5975, 403, 980, 25378, 22584, 12388, 28747,
+ 19265, 20110, 7052, 13713, 4980, 10531, 131, 32208, 21903, 4494,
+ 15695, 24195, 621, 24908, 331, 22061, 14551, 11538, 31527, 21067,
+ 936, 6754, 10288, 20871, 17199, 13149, 10449, 30254, 17877, 11480,
+ 15962, 7396, 21504, 21169, 22017, 19351, 13111, 3683, 17703, 3249,
+ 25734, 15321, 6876, 2706, 8740, 16512, 10916, 32573, 24659, 6304,
+ 13435, 19537, 21896, 20204, 19992, 20284, 19916, 4696, 29039, 17835,
+ 19810, 24106, 21625, 22084, 18090, 26708, 28215, 4504, 26437, 18945,
+ 19701, 32595, 16506, 5742, 8652, 2998, 20184, 21499, 9578, 26952,
+ 9501, 2946, 14870, 15048, 15959, 25063, 28398, 6501, 15177, 28656,
+ 18547, 19250, 3856, 19543, 29256, 15828, 24327, 31774, 15927, 6525,
+ 6631, 15651, 5237, 31, 2611, 24308, 14631, 19673, 26579, 7652,
+ 2852, 26550, 11518, 13407, 8189, 406, 12894, 5754, 24891, 19564,
+ 22127, 3022, 3815, 938, 13353, 7047, 19280, 22778, 11486, 32440,
+ 5128, 6447, 18789, 3314, 19504, 7547, 13944, 22292, 15349, 23778,
+ 24667, 25700, 10587, 12782, 29118, 17887, 28218, 10405, 14821, 29646,
+ 12165, 26808, 15878, 10650, 6610, 4093, 31219, 13281, 18199, 4383,
+ 5112, 25801, 12722, 27285, 2055, 8853, 22701, 18896, 3602, 17526,
+ 31039, 28345, 16313, 12707, 406, 25434, 16677, 30379, 8403, 23515,
+ 28980, 17674, 6231, 21169, 25814, 4347, 12861, 13586, 12727, 16782,
+ 295, 13228, 19486, 9978, 19774, 2966, 31765, 11060, 21108, 23431,
+ 11722, 28865, 13325, 22854, 8501, 21448, 18781, 31585, 15611, 363,
+ 10195, 27426, 2194, 6487, 3638, 21183, 4518, 3482, 5423, 23505,
+ 16572, 13494, 18696, 29191, 24854, 16883, 4275, 7708, 24534, 6137,
+ 1550, 3334, 1638, 10653, 9061, 6001, 13334, 23804, 27192, 23915,
+ 23303, 9414, 26431, 19041, 17481, 17373, 14252, 5450, 24384, 28447,
+ 29616, 4386, 8268, 16767, 8768, 24986, 12968, 13915, 6681, 26638,
+ 403, 7690, 29698, 31927, 23726, 16564, 29265, 18466, 15270, 9062,
+ 432, 20704, 25874, 9061, 14113, 4480, 31903, 23491, 28480, 10938,
+ 15466, 2353, 29384, 1517, 23981, 24596, 17497, 31692, 29854, 2267,
+ 31609, 21331, 17300, 13967, 20696, 11521, 18796, 2987, 16344, 11841,
+ 3883, 16687, 24908, 297, 30948, 17392, 25472, 31846, 7645, 15410,
+ 17275, 1911, 27629, 13176, 11136, 3866, 6696, 19611, 6875, 7684,
+ 11967, 16922, 15066, 28117, 7201, 7857, 1305, 1099, 14694, 25645,
+ 7938, 12470, 6638, 5246, 3733, 32172, 2117, 20750, 11365, 27389,
+ 10314, 1105, 30435, 1001, 1169, 18846, 10975, 9617, 2821, 1853,
+ 17740, 2476, 15570, 28353, 21060, 27003, 5506, 22423, 11596, 19711,
+ 28005, 10208, 5848, 23145, 23351, 16252, 17170, 14802, 22781, 6503,
+ 17879, 24876, 12336, 5961, 2, 23673, 28957, 11080, 29166, 26171,
+ 31116, 21537, 5942, 25643, 20128, 8055, 12223, 7213, 19966, 9835,
+ 6649, 13700, 31281, 14444, 8801, 23106, 26190, 10320, 27723, 3331,
+ 1235, 28580, 22494, 1755, 24021, 7233, 2400, 12685, 28763, 15392,
+ 30132, 4606, 17157, 15216, 6176, 14057, 26609, 26853, 13652, 32723,
+ 30686, 5202, 20392, 20546, 18578, 31610, 12454, 810, 25210, 31012,
+ 11208, 12968, 31121, 10861, 32386, 10226, 28034, 32354, 29059, 1935,
+ 5393, 25550, 7993, 3523, 22711, 2385, 915, 28494, 24716, 25522,
+ 14602, 12886, 22891, 28278, 1762, 5025, 5456, 23218, 9389, 19463,
+ 2820, 8221, 22290, 18983, 30973, 9321, 18892, 13402, 12159, 27860,
+ 19189, 18149, 17928, 3578, 19333, 25203, 16363, 19949, 18710, 24258,
+ 25659, 11399, 1258, 30108, 19690, 17919, 11310, 23049, 28978, 17339,
+ 21888, 20419, 12084, 20325, 30640, 22250, 6368, 15425, 15811, 16377,
+ 2068, 23230, 23614, 15353, 15880, 10827, 19361, 15604, 4585, 23915,
+ 3121, 15021, 29380, 25612, 22266, 12174, 16550, 28693, 24597, 25058,
+ 16642, 10302, 3623, 19780, 12882, 32036, 19242, 16471, 17153, 21661,
+ 21104, 696, 28553, 32584, 8164, 5937, 3033, 11369, 25748, 28208,
+ 31737, 20468, 9324, 7287, 24560, 12008, 24900, 27156, 14054, 1502,
+ 30494, 19860, 15750, 32226, 3496, 10100, 2982, 25473, 17161, 20952,
+ 13610, 21539, 29657, 22655, 29221, 21916, 17521, 27895, 4674, 3069,
+ 20326, 27405, 16227, 432, 7504, 392, 21383, 13764, 18896, 21271,
+ 17905, 25733, 31185, 9095, 29575, 15952, 1805, 25913, 18040, 165,
+ 1235, 15060, 289, 9598, 520, 16695, 12338, 7391, 11373, 13746,
+ 2060, 17583, 14623, 19573, 12654, 4806, 13924, 19272, 18769, 9543,
+ 10916, 15485, 6160, 11568, 9398, 20003, 17356, 26415, 8542, 12669,
+ 527, 5816, 27155, 3763, 3247, 14164, 20741, 24774, 24054, 22588,
+ 28254, 19913, 30719, 22054, 17096, 20303, 15203, 26463, 25392, 16160,
+ 4374, 11802, 4554, 7216, 27531, 17672, 26710, 7121, 25375, 31272,
+ 30625, 23335, 29108, 11233, 78, 17628, 4508, 31822, 10454, 32534,
+ 17338, 20185, 21710, 30118, 16611, 17419, 361, 21635, 23178, 10146,
+ 19261, 1654, 20125, 1252, 330, 3094, 4778, 21812, 26936, 16119,
+ 23110, 31971, 6368, 21791, 23727, 2632, 2318, 14521, 7600, 27411,
+ 17797, 2062, 15813, 3038, 24132, 20912, 5504, 5637, 32264, 24824,
+ 8235, 16312, 18962, 11955, 31151, 25166, 28458, 18969, 29621, 19164,
+ 32740, 19967, 1546, 30983, 2082, 13901, 7752, 16406, 31194, 10673,
+ 4787, 32332, 22298, 2965, 15457, 24180, 15689, 27215, 31902, 22461,
+ 13743, 7576, 12686, 24520, 28472, 10560, 24084, 768, 17780, 14368,
+ 2291, 22314, 14563, 17231, 5939, 31804, 15472, 14745, 9671, 8051,
+ 31803, 15148, 9836, 13472, 411, 15765, 17364, 22979, 22628, 11243,
+ 20740, 6362, 6501, 22346, 18427, 31739, 32309, 19331, 7060, 10145,
+ 25136, 23570, 24749, 28484, 21692, 32081, 4745, 6188, 8401, 15851,
+ 30323, 16006, 28088, 29842, 25252, 4280, 23826, 30197, 27751, 21746,
+ 18973, 26348, 16763, 27909, 3635, 32502, 12473, 19577, 28307, 20198,
+ 9718, 5337, 5988, 24537, 7467, 19538, 18423, 15979, 20692, 25213,
+ 5197, 17963, 10133, 30584, 24537, 16716, 9507, 6459, 30086, 12445,
+ 25186, 27433, 24828, 20411, 20683, 27622, 27935, 10628, 19729, 19817,
+ 27609, 20688, 17668, 4946, 11034, 4444, 29877, 27517, 15133, 11527,
+ 32475, 29911, 27116, 31041, 25717, 26736, 6182, 28864, 8113, 22738,
+ 19200, 3444, 26125, 31634, 8074, 32446, 21948, 12580, 820, 4061,
+ 4683, 16115, 21904, 21161, 5252, 28593, 22361, 25219, 12691, 3564,
+ 2741, 21388, 7527, 27875, 26807, 8725, 27739, 29591, 4136, 13911,
+ 22550, 24101, 20871, 20580, 19375, 10578, 15438, 28766, 31509, 23656,
+ 4471, 3815, 2479, 9537, 16191, 14808, 1087, 31393, 18986, 26934,
+ 12812, 14537, 18247, 8290, 320, 27720, 19381, 12175, 4751, 16149,
+ 30054, 10617, 10265, 15323, 28963, 24917, 31634, 23444, 8656, 1283,
+ 16288, 4441, 19698, 10123, 20612, 18552, 28782, 20423, 22525, 2248,
+ 9619, 24413, 26729, 13625, 13659, 26097, 21294, 6319, 16878, 13464,
+ 15960, 13585, 10600, 17807, 15748, 2204, 1500, 19501, 29180, 15742,
+ 28313, 278, 30243, 30624, 24236, 32434, 6164, 13507, 25766, 16861,
+ 10118, 29390, 32671, 8928, 23283, 4198, 19834, 23200, 4089, 7104,
+ 28267, 26646, 27392, 947, 16823, 27135, 6685, 24338, 24507, 16597,
+ 16182, 15928, 30000, 3325, 17767, 15076, 25517, 23874, 9637, 14920,
+ 19309, 8578, 24225, 5468, 25171, 13735, 9199, 7032, 15403, 6361,
+ 2152, 8994, 26675, 9459, 10189, 7461, 2010, 23091, 5037, 24035,
+ 17095, 4917, 1928, 4331, 15389, 13602, 10292, 2766, 27902, 12325,
+ 21120, 27951, 2126, 25630, 15640, 20762, 19385, 15771, 29096, 27543,
+ 25079, 7940, 24900, 24702, 14926, 27157, 6152, 14220, 31065, 15761,
+ 21499, 10167, 26377, 15157, 825, 11455, 32233, 27115, 27986, 6918,
+ 32678, 2113, 3053, 9633, 13006, 25369, 22193, 2735, 11736, 1186,
+ 1637, 23017, 21349, 20359, 4949, 2427, 25541, 23142, 29432, 19731,
+ 18365, 8067, 22737, 25399, 30855, 21694, 32403, 19675, 10523, 32706,
+ 14216, 9011, 5293, 6784, 21299, 32710, 5751, 23516, 4917, 10948,
+ 28344, 30885, 14445, 921, 22781, 28875, 27491, 22466, 22431, 15564,
+ 999, 7135, 22669, 28528, 29685, 15114, 5963, 8118, 23004, 28776,
+ 24635, 12046, 32159, 24317, 6428, 16328, 15772, 23493, 13008, 28621,
+ 11883, 7680, 26722, 11149, 29193, 18893, 28487, 11576, 2614, 2298,
+ 31972, 31793, 10779, 9755, 17745, 192, 19248, 24025, 22365, 7,
+ 2397, 23181, 31186, 5175, 2656, 3598, 28154, 29955, 29806, 24006,
+ 15201, 9301, 14365, 21772, 26845, 21312, 12673, 20910, 18124, 4919,
+ 25749, 24268, 11933, 10108, 22749, 12781, 23442, 2778, 22602, 32332,
+ 16579, 32151, 5470, 4723, 103, 12197, 31888, 29707, 26703, 23320,
+ 13554, 28147, 6067, 25309, 5137, 17551, 12849, 18856, 2333, 1123,
+ 17427, 5422, 17226, 7904, 15313, 29077, 6005, 18813, 7382, 10536,
+ 26891, 21258, 20359, 17488, 6695, 25409, 12930, 26047, 18170, 22687,
+ 20771, 14063, 20592, 14450, 25421, 30923, 31248, 25906, 31335, 3244,
+ 7973, 3860, 32676, 2438, 17179, 4829, 26504, 12644, 299, 15092,
+ 16040, 23313, 7995, 5820, 29617, 9240, 18431, 23584, 683, 32495,
+ 12389, 1904, 25983, 29040, 11312, 11627, 28087, 6024, 30178, 13213,
+ 27526, 15923, 11744, 25323, 17928, 10920, 21713, 2156, 26826, 25040,
+ 17735, 6266, 10893, 1021, 28833, 2057, 4423, 4313, 25392, 20536,
+ 5995, 10141, 21400, 20518, 22122, 6019, 16761, 263, 14970, 21629,
+ 26447, 12407, 9110, 9255, 919, 13581, 6086, 5882, 15668, 20788,
+ 27296, 8643, 10000, 14390, 32271, 27476, 9990, 27034, 83, 8826,
+ 17408, 22192, 19273, 28719, 8028, 1642, 18669, 23056, 7573, 11117,
+ 285, 10513, 543, 24680, 13472, 10351, 658, 32421, 10598, 20710,
+ 5387, 17118, 3089, 13349, 32207, 13393, 2741, 15487, 24626, 534,
+ 3292, 5347, 22200, 19121, 11470, 19726, 22137, 484, 22031, 3583,
+ 25034, 26823, 11560, 29355, 19993, 19482, 9386, 22771, 8473, 31961,
+ 25457, 16083, 18720, 14097, 24614, 32732, 13517, 27379, 22023, 1764,
+ 3565, 7206, 30443, 18428, 7071, 19298, 32384, 5794, 4023, 7739,
+ 2776, 11320, 17249, 14650, 24100, 29365, 9991, 50, 28095, 26523,
+ 26996, 12497, 25198, 11049, 6713, 2934, 28134, 4049, 19279, 32322,
+ 6542, 15852, 30207, 1650, 29319, 16301, 9983, 15340, 14058, 2387,
+ 13790, 15127, 26704, 20899, 2977, 24816, 26520, 20118, 15535, 3419,
+ 32228, 10831, 31210, 24502, 30437, 17487, 7455, 8628, 12377, 4844,
+ 21664, 21609, 17105, 14591, 12847, 5025, 10168, 9182, 8478, 17270,
+ 145, 17802, 1973, 15394, 25472, 16169, 6100, 26641, 20748, 4022,
+ 4825, 2107, 14115, 6903, 1220, 4784, 9566, 7343, 15002, 24436,
+ 5767, 23574, 30727, 6030, 29529, 13190, 12358, 6748, 12934, 16503,
+ 17990, 19753, 14847, 20397, 6149, 2305, 25967, 22960, 22848, 6852,
+ 22024, 9085, 335, 2426, 28547, 22395, 20555, 5862, 9826, 10928,
+ 12145, 11870, 889, 25141, 28875, 13786, 172, 19687, 12813, 30026,
+ 8954, 1376, 26301, 2093, 30139, 4134, 19862, 3423, 19237, 10785,
+ 21807, 2354, 26133, 23379, 13272, 11713, 28941, 8643, 14020, 32129,
+ 26232, 18618, 3182, 31769, 20022, 16434, 3637, 24948, 29780, 2188,
+ 19785, 788, 32027, 1665, 26315, 26537, 31309, 21339, 25392, 14562,
+ 26027, 23909, 9447, 1923, 9402, 27808, 10811, 5560, 31175, 24503,
+ 9850, 7080, 1577, 13621, 13911, 14926, 16838, 13558, 13197, 4228,
+ 3033, 19931, 27589, 9825, 14578, 31682, 16058, 8901, 16958, 18870,
+ 26523, 32562, 31240, 17506, 30129, 11742, 27008, 28876, 14401, 26118,
+ 15291, 6976, 8628, 2692, 23036, 4745, 26101, 24228, 7474, 9064,
+ 22555, 32052, 14529, 26686, 19272, 17882, 17029, 16652, 31440, 13483,
+ 31764, 1949, 15774, 22520, 16708, 21506, 2260, 22635, 16366, 25919,
+ 1458, 18259, 23793, 580, 16057, 10045, 27257, 26399, 10256, 25284,
+ 4993, 4719, 1830, 9642, 8342, 1820, 32153, 19495, 31198, 22085,
+ 15191, 23680, 2650, 1402, 7171, 16092, 26728, 9516, 13210, 10068,
+ 26508, 11105, 3670, 26185, 30575, 26284, 10194, 4858, 29736, 7517,
+ 23920, 17493, 19387, 11509, 24568, 19470, 7391, 15837, 26753, 10223,
+ 13061, 24407, 13461, 7535, 917, 8116, 3472, 13189, 4219, 29896,
+ 24393, 32446, 21474, 2203, 8692, 29582, 6463, 15969, 6983, 13027,
+ 26514, 940, 15068, 1280, 24809, 16865, 5591, 30345, 15141, 1000,
+ 17864, 19418, 13824, 9256, 11987, 16029, 12879, 5811, 28942, 14748,
+ 20101, 9149, 2346, 1747, 11385, 9811, 25686, 9162, 17513, 9034,
+ 27488, 12322, 26942, 19573, 18717, 10861, 25105, 17435, 28684, 28483,
+ 15599, 13479, 9014, 11922, 16089, 4258, 1624, 19253, 5391, 3807,
+ 31044, 22728, 11151, 14069, 17029, 11195, 19672, 4594, 19778, 12198,
+ 28403, 21326, 32357, 30684, 20916, 3614, 25851, 15939, 21054, 19082,
+ 18910, 17507, 6085, 3969, 25234, 19132, 32152, 13484, 11118, 4701,
+ 24158, 4256, 11516, 7346, 9375, 22359, 12450, 7582, 17543, 15585,
+ 10369, 21449, 743, 12375, 20125, 15164, 11645, 17169, 16190, 20011,
+ 10357, 4120, 4759, 18449, 29999, 14302, 14758, 7939, 5699, 17453,
+ 8795, 10045, 29891, 2142, 26364, 5378, 10944, 20939, 3272, 20643,
+ 22287, 31879, 5595, 20701, 24140, 16460, 27217, 28519, 15648, 18868,
+ 23726, 27596, 20416, 29612, 19838, 4215, 12982, 13606, 12856, 11788,
+ 8420, 5903, 872, 24831, 29382, 18049, 22029, 21855, 8951, 5945,
+ 9280, 31986, 31735, 2635, 2327, 27527, 21291, 11540, 29641, 19848,
+ 29989, 25713, 5651, 11471, 10022, 30766, 4570, 30650, 25057, 29378,
+ 10769, 32386, 10626, 10553, 31453, 23240, 9967, 32625, 31991, 30065,
+ 26190, 15497, 22611, 7860, 24263, 919, 18943, 27761, 10123, 17561,
+ 8525, 21189, 32277, 14767, 6196, 10971, 432, 17543, 2804, 7173,
+ 18489, 16408, 21241, 6923, 12326, 6803, 18690, 29635, 5063, 19350,
+ 12930, 4321, 16844, 31395, 7750, 30225, 24328, 27090, 29785, 8259,
+ 5492, 30914, 15653, 16454, 13431, 21461, 25562, 921, 9828, 9117,
+ 30740, 24446, 24389, 20625, 12984, 4687, 10455, 12037, 16926, 20245,
+ 28629, 10073, 8566, 18263, 30329, 11888, 32612, 1840, 4161, 8803,
+ 30702, 22436, 19183, 24439, 9624, 6964, 10451, 8525, 19917, 22704,
+ 20556, 1113, 11393, 26701, 21645, 15253, 8981, 30456, 31645, 20087,
+ 20091, 21481, 9633, 29472, 18586, 15482, 14686, 22742, 6388, 6714,
+ 14842, 30388, 6278, 26429, 27138, 12960, 19695, 11447, 8114, 29822,
+ 32469, 20425, 11888, 31139, 3973, 8347, 2457, 31885, 20953, 24491,
+ 1152, 1233, 27231, 11621, 21428, 29524, 31415, 6131, 13186, 7870,
+ 7229, 15190, 22459, 5164, 28137, 10166, 2232, 20518, 14707, 502,
+ 4506, 976, 29626, 4748, 25558, 14948, 7270, 13968, 5106, 29407,
+ 16588, 26386, 5001, 507, 9747, 19121, 19605, 20574, 24213, 1385,
+ 494, 18705, 20104, 15021, 6413, 3123, 25566, 30134, 12566, 14831,
+ 1385, 27674, 11030, 27051, 32067, 20128, 1928, 8578, 25197, 7251,
+ 15647, 25077, 17846, 11221, 27839, 6621, 9695, 24310, 5836, 5796,
+ 28412, 13445, 13736, 17589, 2333, 11367, 24951, 21553, 14894, 12773,
+ 24870, 5604, 24348, 74, 19627, 9335, 16442, 13742, 9358, 11751,
+ 1250, 2061, 680, 28982, 2655, 20636, 18475, 17504, 8714, 24924,
+ 27874, 13968, 31412, 22767, 21434, 8852, 14660, 26795, 18562, 17806,
+ 1185, 16621, 2799, 11757, 2259, 6063, 2787, 5788, 13669, 32093,
+ 14830, 633, 15117, 29669, 5654, 11273, 3215, 31758, 20947, 7530,
+ 26334, 3338, 15710, 1161, 9348, 10830, 21803, 6037, 24645, 2977,
+ 6580, 7603, 11007, 2931, 5241, 28659, 22741, 20337, 11845, 1666,
+ 10636, 24406, 15026, 26146, 20533, 7684, 23791, 472, 7693, 22739,
+ 10689, 25828, 21665, 24873, 10952, 14582, 25398, 25675, 9988, 31903,
+ 4967, 30066, 21656, 32262, 26896, 32290, 22477, 28124, 14699, 2231,
+ 13145, 7826, 15737, 6465, 3554, 17353, 9124, 2193, 28862, 17930,
+ 25762, 5524, 25597, 32439, 24476, 8416, 2985, 28737, 400, 18061,
+ 10828, 20124, 31732, 19014, 11443, 27632, 20124, 2463, 8946, 23954,
+ 10461, 26793, 19112, 27954, 26099, 27845, 3716, 10838, 10400, 31157,
+ 7944, 12295, 23062, 25849, 2189, 29385, 4119, 21336, 27272, 10961,
+ 7771, 5309, 13323, 11891, 22322, 29252, 2447, 20698, 16234, 8853,
+ 14320, 6395, 14707, 22641, 22713, 25803, 27585, 8074, 2978, 19632,
+ 26226, 31640, 26967, 23350, 19505, 32169, 4987, 27908, 602, 17336,
+ 1517, 19726, 11358, 5762, 3402, 24844, 30314, 6549, 1715, 31274,
+ 29507, 16810, 19664, 7681, 4469, 1332, 30228, 23494, 27564, 31545,
+ 18499, 449, 30818, 23649, 1330, 18177, 23738, 6733, 29903, 15695,
+ 26284, 297, 20576, 8032, 29283, 6021, 29456, 20303, 16099, 12384,
+ 29607, 6474, 30191, 25478, 2969, 3723, 27434, 24605, 28482, 3209,
+ 22140, 19834, 31600, 17520, 3511, 11833, 23586, 22223, 379, 31116,
+ 4239, 22417, 343, 24275, 28778, 20015, 2864, 26477, 5733, 1572,
+ 10727, 27342, 21492, 17312, 10038, 2258, 4691, 12416, 5339, 7761,
+ 17610, 5502, 28921, 26612, 20528, 13221, 27067, 18247, 2990, 21001,
+ 1082, 24079, 16069, 21428, 10913, 29661, 16530, 27107, 25999, 23011,
+ 7249, 13939, 17596, 16647, 24353, 29334, 15072, 13878, 29446, 28106,
+ 28880, 14587, 11060, 30988, 21482, 8272, 25995, 4680, 25524, 16820,
+ 25950, 25621, 704, 3709, 19320, 28063, 20179, 7024, 20321, 26340,
+ 17477, 18063, 7645, 13604, 12459, 28466, 182, 914, 14516, 29785,
+ 13243, 21584, 30033, 27969, 2825, 7578, 27673, 20533, 20105, 18242,
+ 26347, 31655, 28346, 7260, 28373, 21887, 30385, 1338, 28212, 29875,
+ 24414, 7579, 15901, 2328, 10256, 31519, 8956, 30072, 22587, 14334,
+ 31867, 20452, 20090, 5626, 11430, 15435, 208, 19858, 31308, 21836,
+ 4659, 23929, 29352, 5961, 24907, 28230, 3648, 445, 29815, 7789,
+ 7438, 25295, 26385, 19054, 15838, 295, 15347, 9548, 25847, 6144,
+ 14649, 13633, 13821, 22910, 12617, 2224, 13590, 27458, 23825, 14171,
+ 4940, 4413, 11152, 982, 6707, 31425, 10904, 12604, 31435, 26078,
+ 27858, 24864, 935, 3307, 4354, 3526, 591, 4707, 20108, 29843,
+ 21476, 24307, 11064, 1219, 26882, 9680, 15922, 9818, 16618, 846,
+ 9301, 27997, 8161, 27055, 2472, 3393, 1235, 20536, 27689, 8356,
+ 8764, 22667, 31690, 6459, 24137, 24112, 15290, 27660, 7738, 9333,
+ 18661, 19933, 24842, 5752, 27070, 5100, 27986, 19842, 19260, 3296,
+ 5739, 20886, 3874, 26112, 23762, 18506, 3972, 28835, 28113, 1494,
+ 31623, 23527, 18012, 13419, 12648, 13990, 32058, 1478, 31168, 19878,
+ 30821, 8964, 2054, 14864, 4530, 20152, 25685, 13348, 28340, 27963,
+ 8815, 32298, 4062, 26435, 2563, 31660, 23273, 6839, 5163, 18658,
+ 9333, 19906, 25145, 26222, 31987, 22567, 4531, 19786, 17602, 30420,
+ 4508, 32510, 19352, 32185, 23797, 26134, 32548, 23514, 16004, 6867,
+ 27890, 9635, 468, 24609, 7054, 6524, 13693, 27849, 32492, 21150,
+ 25253, 21736, 3079, 7717, 24007, 10144, 12233, 9830, 5300, 5389,
+ 11563, 26754, 32215, 12410, 9885, 10300, 3260, 8917, 22184, 22023,
+ 20436, 24929, 15314, 7011, 7026, 15531, 15298, 362, 26138, 23487,
+ 420, 26022, 14843, 30619, 7119, 12582, 24506, 27364, 7333, 1489,
+ 9841, 27096, 17083, 22010, 27896, 30340, 27707, 6708, 20579, 25911,
+ 22918, 6503, 9163, 1334, 797, 30499, 5458, 16817, 1729, 31797,
+ 9313, 20214, 28633, 19832, 19764, 14309, 24341, 1262, 3481, 24484,
+ 21841, 24847, 9972, 19348, 9660, 32353, 16775, 18819, 21305, 20297,
+ 21744, 17955, 23813, 17953, 31219, 26554, 16026, 25994, 2426, 16668,
+ 9940, 11012, 11482, 12503, 10835, 1980, 17240, 16557, 29984, 23460,
+ 16620, 6471, 16275, 9929, 27205, 24103, 2676, 25826, 4620, 1503,
+ 26208, 18212, 15213, 640, 19054, 16478, 17876, 20054, 15891, 5953,
+ 1524, 12498, 23107, 29439, 28686, 20424, 26073, 5657, 14192, 24795,
+ 4409, 15217, 1852, 3893, 5428, 18855, 14442, 27003, 14636, 20642,
+ 10512, 27647, 1144, 1389, 6369, 31544, 7945, 12357, 12020, 25200,
+ 9550, 16624, 3272, 10941, 29526, 32080, 4740, 24114, 11061, 32311,
+ 14467, 2902, 31400, 28285, 8719, 7381, 25596, 16464, 19821, 22902,
+ 3627, 19660, 1307, 8269, 24649, 4555, 30293, 13618, 27678, 511,
+ 4317, 12658, 27669, 6974, 5116, 27844, 22613, 14108, 27844, 29310,
+ 22317, 18879, 18841, 22280, 3253, 751, 1776, 401, 3506, 1389,
+ 22869, 15874, 31163, 10374, 22707, 11056, 154, 30695, 20688, 22870,
+ 22261, 26035, 31511, 11458, 24110, 25299, 1434, 22734, 903, 20878,
+ 2903, 1810, 6794, 1625, 25018, 32472, 13992, 19184, 24420, 24784,
+ 18464, 6053, 43, 19206, 34, 30456, 2658, 30992, 16436, 18281,
+ 6490, 13452, 6358, 20362, 12584, 10698, 7009, 22616, 16297, 29893,
+ 821, 16843, 11972, 31320, 31251, 17836, 27631, 25006, 31688, 23719,
+ 2293, 16891, 7436, 31137, 23030, 22633, 14761, 3916, 13487, 23126,
+ 19936, 5112, 13563, 14268, 32520, 30636, 10906, 25072, 6008, 16501,
+ 5170, 27280, 31143, 16638, 19347, 3766, 20114, 7521, 18239, 626,
+ 29534, 4669, 5418, 4216, 27199, 12809, 29374, 25109, 21144, 3239,
+ 9762, 872, 11364, 30012, 31932, 30670, 27348, 23104, 4853, 29342,
+ 6713, 25553, 18748, 2071, 7461, 19533, 2637, 27286, 17613, 10015,
+ 18099, 2060, 18610, 2521, 18827, 7088, 24961, 19332, 19084, 2033,
+ 2871, 20019, 24900, 3247, 12936, 1759, 15780, 11690, 20866, 14190,
+ 18879, 23867, 16238, 3861, 6351, 16194, 14327, 9440, 18297, 6239,
+ 23950, 143, 12626, 15717, 15116, 9636, 8097, 5899, 2201, 21690,
+ 21863, 3557, 14285, 30488, 7324, 29331, 2838, 26758, 14524, 13881,
+ 15450, 4960, 25218, 1839, 30429, 4840, 12531, 9721, 10340, 20448,
+ 5023, 1657, 28059, 19289, 16932, 4451, 7604, 3014, 17651, 6642,
+ 14673, 24660, 31575, 23513, 16548, 28286, 17075, 5501, 13524, 15835,
+ 8971, 4705, 18595, 13883, 9413, 14817, 1103, 17395, 13233, 30244,
+ 24757, 5749, 13128, 1868, 7612, 11556, 10289, 5871, 22513, 9830,
+ 6922, 8139, 8559, 1274, 6244, 32181, 8706, 24460, 29199, 14803,
+ 652, 11910, 9625, 26379, 10151, 11306, 3089, 8891, 32651, 31454,
+ 14096, 3499, 26419, 1478, 7931, 20800, 27323, 20376, 1666, 1266,
+ 25869, 9132, 14188, 2047, 17084, 23891, 31895, 9057, 27696, 14698,
+ 32058, 2046, 6916, 26159, 23918, 32032, 7852, 17747, 18413, 21284,
+ 21595, 5200, 17689, 28278, 22051, 28412, 832, 32445, 9567, 24670,
+ 29726, 13906, 21582, 30145, 25507, 5623, 29440, 2056, 27639, 8390,
+ 17270, 12097, 27324, 3175, 30981, 5245, 23443, 16774, 1787, 5598,
+ 15329, 16516, 17029, 28913, 23507, 15981, 23504, 26430, 16543, 3627,
+ 29295, 4382, 31757, 10745, 18685, 21197, 7479, 28954, 23555, 10176,
+ 7820, 28106, 24603, 14393, 29979, 14197, 27478, 27928, 9487, 17703,
+ 19932, 30196, 32629, 17476, 24018, 30058, 27974, 18297, 14977, 18357,
+ 27553, 25074, 19124, 6015, 7512, 717, 31329, 13559, 5550, 9423,
+ 31628, 25380, 16479, 9814, 3689, 3961, 2785, 23951, 5313, 10153,
+ 13034, 15593, 29846, 445, 24114, 7114, 3594, 2659, 24442, 30592,
+ 18557, 11657, 19661, 16506, 31478, 11562, 19206, 1976, 13252, 23144,
+ 12946, 8320, 9061, 25820, 29047, 2643, 11942, 13354, 20117, 14111,
+ 27660, 32728, 29228, 438, 4211, 6496, 22431, 26751, 3829, 7299,
+ 3192, 24683, 28685, 31201, 24747, 21547, 9212, 4039, 27679, 9121,
+ 21612, 17736, 3434, 14228, 31060, 23439, 17885, 32167, 13595, 26995,
+ 5824, 24716, 15360, 13644, 17374, 4213, 19129, 24837, 8005, 12235,
+ 28762, 7283, 16967, 14371, 12153, 20965, 22468, 11118, 14992, 253,
+ 23468, 25967, 20386, 15294, 29631, 8563, 30498, 31205, 17815, 2108,
+ 10768, 13949, 28137, 23102, 9061, 2990, 32008, 2574, 24753, 16598,
+ 7338, 23319, 5635, 32475, 17135, 22671, 6409, 7871, 5791, 14505,
+ 1912, 18036, 26803, 12, 11438, 18418, 26392, 31109, 27287, 30344,
+ 27823, 22008, 10701, 26223, 4760, 2205, 5379, 19109, 26288, 13160,
+ 9123, 25848, 27480, 14281, 14262, 15457, 17529, 16278, 21253, 3476,
+ 13765, 21062, 10109, 10709, 22079, 19039, 1752, 14349, 7421, 16177,
+ 30074, 3101, 11052, 14021, 25753, 2162, 30550, 13329, 22433, 15834,
+ 15840, 30061, 30935, 15766, 23255, 30539, 24892, 20912, 28908, 3874,
+ 6068, 3983, 444, 12971, 2919, 30920, 23381, 16208, 3432, 7735,
+ 32502, 21986, 3477, 31055, 25879, 7818, 7870, 28590, 17065, 2306,
+ 1545, 13556, 13215, 23812, 22932, 32470, 28333, 12035, 29277, 16238,
+ 26192, 3354, 13663, 22997, 31502, 30786, 30718, 1268, 8959, 32199,
+ 933, 20631, 10892, 1277, 31918, 195, 29303, 9519, 12418, 13130,
+ 20252, 6104, 3841, 924, 27894, 6933, 21284, 8416, 24164, 22619,
+ 7904, 2628, 13997, 9061, 3662, 26001, 22082, 9585, 1546, 9218,
+ 19524, 18604, 16601, 26966, 28998, 30699, 24718, 26916, 8020, 1691,
+ 1582, 11887, 11060, 21755, 13650, 378, 747, 1161, 1741, 24541,
+ 5508, 20665, 28303, 15065, 26636, 24557, 6345, 28649, 31713, 8354,
+ 8786, 12185, 27181, 1767, 12362, 18075, 22701, 15892, 11005, 32024,
+ 11191, 8888, 8201, 68, 6523, 6355, 4036, 2613, 649, 4678,
+ 10712, 15349, 13203, 22919, 15664, 24022, 29812, 29849, 24344, 31237,
+ 2162, 13372, 3487, 1378, 960, 17249, 20800, 2703, 6727, 19168,
+ 8642, 2887, 19367, 32109, 4701, 3058, 4216, 8137, 2334, 32118,
+ 27861, 24885, 1421, 31055, 3099, 6188, 14988, 994, 18926, 14161,
+ 32642, 18702, 19581, 3751, 23737, 1797, 5127, 11520, 14085, 7002,
+ 9119, 30136, 24231, 26203, 10028, 16034, 1392, 30880, 15027, 2627,
+ 24618, 16100, 14041, 12862, 30515, 8212, 9891, 5648, 27243, 16806,
+ 19073, 8701, 11344, 26156, 19595, 16970, 30824, 6697, 2570, 5805,
+ 2272, 8995, 5690, 31234, 20338, 25849, 23118, 12863, 13708, 12663,
+ 30389, 23722, 10158, 13864, 18844, 27210, 28691, 31851, 16052, 16539,
+ 9365, 12233, 19509, 21126, 11211, 7814, 16675, 17807, 7540, 10358,
+ 18640, 30545, 536, 4114, 18338, 30503, 13804, 25035, 29974, 18477,
+ 29431, 26015, 22277, 32615, 18035, 20201, 550, 4671, 30070, 7805,
+ 17365, 26933, 5329, 27380, 6418, 2770, 22584, 837, 5837, 29405,
+ 23716, 8086, 10081, 27090, 29174, 5201, 16734, 28816, 10205, 15225,
+ 31627, 5202, 8697, 2111, 8747, 16096, 30529, 30928, 12672, 22279,
+ 8354, 23154, 22926, 17734, 15080, 5071, 28449, 12490, 8162, 27024,
+ 28177, 2205, 6849, 28974, 28869, 11546, 15298, 9733, 16630, 19876,
+ 3853, 21675, 26037, 20119, 15068, 20607, 21168, 19327, 18655, 10117,
+ 7345, 2440, 7904, 18545, 22375, 28214, 27299, 20225, 105, 20054,
+ 1296, 27280, 7032, 10549, 4243, 4841, 25604, 9231, 22212, 32601,
+ 14322, 22986, 10563, 5128, 8093, 21220, 18918, 14728, 5915, 14763,
+ 7703, 21167, 31937, 7852, 12663, 17570, 18665, 24941, 19400, 17715,
+ 29426, 4447, 7689, 25453, 10121, 23310, 19170, 32364, 13351, 21915,
+ 20035, 7795, 19419, 17516, 2121, 25656, 2378, 8482, 28513, 642,
+ 20980, 459, 11695, 30198, 32441, 12121, 11697, 28462, 28059, 84,
+ 23071, 8972, 24773, 19403, 5398, 30030, 20173, 2192, 10870, 12642,
+ 2102, 27813, 16777, 17787, 22073, 8433, 4581, 13284, 30404, 23863,
+ 24467, 11925, 6596, 73, 624, 4356, 17312, 30841, 31956, 11325,
+ 14597, 4177, 25970, 6453, 22505, 29572, 10367, 1371, 458, 35,
+ 25623, 11633, 31543, 14356, 25564, 31386, 25746, 26305, 32736, 30132,
+ 12308, 20237, 25285, 1255, 14609, 30092, 31522, 10110, 24702, 23283,
+ 7209, 9206, 21168, 15053, 4487, 23637, 23142, 8816, 10892, 15550,
+ 25866, 29744, 140, 30785, 7220, 10962, 31877, 2039, 14448, 28996,
+ 24577, 8271, 28993, 25227, 21822, 4259, 11878, 1532, 19085, 16655,
+ 24155, 23471, 7416, 17026, 5667, 3377, 22055, 9493, 24133, 5753,
+ 389, 2204, 20757, 31517, 23710, 7035, 28212, 23494, 26315, 31676,
+ 18266, 32738, 5138, 11870, 27219, 10136, 10056, 8431, 11336, 14849,
+ 30584, 26973, 14912, 9109, 9353, 14345, 4838, 30947, 32538, 12317,
+ 19853, 12678, 10161, 6688, 21105, 3924, 10517, 9415, 26688, 1496,
+ 4600, 10254, 15065, 13827, 20953, 7816, 16211, 21022, 23849, 18675,
+ 6465, 32259, 23725, 12304, 25908, 32653, 27683, 30898, 3202, 21325,
+ 11304, 15892, 1606, 31102, 11097, 26223, 10664, 3899, 27321, 9676,
+ 30047, 2032, 339, 8983, 28788, 6927, 8992, 29558, 2120, 14852,
+ 3882, 24537, 4056, 8810, 10482, 10449, 17472, 24703, 16655, 15525,
+ 31358, 21973, 20761, 5027, 23161, 6219, 11973, 9908, 19266, 15676,
+ 31313, 13363, 29849, 25846, 19491, 18175, 31155, 6766, 26029, 13263,
+ 20794, 23346, 27027, 198, 24214, 23454, 24336, 27464, 12395, 23379,
+ 1174, 11, 2146, 7653, 13748, 31089, 4141, 23508, 26685, 22549,
+ 24517, 16318, 1191, 27043, 14582, 17362, 7601, 12782, 7198, 904,
+ 19272, 27196, 6706, 21903, 11436, 2788, 2049, 16903, 21967, 4892,
+ 30397, 10481, 11262, 780, 5559, 11492, 30146, 15399, 24938, 13825,
+ 8713, 15290, 17339, 8489, 2689, 25541, 2431, 28525, 13637, 17931,
+ 20798, 2501, 22971, 9573, 22326, 27909, 11452, 8539, 17059, 21006,
+ 14326, 16373, 22590, 9793, 16527, 18895, 13828, 26682, 267, 11372,
+ 31800, 15546, 14960, 22220, 1963, 20452, 24744, 17473, 8507, 22189,
+ 26150, 10622, 18074, 17550, 27341, 30705, 28753, 2427, 21005, 11091,
+ 30980, 27673, 1103, 5501, 2551, 21548, 24467, 7293, 12497, 6478,
+ 6999, 7913, 672, 10727, 9147, 29299, 28702, 7769, 12260, 12478,
+ 12083, 3195, 6046, 18032, 23994, 12105, 11333, 30857, 16776, 14042,
+ 6373, 21491, 18858, 21650, 3488, 15193, 13551, 22424, 14928, 1853,
+ 423, 28042, 23662, 27717, 2729, 23408, 25651, 7126, 30107, 17135,
+ 29948, 21220, 22125, 18368, 17651, 19209, 11303, 10592, 8172, 16852,
+ 6885, 9480, 4493, 2659, 1823, 13279, 31410, 23860, 30254, 31087,
+ 5647, 23096, 22540, 30293, 12312, 28969, 7772, 21309, 5661, 9246,
+ 17578, 22542, 186, 22621, 11763, 25442, 32110, 10608, 31592, 30265,
+ 7050, 29307, 16495, 10222, 24653, 460, 14315, 5738, 17997, 10932,
+ 24253, 9879, 19480, 10645, 6027, 10519, 22044, 3645, 15295, 14135,
+ 26564, 8306, 15827, 23582, 30692, 29390, 16589, 24139, 25687, 6094,
+ 18693, 15678, 18663, 11557, 27182, 14196, 15724, 12630, 5780, 27801,
+ 16184, 22401, 29603, 28666, 18867, 19837, 22441, 24377, 25155, 10280,
+ 21725, 20804, 7023, 27131, 30111, 12679, 21315, 22498, 3585, 23393,
+ 12534, 4170, 18055, 2517, 9674, 6267, 17451, 28547, 30004, 21544,
+ 4516, 2774, 2109, 6980, 11752, 2686, 4136, 25112, 25584, 22049,
+ 15445, 10131, 20411, 3917, 1893, 7649, 13461, 7858, 24479, 16703,
+ 2201, 8590, 11922, 20749, 22901, 19304, 1020, 24356, 28269, 4097,
+ 26603, 26987, 19363, 10632, 6178, 12709, 31381, 20237, 13502, 18317,
+ 15335, 12088, 8218, 31013, 1635, 827, 5615, 7499, 30526, 19973,
+ 15808, 27789, 6044, 7096, 15477, 23614, 6999, 21854, 2374, 12233,
+ 31996, 31960, 2522, 13382, 6935, 25878, 14768, 23115, 15025, 14990,
+ 24767, 8709, 4886, 28646, 7513, 3463, 18140, 25332, 17749, 3425,
+ 28192, 19945, 25197, 7029, 5651, 22729, 19941, 30726, 22966, 24351,
+ 12142, 15634, 30689, 15854, 25417, 15330, 2698, 15850, 2991, 22751,
+ 17220, 28136, 20849, 22951, 20742, 404, 6108, 22880, 21294, 2146,
+ 10207, 22349, 32197, 4295, 5744, 5022, 21253, 2984, 27179, 11917,
+ 5656, 1043, 17468, 15782, 23331, 32557, 4224, 19302, 22659, 6251,
+ 231, 29960, 23895, 11781, 22557, 6812, 4414, 12712, 18281, 21849,
+ 24930, 29036, 25557, 10292, 16053, 27909, 30351, 7858, 4474, 2877,
+ 11407, 19962, 1544, 17314, 27002, 27694, 5834, 4219, 16838, 29179,
+ 30603, 15617, 24608, 31343, 17904, 25548, 23050, 21771, 9030, 12684,
+ 14281, 32282, 7038, 16377, 13182, 28993, 32118, 7437, 29587, 2646,
+ 2171, 21104, 17496, 26741, 4875, 308, 5358, 1873, 3807, 26050,
+ 15205, 713, 3625, 22548, 17441, 14524, 11802, 7205, 20610, 15645,
+ 2727, 5798, 18628, 21578, 8077, 14835, 25891, 26521, 14994, 16197,
+ 21059, 10292, 25358, 41, 29904, 21544, 23211, 1073, 4193, 20920,
+ 7017, 5865, 21923, 5367, 30437, 31244, 7091, 918, 15066, 2040,
+ 18635, 19194, 32488, 23136, 11809, 23697, 32660, 18753, 23308, 1127,
+ 10897, 22039, 11113, 19956, 16446, 22352, 5437, 11065, 11887, 30721,
+ 31132, 4619, 2160, 24536, 31945, 942, 16455, 5970, 10654, 12965,
+ 1338, 31789, 25646, 15049, 27537, 23073, 28586, 8089, 16797, 31691,
+ 2945, 1233, 13817, 18410, 27595, 21822, 13072, 16077, 4328, 19408,
+ 5087, 27660, 16996, 4849, 5629, 8311, 12574, 28181, 11480, 2124,
+ 1194, 8594, 6721, 29101, 22515, 3251, 28715, 22352, 26917, 10759,
+ 24495, 889, 202, 27135, 31060, 24357, 21555, 7096, 17038, 16776,
+ 26393, 22550, 17540, 21434, 12420, 8978, 30742, 23726, 1772, 14165,
+ 13087, 2403, 6046, 12293, 31479, 1374, 28002, 1247, 24637, 30551,
+ 19035, 3206, 18387, 13875, 22830, 31002, 17705, 18994, 31079, 781,
+ 27071, 3690, 11032, 13874, 11749, 1652, 24002, 5399, 22214, 15461,
+ 9849, 1685, 32164, 15103, 8516, 16805, 7269, 30761, 451, 11125,
+ 17231, 17309, 5908, 23484, 23568, 3553, 18166, 15178, 7681, 7032,
+ 17455, 28899, 6059, 30809, 1068, 4173, 29067, 16288, 14312, 16296,
+ 19986, 2948, 19471, 18174, 27376, 8585, 13410, 15899, 26514, 12022,
+ 1629, 19615, 21737, 10634, 10007, 12369, 29294, 10347, 4203, 32182,
+ 15459, 18783, 29013, 20195, 12123, 30270, 11678, 21647, 25852, 7848,
+ 188, 32108, 28164, 14835, 18420, 10168, 3466, 9575, 14273, 4366,
+ 14727, 12974, 121, 30851, 1172, 31366, 9774, 9966, 21749, 18361,
+ 4050, 20871, 3287, 11855, 4511, 2740, 2006, 8962, 30390, 13599,
+ 4546, 9970, 19975, 11532, 15011, 23450, 32368, 7146, 11258, 4867,
+ 26153, 10791, 25418, 12343, 2399, 841, 30167, 27641, 5151, 24635,
+ 16814, 20915, 13174, 3044, 12261, 2224, 2519, 5630, 27684, 15755,
+ 17084, 10278, 13669, 16360, 2448, 12591, 11255, 10337, 26573, 23228,
+ 16585, 6852, 20066, 32014, 10725, 30843, 20055, 1306, 59, 5963,
+ 17587, 223, 27296, 20546, 32158, 17910, 31254, 31466, 4803, 26219,
+ 6990, 10435, 2296, 26571, 16747, 13552, 28961, 28798, 11785, 31793,
+ 4177, 24407, 31358, 20753, 21299, 362, 18015, 97, 4265, 23070,
+ 12103, 31204, 24498, 12675, 30163, 29004, 1169, 23781, 29681, 2917,
+ 14636, 30113, 18523, 27537, 21682, 29239, 23390, 13684, 5760, 21921,
+ 8416, 22256, 6214, 26851, 15265, 11860, 11109, 13028, 26049, 24784,
+ 9628, 8828, 17027, 29997, 24804, 7886, 32080, 1722, 29336, 29144,
+ 23039, 9354, 24025, 16712, 6739, 12508, 17713, 2449, 23749, 21723,
+ 24438, 20287, 22660, 23688, 13298, 31367, 6843, 3828, 25024, 4387,
+ 10514, 22194, 30329, 16989, 11639, 20108, 6161, 31081, 3870, 1653,
+ 1531, 27127, 7366, 5311, 13716, 19209, 11327, 18318, 3518, 13314,
+ 21289, 2701, 1483, 20480, 7422, 21727, 11166, 23404, 25171, 13145,
+ 21772, 8144, 9562, 17134, 136, 25064, 6060, 12138, 10496, 30203,
+ 11589, 2660, 4354, 28267, 24784, 3693, 18723, 6284, 3366, 8846,
+ 30113, 15282, 17, 12786, 5959, 20110, 10837, 11231, 23441, 5818,
+ 4337, 16363, 14353, 26258, 25506, 10860, 21777, 27974, 23721, 9520,
+ 2938, 19757, 19918, 20590, 31221, 27740, 32421, 10237, 30031, 13176,
+ 16400, 22724, 22562, 11976, 22789, 2674, 30130, 17806, 12433, 29039,
+ 13333, 31640, 22813, 15634, 4503, 28946, 24817, 13844, 6492, 5278,
+ 3062, 8516, 2887, 15271, 23232, 14973, 15131, 5361, 715, 23509,
+ 27360, 10613, 15365, 9496, 9353, 24429, 1933, 14197, 22227, 13227,
+ 21435, 22902, 14704, 7470, 8544, 5942, 15461, 20215, 3663, 13006,
+ 1713, 19481, 26908, 30992, 18479, 528, 12835, 20088, 25277, 23891,
+ 11724, 2143, 11934, 3117, 27662, 26226, 24093, 25544, 26930, 16483,
+ 17523, 7051, 11226, 15326, 1003, 21157, 1089, 7871, 26436, 5098,
+ 20676, 4482, 27223, 19423, 27554, 26106, 13818, 25872, 9728, 13894,
+ 4899, 32426, 29744, 28674, 6481, 28997, 12082, 8122, 7207, 5634,
+ 3963, 4260, 7258, 982, 17654, 5262, 16334, 14117, 20553, 2069,
+ 5372, 22419, 345, 26392, 9623, 4119, 16144, 1388, 7279, 11601,
+ 31838, 16337, 661, 30237, 32381, 14629, 22464, 29288, 22650, 30680,
+ 2543, 5186, 16369, 30624, 4176, 30517, 7960, 878, 11617, 10709,
+ 2046, 27552, 7253, 13721, 27925, 27768, 11705, 22761, 17135, 22733,
+ 5975, 10104, 28485, 23808, 31579, 1236, 10557, 28210, 27316, 11580,
+ 12012, 14772, 26301, 16561, 29722, 10431, 9757, 1103, 11846, 19558,
+ 8428, 19934, 25066, 17864, 10263, 19877, 21761, 32394, 3077, 10878,
+ 2757, 17797, 5754, 9264, 11453, 9147, 23484, 12280, 1271, 32144,
+ 9973, 17257, 28051, 21559, 1497, 16759, 22913, 15210, 14216, 15822,
+ 23178, 22366, 694, 2664, 18581, 30454, 14089, 17246, 28195, 7735,
+ 24002, 19710, 24093, 5372, 23968, 30751, 22223, 19946, 5633, 16561,
+ 22068, 14759, 13643, 23192, 17268, 23111, 20106, 187, 20907, 11015,
+ 29275, 14935, 32748, 12350, 20232, 2714, 23174, 17296, 7156, 15981,
+ 24965, 28773, 21562, 19601, 14460, 29849, 1169, 31725, 898, 14710,
+ 12403, 17446, 5499, 22751, 4734, 7281, 21401, 717, 15386, 11429,
+ 29218, 22272, 22620, 5269, 28275, 1774, 5674, 15772, 27205, 21504,
+ 32160, 27257, 19503, 15869, 13491, 31069, 18796, 30150, 30484, 3139,
+ 15583, 26693, 17751, 2944, 28500, 30112, 3925, 13979, 13577, 10418,
+ 24015, 14174, 1133, 699, 16212, 27437, 27175, 12118, 31844, 22167,
+ 32346, 13484, 22229, 30507, 16167, 29672, 22646, 26509, 29812, 3563,
+ 29939, 2505, 236, 64, 760, 11238, 17479, 3666, 20633, 23231,
+ 29388, 19164, 22258, 22286, 1556, 21922, 20746, 24778, 11024, 8543,
+ 14846, 19635, 20814, 22014, 30299, 6187, 16247, 8972, 11467, 28487,
+ 20765, 5742, 4596, 22822, 16819, 19279, 11165, 32385, 10461, 1373,
+ 20242, 16004, 3051, 3125, 24266, 1500, 10399, 23323, 2888, 7186,
+ 23863, 30959, 6975, 23319, 20903, 3164, 32505, 1312, 17959, 83,
+ 13049, 11443, 10989, 19640, 13792, 25346, 25916, 14171, 5517, 8313,
+ 26013, 8489, 22408, 7059, 29549, 13220, 16545, 497, 20887, 656,
+ 16340, 18349, 8355, 30191, 112, 236, 8688, 4144, 26489, 31154,
+ 16445, 25764, 74, 32763, 366, 21041, 7294, 5127, 17805, 22090,
+ 11025, 29429, 30480, 3102, 2755, 12179, 4186, 11280, 23485, 19829,
+ 6788, 8040, 5239, 4676, 2396, 31816, 24025, 345, 6318, 32225,
+ 31393, 13706, 3779, 19686, 15876, 3396, 2088, 11329, 21912, 23771,
+ 12464, 24070, 27249, 6941, 3516, 21669, 23946, 15405, 15802, 1123,
+ 9063, 11919, 20716, 26891, 761, 11903, 8043, 5088, 15298, 25479,
+ 16491, 21975, 22330, 31824, 1728, 23043, 10608, 15545, 9890, 17489,
+ 17652, 12838, 26797, 10357, 26101, 538, 3627, 27940, 6311, 1801,
+ 19094, 28548, 7911, 12135, 30297, 31457, 22818, 21253, 24279, 26785,
+ 13939, 29341, 22446, 31866, 28683, 5548, 28989, 20706, 5078, 14975,
+ 30820, 26567, 8796, 3217, 9098, 13185, 17381, 21780, 4325, 11269,
+ 22752, 22990, 31221, 17499, 27013, 7718, 16466, 21586, 14522, 14975,
+ 14248, 19058, 32307, 15812, 20736, 14898, 3038, 19780, 2881, 6763,
+ 25214, 30401, 19702, 18445, 31125, 26819, 2897, 8465, 16008, 1330,
+ 25200, 19374, 3838, 548, 736, 32208, 12937, 3316, 6240, 22726,
+ 6024, 9108, 3559, 11578, 22348, 6180, 21224, 15207, 17785, 29379,
+ 1492, 17286, 3759, 9637, 10209, 31369, 10858, 18277, 15882, 14092,
+ 9255, 18333, 854, 27273, 32713, 20917, 4190, 15051, 15674, 20984,
+ 7177, 20389, 16213, 20717, 14747, 10467, 6660, 6372, 14318, 4225,
+ 2981, 22991, 1534, 32027, 9651, 16211, 16556, 30885, 26786, 11551,
+ 19899, 24412, 22282, 5501, 10271, 2812, 17416, 7718, 16759, 15924,
+ 24802, 1883, 7384, 25687, 19945, 2353, 1740, 31060, 12964, 6957,
+ 3738, 11752, 8490, 23056, 9416, 7186, 18640, 32756, 735, 8136,
+ 15364, 8856, 16494, 10216, 19833, 11257, 14673, 4977, 18565, 16674,
+ 10547, 28403, 2247, 2884, 8274, 9796, 13580, 5897, 13698, 32373,
+ 8563, 15910, 6517, 27652, 7376, 20272, 28473, 6483, 11599, 26544,
+ 3586, 12633, 90, 13433, 4138, 17048, 4540, 3129, 21366, 20047,
+ 19974, 6223, 20123, 22512, 13361, 32732, 24577, 2260, 14982, 18717,
+ 31174, 15406, 31419, 25848, 20230, 1854, 26975, 6356, 26202, 4551,
+ 7288, 15022, 13726, 21186, 25962, 29545, 11000, 1364, 16922, 31590,
+ 18197, 27134, 26964, 1365, 11446, 10260, 30314, 19275, 18796, 25456,
+ 30750, 29204, 31647, 23143, 26306, 14026, 22997, 8188, 17822, 6822,
+ 32561, 18004, 29586, 279, 314, 3434, 28413, 29713, 29407, 27140,
+ 4317, 680, 6327, 30950, 823, 28125, 12941, 12869, 30393, 6072,
+ 32283, 29054, 23454, 26775, 22294, 9480, 8658, 7877, 6251, 15015,
+ 17494, 15438, 8905, 7139, 9191, 1810, 11359, 20153, 29914, 20249,
+ 15847, 3728, 17483, 28454, 227, 29039, 22646, 15247, 17190, 28012,
+ 28773, 21323, 21399, 21096, 9932, 1869, 7218, 3065, 31793, 19472,
+ 7503, 16296, 19535, 26996, 11815, 7005, 12989, 23752, 9876, 26647,
+ 8907, 8488, 22040, 13536, 13997, 21001, 27681, 11777, 31195, 23570,
+ 13707, 29810, 12983, 12334, 21351, 2452, 28528, 11487, 20219, 8994,
+ 23079, 12757, 12041, 31589, 6225, 4543, 29269, 29096, 14685, 22113,
+ 4961, 3820, 30870, 2790, 31099, 17117, 22090, 120, 31481, 27908,
+ 19500, 16655, 21700, 1597, 8439, 9350, 15123, 32364, 8020, 15348,
+ 26489, 8812, 13310, 1849, 18466, 7752, 14116, 10455, 13402, 28590,
+ 25871, 3076, 19022, 23712, 18948, 12541, 23063, 17005, 9580, 5020,
+ 500, 20704, 2098, 24621, 24535, 1463, 12909, 27262, 31780, 31830,
+ 29759, 6965, 20917, 26045, 5628, 18278, 5921, 15544, 2959, 9829,
+ 11582, 2645, 30490, 23001, 22244, 20123, 16093, 15378, 7668, 24953,
+ 14937, 26781, 2457, 24573, 15029, 13077, 2510, 31175, 29280, 59,
+ 15393, 12988, 32760, 13641, 28086, 27903, 8299, 12676, 32398, 20253,
+ 19548, 1553, 2569, 23175, 17608, 24585, 30890, 17990, 21225, 22736,
+ 24347, 29162, 16218, 8354, 20081, 1219, 17533, 14190, 31152, 3412,
+ 26, 10216, 21650, 13573, 10312, 30938, 3972, 23576, 1937, 18618,
+ 5362, 12766, 1105, 18306, 27588, 7467, 14175, 700, 9001, 2311,
+ 21999, 14300, 11155, 27046, 29367, 8403, 16643, 3483, 23121, 28385,
+ 19078, 3912, 3809, 26539, 21247, 31385, 9975, 22669, 32552, 31474,
+ 5047, 21553, 9428, 9573, 4663, 28257, 26487, 13097, 19496, 27161,
+ 32231, 16455, 27577, 3553, 1380, 25239, 9912, 4697, 1495, 11499,
+ 1274, 24342, 2903, 29322, 26110, 2476, 30961, 24288, 2509, 19212,
+ 30889, 13683, 8484, 24337, 11452, 19993, 10453, 597, 1576, 8553,
+ 5227, 585, 25710, 31087, 3085, 4997, 25239, 6820, 16805, 25180,
+ 30069, 31004, 8513, 4532, 16171, 19970, 24761, 7188, 15344, 8514,
+ 12946, 19199, 11279, 7045, 8226, 14465, 24370, 13410, 20213, 3847,
+ 17633, 4306, 13680, 31604, 26182, 9701, 692, 1392, 11571, 29620,
+ 15813, 16899, 7270, 27799, 24556, 5220, 23819, 23704, 28249, 28939,
+ 17794, 25895, 22285, 22285, 15715, 24847, 5367, 29609, 8895, 17576,
+ 24413, 9246, 5289, 20046, 26750, 18880, 18165, 6931, 28534, 9291,
+ 17216, 29617, 10593, 9847, 15153, 26051, 17859, 30925, 20477, 32052,
+ 4648, 7864, 29489, 12791, 263, 29151, 17580, 24056, 6124, 26546,
+ 4586, 20307, 2262, 21827, 23177, 19141, 31454, 9560, 32261, 4703,
+ 17946, 13502, 30407, 17538, 9921, 18656, 18014, 9991, 11152, 21656,
+ 30476, 12990, 25452, 32580, 22148, 29466, 3656, 8733, 19954, 3626,
+ 21833, 12228, 31548, 2251, 20008, 14878, 28551, 6941, 19929, 2658,
+ 14078, 10547, 20074, 32624, 3534, 13327, 27693, 9829, 26229, 22221,
+ 15897, 16748, 9533, 9246, 3438, 12503, 13571, 30712, 12440, 29294,
+ 22845, 4492, 3414, 11014, 24892, 2425, 1563, 28246, 8366, 30783,
+ 22197, 14599, 20838, 24822, 9260, 20746, 16992, 13376, 17389, 46,
+ 30719, 32636, 32295, 23794, 8602, 7228, 20342, 5527, 2103, 29689,
+ 28095, 29050, 23190, 11270, 5211, 31905, 31346, 19907, 23415, 4500,
+ 12035, 16147, 7866, 13678, 24775, 7952, 14121, 31283, 17026, 23293,
+ 3144, 23396, 2948, 3963, 16514, 18641, 10026, 2560, 31947, 21423,
+ 32167, 32390, 8068, 12778, 14852, 17792, 21151, 3005, 12646, 13842,
+ 19715, 18303, 20368, 28801, 17202, 18368, 11432, 11497, 19241, 20372,
+ 12350, 25134, 14216, 303, 25994, 22836, 11762, 10930, 25845, 83,
+ 31927, 21829, 30428, 4869, 29616, 19046, 21392, 27106, 17515, 896,
+ 9377, 1743, 11656, 14272, 11100, 12658, 30051, 31780, 12434, 14313,
+ 30708, 10709, 8603, 10171, 19443, 32438, 32411, 4878, 17215, 11325,
+ 32260, 13851, 19072, 18562, 2396, 4320, 27659, 21909, 30529, 18708,
+ 31239, 21269, 9898, 26720, 9166, 3582, 24431, 19148, 31382, 8899,
+ 7180, 20856, 10577, 26013, 8354, 11660, 25554, 9506, 830, 22385,
+ 20784, 31513, 2398, 1602, 30063, 8077, 32433, 15229, 24157, 29216,
+ 26911, 14079, 6075, 11682, 15881, 26415, 10909, 31202, 31954, 10617,
+ 11284, 20420, 21150, 28414, 7945, 25492, 11097, 6537, 11628, 2458,
+ 21500, 9413, 31887, 18671, 4619, 28590, 8396, 4239, 21602, 14918,
+ 29806, 17070, 24882, 11145, 21967, 2640, 9543, 29602, 4285, 12052,
+ 2188, 24159, 30498, 23376, 27600, 27107, 27876, 2147, 13258, 13723,
+ 27403, 1351, 1371, 23923, 15906, 19302, 5908, 5449, 991, 5551,
+ 15352, 6305, 11270, 28136, 2947, 17051, 138, 9286, 19179, 25123,
+ 30965, 25915, 31653, 7784, 23819, 24975, 13099, 32655, 31402, 15538,
+ 8189, 28584, 29429, 13649, 24549, 18401, 25266, 15399, 2944, 15865,
+ 27119, 27926, 6906, 17912, 22252, 7798, 2073, 15390, 30773, 31405,
+ 20861, 27417, 23055, 22527, 17190, 17019, 29461, 17064, 10294, 20842,
+ 1059, 27944, 18936, 22937, 12147, 31455, 24610, 3704, 2822, 22745,
+ 22103, 21672, 12870, 6379, 2800, 5554, 6889, 767, 27388, 31736,
+ 12568, 20652, 3973, 10988, 32465, 18186, 16406, 18303, 25226, 8900,
+ 32377, 25821, 6423, 2670, 32709, 10583, 7885, 31513, 13977, 16288,
+ 11240, 25381, 21154, 26685, 20522, 24407, 22883, 16183, 29125, 20011,
+ 15413, 2579, 13179, 11628, 3980, 8707, 1540, 30209, 18301, 20062,
+ 26800, 27146, 7549, 9038, 7501, 2348, 876, 14537, 21323, 7976,
+ 18386, 19906, 3614, 8371, 20328, 11168, 19172, 19074, 2010, 24047,
+ 10568, 13988, 30667, 4693, 7078, 23572, 4121, 13512, 25200, 11407,
+ 8803, 7167, 22224, 17571, 8393, 23078, 18574, 25097, 2803, 1494,
+ 29493, 5172, 11349, 3908, 20081, 23338, 4017, 30137, 15804, 10387,
+ 19421, 28994, 25401, 30479, 3526, 25768, 6624, 27597, 949, 11170,
+ 23260, 13914, 3537, 6474, 4657, 8886, 22502, 15054, 9890, 4525,
+ 16484, 12904, 14546, 19300, 12459, 16016, 23977, 24627, 19077, 16752,
+ 22521, 2994, 3828, 23704, 5474, 19991, 25135, 29939, 29299, 12223,
+ 4327, 13049, 2577, 25354, 15054, 21287, 5149, 14444, 18010, 23212,
+ 5969, 6337, 16838, 1126, 29291, 31201, 21851, 31244, 142, 373,
+ 10989, 11693, 23781, 18953, 28328, 26457, 2441, 32354, 19725, 23326,
+ 32165, 16145, 4663, 23350, 24280, 1608, 20067, 31358, 27098, 32237,
+ 9135, 13098, 20067, 31725, 8482, 26039, 584, 6355, 20205, 17442,
+ 20455, 5273, 20464, 32088, 9158, 32189, 15488, 15597, 23927, 20120,
+ 6760, 21264, 10175, 29932, 5677, 6335, 7159, 30652, 24983, 25655,
+ 13489, 12128, 23404, 8623, 21407, 17368, 25727, 25669, 24241, 25953,
+ 1513, 825, 14462, 29510, 19607, 5977, 6117, 1273, 32261, 27836,
+ 756, 2402, 2632, 15539, 28936, 28791, 24402, 17405, 22582, 4877,
+ 370, 2362, 10730, 19693, 3354, 26530, 718, 32043, 1509, 12791,
+ 4590, 24755, 5848, 440, 31513, 31525, 10217, 1688, 14474, 483,
+ 27837, 27183, 16328, 32104, 20662, 7150, 28106, 5339, 25645, 6488,
+ 32351, 14307, 12028, 1647, 4813, 6846, 3136, 10861, 3000, 14477,
+ 29533, 9397, 14918, 20466, 21058, 28169, 11393, 3549, 23790, 31229,
+ 6397, 23203, 30258, 3244, 11706, 32081, 5561, 6313, 17995, 2367,
+ 20295, 14649, 19768, 18920, 24382, 7359, 19618, 8440, 24678, 29559,
+ 29221, 2727, 3821, 13927, 2563, 15430, 15533, 23187, 13694, 4375,
+ 23214, 17521, 24709, 14690, 15340, 3996, 14995, 24517, 30042, 32460,
+ 14037, 14540, 32550, 10246, 22411, 12482, 31551, 12560, 18608, 11206,
+ 17685, 12328, 3549, 3105, 11936, 1269, 18283, 29398, 3747, 15806,
+ 21208, 28283, 1074, 23770, 19051, 3144, 4978, 4712, 10267, 32622,
+ 32672, 15936, 4014, 21161, 1620, 20009, 1054, 22553, 24583, 19532,
+ 3136, 19278, 10707, 12776, 2727, 22946, 7291, 21064, 19655, 1227,
+ 13483, 29170, 5462, 5040, 12417, 24098, 9720, 1404, 1611, 6262,
+ 3098, 15089, 14483, 27371, 13598, 18944, 11097, 30728, 3513, 12182,
+ 24223, 7001, 12442, 21432, 12843, 11807, 26701, 5074, 5768, 1094,
+ 2142, 18252, 20302, 13719, 25025, 29279, 10915, 1839, 22129, 6951,
+ 20994, 2352, 20568, 29945, 6203, 15542, 8047, 22006, 26811, 22029,
+ 806, 10976, 15374, 28449, 25350, 23853, 13730, 15925, 31381, 24410,
+ 20174, 9432, 31866, 21378, 13074, 11029, 28897, 47, 12705, 15083,
+ 21281, 1904, 26652, 12285, 12956, 5164, 2721, 3977, 23271, 29109,
+ 27908, 31902, 18220, 16800, 12636, 15498, 25804, 17365, 16322, 24466,
+ 26952, 25826, 27477, 25063, 16225, 1685, 26754, 22741, 20350, 14025,
+ 30850, 60, 10063, 18560, 28195, 15428, 17584, 818, 28620, 25421,
+ 2000, 23653, 6843, 25637, 4242, 28542, 27538, 7294, 2867, 10199,
+ 4114, 29599, 12334, 20753, 1574, 3417, 31580, 428, 11299, 10557,
+ 24160, 5076, 9806, 524, 29250, 8318, 15775, 16751, 27738, 12468,
+ 7108, 23528, 23152, 6445, 2153, 26889, 27169, 13345, 2999, 19428,
+ 16260, 27995, 6682, 16322, 7950, 21648, 11592, 7448, 28339, 10735,
+ 28287, 27318, 21070, 6393, 22029, 3906, 26435, 5523, 25622, 14053,
+ 25443, 3930, 22162, 16708, 6928, 28470, 149, 19378, 12961, 4914,
+ 9939, 11171, 32520, 15499, 1379, 28004, 22961, 9222, 25283, 11018,
+ 27566, 10375, 21533, 20393, 13330, 19424, 5832, 6854, 19866, 29159,
+ 8978, 30734, 14227, 5579, 23613, 32584, 9719, 27048, 455, 12424,
+ 7386, 5208, 17903, 16549, 23300, 397, 11636, 2542, 22496, 30748,
+ 7328, 29977, 22677, 27292, 13701, 28284, 24690, 13872, 27527, 15232,
+ 143, 17313, 28698, 17490, 19121, 16048, 23757, 9691, 27503, 22442,
+ 16008, 8179, 12179, 17212, 26129, 13265, 30915, 27785, 8661, 1734,
+ 25953, 3450, 17638, 23852, 12207, 8533, 8000, 16793, 2103, 26002,
+ 19280, 11352, 28522, 23786, 29879, 16153, 21127, 2224, 31819, 26855,
+ 28606, 19556, 7518, 1627, 17814, 12166, 30788, 21007, 4492, 29096,
+ 9743, 14678, 8700, 9415, 14749, 26922, 32581, 16859, 20949, 10086,
+ 12329, 27565, 8493, 19510, 7538, 21481, 3695, 28619, 22747, 30324,
+ 21182, 8275, 19245, 7935, 14548, 13352, 3497, 27869, 24973, 3143,
+ 29350, 18705, 12713, 23301, 379, 684, 19661, 17149, 27039, 1366,
+ 16844, 25165, 12559, 24106, 19493, 7682, 8688, 711, 20173, 16848,
+ 15222, 3747, 27694, 18439, 10756, 27299, 24431, 24002, 2709, 4841,
+ 31478, 30561, 32090, 28398, 28715, 2362, 19364, 28624, 17535, 14476,
+ 9477, 26861, 6062, 6324, 14258, 22192, 8000, 18596, 10284, 1963,
+ 31574, 1168, 11296, 23526, 18595, 32746, 19595, 3703, 5049, 7057,
+ 4897, 15699, 4486, 19526, 9968, 9060, 16670, 17759, 7233, 14556,
+ 23227, 15295, 31679, 11720, 12289, 21765, 17627, 29416, 24967, 5892,
+ 28526, 17598, 3476, 27508, 12448, 27877, 23590, 3046, 1802, 11684,
+ 3129, 27134, 21015, 3011, 26181, 26588, 30896, 27293, 14345, 29915,
+ 25368, 11895, 15751, 25214, 19476, 22800, 6992, 1447, 11600, 21625,
+ 19969, 30730, 19198, 24615, 13070, 3554, 8896, 21575, 3774, 21474,
+ 16840, 12113, 13175, 10607, 17981, 8672, 11836, 19212, 4065, 3265,
+ 7284, 24854, 25586, 9546, 3821, 26289, 2126, 13293, 7712, 32002,
+ 6618, 8461, 5047, 32415, 8739, 17423, 19788, 26435, 12358, 10421,
+ 15476, 25543, 30990, 16039, 10236, 7757, 16989, 10067, 4722, 6847,
+ 7629, 5623, 27111, 14200, 13974, 30204, 25844, 9792, 14003, 19334,
+ 12539, 29054, 1856, 585, 21935, 25001, 28711, 7838, 29143, 22272,
+ 23291, 1238, 13647, 27515, 15652, 19150, 15439, 28929, 27965, 18371,
+ 12271, 8155, 26554, 22120, 20459, 2409, 18126, 32054, 18852, 8979,
+ 29068, 28932, 104, 32131, 17996, 9687, 10995, 31761, 17488, 25083,
+ 27190, 8319, 30887, 1875, 15703, 16103, 12882, 1773, 30456, 11761,
+ 16806, 13017, 6076, 18249, 18161, 25148, 12807, 19537, 21600, 7072,
+ 15110, 787, 26400, 14734, 27888, 8057, 31684, 15711, 7819, 19648,
+ 16871, 17487, 13297, 27434, 13074, 21203, 3220, 22003, 4320, 27181,
+ 4736, 17799, 3679, 7229, 20192, 8690, 10426, 4506, 10180, 22936,
+ 29461, 13793, 11041, 4134, 22969, 32333, 2841, 14792, 8305, 32392,
+ 12157, 30365, 8243, 16321, 145, 17000, 2051, 3583, 20239, 19592,
+ 9493, 12213, 32110, 3114, 30258, 15254, 20067, 25789, 3676, 170,
+ 31913, 28326, 2741, 13474, 32766, 14389, 8093, 23657, 9070, 4824,
+ 283, 8955, 20691, 16527, 10878, 4730, 13725, 5536, 18756, 25471,
+ 9423, 25228, 20282, 22190, 23114, 14913, 28645, 19597, 846, 26769,
+ 3361, 3990, 12350, 11491, 22280, 1162, 5027, 3369, 8981, 13577,
+ 12916, 21778, 16009, 26720, 27029, 5504, 16398, 16034, 27805, 14396,
+ 7323, 506, 8668, 31721, 919, 8767, 32669, 27702, 17985, 3785,
+ 20136, 10840, 20047, 25219, 30219, 6584, 26581, 5698, 13338, 17640,
+ 25193, 11605, 26805, 3804, 19845, 4190, 21705, 1111, 21549, 2656,
+ 29465, 24995, 31697, 7192, 20031, 8325, 19060, 6545, 30701, 8816,
+ 6158, 17907, 1401, 19193, 3887, 24987, 13721, 7819, 8422, 24177,
+ 9067, 14684, 28641, 11894, 10936, 12959, 30421, 24733, 24953, 16380,
+ 28193, 32732, 19098, 11581, 13486, 26754, 9727, 31818, 16409, 1995,
+ 453, 16727, 22548, 14770, 28874, 3932, 8457, 14598, 2671, 2245,
+ 14849, 21952, 6044, 26731, 29125, 26004, 4357, 5828, 22338, 8902,
+ 21164, 8022, 10546, 27967, 10407, 6770, 26873, 8672, 6436, 24350,
+ 5325, 31766, 4010, 4435, 19738, 13743, 19874, 24681, 26917, 22764,
+ 17429, 2511, 16111, 30935, 15031, 29695, 8796, 17366, 26661, 30129,
+ 24468, 9345, 24427, 7503, 13482, 25777, 30409, 3242, 3708, 1753,
+ 2999, 15595, 3290, 18842, 18470, 16076, 4586, 2449, 19721, 19208,
+ 24778, 30068, 26132, 14095, 3960, 18525, 10947, 8703, 20463, 32357,
+ 12447, 28112, 21651, 14197, 12989, 22734, 21455, 15449, 21127, 19277,
+ 28413, 23062, 21950, 11672, 134, 1918, 1472, 23082, 5450, 2305,
+ 5127, 33, 5442, 1734, 10227, 2543, 24419, 18683, 31177, 23635,
+ 23750, 3689, 7931, 392, 20231, 12619, 27562, 5308, 24043, 3680,
+ 3433, 451, 10309, 25151, 17220, 27917, 23578, 4331, 22273, 22485,
+ 6659, 2983, 15269, 21660, 10195, 18699, 30010, 24534, 13946, 856,
+ 11728, 12515, 16169, 12553, 7106, 5952, 15287, 27562, 7482, 14335,
+ 15940, 14573, 11511, 16244, 11292, 27131, 5198, 23346, 8157, 1288,
+ 32367, 4150, 14045, 27946, 20714, 16737, 19910, 15467, 28018, 31276,
+ 28803, 1053, 16608, 20887, 352, 26477, 17275, 31074, 23404, 17467,
+ 20086, 19840, 29730, 24105, 27322, 30665, 16457, 16370, 31974, 31727,
+ 24601, 18174, 29332, 16307, 22175, 3379, 21727, 25432, 20579, 9485,
+ 25634, 32344, 15687, 23537, 8449, 5207, 16818, 30398, 26286, 22101,
+ 17134, 7334, 31333, 1063, 4815, 25660, 13369, 552, 32406, 14029,
+ 9491, 30508, 17684, 32244, 24056, 1717, 14355, 20329, 15498, 31594,
+ 3313, 2842, 24786, 30148, 8334, 8061, 12348, 29451, 12905, 26660,
+ 2531, 16513, 23301, 23186, 4111, 11997, 16786, 30029, 11004, 6650,
+ 21705, 9524, 10462, 6353, 2840, 5395, 7969, 27045, 28159, 7029,
+ 28917, 28285, 29882, 15033, 7946, 19927, 29216, 26472, 17560, 2971,
+ 6603, 2246, 26019, 11854, 24697, 26535, 29309, 17544, 15282, 32644,
+ 9356, 24232, 1195, 26062, 6221, 20678, 619, 15234, 18585, 20713,
+ 24364, 23806, 20264, 17786, 3332, 17427, 3667, 22521, 24004, 20571,
+ 10270, 8175, 21025, 27085, 26229, 31268, 25617, 12686, 30902, 24593,
+ 20600, 13578, 10864, 21400, 9220, 22340, 30571, 13043, 3925, 25706,
+ 8424, 2283, 18018, 941, 10281, 11594, 28440, 31568, 21044, 18834,
+ 25412, 31486, 6357, 5615, 18866, 24672, 11490, 25195, 19094, 10735,
+ 28098, 16481, 25388, 3079, 31280, 24628, 7324, 23613, 15933, 30528,
+ 10784, 18163, 8852, 16913, 12904, 810, 16642, 30419, 18494, 30871,
+ 16950, 15370, 22118, 3064, 18629, 30596, 712, 1448, 3441, 2443,
+ 19665, 18033, 4266, 18527, 27414, 16034, 1365, 20451, 11322, 23394,
+ 22733, 31126, 24338, 24132, 31783, 4293, 1544, 21276, 21179, 5887,
+ 22973, 6160, 27103, 11466, 24307, 11250, 24054, 29332, 5033, 14029,
+ 4266, 30188, 30599, 189, 5237, 32498, 29565, 19204, 29030, 21004,
+ 25768, 16219, 10018, 14811, 20085, 27014, 4137, 28014, 30728, 28459,
+ 2650, 9909, 30943, 31204, 2234, 32056, 30898, 1939, 29297, 22792,
+ 9886, 5366, 29461, 4598, 11139, 22139, 8235, 3844, 7083, 29525,
+ 6123, 31257, 11180, 30415, 32068, 23545, 11407, 27616, 29984, 13427,
+ 4913, 22272, 2281, 25309, 3818, 571, 4684, 29373, 29549, 20356,
+ 5181, 8393, 31215, 1355, 9531, 11282, 7564, 18770, 20181, 18300,
+ 5862, 15804, 1645, 16241, 15119, 29799, 9020, 10198, 16809, 11387,
+ 30102, 9790, 13899, 3651, 25455, 11358, 6439, 22844, 11807, 14018,
+ 29418, 14444, 17762, 25534, 24548, 12533, 19363, 30374, 22121, 24298,
+ 12154, 6977, 11383, 29793, 32371, 32124, 8344, 11978, 21777, 2396,
+ 27146, 13951, 4114, 26422, 5150, 7324, 8949, 2082, 10462, 27408,
+ 14266, 22189, 28402, 31476, 31721, 24526, 16069, 1308, 16085, 2076,
+ 13027, 8428, 17698, 8509, 14246, 9581, 30085, 29602, 15889, 8352,
+ 17099, 4209, 5628, 22803, 30493, 32707, 13169, 3505, 17538, 7952,
+ 25431, 26590, 16037, 17383, 13133, 21444, 8665, 30435, 4313, 13031,
+ 2906, 23258, 25538, 7424, 1749, 5207, 10170, 8968, 5419, 17739,
+ 18752, 18579, 4211, 28927, 18885, 10079, 4414, 23629, 28430, 28973,
+ 14622, 15888, 473, 17359, 1641, 21465, 24515, 899, 5434, 12004,
+ 25705, 12159, 29113, 19786, 28110, 25805, 24476, 21367, 32765, 857,
+ 15086, 31199, 19439, 10569, 22031, 749, 7598, 30860, 30973, 19772,
+ 30139, 23222, 26065, 22026, 20909, 14091, 1677, 16362, 26652, 20185,
+ 10260, 12728, 23485, 13324, 26234, 8658, 10702, 3580, 11902, 24965,
+ 22453, 8329, 30805, 31942, 9188, 18794, 8106, 16931, 15871, 26562,
+ 31970, 1785, 19009, 25076, 9124, 31718, 13340, 15801, 27289, 9601,
+ 5151, 32368, 8304, 19785, 11549, 15797, 4646, 32476, 17548, 12852,
+ 18052, 25962, 23083, 6335, 4841, 7528, 744, 13215, 27977, 20105,
+ 27392, 21544, 8054, 8682, 17256, 8849, 16286, 26764, 7788, 6146,
+ 4629, 1544, 32662, 24301, 14421, 29566, 8913, 3490, 20804, 28367,
+ 16078, 28446, 28341, 10764, 18087, 20004, 1072, 3886, 28354, 30352,
+ 13046, 27655, 30969, 24807, 5952, 6776, 3063, 15410, 31432, 30949,
+ 6629, 18957, 4234, 18150, 6727, 16635, 7628, 14911, 6944, 10492,
+ 13404, 24595, 27997, 26210, 25113, 7764, 28784, 26336, 31156, 27006,
+ 16700, 9444, 22712, 645, 20529, 29990, 20168, 20747, 8888, 21121,
+ 2600, 11735, 17361, 7171, 11648, 12675, 10234, 31040, 29404, 23412,
+ 2132, 22763, 32758, 9488, 30977, 15783, 20408, 21802, 16080, 19738,
+ 21757, 10177, 10268, 21827, 15000, 7659, 27889, 15374, 25751, 2572,
+ 23153, 3366, 5833, 11339, 19830, 6667, 25725, 29511, 16505, 24676,
+ 19853, 13573, 28851, 10902, 11419, 29742, 24193, 7829, 23195, 1399,
+ 11533, 12027, 11153, 10592, 9515, 8791, 10396, 28193, 24449, 9415,
+ 11060, 28129, 23019, 6089, 15792, 15658, 31774, 5198, 25867, 7578,
+ 20363, 21264, 14311, 18651, 28294, 28454, 26322, 26581, 28327, 14037,
+ 6601, 2593, 19056, 32426, 18170, 12737, 3633, 10949, 26318, 18191,
+ 19497, 25208, 10535, 2292, 7150, 8721, 4071, 19802, 10511, 7923,
+ 4785, 9700, 5367, 12780, 12275, 15580, 12308, 15298, 3876, 32365,
+ 20025, 14351, 6218, 25106, 14913, 29263, 9408, 26702, 3318, 4408,
+ 11574, 8350, 27441, 27722, 6393, 19372, 28482, 24486, 4725, 28101,
+ 16785, 4643, 1272, 25997, 9350, 24991, 10168, 23281, 30631, 27027,
+ 14872, 6750, 30208, 22506, 21799, 12336, 13256, 1044, 30313, 22638,
+ 8001, 31830, 10203, 5812, 2272, 32100, 26929, 2672, 30382, 2097,
+ 15970, 21329, 18158, 2566, 1894, 6653, 26112, 19154, 1342, 4355,
+ 7045, 5569, 12342, 528, 12996, 20495, 17255, 15205, 589, 29215,
+ 8575, 29064, 5851, 5831, 30405, 26938, 1407, 5358, 15447, 32170,
+ 10491, 22362, 182, 22248, 20076, 26307, 6533, 25756, 5421, 23084,
+ 8846, 28920, 1527, 8563, 28166, 24555, 9549, 24102, 18962, 28312,
+ 1303, 16024, 16266, 1798, 6541, 3892, 11772, 31769, 21846, 30226,
+ 26868, 16833, 20721, 3272, 14970, 30065, 341, 19587, 28381, 19155,
+ 16852, 86, 19887, 12474, 13637, 12753, 9233, 16984, 16994, 17366,
+ 17457, 22705, 12143, 12200, 7696, 20559, 8477, 6213, 21897, 22327,
+ 173, 10230, 31119, 22301, 3416, 27684, 16566, 20436, 7407, 9069,
+ 28404, 13832, 20415, 12791, 18601, 10799, 15287, 12292, 14046, 7101,
+ 21197, 18119, 202, 11415, 2205, 20343, 16027, 26827, 31571, 26785,
+ 26995, 9854, 9164, 30146, 11440, 8742, 20728, 15637, 23664, 11001,
+ 29315, 6058, 13652, 29604, 30388, 26552, 18821, 23361, 16277, 18740,
+ 16117, 17027, 29524, 12450, 17128, 16692, 11241, 27692, 22194, 20450,
+ 18937, 15089, 22978, 14805, 28410, 28319, 29919, 27460, 25241, 19268,
+ 19122, 28616, 26456, 6497, 4485, 13584, 17020, 7745, 31306, 26071,
+ 31526, 28296, 2271, 28947, 5312, 20239, 16784, 4463, 18586, 6127,
+ 20446, 26876, 725, 19932, 2686, 1315, 9857, 26037, 30885, 24287,
+ 23810, 26200, 15491, 11049, 29880, 23739, 1805, 4019, 4831, 22073,
+ 30976, 4056, 15539, 21801, 5411, 17875, 31704, 29621, 10188, 15408,
+ 8698, 10474, 18341, 31617, 28593, 25611, 21424, 8274, 8871, 29227,
+ 4745, 3423, 12028, 25082, 22252, 3588, 10217, 23008, 19830, 31988,
+ 7076, 5192, 22448, 17198, 26244, 30271, 6217, 17197, 16742, 29757,
+ 5283, 1119, 3919, 14658, 3986, 13017, 11859, 17445, 352, 18249,
+ 20405, 28457, 20756, 27436, 6991, 5586, 13043, 27969, 8756, 19703,
+ 20552, 23101, 25749, 24855, 7265, 3520, 28385, 3825, 31450, 20360,
+ 21040, 10830, 6942, 20709, 31714, 10018, 11562, 7788, 12419, 14547,
+ 21396, 23024, 11762, 31705, 30412, 20654, 14531, 23943, 23971, 16840,
+ 6369, 13864, 12041, 26869, 18808, 18766, 16667, 8566, 24594, 8295,
+ 22877, 13644, 28416, 29585, 16963, 11432, 26363, 5296, 23031, 12707,
+ 15371, 4285, 32342, 23599, 20904, 31585, 31291, 31309, 29215, 6338,
+ 22529, 10369, 21816, 22941, 15683, 20099, 31254, 23957, 13286, 21560,
+ 22622, 28618, 1114, 8928, 11420, 12718, 1308, 18065, 25570, 26644,
+ 896, 17380, 27314, 7818, 10669, 30190, 25373, 5353, 1513, 2162,
+ 1581, 11050, 5911, 25172, 13441, 16251, 637, 5201, 31287, 12946,
+ 22219, 8174, 2575, 1602, 89, 10926, 29644, 19020, 21169, 29064,
+ 6622, 19319, 19277, 4248, 10815, 14563, 29090, 29461, 7835, 13210,
+ 30813, 32643, 1971, 31848, 1004, 21546, 10243, 13293, 14912, 10182,
+ 8610, 24816, 32721, 8832, 15211, 12534, 1507, 17181, 346, 10003,
+ 3592, 9334, 17464, 11521, 1767, 14120, 15483, 14959, 26171, 17292,
+ 21608, 1691, 25631, 18410, 23930, 30755, 31624, 1769, 13575, 18201,
+ 21523, 23114, 7201, 1365, 30977, 7638, 18107, 271, 383, 18069,
+ 26124, 13741, 3627, 31297, 12857, 16089, 16341, 15098, 14126, 471,
+ 2946, 31547, 26828, 277, 4023, 11789, 16970, 3588, 20212, 10107,
+ 29909, 19751, 29566, 24901, 27002, 16490, 97, 30681, 6726, 19380,
+ 5046, 29566, 1708, 26559, 7714, 12755, 18214, 30504, 13215, 888,
+ 1055, 29122, 22911, 21003, 21521, 23088, 30126, 25174, 17643, 12723,
+ 17207, 1734, 5301, 24128, 28681, 22047, 23926, 14038, 18428, 14959,
+ 14422, 10766, 4367, 27713, 7168, 13044, 31987, 11794, 31306, 4117,
+ 21454, 23561, 24856, 28889, 15417, 9186, 8829, 3347, 17546, 31020,
+ 18468, 23255, 4441, 6580, 21999, 22156, 21821, 13889, 8157, 4417,
+ 30167, 4993, 14129, 31045, 530, 14148, 13009, 4337, 23976, 30184,
+ 22252, 1993, 17897, 29716, 24543, 27076, 5048, 28842, 29786, 22759,
+ 24278, 27382, 702, 1304, 26211, 31020, 3530, 22066, 25249, 25361,
+ 11383, 31829, 9212, 21752, 16672, 23168, 9031, 16112, 11238, 32609,
+ 26441, 13372, 31827, 8299, 25464, 24323, 26174, 19242, 13316, 23625,
+ 32238, 16595, 23319, 5150, 32642, 12320, 25436, 25109, 9615, 16730,
+ 3006, 8696, 21260, 10423, 24690, 29882, 5227, 13031, 25911, 20909,
+ 15369, 32746, 13532, 14325, 7624, 24612, 14851, 5181, 11770, 1971,
+ 25894, 11945, 1922, 3072, 983, 13579, 7477, 24468, 7500, 13657,
+ 6791, 16430, 30746, 7263, 14179, 19218, 11585, 3249, 858, 11171,
+ 27753, 8676, 27648, 6196, 21867, 29693, 659, 4380, 2835, 28458,
+ 17630, 5640, 25381, 21424, 27997, 17814, 22429, 29221, 3746, 6943,
+ 7483, 30687, 32247, 16083, 831, 24492, 20805, 7180, 114, 23235,
+ 29749, 12764, 4453, 17915, 6292, 20968, 19453, 32571, 1532, 16762,
+ 19503, 12082, 3249, 28881, 24073, 23368, 8137, 15548, 2290, 21460,
+ 23184, 28263, 24626, 21135, 29994, 28020, 15541, 23881, 27770, 22605,
+ 17419, 16602, 24899, 30393, 24756, 14428, 29325, 15022, 3995, 5271,
+ 5963, 17255, 9952, 30653, 15162, 5813, 31194, 31064, 8972, 1178,
+ 32349, 18048, 23494, 26900, 22328, 4689, 14695, 16439, 26626, 27292,
+ 10442, 16510, 22039, 17629, 22733, 28515, 6877, 22381, 32435, 25645,
+ 2892, 4857, 14791, 11530, 30893, 20531, 23106, 2653, 20129, 1479,
+ 3951, 29785, 21094, 6801, 16653, 7887, 26454, 10253, 6133, 28484,
+ 31920, 16655, 31229, 6471, 2203, 4276, 32027, 21762, 13416, 26008,
+ 5582, 25614, 7704, 32073, 1209, 22668, 21278, 9212, 18321, 21105,
+ 26726, 31871, 4410, 10017, 21397, 1135, 3373, 10048, 27027, 10411,
+ 29213, 30404, 9799, 32264, 10202, 11087, 8609, 29255, 1141, 9405,
+ 21982, 2372, 25765, 21496, 6919, 31343, 9065, 25620, 31675, 17024,
+ 13551, 31128, 18223, 32103, 26805, 31769, 1139, 7298, 5870, 7694,
+ 10999, 19731, 15655, 5855, 17485, 8945, 20010, 17215, 23344, 23422,
+ 14627, 8124, 23494, 19672, 27649, 20884, 18722, 21844, 21791, 12747,
+ 27661, 24360, 10276, 3706, 24326, 19559, 27176, 5738, 7047, 24371,
+ 2328, 8929, 27786, 29230, 603, 21436, 27212, 5425, 23733, 12734,
+ 25425, 25153, 31084, 19240, 22184, 7870, 170, 32394, 25456, 31966,
+ 27939, 26584, 20891, 4442, 31479, 9152, 6130, 20839, 32218, 23867,
+ 857, 11496, 25202, 22883, 25429, 6370, 24320, 30084, 24523, 7728,
+ 5955, 19317, 23563, 16504, 14234, 28713, 2828, 20829, 19304, 129,
+ 6393, 1014, 21180, 28772, 3565, 21631, 23346, 20498, 19964, 6223,
+ 8212, 31669, 23154, 18954, 30149, 26938, 14431, 26136, 1120, 2142,
+ 8275, 27478, 5532, 26892, 23398, 21515, 31219, 7142, 29051, 6941,
+ 18691, 290, 3270, 8581, 308, 31127, 13964, 2048, 19099, 11799,
+ 20778, 20743, 24862, 24832, 29529, 24322, 27097, 32270, 2224, 8889,
+ 14273, 23667, 23403, 3595, 17287, 26410, 27498, 7906, 23232, 8072,
+ 13949, 5734, 19010, 11796, 21982, 12401, 2001, 30104, 5375, 28483,
+ 7931, 23672, 25990, 20344, 25920, 16451, 21654, 30775, 14710, 18312,
+ 25937, 15275, 21100, 1515, 29851, 31671, 24782, 9847, 2592, 18149,
+ 2120, 4150, 15000, 16800, 29678, 14591, 32586, 12196, 2524, 6800,
+ 9934, 12722, 537, 32221, 17176, 2952, 25794, 4263, 14514, 1552,
+ 13156, 31055, 21321, 16856, 16809, 23789, 875, 3522, 311, 2973,
+ 10639, 5629, 17621, 18201, 4694, 32563, 16079, 22413, 2064, 16900,
+ 16028, 25254, 7554, 23220, 29119, 14572, 5607, 8480, 11243, 3411,
+ 3636, 23799, 31338, 19212, 19360, 27174, 1728, 32161, 21348, 404,
+ 3211, 32577, 12223, 31248, 26285, 24921, 1598, 5512, 30637, 17252,
+ 25402, 11899, 29019, 3075, 24226, 22960, 16307, 14416, 32251, 20521,
+ 6916, 13679, 30628, 13651, 1362, 30823, 15199, 3455, 14072, 18480,
+ 25613, 30869, 16017, 28174, 30393, 1287, 22553, 16413, 4824, 12037,
+ 16208, 14892, 30671, 24560, 351, 6350, 950, 528, 4542, 10927,
+ 3932, 31881, 9813, 19493, 19339, 11147, 7906, 16647, 909, 10442,
+ 31642, 24770, 26862, 30766, 10003, 18601, 19588, 27851, 5985, 2189,
+ 26797, 23059, 2688, 32142, 8408, 25930, 25074, 20272, 23111, 2875,
+ 25000, 17074, 21011, 11818, 22054, 22683, 5232, 16393, 26083, 26773,
+ 31026, 23791, 4590, 12158, 18832, 27077, 10711, 957, 29480, 2883,
+ 14029, 9170, 27716, 2331, 8708, 21297, 11612, 29043, 6746, 14673,
+ 25564, 4249, 32057, 14080, 16934, 4338, 18111, 9721, 4315, 22324,
+ 19740, 14008, 25943, 28373, 19260, 24717, 8570, 6852, 32423, 6128,
+ 8366, 24150, 23717, 16148, 13861, 4739, 8869, 1215, 24675, 23378,
+ 17887, 9560, 22013, 4498, 1593, 16962, 20384, 29899, 10343, 17256,
+ 13140, 14708, 6999, 30489, 1282, 18278, 3276, 25623, 16436, 15505,
+ 12617, 490, 32541, 2030, 17200, 19322, 4825, 12468, 32043, 24541,
+ 28918, 7631, 5067, 9582, 6706, 29070, 29295, 8991, 24198, 19868,
+ 16232, 1040, 8804, 4913, 27482, 31072, 2366, 29577, 20453, 28227,
+ 10567, 25750, 8581, 16980, 11389, 19954, 14519, 32301, 743, 535,
+ 30302, 13877, 2587, 22482, 18276, 4026, 19972, 30709, 2980, 7232,
+ 18146, 13133, 25608, 32536, 14482, 29907, 11246, 4404, 5904, 9254,
+ 8657, 30521, 5178, 3129, 805, 24022, 15063, 6729, 8066, 20565,
+ 15063, 2323, 9989, 23919, 19164, 19523, 14324, 32357, 17146, 20527,
+ 28576, 29772, 21691, 25029, 656, 4008, 1127, 21186, 8155, 5693,
+ 18306, 11814, 9174, 15138, 27797, 4324, 24047, 23831, 12338, 31453,
+ 28121, 32536, 9010, 11279, 31722, 12083, 17985, 25098, 20673, 20374,
+ 32413, 2468, 4139, 30188, 18458, 14574, 6984, 21738, 18538, 1383,
+ 24041, 25636, 10139, 2671, 2877, 14886, 20961, 13310, 3501, 19648,
+ 1686, 8597, 11780, 2977, 22655, 13685, 13779, 2343, 849, 9232,
+ 4372, 9590, 14963, 6077, 13069, 28616, 21766, 15535, 17015, 12804,
+ 31523, 18728, 20704, 23185, 14435, 21994, 8526, 14444, 6053, 6895,
+ 16933, 15736, 11275, 25689, 32330, 15126, 11078, 21420, 27017, 19702,
+ 32020, 16699, 3124, 26157, 25606, 20960, 29197, 13447, 9095, 5360,
+ 8294, 19998, 18202, 15982, 14215, 23851, 28387, 20863, 17232, 15901,
+ 17769, 20254, 32544, 17384, 666, 15633, 4341, 5792, 8208, 6428,
+ 32724, 24646, 8850, 3188, 26987, 15330, 7390, 29558, 15093, 6865,
+ 20389, 3481, 29022, 5217, 2776, 27042, 9383, 21403, 13346, 25111,
+ 25229, 5984, 5814, 15861, 7269, 30904, 24650, 18853, 11339, 27494,
+ 28515, 31789, 13691, 11456, 22228, 31908, 25599, 5309, 14977, 7144,
+ 20363, 32080, 26985, 5779, 1445, 13300, 22756, 13098, 32520, 10632,
+ 25896, 4248, 1099, 21598, 31506, 14555, 17854, 30863, 3876, 19454,
+ 10901, 19089, 1482, 22343, 6984, 8203, 28897, 11441, 19257, 8935,
+ 18041, 20124, 17816, 15017, 29914, 17348, 16771, 8192, 30662, 26480,
+ 370, 20123, 21246, 2540, 16851, 18750, 5640, 30008, 31473, 25621,
+ 19758, 10754, 31258, 2376, 970, 26834, 5633, 11215, 15297, 23429,
+ 609, 23688, 32334, 29436, 1763, 13703, 27137, 19733, 7490, 4013,
+ 25095, 14042, 15021, 13948, 17067, 7929, 18541, 3625, 16157, 3189,
+ 4039, 24563, 19570, 28058, 7460, 16564, 15853, 21302, 24175, 17846,
+ 30333, 27654, 191, 31687, 21382, 21615, 20790, 21648, 13540, 3694,
+ 9513, 32290, 17966, 13778, 3456, 22738, 27959, 17577, 22880, 32583,
+ 475, 31736, 11272, 5329, 13048, 17583, 10745, 19964, 15546, 7387,
+ 346, 26470, 21532, 25886, 20890, 32461, 27563, 8796, 13911, 620,
+ 13709, 1976, 31103, 10888, 1731, 23743, 12469, 12614, 32683, 5090,
+ 18934, 15551, 7625, 9514, 19324, 12118, 6854, 295, 19170, 21066,
+ 15545, 12330, 24458, 3719, 31654, 29108, 5180, 10178, 8260, 28717,
+ 7183, 11716, 16388, 23769, 20109, 6150, 14926, 2057, 12050, 16255,
+ 6926, 18830, 885, 10938, 1647, 19827, 15850, 24619, 4582, 6380,
+ 15911, 12995, 11891, 23433, 11718, 15554, 2084, 24751, 31723, 31949,
+ 32474, 13641, 15398, 18752, 7247, 21947, 27803, 3525, 11096, 30743,
+ 26464, 1830, 21608, 18068, 806, 29023, 25430, 7740, 10012, 23544,
+ 6752, 9700, 22032, 6289, 13935, 20833, 29911, 30655, 2205, 9465,
+ 20464, 18454, 18676, 19736, 9316, 19335, 1656, 24132, 12272, 5869,
+ 22632, 20819, 3174, 4066, 13506, 4060, 23121, 31959, 4101, 9451,
+ 32472, 23396, 10810, 26105, 30949, 28892, 11573, 10267, 4486, 18725,
+ 25, 21881, 27539, 6086, 29722, 30466, 13969, 12098, 11911, 1630,
+ 2262, 677, 29703, 7204, 9454, 25948, 14627, 20046, 11838, 32073,
+ 7172, 21226, 4327, 6935, 11134, 15122, 8429, 27851, 8014, 23069,
+ 13465, 16028, 26016, 11543, 15899, 15877, 10709, 22127, 10356, 29464,
+ 14466, 496, 31635, 25621, 25788, 17650, 3006, 5947, 21139, 20178,
+ 14388, 26334, 19164, 32159, 32017, 23482, 31796, 11030, 23665, 391,
+ 19777, 17873, 25304, 27086, 9275, 2747, 19154, 20730, 18347, 29383,
+ 982, 6578, 15475, 10466, 8304, 4710, 17679, 7206, 28576, 14632,
+ 26138, 592, 17789, 29118, 5140, 24180, 14109, 25077, 28258, 24559,
+ 19897, 26680, 11158, 11678, 29965, 24672, 6897, 29005, 10494, 10958,
+ 24358, 14194, 9855, 10679, 18017, 30492, 9141, 10432, 25480, 22054,
+ 21337, 25291, 19649, 32176, 14175, 6672, 9012, 4815, 1749, 30319,
+ 18450, 10116, 11021, 7684, 25302, 14315, 6142, 15357, 7371, 1973,
+ 1000, 27048, 13774, 29656, 16951, 11728, 22101, 3205, 17834, 1610,
+ 17072, 2907, 3508, 12235, 21391, 31194, 803, 8189, 22469, 7194,
+ 2047, 26065, 17227, 29629, 16053, 25622, 20360, 28450, 19572, 6731,
+ 28879, 6363, 6872, 28593, 17706, 23394, 23750, 13477, 24662, 11527,
+ 23191, 20013, 6414, 14381, 18808, 16337, 15245, 21430, 12816, 1964,
+ 17742, 24508, 10852, 194, 3606, 23170, 26360, 16276, 564, 16810,
+ 26423, 7410, 20999, 5032, 16661, 25361, 15042, 1398, 20467, 20701,
+ 19564, 16521, 19139, 26512, 20779, 15621, 1388, 13956, 14785, 3117,
+ 24944, 6469, 13143, 10013, 12748, 7147, 19066, 5563, 5664, 31143,
+ 16227, 491, 4367, 27035, 28539, 2818, 24041, 11759, 30750, 28030,
+ 18823, 6433, 30367, 21236, 4727, 32156, 2445, 24137, 5210, 15245,
+ 30517, 18469, 17033, 24818, 7528, 8101, 13823, 4083, 3711, 848,
+ 21107, 8054, 32667, 26189, 18116, 10734, 27698, 13779, 27802, 32371,
+ 4807, 29408, 19275, 10264, 12024, 5166, 16891, 32633, 5310, 17507,
+ 7432, 31379, 4337, 20615, 6821, 11993, 13066, 23228, 8900, 14724,
+ 25645, 9513, 13882, 554, 28519, 2360, 22813, 2962, 24372, 28417,
+ 31857, 18119, 21572, 22790, 11012, 7275, 14718, 22560, 32151, 8270,
+ 31046, 31673, 6718, 9023, 6139, 4668, 17162, 5922, 22468, 19914,
+ 14308, 31043, 18829, 8495, 28604, 14058, 28492, 26900, 27876, 16432,
+ 21385, 13685, 12470, 15632, 14877, 18262, 4733, 6337, 20026, 5810,
+ 32147, 22339, 29099, 29877, 23238, 26937, 4445, 7723, 10496, 29174,
+ 8991, 21047, 2344, 13274, 12454, 16712, 16707, 5855, 5076, 26697,
+ 31455, 32111, 18490, 11288, 16561, 23417, 30171, 18746, 32637, 17347,
+ 6450, 27597, 3638, 24450, 27767, 957, 359, 1064, 30239, 10555,
+ 19921, 23421, 24738, 9579, 32341, 20977, 32640, 29533, 277, 16176,
+ 9606, 19775, 20439, 31992, 12365, 6609, 30634, 24615, 27909, 19993,
+ 17355, 18457, 14960, 5975, 4041, 14384, 3121, 24891, 1256, 12212,
+ 13127, 3158, 18115, 13278, 4053, 26831, 21302, 16431, 4132, 18775,
+ 6523, 4358, 8426, 16990, 3219, 31858, 29389, 27015, 13544, 19781,
+ 14627, 10586, 1328, 21610, 17916, 32058, 30356, 9336, 10082, 10646,
+ 12306, 11142, 10719, 17507, 15648, 8002, 25664, 8649, 6034, 28477,
+ 12441, 31004, 2237, 12681, 13961, 22031, 9693, 15750, 27327, 10788,
+ 27572, 26873, 10173, 4711, 15732, 7006, 17372, 9564, 19167, 11136,
+ 18577, 23862, 8621, 15174, 12014, 29257, 28206, 1488, 17772, 14786,
+ 12080, 21442, 8935, 23702, 24867, 2528, 19178, 31416, 25723, 1500,
+ 26413, 3727, 9046, 15723, 14940, 9383, 14943, 21406, 12314, 15271,
+ 10482, 6256, 11846, 24707, 19585, 9884, 2941, 23282, 11062, 5041,
+ 20192, 32291, 20953, 26215, 7447, 29099, 18677, 18228, 30358, 1731,
+ 25910, 7963, 11038, 28080, 30486, 6341, 9863, 24450, 7608, 14290,
+ 31422, 4097, 16660, 31345, 19210, 31717, 30549, 14638, 31891, 26437,
+ 22911, 14604, 20516, 8274, 2901, 9172, 18736, 23109, 31354, 23212,
+ 1555, 13462, 6358, 22251, 28059, 17007, 5691, 3372, 21959, 9824,
+ 23881, 1698, 1998, 5716, 22415, 9387, 17763, 23492, 15602, 17063,
+ 13112, 9258, 29267, 10762, 19649, 13753, 15212, 3248, 17722, 23627,
+ 17403, 31089, 31211, 8859, 17443, 32502, 22955, 11188, 17423, 28874,
+ 26019, 16553, 17112, 692, 12116, 26247, 17577, 11845, 30684, 4232,
+ 3105, 5805, 21620, 17033, 760, 24275, 31806, 14270, 5606, 9636,
+ 9022, 24997, 1984, 7338, 1701, 21304, 32741, 27873, 3670, 27751,
+ 22488, 24007, 10147, 22981, 27694, 29363, 15703, 15490, 29867, 29287,
+ 28922, 3737, 10152, 3304, 31056, 5962, 11447, 5006, 18979, 971,
+ 8842, 30551, 26946, 30779, 15377, 384, 5322, 11479, 14563, 31319,
+ 7844, 27504, 15583, 12875, 8527, 285, 19219, 8517, 29152, 30765,
+ 26589, 4155, 29511, 11871, 9807, 258, 11987, 6998, 9432, 18531,
+ 22009, 23367, 15649, 3698, 4433, 20981, 27446, 10523, 16609, 31199,
+ 12262, 1278, 4510, 13239, 29292, 4221, 3120, 10775, 9551, 23826,
+ 246, 7536, 12934, 27366, 30026, 11331, 29408, 21152, 30214, 27539,
+ 13475, 16763, 29510, 25498, 5491, 31644, 2416, 17595, 13174, 22690,
+ 23410, 26808, 31158, 28286, 25163, 29733, 3015, 24197, 21965, 11292,
+ 5289, 30915, 4769, 21555, 31983, 10643, 8587, 10411, 19489, 25965,
+ 17391, 18666, 14688, 1790, 10645, 9771, 12104, 21374, 13225, 19061,
+ 18203, 6462, 26886, 3017, 32539, 7296, 32692, 32672, 12343, 18060,
+ 8110, 17045, 1770, 19200, 17129, 26718, 865, 14184, 22163, 10240,
+ 17628, 8462, 408, 6211, 9302, 25876, 13419, 4196, 25192, 11967,
+ 26115, 267, 27755, 14358, 8740, 22908, 31965, 30892, 19679, 19729,
+ 6917, 14010, 16220, 3304, 15834, 11888, 8663, 18905, 5666, 17293,
+ 9961, 4779, 17367, 28974, 3081, 25223, 31438, 27619, 850, 29612,
+ 23195, 10760, 27271, 10853, 32175, 18003, 29524, 11320, 963, 28841,
+ 8406, 30561, 7034, 24886, 15966, 3711, 20289, 444, 13170, 3212,
+ 6522, 16683, 22805, 13586, 987, 17779, 13385, 21660, 22032, 28566,
+ 14801, 1387, 6056, 26113, 32571, 11371, 26926, 6428, 32030, 16998,
+ 30870, 30240, 18081, 15734, 5340, 15401, 23100, 11968, 9447, 10124,
+ 28611, 26719, 1459, 26474, 26528, 16287, 5039, 4485, 16223, 16236,
+ 25444, 2131, 12145, 24330, 27992, 1873, 22057, 4358, 12594, 18842,
+ 5131, 15980, 5150, 32440, 32070, 570, 32371, 442, 1151, 14613,
+ 31892, 1670, 17104, 14651, 26388, 12657, 273, 18105, 22045, 19725,
+ 26198, 6110, 25618, 4674, 28600, 32239, 883, 13985, 5465, 1564,
+ 27649, 13556, 16546, 9907, 25379, 1050, 30671, 19604, 25481, 12306,
+ 25262, 23781, 26639, 2389, 3235, 32518, 24036, 24169, 2032, 17095,
+ 491, 29619, 22067, 30425, 11617, 11661, 14896, 17283, 21953, 8344,
+ 22225, 23958, 17380, 31827, 16235, 26019, 18029, 1005, 23875, 18283,
+ 25444, 2392, 20049, 11671, 19745, 7839, 8516, 23978, 7788, 29049,
+ 4806, 4147, 8674, 1310, 12288, 6471, 10395, 15961, 609, 29998,
+ 13321, 30175, 10395, 3421, 30499, 1247, 239, 18852, 29379, 32730,
+ 18603, 16809, 12621, 5045, 21745, 8853, 26002, 14605, 18617, 7437,
+ 28916, 12746, 27673, 28516, 5322, 1271, 2245, 24591, 21254, 27857,
+ 28626, 15449, 16917, 27421, 3263, 12120, 22534, 30655, 10677, 1311,
+ 28911, 32137, 18702, 11829, 5260, 6481, 14357, 5958, 16170, 20294,
+ 16140, 10521, 12739, 10884, 4724, 1218, 3435, 31461, 27016, 20505,
+ 15850, 9498, 24075, 9834, 30635, 14587, 31043, 366, 19669, 16924,
+ 4678, 11898, 7607, 1697, 24948, 9207, 26729, 10323, 27973, 19218,
+ 15280, 23539, 13381, 4532, 20771, 10958, 14428, 22709, 4748, 29329,
+ 20307, 4685, 3729, 5983, 23700, 9419, 8340, 7201, 22577, 25993,
+ 20439, 5405, 18216, 16415, 10724, 10443, 2278, 24023, 7212, 4835,
+ 7689, 24929, 4334, 23995, 19562, 2760, 21338, 17872, 17499, 22437,
+ 32503, 31650, 11053, 29587, 32322, 14278, 12022, 3298, 23704, 21814,
+ 1936, 24976, 28501, 26091, 2277, 6260, 6718, 30126, 10858, 15037,
+ 13084, 28459, 10218, 24987, 18602, 22343, 8069, 27708, 20657, 21171,
+ 20728, 20986, 370, 10689, 25119, 25811, 23108, 15991, 19640, 6169,
+ 8062, 10467, 22889, 8042, 19863, 28077, 19461, 31203, 18316, 755,
+ 9483, 15761, 17538, 5968, 7279, 14120, 16557, 20286, 14749, 12792,
+ 30064, 27807, 11452, 31772, 7366, 5270, 19759, 31477, 992, 10139,
+ 24930, 25559, 12560, 24527, 5059, 27905, 8421, 10636, 14606, 2771,
+ 24216, 27201, 19406, 3387, 31654, 10621, 16673, 12657, 10943, 20553,
+ 6843, 31716, 479, 29371, 23085, 28276, 10171, 22472, 14695, 28385,
+ 28766, 13146, 19580, 29059, 11540, 18082, 28838, 15420, 13191, 23216,
+ 11402, 21932, 24616, 18753, 26045, 29859, 6096, 2008, 3974, 988,
+ 3239, 26896, 14054, 3560, 19014, 2096, 4053, 9576, 19736, 4864,
+ 26575, 7551, 10502, 26075, 8591, 9863, 851, 11782, 7707, 8963,
+ 25540, 1600, 14080, 18645, 8453, 16794, 11743, 25266, 27720, 22665,
+ 13608, 17874, 16431, 11322, 30246, 20460, 14060, 5157, 14396, 353,
+ 2983, 27109, 3438, 1976, 19231, 1863, 10274, 19530, 30613, 27297,
+ 15912, 23358, 9190, 30053, 7417, 14008, 18935, 30965, 21308, 27214,
+ 24661, 1465, 5007, 29372, 29469, 12400, 13443, 19928, 17434, 16835,
+ 29160, 18120, 13870, 1056, 21324, 21106, 2035, 9157, 23486, 4148,
+ 8609, 21787, 26328, 17109, 31283, 13638, 22268, 21948, 22469, 6394,
+ 30941, 16992, 28481, 15760, 16449, 27136, 10042, 4185, 16902, 14228,
+ 536, 50, 3939, 7683, 29558, 3416, 22129, 18070, 9416, 2942,
+ 27626, 941, 27969, 18973, 8752, 23473, 244, 5900, 4497, 16457,
+ 6969, 20304, 13769, 17873, 10322, 29237, 1224, 28424, 12878, 27294,
+ 25270, 24840, 5422, 665, 5941, 4988, 15943, 13622, 10214, 20749,
+ 31463, 21146, 15406, 7197, 6715, 10831, 28218, 19384, 26224, 12254,
+ 11584, 29895, 14617, 19872, 5384, 29575, 11985, 22993, 24236, 10554,
+ 15905, 25062, 20124, 16925, 13732, 16416, 17380, 6041, 25960, 12130,
+ 19634, 701, 30616, 20800, 25618, 13036, 15448, 23128, 15613, 23763,
+ 27889, 22757, 16018, 21918, 10798, 18833, 5539, 28268, 14854, 28299,
+ 32627, 9216, 18554, 7386, 12734, 30393, 12225, 29681, 1018, 32452,
+ 2979, 13187, 15837, 4240, 7203, 9112, 12063, 1410, 15200, 17121,
+ 29825, 31979, 27325, 12104, 3598, 10551, 15168, 31948, 10913, 32103,
+ 5432, 28300, 19623, 20161, 8995, 17953, 11302, 16069, 25550, 7473,
+ 31231, 356, 10174, 32065, 26736, 21357, 32207, 10699, 7388, 13640,
+ 21275, 20625, 28367, 15846, 18973, 5168, 6205, 6648, 3351, 9464,
+ 15114, 2911, 8112, 23547, 24527, 31972, 29666, 3172, 20956, 32298,
+ 17939, 32523, 31865, 15328, 1154, 19526, 11634, 18491, 17893, 2049,
+ 24786, 18340, 4945, 29713, 31214, 21934, 2393, 11461, 3493, 13898,
+ 5242, 958, 8679, 10046, 19639, 32001, 1652, 26067, 13440, 8779,
+ 10982, 15566, 24280, 8357, 5618, 11938, 16567, 25655, 25067, 4068,
+ 12717, 9825, 25223, 9727, 24521, 8712, 22502, 7721, 15033, 25134,
+ 21200, 28822, 6706, 24262, 11839, 1003, 9107, 23494, 16925, 9461,
+ 12997, 15997, 13134, 9883, 19045, 19751, 1265, 15889, 20261, 3263,
+ 20195, 28495, 4719, 12564, 15749, 7618, 28748, 21279, 16064, 5441,
+ 1157, 24980, 70, 8002, 15112, 32695, 8986, 30798, 16268, 18033,
+ 18514, 14770, 4216, 7075, 23324, 2936, 14593, 5050, 15359, 12949,
+ 30355, 4484, 12643, 20324, 19827, 6210, 16724, 24659, 20642, 1022,
+ 22659, 23773, 8452, 7198, 25229, 31928, 26561, 13370, 14208, 32591,
+ 20460, 20267, 668, 1906, 17251, 30820, 1622, 24396, 28406, 18310,
+ 24995, 14486, 20939, 16942, 14962, 15627, 23552, 4113, 29050, 796,
+ 24723, 13644, 17207, 15076, 24191, 18165, 31279, 10078, 25896, 19958,
+ 5754, 14294, 6137, 19483, 3713, 21917, 5452, 5993, 3334, 14849,
+ 17546, 32690, 20581, 24700, 20371, 29286, 3865, 26924, 19296, 4268,
+ 1409, 32643, 21479, 27569, 4324, 6464, 7998, 23360, 31668, 8606,
+ 19460, 8852, 24335, 25803, 28413, 22378, 15755, 20379, 9212, 16218,
+ 15155, 22398, 9734, 5990, 5837, 7856, 12980, 31188, 18527, 10415,
+ 15577, 22073, 26865, 13042, 12901, 12247, 18323, 1496, 22921, 5672,
+ 20386, 20959, 2332, 3003, 9288, 27926, 16446, 20287, 5442, 1237,
+ 24891, 15070, 20710, 6059, 5042, 11724, 30564, 19352, 4598, 13343,
+ 29516, 29820, 26036, 24801, 15184, 24272, 22486, 3683, 24908, 12948,
+ 6056, 30933, 4739, 648, 23865, 26388, 27947, 23455, 2821, 21955,
+ 20269, 26801, 4816, 22685, 550, 32368, 8661, 9737, 26801, 9117,
+ 22560, 239, 4328, 27004, 3897, 29899, 20520, 10373, 29698, 6144,
+ 19477, 30044, 30690, 18542, 5342, 25091, 23843, 5702, 13507, 24399,
+ 25241, 20765, 22740, 21144, 21125, 27456, 30459, 13237, 30904, 10056,
+ 5436, 18215, 17404, 17390, 5692, 18581, 5807, 6688, 12032, 6521,
+ 2737, 24916, 27128, 18456, 11393, 3612, 23356, 695, 29090, 32506,
+ 27157, 19212, 28228, 27510, 21439, 32243, 3616, 18799, 19309, 866,
+ 21668, 7343, 23438, 15007, 26704, 25794, 27727, 30384, 28000, 7431,
+ 4961, 7956, 29611, 775, 4348, 18608, 31691, 5894, 7716, 23308,
+ 22398, 2776, 28715, 5567, 26956, 4854, 5495, 2600, 1898, 19921,
+ 3973, 23903, 1503, 13670, 20014, 26219, 11237, 20243, 28713, 31926,
+ 6290, 3497, 27858, 2750, 23223, 6594, 2857, 14604, 16393, 29781,
+ 18974, 17770, 8062, 10119, 7692, 23121, 8954, 31172, 10115, 31393,
+ 21547, 22287, 18250, 21908, 28849, 25750, 13220, 5877, 18819, 29322,
+ 29395, 1933, 12686, 16429, 24283, 4575, 16287, 17965, 5768, 32533,
+ 26498, 31536, 32690, 57, 11884, 18096, 16064, 22440, 32406, 5641,
+ 18283, 14020, 24107, 18384, 27333, 9194, 3428, 24935, 1657, 31908,
+ 20465, 17102, 14676, 26655, 26012, 19644, 16644, 19935, 30249, 11503,
+ 25888, 9393, 29824, 17600, 4969, 11745, 15630, 24058, 4432, 28846,
+ 29544, 8684, 26296, 2555, 25393, 1725, 26108, 9287, 26687, 9984,
+ 30004, 11231, 8697, 14216, 31924, 4946, 30211, 3966, 7894, 15398,
+ 9758, 30384, 7418, 22473, 32073, 11820, 3530, 21706, 22572, 26382,
+ 18627, 11337, 3255, 7062, 10993, 9133, 29959, 32382, 6393, 22165,
+ 8585, 29834, 25181, 7440, 30305, 19552, 27132, 8720, 14349, 10394,
+ 14296, 15900, 19269, 20506, 22556, 27206, 11302, 22685, 11102, 24413,
+ 24720, 24467, 3105, 13667, 27085, 17711, 28062, 5953, 31091, 7610,
+ 22468, 24250, 28043, 19756, 25725, 11422, 22514, 253, 8755, 20800,
+ 5376, 31801, 32659, 6441, 13672, 27091, 9360, 21006, 16223, 10555,
+ 23723, 7168, 2817, 18738, 30322, 23267, 15856, 9438, 15431, 23585,
+ 10814, 22297, 27235, 1184, 5261, 30735, 17947, 6897, 9588, 22792,
+ 14945, 458, 2597, 12930, 7565, 30390, 2125, 30851, 1118, 10507,
+ 2364, 18733, 17979, 15644, 24646, 10643, 5823, 4017, 20585, 1227,
+ 22645, 19892, 5424, 8517, 3296, 13357, 29398, 90, 1471, 3185,
+ 4527, 23592, 15246, 14485, 10436, 14238, 27984, 25641, 15293, 13523,
+ 28044, 11555, 28677, 9628, 16534, 22810, 15656, 2653, 28687, 27317,
+ 31872, 29471, 14255, 11106, 7184, 30435, 28482, 32075, 30896, 13622,
+ 22001, 2438, 9067, 5638, 8899, 7819, 5669, 15284, 32356, 21228,
+ 7040, 23402, 18980, 16448, 28161, 28591, 22594, 27232, 21103, 31033,
+ 31083, 9943, 12668, 16898, 894, 6291, 29864, 22174, 13714, 5089,
+ 10849, 10699, 7482, 32408, 13679, 5706, 24840, 147, 2959, 13037,
+ 5199, 6245, 18270, 11506, 30765, 26697, 4473, 7311, 19913, 20312,
+ 9443, 1998, 7642, 8959, 29351, 1947, 6505, 7343, 10430, 17179,
+ 30679, 20438, 8242, 13632, 30241, 15375, 30340, 28827, 23395, 20373,
+ 22092, 21873, 9883, 28158, 13087, 28176, 18864, 20262, 31925, 25955,
+ 5555, 19049, 3403, 19397, 15460, 25109, 22343, 7699, 2808, 8990,
+ 5659, 17157, 16921, 11540, 1643, 29374, 12079, 30291, 26994, 15521,
+ 27358, 8314, 22434, 8039, 24783, 28958, 9866, 26478, 1204, 17087,
+ 26109, 18260, 22662, 506, 14449, 24261, 10257, 2817, 2725, 9105,
+ 7603, 31561, 28295, 24834, 5217, 19330, 7508, 16748, 19178, 17868,
+ 25857, 5637, 23680, 11304, 1242, 20727, 8820, 9004, 15721, 26036,
+ 25409, 13564, 6041, 906, 29388, 117, 10011, 24183, 10218, 26795,
+ 19465, 31294, 19235, 22678, 14281, 11194, 25270, 28424, 14645, 17523,
+ 32732, 9954, 5112, 7279, 29009, 20360, 26427, 28235, 32529, 27026,
+ 26498, 14730, 4959, 15301, 28624, 7980, 29964, 13377, 11794, 27778,
+ 30454, 27131, 28346, 18498, 16591, 21102, 19371, 13783, 5408, 32654,
+ 16981, 25338, 14477, 31230, 29985, 29574, 24154, 2946, 7183, 16264,
+ 15918, 3511, 26781, 14230, 14103, 4354, 24812, 25443, 9167, 28614,
+ 30238, 11920, 17470, 8666, 23042, 30660, 24639, 25658, 22515, 5630,
+ 1959, 2300, 13565, 18474, 4996, 902, 23362, 17139, 19618, 1279,
+ 21660, 20697, 23380, 15619, 22660, 14467, 25712, 4763, 28979, 23894,
+ 30620, 26988, 31750, 20038, 13000, 18222, 2343, 14060, 16124, 28000,
+ 24170, 26329, 2644, 15162, 8565, 25387, 25417, 27620, 27940, 13918,
+ 22833, 1253, 22060, 29284, 1545, 2270, 8958, 6391, 9587, 17016,
+ 15086, 24110, 7419, 15259, 4244, 31054, 22942, 13537, 2930, 30691,
+ 9869, 12618, 13528, 18192, 24878, 27185, 11269, 26404, 11876, 16254,
+ 9615, 32109, 5392, 30750, 31237, 14417, 8664, 26288, 2002, 14746,
+ 30759, 18049, 27748, 31506, 29812, 25787, 22670, 24912, 17352, 27097,
+ 1067, 28881, 5242, 22366, 1285, 22859, 17469, 3527, 3317, 19261,
+ 12126, 28350, 21323, 19403, 1350, 28560, 11631, 31433, 17990, 12257,
+ 6857, 32534, 20116, 26783, 18399, 3371, 4752, 18228, 19645, 15347,
+ 28748, 2304, 10906, 7134, 14924, 27398, 19640, 17457, 24458, 16869,
+ 4236, 19104, 21693, 19979, 6431, 22814, 8923, 8229, 29108, 22004,
+ 16093, 8665, 17323, 21008, 3778, 5816, 9125, 12704, 16342, 10606,
+ 14825, 17120, 21044, 22844, 18951, 14128, 32138, 23465, 23995, 12906,
+ 21276, 18036, 5907, 25714, 16652, 5580, 28116, 24847, 23256, 25283,
+ 23579, 10745, 2852, 24065, 15936, 7987, 4794, 25269, 27135, 18842,
+ 30927, 13778, 16602, 13247, 20616, 17783, 16825, 17650, 30652, 31918,
+ 24020, 21151, 13052, 32602, 5330, 23518, 19152, 25195, 7218, 9029,
+ 3652, 13396, 5611, 6912, 24227, 27071, 6735, 22308, 10371, 639,
+ 6453, 31297, 28161, 31430, 22103, 20535, 17998, 23704, 1273, 2890,
+ 30315, 1407, 18124, 22392, 1840, 29825, 4625, 14345, 31891, 13391,
+ 17153, 25449, 4647, 13759, 23661, 4403, 8419, 11900, 15266, 28302,
+ 4645, 20476, 17295, 11452, 1014, 27315, 17194, 24048, 656, 20871,
+ 6927, 5216, 31518, 4483, 26218, 30620, 19394, 20943, 11032, 17438,
+ 5340, 28640, 21769, 26914, 12170, 11244, 233, 14520, 28011, 31137,
+ 23039, 24087, 1449, 18710, 3925, 3636, 21302, 23554, 9241, 9875,
+ 18517, 31532, 8003, 11869, 15197, 8226, 24184, 28084, 28857, 26414,
+ 4142, 3907, 1588, 23942, 6418, 25, 9076, 32707, 26790, 439,
+ 5059, 31892, 303, 8807, 11542, 4020, 14030, 4048, 10311, 2329,
+ 27117, 30664, 20134, 21615, 16604, 27497, 8368, 5316, 9404, 30823,
+ 23070, 10373, 1437, 27808, 30498, 10665, 10723, 30709, 7917, 15916,
+ 3310, 8281, 6004, 19647, 4346, 15399, 9844, 27070, 2115, 26297,
+ 947, 4194, 22893, 9014, 16522, 31800, 17188, 8619, 18592, 14033,
+ 768, 23134, 24568, 11707, 25515, 29535, 16942, 25777, 30277, 9311,
+ 18173, 6159, 31495, 3269, 12293, 25481, 15655, 12287, 971, 16667,
+ 26108, 3094, 6658, 29763, 2915, 32390, 15625, 13679, 32097, 27468,
+ 1204, 12721, 5898, 23104, 20047, 12986, 5793, 32421, 30176, 774,
+ 16640, 23807, 13485, 25172, 21562, 804, 18686, 7769, 3456, 1686,
+ 19236, 9141, 17985, 15632, 21434, 6950, 27797, 25439, 22315, 26364,
+ 23260, 9843, 23157, 5325, 21154, 17078, 25900, 5993, 7879, 11677,
+ 21697, 23824, 8412, 32124, 29956, 5603, 19919, 926, 488, 16025,
+ 24011, 19605, 30342, 17267, 13146, 31439, 19813, 20338, 15821, 12138,
+ 5625, 7111, 23261, 30025, 873, 21387, 31634, 25192, 22678, 24496,
+ 4196, 25452, 21848, 12088, 161, 25983, 2314, 20388, 12558, 21082,
+ 11850, 27056, 24017, 4771, 29690, 30269, 19342, 2682, 22410, 16271,
+ 5073, 17487, 29818, 696, 4268, 15862, 27930, 17748, 11169, 3069,
+ 20629, 13175, 5057, 18237, 8749, 6628, 7958, 30895, 26056, 20608,
+ 23359, 30593, 21932, 10502, 4442, 28009, 9607, 13819, 16679, 30010,
+ 30386, 32229, 22377, 1973, 25014, 28344, 9104, 10913, 14608, 9617,
+ 20630, 5662, 26929, 24230, 25895, 17462, 6601, 8573, 3844, 7861,
+ 29765, 32093, 15785, 16186, 13206, 27139, 20526, 30095, 24885, 8341,
+ 23147, 2102, 25444, 220, 17759, 25412, 16566, 22189, 20179, 10611,
+ 15569, 5032, 11322, 23410, 12915, 20774, 21724, 2431, 20147, 11884,
+ 14131, 17208, 4490, 24357, 23957, 14766, 14225, 32271, 17940, 18364,
+ 28940, 30708, 29091, 21655, 2600, 8924, 28282, 17573, 26753, 21889,
+ 25019, 27795, 487, 4867, 21589, 15010, 12386, 7901, 18216, 2625,
+ 1907, 3352, 21099, 21985, 3741, 8894, 21579, 15109, 1316, 6802,
+ 29397, 1176, 4885, 8702, 29974, 12164, 2950, 8781, 14209, 7552,
+ 9247, 10778, 16273, 27177, 17882, 2824, 12975, 5717, 23302, 32692,
+ 13397, 32164, 16018, 28136, 28532, 19032, 12424, 6418, 20243, 23398,
+ 29656, 22772, 10809, 20684, 31063, 10396, 26382, 12838, 15367, 8599,
+ 22845, 25468, 12953, 14178, 24476, 23647, 31280, 18209, 1295, 21812,
+ 7784, 20371, 10410, 24271, 8855, 25926, 28949, 6212, 12371, 14087,
+ 3893, 30457, 3892, 13981, 5128, 21760, 18906, 14775, 24017, 14756,
+ 9266, 10018, 24694, 4162, 18166, 1087, 19750, 16731, 17523, 30389,
+ 23870, 25062, 23183, 3683, 17518, 27883, 5642, 27545, 3608, 15181,
+ 15108, 5511, 27128, 11752, 5824, 5365, 11274, 15835, 7847, 10037,
+ 936, 26407, 144, 7510, 11763, 8570, 2110, 15259, 10101, 23365,
+ 32298, 11563, 8453, 11028, 25475, 24586, 15338, 11039, 12148, 23880,
+ 20803, 13084, 29093, 29049, 18598, 25688, 32260, 14693, 16903, 15366,
+ 1477, 26368, 5851, 8151, 16807, 21148, 30334, 6347, 4474, 11357,
+ 8658, 12358, 13534, 25069, 2602, 9062, 333, 3186, 22374, 24724,
+ 14684, 31421, 6495, 857, 26941, 11204, 10373, 17011, 27785, 19795,
+ 31174, 1065, 316, 4862, 27058, 3291, 3074, 31066, 17117, 31709,
+ 29105, 18797, 901, 2694, 10774, 28770, 9845, 16771, 28660, 32641,
+ 29481, 6257, 12874, 26719, 6451, 13228, 10965, 18770, 6878, 13409,
+ 15830, 24104, 19216, 20203, 1813, 26905, 25205, 7004, 14374, 10233,
+ 28633, 21593, 11243, 10675, 10198, 30764, 21338, 6130, 22448, 20,
+ 24448, 18721, 32637, 8671, 19654, 11926, 22409, 20411, 13172, 29450,
+ 17656, 27210, 371, 23885, 429, 22772, 343, 19255, 31595, 31873,
+ 21149, 22754, 11834, 12263, 14128, 2070, 32269, 19296, 23090, 31749,
+ 21409, 24000, 29690, 7481, 168, 4102, 28505, 14794, 12071, 26417,
+ 29730, 30164, 24605, 22613, 31465, 8232, 15717, 25325, 19978, 16194,
+ 17117, 9587, 7150, 27260, 712, 8238, 32393, 17281, 2417, 6732,
+ 7207, 9219, 9234, 23856, 17769, 21425, 3827, 14861, 13450, 23139,
+ 20182, 3508, 20967, 17048, 14739, 13994, 8639, 24611, 29184, 12670,
+ 16183, 28449, 23315, 20313, 2209, 7982, 17995, 15063, 24829, 24281,
+ 24907, 16149, 10944, 31573, 9929, 1292, 24533, 26737, 22182, 15133,
+ 27362, 17609, 14686, 23276, 9676, 28222, 12963, 370, 8573, 15013,
+ 26437, 3406, 6885, 10428, 31317, 30556, 16702, 7522, 9610, 6537,
+ 12693, 263, 12515, 22502, 19334, 20833, 3470, 24571, 17223, 31584,
+ 6153, 29277, 5352, 4453, 17799, 27267, 15576, 12719, 16533, 30933,
+ 22956, 12565, 14589, 17158, 6940, 24059, 27371, 24228, 8782, 28543,
+ 8526, 23021, 14168, 29939, 14209, 18149, 30720, 22928, 24107, 31909,
+ 25541, 20584, 10084, 758, 26916, 15517, 7705, 23582, 22548, 27089,
+ 27825, 8442, 24019, 10461, 22256, 9037, 28132, 9414, 2844, 2648,
+ 15449, 1005, 3679, 7595, 11598, 10629, 18541, 12858, 23990, 11082,
+ 29286, 28083, 10586, 20336, 27902, 21519, 21022, 9946, 16859, 21352,
+ 11398, 6029, 21567, 16906, 30074, 27492, 1254, 716, 13638, 14085,
+ 19762, 17313, 21477, 11539, 5509, 2666, 17023, 12710, 19182, 1038,
+ 24112, 16888, 30729, 18893, 28683, 1121, 25888, 4305, 28255, 5253,
+ 918, 30726, 25400, 24524, 10374, 26668, 7209, 9746, 23207, 14891,
+ 1865, 29344, 14195, 6054, 24956, 8539, 13192, 18898, 6644, 17468,
+ 14926, 27273, 3831, 32000, 28890, 11162, 2018, 7969, 8210, 10340,
+ 4206, 11780, 2578, 30115, 6450, 2932, 11983, 25481, 361, 27215,
+ 17402, 9745, 28150, 22911, 25640, 22416, 4517, 31532, 14639, 2444,
+ 19124, 15408, 9683, 22482, 14738, 8140, 12962, 12739, 13542, 29593,
+ 16924, 19951, 16083, 32705, 20503, 31717, 24442, 1902, 16482, 18504,
+ 2241, 11651, 169, 10022, 26451, 4491, 408, 6278, 17641, 14574,
+ 19267, 31552, 24519, 6251, 12486, 530, 23433, 20930, 26408, 32495,
+ 12063, 31153, 902, 30874, 13335, 31266, 9325, 15988, 15130, 25763,
+ 19079, 28307, 18874, 18710, 9338, 8723, 25963, 25770, 21005, 13233,
+ 4046, 15626, 25229, 21653, 22582, 31700, 4719, 25456, 9829, 7756,
+ 3126, 14791, 8854, 19794, 12439, 25487, 24257, 29073, 10715, 29945,
+ 9498, 22522, 20102, 29327, 4058, 31345, 5942, 32640, 20035, 16581,
+ 11213, 17976, 15070, 19942, 19410, 20276, 9992, 11602, 5653, 14869,
+ 32684, 29905, 29586, 3315, 12114, 11874, 10648, 3571, 24921, 7797,
+ 22315, 23324, 2688, 14938, 24998, 13414, 23212, 25338, 5285, 11284,
+ 31717, 14277, 31009, 12612, 17057, 5611, 10205, 10437, 13125, 6095,
+ 6913, 2088, 233, 10425, 17157, 10010, 26971, 202, 25297, 15089,
+ 4711, 7478, 30499, 12420, 19542, 2221, 11568, 22592, 23989, 2074,
+ 11406, 6264, 15448, 32656, 14417, 6653, 22430, 9089, 27509, 8943,
+ 22517, 18994, 5244, 5074, 30625, 29035, 29783, 15076, 22714, 19571,
+ 25738, 29102, 31860, 28220, 10380, 14554, 16292, 25562, 28268, 17988,
+ 127, 21305, 17082, 14676, 20900, 29200, 31653, 27018, 24157, 26897,
+ 24417, 858, 25633, 30563, 2508, 26427, 25950, 27217, 21840, 32507,
+ 31094, 15684, 19211, 32085, 24071, 30190, 24109, 15301, 11632, 4297,
+ 30370, 10907, 24209, 4544, 3826, 1871, 29138, 3371, 26981, 19732,
+ 28518, 15617, 8298, 5039, 6865, 30281, 5689, 20618, 32679, 4818,
+ 1976, 11780, 15255, 8996, 18075, 27916, 10665, 31926, 24272, 1262,
+ 21188, 30818, 11034, 30060, 18291, 29973, 7420, 32529, 18152, 29387,
+ 15320, 13762, 22338, 22971, 8024, 8598, 13067, 16846, 26893, 25064,
+ 12293, 20054, 342, 1706, 806, 29181, 7044, 5115, 1505, 12027,
+ 17723, 25596, 24743, 10125, 1307, 23264, 16046, 4770, 19616, 8515,
+ 28401, 26839, 16711, 22717, 5752, 23973, 8435, 32438, 22489, 30937,
+ 17806, 29052, 5119, 25669, 3059, 19346, 10282, 16822, 8716, 2380,
+ 19767, 7462, 55, 11416, 31778, 20274, 4591, 21279, 31689, 25550,
+ 20904, 29325, 31730, 22839, 23546, 12076, 24976, 19241, 15874, 184,
+ 10306, 24147, 774, 6511, 32029, 8, 17751, 17255, 30379, 20023,
+ 18044, 10276, 3635, 15261, 21132, 13930, 15931, 17465, 29404, 6736,
+ 27212, 17920, 13274, 31638, 29685, 20947, 569, 30264, 8466, 2222,
+ 25423, 323, 14159, 22818, 3259, 14312, 28903, 12549, 8010, 14543,
+ 11954, 30568, 2332, 4014, 2910, 25289, 21250, 23833, 13308, 32650,
+ 23851, 12444, 10687, 31394, 20224, 18695, 20737, 1171, 15948, 12041,
+ 29063, 24732, 20896, 24064, 3078, 29743, 25078, 28432, 10470, 27301,
+ 24468, 31346, 1093, 16689, 32307, 8975, 15167, 20242, 27745, 78,
+ 24173, 7693, 6692, 23082, 3499, 10011, 21216, 27527, 287, 18271,
+ 11898, 7878, 9079, 346, 7614, 30871, 8561, 24162, 5630, 9486,
+ 4769, 1104, 8188, 23290, 8047, 21370, 19979, 2418, 18527, 8417,
+ 23920, 944, 12949, 24747, 1806, 7971, 7576, 21715, 17219, 30655,
+ 26198, 5151, 1293, 20120, 15208, 32082, 12401, 13999, 26264, 27299,
+ 20509, 1035, 20384, 14703, 20044, 12556, 7221, 31275, 13546, 11773,
+ 4420, 23708, 14584, 20200, 6524, 11338, 5427, 19374, 5388, 28978,
+ 30704, 1622, 22190, 2235, 2123, 2982, 29156, 19179, 18048, 496,
+ 16001, 4059, 19353, 31279, 13676, 10600, 11338, 22355, 2721, 9516,
+ 793, 16344, 10360, 27309, 26049, 19869, 28714, 2515, 18905, 28660,
+ 25489, 19872, 7345, 13301, 7215, 26395, 4733, 26393, 13170, 17549,
+ 28853, 18436, 54, 26864, 22459, 14753, 19852, 22437, 20415, 11380,
+ 28346, 26725, 7392, 12844, 21635, 6010, 7827, 28536, 1960, 9775,
+ 15945, 24604, 11438, 8069, 12620, 8516, 29922, 5415, 4586, 13848,
+ 8347, 10400, 5078, 31376, 30399, 13516, 22475, 14474, 21896, 11148,
+ 8818, 4890, 16520, 31678, 31366, 15393, 4075, 4973, 29238, 10273,
+ 9469, 21060, 8139, 13391, 18412, 73, 2442, 29418, 4814, 7368,
+ 2268, 4556, 3557, 6540, 26796, 3903, 24866, 22101, 17169, 12561,
+ 16105, 28807, 25133, 29163, 27668, 15136, 10325, 22750, 2362, 29420,
+ 17265, 28479, 305, 764, 12198, 18613, 16593, 27988, 19763, 20880,
+ 7163, 11236, 3481, 22364, 986, 7610, 31743, 32694, 29289, 21621,
+ 9428, 8543, 12086, 22013, 8374, 13199, 20837, 9841, 18067, 18316,
+ 8951, 11873, 18702, 16506, 18765, 20798, 17188, 15733, 22247, 18446,
+ 30735, 27101, 10866, 5220, 19050, 10225, 16130, 8080, 11927, 18848,
+ 20892, 23059, 7262, 19355, 32759, 28502, 17366, 18095, 17539, 24987,
+ 2441, 2898, 29611, 8755, 3539, 7036, 7767, 31217, 17291, 30392,
+ 32182, 21984, 23013, 27770, 19514, 19505, 32151, 26803, 12260, 28023,
+ 13627, 28323, 6593, 13847, 23797, 13806, 16053, 13305, 1365, 7667,
+ 3447, 13444, 14719, 27481, 17885, 3786, 28809, 1002, 5466, 24063,
+ 11812, 7333, 23749, 16432, 5759, 3598, 859, 27953, 31080, 17097,
+ 31496, 14808, 6325, 29799, 23010, 23400, 11746, 10880, 11510, 32592,
+ 29435, 12290, 26696, 2838, 12988, 29384, 6165, 6286, 9208, 367,
+ 14171, 591, 5175, 7013, 20380, 5223, 9635, 1858, 17886, 13646,
+ 9253, 9052, 30966, 6937, 13771, 25749, 5382, 24816, 27245, 14200,
+ 16453, 4290, 28304, 30597, 1278, 30007, 25994, 28872, 7388, 18407,
+ 12007, 8113, 356, 4041, 6924, 8991, 26051, 17390, 21274, 5310,
+ 32202, 1647, 30741, 15251, 13879, 2980, 15686, 19669, 16950, 406,
+ 477, 12031, 8743, 2999, 11739, 29475, 1954, 9937, 22063, 30849,
+ 15032, 2365, 27679, 28248, 25724, 21333, 31722, 10236, 25283, 9259,
+ 16044, 30505, 2343, 26236, 897, 151, 29522, 27103, 13293, 16078,
+ 19577, 7234, 30588, 10044, 12326, 30615, 15013, 9605, 2107, 30667,
+ 7412, 24858, 3124, 11512, 2665, 269, 17836, 15835, 1051, 25124,
+ 15906, 28296, 23584, 29484, 14846, 32604, 26801, 11151, 9423, 30772,
+ 29322, 20521, 4823, 13276, 25232, 31320, 31689, 16331, 29366, 5458,
+ 4817, 25613, 26145, 17852, 24533, 26496, 3211, 28536, 32251, 25667,
+ 5349, 19902, 9067, 16492, 29504, 20846, 22102, 7929, 24045, 14756,
+ 29495, 23818, 9699, 6797, 26712, 28493, 28258, 18042, 19096, 13241,
+ 2006, 19763, 10093, 2943, 29182, 1422, 14373, 20797, 18765, 21824,
+ 23153, 32629, 9105, 10994, 29219, 6975, 8146, 24216, 6199, 14138,
+ 11645, 27646, 15120, 8904, 20162, 15267, 5125, 6523, 23098, 28107,
+ 5660, 1738, 32717, 23504, 14869, 12809, 5331, 17337, 19371, 26264,
+ 27513, 21005, 7190, 27738, 14694, 32234, 15828, 25704, 20895, 27473,
+ 11689, 24071, 13736, 18372, 3301, 14296, 16877, 21779, 20709, 8527,
+ 31072, 5747, 3036, 20582, 13410, 21456, 13012, 16275, 14055, 26468,
+ 1263, 2039, 29141, 2441, 30707, 11224, 29614, 3787, 19973, 25937,
+ 19567, 19522, 14517, 19784, 26808, 5663, 11579, 28321, 10284, 3204,
+ 19968, 6577, 13083, 10905, 3425, 3062, 21343, 19420, 28079, 16389,
+ 21635, 7096, 634, 31171, 12075, 9050, 5903, 25304, 943, 27072,
+ 7743, 19297, 10250, 23058, 20322, 25317, 19699, 25654, 5276, 32139,
+ 32329, 2975, 11871, 14730, 692, 22629, 12337, 6368, 24202, 24219,
+ 15024, 25415, 32239, 20445, 5843, 25701, 19009, 19240, 5746, 23107,
+ 11955, 24302, 24073, 10240, 20535, 29034, 31673, 8391, 31906, 818,
+ 28559, 32510, 5386, 11, 2313, 23488, 30579, 4608, 15830, 14990,
+ 11179, 10934, 24030, 32065, 22387, 14074, 18562, 21571, 15839, 12444,
+ 1829, 32511, 19968, 640, 28907, 28822, 1216, 29426, 15296, 11476,
+ 9740, 2106, 7837, 29026, 4409, 7024, 26886, 32573, 13472, 3474,
+ 13272, 6246, 25740, 21204, 3905, 1500, 6487, 18487, 21008, 14791,
+ 22735, 1885, 28207, 25078, 20190, 11420, 28269, 32395, 22891, 17233,
+ 385, 20725, 2939, 19575, 13900, 14111, 27548, 4984, 19807, 18151,
+ 29059, 17730, 17341, 15826, 1780, 32158, 31458, 6398, 4066, 16061,
+ 8708, 26968, 15832, 1812, 17560, 14350, 12951, 31083, 8728, 3912,
+ 13825, 19248, 13060, 31507, 821, 27920, 32551, 5789, 28924, 8649,
+ 10523, 31144, 31076, 30521, 21263, 6713, 25770, 21947, 16584, 30352,
+ 7005, 6580, 23270, 7005, 25537, 27497, 30569, 23089, 3698, 18708,
+ 2931, 17459, 22089, 30518, 10831, 15636, 30595, 19246, 30131, 14917,
+ 16928, 1035, 25410, 615, 11146, 9631, 31573, 259, 9079, 2516,
+ 29947, 635, 12304, 7236, 21311, 27712, 5459, 29699, 26537, 17734,
+ 2998, 16319, 24071, 8885, 18957, 14348, 13676, 19682, 26285, 3065,
+ 19066, 12413, 21458, 31719, 22237, 28684, 31550, 5787, 2584, 10647,
+ 15651, 19601, 8068, 17573, 22083, 19859, 5525, 23656, 29014, 25739,
+ 27232, 6709, 26540, 17814, 346, 5175, 29971, 601, 5731, 1123,
+ 25339, 6296, 25091, 27566, 28376, 20228, 21235, 30078, 28616, 21589,
+ 223, 12127, 32630, 21657, 15466, 26872, 10814, 30924, 24691, 20541,
+ 27282, 1192, 18582, 7654, 29596, 1726, 4342, 26143, 3876, 20166,
+ 826, 24961, 4789, 7732, 21718, 16961, 12283, 18188, 6796, 27047,
+ 9328, 11510, 5426, 4546, 3128, 23701, 15285, 16219, 23624, 11541,
+ 9822, 4135, 18382, 8195, 16212, 14656, 5325, 29538, 23651, 18902,
+ 9224, 6651, 9723, 1570, 12322, 3572, 28540, 28316, 2051, 12708,
+ 25776, 18286, 18558, 12966, 12441, 13352, 22832, 9004, 366, 15285,
+ 12459, 15766, 3552, 18574, 9172, 1604, 32673, 31021, 17545, 16296,
+ 26407, 21701, 4999, 25759, 7342, 14384, 2443, 7425, 12924, 3881,
+ 15288, 24694, 23656, 11707, 7993, 15244, 28829, 24057, 12327, 27399,
+ 26012, 30192, 32685, 16761, 29056, 2522, 28010, 2834, 11910, 3733,
+ 4118, 25528, 26828, 83, 4457, 13146, 31065, 24978, 312, 17538,
+ 21086, 9807, 25570, 10538, 8379, 24438, 32746, 25041, 9925, 15006,
+ 12005, 31438, 13383, 10739, 13719, 5091, 24519, 18547, 26457, 1557,
+ 25866, 20062, 6333, 7099, 19674, 10727, 9589, 3798, 16902, 4144,
+ 3441, 16800, 14251, 6773, 27976, 25960, 17586, 17288, 21977, 924,
+ 22682, 22909, 18226, 7464, 11639, 14246, 21169, 21502, 6971, 23746,
+ 10344, 21238, 12341, 12657, 5062, 26585, 13015, 4843, 11124, 952,
+ 28860, 30194, 14462, 5507, 32490, 13829, 6323, 29399, 20308, 25815,
+ 8270, 17174, 16291, 11775, 16086, 8381, 1333, 8945, 27458, 25842,
+ 6758, 813, 7009, 20829, 4367, 21686, 19065, 3129, 28237, 24774,
+ 21295, 8875, 29572, 26816, 8358, 1362, 30883, 10086, 31467, 13087,
+ 15273, 29260, 29329, 1639, 18792, 3980, 12184, 22582, 25480, 5052,
+ 10132, 28135, 2000, 23581, 32522, 25841, 31905, 30997, 6686, 4356,
+ 1731, 7392, 8299, 85, 11365, 25218, 30771, 6710, 10590, 256,
+ 31928, 3049, 30905, 16079, 29673, 30646, 6001, 14733, 1857, 6715,
+ 25721, 21999, 17389, 23044, 16895, 27643, 26157, 30043, 23538, 887,
+ 29692, 16993, 14274, 13473, 27379, 13662, 29031, 288, 1387, 8534,
+ 18852, 14651, 23266, 26333, 27021, 16713, 24480, 1323, 32583, 19304,
+ 1945, 16755, 6159, 22898, 4246, 22641, 23421, 6957, 14224, 28227,
+ 3082, 31938, 23900, 12409, 28881, 31089, 24206, 24175, 3218, 1666,
+ 8855, 11227, 17916, 10879, 9776, 12706, 25900, 5280, 1276, 24816,
+ 2673, 18567, 18024, 11399, 594, 12845, 29143, 23639, 6866, 13853,
+ 11772, 16207, 24050, 4576, 28550, 12148, 21880, 8376, 31491, 7216,
+ 15343, 22673, 15870, 3820, 16111, 4916, 17259, 24033, 13982, 30654,
+ 18246, 298, 30327, 6224, 11638, 15902, 6986, 6153, 24567, 7390,
+ 31364, 27953, 22584, 23594, 5809, 5047, 22466, 22393, 15679, 17374,
+ 5147, 4936, 12677, 307, 23018, 25522, 2308, 5570, 27483, 24897,
+ 7404, 19849, 7621, 8196, 13538, 1581, 31371, 23777, 20224, 26348,
+ 26432, 5421, 10525, 21715, 6414, 15482, 28495, 30513, 22360, 1200,
+ 13231, 24651, 20894, 27744, 4956, 11857, 3233, 1876, 11459, 14481,
+ 10952, 13675, 19229, 7403, 5059, 15268, 27448, 16773, 16238, 29560,
+ 32123, 7872, 10232, 1133, 2341, 25962, 10052, 23528, 5333, 21813,
+ 17295, 22338, 30799, 22375, 12116, 21535, 31613, 12756, 108, 6907,
+ 26292, 26121, 25210, 22534, 26681, 4299, 18566, 5682, 29444, 24000,
+ 25064, 28810, 31427, 25451, 22120, 28101, 12578, 31582, 3491, 14875,
+ 10314, 27306, 1457, 13143, 32423, 28315, 32004, 31534, 30703, 418,
+ 29587, 975, 10080, 27795, 18232, 19131, 3913, 30736, 28503, 13783,
+ 22987, 21061, 7105, 18111, 3809, 31959, 15064, 6238, 27550, 22294,
+ 10995, 23228, 16054, 6266, 6916, 16662, 28224, 20301, 24184, 5684,
+ 2746, 14245, 14430, 27383, 4942, 32405, 25036, 4914, 20307, 17828,
+ 20350, 25786, 24855, 31358, 31425, 27841, 30172, 22250, 12687, 3935,
+ 14112, 7420, 12796, 17778, 24866, 25484, 5329, 27816, 8865, 1767,
+ 19318, 24026, 10727, 4547, 13589, 15772, 774, 12921, 3836, 15122,
+ 11106, 4206, 17475, 12549, 32367, 5586, 24751, 23861, 24508, 398,
+ 10967, 8689, 17969, 21879, 10629, 1510, 3221, 29896, 6239, 26165,
+ 11090, 1743, 4039, 3784, 16253, 29158, 25599, 11493, 785, 677,
+ 32657, 20483, 6779, 4950, 15598, 27869, 23388, 18345, 853, 5830,
+ 28810, 12458, 10998, 25404, 32600, 27887, 27736, 11199, 12823, 6422,
+ 24312, 8676, 19420, 9327, 19251, 27045, 10628, 24053, 21349, 11771,
+ 21494, 19843, 14419, 25519, 1960, 11588, 15558, 11884, 21861, 5996,
+ 27769, 7194, 16461, 15397, 18997, 10855, 32029, 13260, 10555, 19110,
+ 14000, 16734, 13794, 22493, 31686, 6445, 29057, 13081, 14853, 32728,
+ 9615, 31237, 27197, 21881, 4617, 3003, 20976, 24864, 23316, 20442,
+ 32274, 28801, 31204, 29657, 23309, 8169, 13532, 4763, 3592, 24183,
+ 25335, 31299, 29545, 648, 32358, 1097, 26264, 627, 19067, 13262,
+ 14086, 9591, 4293, 3628, 28271, 16625, 14717, 25042, 19548, 21970,
+ 17184, 28495, 6891, 8785, 23902, 10412, 16594, 31709, 11059, 31487,
+ 13474, 1366, 28756, 22077, 13641, 5500, 11724, 26448, 27611, 25000,
+ 29159, 14441, 23186, 16570, 24399, 11160, 15635, 6738, 12149, 922,
+ 15858, 22083, 13362, 28402, 9593, 24644, 7343, 18747, 26021, 5097,
+ 386, 1724, 10098, 9426, 31769, 32317, 15704, 22307, 19804, 1305,
+ 7958, 7219, 22414, 4501, 21166, 26505, 28532, 22384, 26289, 20484,
+ 18618, 4795, 25020, 20825, 402, 29931, 19267, 16835, 4510, 26669,
+ 12685, 20469, 8208, 7417, 20736, 7508, 1296, 5610, 16543, 18531,
+ 31326, 9677, 18385, 31614, 16184, 5112, 16740, 21452, 13182, 23261,
+ 12241, 13423, 11796, 13534, 26306, 23037, 4744, 27491, 28113, 16948,
+ 27124, 7210, 147, 15337, 806, 26847, 20437, 13122, 24063, 17645,
+ 26661, 3621, 26137, 21907, 24981, 11504, 16556, 6202, 15547, 25451,
+ 12723, 17158, 4348, 32251, 23626, 5035, 28683, 10008, 25179, 130,
+ 8876, 16640, 10105, 32732, 8894, 1965, 15116, 22934, 30328, 3845,
+ 11695, 14061, 20723, 29010, 21974, 25748, 7144, 16881, 18356, 31492,
+ 20156, 6222, 1116, 24852, 14009, 18192, 9254, 23753, 5279, 5008,
+ 84, 9839, 13147, 400, 8181, 12776, 23574, 1834, 27658, 8773,
+ 19313, 15622, 28392, 7059, 3087, 24272, 8925, 26359, 23125, 12265,
+ 5142, 7422, 30061, 6237, 22976, 18990, 401, 3606, 10862, 16865,
+ 24454, 7759, 4027, 4947, 7526, 11083, 32048, 21753, 25763, 12870,
+ 20072, 14868, 2377, 11692, 28785, 9863, 7811, 26505, 14966, 13541,
+ 13409, 20544, 14747, 25295, 8920, 11649, 29737, 22397, 1547, 13685,
+ 26603, 30874, 20424, 27195, 18392, 16725, 4694, 18840, 15601, 4021,
+ 26734, 9450, 11885, 23596, 7815, 13662, 21780, 3952, 343, 16483,
+ 7657, 27270, 30102, 24671, 8203, 13599, 15621, 17824, 10717, 9768,
+ 3247, 917, 10597, 15005, 22638, 15934, 29682, 28318, 30642, 19425,
+ 12546, 3268, 1918, 7935, 27746, 1973, 11699, 3206, 5015, 4598,
+ 8593, 16968, 25213, 26625, 7547, 428, 814, 152, 7674, 29347,
+ 25893, 5976, 4613, 8926, 4004, 17809, 24704, 1343, 29522, 7509,
+ 26370, 1421, 32553, 31439, 21979, 1131, 31887, 32726, 3414, 20363,
+ 30403, 28098, 24635, 27167, 12667, 20863, 24472, 14736, 29388, 13792,
+ 5057, 27251, 9289, 20533, 18070, 8633, 3951, 23327, 17156, 20005,
+ 14657, 5027, 11727, 11780, 8495, 3198, 23438, 23832, 26428, 19384,
+ 18423, 32469, 7520, 26236, 4700, 22736, 18475, 3879, 9078, 29044,
+ 21164, 18847, 24674, 1782, 31121, 14822, 3817, 29324, 29071, 16623,
+ 20228, 19418, 19717, 23472, 19871, 24749, 25820, 30840, 5278, 21740,
+ 18609, 13955, 7198, 32460, 31286, 17356, 253, 21314, 30677, 19746,
+ 1180, 30398, 23191, 13438, 14819, 17942, 2885, 404, 902, 27584,
+ 21197, 16552, 18311, 21829, 18918, 17315, 31741, 7410, 27639, 31078,
+ 28947, 15313, 20789, 20318, 31827, 6104, 21516, 20824, 26917, 16991,
+ 9665, 31639, 21138, 31448, 5717, 29476, 19022, 18874, 5036, 6246,
+ 28918, 18366, 9199, 10226, 25494, 25934, 24366, 23972, 8814, 17978,
+ 11338, 19951, 21750, 1454, 17682, 26993, 3871, 30305, 17836, 24267,
+ 31708, 13070, 19255, 20143, 4321, 4904, 26030, 1595, 12202, 22474,
+ 24847, 13189, 22464, 9453, 10685, 18551, 20024, 6877, 20515, 32733,
+ 24188, 9198, 28571, 14524, 6222, 19050, 31886, 7141, 12041, 10959,
+ 15836, 16331, 24106, 22071, 30078, 16018, 30480, 14616, 31850, 29288,
+ 31744, 23085, 21942, 19480, 27756, 1460, 32001, 30684, 9845, 14554,
+ 29711, 17523, 430, 24948, 21427, 116, 1827, 17903, 25586, 16866,
+ 27290, 10634, 32613, 19456, 10520, 194, 17887, 1895, 28839, 18958,
+ 25168, 16469, 13655, 24269, 26601, 8008, 6019, 20605, 2689, 4044,
+ 32597, 9773, 13880, 2449, 4492, 3637, 19034, 28608, 24957, 22564,
+ 31622, 31375, 1112, 19194, 8463, 24340, 27053, 11160, 29090, 10582,
+ 7471, 1908, 29481, 31914, 21943, 6033, 8688, 11837, 30092, 20399,
+ 4870, 28141, 24545, 28095, 5607, 29021, 18335, 7577, 6487, 21832,
+ 23397, 1265, 22417, 10517, 29389, 19335, 3489, 22700, 8434, 29599,
+ 16911, 26761, 20527, 5809, 24253, 14350, 19241, 23137, 8722, 15902,
+ 22287, 12721, 11096, 29671, 17184, 15990, 9827, 25087, 4462, 26377,
+ 23156, 947, 7394, 29758, 8285, 29852, 24705, 19354, 997, 7283,
+ 17389, 6592, 5229, 19749, 4399, 301, 10452, 1834, 30643, 8485,
+ 6809, 22547, 16532, 2285, 15423, 1891, 6171, 27451, 3830, 1440,
+ 4226, 9707, 31607, 20906, 16893, 29171, 4656, 18507, 11259, 20377,
+ 5793, 4622, 15272, 740, 23046, 9045, 7095, 13392, 10550, 678,
+ 12640, 2501, 20939, 18758, 27300, 19402, 643, 4617, 16856, 27383,
+ 2790, 19048, 6753, 31144, 15913, 6612, 23229, 28153, 32083, 21322,
+ 26563, 16366, 11422, 9512, 25899, 14321, 6176, 31551, 24400, 386,
+ 2986, 18217, 16949, 22058, 8689, 8924, 16838, 21680, 3819, 384,
+ 5985, 22672, 27004, 25214, 14485, 26025, 14418, 15066, 27434, 31798,
+ 17934, 2242, 23137, 26879, 164, 17767, 4476, 26065, 26628, 10507,
+ 32641, 7723, 20474, 30043, 26684, 27706, 31058, 14848, 26243, 25095,
+ 17985, 18289, 25534, 29424, 3584, 17419, 10406, 20821, 21434, 5987,
+ 27468, 21651, 25768, 8155, 32349, 31542, 8571, 26227, 1445, 23914,
+ 30458, 17634, 21459, 9139, 18924, 12774, 21884, 21982, 23096, 10200,
+ 11618, 5688, 24907, 22915, 26101, 7421, 28602, 10550, 23578, 2067,
+ 20008, 5656, 18220, 21240, 25963, 5052, 576, 2810, 29162, 32757,
+ 31406, 5030, 1609, 10988, 26573, 3970, 8521, 9583, 12285, 16639,
+ 23273, 18828, 7915, 30633, 27858, 12639, 20752, 23969, 6641, 4136,
+ 30843, 14669, 14694, 8608, 24273, 30542, 26781, 9102, 18578, 4274,
+ 10426, 3477, 7581, 8555, 27451, 31568, 31479, 17152, 20952, 31905,
+ 4552, 32643, 9646, 16453, 30630, 28867, 18845, 19628, 19478, 24514,
+ 11247, 15112, 22352, 30826, 31546, 10405, 1603, 25979, 8839, 21112,
+ 26585, 26824, 20659, 3834, 3964, 17315, 3862, 6711, 217, 918,
+ 11107, 26657, 2276, 1876, 30927, 28971, 10268, 20462, 11382, 11539,
+ 29200, 29258, 22778, 12287, 1570, 15570, 19821, 7628, 1419, 25961,
+ 23409, 26531, 10911, 21411, 18589, 1997, 25938, 23349, 28451, 12232,
+ 8444, 31402, 20912, 7322, 5977, 29272, 9876, 1381, 21716, 18323,
+ 7715, 22588, 20997, 2080, 26715, 14645, 18040, 25068, 15815, 30655,
+ 6320, 25342, 28578, 28214, 3947, 30123, 17216, 32693, 10280, 27913,
+ 7338, 10284, 14055, 13734, 15497, 21170, 13104, 32377, 5445, 27164,
+ 22102, 28184, 31597, 22478, 28413, 14380, 13658, 25809, 3546, 10018,
+ 11791, 12582, 28602, 28196, 20324, 13658, 18630, 22344, 18276, 603,
+ 21765, 8711, 15603, 13194, 21026, 9712, 14260, 18193, 18032, 3485,
+ 16169, 20599, 14635, 15847, 29980, 14706, 16385, 15702, 12094, 1276,
+ 1488, 12251, 21519, 18600, 11954, 15042, 32509, 20535, 15671, 25826,
+ 12240, 8038, 23793, 18199, 2373, 17931, 13878, 8434, 25337, 14944,
+ 12065, 9646, 12937, 11679, 15834, 5478, 4088, 3791, 12311, 30342,
+ 22865, 12253, 3043, 896, 14733, 16622, 28063, 8384, 5814, 5620,
+ 1862, 28385, 11085, 27263, 9461, 19745, 20202, 6103, 23210, 24594,
+ 12834, 28999, 16203, 28819, 4525, 15035, 22763, 14079, 9416, 28046,
+ 7754, 26276, 19161, 16285, 12698, 3447, 15442, 8352, 14473, 7173,
+ 17111, 8634, 30075, 10669, 15523, 31566, 1559, 18701, 28456, 9493,
+ 27398, 186, 27893, 13421, 15607, 15412, 4829, 29940, 13031, 18713,
+ 24662, 28502, 23967, 13464, 12063, 21091, 15486, 7465, 3622, 29285,
+ 3960, 19579, 17320, 21168, 2655, 11694, 15002, 28026, 19809, 29635,
+ 24392, 11757, 18131, 1105, 12092, 20603, 25133, 31353, 97, 7538,
+ 10325, 22043, 17256, 12752, 13600, 11082, 17771, 19032, 9750, 26110,
+ 13520, 17637, 26229, 30217, 28017, 19455, 31865, 30541, 20473, 24748,
+ 15323, 10795, 10385, 13960, 407, 20543, 26813, 5656, 23795, 16714,
+ 14464, 14684, 18877, 19567, 8903, 22179, 24532, 14755, 24837, 19875,
+ 7146, 32607, 2586, 10953, 9607, 151, 10361, 29902, 13905, 26352,
+ 31626, 30859, 1676, 27950, 26701, 1806, 25309, 11755, 23873, 23021,
+ 20307, 19087, 11652, 4570, 23463, 32380, 10043, 888, 3267, 29321,
+ 26932, 18030, 32642, 25778, 15306, 15033, 10423, 30734, 28937, 30790,
+ 22128, 16641, 4115, 23744, 22140, 25010, 20418, 11175, 26154, 19135,
+ 9359, 29858, 20308, 29744, 26035, 13334, 22172, 8874, 19852, 25079,
+ 24310, 3301, 22849, 25310, 26215, 30048, 19369, 3932, 16396, 3156,
+ 22377, 17807, 12125, 11750, 13405, 14578, 18611, 20640, 9274, 29817,
+ 15112, 14370, 10865, 17118, 26366, 16405, 31574, 28981, 26403, 21345,
+ 26241, 8135, 28020, 25504, 16500, 5405, 6688, 29906, 3967, 18267,
+ 12174, 4434, 32737, 4048, 18336, 14857, 25392, 15562, 28218, 9953,
+ 16123, 30127, 17662, 27516, 11949, 9545, 5210, 21543, 7348, 24162,
+ 28101, 3849, 5859, 28305, 17221, 30112, 16917, 4947, 6197, 2671,
+ 12564, 1373, 12101, 32496, 8889, 20017, 22978, 21968, 27476, 7152,
+ 19480, 30043, 3405, 1903, 7061, 15926, 17676, 140, 18799, 31308,
+ 3095, 21699, 32521, 14346, 22394, 1020, 24434, 26063, 5484, 22439,
+ 4654, 16798, 11823, 28683, 27450, 28951, 3128, 15323, 21578, 21925,
+ 28560, 3595, 23381, 28920, 4218, 17889, 2643, 28086, 21846, 15695,
+ 27718, 8301, 8133, 29056, 25463, 5325, 29966, 6577, 13570, 31508,
+ 1473, 8258, 28052, 2505, 22682, 12813, 884, 10157, 7335, 22518,
+ 22976, 29167, 26285, 20163, 2298, 29343, 24009, 4399, 4291, 7013,
+ 6995, 18489, 22245, 22643, 16903, 5570, 6039, 20408, 4199, 27991,
+ 11005, 8278, 29275, 28492, 17391, 13911, 22043, 31242, 3067, 1691,
+ 18510, 26025, 16557, 18197, 7028, 7618, 13837, 30520, 7809, 3454,
+ 25194, 19627, 9930, 4595, 22358, 22596, 28965, 26289, 19442, 30516,
+ 7756, 16535, 7276, 25727, 20099, 2796, 25285, 32432, 8315, 31403,
+ 3288, 5578, 6005, 27677, 5016, 21889, 11434, 16045, 14233, 8106,
+ 4075, 8953, 26322, 27377, 23429, 3877, 12193, 31178, 16231, 19828,
+ 25871, 32170, 26503, 22809, 22614, 31350, 8577, 32074, 19360, 32316,
+ 1409, 27287, 530, 289, 9828, 13946, 4361, 410, 3354, 31023,
+ 22179, 12511, 847, 32197, 14722, 17309, 29002, 14454, 5580, 15083,
+ 21269, 30516, 31606, 14720, 2270, 132, 8643, 14627, 1693, 5263,
+ 13319, 13410, 9975, 1142, 23473, 6279, 9570, 21479, 11144, 5064,
+ 907, 6382, 20533, 5054, 24053, 3597, 10754, 2073, 29666, 2702,
+ 13281, 15761, 26230, 21784, 23472, 25888, 29466, 1153, 12219, 7022,
+ 11551, 25315, 1411, 1165, 31395, 1778, 32190, 20454, 22713, 6028,
+ 2462, 14451, 10948, 28050, 21846, 21807, 6436, 2039, 15323, 19915,
+ 17173, 1558, 10215, 18339, 18387, 7241, 1604, 7920, 27395, 14007,
+ 11591, 16447, 22606, 15981, 23963, 13858, 19023, 13489, 16447, 16165,
+ 6319, 6290, 1490, 3, 29070, 19140, 2831, 9754, 16933, 25515,
+ 9876, 3613, 4778, 12214, 999, 17161, 22900, 17902, 12218, 26970,
+ 2400, 27855, 14702, 27262, 24435, 16726, 3543, 29834, 13249, 21595,
+ 28479, 8748, 20877, 12833, 11949, 24288, 6833, 2092, 2663, 23399,
+ 31297, 23890, 21941, 9846, 27243, 4117, 19944, 15787, 4513, 3888,
+ 16539, 10948, 15099, 112, 26425, 275, 11734, 18885, 7103, 20269,
+ 10434, 12441, 19139, 22755, 923, 864, 18102, 11635, 15605, 369,
+ 24678, 28159, 30397, 29972, 26822, 22589, 9758, 13276, 32754, 26993,
+ 31394, 31031, 21870, 11672, 16538, 20291, 15790, 3814, 17087, 31203,
+ 16604, 14707, 28441, 6163, 1749, 26418, 17184, 28536, 17525, 10274,
+ 17186, 5691, 3604, 31432, 228, 28440, 13136, 18652, 30092, 11186,
+ 2061, 7235, 12990, 18730, 16059, 8253, 12038, 15087, 14296, 17120,
+ 12662, 14296, 27317, 2757, 8336, 23920, 19324, 29953, 14438, 7569,
+ 21106, 28502, 27647, 10804, 2170, 17067, 30205, 21383, 15579, 442,
+ 23677, 3136, 18498, 20489, 27711, 2097, 267, 5403, 28423, 10525,
+ 17596, 28647, 8514, 11723, 15058, 32393, 10989, 22360, 13505, 20024,
+ 8115, 30929, 20278, 1912, 19029, 9474, 14495, 10896, 18255, 28296,
+ 16621, 28735, 12985, 28206, 5784, 8875, 28011, 886, 21732, 666,
+ 15716, 885, 18276, 3300, 19821, 18916, 1724, 13353, 20473, 24693,
+ 21162, 25279, 18768, 12387, 19784, 22766, 17644, 29261, 31627, 15200,
+ 31267, 20548, 12048, 26067, 9223, 28195, 15640, 22033, 4235, 19486,
+ 9937, 17186, 10983, 14238, 5847, 13504, 1341, 15949, 22522, 12043,
+ 9596, 22380, 10562, 18046, 6533, 14189, 4912, 12322, 5772, 446,
+ 8775, 8705, 10177, 19683, 10955, 6110, 12336, 11463, 31177, 20515,
+ 17382, 14164, 5975, 5403, 7254, 14145, 32285, 9825, 11259, 299,
+ 27668, 22169, 5438, 7912, 12430, 12637, 2201, 17688, 7031, 15738,
+ 19965, 18172, 29146, 12125, 32113, 31884, 2982, 8136, 11005, 20163,
+ 32435, 6858, 2502, 24126, 31488, 6893, 19066, 30725, 15423, 17585,
+ 14574, 19625, 13459, 30265, 23814, 7567, 21656, 32581, 8918, 21643,
+ 5284, 5472, 19974, 14768, 9036, 22619, 15483, 15207, 23850, 31481,
+ 15411, 31935, 29150, 25580, 30833, 7684, 23123, 23296, 16923, 29587,
+ 1092, 5783, 14176, 7916, 22270, 15701, 3741, 15881, 30055, 12316,
+ 2178, 9455, 24895, 12347, 19825, 21890, 25510, 13794, 14886, 10653,
+ 24286, 2778, 24477, 25442, 27987, 32114, 14896, 6095, 29144, 16317,
+ 25601, 10130, 32052, 18170, 18071, 14879, 11485, 16212, 4044, 28415,
+ 26371, 26572, 28134, 14699, 6096, 27251, 22276, 6681, 21487, 1244,
+ 24508, 11094, 1099, 5329, 25858, 13141, 32537, 23877, 3403, 12487,
+ 12824, 6026, 25843, 5547, 16919, 9412, 6620, 9320, 17337, 29598,
+ 6745, 8985, 29045, 28219, 6986, 22824, 736, 1136, 18824, 2846,
+ 2351, 9776, 10883, 26809, 29943, 16967, 28713, 8512, 10552, 7499,
+ 17418, 4627, 16282, 5328, 19898, 17286, 25078, 8924, 30839, 10223,
+ 23832, 13723, 15372, 20734, 20676, 12115, 27893, 3917, 8438, 8857,
+ 22468, 12344, 3182, 7878, 11204, 19951, 3180, 8357, 30939, 26057,
+ 25017, 31598, 17589, 10460, 29414, 19960, 31518, 15050, 24536, 22570,
+ 15792, 21213, 28293, 17587, 22191, 29527, 13560, 15098, 21297, 11011,
+ 9371, 19800, 2178, 5392, 23221, 6022, 2246, 2847, 23090, 8529,
+ 19168, 15771, 4771, 22933, 2451, 9801, 22661, 15720, 7655, 2336,
+ 12998, 32662, 22735, 30554, 8581, 17486, 8200, 2251, 16922, 17690,
+ 21060, 16242, 29782, 28948, 13960, 18766, 25867, 23896, 31443, 5234,
+ 8655, 6581, 1536, 26972, 6654, 15784, 8429, 32643, 12542, 16778,
+ 15069, 16431, 17863, 30728, 19739, 11149, 21410, 15316, 8673, 5123,
+ 4144, 9626, 631, 9153, 10927, 24118, 4255, 24729, 4217, 24868,
+ 20273, 8720, 23245, 17207, 7683, 11701, 18898, 20878, 11531, 28081,
+ 28889, 7365, 10952, 30112, 30691, 17512, 12765, 18847, 5731, 5805,
+ 14848, 7078, 11077, 22626, 4114, 29465, 5678, 18724, 6543, 29337,
+ 13830, 14290, 26409, 12320, 12468, 15169, 23216, 21325, 26664, 25393,
+ 25653, 28156, 16543, 30080, 6767, 17178, 7202, 2974, 12894, 28600,
+ 12112, 9281, 6701, 10845, 4958, 32090, 15197, 3233, 14684, 19015,
+ 10272, 6903, 8890, 6730, 14339, 32459, 778, 826, 22480, 9933,
+ 12039, 25720, 4275, 16780, 31959, 22053, 2715, 17990, 31117, 6290,
+ 3555, 32766, 6130, 6136, 18482, 20176, 15493, 22634, 22688, 4994,
+ 19136, 24071, 26394, 31067, 6045, 25972, 19207, 4664, 25945, 138,
+ 1323, 30940, 19576, 27467, 4300, 28040, 13833, 11547, 20500, 8395,
+ 19243, 23085, 6071, 8348, 32208, 2363, 7638, 7078, 3777, 20858,
+ 20514, 28387, 13539, 25805, 21828, 12652, 18872, 6712, 15741, 12944,
+ 7976, 31896, 9865, 7715, 25218, 12690, 22218, 15128, 12478, 19658,
+ 5026, 30803, 16389, 25429, 14113, 15288, 17011, 29552, 18656, 10120,
+ 26139, 29810, 7724, 18925, 5707, 8959, 17767, 27347, 25106, 23935,
+ 16556, 27642, 11264, 9422, 21426, 28489, 1837, 5429, 26867, 14182,
+ 25980, 27546, 21005, 30339, 31521, 27379, 26472, 32635, 31585, 13825,
+ 19225, 3357, 4761, 28986, 21254, 5063, 16770, 16647, 24139, 20792,
+ 32179, 30767, 6621, 3743, 15208, 2707, 30829, 18679, 17537, 6173,
+ 24976, 13207, 206, 9203, 23580, 18693, 5001, 19440, 14293, 24076,
+ 29220, 5204, 31305, 27406, 22598, 7098, 4856, 32667, 15632, 19275,
+ 6840, 5185, 11684, 22322, 8792, 11942, 12520, 9039, 21636, 3029,
+ 6279, 24624, 28392, 17622, 25401, 29757, 22169, 8577, 5189, 1330,
+ 19376, 3475, 9284, 13779, 56, 25602, 28455, 27611, 5706, 1166,
+ 17275, 12853, 18806, 26521, 30444, 2926, 18277, 9272, 9224, 18539,
+ 31677, 7306, 30022, 14167, 21317, 17481, 8519, 16096, 14922, 13726,
+ 31835, 14755, 23105, 2106, 17223, 9700, 23213, 7842, 838, 32131,
+ 10563, 24010, 17229, 18987, 3404, 742, 21139, 18893, 2636, 2941,
+ 24657, 14157, 21985, 25535, 16582, 2939, 25837, 20248, 895, 19012,
+ 21495, 16133, 16085, 12330, 11983, 3111, 13495, 21489, 23409, 17814,
+ 13482, 4251, 11308, 2679, 24333, 19351, 23812, 8657, 11682, 27446,
+ 84, 17564, 25930, 4446, 7864, 19995, 21776, 28290, 3625, 18028,
+ 1641, 16593, 17514, 31582, 17082, 21422, 10404, 7042, 4635, 4961,
+ 10317, 1925, 5979, 2316, 4941, 19900, 27972, 21216, 868, 1025,
+ 26912, 27792, 21190, 29630, 26236, 23558, 26121, 19527, 43, 5718,
+ 19777, 20333, 23182, 12528, 106, 11344, 25363, 13081, 15110, 31860,
+ 10492, 7068, 15110, 5911, 13154, 28348, 26350, 11970, 30841, 24686,
+ 7989, 27935, 23061, 28357, 16106, 266, 19309, 174, 3998, 21226,
+ 1055, 23773, 13437, 21314, 25717, 3335, 20670, 6019, 28391, 338,
+ 27966, 14629, 31457, 2058, 24935, 10997, 1222, 28053, 17239, 30897,
+ 16180, 22697, 9022, 9426, 18826, 14012, 5640, 6313, 12199, 19644,
+ 21309, 23213, 5877, 16385, 27173, 32532, 15527, 11136, 21039, 1696,
+ 10558, 5441, 23187, 8124, 15698, 22547, 15671, 32199, 31631, 21886,
+ 22736, 15024, 13310, 1017, 22089, 30403, 29829, 11613, 15720, 10946,
+ 25266, 29082, 15535, 24632, 25268, 25000, 10368, 17418, 12202, 18113,
+ 30085, 18255, 18721, 27086, 12879, 16993, 22999, 28447, 17469, 20020,
+ 31685, 6750, 27552, 18407, 32093, 3782, 21276, 12953, 3089, 24464,
+ 11858, 27518, 26644, 1198, 11195, 25650, 1380, 1980, 15831, 22349,
+ 15880, 32052, 32648, 11063, 31126, 7649, 14264, 30526, 28153, 5270,
+ 16450, 24293, 23921, 21535, 21520, 14207, 30171, 2424, 2177, 11261,
+ 13619, 32317, 30221, 21253, 30551, 32610, 21547, 27460, 4366, 7204,
+ 3186, 12804, 7240, 20799, 2303, 2049, 22952, 29794, 16920, 22648,
+ 19263, 29664, 20238, 30338, 27803, 16040, 32360, 25760, 11264, 26743,
+ 14653, 14999, 2293, 24140, 13794, 7550, 31746, 16157, 15814, 32277,
+ 3001, 11464, 2713, 4440, 13043, 10572, 32436, 14164, 31836, 21561,
+ 15541, 17466, 30514, 7269, 25193, 24498, 26953, 14817, 27376, 28273,
+ 25171, 1067, 31771, 14862, 5214, 30885, 8985, 19217, 5534, 1350,
+ 17491, 10574, 28525, 27536, 17044, 30321, 7824, 20418, 8557, 5849,
+ 26812, 18510, 9944, 23722, 11096, 397, 16411, 26909, 1925, 18866,
+ 11759, 14363, 3932, 6397, 15330, 2571, 22646, 27185, 1786, 8168,
+ 6066, 30535, 6043, 32150, 10802, 11876, 21162, 9846, 12199, 29449,
+ 1523, 2104, 6607, 32649, 5064, 2032, 21820, 31425, 491, 25964,
+ 28502, 5635, 28591, 26821, 23971, 18259, 14169, 3637, 19014, 29654,
+ 16076, 9256, 2502, 7815, 15206, 3990, 7697, 28460, 27941, 10895,
+ 27329, 9609, 5390, 28952, 32413, 19667, 10959, 28725, 5731, 17255,
+ 5539, 11079, 15557, 27324, 27766, 27544, 11185, 5014, 330, 11829,
+ 21205, 31357, 15321, 9212, 10083, 26734, 1915, 30709, 8465, 19408,
+ 22603, 20454, 2149, 23977, 2949, 15137, 31279, 10002, 10035, 929,
+ 17495, 31465, 15625, 5461, 32728, 14277, 29837, 28604, 3085, 26159,
+ 123, 21938, 20268, 1807, 871, 12170, 24592, 9828, 10148, 21340,
+ 32059, 1592, 28261, 10144, 29979, 30164, 31266, 21500, 25484, 10544,
+ 22589, 29787, 26783, 9389, 3558, 575, 15513, 4358, 27708, 26712,
+ 17727, 2948, 28596, 29781, 4177, 18034, 11967, 6906, 22357, 3537,
+ 7079, 17011, 28821, 1101, 7610, 1768, 20843, 11375, 17835, 11601,
+ 1468, 4627, 8501, 14476, 16579, 10269, 29185, 21676, 27408, 11880,
+ 19402, 3221, 20944, 13311, 23999, 32198, 23374, 2448, 27433, 32373,
+ 25786, 14365, 14157, 27105, 11562, 20469, 26772, 1764, 29150, 9187,
+ 9961, 15559, 8136, 17573, 31075, 2651, 15947, 20639, 10020, 29509,
+ 30532, 27601, 8065, 22426, 24647, 29703, 11619, 27052, 26923, 17743,
+ 31212, 13859, 5064, 8880, 8798, 29263, 22783, 5913, 25913, 1212,
+ 24315, 25240, 10916, 31751, 25783, 18380, 27662, 26609, 1728, 19869,
+ 16149, 18610, 16701, 18730, 1959, 2192, 21292, 17411, 5479, 13231,
+ 26350, 4761, 12370, 25131, 9222, 12019, 22690, 2148, 3614, 11170,
+ 15858, 8601, 21834, 21238, 12708, 26809, 31633, 18034, 6272, 4981,
+ 29610, 12926, 8093, 17306, 7427, 27228, 14469, 8862, 16648, 93,
+ 8340, 23416, 30113, 11861, 30625, 26293, 2300, 8780, 10721, 23753,
+ 23182, 886, 12551, 17059, 17748, 17254, 28848, 1156, 32607, 3966,
+ 12799, 4880, 4751, 30378, 644, 22182, 21151, 5966, 31331, 27885,
+ 29793, 27004, 11698, 25775, 10827, 31083, 19746, 27627, 27187, 9764,
+ 14818, 9253, 16471, 14463, 4288, 4353, 21408, 26190, 28818, 21776,
+ 32552, 5592, 32724, 12522, 9465, 30089, 30098, 30845, 7704, 15335,
+ 10633, 29348, 27586, 9160, 28553, 22268, 3573, 30914, 16925, 24051,
+ 9010, 18404, 110, 5921, 13698, 2211, 17253, 31196, 22711, 21015,
+ 3600, 25606, 32244, 28776, 23879, 31530, 8303, 28291, 23183, 9159,
+ 12150, 26641, 13886, 748, 22960, 14249, 27872, 15877, 7590, 21828,
+ 31706, 27893, 17281, 30962, 18765, 29285, 9237, 21964, 17213, 11867,
+ 24863, 298, 31219, 16142, 29387, 23062, 14751, 17401, 11898, 1280,
+ 26434, 22318, 10945, 20403, 9419, 12525, 9397, 4487, 128, 10613,
+ 19046, 23512, 13216, 3354, 3753, 3768, 13383, 30360, 27163, 9697,
+ 7825, 9127, 11618, 20973, 14594, 30671, 18614, 12746, 6182, 8574,
+ 11425, 16488, 9588, 5464, 10242, 19124, 3448, 21454, 26456, 458,
+ 22834, 11506, 31037, 32102, 14009, 30345, 31793, 17052, 13603, 26722,
+ 22937, 8906, 30633, 4839, 12807, 1738, 9223, 9202, 24252, 31340,
+ 4130, 28130, 11372, 3107, 29421, 25837, 13121, 21758, 7309, 1720,
+ 28706, 15578, 31164, 24612, 820, 20183, 26219, 9579, 14241, 12808,
+ 5035, 4205, 14489, 6767, 1229, 31044, 6039, 17960, 26568, 23838,
+ 2022, 23268, 19676, 18252, 29539, 14233, 373, 20630, 19588, 3704,
+ 4690, 10450, 16793, 23328, 14566, 24245, 13650, 2321, 14335, 23016,
+ 8322, 24163, 27557, 15198, 16674, 32440, 4165, 6118, 15001, 6767,
+ 1295, 16636, 2875, 7706, 3484, 4069, 31503, 30258, 22228, 26363,
+ 26581, 15114, 17167, 23877, 4679, 22786, 16762, 18506, 20640, 2301,
+ 13501, 6183, 19035, 11541, 11482, 14816, 8509, 25997, 30808, 29684,
+ 11157, 29190, 20642, 28980, 9155, 13046, 9642, 28116, 28919, 24407,
+ 19665, 15043, 27963, 17052, 5899, 2872, 19636, 5865, 4670, 16526,
+ 2596, 20355, 31212, 10321, 31924, 26502, 6930, 24729, 31473, 2262,
+ 12112, 22166, 12052, 8023, 29513, 4973, 134, 11361, 31821, 19266,
+ 13987, 28270, 4406, 25238, 14527, 12566, 2703, 24020, 3942, 22846,
+ 32252, 28454, 2792, 396, 14549, 5773, 13077, 15134, 19989, 2097,
+ 25670, 18043, 15219, 19702, 15773, 22729, 27086, 20815, 17549, 16705,
+ 3278, 22103, 24988, 737, 9673, 31006, 6759, 13920, 11747, 17472,
+ 11495, 18535, 11130, 32701, 28660, 26622, 14017, 13060, 7431, 14661,
+ 12714, 3409, 26436, 8292, 14090, 10297, 952, 14532, 1272, 22660,
+ 1759, 19584, 26229, 314, 15209, 24598, 24659, 7424, 22077, 9827,
+ 9551, 29093, 11199, 28878, 5505, 8697, 19022, 28611, 19702, 4574,
+ 7697, 22371, 1435, 20641, 500, 15481, 20572, 32138, 25069, 15792,
+ 27022, 23217, 21124, 19716, 11402, 532, 16786, 11639, 27291, 28903,
+ 9289, 30981, 10523, 23851, 18036, 17113, 2776, 2434, 7936, 10689,
+ 26813, 2882, 19900, 28384, 23982, 14024, 9821, 25763, 18867, 9743,
+ 27845, 18934, 4185, 3457, 9861, 26039, 5717, 21260, 9632, 30314,
+ 17003, 7033, 12434, 18991, 1422, 16889, 27536, 4850, 11849, 28161,
+ 26386, 19170, 2909, 15192, 30607, 15652, 8620, 10351, 14983, 1736,
+ 31061, 16112, 27847, 9212, 17953, 10905, 30185, 23935, 28446, 12875,
+ 19738, 10841, 14729, 18270, 6944, 22986, 6897, 7992, 15771, 6528,
+ 30362, 2846, 3978, 11276, 18976, 585, 6930, 25495, 3420, 4669,
+ 6267, 13521, 18827, 10582, 24188, 30251, 11181, 28580, 10168, 8006,
+ 5676, 8697, 20872, 7339, 30142, 9023, 30715, 3004, 23948, 14351,
+ 4891, 29419, 11924, 8320, 31090, 18985, 20044, 1085, 27597, 26529,
+ 12424, 25819, 3648, 9383, 14493, 2665, 29290, 20203, 13767, 7752,
+ 5882, 14835, 32456, 26685, 114, 1224, 28882, 25028, 20268, 26607,
+ 21927, 5031, 30362, 8090, 29951, 29136, 31185, 17952, 21802, 10587,
+ 20809, 12971, 28406, 5360, 24030, 12336, 22739, 19280, 3355, 8357,
+ 11573, 31789, 4792, 24686, 12346, 3903, 23393, 32280, 30861, 14740,
+ 7354, 6729, 8074, 32040, 9887, 1015, 15523, 18101, 22960, 25817,
+ 12290, 7628, 26381, 4635, 111, 6949, 15710, 21846, 20597, 6452,
+ 18199, 16831, 11968, 21244, 24058, 27039, 17866, 25896, 6109, 2051,
+ 11959, 25944, 20653, 29364, 27517, 953, 5555, 26729, 19527, 27352,
+ 22038, 3900, 17436, 20920, 31905, 14171, 28859, 29730, 22215, 13824,
+ 22986, 25916, 27876, 27811, 11056, 28765, 12230, 20590, 28352, 31776,
+ 8044, 1521, 2327, 9143, 20237, 25879, 32199, 31362, 27229, 31064,
+ 16053, 11744, 8203, 21041, 2751, 31046, 5518, 14289, 8098, 8334,
+ 18465, 6166, 17179, 25745, 32524, 16311, 26445, 9719, 13094, 13251,
+ 28259, 10830, 3992, 16202, 20854, 14170, 28643, 2393, 11953, 30892,
+ 32549, 18220, 691, 25462, 23704, 24224, 4404, 3230, 26971, 3303,
+ 16620, 9489, 9077, 25983, 28336, 4186, 12823, 15717, 31711, 18803,
+ 1825, 22150, 7164, 2523, 14824, 24438, 9628, 26344, 32566, 7012,
+ 27267, 22879, 25235, 17998, 23306, 25410, 9411, 2417, 30916, 18409,
+ 25488, 5124, 23648, 2644, 28362, 11301, 21201, 9664, 28299, 19476,
+ 21933, 13432, 16063, 8095, 25299, 30958, 9188, 30173, 30545, 32010,
+ 15631, 31519, 12677, 15298, 22320, 20260, 24194, 2283, 1430, 19340,
+ 30388, 11087, 9142, 3727, 19912, 23807, 9256, 7663, 31174, 9707,
+ 20722, 13867, 13696, 17583, 24841, 6646, 16944, 6576, 1813, 30183,
+ 3165, 18536, 23925, 11378, 6142, 766, 21379, 7703, 30690, 13338,
+ 25, 16857, 21583, 31479, 32084, 8690, 17642, 11706, 12695, 4293,
+ 470, 22018, 10707, 10772, 12320, 23488, 26886, 29811, 19803, 21065,
+ 20738, 14077, 32391, 7081, 2160, 22341, 17976, 22074, 532, 21392,
+ 26100, 18550, 2387, 11585, 28380, 16138, 30706, 22420, 17806, 4395,
+ 31008, 32399, 7499, 16173, 32183, 14902, 11861, 24402, 17855, 511,
+ 11163, 19680, 9012, 29829, 15256, 19830, 23048, 18304, 30841, 8351,
+ 16748, 29685, 15230, 11688, 2636, 29354, 14242, 17327, 20248, 7389,
+ 10110, 8189, 20682, 1333, 4715, 11926, 1317, 23801, 27879, 14605,
+ 23098, 14720, 6202, 30621, 21297, 19945, 1369, 14454, 25158, 27916,
+ 32522, 4437, 9234, 26543, 24393, 20311, 24588, 6910, 13290, 6415,
+ 29263, 17205, 5761, 30422, 670, 26272, 15231, 13666, 11429, 27845,
+ 31901, 22171, 32129, 13792, 25214, 1193, 27267, 18063, 29071, 15186,
+ 9521, 23503, 15923, 7043, 28814, 31527, 3101, 7468, 23452, 21283,
+ 31996, 4945, 1310, 4, 4702, 13919, 19618, 2230, 1742, 10428,
+ 5311, 10242, 16960, 10657, 31388, 13829, 28080, 27180, 9905, 17889,
+ 27141, 14513, 6866, 19378, 11835, 30290, 8553, 24260, 20673, 2767,
+ 16899, 27651, 16416, 19103, 24334, 27826, 28382, 831, 24800, 30048,
+ 30370, 8650, 4604, 12568, 30360, 10186, 4241, 7385, 12567, 25165,
+ 31044, 5957, 11394, 5948, 12079, 6301, 23404, 7401, 25898, 9965,
+ 4095, 4071, 19529, 23172, 16030, 6942, 2982, 1703, 21449, 1566,
+ 25952, 23175, 8513, 32180, 11491, 3696, 9837, 19131, 29290, 28994,
+ 14333, 27445, 1987, 27173, 19149, 16795, 16978, 17017, 26124, 20081,
+ 7769, 19468, 157, 10268, 10103, 14224, 19901, 9464, 19054, 12108,
+ 15591, 27558, 29737, 2577, 12532, 23971, 8701, 10864, 12935, 4127,
+ 18223, 24106, 8616, 18188, 11190, 20968, 10927, 9845, 10307, 27948,
+ 612, 3601, 25471, 10888, 11620, 21272, 29843, 16398, 22215, 19541,
+ 3822, 11271, 31231, 25725, 6978, 31208, 25603, 9919, 25040, 21377,
+ 20398, 31132, 10726, 12920, 8545, 31737, 29350, 17910, 1520, 14450,
+ 10504, 24736, 30908, 8946, 32547, 713, 29980, 5248, 18600, 21733,
+ 22274, 14684, 175, 9793, 11995, 9547, 23734, 17394, 3254, 559,
+ 4326, 15372, 1705, 3290, 10649, 24852, 32368, 21540, 7706, 8631,
+ 27224, 28219, 171, 2235, 9564, 6203, 28621, 31031, 2701, 29695,
+ 11451, 31487, 24503, 22582, 31544, 11107, 21313, 26297, 11914, 9753,
+ 4437, 23836, 1991, 31351, 13377, 21378, 18767, 229, 5149, 23990,
+ 9114, 9363, 14766, 17016, 24372, 30055, 30859, 15637, 26629, 5690,
+ 29822, 32059, 7638, 23363, 5677, 22794, 3601, 11475, 13050, 25966,
+ 31432, 579, 27687, 26797, 21241, 2347, 2366, 23356, 17, 19669,
+ 20912, 27351, 11438, 29170, 10684, 13264, 26793, 23179, 30354, 9384,
+ 20052, 17978, 3513, 16348, 3328, 17049, 13230, 12289, 31939, 32763,
+ 28110, 25107, 8056, 24154, 11125, 6667, 13062, 18065, 2664, 13743,
+ 14566, 9163, 14960, 4526, 5855, 4412, 17480, 17644, 13588, 4111,
+ 14265, 9755, 15681, 22943, 1284, 20363, 24386, 8681, 1408, 5443,
+ 16085, 24130, 30596, 8528, 28320, 25669, 29063, 10845, 7286, 29968,
+ 4230, 30852, 21206, 2224, 26023, 11364, 29620, 28121, 26395, 31860,
+ 20604, 4570, 26696, 23702, 853, 1233, 23848, 17392, 28067, 3611,
+ 27884, 1271, 32719, 25871, 6118, 27596, 11850, 25068, 29861, 5836,
+ 14287, 15119, 18530, 15715, 8425, 8810, 32411, 22816, 2230, 22321,
+ 17405, 25871, 15082, 32726, 18567, 10051, 8982, 24632, 27885, 14514,
+ 1323, 16408, 24378, 16198, 7994, 5580, 27322, 3632, 6269, 18743,
+ 32535, 8320, 24987, 8952, 12994, 8690, 27176, 15330, 17556, 31243,
+ 20331, 172, 24758, 3429, 26725, 7658, 11454, 10568, 21262, 26684,
+ 24346, 19833, 26338, 5318, 26034, 18519, 12444, 21984, 24521, 22819,
+ 23362, 12302, 28452, 19616, 10849, 6962, 9327, 18396, 27034, 17408,
+ 2780, 13645, 30045, 435, 5901, 2079, 16629, 21502, 32052, 18893,
+ 32197, 32070, 12921, 9711, 18385, 3342, 7580, 26707, 31616, 28339,
+ 15067, 8526, 6304, 20569, 14102, 25684, 22186, 30245, 17969, 21703,
+ 20039, 19885, 14522, 29965, 23572, 21932, 5323, 27621, 8354, 11771,
+ 13874, 13307, 16834, 25532, 14800, 27066, 20735, 19928, 14399, 11105,
+ 31595, 3501, 5048, 16217, 26271, 2048, 23859, 29894, 24317, 27193,
+ 5327, 29276, 15160, 4047, 18805, 26483, 6423, 23553, 23480, 21342,
+ 22389, 23495, 26624, 22265, 29069, 17416, 7144, 17538, 8052, 8205,
+ 31460, 25002, 24551, 17462, 22055, 4075, 20295, 22763, 31684, 20251,
+ 28642, 4566, 24851, 20034, 18292, 25935, 19542, 32425, 30190, 22552,
+ 16796, 23859, 10613, 12619, 14054, 26096, 5038, 10896, 21385, 26096,
+ 17465, 28819, 16083, 8021, 3195, 1974, 16881, 29612, 20641, 26883,
+ 16656, 2174, 27105, 27492, 20419, 6689, 32259, 19734, 25765, 28884,
+ 28705, 29019, 28735, 11276, 20139, 9839, 23340, 22536, 25261, 1982,
+ 12154, 427, 17493, 20564, 29012, 15499, 6320, 12693, 27358, 20294,
+ 23732, 558, 28513, 31253, 24963, 22859, 22952, 2979, 24046, 27147,
+ 18858, 14367, 14648, 13104, 25961, 26255, 29469, 22300, 8473, 26728,
+ 19731, 12281, 21125, 20316, 6352, 29751, 5039, 21876, 20492, 32571,
+ 14518, 2910, 22920, 4693, 23805, 16648, 8015, 8691, 19338, 23662,
+ 23100, 789, 18092, 4784, 14012, 3329, 29409, 14183, 14037, 824,
+ 26870, 5689, 30056, 23464, 13168, 2731, 11955, 13603, 15147, 18999,
+ 12825, 4624, 26433, 5279, 8486, 11105, 29741, 16000, 8142, 28613,
+ 17969, 18986, 23029, 798, 15093, 687, 565, 21045, 15984, 19770,
+ 11739, 3756, 9995, 9378, 12850, 10037, 7428, 29503, 26373, 4098,
+ 4369, 16125, 29279, 28541, 1607, 23470, 405, 824, 13113, 6053,
+ 4998, 20775, 15972, 5760, 14370, 30989, 6603, 20037, 26921, 14900,
+ 16862, 23217, 24629, 353, 25504, 6860, 3579, 4871, 11785, 19649,
+ 5838, 9659, 21161, 7149, 30821, 232, 31119, 21814, 15581, 29636,
+ 11369, 13726, 24321, 14466, 31981, 1815, 17354, 6090, 27255, 32666,
+ 27938, 24678, 19187, 5747, 18925, 1854, 15101, 17375, 18250, 902,
+ 22855, 24280, 1814, 15158, 20795, 3376, 24499, 5050, 30946, 31197,
+ 2311, 31467, 1541, 17812, 6855, 31807, 7826, 26009, 16373, 13884,
+ 18496, 25813, 17319, 17459, 31606, 15145, 23307, 28714, 23914, 12034,
+ 20648, 16666, 25990, 29997, 29926, 14683, 29199, 749, 30673, 22876,
+ 4104, 17995, 4122, 14999, 31316, 14510, 4958, 22212, 5148, 32683,
+ 25515, 20301, 25200, 4126, 22081, 18691, 18737, 1914, 30613, 12303,
+ 3886, 12125, 20636, 30763, 28045, 24424, 4421, 11538, 11885, 12621,
+ 17480, 26420, 7881, 15145, 28702, 30895, 22431, 17429, 18768, 26235,
+ 8786, 9975, 23029, 484, 31822, 22431, 17014, 13886, 32234, 15887,
+ 30613, 24276, 10386, 23577, 8622, 14625, 24613, 28976, 316, 18243,
+ 5020, 4216, 31902, 13996, 22765, 23839, 15132, 7963, 46, 24816,
+ 28965, 11722, 25086, 12581, 16858, 4329, 27937, 21885, 22993, 14156,
+ 14186, 9615, 10002, 14433, 5598, 4190, 21094, 30820, 22, 557,
+ 24018, 23766, 17125, 23701, 3166, 9515, 17979, 13524, 30490, 15299,
+ 27209, 19560, 29539, 4891, 16358, 30685, 11875, 25413, 8242, 26595,
+ 8663, 23445, 26489, 2211, 17941, 7326, 22362, 27475, 9549, 3676,
+ 25640, 28168, 13327, 26291, 29072, 5580, 4877, 29720, 17020, 20209,
+ 7715, 143, 8248, 1957, 27796, 24789, 31955, 22726, 9879, 990,
+ 5321, 12535, 21522, 5762, 21470, 13811, 2213, 3955, 333, 20513,
+ 4330, 14194, 30498, 5225, 1275, 450, 26853, 71, 25653, 18653,
+ 32120, 15389, 7740, 17255, 16450, 22478, 11583, 17760, 11662, 13704,
+ 9598, 8605, 24109, 5857, 24073, 16249, 5731, 38, 5834, 14536,
+ 15361, 26095, 16325, 5132, 30670, 22775, 17823, 28396, 1579, 9259,
+ 1885, 11489, 31479, 4353, 22895, 32307, 31921, 17931, 14829, 21284,
+ 15068, 29644, 6688, 3946, 9128, 17354, 24900, 4579, 7374, 15844,
+ 3212, 25733, 17340, 6118, 4199, 10388, 30962, 9051, 24322, 4887,
+ 15020, 19875, 14350, 3468, 4801, 26181, 9667, 20187, 7115, 8070,
+ 19237, 137, 24968, 32058, 26502, 17454, 8320, 9690, 13132, 11561,
+ 10472, 18903, 31220, 658, 26823, 5422, 5463, 23920, 24919, 24381,
+ 11820, 30508, 2990, 3284, 26063, 15430, 28829, 22672, 19777, 30535,
+ 30681, 30052, 19823, 10231, 12888, 16249, 25783, 23247, 9214, 28472,
+ 23976, 5297, 20601, 677, 25353, 9943, 3946, 20718, 5405, 32522,
+ 27589, 31811, 1062, 18452, 4730, 13801, 13352, 28279, 5205, 2186,
+ 3567, 23903, 32546, 7376, 24915, 2006, 4630, 11314, 23739, 4663,
+ 4458, 5645, 7648, 12261, 32073, 19190, 16340, 2364, 12268, 591,
+ 2626, 15816, 9988, 28184, 9719, 22197, 31832, 24840, 31393, 15751,
+ 20911, 6876, 6615, 2828, 13296, 12016, 23386, 17038, 14728, 14604,
+ 3739, 19788, 24588, 21632, 25981, 18988, 27935, 2419, 31835, 1450,
+ 22167, 9336, 9037, 11796, 30171, 11362, 19623, 6137, 2703, 27226,
+ 17603, 9951, 20596, 14382, 5889, 11828, 11401, 2284, 17419, 24199,
+ 13687, 24496, 11614, 4856, 6955, 10426, 23046, 4845, 12741, 10435,
+ 30888, 7175, 9137, 30353, 17094, 18517, 3859, 13002, 9535, 9415,
+ 4713, 29190, 21013, 3045, 3180, 3367, 8051, 6336, 4918, 19437,
+ 22511, 17961, 26282, 7621, 24588, 3618, 25105, 21730, 21763, 7570,
+ 12545, 6031, 2243, 28733, 19331, 31684, 32566, 26866, 32116, 247,
+ 20678, 14854, 32044, 23604, 5664, 12802, 21854, 19056, 16695, 16537,
+ 9791, 23835, 1932, 18397, 491, 29940, 16814, 3506, 26628, 24353,
+ 25596, 24962, 9372, 18559, 29874, 18994, 5717, 31543, 8996, 20565,
+ 8134, 6802, 25668, 14496, 18465, 20750, 14442, 17054, 20243, 9393,
+ 32341, 16293, 14316, 26013, 30573, 5641, 4096, 27365, 24906, 1167,
+ 29773, 4511, 18554, 14885, 6750, 12858, 30847, 5584, 24687, 18,
+ 11544, 8933, 10449, 1858, 26818, 9596, 1168, 15545, 5245, 19234,
+ 29012, 21649, 19667, 21454, 11909, 21148, 23, 18199, 28082, 2367,
+ 16875, 2467, 25140, 31363, 30724, 26339, 29710, 20329, 17458, 25341,
+ 6680, 22910, 20378, 26890, 8029, 21168, 23366, 10626, 22465, 20320,
+ 14817, 15604, 2023, 5816, 5819, 24315, 1105, 21823, 11796, 21869,
+ 19401, 23978, 23190, 22485, 8448, 27638, 7203, 2852, 26486, 7859,
+ 31697, 26019, 18329, 6819, 28979, 3884, 24113, 3203, 11483, 4506,
+ 31483, 32041, 27676, 28030, 12948, 11215, 14869, 26388, 18329, 25263,
+ 16874, 8053, 12045, 31184, 5717, 19981, 13307, 31775, 4702, 11856,
+ 32348, 8897, 14182, 30121, 314, 6824, 11370, 26035, 5142, 18532,
+ 17030, 20140, 15240, 32316, 8888, 5671, 25893, 22654, 2279, 5632,
+ 6821, 13331, 12324, 26517, 28742, 29526, 21551, 28467, 12907, 1319,
+ 27709, 15311, 5769, 25146, 760, 3831, 29507, 29877, 20424, 8456,
+ 17364, 7675, 30033, 30112, 31406, 20162, 2365, 21590, 26464, 25964,
+ 18747, 14761, 13245, 18068, 8519, 21559, 15419, 25575, 26413, 25136,
+ 18329, 9525, 28488, 777, 25029, 26567, 24208, 20853, 24060, 2036,
+ 24020, 22929, 17459, 10479, 4675, 16222, 11702, 12003, 32561, 10613,
+ 21775, 8002, 13592, 17398, 23849, 23386, 29149, 28610, 5045, 26921,
+ 5717, 29162, 13005, 15986, 5384, 14183, 26071, 16912, 15925, 267,
+ 5549, 30603, 3350, 2999, 16379, 2281, 23140, 2255, 24040, 8902,
+ 6174, 31467, 7672, 22183, 31367, 19151, 30000, 30604, 12910, 10398,
+ 19324, 9412, 7345, 3402, 18255, 30469, 2820, 28751, 31881, 956,
+ 2543, 1441, 669, 10914, 18454, 6114, 13811, 24976, 701, 21209,
+ 10379, 29332, 7051, 4640, 1508, 24644, 15246, 2076, 28188, 25682,
+ 10112, 20786, 3160, 15457, 10569, 18232, 27750, 14615, 12996, 10538,
+ 21409, 17268, 7622, 27423, 8469, 19554, 11613, 17019, 30948, 23181,
+ 13397, 16997, 16105, 10868, 1281, 7292, 9370, 5313, 3640, 22981,
+ 20019, 11989, 18845, 8168, 21265, 22952, 24355, 22173, 7515, 13008,
+ 8657, 16737, 27880, 7135, 18883, 24941, 349, 19442, 3954, 13288,
+ 12182, 8071, 3125, 8284, 26184, 6799, 1031, 11111, 26084, 20677,
+ 31882, 16819, 12222, 10301, 17740, 12071, 28782, 10816, 21833, 5727,
+ 26998, 22103, 8626, 31834, 7718, 11174, 20973, 15475, 18365, 23675,
+ 29917, 30867, 21713, 24615, 7011, 22948, 30705, 22285, 31781, 13385,
+ 2440, 29944, 1166, 26060, 16644, 26034, 31510, 32088, 2360, 24530,
+ 5827, 1384, 29695, 22997, 12271, 383, 4387, 5488, 28237, 29722,
+ 11389, 29989, 6183, 226, 14173, 20501, 26345, 32551, 24876, 14357,
+ 1251, 4234, 9039, 26115, 6219, 4089, 17487, 16475, 32641, 27873,
+ 5687, 12293, 8855, 18078, 29758, 14193, 32273, 23607, 17318, 32742,
+ 19177, 9288, 31716, 20759, 26583, 8511, 31233, 9976, 26575, 17867,
+ 9024, 22991, 27082, 32146, 6913, 3214, 7625, 11811, 4069, 21856,
+ 6935, 17451, 25651, 21634, 27599, 8427, 13691, 11604, 29087, 31721,
+ 1913, 5552, 1995, 3302, 5691, 28538, 1653, 4625, 4998, 8312,
+ 2843, 1658, 21367, 7268, 10849, 7369, 11366, 21824, 28433, 21040,
+ 3599, 1514, 19040, 11678, 5108, 2800, 22899, 32566, 5885, 15781,
+ 9249, 13311, 610, 1397, 14587, 4573, 28618, 4981, 19081, 28608,
+ 20149, 31806, 12759, 15899, 6935, 9212, 31280, 29592, 26437, 12482,
+ 23082, 12810, 15637, 30497, 15843, 14242, 6721, 5368, 18057, 28775,
+ 3085, 11917, 25376, 15328, 11818, 477, 26239, 15123, 4313, 17457,
+ 16028, 15028, 19028, 32242, 12554, 3478, 14185, 22718, 16576, 27493,
+ 12136, 5051, 8476, 10135, 12095, 4652, 23080, 21664, 16356, 14402,
+ 539, 10085, 7155, 2612, 12323, 12020, 22681, 16786, 3169, 13426,
+ 5552, 19670, 8501, 22356, 31019, 27964, 20925, 14803, 31157, 26323,
+ 6552, 20889, 15509, 30420, 31216, 12481, 2773, 1075, 14263, 23294,
+ 8611, 15989, 20272, 31514, 25079, 7873, 16562, 3235, 9078, 32569,
+ 6825, 19937, 11927, 15499, 25821, 3594, 8708, 5570, 20727, 11193,
+ 18243, 15971, 21569, 22429, 6805, 22197, 3757, 28526, 2590, 15968,
+ 8985, 1318, 12359, 30009, 25809, 26221, 3425, 32349, 32341, 14421,
+ 1163, 31101, 30045, 31559, 8149, 26232, 12315, 2878, 24485, 18223,
+ 24512, 28722, 6490, 5013, 29761, 4824, 10544, 13317, 32091, 10632,
+ 31587, 30169, 7381, 29054, 12440, 11832, 28165, 2118, 24952, 32559,
+ 1685, 31090, 17822, 29443, 29831, 21646, 16819, 25030, 23927, 24406,
+ 8407, 21801, 8992, 14374, 32067, 24209, 12578, 31921, 7213, 4973,
+ 22531, 18678, 16620, 9158, 22899, 8816, 15197, 16151, 2516, 9101,
+ 13701, 15200, 11001, 31586, 1144, 12918, 25646, 5533, 121, 2461,
+ 31609, 32443, 10338, 5976, 13344, 22651, 5191, 23424, 30315, 29330,
+ 31574, 32148, 9387, 23456, 20737, 1360, 16763, 32355, 15712, 385,
+ 19270, 7978, 29904, 4375, 28938, 19853, 13025, 636, 1115, 7772,
+ 23663, 32036, 19626, 16853, 3342, 26982, 8135, 18970, 5036, 2698,
+ 25509, 13794, 8817, 32547, 23902, 4974, 13802, 7071, 29046, 20415,
+ 30567, 21276, 14692, 1542, 7841, 8829, 4686, 25436, 5792, 12733,
+ 2325, 29363, 27100, 8068, 18321, 25868, 14755, 11000, 26398, 10731,
+ 17594, 12246, 19543, 27656, 16711, 10433, 28705, 17992, 3566, 11226,
+ 14828, 17643, 32315, 5520, 20277, 1799, 17984, 21946, 31823, 5173,
+ 18815, 4835, 6756, 14986, 20746, 6116, 5815, 2249, 27880, 16313,
+ 32555, 14550, 1211, 21389, 14345, 7790, 23456, 3863, 16126, 28182,
+ 2903, 16169, 8035, 28753, 15012, 11910, 31681, 29974, 4852, 21749,
+ 20629, 7041, 14660, 31891, 21584, 16841, 20031, 20845, 6306, 12658,
+ 14758, 3918, 20728, 23492, 17653, 16854, 25156, 14971, 18756, 19148,
+ 8188, 10432, 29803, 8885, 23141, 18520, 26985, 1958, 8721, 18204,
+ 16391, 3670, 25766, 6313, 10168, 18807, 18146, 30808, 12740, 31559,
+ 24540, 18289, 1701, 1378, 14733, 7067, 2737, 2778, 14990, 4503,
+ 13818, 30857, 23843, 14382, 9075, 26534, 22393, 10088, 6996, 3735,
+ 6444, 6143, 7359, 13318, 16908, 3859, 10915, 22583, 30241, 29215,
+ 24545, 2201, 13037, 5932, 3757, 4507, 2544, 9541, 28471, 704,
+ 25714, 22826, 8587, 14582, 13436, 585, 1718, 25380, 14120, 19433,
+ 13611, 13570, 11290, 9897, 3173, 15405, 9807, 26153, 11213, 2939,
+ 23062, 26375, 20701, 12427, 3163, 20749, 24710, 10145, 1835, 18856,
+ 8143, 16817, 14197, 10908, 24512, 12474, 22542, 4343, 8318, 11862,
+ 19960, 22595, 28599, 28814, 6628, 22016, 1600, 24818, 757, 26962,
+ 26877, 18922, 24263, 13046, 4354, 28231, 6832, 2426, 24311, 16157,
+ 27206, 32174, 24001, 9173, 16161, 854, 6239, 2174, 28130, 4641,
+ 1809, 9828, 9331, 21215, 22464, 15076, 5521, 11502, 5530, 8318,
+ 32136, 18421, 29693, 32300, 25662, 21973, 16534, 242, 16499, 14557,
+ 16586, 21431, 24647, 23102, 32340, 18771, 15101, 17598, 18224, 27881,
+ 4094, 22448, 25784, 27767, 30497, 9763, 19982, 4523, 17961, 22106,
+ 22969, 15609, 28560, 5500, 12947, 5866, 16003, 29581, 5090, 27575,
+ 5165, 15261, 4293, 25878, 2616, 7231, 27346, 5716, 7825, 13373,
+ 15357, 3748, 19564, 22410, 30651, 26039, 13961, 8312, 1896, 30348,
+ 18101, 8491, 1510, 15498, 26259, 18766, 24200, 1740, 13724, 21508,
+ 21294, 30140, 24677, 21026, 11697, 30435, 32032, 9371, 8321, 13055,
+ 4454, 31548, 6796, 8790, 9524, 11161, 4706, 15179, 1843, 29767,
+ 3223, 28463, 9788, 75, 24937, 26969, 9243, 16083, 1443, 17529,
+ 1427, 25380, 23234, 10793, 9123, 8404, 19029, 4293, 16904, 30777,
+ 12458, 2941, 28419, 10017, 23206, 24744, 4188, 4547, 6901, 23131,
+ 16807, 14326, 14948, 1339, 26566, 2721, 18314, 20879, 7599, 13683,
+ 2478, 19098, 24176, 12500, 6885, 22567, 4208, 12315, 28027, 15973,
+ 22007, 16385, 16532, 20469, 18160, 10581, 18451, 1602, 30702, 27634,
+ 3003, 29713, 29294, 26095, 16788, 18009, 604, 31509, 10129, 18260,
+ 31960, 20630, 8303, 6102, 25657, 28923, 6112, 4830, 3410, 27743,
+ 29161, 3946, 10741, 18651, 2441, 29840, 23734, 22337, 667, 21451,
+ 14833, 16397, 29437, 32147, 23055, 23704, 9970, 17456, 24836, 12431,
+ 1221, 24783, 7964, 6052, 21424, 11990, 12024, 31619, 27131, 12661,
+ 13523, 9736, 1640, 6013, 8971, 943, 22735, 12662, 10204, 27212,
+ 32262, 3564, 10350, 14332, 29443, 12297, 27922, 24155, 17221, 5225,
+ 25288, 11767, 30320, 30761, 5638, 30213, 311, 5697, 19124, 19539,
+ 15742, 20244, 21883, 4478, 11712, 28230, 6719, 1381, 4015, 718,
+ 21482, 32733, 539, 32076, 2412, 8615, 16917, 2204, 21504, 4511,
+ 17236, 20651, 23216, 6709, 10200, 11145, 10011, 15137, 23244, 22720,
+ 14198, 851, 21169, 19173, 29137, 18217, 16057, 12140, 23707, 1765,
+ 9073, 10432, 16489, 6494, 10915, 28308, 5875, 28406, 10875, 18547,
+ 27487, 203, 10216, 5791, 4035, 16434, 22597, 23832, 19429, 6753,
+ 26169, 1275, 26949, 25707, 32220, 18445, 16477, 17266, 25627, 31384,
+ 11047, 25879, 7517, 10102, 224, 7222, 26471, 12907, 32524, 13777,
+ 2684, 29880, 17338, 6729, 17865, 2028, 15625, 3796, 23297, 13054,
+ 12779, 11051, 32069, 11673, 18473, 22403, 10054, 11703, 11175, 26303,
+ 7341, 29553, 15082, 8420, 6843, 18197, 23767, 20941, 31788, 7546,
+ 25533, 12320, 21602, 22160, 8598, 12416, 17855, 19003, 4490, 6404,
+ 5971, 5986, 15029, 26856, 19895, 26947, 12330, 26755, 19256, 9993,
+ 21048, 30073, 15160, 16800, 13548, 24370, 19666, 5064, 20438, 26507,
+ 189, 2152, 23312, 15307, 3699, 31525, 32125, 31192, 9362, 1844,
+ 12367, 5547, 2178, 14444, 31692, 13057, 22872, 21152, 29009, 18259,
+ 31226, 9003, 1687, 6153, 26244, 4300, 13877, 26859, 30955, 23989,
+ 2406, 28376, 24801, 20446, 28429, 23226, 21240, 13215, 1014, 4281,
+ 13065, 27774, 12383, 24495, 15831, 2118, 16055, 19676, 30192, 2137,
+ 20389, 18396, 22484, 21830, 20300, 23253, 6489, 4254, 20430, 10997,
+ 30798, 14596, 27918, 23836, 23647, 21636, 7611, 13013, 20536, 5414,
+ 5514, 29579, 5614, 11202, 7362, 30202, 23194, 15637, 254, 24035,
+ 19783, 11541, 814, 25092, 7438, 13442, 26336, 11847, 8831, 29886,
+ 1726, 13882, 14403, 32222, 4695, 3007, 1792, 31489, 22818, 3589,
+ 18557, 30944, 18111, 1206, 17927, 31399, 29825, 31602, 5651, 20740,
+ 29738, 29053, 23844, 26493, 14325, 12724, 5615, 31750, 15322, 26310,
+ 9405, 29907, 21517, 16288, 14866, 18539, 17608, 14377, 18572, 11262,
+ 1866, 23088, 4621, 31736, 24608, 2722, 4125, 4822, 10915, 14081,
+ 15241, 568, 32194, 30481, 30544, 25144, 3585, 30421, 8896, 11003,
+ 28866, 15545, 5853, 19589, 9411, 8209, 4866, 30930, 1001, 962,
+ 23755, 21538, 572, 10559, 5937, 32660, 24114, 12216, 5367, 12790,
+ 9776, 5006, 10822, 21212, 14158, 16905, 16788, 19439, 6491, 5453,
+ 14282, 1160, 23585, 19594, 17317, 15230, 23017, 21620, 27740, 13116,
+ 834, 29683, 21380, 25622, 6143, 12571, 22065, 10461, 29055, 606,
+ 18783, 6576, 16945, 8192, 21904, 2326, 28246, 2508, 13750, 22346,
+ 25097, 5382, 23890, 4054, 2173, 5792, 18910, 1379, 18567, 32176,
+ 873, 24528, 10844, 29218, 4225, 20609, 2715, 19370, 24917, 24826,
+ 32398, 29949, 30235, 4012, 19885, 3905, 17584, 12046, 9315, 27074,
+ 8574, 15088, 25621, 8678, 12195, 6157, 13409, 32611, 7248, 29151,
+ 14755, 24751, 10606, 10935, 5310, 19385, 19336, 4620, 4121, 30422,
+ 24293, 21779, 7655, 24062, 14324, 23953, 2988, 14392, 4846, 4846,
+ 3836, 24915, 9910, 12682, 3974, 3031, 24324, 11348, 21074, 20283,
+ 450, 19608, 27207, 26200, 17334, 1048, 4592, 12830, 4194, 9567,
+ 21120, 21638, 2344, 30290, 7187, 30663, 32690, 20744, 13110, 5581,
+ 28561, 18139, 6058, 21479, 15140, 31167, 18533, 18112, 12220, 8147,
+ 2266, 12944, 5373, 25910, 2938, 7059, 19336, 8220, 9595, 15035,
+ 16087, 2849, 28632, 10914, 11879, 31197, 31129, 24770, 4637, 15288,
+ 28500, 18152, 7651, 8447, 23540, 2278, 10386, 22072, 26297, 27272,
+ 31252, 2483, 12928, 14794, 17610, 3938, 16965, 12616, 20011, 30442,
+ 1766, 24310, 2734, 18426, 31273, 25361, 12522, 22748, 27393, 6998,
+ 2044, 29514, 24333, 3697, 29994, 15234, 11618, 11192, 3270, 3485,
+ 13962, 13081, 10836, 17692, 24012, 22865, 21487, 8900, 10158, 31839,
+ 27880, 17580, 8633, 31801, 31665, 25748, 30588, 3005, 1785, 20600,
+ 22740, 3562, 19993, 20837, 5482, 21328, 24751, 29836, 4476, 19397,
+ 22920, 27285, 30689, 90, 16580, 28981, 19783, 27022, 22836, 31491,
+ 18624, 30145, 23815, 2439, 5501, 21483, 28070, 28052, 25048, 22157,
+ 15068, 25048, 24472, 744, 9530, 13234, 6513, 8302, 24506, 28227,
+ 16843, 23670, 21666, 15304, 24261, 22067, 20907, 28967, 30584, 9959,
+ 16227, 30663, 9856, 14932, 26576, 2469, 13753, 2931, 4182, 29605,
+ 10054, 6505, 27354, 21030, 20440, 10423, 8744, 31704, 26156, 9393,
+ 1426, 3794, 11222, 13617, 6106, 21471, 4926, 23692, 1363, 27673,
+ 1768, 12741, 17730, 31930, 13816, 2817, 27274, 19758, 2549, 11323,
+ 26505, 2925, 10701, 20025, 18749, 10887, 11801, 4543, 11691, 3968,
+ 27299, 13058, 31105, 95, 28965, 4447, 4346, 2434, 12628, 24397,
+ 6146, 19764, 23069, 3729, 32155, 29058, 24623, 19633, 22143, 8266,
+ 19897, 9130, 19206, 19860, 16245, 4837, 7243, 14373, 13029, 13416,
+ 1162, 22610, 2525, 16970, 30413, 12563, 26433, 4201, 456, 14168,
+ 18704, 20063, 23041, 17312, 929, 9649, 20276, 16839, 557, 2122,
+ 12533, 4895, 28814, 17192, 26263, 22211, 12870, 10582, 15949, 3112,
+ 19139, 27418, 14223, 17397, 6882, 28015, 19647, 21269, 6065, 13749,
+ 13, 15370, 24185, 15784, 12184, 17028, 18940, 17295, 29909, 23858,
+ 27899, 27317, 4917, 31192, 5627, 16413, 14850, 18338, 16457, 30578,
+ 7562, 31672, 5692, 29757, 11136, 17426, 26810, 29531, 24223, 23694,
+ 16381, 26797, 30096, 31295, 27031, 25873, 4366, 264, 10164, 6289,
+ 32072, 14186, 26016, 17627, 10887, 27803, 5513, 13297, 6416, 17624,
+ 7045, 1826, 15436, 8187, 27095, 29241, 6438, 20048, 12910, 14068,
+ 9141, 1957, 20910, 29880, 8219, 22688, 22131, 8322, 2733, 31318,
+ 19283, 14625, 19284, 18456, 9508, 2979, 14386, 18320, 31422, 7181,
+ 11145, 30478, 27138, 1615, 12505, 22044, 19996, 27510, 3401, 23640,
+ 11012, 16164, 10056, 21123, 29259, 2365, 4468, 16853, 1300, 28644,
+ 15547, 28051, 5985, 7590, 5568, 2788, 22672, 22516, 4480, 10977,
+ 1317, 22999, 27957, 2795, 17865, 18143, 9595, 16193, 32659, 19037,
+ 26801, 27601, 31111, 14033, 2210, 32591, 31580, 14758, 12132, 9349,
+ 18819, 30493, 23425, 24042, 8804, 8840, 26453, 32629, 8427, 26296,
+ 8119, 31411, 10307, 12984, 11740, 12568, 15585, 16060, 22647, 16531,
+ 28357, 23892, 24613, 32356, 14588, 27877, 31497, 5170, 31338, 32090,
+ 13235, 29528, 27590, 32279, 12103, 4737, 14054, 2094, 7899, 10612,
+ 4925, 6358, 24608, 24369, 2978, 20505, 4421, 7740, 20818, 1996,
+ 7192, 825, 16441, 22212, 31855, 6585, 30829, 21575, 17862, 23380,
+ 12540, 12225, 11305, 9464, 10215, 28856, 5205, 5760, 21358, 29442,
+ 28442, 4232, 14478, 29494, 25603, 17536, 2761, 16224, 3897, 2816,
+ 31013, 24569, 22181, 29787, 19575, 19734, 6741, 18295, 15073, 991,
+ 17441, 25308, 5274, 4163, 31374, 13322, 11757, 24298, 31474, 14608,
+ 10885, 27499, 24281, 16474, 3559, 7872, 20648, 23243, 13632, 29175,
+ 29568, 13324, 7777, 10537, 613, 17699, 8200, 15024, 27296, 5447,
+ 30561, 13973, 25953, 31986, 20172, 16968, 21673, 7993, 8673, 31892,
+ 26471, 3417, 8881, 24017, 18658, 18578, 1103, 26716, 24406, 5688,
+ 20112, 15684, 24034, 23047, 7950, 26950, 11681, 27319, 31603, 32252,
+ 29208, 5328, 6388, 19281, 11472, 16320, 15643, 19768, 17475, 26922,
+ 7114, 8606, 29181, 27266, 22141, 6812, 23547, 15575, 207, 16626,
+ 23895, 12015, 20032, 23217, 16935, 16793, 19765, 18999, 31394, 7743,
+ 21312, 22880, 2436, 23483, 32418, 17659, 12724, 1387, 28942, 7291,
+ 10020, 6280, 10160, 18927, 18169, 27571, 5230, 22069, 6893, 13521,
+ 23662, 15722, 11249, 8473, 24536, 26532, 26646, 13163, 28381, 6628,
+ 8109, 23780, 20472, 29510, 23981, 943, 31603, 19067, 8022, 27678,
+ 12334, 32633, 12052, 14329, 17820, 5489, 9894, 28694, 24334, 10498,
+ 23679, 19497, 25652, 5804, 16493, 11486, 25312, 25991, 27512, 31781,
+ 15886, 18997, 26381, 26573, 20002, 22037, 28508, 10837, 22128, 9913,
+ 13566, 22015, 29697, 10651, 25051, 22053, 27028, 18443, 25931, 6864,
+ 27876, 3948, 19323, 8839, 22825, 10656, 9235, 22117, 27361, 14785,
+ 15381, 27759, 26832, 28946, 12040, 17444, 24134, 28725, 4951, 29013,
+ 19104, 18590, 17908, 26934, 27153, 12871, 6464, 1462, 31651, 18853,
+ 27439, 21260, 10360, 27100, 26279, 23442, 28758, 30511, 29738, 26071,
+ 16227, 11706, 7605, 22767, 4396, 18531, 27112, 15118, 17644, 5134,
+ 29286, 32342, 1804, 17168, 14719, 4076, 29670, 5350, 781, 23889,
+ 22478, 9768, 13467, 17392, 12371, 31928, 205, 7923, 21186, 9279,
+ 25084, 26459, 23532, 28378, 10272, 6736, 19753, 11792, 7667, 22965,
+ 31389, 30728, 2387, 31488, 11962, 19704, 2792, 30793, 9990, 12513,
+ 8456, 30624, 19999, 3450, 20951, 23716, 22268, 28777, 16563, 6226,
+ 7541, 31161, 13007, 11034, 28678, 3721, 18205, 3384, 9936, 9217,
+ 25970, 28993, 11232, 13963, 10469, 5372, 22708, 16703, 18808, 5236,
+ 19707, 18846, 18682, 29515, 8861, 21380, 26411, 20561, 8955, 20824,
+ 8482, 30549, 24952, 25734, 16364, 17724, 24376, 559, 14966, 4688,
+ 7208, 20511, 28332, 5850, 14654, 19967, 30179, 32242, 4098, 7883,
+ 6260, 6806, 25421, 1671, 9386, 29434, 3408, 28718, 11487, 5663,
+ 20185, 4076, 28897, 28583, 9170, 30092, 30363, 3560, 16650, 9012,
+ 5617, 3647, 7993, 31824, 31723, 9126, 14142, 8396, 26902, 27529,
+ 21418, 2182, 12071, 1238, 7042, 29443, 12770, 7508, 14913, 32609,
+ 28474, 26933, 18717, 140, 21178, 14574, 23947, 25013, 22563, 8518,
+ 24837, 12032, 16727, 27053, 5643, 5757, 25461, 13520, 28264, 30042,
+ 20294, 5994, 5814, 17751, 22744, 4445, 23332, 32377, 17000, 7425,
+ 18807, 16643, 3717, 18620, 13391, 23458, 15731, 3795, 31660, 488,
+ 31182, 24447, 16048, 18171, 30831, 4420, 23207, 12431, 3988, 11134,
+ 23364, 30225, 18746, 16189, 16429, 16421, 29902, 16978, 15291, 31827,
+ 31749, 8362, 20218, 6397, 32521, 30683, 26360, 15765, 31701, 12541,
+ 24380, 21261, 1250, 27835, 3476, 28814, 19203, 30121, 15124, 108,
+ 32397, 11481, 11867, 12634, 19388, 9385, 11032, 2010, 30290, 24030,
+ 2765, 9208, 22657, 23287, 21203, 3896, 18699, 32187, 27551, 9933,
+ 11432, 25365, 23875, 30219, 13992, 12577, 13623, 5407, 7385, 2951,
+ 31066, 24574, 17067, 8712, 19508, 6555, 8082, 3414, 9854, 20317,
+ 25772, 28201, 18916, 4304, 9636, 655, 20745, 20379, 2262, 9603,
+ 204, 31666, 17076, 27842, 16074, 12236, 24680, 22746, 20771, 536,
+ 9659, 19332, 19330, 19755, 565, 14387, 19799, 1341, 24965, 17133,
+ 30055, 28054, 23332, 16730, 11911, 16963, 1334, 21019, 14756, 10765,
+ 28337, 32348, 6407, 1196, 1216, 6573, 16599, 26935, 26474, 21517,
+ 12512, 26847, 29039, 12872, 23442, 27101, 30578, 24708, 32333, 11945,
+ 605, 4886, 20188, 23917, 2306, 27034, 8767, 7097, 27902, 2114,
+ 28845, 4728, 16099, 23406, 23257, 28195, 3478, 14717, 5237, 12084,
+ 17653, 22243, 22516, 24286, 24509, 16508, 18325, 31739, 28843, 20513,
+ 24477, 13382, 18146, 20344, 24035, 15818, 12685, 15632, 17042, 25754,
+ 9925, 26541, 20011, 8387, 20917, 21472, 8393, 18559, 19452, 8155,
+ 24233, 12971, 1618, 22916, 32233, 23931, 9327, 31432, 8592, 28013,
+ 20521, 50, 9679, 6267, 18396, 19900, 16775, 20885, 11278, 21989,
+ 24842, 18510, 20563, 14083, 7718, 4310, 4975, 17115, 31072, 2088,
+ 699, 9327, 14461, 18564, 19658, 6167, 3655, 16928, 18251, 27091,
+ 28557, 19483, 3121, 11744, 14700, 16818, 29202, 26505, 3277, 32694,
+ 25549, 4672, 815, 22077, 23408, 16621, 8359, 17049, 1113, 18310,
+ 10020, 1414, 18587, 8928, 12024, 27047, 19875, 4805, 10388, 20020,
+ 9243, 6726, 11155, 18925, 12046, 23122, 14075, 31314, 1613, 31368,
+ 18111, 21269, 22546, 5194, 25224, 464, 3556, 21523, 2484, 14836,
+ 14522, 17674, 8351, 32001, 2147, 31447, 17186, 13053, 21029, 3509,
+ 8282, 10015, 27301, 7368, 17323, 15563, 22278, 19122, 28420, 28867,
+ 6485, 26721, 27236, 31387, 7205, 16938, 27805, 8813, 374, 17180,
+ 344, 7887, 22748, 25230, 4185, 3842, 221, 4091, 27140, 25964,
+ 14234, 4368, 32032, 22088, 7858, 1538, 6620, 7837, 13923, 2085,
+ 26127, 14188, 5106, 5819, 26308, 18734, 22349, 17929, 17142, 29566,
+ 9200, 25777, 9112, 15634, 8453, 2875, 21721, 16367, 17615, 18933,
+ 3237, 26077, 28488, 26877, 31343, 18713, 6153, 28316, 1070, 3403,
+ 4971, 24533, 21669, 17591, 13036, 28478, 7912, 13751, 17620, 3599,
+ 15132, 5225, 14104, 4985, 126, 1189, 24958, 28217, 167, 30770,
+ 15106, 5228, 2062, 15673, 32376, 9637, 1998, 20729, 628, 29501,
+ 19625, 19133, 18535, 25322, 10061, 29451, 1802, 24467, 27095, 23327,
+ 13312, 19555, 24214, 2200, 20663, 11805, 7185, 2416, 32399, 32431,
+ 23115, 1073, 7742, 24329, 11589, 6246, 32371, 6959, 18629, 9040,
+ 23993, 13453, 12630, 15579, 17310, 26252, 32400, 208, 29973, 22882,
+ 4761, 30796, 2074, 30510, 27372, 14193, 23188, 5956, 28249, 859,
+ 28799, 29637, 23629, 5206, 32074, 7540, 16724, 18510, 7294, 25028,
+ 5340, 22919, 32161, 22326, 25660, 28046, 1882, 993, 12021, 4207,
+ 13782, 21074, 22583, 28712, 14441, 18583, 20903, 27742, 4729, 13719,
+ 25439, 20047, 17304, 18597, 13622, 15624, 15088, 18260, 32066, 16855,
+ 6628, 21900, 30620, 28932, 2548, 989, 2915, 2748, 10721, 6164,
+ 16644, 10318, 22034, 17420, 28088, 18842, 20535, 16071, 14414, 22213,
+ 2604, 29629, 23338, 27186, 6176, 15476, 18318, 30382, 3574, 22609,
+ 3608, 7659, 19435, 5806, 12428, 19248, 32378, 26413, 16596, 26190,
+ 21885, 17483, 28997, 13014, 13972, 11320, 31268, 12169, 28362, 7142,
+ 30825, 2576, 10102, 16479, 10690, 31470, 8800, 21085, 10715, 7602,
+ 293, 20500, 5341, 6513, 7133, 2387, 13109, 11635, 11002, 12747,
+ 4758, 30253, 18547, 28078, 12353, 32367, 3107, 3197, 6276, 28895,
+ 18284, 26139, 8064, 32166, 9247, 3621, 5936, 18537, 10912, 20870,
+ 9895, 29307, 29509, 12869, 9881, 5457, 1792, 21922, 10013, 16694,
+ 13118, 6242, 689, 21567, 21774, 15719, 8831, 15746, 24454, 27267,
+ 22495, 131, 8546, 26510, 28444, 3311, 3567, 21430, 24443, 16013,
+ 3368, 17687, 15481, 6513, 5918, 1676, 19541, 5747, 7837, 26564,
+ 26574, 5087, 3852, 21400, 1838, 15982, 24981, 8347, 8327, 1653,
+ 3462, 20467, 15165, 30045, 22519, 11880, 23748, 30547, 18094, 3003,
+ 12971, 27968, 14911, 31801, 7642, 6908, 29559, 22671, 792, 17855,
+ 2043, 28640, 1232, 5848, 2605, 8213, 2580, 5793, 26703, 18549,
+ 14050, 21426, 18155, 19061, 14758, 2645, 23154, 3281, 4609, 24634,
+ 1059, 13531, 13513, 2156, 13870, 2579, 12625, 25476, 25370, 14329,
+ 15338, 28701, 31844, 25119, 16809, 8071, 17513, 16002, 26987, 25280,
+ 30597, 10778, 9751, 927, 4221, 27568, 15907, 7763, 11290, 6384,
+ 27738, 20236, 20503, 20927, 32220, 26616, 6462, 17871, 4454, 17265,
+ 5325, 14448, 23507, 1653, 18718, 30377, 5603, 26454, 12679, 29575,
+ 30524, 19634, 12672, 32437, 25262, 22694, 17155, 18765, 10171, 13375,
+ 25657, 11502, 32087, 12081, 2130, 26895, 6636, 1996, 4020, 19090,
+ 3233, 28459, 2905, 29084, 15324, 7599, 20338, 10661, 11525, 2988,
+ 6481, 1995, 31118, 8801, 19589, 17260, 5424, 31022, 2887, 31987,
+ 18807, 29441, 11797, 26354, 2688, 20498, 24220, 1394, 2306, 2000,
+ 23003, 30599, 9611, 32538, 7558, 32551, 10508, 28339, 1192, 15163,
+ 26264, 3568, 6029, 18423, 10857, 21940, 4831, 14695, 6692, 28574,
+ 27151, 9291, 27229, 9601, 18678, 10533, 3422, 25877, 22717, 13712,
+ 16164, 11244, 19450, 28627, 4779, 28583, 30235, 182, 25708, 22121,
+ 29192, 12181, 22051, 21388, 7172, 1202, 14293, 31891, 25300, 26063,
+ 530, 10848, 13348, 24829, 17784, 15016, 2086, 6575, 13176, 1443,
+ 20604, 3090, 9309, 23560, 20056, 6817, 16009, 8504, 5090, 6644,
+ 8962, 21945, 13530, 20184, 17198, 9703, 27262, 4773, 17371, 20710,
+ 11950, 4556, 4482, 31707, 4686, 22704, 2509, 17756, 21228, 8887,
+ 24150, 11557, 29602, 8096, 5298, 9228, 23870, 8983, 18350, 22583,
+ 18849, 29318, 3544, 4492, 32357, 9519, 10562, 12905, 6851, 19064,
+ 25730, 12437, 31923, 19077, 16637, 6775, 340, 13580, 23142, 31878,
+ 9359, 29285, 9089, 15105, 17399, 2785, 24621, 13280, 2292, 30813,
+ 161, 15626, 15905, 13847, 16886, 21192, 5106, 704, 14310, 2682,
+ 6298, 2258, 9171, 7561, 26412, 24867, 15626, 8348, 20992, 9147,
+ 20042, 15119, 3160, 31458, 19584, 29345, 5955, 27774, 19157, 24428,
+ 30146, 19868, 28650, 23579, 27690, 5197, 20578, 1623, 20169, 31667,
+ 21154, 9090, 9164, 11867, 32724, 15784, 7264, 27341, 26162, 3250,
+ 10520, 22114, 28801, 32733, 11663, 29270, 22235, 31595, 5966, 26398,
+ 3250, 7833, 23536, 6652, 20498, 9680, 8836, 16592, 15910, 15647,
+ 7218, 26673, 4350, 22249, 20514, 8124, 27279, 23259, 24217, 16556,
+ 20732, 16673, 32613, 684, 16404, 28122, 16252, 21225, 29723, 24777,
+ 16864, 8554, 20941, 3405, 1989, 6308, 4000, 28307, 1014, 29513,
+ 1098, 11274, 32117, 25698, 16003, 25111, 1377, 17821, 18956, 25355,
+ 1053, 32744, 17904, 1106, 8623, 25150, 12298, 19436, 3430, 23233,
+ 2503, 4642, 26816, 17930, 14893, 27505, 22922, 18621, 20764, 28363,
+ 1865, 26464, 4052, 11263, 2009, 20589, 23224, 26229, 32596, 3237,
+ 30802, 26654, 30518, 2472, 16790, 171, 12478, 12995, 10091, 1277,
+ 30359, 3081, 12647, 25309, 12727, 933, 23002, 7406, 17800, 28014,
+ 27407, 17119, 30533, 23740, 16846, 14821, 25767, 20602, 6437, 26985,
+ 19906, 25981, 17257, 8190, 13865, 788, 29815, 17557, 8537, 13793,
+ 319, 10228, 28245, 11495, 14468, 2660, 5773, 3299, 14557, 10666,
+ 21508, 3552, 26624, 27449, 29362, 5894, 28479, 30374, 20776, 19635,
+ 24915, 21596, 21618, 17613, 27993, 25745, 21313, 21846, 17178, 17017,
+ 15434, 12608, 3215, 26553, 31721, 18307, 8357, 9246, 25866, 6254,
+ 21309, 15759, 8521, 30010, 1655, 19520, 27736, 24037, 24880, 10025,
+ 7841, 28990, 20169, 29879, 19245, 9020, 11306, 13249, 29893, 11667,
+ 17927, 20669, 7767, 28297, 3170, 6964, 15003, 10758, 8018, 12147,
+ 16117, 24811, 6402, 10372, 23966, 12965, 14588, 11868, 11007, 32002,
+ 21672, 13398, 12893, 11843, 12559, 31712, 15803, 32114, 10725, 12148,
+ 21756, 31990, 18887, 10699, 14409, 15204, 14273, 15693, 22962, 26264,
+ 7699, 4043, 6680, 9477, 28213, 24176, 19786, 6473, 9752, 15861,
+ 18798, 17412, 31407, 11029, 1443, 14315, 2990, 32577, 3044, 21528,
+ 1170, 7572, 16943, 30884, 20193, 27657, 20199, 27000, 14771, 27884,
+ 7288, 21344, 14961, 3214, 16441, 10082, 10973, 30525, 18582, 16461,
+ 10322, 2931, 13934, 1684, 30797, 15438, 9658, 1629, 5677, 30784,
+ 26992, 11222, 20023, 26632, 7847, 6600, 2525, 6625, 31483, 20078,
+ 12608, 27897, 23091, 2695, 17907, 20772, 20257, 11946, 6914, 11986,
+ 15306, 730, 20019, 2879, 13511, 7258, 26251, 15593, 13291, 21954,
+ 15380, 17479, 24102, 3411, 3294, 7352, 24745, 7560, 25412, 6586,
+ 10571, 17389, 12656, 9308, 32300, 27188, 17954, 27894, 14488, 1414,
+ 32428, 25879, 10030, 23, 23106, 5567, 23361, 24829, 21104, 9678,
+ 25982, 9794, 7404, 9405, 17871, 1336, 14990, 28044, 4736, 1292,
+ 30621, 13819, 6817, 10142, 16716, 7677, 1963, 5264, 29828, 21354,
+ 16998, 31390, 2532, 7668, 7945, 6957, 17159, 26460, 5283, 13350,
+ 15621, 5094, 955, 15364, 3132, 16138, 20531, 9260, 17744, 12396,
+ 21107, 5501, 6000, 7438, 25539, 23337, 23515, 2244, 2551, 28611,
+ 16035, 23529, 1618, 24729, 25777, 337, 19365, 31555, 13066, 8318,
+ 8119, 31100, 6993, 18455, 27625, 7985, 4492, 7317, 282, 32472,
+ 3883, 24384, 21193, 22531, 18246, 24922, 28025, 17461, 28710, 14234,
+ 11354, 9716, 17927, 16860, 29221, 3615, 11036, 23318, 26952, 2946,
+ 2260, 17806, 3907, 6312, 22108, 10058, 3922, 7152, 26725, 10952,
+ 12364, 11747, 28199, 6128, 22987, 6597, 16293, 31047, 29837, 19562,
+ 24883, 8549, 10778, 9548, 24630, 9385, 18343, 24026, 27948, 6955,
+ 18491, 31506, 22252, 16114, 18960, 32081, 19246, 14952, 29500, 17002,
+ 77, 15114, 2448, 19958, 11340, 7268, 16833, 27628, 27928, 16189,
+ 2501, 24946, 1548, 24847, 21120, 8178, 5818, 1978, 7328, 11887,
+ 12009, 21880, 19654, 15642, 25562, 22804, 2790, 5920, 19152, 11863,
+ 12528, 26311, 31950, 708, 3248, 32697, 1955, 21125, 30963, 9119,
+ 28708, 29092, 4587, 29938, 10681, 13694, 2260, 3086, 10011, 21109,
+ 23256, 25225, 26715, 16870, 28464, 2242, 10791, 17499, 24717, 22973,
+ 6729, 21505, 30134, 8494, 13680, 7004, 3442, 26579, 12851, 17465,
+ 424, 23047, 7507, 13028, 17861, 31893, 2880, 412, 17502, 9162,
+ 735, 20548, 16407, 24782, 1419, 15451, 15299, 22836, 22618, 5422,
+ 11724, 15567, 29345, 8268, 725, 19911, 13754, 571, 13215, 12013,
+ 20996, 8041, 29225, 27724, 32044, 2405, 12828, 29184, 23979, 19535,
+ 4197, 25932, 20368, 12430, 24100, 5094, 26240, 17600, 21189, 28053,
+ 20731, 17399, 10604, 15358, 224, 11298, 11671, 3259, 15668, 6345,
+ 31487, 430, 287, 13822, 29887, 31637, 19511, 24464, 14263, 21214,
+ 18434, 16513, 3123, 4796, 26293, 1722, 6856, 27258, 24386, 32510,
+ 26751, 18704, 10898, 11549, 24118, 22260, 26127, 13418, 24386, 16946,
+ 16230, 9326, 13145, 4287, 19851, 32222, 18352, 27914, 31485, 971,
+ 2912, 8405, 25931, 11545, 27406, 12867, 21975, 18994, 12235, 22322,
+ 14298, 13051, 17721, 13002, 12200, 4360, 10991, 4438, 14134, 6668,
+ 5407, 5715, 25561, 20115, 118, 4295, 14672, 4339, 15684, 27093,
+ 11781, 10367, 13789, 24973, 17552, 1279, 29759, 3593, 24189, 22109,
+ 10997, 20661, 11343, 19617, 17723, 13806, 24260, 5151, 16994, 29391,
+ 32091, 25071, 24694, 30023, 1556, 9374, 23071, 14959, 14967, 11555,
+ 15301, 24347, 15831, 25621, 5111, 7856, 26840, 24347, 782, 13365,
+ 30255, 27299, 28173, 20908, 27817, 23511, 22732, 8610, 27247, 16076,
+ 11094, 1797, 13704, 13565, 26255, 3894, 13727, 6137, 3098, 19039,
+ 15111, 13400, 15737, 32263, 14076, 12531, 22134, 26083, 18732, 30293,
+ 1730, 30447, 18038, 10860, 11997, 22718, 7409, 5252, 1077, 2318,
+ 14640, 32119, 16530, 23968, 20676, 24605, 24753, 22599, 13827, 32266,
+ 13871, 318, 6408, 11385, 20650, 15294, 23035, 28035, 546, 18640,
+ 20627, 10645, 677, 27745, 11480, 7456, 30507, 26772, 21806, 20114,
+ 24511, 17244, 25999, 8326, 12511, 2633, 13336, 21559, 7206, 2210,
+ 32455, 4155, 19496, 9141, 9859, 16238, 6046, 20843, 7004, 23596,
+ 28611, 23839, 24085, 31683, 3581, 28336, 15071, 11815, 9408, 2005,
+ 8552, 1512, 6063, 27569, 15892, 23650, 32517, 9384, 14474, 9780,
+ 31284, 7280, 15219, 27635, 5580, 31339, 10622, 15135, 18589, 15412,
+ 9128, 9045, 19488, 15480, 17594, 5063, 21523, 7175, 13843, 11498,
+ 26980, 16682, 423, 23150, 27728, 24888, 17736, 18803, 460, 18532,
+ 11045, 3834, 28708, 21465, 19344, 4761, 12002, 21001, 23556, 4468,
+ 11761, 15681, 20326, 19816, 6146, 1153, 19339, 15497, 5167, 22156,
+ 6139, 19663, 19166, 9019, 27124, 4108, 12777, 18198, 12722, 25633,
+ 25596, 5413, 19694, 27506, 1854, 13060, 17061, 27031, 1843, 31542,
+ 27674, 22613, 9697, 22971, 12062, 18636, 10289, 22245, 11663, 25841,
+ 8601, 17511, 3615, 9535, 8952, 16559, 16982, 3754, 20673, 1142,
+ 28123, 3285, 9308, 11925, 21231, 15492, 23753, 538, 26682, 14932,
+ 25223, 19099, 31690, 18858, 8884, 23242, 1881, 26601, 9589, 22858,
+ 6606, 8168, 25496, 20417, 31239, 12707, 8056, 12335, 26326, 25136,
+ 17697, 17534, 6217, 2037, 5557, 15450, 26159, 10009, 8719, 19778,
+ 14295, 12856, 22693, 6367, 8475, 17243, 10931, 19861, 20637, 24871,
+ 3222, 13657, 13137, 9300, 21877, 9922, 28988, 20833, 16935, 3170,
+ 10107, 14982, 8017, 30294, 902, 32235, 24271, 27164, 9142, 29719,
+ 7254, 25765, 24837, 25259, 21847, 17067, 26134, 18256, 22566, 837,
+ 14197, 20206, 11867, 6329, 4383, 19743, 1657, 15249, 15685, 18403,
+ 24781, 29681, 18509, 27541, 921, 19751, 13850, 31517, 31346, 26500,
+ 7309, 4200, 9447, 23658, 18251, 16661, 6243, 10407, 18625, 31601,
+ 22869, 4353, 7270, 12198, 12173, 13586, 15936, 6447, 6633, 17495,
+ 23466, 15503, 9522, 2435, 340, 27971, 10817, 16409, 27275, 28661,
+ 14182, 26681, 21947, 3314, 10506, 3258, 562, 9950, 13714, 12154,
+ 15142, 10663, 28807, 20466, 5114, 26039, 2292, 16398, 14781, 11118,
+ 18192, 15163, 32244, 15055, 3357, 29633, 32409, 23417, 24464, 2643,
+ 3939, 12505, 14450, 9188, 18504, 7839, 10758, 4541, 23873, 20846,
+ 5292, 16333, 9037, 16344, 29701, 23872, 26296, 14217, 1880, 29523,
+ 30365, 19138, 22837, 24166, 2474, 12810, 27224, 23890, 24611, 30240,
+ 975, 11006, 18217, 30259, 29792, 22061, 24893, 7765, 15653, 19354,
+ 22528, 25134, 29049, 17991, 23356, 20461, 19992, 6674, 4392, 20356,
+ 19329, 3209, 23528, 25109, 12191, 12287, 6228, 30119, 25257, 29920,
+ 14842, 8478, 2887, 25921, 26726, 23658, 13814, 16059, 417, 2302,
+ 2989, 24186, 9719, 24196, 23489, 13201, 12541, 4047, 32006, 11152,
+ 17363, 15377, 18999, 19801, 17575, 78, 15767, 30255, 30586, 15632,
+ 28633, 27920, 5159, 25693, 32317, 16453, 32161, 25574, 7165, 8503,
+ 32380, 32641, 21223, 12932, 11951, 12249, 14155, 31826, 26264, 22884,
+ 4887, 31460, 25408, 28566, 19521, 31595, 32737, 22613, 2661, 15134,
+ 10405, 9132, 24496, 31884, 27313, 27587, 30972, 1841, 17762, 28943,
+ 6460, 17736, 8406, 18118, 25627, 29665, 3503, 9110, 15328, 6451,
+ 12819, 10902, 13973, 13619, 2039, 16509, 28264, 24678, 20638, 16658,
+ 12625, 19699, 24924, 10467, 21493, 24060, 11680, 1850, 11211, 18734,
+ 12850, 19533, 29821, 30359, 9656, 18357, 9361, 4792, 4735, 27425,
+ 30024, 1756, 15736, 9548, 8646, 19368, 32385, 26924, 8564, 18930,
+ 28134, 13677, 24995, 15831, 2856, 12317, 17010, 20487, 16637, 10921,
+ 23281, 22884, 27287, 8712, 18566, 1228, 15913, 3894, 3472, 17202,
+ 16552, 7140, 17227, 17908, 9935, 3950, 8948, 29544, 18277, 2061,
+ 10797, 2488, 706, 21582, 24226, 25585, 17296, 194, 29933, 5462,
+ 31951, 28151, 24247, 20218, 18715, 680, 1056, 17294, 3890, 20017,
+ 11361, 32119, 20401, 12101, 22960, 23332, 30, 21219, 7269, 9630,
+ 5931, 8070, 8538, 30048, 11833, 24733, 32663, 22890, 23580, 17978,
+ 2351, 29841, 11550, 3342, 9061, 1305, 23622, 25237, 27155, 2693,
+ 12762, 22926, 8781, 32174, 11042, 686, 16449, 20243, 20335, 32149,
+ 1121, 8048, 22108, 5633, 29637, 26258, 852, 16706, 12234, 31849,
+ 23124, 4078, 28928, 14431, 4594, 26581, 10563, 6888, 26271, 6711,
+ 4391, 13658, 13097, 10805, 9370, 17408, 29316, 22406, 21188, 11881,
+ 3785, 16747, 25906, 25094, 8575, 13797, 25140, 15093, 2330, 293,
+ 28291, 28439, 30657, 20804, 29223, 12136, 24404, 564, 1176, 29584,
+ 24238, 26103, 25636, 9141, 5159, 23822, 31888, 5268, 31069, 21301,
+ 16642, 2512, 11317, 29773, 23839, 12937, 18716, 11674, 368, 21553,
+ 14995, 20270, 20234, 6043, 8682, 24997, 9838, 11349, 15691, 1043,
+ 23982, 13880, 28411, 26171, 8657, 14653, 18909, 13058, 1913, 30611,
+ 18232, 32547, 3779, 30190, 2489, 4131, 7791, 6689, 20924, 3976,
+ 14913, 6127, 1735, 32326, 30886, 8222, 31319, 31866, 31643, 1486,
+ 18400, 14682, 28875, 19977, 30223, 8044, 23799, 23963, 15698, 4343,
+ 13979, 14628, 6042, 18616, 5071, 2923, 32096, 13013, 28523, 26101,
+ 29670, 21015, 18798, 28631, 20671, 1363, 9889, 30408, 22161, 16681,
+ 13175, 5754, 3866, 4593, 3640, 27179, 1649, 31219, 31838, 31863,
+ 19342, 32726, 3904, 26992, 23053, 348, 31725, 26352, 20783, 7756,
+ 10843, 10030, 7202, 20399, 16321, 18832, 28546, 32574, 10305, 19904,
+ 16415, 13084, 25546, 15618, 5889, 8641, 6717, 32197, 26281, 16950,
+ 15054, 1399, 17818, 11400, 10926, 23710, 12824, 24183, 18151, 10533,
+ 17200, 14446, 15751, 13043, 27384, 18104, 512, 5827, 11800, 10992,
+ 24783, 6959, 29833, 14777, 30300, 23565, 22429, 8368, 3361, 16383,
+ 4416, 10399, 9999, 27718, 28797, 26612, 13869, 10967, 30532, 31089,
+ 18563, 30385, 1386, 2852, 11062, 8813, 13553, 22938, 18676, 19735,
+ 19338, 27472, 18322, 6460, 25944, 8298, 10484, 23108, 15607, 27303,
+ 29486, 11266, 13501, 16789, 9192, 10378, 1343, 9985, 29447, 12355,
+ 13591, 20402, 10378, 30781, 15845, 17495, 2481, 21188, 660, 3773,
+ 8549, 26165, 31455, 18245, 26580, 17936, 14355, 5782, 3420, 8783,
+ 10006, 32655, 27818, 246, 13224, 1407, 26659, 13804, 12521, 665,
+ 13954, 3337, 11035, 17058, 25283, 23152, 1706, 13805, 833, 25887,
+ 4201, 20617, 27675, 24516, 25375, 27065, 24795, 25554, 17986, 12196,
+ 2394, 8917, 27138, 846, 11742, 16899, 9354, 20679, 32390, 5139,
+ 5250, 14243, 27112, 9554, 19672, 6057, 18168, 19955, 28096, 21968,
+ 22060, 16038, 20217, 28007, 24029, 15213, 8018, 8595, 26097, 30891,
+ 7534, 25342, 22199, 20094, 19908, 15822, 32530, 13903, 20969, 25556,
+ 17882, 18088, 17682, 9990, 2687, 8517, 16853, 30768, 30959, 1901,
+ 29999, 15846, 21690, 2179, 25291, 6077, 32628, 32472, 16001, 25019,
+ 15964, 20163, 32542, 3083, 826, 7156, 3683, 6901, 15502, 26885,
+ 14928, 25358, 28902, 21842, 19362, 21932, 10640, 27915, 26010, 29085,
+ 28785, 16263, 4864, 11289, 25909, 12251, 9320, 26100, 11689, 13228,
+ 17332, 16664, 17764, 29761, 24794, 27187, 28845, 1500, 23527, 10925,
+ 22169, 10571, 4164, 22237, 1652, 19386, 9528, 27772, 27746, 14539,
+ 18351, 30042, 31046, 13033, 12602, 591, 483, 26073, 8278, 21109,
+ 6466, 26513, 9713, 31380, 27219, 15182, 27690, 8414, 21718, 2785,
+ 23129, 8413, 20860, 2633, 14927, 11177, 24906, 14727, 17119, 14430,
+ 3135, 30894, 11165, 22733, 13110, 8762, 11749, 18034, 14606, 8098,
+ 5919, 15271, 18183, 11313, 20546, 27926, 12399, 14865, 32407, 14196,
+ 14719, 11689, 8640, 21869, 17792, 25385, 21240, 12762, 12337, 12898,
+ 2460, 10810, 22125, 25820, 2283, 21856, 4617, 21026, 23306, 8809,
+ 11516, 5729, 32074, 25585, 4034, 5937, 8622, 7047, 12034, 19123,
+ 10664, 6493, 31854, 29916, 15908, 17476, 24298, 20240, 10439, 7640,
+ 30193, 19955, 21113, 22264, 11317, 31100, 2849, 2170, 23942, 2891,
+ 32431, 25628, 5109, 18236, 31584, 29117, 8249, 16956, 27965, 11469,
+ 4434, 2907, 13030, 5634, 20332, 27427, 12173, 3404, 24069, 11560,
+ 15941, 2060, 2386, 10209, 27261, 30593, 735, 30390, 4551, 29570,
+ 12663, 6746, 21215, 32115, 14403, 29531, 28136, 28530, 31029, 19192,
+ 31224, 27601, 5800, 24114, 5079, 24777, 14400, 7974, 27140, 29804,
+ 5912, 8345, 18937, 27868, 5404, 24533, 4784, 26811, 25523, 24756,
+ 12390, 31714, 32162, 20474, 1439, 1110, 30765, 8167, 25962, 19319,
+ 28542, 21261, 742, 18299, 4683, 26976, 31237, 4379, 4276, 9100,
+ 21904, 24972, 29290, 4235, 13932, 11441, 6166, 6518, 27, 11151,
+ 27641, 32667, 11909, 27393, 1487, 209, 14585, 12973, 17914, 5640,
+ 9839, 22582, 11228, 36, 14096, 21172, 27525, 5900, 18168, 8801,
+ 1678, 3837, 20026, 24724, 27716, 10277, 8740, 3060, 25866, 31853,
+ 23493, 25829, 19704, 24470, 1965, 28231, 25032, 1415, 756, 26208,
+ 10227, 25317, 10622, 19478, 11031, 31717, 14716, 17506, 7580, 5470,
+ 4150, 29697, 7063, 31779, 9225, 8557, 5358, 22159, 24491, 13067,
+ 8894, 13409, 17079, 23974, 19449, 20682, 27493, 5916, 32084, 15045,
+ 28056, 8535, 14432, 22439, 6943, 16767, 15862, 29687, 8500, 30574,
+ 14297, 22143, 8009, 18789, 9623, 2467, 6917, 30717, 4272, 20210,
+ 30089, 11872, 19450, 28923, 17911, 696, 16964, 26466, 15669, 23272,
+ 6202, 307, 30446, 2427, 9609, 2421, 23514, 14041, 2371, 6659,
+ 31040, 27329, 23940, 4247, 29113, 18931, 20054, 23080, 27446, 23597,
+ 6098, 2166, 7748, 28249, 12168, 26083, 27279, 25861, 7457, 31620,
+ 5285, 4883, 17987, 15736, 4349, 26802, 12725, 20856, 56, 3725,
+ 1476, 9136, 16550, 16706, 17893, 15821, 14604, 277, 5019, 5208,
+ 16549, 27110, 30363, 15938, 18534, 18272, 28719, 19136, 10630, 14708,
+ 24024, 10585, 15678, 32005, 28471, 22588, 8654, 11493, 13101, 19672,
+ 20672, 3841, 66, 19111, 27248, 16856, 15427, 7242, 23244, 24114,
+ 18223, 25307, 15193, 24846, 3413, 28543, 5751, 29148, 1206, 23354,
+ 28645, 22764, 6576, 20744, 13959, 14887, 20190, 15913, 871, 26621,
+ 5178, 23740, 18939, 25246, 6532, 19599, 23974, 22381, 8168, 11830,
+ 28800, 13489, 3803, 29786, 28506, 9614, 20550, 24404, 24317, 2613,
+ 14310, 22266, 7859, 16471, 31218, 5817, 13321, 20447, 29951, 24549,
+ 978, 20448, 21282, 9804, 7279, 6092, 18004, 27409, 30030, 4328,
+ 25626, 14776, 18353, 15356, 25701, 31613, 25777, 16207, 18358, 5354,
+ 11394, 4306, 10375, 424, 2808, 4252, 15335, 25238, 7498, 10134,
+ 17764, 12824, 25879, 15992, 557, 4786, 11430, 8436, 20344, 27605,
+ 114, 8496, 4130, 18680, 25062, 3962, 5525, 12011, 5989, 23096,
+ 4079, 23400, 15757, 27165, 18785, 8940, 32189, 3747, 12500, 24772,
+ 3540, 3765, 30675, 11627, 23868, 12715, 18341, 20243, 4904, 21628,
+ 20921, 6274, 16921, 24367, 16200, 10783, 29863, 11923, 17461, 18765,
+ 30590, 17968, 22840, 16887, 1191, 24189, 24891, 1644, 13321, 9044,
+ 15876, 366, 21807, 13986, 6165, 20101, 5707, 19299, 24016, 19610,
+ 7291, 27854, 15839, 16064, 29004, 17868, 8403, 28501, 27005, 31919,
+ 26123, 2378, 26885, 30497, 26584, 7103, 10326, 6746, 2782, 31699,
+ 24292, 23447, 23742, 30906, 30433, 13511, 1522, 5648, 11851, 20871,
+ 4856, 16492, 18729, 2128, 22706, 12345, 14610, 29679, 30733, 28353,
+ 24046, 16694, 17633, 12683, 17409, 1266, 5144, 32743, 805, 11805,
+ 13587, 22215, 9046, 26708, 6729, 16080, 10868, 651, 30001, 2225,
+ 14149, 11775, 18787, 9140, 19898, 10604, 15098, 17042, 14451, 11392,
+ 7228, 17036, 9092, 10128, 32381, 2231, 21626, 11147, 19008, 18840,
+ 9113, 3628, 8864, 28400, 6760, 7795, 6126, 4057, 23408, 32085,
+ 28060, 12050, 14144, 28339, 30553, 13208, 4788, 13961, 20862, 20342,
+ 631, 22120, 30889, 18653, 16327, 16166, 1191, 22903, 23160, 19156,
+ 2712, 6137, 19516, 4848, 27213, 8184, 20769, 30428, 2805, 27645,
+ 10587, 26255, 19193, 5595, 10308, 17803, 10020, 28992, 13473, 31246,
+ 23815, 13451, 7719, 31885, 3228, 9181, 27710, 31582, 7465, 29299,
+ 2564, 26293, 26983, 20019, 29589, 30929, 30436, 18820, 18570, 3703,
+ 15526, 5987, 26559, 25504, 15633, 19892, 30810, 2159, 30475, 8661,
+ 1032, 8805, 29277, 21369, 1674, 19928, 27484, 14772, 5745, 13217,
+ 25034, 9810, 2853, 10006, 3831, 4973, 17452, 24632, 1835, 20287,
+ 30121, 9773, 2632, 6708, 7715, 32240, 18348, 27459, 2440, 12615,
+ 6485, 20095, 1394, 16885, 31304, 4585, 10920, 7473, 15411, 13449,
+ 24552, 9048, 16465, 19389, 31204, 22495, 14222, 21200, 7306, 19851,
+ 11756, 6350, 16776, 8932, 25893, 16535, 2064, 8935, 17042, 1843,
+ 12760, 24059, 21579, 17509, 29030, 20262, 12688, 22915, 28042, 24961,
+ 14951, 644, 7724, 27113, 31367, 15707, 26183, 26872, 13173, 15236,
+ 3894, 10547, 20973, 4572, 2351, 3461, 21123, 6837, 5389, 9197,
+ 22922, 15914, 15186, 20595, 565, 5296, 13420, 9312, 10492, 6126,
+ 9783, 13742, 13633, 21967, 23236, 2750, 9780, 22997, 21593, 28233,
+ 26356, 16560, 25272, 16281, 11767, 10767, 7588, 4857, 27563, 31926,
+ 26786, 13930, 3165, 12496, 25597, 28311, 4443, 5255, 28428, 11,
+ 17749, 16083, 8119, 22690, 4105, 9359, 21304, 27965, 11552, 978,
+ 15391, 8122, 19026, 6524, 4505, 16676, 20689, 21775, 17393, 1062,
+ 24037, 32449, 23127, 29638, 11987, 975, 24033, 16976, 1028, 23827,
+ 30159, 1167, 16227, 17369, 6419, 11587, 16903, 10479, 30993, 23760,
+ 19730, 8699, 2467, 22836, 27097, 16657, 19040, 16955, 7493, 2693,
+ 13598, 22006, 27257, 31998, 30133, 22889, 26804, 24524, 20230, 31108,
+ 28793, 19324, 20796, 14421, 9198, 8361, 17746, 14971, 22147, 24853,
+ 29142, 2270, 6099, 7928, 7404, 6813, 26063, 30359, 28565, 15176,
+ 18969, 17945, 7729, 8528, 26286, 6038, 31299, 18619, 13768, 29042,
+ 20853, 26140, 259, 233, 15836, 1475, 21438, 21226, 19324, 11057,
+ 27844, 3881, 5903, 1231, 29484, 26992, 18946, 2015, 29309, 15669,
+ 6081, 2226, 25110, 1906, 8244, 8987, 15309, 12977, 23433, 1829,
+ 26071, 26982, 29493, 32257, 29672, 25218, 11317, 15170, 922, 23621,
+ 18074, 20045, 14355, 14676, 30276, 18442, 6370, 29707, 22766, 26848,
+ 22571, 23572, 3435, 27361, 17412, 21049, 20526, 15425, 26398, 30326,
+ 16656, 15885, 7336, 31827, 13902, 23321, 7024, 6513, 16593, 2875,
+ 15436, 16994, 17843, 5814, 32696, 10685, 20734, 11769, 5824, 13682,
+ 1463, 10634, 29473, 24156, 20251, 1597, 8875, 11797, 14120, 29097,
+ 31209, 20238, 1631, 31452, 20996, 25311, 4297, 15182, 24037, 4827,
+ 21560, 3092, 23194, 3816, 19407, 6998, 7931, 28302, 7364, 30211,
+ 20109, 10317, 101, 22979, 13222, 4916, 3929, 25390, 1234, 9903,
+ 21033, 27707, 6518, 27809, 15103, 12027, 20915, 22962, 27821, 135,
+ 13709, 32747, 29424, 14391, 3917, 20352, 20470, 5908, 1315, 23020,
+ 799, 17296, 30224, 19267, 27905, 11637, 7683, 3524, 13486, 28188,
+ 17731, 19374, 4665, 30943, 32524, 17238, 8822, 12240, 15229, 8565,
+ 10242, 12460, 12466, 21958, 23939, 28170, 24365, 5585, 15665, 26840,
+ 13690, 513, 24982, 7688, 5906, 8445, 25489, 31879, 19073, 9525,
+ 22945, 30575, 4804, 12475, 23648, 2173, 30709, 2901, 13390, 14021,
+ 810, 32464, 5328, 30116, 29082, 19863, 2169, 28663, 8961, 30596,
+ 29319, 5002, 18246, 16629, 18865, 28884, 3931, 12323, 28704, 17121,
+ 25958, 29871, 19643, 13199, 28702, 28030, 2471, 12285, 25975, 16583,
+ 7182, 24897, 28801, 14954, 31008, 7513, 11917, 25732, 7256, 25700,
+ 1939, 3648, 17153, 15891, 26064, 13552, 248, 2906, 4275, 860,
+ 4787, 8299, 12026, 23385, 4226, 15076, 13337, 7582, 26389, 10311,
+ 15579, 9172, 14655, 12460, 8011, 8428, 3833, 6578, 12757, 23477,
+ 30122, 21947, 3497, 30638, 30118, 13145, 20576, 16409, 244, 8451,
+ 8418, 10576, 16212, 22797, 31623, 31836, 23424, 2519, 2428, 24772,
+ 13747, 20036, 1897, 14499, 8040, 2669, 32592, 765, 1124, 151,
+ 22969, 14419, 9462, 12899, 2572, 21877, 17790, 25157, 23102, 2200,
+ 30508, 18743, 6575, 13480, 24074, 21679, 13139, 16096, 6205, 206,
+ 28433, 23191, 10888, 8922, 25192, 18269, 5649, 14318, 21592, 13638,
+ 31592, 3056, 6272, 17286, 28357, 19652, 9604, 19774, 24977, 23999,
+ 27313, 30870, 17704, 32607, 10468, 15372, 19166, 7993, 21159, 19980,
+ 25920, 25650, 14238, 12992, 28316, 19186, 32546, 23593, 6339, 26262,
+ 13867, 4207, 2573, 6565, 29811, 2677, 19358, 23366, 23768, 2225,
+ 27880, 23728, 32002, 15931, 113, 8929, 20551, 23075, 21974, 26771,
+ 27083, 6408, 5393, 23660, 2540, 5350, 7927, 3957, 8925, 18224,
+ 22276, 10189, 4240, 28959, 14939, 11167, 2010, 24137, 26633, 30801,
+ 210, 13685, 32394, 14846, 8314, 19374, 29326, 30503, 26017, 11670,
+ 17149, 1189, 7431, 21245, 11832, 30178, 24771, 12466, 19618, 23881,
+ 9954, 7321, 13407, 28923, 9041, 14334, 2651, 26564, 253, 21545,
+ 9358, 8781, 13880, 1331, 8575, 29843, 30815, 22296, 6407, 9111,
+ 4793, 22796, 19032, 27480, 9379, 29459, 27453, 8446, 2794, 14796,
+ 31908, 17752, 30841, 13453, 18521, 7048, 564, 18869, 27668, 6141,
+ 8739, 17726, 5558, 15266, 30163, 11666, 21712, 12117, 15353, 23200,
+ 9573, 13211, 21849, 814, 6129, 14482, 19686, 13425, 15017, 12839,
+ 11051, 26587, 10245, 31880, 6377, 11060, 24188, 25821, 5378, 3820,
+ 17806, 10803, 16789, 20144, 1032, 2744, 3179, 26683, 2948, 12590,
+ 13970, 5231, 32047, 5786, 32583, 22180, 19407, 11324, 30234, 5696,
+ 16132, 25028, 14412, 30343, 15309, 23491, 7548, 24757, 30287, 28256,
+ 6018, 29770, 28882, 12364, 18844, 20902, 27661, 14840, 6856, 29397,
+ 11427, 25861, 18288, 1708, 14829, 8188, 13900, 533, 31226, 10815,
+ 5253, 23463, 20180, 19519, 32022, 9594, 6405, 24560, 12152, 31033,
+ 17242, 15738, 6526, 27256, 15335, 24626, 14462, 29512, 32331, 22472,
+ 5553, 3849, 4918, 22977, 25052, 30592, 10536, 1832, 29744, 14378,
+ 10875, 14977, 12399, 3023, 29859, 29183, 6225, 14425, 5301, 10743,
+ 3110, 23783, 11558, 15251, 32444, 26142, 26837, 5067, 8323, 7359,
+ 8012, 22161, 17903, 639, 3651, 16972, 3358, 28947, 19558, 26504,
+ 1723, 12170, 22873, 2284, 26146, 29151, 28408, 14188, 31941, 30415,
+ 30691, 32448, 1230, 14312, 20282, 13844, 32518, 24547, 11685, 18689,
+ 10229, 31539, 26520, 3260, 18507, 5854, 24789, 30093, 25726, 16780,
+ 22834, 16515, 4021, 8925, 30364, 25959, 26085, 7424, 12380, 25838,
+ 28985, 11394, 32665, 18226, 32440, 31331, 31006, 24163, 9762, 21615,
+ 13406, 8634, 2330, 32715, 9141, 13487, 3466, 6607, 16881, 28268,
+ 5956, 31507, 14609, 30081, 1253, 20685, 26189, 17369, 29695, 24666,
+ 24406, 9965, 4215, 10522, 23774, 4151, 29483, 22657, 11867, 18922,
+ 21464, 17515, 6920, 25568, 4668, 24496, 21549, 27860, 23159, 23801,
+ 23713, 19409, 26807, 29650, 2445, 19946, 12308, 31744, 114, 15404,
+ 26809, 21268, 22126, 3537, 18757, 16448, 13499, 2742, 28529, 19050,
+ 9848, 29200, 15346, 13439, 29612, 31066, 9633, 5130, 11656, 14226,
+ 18393, 13829, 20460, 20644, 12320, 17902, 7213, 29991, 12042, 27422,
+ 4374, 2631, 12379, 20567, 9260, 3586, 24172, 18844, 8246, 2968,
+ 5328, 3141, 19709, 13372, 26166, 11602, 17489, 28688, 14737, 23040,
+ 6220, 31568, 17015, 32410, 11995, 25549, 22727, 20370, 30329, 31390,
+ 29583, 26832, 22590, 3602, 19245, 30538, 2841, 32745, 26292, 8405,
+ 11354, 3011, 6289, 7738, 16755, 20952, 11886, 15245, 1791, 31210,
+ 22614, 12986, 12547, 632, 2842, 5217, 116, 4149, 25076, 13028,
+ 20986, 20920, 17259, 17342, 2548, 19317, 19830, 11030, 444, 8172,
+ 19684, 9619, 23084, 10272, 17403, 17523, 22369, 28747, 17504, 28631,
+ 10686, 27856, 8247, 25441, 18484, 31601, 13962, 22785, 16321, 1218,
+ 24303, 22028, 7223, 20957, 14437, 20111, 20031, 27224, 24448, 4834,
+ 12957, 3700, 20422, 15232, 7862, 8599, 29784, 1813, 5711, 6397,
+ 11221, 24281, 3735, 17066, 17275, 29981, 25192, 30883, 11663, 12835,
+ 23498, 5213, 30463, 25395, 30393, 13942, 16455, 24555, 16680, 13987,
+ 15761, 6615, 31813, 20458, 544, 19010, 25343, 23825, 6894, 12875,
+ 14789, 14678, 15508, 8507, 2961, 6496, 2155, 13589, 14374, 28790,
+ 11505, 2415, 14230, 13807, 25966, 18561, 14086, 7913, 7383, 21116,
+ 29365, 8254, 14322, 28445, 28987, 19636, 19131, 15745, 1039, 25460,
+ 15623, 22075, 12620, 8894, 8807, 21412, 27317, 13018, 18767, 13426,
+ 13814, 15698, 17783, 19596, 10797, 1118, 31106, 14365, 26280, 3744,
+ 25566, 1255, 26352, 15121, 13035, 1499, 22535, 20796, 25695, 1254,
+ 21231, 25002, 29673, 18189, 8299, 2717, 23828, 5820, 27146, 29953,
+ 29807, 18523, 31840, 7583, 23531, 27939, 32407, 16020, 5764, 10288,
+ 17191, 27905, 32547, 22999, 5601, 16133, 9923, 5433, 11058, 3560,
+ 24019, 5144, 5286, 10393, 27868, 7402, 24235, 2651, 16484, 3884,
+ 15256, 27067, 3090, 2553, 24557, 13253, 10515, 24795, 29660, 18295,
+ 13243, 21217, 15881, 1398, 11376, 14322, 27535, 2048, 8132, 6240,
+ 6467, 5922, 6625, 25280, 572, 11563, 26922, 13306, 30611, 8032,
+ 29727, 26012, 1383, 16113, 9857, 22132, 26916, 1580, 14775, 8541,
+ 15621, 9713, 23665, 13913, 31960, 1894, 32139, 2528, 18434, 5611,
+ 15924, 20088, 1218, 25937, 20303, 27782, 18618, 2118, 15897, 11364,
+ 10923, 11028, 29709, 18099, 24960, 18060, 28165, 20211, 21646, 32572,
+ 28321, 11345, 282, 1257, 12268, 5311, 22811, 1593, 22589, 15946,
+ 32578, 3247, 13916, 15016, 1080, 21724, 2278, 12561, 2343, 30420,
+ 21747, 27217, 27515, 29408, 4085, 25370, 24042, 30322, 8420, 22686,
+ 4785, 27998, 31896, 861, 23329, 13126, 24950, 29756, 24667, 31062,
+ 30286, 18392, 22872, 13362, 20612, 9241, 25132, 9773, 9582, 13322,
+ 22667, 22972, 11006, 5608, 24972, 8234, 27553, 28537, 31917, 26765,
+ 4454, 7326, 18455, 760, 27747, 11308, 23076, 9202, 14421, 7928,
+ 21535, 15399, 25990, 7473, 4683, 30814, 26868, 5619, 7462, 32171,
+ 22447, 32024, 16366, 13798, 20867, 6994, 26725, 16475, 32471, 9335,
+ 13266, 23235, 9685, 2075, 19784, 22132, 6859, 12388, 298, 28116,
+ 4049, 8986, 10735, 3603, 1965, 14590, 23075, 26906, 28659, 24413,
+ 26542, 25534, 9841, 6116, 15449, 13370, 28105, 10934, 3982, 17628,
+ 5472, 16060, 27999, 12030, 22647, 19516, 11979, 25144, 14488, 7598,
+ 18236, 19412, 22324, 21195, 2899, 4738, 4746, 6630, 21736, 14925,
+ 27082, 4991, 10317, 17614, 27771, 5142, 16083, 8608, 14618, 14397,
+ 6800, 788, 20228, 32497, 1887, 27429, 14230, 24106, 11559, 1198,
+ 19090, 1457, 5985, 7386, 4548, 17458, 21972, 20700, 4070, 17042,
+ 6819, 17377, 28354, 2434, 31114, 28995, 22678, 1365, 11365, 28416,
+ 188, 31758, 242, 13418, 8074, 10686, 21463, 14624, 25976, 30477,
+ 15591, 60, 10624, 32278, 20641, 25550, 22219, 20856, 6905, 13450,
+ 23945, 14761, 14172, 445, 11041, 23694, 10734, 7558, 28042, 841,
+ 24086, 12610, 9720, 29267, 28220, 30280, 20156, 1994, 6353, 26327,
+ 6245, 5132, 1680, 31564, 556, 8324, 17924, 18328, 20879, 6340,
+ 8267, 3314, 11579, 2516, 11033, 5065, 24367, 27594, 15360, 25085,
+ 543, 10651, 8430, 8526, 7702, 23345, 16887, 18965, 30816, 26046,
+ 4180, 26162, 6823, 30287, 26284, 69, 21852, 2724, 16019, 4897,
+ 16729, 31807, 24401, 3453, 1220, 16827, 27108, 15853, 24374, 23135,
+ 26184, 15121, 16668, 6131, 13813, 7180, 29278, 15058, 4010, 5432,
+ 3135, 5185, 26729, 19737, 19077, 8959, 28098, 32143, 30681, 24094,
+ 30037, 13647, 31088, 8720, 1427, 19859, 15851, 29701, 23492, 26641,
+ 4988, 3957, 4942, 2346, 10571, 29176, 21044, 8805, 16408, 22878,
+ 7901, 8475, 20001, 26620, 17175, 21876, 6726, 25412, 24667, 17810,
+ 4715, 16537, 6483, 16651, 24862, 29793, 29849, 18589, 1657, 14171,
+ 23746, 7709, 30794, 13874, 24987, 4273, 3442, 24403, 7858, 22847,
+ 14475, 17148, 27416, 6949, 21966, 14742, 13926, 23851, 4147, 17477,
+ 14078, 3765, 8665, 23485, 19859, 27966, 29609, 8535, 16876, 24065,
+ 24631, 9828, 15588, 4089, 7656, 15809, 9142, 31244, 5210, 2988,
+ 14455, 2436, 8448, 18389, 9188, 5310, 3853, 26040, 19550, 26150,
+ 18068, 5931, 7731, 29539, 30445, 23859, 10527, 5326, 16474, 6940,
+ 14099, 20777, 8426, 24521, 16436, 4494, 10398, 22856, 24615, 20901,
+ 14539, 9897, 12428, 8218, 21183, 31761, 11464, 846, 14759, 19722,
+ 776, 5709, 27569, 28957, 30339, 29185, 13933, 30371, 14079, 13989,
+ 27257, 6104, 20886, 18811, 29277, 1585, 7866, 6850, 20660, 32752,
+ 20855, 2019, 18829, 25589, 3064, 11755, 15120, 14295, 7501, 16445,
+ 26981, 21555, 19563, 14217, 16849, 11076, 21620, 27896, 22818, 23988,
+ 30265, 30121, 10574, 4530, 17150, 21089, 21079, 16453, 1149, 18302,
+ 25201, 27872, 26157, 28973, 26983, 31542, 17347, 26589, 23355, 5967,
+ 16633, 2292, 1549, 25564, 3727, 14272, 7997, 25288, 144, 10928,
+ 11220, 19471, 22999, 6340, 18464, 18131, 28881, 23362, 4767, 14509,
+ 4485, 22443, 15903, 8001, 16593, 17901, 3874, 10261, 17654, 9946,
+ 18567, 31395, 5975, 32473, 19303, 26796, 9085, 10459, 28222, 30928,
+ 30559, 21905, 20299, 32604, 18656, 2781, 9785, 14691, 29850, 14214,
+ 22782, 7696, 23002, 12079, 22532, 23098, 14315, 8842, 1414, 10809,
+ 28824, 26569, 11326, 1528, 21484, 10069, 18749, 21324, 22844, 16579,
+ 11546, 4740, 26984, 31748, 14414, 14658, 7773, 23259, 14047, 12169,
+ 7134, 7828, 7996, 8982, 25989, 22004, 14440, 9460, 22020, 1900,
+ 27483, 17739, 7089, 19345, 17318, 8569, 24130, 27601, 25429, 6243,
+ 29140, 22878, 28185, 6413, 15155, 4207, 12199, 16233, 10581, 15272,
+ 347, 13165, 26663, 11222, 13089, 32360, 12429, 30688, 31637, 19094,
+ 22947, 22779, 13161, 16626, 3914, 5916, 24583, 31051, 20960, 6579,
+ 20856, 12442, 9038, 28822, 22405, 14739, 1352, 26939, 21020, 23418,
+ 11472, 1067, 8437, 4920, 3836, 24243, 13940, 27310, 11002, 25821,
+ 20946, 23113, 13649, 24479, 9336, 26839, 2153, 13137, 26283, 32153,
+ 32334, 25188, 8046, 6297, 6065, 10322, 9124, 25917, 5168, 16593,
+ 4214, 23325, 24535, 12108, 17652, 24850, 31206, 6803, 7935, 9871,
+ 14548, 4306, 32614, 10037, 3989, 18368, 22863, 3233, 14361, 11544,
+ 20697, 25225, 26389, 23373, 11519, 20743, 27909, 18042, 8384, 20788,
+ 26738, 13719, 12156, 4089, 28016, 23539, 12450, 29474, 18028, 9950,
+ 13960, 29876, 12836, 5030, 23706, 18561, 17143, 8646, 16567, 32761,
+ 17247, 13657, 11224, 8259, 17340, 32213, 11763, 24205, 13651, 13557,
+ 12575, 30368, 13974, 18935, 18424, 20407, 29862, 19720, 15173, 25489,
+ 17942, 12029, 6872, 7109, 25330, 10563, 21942, 6486, 24063, 25113,
+ 7544, 6791, 17221, 8444, 6385, 29424, 32715, 10083, 10769, 18898,
+ 30370, 429, 19209, 4776, 26404, 25688, 18096, 29694, 2174, 26995,
+ 20518, 4230, 32364, 16982, 15799, 26217, 2884, 12688, 27394, 14555,
+ 9014, 24865, 1626, 14322, 17618, 26858, 19820, 23224, 15050, 6497,
+ 32034, 8063, 11002, 24201, 30920, 9844, 5797, 20258, 27758, 23159,
+ 12290, 15388, 28301, 7210, 10487, 21586, 25837, 9032, 24356, 12405,
+ 12485, 2617, 2339, 23366, 26149, 14307, 18702, 10761, 4753, 7106,
+ 18498, 31030, 22254, 28731, 16483, 8561, 22691, 30509, 5537, 14524,
+ 19960, 25802, 26169, 29676, 10689, 27813, 13118, 15449, 10817, 9483,
+ 1689, 19930, 20297, 13463, 14927, 28913, 31648, 32257, 17666, 9538,
+ 17831, 15927, 12219, 20554, 15165, 20655, 6374, 17485, 7393, 3579,
+ 26782, 13200, 21526, 30878, 6699, 25545, 10508, 11294, 16073, 13780,
+ 31612, 16986, 7595, 21927, 724, 8990, 5440, 9864, 22932, 29173,
+ 8629, 16254, 22520, 3646, 11451, 3077, 471, 22914, 2698, 25861,
+ 3019, 14341, 18470, 13829, 15250, 32667, 12001, 668, 10164, 18621,
+ 8481, 24617, 6758, 21980, 13411, 14276, 7087, 1269, 11392, 25717,
+ 26313, 32614, 15407, 419, 20170, 7168, 11980, 32207, 22148, 10077,
+ 24408, 17794, 32681, 1652, 8384, 6787, 5427, 26474, 31586, 27470,
+ 29954, 29868, 25549, 16066, 7367, 15930, 20168, 2074, 32290, 19782,
+ 18071, 30494, 24071, 5629, 25977, 6298, 17254, 15269, 22901, 23312,
+ 14603, 23272, 21846, 19370, 26307, 20079, 4853, 8050, 17856, 8627,
+ 19126, 23749, 29758, 9744, 17493, 14597, 27751, 24092, 25827, 32399,
+ 8820, 13110, 24075, 3821, 19990, 10594, 25242, 21836, 25364, 1364,
+ 1087, 15664, 32053, 6346, 7822, 358, 17248, 10527, 29515, 26427,
+ 1538, 9245, 23526, 14827, 7344, 5908, 13378, 6748, 18190, 7208,
+ 25274, 30476, 5359, 12783, 8550, 16456, 6589, 12604, 27802, 11424,
+ 28444, 21813, 15024, 8599, 19146, 2476, 24840, 5279, 11209, 29612,
+ 19020, 30788, 25281, 26705, 25081, 2471, 31136, 17885, 22811, 4654,
+ 16003, 25353, 10328, 29050, 30169, 2201, 29487, 921, 30661, 10547,
+ 12418, 14205, 15557, 19313, 15442, 27053, 7570, 23093, 14027, 22331,
+ 19015, 20285, 21632, 15606, 15556, 27639, 1015, 30432, 10837, 29846,
+ 3176, 13283, 14479, 8549, 2498, 4543, 31099, 14939, 27119, 13639,
+ 29431, 4336, 20313, 13005, 13656, 19504, 31917, 23259, 17748, 15118,
+ 11743, 16164, 23840, 8442, 622, 953, 18645, 12470, 23785, 20608,
+ 25112, 10597, 23474, 30435, 28410, 18917, 20226, 8133, 26653, 3678,
+ 20525, 5562, 27161, 27675, 24103, 32631, 22045, 32665, 9031, 7815,
+ 26074, 24798, 18508, 26176, 13980, 4620, 30878, 32502, 4026, 15414,
+ 31702, 2414, 26673, 11890, 2175, 13973, 28556, 21296, 13342, 1906,
+ 7687, 4042, 9329, 18778, 4083, 16988, 26101, 8803, 12380, 20949,
+ 2986, 16923, 30442, 1102, 31770, 2681, 15621, 3995, 3992, 17683,
+ 28220, 6176, 25542, 14482, 6120, 4582, 2138, 12899, 7180, 14319,
+ 26913, 22704, 2944, 3526, 6468, 22671, 27471, 8025, 25546, 17529,
+ 26973, 29451, 17758, 14077, 17485, 25094, 13138, 3509, 27297, 19150,
+ 21477, 20602, 5411, 21020, 3009, 6356, 24708, 9705, 1224, 3508,
+ 10820, 30409, 4624, 18278, 13521, 7034, 5420, 12225, 22259, 4797,
+ 18606, 12961, 14951, 22372, 5097, 21143, 28107, 15021, 19452, 30174,
+ 19898, 14542, 1548, 32657, 2359, 31697, 24272, 2332, 17743, 162,
+ 23379, 20465, 9210, 4711, 18165, 11132, 12867, 4111, 12979, 8024,
+ 424, 12334, 31145, 24003, 28868, 14088, 28373, 20047, 26411, 21227,
+ 6174, 27867, 2198, 4803, 6805, 5314, 9024, 10984, 15354, 3154,
+ 23951, 31802, 7554, 25728, 26359, 4464, 5079, 217, 12316, 1709,
+ 16481, 23484, 28214, 3924, 20420, 23239, 28090, 3614, 426, 18319,
+ 30775, 29546, 24002, 16532, 20861, 21972, 14857, 13940, 4101, 30984,
+ 30280, 18782, 21645, 14041, 4317, 6858, 9475, 32397, 30911, 26471,
+ 28324, 24187, 16573, 32085, 29541, 19417, 6150, 25237, 9874, 7375,
+ 11246, 16318, 15541, 26831, 22255, 25329, 29369, 17193, 16622, 28430,
+ 20559, 986, 21696, 2856, 27025, 4773, 12013, 9783, 25573, 26726,
+ 27060, 8973, 16933, 15010, 27215, 140, 15357, 1378, 4984, 21013,
+ 9364, 26434, 299, 7235, 9326, 965, 12718, 27098, 19089, 24555,
+ 16335, 11514, 14566, 27910, 4717, 16537, 28643, 13769, 9529, 7728,
+ 32103, 24994, 20158, 7091, 4837, 586, 10143, 17863, 18117, 24474,
+ 30496, 10800, 1287, 13728, 18664, 9864, 29482, 6386, 4102, 3895,
+ 19276, 30018, 31537, 17055, 29330, 23091, 24148, 31895, 20170, 2667,
+ 21834, 32283, 8015, 233, 997, 23873, 23853, 24729, 5942, 4463,
+ 26246, 550, 27656, 4044, 31029, 5136, 32430, 3060, 16560, 254,
+ 2047, 12528, 31539, 4181, 27550, 26213, 31259, 29961, 23423, 30219,
+ 400, 16052, 21670, 9569, 19302, 24805, 22834, 6048, 12613, 17594,
+ 2971, 3053, 16904, 6321, 3896, 19410, 18020, 21179, 20996, 24047,
+ 30922, 6290, 9121, 20717, 29838, 589, 15773, 12980, 8264, 27442,
+ 8437, 2014, 6011, 17611, 27863, 22379, 22388, 8252, 4780, 7862,
+ 13173, 25043, 2902, 16807, 21523, 21217, 29110, 19243, 17885, 1480,
+ 9842, 4577, 23358, 16470, 24821, 5399, 26021, 24657, 20919, 9716,
+ 2530, 28243, 14782, 12534, 13268, 21208, 7013, 15264, 27969, 24982,
+ 26716, 27244, 7173, 12045, 20720, 8967, 27503, 25694, 6284, 7869,
+ 25832, 1376, 4992, 306, 31701, 23793, 12802, 18260, 4287, 906,
+ 15474, 8845, 12209, 13335, 9443, 5181, 3554, 25349, 4566, 23911,
+ 2708, 19356, 1608, 5803, 14140, 26511, 19184, 1140, 10979, 1233,
+ 31938, 31602, 9420, 28075, 25783, 26955, 16983, 22284, 31952, 21901,
+ 19493, 2336, 18009, 28392, 24189, 30243, 21867, 30874, 28911, 13176,
+ 13748, 11306, 311, 2293, 3194, 25433, 25956, 2690, 7134, 7766,
+ 2361, 28642, 2910, 14897, 6867, 7888, 6558, 27538, 27276, 6990,
+ 7016, 20907, 544, 21050, 27633, 13675, 14094, 29218, 12894, 18676,
+ 15425, 18009, 8326, 31568, 30448, 18506, 3834, 13407, 6851, 23309,
+ 6723, 3348, 20791, 25912, 9578, 22497, 28739, 15608, 26046, 3440,
+ 1084, 6752, 23505, 29076, 12534, 1024, 24004, 1151, 11820, 27066,
+ 5828, 5173, 25377, 25041, 8149, 577, 25992, 15427, 5582, 4518,
+ 24481, 24665, 20645, 20760, 8614, 10364, 8173, 30060, 25189, 12362,
+ 12445, 14414, 29486, 18665, 19, 3890, 27375, 1947, 89, 20109,
+ 3230, 8851, 20902, 3396, 27863, 4104, 13608, 23652, 6855, 7047,
+ 7424, 10005, 20552, 25997, 32143, 20169, 27981, 341, 17392, 22457,
+ 17025, 9455, 5573, 14738, 28459, 8082, 15927, 10347, 22101, 2611,
+ 27704, 27131, 28461, 26198, 9739, 2825, 29867, 7973, 5639, 2339,
+ 14452, 8383, 5272, 17555, 7423, 31186, 4998, 20111, 31478, 15212,
+ 20090, 26544, 30175, 2830, 25790, 17062, 1019, 6915, 16452, 24361,
+ 11630, 31983, 28138, 4402, 18081, 683, 19196, 2156, 10725, 8528,
+ 11258, 27621, 13401, 2706, 24732, 24074, 2573, 28752, 14612, 31954,
+ 25959, 9832, 28819, 12857, 30150, 5840, 8462, 26864, 4454, 15331,
+ 9282, 31059, 16004, 5368, 1526, 25243, 22466, 18745, 27520, 9301,
+ 20428, 27827, 5258, 19475, 22588, 7081, 22806, 2913, 28603, 24622,
+ 18624, 27130, 7017, 5619, 20291, 26684, 20352, 16477, 575, 9690,
+ 19252, 1754, 31802, 24785, 27613, 19318, 26852, 24733, 15191, 4009,
+ 9887, 8620, 15785, 7027, 8510, 21779, 16870, 6827, 18957, 2176,
+ 14929, 9365, 20754, 2671, 24516, 25010, 915, 24225, 9299, 17372,
+ 29657, 22218, 14636, 1170, 20019, 9099, 11201, 23952, 32573, 29087,
+ 24106, 12194, 3937, 26457, 24260, 3003, 22431, 5710, 25375, 21057,
+ 29578, 13647, 27159, 23724, 5267, 13978, 18752, 25935, 6794, 3664,
+ 10632, 8565, 5474, 15658, 14103, 16816, 5173, 29544, 2170, 19566,
+ 25991, 24587, 257, 1741, 11471, 68, 12901, 24497, 28980, 812,
+ 430, 4371, 2452, 5557, 4948, 27548, 2506, 10977, 17061, 114,
+ 5425, 5170, 10342, 7506, 14948, 32353, 29885, 20191, 15432, 9811,
+ 8271, 23865, 27725, 23112, 14501, 30418, 31216, 6998, 19412, 32125,
+ 23429, 29462, 14173, 10696, 13363, 20893, 24146, 30860, 23360, 1965,
+ 2746, 5826, 26766, 12589, 32311, 16280, 27238, 9175, 30182, 16581,
+ 10357, 13873, 9607, 6425, 6164, 29374, 28126, 25944, 26061, 2933,
+ 21080, 3912, 14362, 8562, 29170, 29449, 3951, 13548, 1879, 28325,
+ 26491, 20839, 13384, 4072, 32172, 18986, 7233, 21618, 24817, 6900,
+ 4698, 12298, 11971, 16619, 24171, 19765, 8550, 8149, 23923, 15367,
+ 21356, 18314, 315, 826, 23676, 11689, 29494, 18301, 11089, 12171,
+ 24236, 32014, 16645, 28789, 9751, 22411, 12688, 26642, 1998, 27654,
+ 3468, 13600, 30176, 14679, 6459, 2153, 9539, 2742, 29898, 15349,
+ 6190, 26761, 6615, 27262, 10179, 2938, 21042, 6948, 20721, 1485,
+ 3040, 21858, 18585, 5872, 11878, 12609, 6895, 23892, 21828, 14283,
+ 23076, 23164, 5055, 10179, 8258, 32084, 9699, 29331, 26711, 9923,
+ 13001, 1414, 725, 23683, 1046, 13111, 10553, 7729, 22212, 20810,
+ 29931, 4256, 10533, 24153, 15717, 29555, 10788, 17457, 8600, 5355,
+ 11727, 2623, 16523, 14333, 19218, 3141, 25926, 8360, 1733, 2385,
+ 10734, 14981, 12266, 7920, 22065, 3488, 20783, 1183, 31973, 30086,
+ 23483, 7042, 7403, 20127, 28454, 9817, 18778, 3518, 25289, 15791,
+ 7385, 30199, 29753, 21588, 31821, 24753, 16142, 24590, 27829, 19451,
+ 25065, 31372, 81, 8996, 29877, 3739, 7946, 30085, 13356, 26013,
+ 11790, 4002, 1693, 10550, 23227, 10866, 15853, 11592, 3262, 9466,
+ 15069, 5666, 17276, 31777, 21898, 12020, 25265, 29887, 12090, 1158,
+ 12886, 11255, 20821, 6186, 5577, 455, 15794, 16112, 15912, 4573,
+ 21524, 280, 23549, 11948, 12533, 3533, 5153, 4800, 27010, 5904,
+ 15322, 15438, 18662, 10738, 8263, 10000, 29387, 22278, 23806, 22607,
+ 3870, 16150, 1523, 28994, 25363, 22549, 10396, 15254, 31594, 32341,
+ 26706, 25678, 19440, 9722, 14843, 22733, 26696, 16559, 742, 31281,
+ 14827, 11159, 7926, 6883, 22382, 14726, 4611, 31340, 24836, 11634,
+ 26749, 13195, 1603, 14628, 2898, 20612, 6443, 21555, 2834, 31162,
+ 21092, 32563, 9810, 29312, 10951, 18218, 3918, 22573, 28192, 7491,
+ 13522, 22382, 27442, 22215, 4698, 19425, 25852, 26952, 19320, 32223,
+ 10555, 14112, 5750, 29337, 28720, 26, 14908, 614, 27043, 19054,
+ 9077, 10587, 6952, 22515, 21742, 17949, 29601, 31632, 14142, 15091,
+ 14340, 25331, 2988, 9503, 11615, 10374, 1613, 7791, 9241, 16799,
+ 21357, 15631, 18554, 7416, 3120, 17825, 23661, 1374, 24185, 17295,
+ 16005, 7341, 27659, 31648, 25151, 763, 9455, 27850, 7559, 32276,
+ 8469, 21320, 28541, 13607, 15678, 25068, 9336, 21694, 32536, 9653,
+ 31563, 12019, 1195, 18340, 12232, 11233, 757, 8396, 3715, 7770,
+ 6097, 21673, 30169, 20696, 29470, 26034, 26672, 24245, 6940, 30769,
+ 4991, 11678, 20505, 14163, 29202, 6981, 21326, 4219, 26759, 13142,
+ 5380, 14556, 1309, 429, 3579, 12615, 17454, 21702, 18443, 15425,
+ 32249, 1140, 23052, 31321, 24997, 4310, 23284, 8377, 8579, 11655,
+ 4159, 32250, 13460, 3350, 23444, 16701, 20811, 182, 11173, 14199,
+ 1427, 16438, 29783, 29452, 4116, 28211, 29219, 4512, 24242, 11404,
+ 15547, 5161, 22103, 21782, 27889, 32073, 18419, 10897, 22997, 10716,
+ 14017, 5595, 12574, 6093, 21451, 17252, 28364, 3885, 21168, 13538,
+ 30731, 24966, 31653, 6982, 23897, 13164, 7866, 3310, 2027, 1110,
+ 19551, 27676, 22093, 26796, 30502, 4519, 27722, 10785, 25290, 4080,
+ 14859, 16963, 1137, 8728, 32387, 25424, 14382, 7024, 18698, 844,
+ 28618, 27441, 15943, 7504, 16068, 2158, 9300, 7461, 26518, 23110,
+ 31261, 10514, 20026, 28766, 7689, 15857, 29677, 8079, 18397, 20872,
+ 24627, 22235, 23005, 28439, 6939, 16550, 19764, 558, 7364, 1058,
+ 15765, 17345, 22048, 15116, 22563, 32126, 14072, 28566, 12686, 5982,
+ 21808, 13988, 18303, 9083, 6477, 14906, 12599, 23585, 5172, 18485,
+ 17267, 18471, 25140, 14650, 11154, 31104, 16199, 17389, 17913, 6669,
+ 12437, 4195, 13239, 15029, 26426, 8153, 29541, 6328, 16457, 23718,
+ 336, 19776, 1553, 26222, 17115, 6970, 22175, 28313, 16670, 20323,
+ 21380, 14595, 30419, 26278, 32472, 5365, 13683, 28325, 27006, 25173,
+ 26012, 21654, 5802, 30489, 9910, 5712, 14497, 30977, 4566, 2469,
+ 10944, 32646, 9186, 11763, 19648, 4622, 4855, 15350, 9016, 22113,
+ 4871, 26592, 24931, 864, 19911, 2476, 16420, 27637, 4552, 8111,
+ 17991, 13894, 31971, 24432, 26122, 4910, 9691, 18617, 5084, 2541,
+ 2366, 28398, 14948, 11294, 15756, 27806, 12229, 17898, 12955, 13656,
+ 4129, 24188, 58, 14784, 8540, 7348, 2069, 4577, 9250, 25632,
+ 28377, 8645, 13867, 15912, 12440, 27715, 10685, 25480, 21614, 2073,
+ 30323, 31236, 869, 27451, 10046, 23126, 1686, 106, 27049, 29292,
+ 28817, 15111, 8801, 6096, 30207, 7466, 10996, 24168, 14726, 25583,
+ 7385, 18271, 3821, 19984, 19889, 23651, 31105, 12473, 24780, 2833,
+ 27063, 20119, 4591, 21677, 32274, 9523, 7508, 9751, 19271, 9342,
+ 26867, 27642, 28576, 1196, 21248, 14151, 30110, 11846, 18869, 1506,
+ 18914, 26747, 4177, 923, 18509, 16824, 21857, 22367, 9319, 26232,
+ 32318, 20655, 12541, 23132, 19415, 2386, 19215, 18302, 15536, 20295,
+ 27625, 22531, 20523, 27390, 9871, 19951, 3847, 5576, 5214, 19773,
+ 32038, 13451, 29937, 3120, 22675, 10938, 1346, 24036, 18883, 22916,
+ 21009, 19240, 26907, 8012, 2442, 11664, 15795, 27482, 4130, 197,
+ 6490, 14800, 23746, 24096, 30170, 3039, 24615, 22135, 14205, 12346,
+ 31625, 7735, 30927, 28619, 19066, 16307, 17318, 29350, 17426, 18364,
+ 23392, 28987, 30537, 8306, 31852, 1487, 26276, 3673, 13580, 12845,
+ 18196, 944, 15192, 28056, 9755, 15870, 25735, 20229, 15152, 25069,
+ 8554, 10119, 26725, 2395, 9273, 8459, 11847, 30639, 5010, 13637,
+ 5893, 26729, 28351, 4330, 23765, 11262, 1848, 14112, 20372, 1762,
+ 13160, 31027, 15788, 1766, 7860, 5769, 25659, 17092, 23226, 6360,
+ 10866, 14328, 5590, 16534, 11323, 15058, 6891, 5553, 22558, 11466,
+ 32352, 28801, 9317, 27923, 7272, 3835, 8062, 14195, 19591, 2599,
+ 24482, 25937, 28242, 16340, 5556, 17680, 13174, 1162, 18284, 31643,
+ 19195, 12736, 29876, 9281, 20938, 25679, 11346, 8900, 11373, 32551,
+ 21448, 23468, 11799, 17984, 9848, 18145, 12516, 9684, 12300, 4217,
+ 865, 31180, 17941, 15311, 20303, 27000, 17650, 31957, 23972, 11138,
+ 5108, 15275, 23507, 17957, 13504, 30320, 1613, 8090, 25076, 30040,
+ 23624, 29395, 269, 1278, 16575, 31852, 27528, 11004, 11450, 29663,
+ 21319, 2234, 22223, 9463, 17975, 24707, 29673, 15751, 5424, 28894,
+ 30024, 9051, 8732, 6683, 26569, 26223, 22876, 556, 22632, 9055,
+ 23143, 10934, 25091, 27167, 5044, 11624, 18529, 31980, 21979, 4748,
+ 17522, 31618, 8695, 30171, 26072, 20112, 14158, 28054, 11687, 26473,
+ 9268, 26578, 18025, 10236, 24108, 29204, 32102, 1798, 9553, 7965,
+ 24866, 17542, 14068, 32519, 10534, 17010, 4999, 23953, 19203, 21928,
+ 23481, 15032, 24725, 8999, 2275, 12679, 17285, 23935, 1187, 16687,
+ 529, 30342, 25542, 11354, 4368, 6477, 18540, 25277, 24368, 82,
+ 12134, 10476, 11651, 31735, 11491, 29299, 20794, 15667, 23628, 8738,
+ 17072, 14472, 1900, 9384, 7594, 13621, 18644, 6500, 30429, 23724,
+ 11646, 32119, 10928, 24134, 6576, 3358, 2372, 31542, 29987, 20287,
+ 945, 3772, 25189, 32577, 16019, 26267, 1404, 18721, 11718, 32716,
+ 7628, 3010, 7533, 31604, 30523, 5509, 19513, 24596, 30354, 3866,
+ 31464, 31487, 17702, 2198, 5387, 30226, 24505, 23749, 22285, 30111,
+ 3227, 24257, 5489, 21162, 32020, 1475, 2395, 17752, 7687, 2874,
+ 18002, 5028, 23503, 12058, 15684, 6228, 23917, 5751, 28874, 13867,
+ 31461, 30802, 16046, 2913, 29413, 3251, 25259, 31056, 9128, 29176,
+ 5747, 21616, 19226, 31852, 29431, 20613, 4669, 9243, 30434, 32023,
+ 26571, 1253, 22118, 26147, 28189, 9426, 30780, 11536, 75, 29861,
+ 17382, 11748, 4757, 16052, 9528, 1208, 29185, 30710, 26902, 1898,
+ 10054, 10078, 22399, 1937, 233, 22375, 11979, 28854, 2214, 17905,
+ 25648, 5825, 26641, 17995, 19851, 18609, 125, 2449, 6237, 31632,
+ 14877, 16696, 12820, 8614, 20073, 20455, 1421, 494, 4547, 31880,
+ 12758, 9158, 91, 23456, 7736, 8938, 4688, 25307, 3957, 32675,
+ 6936, 23276, 8782, 16188, 14369, 9107, 20296, 28854, 4792, 32255,
+ 23472, 27069, 31019, 20823, 23517, 20442, 4906, 7572, 10933, 16873,
+ 13683, 4241, 31347, 13774, 6319, 29029, 25255, 24164, 30614, 22000,
+ 3965, 11702, 22618, 22196, 30275, 18290, 1347, 13542, 13094, 30618,
+ 30870, 9925, 29756, 381, 16316, 15915, 5576, 23270, 6560, 7522,
+ 21433, 10131, 21593, 28216, 13427, 2280, 11785, 20310, 4306, 5605,
+ 15621, 11213, 23916, 3926, 9014, 12530, 6423, 9289, 4287, 22124,
+ 1196, 23237, 23007, 11403, 2058, 28857, 9241, 25820, 26717, 18739,
+ 28307, 18682, 13216, 14802, 31165, 5030, 1376, 19582, 21042, 24602,
+ 2243, 18774, 739, 9115, 23498, 7402, 12914, 25934, 14291, 28331,
+ 12252, 10316, 866, 31648, 12891, 15352, 12576, 2394, 20619, 26257,
+ 4132, 1321, 29387, 7683, 29042, 9104, 17638, 17155, 18113, 5111,
+ 27379, 4698, 7810, 7328, 32121, 16513, 8477, 13020, 4311, 29551,
+ 29566, 25471, 19427, 3759, 8912, 8081, 20946, 1461, 32136, 16710,
+ 856, 10354, 32166, 23856, 23311, 7718, 10295, 13236, 26909, 630,
+ 1567, 22203, 12818, 22718, 6677, 22441, 29967, 18856, 30703, 4499,
+ 7469, 24318, 24864, 25517, 25116, 12732, 2687, 28673, 23563, 15978,
+ 28490, 12903, 3784, 21416, 21866, 945, 12329, 20235, 26360, 23846,
+ 11690, 7207, 1281, 28722, 13655, 10733, 14214, 26203, 17901, 19000,
+ 24263, 23927, 2620, 12194, 2498, 29724, 975, 32156, 5622, 31321,
+ 18639, 7870, 31852, 6819, 22821, 21851, 28664, 3858, 20191, 14937,
+ 12477, 14030, 28117, 7743, 14575, 8132, 22156, 144, 9949, 22685,
+ 24666, 4440, 2094, 7920, 24267, 28932, 27242, 15798, 22084, 8822,
+ 21693, 12287, 25574, 25433, 3832, 23524, 23733, 24242, 23001, 31165,
+ 26618, 28088, 31884, 31636, 6374, 23270, 19313, 2265, 19319, 23374,
+ 3104, 25174, 18592, 12848, 23211, 16998, 30116, 13003, 29731, 3426,
+ 4803, 5235, 2653, 26205, 19736, 19684, 1269, 31761, 10178, 25814,
+ 21396, 8728, 66, 31442, 13679, 2656, 12836, 26691, 6672, 13017,
+ 7650, 15568, 32601, 23408, 5893, 1001, 28870, 6209, 32141, 2208,
+ 3058, 21512, 1683, 3003, 11869, 22233, 30765, 8199, 12396, 9490,
+ 23698, 8431, 20913, 19085, 28798, 30540, 14957, 26138, 20696, 8319,
+ 13907, 2348, 11155, 11198, 3215, 16338, 30674, 8619, 6407, 21737,
+ 31055, 2603, 2785, 9873, 4861, 1141, 27717, 7901, 11500, 9577,
+ 22372, 9423, 12653, 4132, 31929, 6531, 25976, 31953, 24206, 13738,
+ 8266, 8641, 26051, 23354, 9810, 12991, 13259, 12132, 11086, 27293,
+ 22007, 4295, 16306, 21267, 15863, 15843, 11593, 16074, 9118, 16336,
+ 1822, 10675, 13285, 27951, 28829, 29597, 12595, 6498, 24566, 10503,
+ 26843, 17400, 24514, 20018, 8678, 23659, 5097, 24699, 26900, 28174,
+ 1475, 488, 24093, 18497, 31613, 769, 26172, 30439, 24255, 16097,
+ 26606, 7962, 30347, 32140, 29688, 5149, 30825, 20611, 32679, 14481,
+ 13505, 7574, 5211, 32748, 25224, 19450, 6215, 9256, 19998, 18331,
+ 5234, 25528, 28535, 20147, 7169, 23488, 11130, 15772, 14521, 21125,
+ 17574, 19683, 192, 1571, 16123, 30109, 14755, 21374, 15128, 28670,
+ 11421, 18810, 3233, 39, 4119, 31855, 4067, 1344, 10859, 11735,
+ 699, 32455, 4589, 7242, 25779, 31783, 11820, 4013, 8815, 10893,
+ 24181, 30118, 4168, 29943, 27033, 8786, 30774, 27278, 6896, 2363,
+ 16115, 24373, 12446, 644, 25693, 31330, 32533, 28775, 25373, 10284,
+ 28124, 22754, 13190, 8358, 12686, 18348, 30143, 31084, 26405, 3182,
+ 1829, 30075, 29816, 10544, 1771, 1862, 20995, 1297, 3587, 14598,
+ 8679, 14140, 7746, 28497, 14385, 32279, 3263, 14830, 30815, 14014,
+ 27516, 9960, 11297, 26799, 13896, 19425, 14172, 14791, 18147, 31145,
+ 19828, 24173, 21604, 19983, 3019, 23053, 472, 6135, 7557, 9160,
+ 16428, 16813, 19599, 873, 1869, 13689, 9183, 15003, 10893, 28788,
+ 1789, 20058, 19529, 14233, 25282, 1192, 13512, 8991, 23391, 27265,
+ 4199, 29703, 7074, 30224, 22771, 26609, 10613, 6435, 28247, 32563,
+ 25512, 22493, 8823, 26924, 3312, 14250, 15451, 2774, 2095, 6776,
+ 13968, 21403, 10741, 23077, 15563, 21610, 17223, 14387, 11472, 19721,
+ 18848, 30147, 7826, 9133, 16438, 10177, 14236, 31432, 18046, 7004,
+ 19887, 22818, 28658, 24249, 7341, 6187, 18706, 16872, 5045, 3216,
+ 11689, 25623, 32144, 7436, 21585, 8453, 2124, 15233, 13113, 29370,
+ 28710, 29767, 8742, 7030, 20910, 1987, 23992, 11239, 26405, 16956,
+ 20463, 14750, 13610, 1515, 16877, 22980, 27286, 15185, 23294, 13321,
+ 30628, 7118, 4309, 16862, 8277, 2670, 27929, 3556, 3602, 28422,
+ 19488, 1956, 9363, 18304, 30970, 16256, 7681, 25459, 19121, 7913,
+ 12887, 32247, 9935, 28883, 19982, 10679, 3361, 20070, 7161, 17223,
+ 4283, 17399, 26222, 23992, 25148, 16950, 5030, 23914, 20307, 12201,
+ 16742, 13602, 23426, 11865, 17375, 31068, 22050, 27083, 3028, 15843,
+ 4520, 305, 14330, 29086, 8230, 25058, 21924, 11437, 14613, 9736,
+ 5279, 9397, 11345, 19352, 29275, 15223, 1637, 22408, 8268, 23464,
+ 18953, 14652, 10640, 6140, 25321, 577, 7122, 16517, 13736, 17981,
+ 14190, 25147, 28965, 14118, 27350, 25820, 1277, 20915, 7476, 15094,
+ 24913, 11792, 3153, 22593, 25545, 18646, 16821, 25139, 5592, 22586,
+ 25360, 20175, 8258, 389, 25048, 26046, 6108, 708, 20020, 22432,
+ 1939, 9408, 20761, 24484, 23472, 2352, 4530, 9046, 4699, 10542,
+ 2566, 17593, 21853, 6120, 3797, 23190, 24874, 23960, 3778, 17171,
+ 23838, 32438, 19640, 1159, 2311, 875, 6534, 12429, 25572, 4938,
+ 20684, 32088, 12268, 31035, 7451, 2374, 30674, 9143, 18264, 31927,
+ 31048, 30011, 5473, 32287, 6338, 30966, 31731, 11354, 17020, 20421,
+ 10188, 4928, 23742, 26978, 8716, 20090, 12127, 24025, 5089, 20116,
+ 25736, 31547, 28003, 29778, 1722, 23445, 29629, 30280, 8210, 5923,
+ 31374, 17573, 24268, 26306, 19599, 24400, 25351, 19108, 1909, 21046,
+ 6599, 2375, 28441, 19426, 18752, 6824, 31702, 590, 12882, 21428,
+ 10290, 23032, 27472, 26111, 16833, 825, 22533, 1976, 16711, 466,
+ 25337, 22493, 28189, 21192, 23536, 21163, 20694, 9331, 8116, 27225,
+ 14625, 21713, 27924, 6149, 23281, 10784, 2861, 30959, 18140, 31147,
+ 9448, 19429, 16833, 12516, 32196, 25342, 16302, 29875, 25558, 23947,
+ 1537, 19214, 782, 15947, 14541, 714, 32187, 12766, 22399, 19888,
+ 28241, 6524, 27841, 16596, 13930, 11751, 30110, 12066, 16140, 20126,
+ 17383, 4666, 3626, 20820, 24534, 30078, 21869, 26016, 11506, 5992,
+ 24116, 24822, 22066, 13602, 30425, 1750, 17765, 13392, 17718, 8515,
+ 10705, 7984, 8807, 32119, 21019, 9958, 25554, 8405, 23911, 8209,
+ 13669, 18975, 1983, 11682, 26911, 4841, 5561, 3566, 24530, 17742,
+ 9044, 15874, 28455, 14817, 23076, 26422, 26850, 20966, 21167, 19205,
+ 10087, 25027, 9494, 8475, 17277, 8113, 27896, 7088, 22355, 27319,
+ 17555, 1557, 29377, 32217, 31532, 12684, 9423, 25485, 2737, 9309,
+ 15995, 15726, 4254, 16166, 12983, 13364, 19997, 19571, 14258, 9188,
+ 29553, 11918, 3416, 22596, 14996, 8089, 3356, 28050, 5407, 14297,
+ 26357, 10613, 29035, 11861, 12198, 24628, 23286, 1952, 9283, 14886,
+ 31240, 9971, 18161, 28010, 13974, 30078, 14573, 16343, 614, 5120,
+ 30160, 25910, 3700, 19094, 21521, 3503, 28565, 10960, 28363, 14466,
+ 30298, 6154, 23744, 7928, 15927, 10746, 22687, 19352, 14308, 7557,
+ 16002, 12701, 13060, 18391, 699, 22696, 11013, 16306, 1488, 28851,
+ 23367, 12550, 27076, 25158, 24192, 3779, 19608, 12013, 23903, 5867,
+ 3090, 13801, 4207, 23787, 30397, 12582, 6463, 20011, 3633, 32365,
+ 30400, 25828, 16020, 2267, 6382, 32050, 12129, 26258, 22450, 106,
+ 4456, 32430, 20743, 23213, 3607, 19323, 29277, 28349, 15351, 3301,
+ 12602, 31760, 15481, 32559, 14119, 11043, 26355, 27112, 1226, 13329,
+ 9446, 6939, 20560, 21348, 25474, 8903, 8974, 299, 15980, 25230,
+ 31335, 7757, 18366, 17841, 28656, 3100, 4432, 13628, 11474, 25133,
+ 23350, 7294, 11376, 13928, 2953, 4540, 4682, 11099, 21355, 30503,
+ 5921, 14547, 9541, 10250, 20829, 25262, 24659, 1608, 23723, 20971,
+ 21859, 31750, 9450, 1027, 2265, 17829, 22600, 1148, 22007, 6131,
+ 17576, 25787, 22363, 30370, 9288, 26138, 14537, 20217, 7584, 2618,
+ 22059, 10953, 31373, 32155, 19414, 4003, 23214, 4201, 23567, 24136,
+ 25870, 12697, 19918, 18017, 15620, 8245, 10434, 8816, 15960, 18164,
+ 29332, 20487, 17575, 30222, 20848, 22584, 521, 28494, 14274, 31820,
+ 10480, 30825, 32061, 31415, 27988, 26510, 2338, 8268, 8461, 24126,
+ 29119, 31150, 28544, 9822, 13622, 14599, 31869, 25995, 28543, 9212,
+ 27240, 6829, 12720, 7648, 2967, 6607, 24188, 8743, 17148, 31278,
+ 12282, 17182, 22532, 10895, 19112, 218, 16830, 8150, 432, 3182,
+ 11584, 20949, 12394, 19298, 17223, 31330, 19745, 12128, 28957, 19116,
+ 6426, 13871, 14528, 2767, 4562, 9702, 19520, 22437, 1928, 22873,
+ 30825, 29407, 31995, 12504, 8866, 22869, 13429, 31513, 24085, 5019,
+ 3592, 27250, 23568, 29909, 6936, 27211, 15275, 15308, 2842, 26836,
+ 31916, 19009, 21914, 26867, 6567, 26241, 17795, 28801, 3434, 15161,
+ 18843, 9909, 18328, 2444, 11853, 14048, 21651, 16739, 9387, 19291,
+ 15519, 29700, 15027, 13502, 24133, 21735, 10449, 4435, 18422, 15556,
+ 6310, 2251, 21745, 25329, 18696, 28719, 4455, 16619, 13130, 27161,
+ 10716, 21555, 5565, 22307, 27088, 12891, 1910, 10912, 3487, 9056,
+ 31058, 30602, 27558, 13882, 18488, 18876, 14503, 946, 17566, 8033,
+ 27502, 4980, 21327, 5805, 949, 5989, 2923, 9163, 14406, 28982,
+ 30127, 25366, 20575, 13882, 20726, 23435, 11354, 9588, 0, 17790,
+ 16781, 17397, 1139, 10637, 3440, 4965, 11039, 27603, 17405, 5855,
+ 19846, 5982, 15709, 6658, 19612, 32226, 26304, 28228, 10443, 32686,
+ 14989, 4746, 23354, 4064, 955, 30966, 21583, 18645, 28798, 24320,
+ 17267, 9444, 14375, 27593, 3093, 12108, 22597, 2219, 3057, 16746,
+ 11537, 10261, 5778, 8240, 26889, 28310, 18965, 3538, 12250, 29239,
+ 8497, 9154, 22659, 1038, 26228, 2271, 6840, 14352, 27855, 22506,
+ 11140, 7975, 12629, 19001, 3379, 26501, 19008, 31407, 5743, 22327,
+ 18229, 21739, 29865, 21757, 26313, 1216, 11707, 29529, 17731, 31205,
+ 25803, 12774, 26787, 21486, 26226, 26859, 19940, 19067, 16413, 4912,
+ 23423, 26032, 26292, 27152, 23856, 6885, 12410, 2000, 27900, 8606,
+ 9781, 1071, 28019, 5309, 28558, 16190, 31027, 13302, 24250, 20082,
+ 27565, 22916, 24410, 16376, 26412, 30746, 19616, 10312, 31763, 13597,
+ 29364, 11773, 21861, 29456, 16214, 2020, 3723, 24656, 26052, 8531,
+ 5714, 24065, 31198, 22716, 17204, 21320, 18056, 3201, 31960, 16570,
+ 25424, 27146, 7900, 10261, 19793, 13078, 30929, 7214, 1878, 27982,
+ 3975, 3371, 1347, 12320, 907, 9458, 26289, 1226, 16623, 18402,
+ 17625, 3253, 23625, 3520, 6067, 25093, 16638, 18164, 30303, 26222,
+ 5313, 25077, 14019, 29769, 29782, 17666, 12406, 9703, 28060, 28691,
+ 9948, 10021, 23242, 31503, 7827, 17728, 761, 17471, 8718, 12523,
+ 9187, 25347, 14720, 9887, 18666, 12995, 6652, 28979, 4956, 2601,
+ 20442, 31404, 22517, 29325, 26716, 24406, 13733, 29617, 24210, 14100,
+ 2452, 18351, 20346, 2292, 25700, 2863, 14700, 7430, 25782, 15837,
+ 19125, 8303, 6895, 10011, 899, 20409, 23100, 29426, 12033, 7021,
+ 6867, 6991, 30658, 31460, 20860, 29036, 7011, 24922, 24656, 23436,
+ 364, 2372, 1217, 6891, 14712, 2531, 26331, 11765, 9366, 27418,
+ 11722, 8886, 19950, 11133, 15771, 28050, 13992, 27818, 583, 6198,
+ 6409, 14812, 27629, 23758, 26335, 7357, 95, 376, 1824, 29820,
+ 9696, 2041, 5838, 17184, 2860, 1456, 12573, 25884, 20665, 14280,
+ 728, 26403, 22333, 10161, 11521, 28221, 22384, 29648, 15032, 26139,
+ 10003, 4213, 11869, 27047, 20273, 5390, 27129, 6624, 22437, 27035,
+ 30426, 22245, 27612, 26722, 28798, 3919, 15580, 18404, 5811, 6596,
+ 17541, 24847, 19195, 19658, 19991, 9653, 32053, 18648, 26613, 23357,
+ 19322, 10419, 8873, 28057, 22854, 3064, 16679, 28280, 8664, 12276,
+ 15958, 5308, 18907, 2748, 19404, 20526, 13381, 7290, 11737, 17776,
+ 24192, 27398, 6344, 17972, 18376, 23478, 29537, 6572, 26580, 24438,
+ 8883, 10561, 30904, 9499, 17168, 25992, 6154, 17908, 29272, 30578,
+ 835, 8354, 3963, 4547, 29545, 22058, 4921, 30405, 23531, 7497,
+ 26156, 1597, 4301, 24584, 22537, 26526, 6148, 22415, 7203, 9341,
+ 10788, 6718, 28464, 18245, 9784, 20474, 19024, 21036, 31985, 197,
+ 18251, 8805, 22276, 12690, 6682, 5015, 31437, 17239, 17322, 30607,
+ 13624, 18531, 25052, 13874, 18913, 17394, 16592, 10677, 11898, 2047,
+ 4451, 2832, 5486, 9561, 26870, 687, 3011, 8697, 28274, 12651,
+ 11845, 27027, 22664, 17850, 14817, 11371, 8510, 28962, 31567, 8298,
+ 4775, 20980, 25076, 22641, 4337, 9526, 14854, 9709, 17830, 21729,
+ 20977, 14508, 4139, 13901, 3833, 28911, 24461, 3305, 13601, 6080,
+ 22908, 9519, 26188, 29061, 29336, 7127, 7331, 24278, 23532, 9547,
+ 9270, 32652, 27064, 26972, 22502, 3098, 22388, 18227, 9602, 22817,
+ 3345, 5514, 7472, 14654, 18818, 13084, 4111, 12583, 22139, 31577,
+ 538, 12790, 10617, 29535, 29520, 19908, 5634, 17190, 17426, 6778,
+ 29998, 20218, 14540, 14052, 26214, 1327, 24791, 9735, 3436, 13328,
+ 25758, 29877, 29083, 31768, 32512, 23902, 25201, 12901, 9718, 24105,
+ 1354, 18281, 9846, 30019, 28782, 1507, 14231, 30583, 30542, 15885,
+ 18677, 13568, 3083, 12567, 4183, 24731, 23096, 20693, 6799, 27872,
+ 32481, 10165, 25506, 21457, 460, 31987, 14889, 31924, 29694, 2320,
+ 29175, 13342, 22401, 20096, 10748, 27217, 13413, 27299, 10601, 11207,
+ 32517, 29430, 6165, 2063, 13196, 12939, 5664, 23256, 19127, 23478,
+ 30422, 11084, 27612, 522, 8918, 5535, 43, 28803, 25971, 29415,
+ 2868, 12293, 10586, 13102, 27817, 20997, 26741, 7621, 28517, 21382,
+ 21264, 27612, 18862, 11336, 29243, 29008, 29367, 24124, 18799, 18372,
+ 29033, 6458, 15220, 12275, 2147, 18166, 13953, 7492, 25408, 4913,
+ 27558, 8096, 10520, 17452, 5479, 8064, 6217, 30562, 4522, 8266,
+ 3959, 5750, 21203, 31965, 10193, 6251, 27693, 21098, 17558, 25363,
+ 15756, 3463, 15320, 24778, 560, 19838, 31873, 7780, 18157, 4587,
+ 21907, 1379, 2953, 26246, 17076, 1645, 4966, 317, 25065, 18430,
+ 10592, 1670, 30370, 11611, 23289, 26611, 7671, 18887, 28340, 4358,
+ 6193, 5112, 6590, 22088, 19340, 28108, 14547, 23189, 25659, 21561,
+ 4192, 24250, 13741, 19330, 22501, 12098, 16655, 23473, 5278, 9356,
+ 1298, 12609, 1890, 26913, 31470, 13851, 12747, 31301, 25767, 14020,
+ 13975, 5836, 20622, 26580, 6478, 4143, 30220, 24490, 8485, 12767,
+ 20379, 22622, 25379, 13017, 5653, 19959, 14210, 25979, 305, 19678,
+ 7768, 6550, 29002, 1171, 22391, 25796, 26211, 29343, 12689, 17660,
+ 26729, 14794, 21664, 20835, 17591, 31117, 2948, 28005, 17632, 14794,
+ 20718, 12805, 17064, 16059, 9086, 369, 15699, 22825, 25896, 30938,
+ 21539, 1758, 18908, 13442, 18972, 30556, 6502, 6679, 30474, 18639,
+ 18579, 7487, 18885, 4417, 11669, 12916, 16308, 2061, 21416, 25618,
+ 30096, 25494, 12790, 15790, 13674, 16184, 18872, 426, 9712, 7551,
+ 28575, 23814, 32492, 23191, 17522, 3449, 26381, 8964, 8440, 11713,
+ 24298, 17043, 31000, 7223, 23876, 24465, 31295, 12198, 139, 30266,
+ 26882, 11869, 31140, 10356, 517, 15235, 5098, 13758, 25115, 11947,
+ 32371, 12131, 14766, 2472, 14996, 15603, 20322, 163, 21415, 1267,
+ 5621, 18539, 17419, 3540, 22890, 7947, 11117, 11042, 18278, 17058,
+ 14918, 19198, 22234, 19055, 30373, 14286, 21218, 5676, 15919, 8755,
+ 3309, 18333, 10596, 1852, 31263, 31336, 13348, 18137, 16371, 11815,
+ 20337, 32402, 29733, 5820, 16502, 31864, 5071, 18148, 28872, 24156,
+ 30162, 26896, 5101, 12608, 15479, 31344, 17947, 9483, 2646, 15440,
+ 2113, 10369, 32375, 20391, 15692, 369, 15288, 12013, 3235, 13616,
+ 32622, 31278, 19955, 21831, 2895, 18781, 25138, 1129, 26256, 30954,
+ 7646, 18344, 14922, 9366, 10374, 30696, 19746, 17543, 30092, 26515,
+ 25129, 8343, 14889, 4238, 32513, 3570, 1201, 24172, 23874, 10976,
+ 22809, 26850, 2843, 3295, 30390, 12923, 32573, 5365, 11079, 16269,
+ 9204, 24132, 22326, 6508, 7575, 31455, 1819, 4573, 20515, 29404,
+ 18050, 23246, 26659, 14763, 4078, 17988, 27347, 3494, 32286, 17044,
+ 4484, 30184, 8846, 26326, 29762, 21091, 9537, 9111, 18357, 12845,
+ 4542, 27598, 12869, 25627, 30041, 27153, 31873, 30097, 12979, 5641,
+ 8386, 5016, 11908, 15908, 32267, 561, 14744, 22921, 12852, 7658,
+ 23576, 13905, 24392, 7086, 26123, 22516, 24619, 31457, 26908, 6657,
+ 12416, 23981, 32670, 27411, 3017, 15254, 1229, 13312, 2000, 8789,
+ 8791, 16211, 11847, 30947, 22299, 13565, 22955, 30932, 23344, 32327,
+ 22894, 20966, 1321, 9739, 8532, 11226, 5271, 2340, 2078, 31362,
+ 1488, 27427, 22886, 22556, 21231, 17219, 16074, 23006, 17948, 21920,
+ 17484, 4818, 16654, 27811, 31737, 14564, 7629, 18113, 1225, 8250,
+ 3261, 3173, 30919, 195, 5080, 25130, 1649, 14867, 4923, 27470,
+ 14690, 2414, 29412, 20580, 13870, 26146, 23994, 7752, 28046, 30746,
+ 11725, 4440, 2749, 23729, 28128, 8417, 8481, 11716, 5157, 24280,
+ 23854, 32523, 23111, 32715, 15496, 17833, 22189, 7958, 4455, 24065,
+ 15102, 4954, 21824, 9164, 23520, 26411, 3746, 20584, 26118, 18953,
+ 20062, 4979, 25705, 3474, 2026, 6553, 31701, 757, 18695, 30122,
+ 32680, 19626, 5282, 8176, 17367, 30817, 25848, 32703, 20529, 30008,
+ 6398, 13133, 22760, 14896, 20736, 2500, 8269, 12514, 32392, 25494,
+ 9691, 14446, 11137, 27921, 18039, 21685, 15516, 26419, 12790, 24008,
+ 13043, 29375, 23008, 17311, 12525, 4496, 15731, 14863, 18017, 21038,
+ 14059, 24822, 18430, 22943, 11777, 15545, 13802, 16256, 21426, 4848,
+ 30121, 28756, 19265, 32607, 25409, 2587, 25727, 21801, 32155, 26407,
+ 19274, 8256, 12845, 19243, 20564, 23328, 3030, 26261, 12070, 11453,
+ 18697, 9245, 30052, 17081, 7470, 29854, 28498, 7131, 8517, 3365,
+ 15767, 22205, 14285, 19272, 30785, 22724, 26596, 13242, 778, 24917,
+ 29615, 16156, 30425, 23878, 11772, 26901, 17548, 3731, 21286, 13732,
+ 29941, 23635, 26937, 8373, 10786, 24298, 27479, 11251, 17890, 31871,
+ 17499, 32478, 22916, 10673, 23739, 19741, 17122, 8837, 16307, 30485,
+ 6815, 12195, 7072, 6330, 22444, 19395, 8618, 31397, 19473, 15714,
+ 2213, 6504, 24298, 30905, 14137, 14110, 10159, 24047, 22849, 11078,
+ 20153, 10126, 25714, 25809, 22274, 7476, 20541, 21113, 13613, 24203,
+ 1270, 9557, 22470, 23162, 17973, 8618, 1226, 18077, 7293, 29189,
+ 12394, 10995, 539, 12422, 12556, 21975, 22353, 6783, 29843, 19506,
+ 25012, 8766, 6880, 2542, 23251, 21286, 6552, 9902, 21017, 15365,
+ 19752, 12988, 26101, 21409, 6919, 24642, 6199, 2964, 2363, 19646,
+ 16830, 1370, 28447, 32432, 26960, 7593, 9059, 27541, 457, 16896,
+ 19284, 6681, 21368, 17539, 12126, 13449, 5318, 8710, 14543, 8071,
+ 30232, 28264, 31965, 26881, 9463, 23330, 30955, 9060, 2671, 3103,
+ 25608, 268, 18612, 11983, 14777, 17408, 15372, 1911, 25080, 21980,
+ 744, 26827, 6780, 7182, 20820, 18878, 1339, 23621, 5010, 28057,
+ 46, 17703, 9218, 21066, 10836, 28483, 6214, 22783, 14841, 27206,
+ 27042, 23796, 2104, 10865, 31913, 11401, 30143, 27210, 19478, 6296,
+ 3282, 21650, 15096, 3589, 1171, 2680, 21010, 28055, 2432, 23052,
+ 27777, 5638, 28477, 14582, 6047, 21589, 12180, 22376, 10792, 11873,
+ 23226, 24401, 22171, 15291, 23763, 13268, 15587, 179, 15545, 17656,
+ 16183, 32693, 14329, 19361, 7743, 29913, 24607, 447, 8312, 28597,
+ 7476, 10949, 18649, 16246, 14724, 93, 24759, 25903, 23205, 22361,
+ 22758, 112, 2996, 4333, 17953, 27163, 15586, 11292, 31915, 29043,
+ 23599, 2929, 3895, 28534, 27510, 17135, 13574, 9325, 14250, 586,
+ 23375, 5057, 5471, 28504, 26083, 21008, 18060, 1218, 25361, 31104,
+ 28047, 18687, 14023, 14419, 12657, 29059, 251, 11708, 30572, 17971,
+ 17225, 2289, 21930, 22813, 2526, 7810, 9040, 26214, 7060, 26601,
+ 18875, 28803, 30046, 8546, 15113, 27820, 5351, 31229, 12764, 5006,
+ 22134, 2545, 7770, 10817, 27157, 819, 25721, 22393, 9202, 20551,
+ 20345, 22784, 11269, 5463, 24242, 11620, 20723, 18306, 20367, 1517,
+ 563, 20086, 2267, 5329, 13679, 25665, 19259, 2987, 15149, 10084,
+ 19196, 24106, 18094, 4905, 5903, 7430, 11542, 21047, 29010, 32057,
+ 8142, 8036, 31762, 24427, 26151, 10442, 24781, 27566, 23104, 10525,
+ 21564, 5483, 11561, 11068, 7056, 7068, 13896, 11269, 30461, 22844,
+ 20988, 3694, 5493, 31228, 4993, 5585, 30134, 26424, 19988, 23176,
+ 22662, 297, 14679, 27834, 10301, 30812, 13558, 6516, 31109, 23395,
+ 28555, 1532, 2398, 11466, 29887, 5474, 23653, 5453, 26290, 19543,
+ 25429, 1607, 26270, 10050, 18638, 24686, 28855, 5777, 19541, 29374,
+ 12117, 5453, 20125, 26035, 2388, 3570, 29444, 26299, 28603, 381,
+ 31329, 10219, 11933, 9414, 15101, 2033, 17725, 26640, 23007, 30282,
+ 2421, 7391, 10573, 26549, 6745, 11786, 20623, 28391, 26135, 7696,
+ 8438, 19840, 18210, 16303, 15389, 4414, 31887, 23731, 28527, 4464,
+ 447, 16141, 26857, 24750, 2366, 20516, 10529, 1736, 7915, 17008,
+ 22152, 5884, 13657, 31044, 21996, 30316, 8822, 8939, 19521, 26319,
+ 20330, 14583, 28064, 10598, 8130, 23254, 15760, 20017, 21454, 13990,
+ 9349, 868, 27207, 29770, 32422, 30997, 17717, 22206, 2003, 11575,
+ 5648, 1959, 18663, 13259, 21798, 16687, 27194, 20309, 18492, 18959,
+ 3947, 28045, 23672, 30701, 8284, 23640, 22399, 11241, 9085, 19190,
+ 9178, 32115, 3406, 27517, 15518, 1887, 10527, 18566, 31820, 2875,
+ 32538, 8998, 21238, 24288, 23428, 27936, 10147, 22599, 23360, 13144,
+ 26869, 11166, 8597, 3211, 4361, 28571, 6961, 24638, 8351, 15377,
+ 29293, 6644, 21883, 5825, 6354, 7332, 8203, 8818, 2524, 2666,
+ 7241, 17476, 11007, 13437, 4579, 13121, 27880, 18273, 16281, 9781,
+ 4613, 1886, 30183, 5055, 15943, 12592, 17637, 14505, 13351, 21248,
+ 16747, 22645, 25319, 12691, 9592, 27704, 10778, 3522, 20437, 13228,
+ 30310, 24106, 26357, 23680, 7049, 20772, 8992, 13298, 3994, 11000,
+ 977, 5792, 27537, 21581, 29788, 4763, 21770, 11492, 9171, 28606,
+ 13638, 30342, 5163, 4670, 24947, 27707, 9371, 27521, 6189, 22973,
+ 6981, 27956, 30788, 18220, 29208, 12952, 21696, 3331, 27381, 21532,
+ 2594, 25675, 12048, 6449, 14573, 18191, 32154, 31834, 2405, 13583,
+ 11677, 13698, 23703, 12472, 1831, 16019, 3737, 2132, 14250, 1604,
+ 11795, 16255, 26019, 17715, 19710, 11482, 10106, 10547, 20140, 8195,
+ 25001, 19175, 22281, 9156, 20513, 8592, 16160, 12426, 16105, 26915,
+ 13025, 25369, 13833, 11935, 23585, 2943, 7334, 30365, 16098, 10310,
+ 5998, 12840, 10965, 8686, 9783, 30160, 26141, 23195, 17634, 9978,
+ 30038, 26122, 4998, 4986, 9430, 32201, 18891, 10084, 14130, 1448,
+ 31123, 13598, 23812, 13419, 25824, 954, 23020, 13505, 27378, 6019,
+ 31445, 21114, 20655, 26838, 16762, 2036, 26696, 32052, 26920, 32726,
+ 23578, 5780, 10437, 24321, 8402, 27902, 22033, 27332, 21205, 9813,
+ 20012, 24399, 735, 117, 18265, 2667, 13801, 24958, 28673, 32360,
+ 7249, 17006, 32507, 29014, 17461, 10230, 6410, 7288, 19231, 7558,
+ 12199, 12277, 21224, 26283, 15617, 11985, 15830, 23194, 323, 18204,
+ 30216, 7693, 9493, 31337, 17428, 12109, 25957, 10882, 30958, 30864,
+ 11367, 24154, 28428, 23686, 15322, 21315, 9927, 28975, 19598, 11873,
+ 517, 23791, 18211, 25183, 25365, 2532, 31251, 7520, 13018, 9079,
+ 28915, 21305, 4652, 4657, 20725, 14301, 14971, 27089, 24242, 15896,
+ 20917, 32155, 4390, 28289, 13674, 3826, 22012, 10922, 303, 18985,
+ 27404, 12441, 21568, 1431, 28963, 29308, 6761, 30441, 7170, 5784,
+ 23590, 21180, 9129, 13187, 23049, 2668, 23253, 7315, 30556, 7206,
+ 3783, 21142, 14344, 10565, 5191, 27843, 21941, 18139, 9705, 3569,
+ 12339, 15501, 30607, 14855, 7448, 9637, 9007, 8116, 23211, 10338,
+ 21206, 10848, 10753, 14226, 19437, 28770, 21606, 4707, 16316, 20851,
+ 8191, 30327, 1324, 22882, 30637, 14390, 8145, 15114, 18995, 13672,
+ 14375, 30594, 25756, 22019, 26908, 1427, 19415, 3905, 1743, 3439,
+ 22949, 7414, 17048, 3231, 8373, 25889, 20552, 30270, 23564, 14785,
+ 28850, 9061, 28075, 27882, 1386, 10214, 12396, 27415, 4556, 24381,
+ 8494, 20418, 19776, 17859, 9009, 10290, 10941, 29221, 25539, 22677,
+ 31116, 17173, 8477, 22350, 847, 5439, 22664, 12944, 19265, 5503,
+ 8132, 5164, 21183, 849, 11689, 14247, 1800, 30601, 22031, 1680,
+ 15425, 836, 31980, 20240, 22972, 15134, 17596, 18627, 7033, 677,
+ 31782, 23494, 3309, 11278, 3804, 24082, 8451, 16423, 32195, 15112,
+ 2913, 653, 8788, 14668, 16108, 1567, 16706, 21207, 13710, 26034,
+ 12380, 21320, 25911, 29959, 5046, 12411, 1569, 32250, 30211, 20829,
+ 3673, 24059, 16454, 14079, 1659, 6082, 21674, 15337, 7100, 11583,
+ 20653, 23984, 4910, 21968, 14980, 17611, 576, 25783, 7611, 32418,
+ 28804, 29643, 23325, 7656, 18102, 9837, 12243, 13611, 12025, 6334,
+ 14288, 24489, 19043, 20240, 28524, 19558, 24508, 14746, 30798, 32635,
+ 26499, 8303, 9616, 15793, 6450, 2993, 4894, 22094, 24004, 31745,
+ 19551, 16175, 19315, 1851, 17944, 14103, 3782, 11616, 12173, 25159,
+ 25803, 31188, 24297, 5455, 2721, 17610, 23775, 16931, 17978, 10492,
+ 21394, 15217, 27743, 415, 25778, 16946, 2037, 1174, 10984, 4480,
+ 1662, 19686, 27253, 23719, 3555, 26986, 13590, 29566, 24432, 17352,
+ 1322, 248, 27680, 29603, 5142, 6134, 32283, 21010, 28649, 607,
+ 7037, 24913, 5180, 1651, 1625, 23735, 2653, 5724, 32254, 1256,
+ 21676, 7686, 9592, 31820, 10564, 25393, 13146, 18368, 16350, 11205,
+ 20155, 18315, 14067, 7781, 15743, 15507, 21537, 4422, 18392, 11729,
+ 9168, 15170, 29963, 16898, 15381, 31528, 1400, 24991, 9943, 10583,
+ 19925, 13584, 14128, 10123, 22458, 21277, 19989, 8950, 27490, 13221,
+ 21050, 15507, 26288, 14994, 24368, 2999, 1392, 28428, 28624, 12009,
+ 32480, 13037, 2013, 24307, 7278, 3701, 8421, 14393, 11716, 25664,
+ 24168, 11850, 32258, 8564, 19773, 23989, 11850, 15935, 12848, 12318,
+ 6530, 8833, 11248, 1680, 9557, 17093, 11305, 24085, 9339, 2422,
+ 3053, 8836, 11835, 24656, 16216, 9115, 3886, 28180, 27764, 24653,
+ 14149, 23680, 26970, 7261, 18701, 14974, 26010, 29740, 11826, 20124,
+ 17117, 25296, 21827, 28092, 24777, 28261, 31924, 10764, 24613, 28328,
+ 12073, 28217, 8510, 8642, 21746, 22752, 393, 865, 32465, 27718,
+ 7305, 6669, 19972, 26184, 5107, 11962, 7551, 21653, 8977, 8857,
+ 20602, 14618, 356, 22324, 27179, 21182, 22669, 23738, 21205, 24144,
+ 20846, 23191, 28161, 25533, 31884, 26184, 26123, 25479, 6583, 15470,
+ 20705, 30834, 750, 4129, 4616, 16769, 15997, 25734, 7648, 10272,
+ 31848, 9380, 552, 22179, 780, 28019, 22468, 29423, 20228, 15926,
+ 446, 29047, 27210, 779, 23948, 5227, 16030, 11713, 18577, 27435,
+ 26412, 20713, 7910, 26114, 17769, 28976, 5977, 21009, 23870, 236,
+ 8374, 20873, 15464, 14836, 9286, 9246, 28959, 18869, 20886, 21432,
+ 21493, 898, 22393, 6507, 10498, 3372, 11856, 3753, 23614, 14803,
+ 22409, 32438, 23854, 1787, 13926, 27741, 24003, 28642, 26112, 8162,
+ 30847, 2834, 12427, 20791, 473, 9778, 3035, 17010, 2275, 21537,
+ 16167, 24191, 19242, 8518, 5646, 12306, 8157, 25121, 17623, 17632,
+ 7730, 20518, 25085, 20751, 774, 26828, 6379, 9963, 6596, 17121,
+ 31236, 22234, 11399, 20000, 3046, 2962, 16259, 12549, 496, 30345,
+ 7073, 14560, 15362, 24749, 27753, 4137, 29571, 13142, 29989, 12051,
+ 14761, 3449, 8515, 14947, 10996, 14622, 29692, 17539, 31740, 5396,
+ 6963, 9426, 17261, 18147, 10656, 22847, 9552, 18690, 15405, 9750,
+ 17292, 10570, 3744, 26649, 6060, 2987, 17275, 19667, 6626, 17694,
+ 25376, 25897, 22860, 8922, 22073, 17970, 26999, 12747, 24407, 11337,
+ 18722, 6720, 22489, 21600, 9796, 25572, 13328, 32663, 9040, 13807,
+ 4769, 21773, 439, 26525, 23338, 5621, 21934, 29920, 12328, 22509,
+ 10035, 11089, 14360, 14732, 9290, 9069, 476, 17722, 18573, 23038,
+ 2145, 30277, 7651, 32215, 6527, 5169, 31376, 17860, 9248, 22607,
+ 24686, 25281, 12709, 4497, 24953, 25194, 3717, 15004, 11665, 5555,
+ 26167, 13855, 11644, 20441, 22099, 9571, 20267, 4505, 15604, 3364,
+ 26430, 29855, 18016, 15520, 19402, 27457, 32235, 10989, 3161, 10349,
+ 26136, 16015, 27442, 17376, 23554, 13130, 31707, 28313, 18938, 4661,
+ 2781, 19342, 28018, 28688, 12999, 16541, 13338, 26071, 17013, 21445,
+ 29768, 30615, 22674, 26774, 1181, 23937, 22620, 29158, 30438, 25405,
+ 7079, 27590, 31296, 20865, 1573, 12725, 10368, 5601, 24036, 1299,
+ 17105, 7401, 3352, 22488, 8607, 4713, 12571, 12165, 23476, 31760,
+ 6834, 13403, 26785, 25148, 9106, 16587, 16992, 31505, 32035, 1327,
+ 18999, 3017, 23683, 5047, 29919, 29770, 10190, 26790, 486, 6398,
+ 2205, 17086, 16978, 7903, 1996, 24568, 12935, 11729, 5761, 29305,
+ 27499, 11573, 10345, 25026, 11975, 11963, 17221, 11303, 4849, 31607,
+ 10150, 31874, 4520, 30520, 30452, 18472, 32319, 19989, 31413, 2332,
+ 9982, 8264, 28940, 26755, 9669, 8256, 640, 27992, 9202, 22257,
+ 17663, 865, 5509, 623, 28707, 28258, 12162, 17083, 9908, 32144,
+ 7575, 2268, 31085, 4936, 15103, 31794, 1795, 21761, 21158, 18952,
+ 23907, 6016, 10894, 4968, 59, 23371, 24177, 27955, 14525, 27999,
+ 19880, 9841, 4768, 37, 8267, 18661, 10855, 20643, 10138, 2020,
+ 12517, 11247, 7579, 4456, 18433, 26858, 2053, 30049, 7351, 10794,
+ 16989, 5963, 25183, 31800, 29535, 24069, 4914, 9212, 29087, 5601,
+ 6666, 12661, 23408, 14584, 18793, 10926, 26117, 4544, 17341, 25325,
+ 10198, 27616, 14562, 21037, 25157, 18242, 7401, 206, 3714, 16746,
+ 15384, 23436, 12716, 10503, 20529, 942, 15417, 28616, 31480, 28543,
+ 30871, 28273, 18927, 28418, 19731, 12078, 10084, 26850, 21755, 12839,
+ 23725, 25512, 5375, 24660, 2483, 12080, 20189, 8339, 13741, 16990,
+ 14398, 17144, 23854, 8461, 6362, 13924, 8546, 24136, 5091, 15449,
+ 31892, 3773, 8353, 3852, 8180, 16238, 30298, 11708, 24216, 17578,
+ 28532, 17219, 18880, 30012, 10205, 23275, 25182, 9698, 23211, 22402,
+ 982, 30977, 17152, 24753, 27650, 22166, 1073, 14985, 1145, 8304,
+ 23847, 15199, 20753, 30365, 11013, 21466, 10146, 8226, 32522, 23882,
+ 5389, 27631, 19386, 8763, 4989, 7697, 27960, 21835, 30189, 15658,
+ 4343, 27192, 11499, 21534, 16529, 1341, 18587, 31760, 5111, 29855,
+ 23550, 17037, 20171, 26755, 9588, 16390, 27914, 23810, 8320, 29316,
+ 25326, 27263, 25804, 12439, 5139, 28728, 30317, 18575, 17880, 19740,
+ 27495, 8175, 4360, 6877, 2676, 26399, 5818, 8005, 18177, 13665,
+ 31861, 26573, 15994, 8454, 29592, 17260, 6855, 10210, 20473, 3757,
+ 32279, 31741, 29133, 1540, 23516, 2187, 1736, 4706, 25366, 17183,
+ 26245, 17415, 24021, 7451, 3623, 28568, 10745, 10603, 32577, 8561,
+ 12093, 19059, 1523, 23356, 30324, 31813, 10838, 20418, 17938, 3864,
+ 20762, 4354, 26605, 26102, 20334, 25728, 31813, 3508, 30240, 12768,
+ 32258, 16423, 22534, 16307, 23614, 10133, 20380, 12945, 19715, 30314,
+ 2030, 616, 15702, 10028, 3257, 23059, 628, 30897, 9677, 5423,
+ 12379, 31376, 437, 20522, 14732, 15829, 29594, 16028, 15376, 32249,
+ 18533, 15323, 8121, 22033, 30500, 18890, 27050, 22085, 12463, 29169,
+ 26905, 3460, 4747, 15571, 8532, 23414, 270, 13179, 5378, 7858,
+ 27844, 8025, 22188, 4914, 1810, 31820, 636, 29955, 10777, 20736,
+ 1348, 15169, 30685, 24954, 21697, 32579, 29863, 28657, 32034, 25619,
+ 8360, 32736, 10180, 4641, 21726, 20313, 32576, 6968, 26428, 31388,
+ 5287, 23216, 23045, 32232, 10764, 9702, 6777, 2449, 1603, 24809,
+ 4787, 23635, 13801, 19318, 4818, 6118, 23972, 6695, 21847, 17362,
+ 428, 12263, 8910, 29317, 26251, 2985, 22705, 15523, 28449, 15962,
+ 22409, 1693, 7146, 32019, 7254, 17541, 3972, 9108, 2353, 12321,
+ 15467, 15086, 8496, 9534, 8200, 22655, 15242, 6214, 12010, 26915,
+ 29179, 23317, 22099, 15529, 20074, 9225, 14070, 25988, 31690, 2904,
+ 31999, 16579, 32318, 29351, 31060, 14916, 13952, 2776, 24602, 8484,
+ 13443, 27683, 20604, 8313, 7511, 29800, 2471, 12356, 10318, 24515,
+ 28953, 4769, 30557, 20322, 19996, 12609, 20164, 12947, 24205, 28442,
+ 28657, 17953, 10466, 16989, 7074, 7649, 12140, 10921, 32587, 27784,
+ 26840, 22398, 4535, 32191, 8700, 4852, 8945, 5754, 11473, 17581,
+ 9061, 12165, 187, 8456, 26179, 15967, 12305, 22679, 25380, 76,
+ 22233, 23508, 15088, 31654, 26323, 1807, 1023, 11124, 29882, 19115,
+ 8574, 2366, 27334, 9098, 10773, 26911, 17525, 30662, 8646, 23579,
+ 14219, 11170, 2841, 3251, 28247, 704, 4982, 18871, 14137, 8596,
+ 24274, 13148, 19809, 17176, 13966, 16014, 7897, 30401, 8091, 647,
+ 13254, 31410, 7139, 1185, 6891, 1585, 6884, 30312, 32622, 6231,
+ 23966, 6644, 19423, 7947, 20912, 16502, 32374, 2609, 10174, 5904,
+ 4764, 7966, 10517, 13802, 9133, 8271, 4242, 9602, 11517, 7515,
+ 27328, 20035, 2841, 32551, 16704, 1626, 8783, 9305, 5486, 12741,
+ 20080, 8719, 28225, 10412, 32724, 31952, 32115, 22517, 10655, 28099,
+ 8162, 20499, 25923, 2078, 15671, 13854, 28486, 21218, 19141, 19241,
+ 24902, 10950, 30132, 32208, 19770, 112, 14430, 14864, 7674, 18155,
+ 24313, 27484, 24834, 9814, 16247, 25836, 23922, 18137, 10410, 9305,
+ 7258, 18398, 19628, 8807, 17973, 14205, 10878, 9761, 31155, 7735,
+ 15087, 20012, 32700, 29416, 25791, 17493, 177, 2807, 31749, 20332,
+ 7925, 23248, 20686, 14165, 6828, 6804, 4359, 12124, 25282, 8974,
+ 413, 15049, 14127, 5866, 21218, 16308, 16506, 11297, 5171, 15387,
+ 16508, 10680, 2776, 20786, 16487, 28074, 28715, 6394, 24583, 3875,
+ 23292, 31253, 10823, 28910, 22581, 28121, 4854, 22577, 30394, 27811,
+ 459, 23384, 19091, 29806, 3751, 15695, 11085, 23972, 21275, 2292,
+ 12701, 29235, 29994, 204, 14407, 31460, 20304, 14068, 25662, 14057,
+ 22979, 24923, 30733, 29108, 14584, 15919, 30325, 11024, 5481, 7317,
+ 22616, 1386, 8342, 23965, 22998, 28271, 27465, 373, 8885, 13789,
+ 28959, 5341, 19974, 1682, 32068, 4826, 5381, 30186, 19582, 3759,
+ 8514, 7495, 4205, 14857, 18942, 29169, 14353, 7034, 16600, 20257,
+ 8588, 2344, 29097, 26200, 6441, 15303, 6572, 2549, 18846, 3524,
+ 23010, 1543, 398, 15043, 18612, 31584, 29266, 13132, 18139, 28907,
+ 19449, 22721, 7037, 3903, 23181, 13716, 7064, 14963, 2200, 1462,
+ 24740, 32308, 27367, 9043, 21108, 22, 14734, 11196, 2142, 27688,
+ 23085, 28837, 17819, 4043, 24433, 2448, 5360, 5828, 8669, 6537,
+ 18318, 7823, 21962, 7444, 23352, 5110, 17068, 21604, 2979, 3811,
+ 32664, 7629, 4898, 8307, 22787, 21628, 24195, 18251, 17357, 1894,
+ 14387, 32303, 382, 7294, 11945, 6353, 22991, 13355, 14850, 25318,
+ 3436, 24825, 25833, 13695, 26104, 1935, 31930, 30359, 1873, 31457,
+ 3303, 14056, 26134, 10406, 10650, 25092, 1895, 27149, 19868, 13472,
+ 28140, 19627, 20341, 27955, 22553, 26552, 12757, 27328, 13232, 4476,
+ 21298, 11759, 27271, 2308, 16563, 28771, 27787, 26649, 12365, 17992,
+ 6917, 29043, 26156, 32299, 31004, 3881, 2388, 13071, 17819, 5484,
+ 11144, 17597, 25077, 7541, 2154, 10843, 10887, 3260, 16357, 21312,
+ 9244, 7275, 4040, 2567, 8886, 29970, 20659, 3554, 19852, 12956,
+ 14903, 22065, 9295, 25730, 12857, 13396, 27057, 24126, 11159, 18365,
+ 5928, 27651, 22543, 30793, 15855, 16299, 12636, 27344, 31055, 10737,
+ 7585, 9211, 22044, 29664, 13067, 19797, 21378, 27787, 24242, 20645,
+ 24834, 32511, 29377, 15740, 32183, 25718, 24535, 11530, 23774, 18125,
+ 7597, 6197, 13205, 26424, 1784, 21485, 5091, 7477, 11409, 10169,
+ 30969, 16830, 25555, 12950, 26807, 23235, 5188, 4610, 20082, 6871,
+ 2168, 32596, 29429, 2346, 17971, 22350, 13765, 26039, 12750, 16373,
+ 27562, 7614, 220, 24736, 1642, 25717, 16397, 24656, 27096, 17403,
+ 28754, 7743, 4621, 14989, 32577, 22716, 28406, 14332, 7868, 13877,
+ 6415, 3934, 16333, 25750, 17261, 12548, 13525, 17106, 3842, 16557,
+ 16102, 18622, 8989, 23545, 2669, 8486, 12080, 9505, 24340, 10779,
+ 14806, 26084, 1766, 20362, 24852, 24261, 12468, 29715, 28639, 5747,
+ 20920, 23575, 27871, 15753, 19065, 20243, 1651, 31351, 21230, 25389,
+ 32757, 12736, 29158, 9997, 1087, 7783, 936, 7662, 366, 20131,
+ 5078, 16885, 29158, 22746, 3735, 193, 13974, 23757, 3316, 26179,
+ 26237, 9489, 16515, 27088, 14188, 31934, 16963, 4468, 25614, 3435,
+ 18632, 24458, 13095, 22873, 2456, 16009, 1049, 9710, 18900, 24353,
+ 1196, 27237, 25115, 15495, 29710, 5829, 14763, 15117, 5913, 18191,
+ 31945, 5365, 16853, 14012, 4708, 2439, 6718, 2150, 5365, 609,
+ 30791, 13766, 21161, 8975, 1822, 15326, 6338, 30427, 2994, 22391,
+ 20026, 12518, 29811, 26062, 8618, 12920, 5720, 15755, 20075, 19349,
+ 15143, 5106, 15611, 27089, 25841, 16989, 674, 10597, 27355, 32746,
+ 1109, 31873, 21285, 25457, 16602, 23780, 3684, 16825, 1581, 15275,
+ 30738, 15339, 5667, 9062, 16457, 4678, 32333, 16497, 8908, 3861,
+ 10015, 17282, 3911, 7646, 24145, 21118, 9944, 25309, 24710, 31633,
+ 13005, 26288, 9772, 24189, 30896, 10836, 30627, 50, 3969, 14160,
+ 3233, 31904, 6722, 48, 15061, 2761, 3001, 9525, 30666, 1818,
+ 22385, 29003, 12815, 30715, 13314, 9019, 17813, 16549, 21138, 22306,
+ 3928, 30259, 12188, 9250, 25665, 2812, 24816, 16983, 28491, 17441,
+ 1275, 19725, 15078, 11618, 14153, 30000, 27033, 32566, 11848, 14339,
+ 25066, 11034, 26191, 28181, 29058, 553, 32222, 18034, 11149, 10733,
+ 10024, 534, 1632, 21365, 21198, 935, 31838, 26791, 30702, 1891,
+ 13340, 9176, 7516, 5975, 29635, 17818, 2095, 4049, 25526, 23765,
+ 13184, 18457, 25717, 21786, 30062, 13148, 31682, 16179, 30053, 3561,
+ 7426, 2047, 22433, 27296, 20709, 4477, 16877, 13478, 73, 25126,
+ 7601, 31070, 26204, 24192, 15147, 3733, 28161, 16624, 14845, 26877,
+ 32374, 17359, 23272, 14045, 31539, 12737, 7895, 4870, 31509, 20546,
+ 22303, 25609, 31419, 22658, 2821, 15271, 3633, 29299, 22145, 19081,
+ 21963, 26144, 9793, 15410, 14932, 30528, 29937, 3889, 13416, 7947,
+ 28090, 15771, 8991, 6220, 6152, 18872, 30188, 29112, 28817, 765,
+ 11716, 6782, 5011, 5946, 31106, 7455, 23644, 17429, 29066, 31872,
+ 7696, 15543, 13996, 26430, 22951, 6085, 30796, 13633, 5429, 22930,
+ 9664, 25492, 14446, 28307, 20218, 627, 4713, 10771, 30823, 18854,
+ 27812, 7463, 26134, 18190, 20297, 23013, 8733, 23422, 23215, 30417,
+ 16953, 31180, 23076, 26264, 12468, 23591, 29674, 30721, 31884, 9130,
+ 6783, 4640, 29905, 5682, 8993, 205, 4943, 28269, 9618, 25940,
+ 31341, 29236, 2329, 8046, 2645, 17179, 25289, 17008, 20821, 7494,
+ 2309, 27331, 23429, 30846, 68, 1940, 9643, 16259, 9490, 27852,
+ 14171, 4516, 14168, 16707, 10339, 17038, 10972, 7472, 5478, 3170,
+ 24843, 27877, 18374, 10250, 12279, 27577, 5319, 16332, 23196, 19269,
+ 14322, 28703, 24167, 23251, 11448, 19134, 14841, 17171, 19288, 4092,
+ 4392, 10768, 11523, 4695, 21062, 21347, 6973, 30799, 16550, 4262,
+ 3718, 20601, 2141, 5676, 58, 11215, 16198, 2031, 5046, 12874,
+ 30537, 21194, 23228, 26035, 17884, 9705, 14617, 1718, 25801, 8317,
+ 11140, 20536, 20530, 1972, 30154, 31978, 1491, 6376, 31784, 19230,
+ 18824, 19479, 19448, 29402, 4879, 6803, 6033, 16939, 2318, 7674,
+ 10600, 21436, 11608, 7017, 4731, 5031, 7788, 20205, 6127, 1675,
+ 4671, 2874, 9207, 1759, 28219, 416, 15865, 27782, 8327, 17978,
+ 19948, 21155, 7817, 25705, 12037, 28590, 11433, 6016, 21906, 13256,
+ 21336, 31681, 3110, 8523, 9553, 19337, 3062, 5030, 15135, 31943,
+ 29827, 26728, 2016, 21170, 26233, 16026, 27464, 14268, 17879, 16466,
+ 9449, 29633, 26449, 10885, 3249, 4741, 11507, 1821, 13492, 3677,
+ 22022, 19787, 22571, 4908, 1591, 23583, 15293, 28049, 18422, 854,
+ 25342, 31327, 3613, 3699, 16182, 10830, 30930, 1553, 15203, 28144,
+ 25006, 7031, 18817, 7654, 29471, 29293, 21768, 13139, 20234, 15694,
+ 16055, 25745, 2229, 24415, 17808, 31267, 30181, 2399, 292, 28651,
+ 6979, 1119, 20752, 13981, 14340, 7892, 26056, 10612, 13513, 28651,
+ 18067, 3108, 31172, 25884, 30935, 9487, 28701, 19970, 11415, 18363,
+ 12948, 23146, 4666, 25476, 12647, 16042, 15758, 27278, 19830, 29236,
+ 14860, 9470, 11941, 15466, 13406, 17514, 22914, 948, 23838, 19341,
+ 18472, 4816, 26849, 7744, 2659, 18538, 20852, 19878, 12564, 25837,
+ 15461, 29862, 2263, 27288, 10949, 14494, 26596, 17364, 22061, 16981,
+ 4915, 9157, 24319, 17202, 32484, 21791, 12270, 23212, 28125, 27451,
+ 15041, 28674, 13493, 2410, 29267, 21548, 9169, 13449, 9695, 16401,
+ 23756, 25301, 8570, 762, 5916, 15873, 14305, 30023, 6131, 19334,
+ 6517, 865, 24932, 28475, 7300, 25839, 23751, 31781, 23242, 21581,
+ 1118, 18320, 18488, 23097, 20537, 29278, 9972, 464, 27222, 23712,
+ 31904, 2234, 28173, 30563, 27871, 24481, 13995, 26828, 7445, 3815,
+ 350, 13928, 1391, 21400, 26193, 27069, 21284, 2205, 27927, 25381,
+ 16378, 12339, 16461, 20188, 779, 12700, 17531, 28759, 16073, 7956,
+ 5692, 14295, 4160, 6151, 13215, 22079, 9115, 7041, 21708, 17186,
+ 29162, 24294, 14315, 26913, 3106, 31971, 25665, 27764, 5989, 4260,
+ 10396, 16326, 24196, 4424, 22770, 31558, 7363, 402, 3909, 10747,
+ 26076, 18401, 29641, 343, 20294, 16994, 20553, 14096, 16054, 27524,
+ 29383, 26923, 487, 8876, 9059, 19546, 5015, 27947, 12670, 5255,
+ 12754, 17261, 23582, 19377, 10610, 15986, 6548, 2807, 31463, 14722,
+ 605, 18930, 15412, 15389, 25415, 14408, 23610, 16434, 15060, 21886,
+ 11065, 10385, 9699, 15118, 19604, 31649, 32653, 19642, 30164, 13910,
+ 14414, 17183, 7920, 19294, 10341, 17549, 1996, 8859, 24957, 22,
+ 14079, 11478, 17292, 32485, 21977, 24498, 22780, 8146, 3493, 11742,
+ 15881, 28979, 18987, 20367, 5994, 23796, 1401, 28462, 23603, 23274,
+ 227, 3661, 30458, 7524, 3913, 14048, 568, 27651, 21656, 19626,
+ 9203, 8396, 7827, 4853, 19610, 31612, 15060, 14982, 23857, 16155,
+ 28173, 3024, 30893, 19924, 28820, 360, 1186, 14084, 5151, 26297,
+ 7451, 27537, 30412, 20217, 32713, 3197, 26468, 30812, 12897, 1979,
+ 24288, 28551, 26687, 30529, 13100, 1863, 27471, 30302, 26412, 30851,
+ 3117, 24910, 15357, 15983, 23947, 13068, 26493, 771, 16084, 30055,
+ 5133, 12204, 31246, 30552, 3477, 30273, 30981, 15763, 16329, 26168,
+ 21926, 24924, 27051, 25114, 18857, 20892, 10833, 2356, 16755, 10804,
+ 19177, 27024, 5690, 5521, 27130, 3619, 13162, 27776, 27629, 15688,
+ 11079, 2116, 21707, 31597, 32468, 31463, 28488, 9740, 7412, 8653,
+ 25857, 15070, 23760, 18063, 11266, 8011, 30584, 16902, 28043, 31780,
+ 17613, 21925, 18964, 404, 16286, 12044, 7822, 10068, 5393, 18907,
+ 12012, 15647, 17221, 9156, 23010, 24422, 2869, 30437, 14828, 9284,
+ 14816, 28244, 22419, 5300, 3239, 2299, 20716, 17922, 13558, 7846,
+ 6753, 10111, 16166, 15194, 15539, 22649, 24738, 17641, 13376, 6762,
+ 29001, 7875, 21890, 13168, 5140, 16399, 23257, 21757, 21241, 28666,
+ 32650, 23248, 12815, 7247, 19463, 30244, 32242, 32329, 30577, 6439,
+ 22889, 421, 603, 13997, 20038, 8698, 28369, 10790, 25998, 12877,
+ 14744, 23501, 2778, 17120, 30904, 29987, 16125, 6476, 17208, 14748,
+ 24039, 28367, 17961, 22424, 31690, 26855, 10982, 17812, 7547, 32,
+ 12953, 32674, 20506, 18730, 11009, 14614, 25589, 21550, 8307, 22147,
+ 20138, 5730, 28959, 17382, 30860, 4572, 9621, 31520, 31048, 12196,
+ 12936, 20138, 1993, 12, 2001, 19588, 8536, 21828, 4278, 19822,
+ 11272, 27689, 2413, 1115, 6225, 5982, 19932, 8739, 17915, 8350,
+ 1443, 24952, 12349, 21584, 20828, 3867, 9511, 27484, 23841, 25167,
+ 3133, 18238, 31823, 14735, 101, 13401, 12938, 3964, 16643, 9869,
+ 19970, 15385, 15970, 9227, 30452, 22074, 17750, 21096, 22643, 18746,
+ 3615, 23025, 18024, 29421, 12945, 4927, 1240, 24021, 20338, 13067,
+ 5221, 27545, 21796, 26691, 10264, 946, 19331, 8284, 10333, 6760,
+ 3345, 26091, 26447, 9213, 15697, 3439, 27190, 18472, 32368, 9329,
+ 27726, 27077, 10794, 22224, 32459, 22218, 4588, 15958, 27161, 13437,
+ 2614, 20622, 13416, 31716, 17732, 24282, 29032, 6781, 16621, 23744,
+ 16209, 2864, 19403, 24709, 5415, 31618, 26012, 4605, 17980, 20747,
+ 32488, 31649, 24310, 9002, 23525, 29154, 16082, 31991, 7831, 1213,
+ 5033, 31609, 15419, 12176, 6707, 7194, 25062, 15148, 18377, 20311,
+ 3178, 1579, 16751, 9148, 22393, 10116, 17425, 7440, 18445, 8028,
+ 25101, 3021, 5638, 2591, 14834, 30931, 14613, 2512, 2695, 31068,
+ 15578, 22941, 18448, 32563, 8265, 16311, 5836, 31009, 17490, 20832,
+ 20162, 22440, 11713, 15686, 27838, 18932, 7779, 4111, 5270, 18191,
+ 18794, 10037, 2225, 14164, 10002, 17940, 15050, 21030, 11141, 321,
+ 23026, 994, 25852, 29726, 468, 28689, 17704, 29867, 28477, 25571,
+ 6608, 14751, 24028, 19673, 30907, 9912, 29510, 1985, 8912, 13135,
+ 23356, 7143, 8828, 7983, 31025, 13962, 10580, 27047, 21255, 31373,
+ 28924, 16094, 6426, 30831, 9031, 20327, 28543, 25213, 3487, 17941,
+ 23694, 20806, 9128, 20497, 157, 11344, 5408, 27433, 31503, 2825,
+ 31498, 28267, 8334, 8704, 24587, 243, 26260, 4181, 10260, 29441,
+ 10288, 8559, 6977, 11599, 10247, 22252, 6145, 10913, 29593, 20190,
+ 12408, 12189, 3013, 23092, 14113, 13533, 30351, 22390, 32440, 14147,
+ 7714, 9654, 20823, 25228, 8465, 17347, 25311, 18984, 30690, 28575,
+ 17049, 9289, 5069, 23091, 4125, 15163, 23233, 17218, 30579, 2291,
+ 9384, 4508, 14457, 12522, 7660, 15252, 15748, 19500, 13114, 5043,
+ 1354, 15275, 27270, 19886, 25600, 29914, 19791, 20374, 24511, 31863,
+ 18468, 9039, 11308, 936, 9063, 7235, 2392, 23370, 31057, 1367,
+ 2533, 12678, 19766, 27423, 1131, 19877, 10250, 22093, 13337, 15909,
+ 24101, 2672, 19616, 11532, 25155, 7387, 1356, 20092, 18895, 30690,
+ 24436, 7560, 26209, 7757, 11285, 23366, 6277, 17158, 5306, 1061,
+ 16318, 2325, 11167, 12161, 27594, 32718, 18197, 3445, 13096, 12105,
+ 11304, 30449, 21208, 18707, 19584, 17420, 31586, 20771, 7045, 23707,
+ 28441, 21264, 16071, 14082, 21921, 30593, 7580, 14666, 26799, 3556,
+ 5131, 12404, 24080, 24163, 19688, 21005, 13037, 22547, 1857, 31747,
+ 15437, 28527, 19193, 9911, 8411, 16646, 20659, 15699, 8170, 19568,
+ 8433, 20574, 18870, 23430, 11901, 22158, 3308, 27091, 28681, 28637,
+ 15725, 8261, 15634, 24286, 30799, 14632, 29194, 11346, 2341, 24661,
+ 8117, 10487, 13441, 25511, 18900, 16800, 2999, 18351, 30977, 22922,
+ 11747, 5289, 9178, 7918, 6701, 28590, 13153, 3539, 30539, 21547,
+ 9891, 5414, 29768, 401, 6552, 4620, 9860, 29006, 13131, 5495,
+ 2301, 26877, 16186, 10232, 204, 31961, 30208, 32724, 2803, 5752,
+ 14641, 23897, 30549, 21430, 18054, 370, 21766, 20975, 9786, 29306,
+ 29637, 14705, 22707, 846, 7879, 7472, 1893, 20646, 29879, 700,
+ 15604, 10405, 250, 9841, 26776, 4270, 31287, 20461, 12486, 23930,
+ 18967, 19144, 22797, 4455, 16969, 22399, 16190, 29971, 8906, 10416,
+ 13263, 7722, 21859, 16525, 12673, 22652, 627, 17035, 14401, 9555,
+ 25326, 3418, 20300, 17667, 29606, 12570, 29335, 32450, 28105, 5580,
+ 28526, 6842, 10411, 26118, 29787, 16989, 18630, 4587, 22601, 15097,
+ 24576, 32347, 23785, 11916, 25388, 13415, 28757, 30425, 6354, 9480,
+ 12788, 7867, 25907, 21776, 16029, 3514, 6024, 1376, 2047, 4572,
+ 7307, 11100, 15168, 15293, 14904, 19868, 31460, 16610, 14549, 6372,
+ 28657, 22603, 7472, 16727, 30288, 17735, 22568, 999, 26743, 1165,
+ 3950, 23568, 20037, 20359, 25485, 16838, 29485, 27121, 22312, 940,
+ 10135, 28067, 15235, 4486, 12675, 2219, 17990, 19185, 12400, 24991,
+ 13437, 9810, 30844, 5682, 7906, 17420, 10444, 2052, 25439, 16886,
+ 302, 27583, 18383, 25356, 15101, 20063, 14853, 24420, 26950, 1233,
+ 20751, 28772, 9256, 14784, 29627, 27955, 897, 3500, 18523, 2925,
+ 11463, 32060, 20934, 6171, 30771, 469, 23967, 15586, 28965, 8299,
+ 10202, 9594, 13764, 23191, 22395, 6498, 31204, 13802, 14497, 24018,
+ 12590, 19842, 22468, 29682, 9338, 8666, 25147, 1865, 30336, 6886,
+ 28673, 8312, 23472, 28768, 6840, 28712, 2398, 27741, 1518, 17985,
+ 8226, 15395, 15520, 2396, 5503, 17214, 2044, 17020, 24770, 9425,
+ 9067, 4344, 28461, 30507, 29135, 6844, 9045, 21914, 6153, 19634,
+ 25545, 17540, 8383, 32634, 31988, 7091, 3420, 21601, 23109, 27377,
+ 30808, 24209, 23181, 3285, 11449, 27781, 17320, 23516, 22234, 1472,
+ 6495, 15803, 12907, 28863, 23437, 30964, 22969, 21804, 28545, 2216,
+ 6703, 20052, 14500, 25260, 29213, 475, 9307, 25567, 7097, 3758,
+ 11567, 22202, 18788, 26682, 6444, 18472, 30510, 29148, 30598, 7832,
+ 30107, 28312, 8579, 10065, 4520, 6413, 17044, 3590, 32265, 30632,
+ 11205, 29355, 25013, 16665, 30296, 4487, 12196, 25859, 14765, 12681,
+ 11223, 3320, 22630, 19679, 16794, 10660, 10440, 10181, 3846, 24648,
+ 31843, 18843, 18889, 27755, 19189, 3131, 24874, 18892, 1164, 13705,
+ 327, 15002, 20203, 20300, 23457, 32231, 12847, 12604, 22747, 19035,
+ 30898, 29019, 6079, 24869, 17968, 11913, 23938, 19767, 10792, 26963,
+ 23369, 8883, 12677, 24333, 27883, 21152, 15230, 6944, 13561, 26338,
+ 5563, 12964, 14844, 14953, 9145, 24114, 26877, 424, 5487, 26099,
+ 8523, 14153, 28978, 5117, 11640, 16671, 29910, 8416, 19877, 24924,
+ 4630, 20091, 14079, 18436, 2613, 9493, 11402, 22689, 27878, 1705,
+ 5406, 30777, 32362, 3200, 12975, 30589, 18680, 25349, 24273, 27971,
+ 23905, 6102, 28794, 5430, 1780, 3607, 12042, 1740, 30367, 3339,
+ 30346, 22649, 10584, 7397, 28977, 803, 3515, 9691, 2605, 6613,
+ 11509, 1405, 32160, 10679, 23264, 3653, 10728, 22078, 12655, 9583,
+ 1571, 1440, 23373, 29450, 25074, 12683, 29121, 22608, 21118, 12310,
+ 29141, 8243, 28857, 2296, 3255, 7736, 19687, 10999, 22367, 12168,
+ 15196, 5540, 7538, 21061, 24199, 19270, 23399, 18202, 4655, 7956,
+ 9192, 28950, 7165, 13223, 29819, 26554, 17723, 15790, 15713, 28496,
+ 16859, 24292, 8382, 19327, 2235, 11583, 11515, 8221, 295, 14954,
+ 5737, 21572, 10656, 12150, 13351, 11176, 7131, 20685, 17477, 2599,
+ 4621, 32359, 15145, 5538, 20838, 1088, 8754, 10764, 7643, 20233,
+ 18844, 21440, 6953, 22813, 20900, 17432, 16151, 25528, 20204, 29755,
+ 14587, 20579, 3616, 27190, 29311, 11955, 15066, 21583, 3493, 21043,
+ 28099, 28309, 1033, 1183, 26108, 26300, 19303, 10323, 29116, 12840,
+ 9052, 24322, 19002, 2632, 28785, 2219, 26317, 805, 18517, 11977,
+ 2897, 28731, 4970, 12235, 5582, 2951, 26499, 16067, 20308, 4833,
+ 32749, 2914, 17449, 20364, 30380, 9764, 26407, 15372, 8966, 29896,
+ 1119, 15415, 16710, 19203, 18178, 7055, 18362, 31605, 22146, 17871,
+ 3326, 29916, 20212, 28100, 9084, 16264, 6329, 5726, 3636, 28431,
+ 25437, 12807, 12985, 23617, 18367, 19507, 11388, 15198, 21874, 28985,
+ 25933, 25223, 3940, 18529, 5919, 21619, 7101, 5182, 6924, 25443,
+ 11018, 3390, 10649, 88, 23195, 19071, 28730, 2691, 5673, 11492,
+ 8217, 13053, 15549, 105, 23059, 18616, 3276, 18355, 7171, 182,
+ 7079, 26092, 4932, 3704, 23571, 6861, 30833, 8378, 30771, 1276,
+ 22639, 5725, 687, 7833, 28334, 32677, 17167, 26643, 29867, 16292,
+ 8552, 13633, 2746, 25078, 30011, 20654, 7682, 30895, 15258, 26932,
+ 28617, 5778, 30860, 32204, 8690, 14724, 18355, 15268, 27843, 14656,
+ 24620, 626, 25068, 3659, 4023, 777, 24773, 1323, 28952, 11305,
+ 8152, 12756, 25021, 22940, 28575, 14179, 31392, 31102, 6799, 14350,
+ 4207, 7133, 1621, 347, 32491, 8322, 31327, 18577, 17294, 30477,
+ 12190, 2924, 11120, 9544, 3466, 26901, 6251, 1973, 14439, 1873,
+ 8573, 105, 21703, 22521, 4719, 2077, 9297, 21162, 3764, 21891,
+ 24512, 30397, 23444, 3798, 29231, 10618, 5514, 14773, 31123, 17544,
+ 21738, 23857, 12425, 26792, 1478, 2597, 9554, 26788, 30483, 15814,
+ 25115, 24705, 25864, 21114, 27266, 19708, 711, 29422, 12887, 14133,
+ 18239, 17250, 29087, 18597, 337, 13640, 31199, 23381, 30513, 14606,
+ 28823, 23122, 5392, 16952, 4876, 1628, 28408, 20913, 26442, 29406,
+ 6647, 31331, 32362, 20259, 8319, 5125, 11281, 20422, 5645, 4148,
+ 22329, 19562, 3593, 9670, 18484, 26028, 31213, 18011, 6125, 18262,
+ 12970, 4660, 9330, 23253, 12616, 15945, 11951, 32238, 15052, 8341,
+ 1404, 4524, 862, 22197, 25051, 30109, 3243, 15025, 22650, 17214,
+ 17289, 6682, 1152, 23987, 8409, 25429, 20358, 10683, 20914, 15670,
+ 31458, 484, 10940, 15569, 20012, 15099, 27353, 11660, 3835, 19655,
+ 4363, 8057, 9712, 29431, 18834, 12259, 5366, 23128, 13908, 16423,
+ 8903, 11851, 5762, 3781, 24499, 6775, 4473, 26295, 26525, 5307,
+ 10470, 22786, 1350, 870, 5678, 13450, 6862, 5035, 5901, 12330,
+ 29559, 21583, 28029, 31492, 25261, 26789, 5849, 10006, 21571, 26556,
+ 32322, 8719, 12800, 15319, 11842, 12384, 16986, 5661, 17839, 7829,
+ 25729, 19090, 13266, 7398, 19871, 10310, 32713, 30985, 11102, 8653,
+ 7978, 10827, 20396, 23022, 8169, 25567, 18875, 26783, 10620, 8566,
+ 4171, 27698, 6460, 25104, 8491, 15049, 15887, 1297, 14845, 18447,
+ 30532, 32151, 3643, 4906, 15038, 20491, 7799, 12523, 18005, 3574,
+ 5351, 17992, 121, 17430, 19232, 1805, 19480, 3762, 23842, 3278,
+ 21442, 18474, 28053, 6688, 4108, 1490, 32594, 7689, 3378, 22272,
+ 2085, 2996, 13312, 31332, 8401, 23145, 6642, 32152, 30293, 16829,
+ 7322, 31480, 24686, 1542, 19522, 27060, 16733, 26898, 27091, 13348,
+ 4842, 4889, 31733, 2139, 17577, 2031, 16248, 5886, 20348, 31870,
+ 30451, 13399, 8793, 8308, 23978, 4005, 19534, 12345, 16821, 29878,
+ 1986, 25380, 2399, 19384, 2813, 2542, 10189, 19277, 16875, 29031,
+ 17632, 4317, 21788, 23911, 7259, 4912, 8720, 12296, 22601, 9020,
+ 2226, 4370, 27289, 28475, 12834, 10679, 10764, 15361, 13495, 18561,
+ 13905, 18573, 14661, 392, 26478, 4062, 1435, 7912, 19553, 23816,
+ 4176, 30066, 32007, 25990, 448, 29090, 17214, 24018, 18001, 28881,
+ 24390, 15411, 5627, 15020, 27502, 7638, 5383, 12005, 8940, 545,
+ 29206, 31529, 4108, 20548, 9574, 27985, 25997, 23313, 13649, 13788,
+ 1863, 22285, 9238, 11933, 1554, 30407, 27356, 31153, 4836, 8552,
+ 9716, 3252, 11577, 30604, 22111, 31796, 4280, 6736, 23696, 7014,
+ 9747, 26796, 4210, 17432, 31535, 9988, 6829, 23271, 1669, 17657,
+ 29478, 25522, 14792, 13701, 10436, 14927, 10183, 3399, 22138, 17276,
+ 16790, 23323, 27010, 10776, 28392, 28398, 7398, 31891, 1472, 721,
+ 20037, 16035, 25929, 31307, 4052, 17208, 14337, 11252, 7075, 25267,
+ 8477, 26943, 3106, 24914, 22826, 14488, 32227, 6639, 32240, 30127,
+ 32417, 16619, 6555, 19475, 28034, 21349, 9501, 16386, 12441, 1711,
+ 2510, 14720, 25519, 19458, 26197, 17830, 25667, 15472, 6860, 573,
+ 24271, 283, 24607, 26507, 16717, 2981, 28341, 25709, 14074, 13031,
+ 30803, 166, 4442, 2022, 31037, 31095, 17020, 30466, 9374, 3184,
+ 19583, 2417, 28713, 25733, 19029, 23276, 769, 23908, 30151, 6056,
+ 3030, 4358, 20153, 5768, 16977, 25476, 18352, 25489, 6067, 301,
+ 7057, 20126, 23225, 725, 12460, 21077, 21186, 11375, 11512, 26457,
+ 5683, 31199, 8096, 6081, 8219, 28169, 25535, 26314, 26899, 22574,
+ 8296, 24776, 1897, 888, 2538, 26467, 6781, 1235, 18514, 3583,
+ 1386, 6911, 10033, 6780, 15593, 21731, 29343, 32288, 11379, 29221,
+ 9599, 23249, 30374, 12791, 19717, 26760, 5354, 1076, 17782, 20226,
+ 6740, 20651, 13359, 18361, 7627, 18619, 25321, 7186, 3945, 30496,
+ 24635, 21464, 32035, 524, 2400, 10217, 2733, 21369, 24891, 3375,
+ 8344, 7102, 22680, 27602, 5822, 25185, 27573, 22188, 24031, 6445,
+ 14593, 22270, 27788, 25988, 29987, 8289, 29508, 5110, 24638, 16639,
+ 7134, 27154, 8308, 8706, 22566, 19067, 9641, 27725, 971, 24383,
+ 31369, 9578, 23929, 15973, 9932, 6340, 6978, 15557, 1720, 24855,
+ 7746, 25373, 15336, 9764, 2435, 14688, 6989, 25257, 16414, 23633,
+ 15474, 18064, 3747, 4433, 3588, 2407, 955, 19573, 5009, 16656,
+ 15372, 23772, 12432, 4282, 9565, 13120, 9378, 17424, 31995, 30410,
+ 7447, 10927, 3419, 23595, 32692, 18398, 28416, 29416, 21171, 10873,
+ 20639, 23797, 26124, 303, 2690, 9350, 8691, 16110, 298, 9250,
+ 7842, 25498, 6968, 13561, 26968, 15621, 20110, 6007, 6818, 13340,
+ 2225, 18969, 8665, 31326, 30321, 17024, 27116, 11155, 28365, 15556,
+ 15199, 14266, 1297, 5386, 32660, 10563, 1601, 24409, 18762, 7038,
+ 26042, 12713, 18019, 30036, 23831, 21565, 32490, 15413, 17234, 19507,
+ 1364, 4945, 24363, 29786, 31750, 15115, 14542, 6211, 5144, 9386,
+ 11952, 17819, 26969, 28242, 20922, 18359, 24467, 23348, 19625, 369,
+ 25872, 7169, 23221, 6451, 15964, 31652, 4464, 11089, 16205, 17456,
+ 498, 30364, 5441, 28695, 30003, 14132, 1703, 31646, 18360, 9117,
+ 19393, 27277, 10354, 16405, 25767, 22059, 16099, 31781, 4240, 5993,
+ 31874, 20087, 19021, 24926, 7521, 17127, 28182, 24563, 7181, 11996,
+ 27785, 12000, 7349, 32729, 12016, 15575, 5007, 22607, 4291, 28414,
+ 10872, 28342, 4718, 6307, 10715, 25307, 10579, 6956, 26835, 32124,
+ 20755, 16972, 2196, 3602, 16905, 12413, 32519, 23278, 28952, 28586,
+ 13492, 22407, 15527, 31275, 14821, 5395, 27369, 20471, 22280, 8532,
+ 23906, 27669, 31830, 18357, 7591, 11860, 21682, 26773, 10085, 3388,
+ 32724, 23267, 5028, 9284, 14246, 3051, 2381, 29254, 25838, 20847,
+ 5866, 23599, 26414, 8698, 22958, 18427, 5064, 10097, 5557, 25569,
+ 12390, 24555, 9100, 28106, 27801, 16578, 22260, 3848, 7873, 4075,
+ 17123, 8261, 18476, 26498, 32460, 27065, 9346, 6057, 20768, 13217,
+ 18528, 23187, 25365, 15084, 4931, 3804, 24998, 24119, 30888, 27676,
+ 12251, 5883, 25713, 26043, 3658, 4869, 16011, 12295, 23518, 551,
+ 20942, 7043, 21463, 27694, 6692, 14978, 27922, 8979, 15854, 1269,
+ 16011, 9590, 13987, 28290, 3360, 1351, 27834, 8918, 26264, 9927,
+ 19147, 23611, 28131, 27567, 3057, 2157, 15523, 7854, 18802, 12201,
+ 32236, 13081, 2978, 21000, 9800, 11487, 25092, 12043, 27903, 17595,
+ 18099, 11127, 27285, 7341, 20736, 18787, 147, 6314, 31581, 26255,
+ 28299, 12179, 122, 13559, 14422, 18532, 5037, 8616, 16800, 30638,
+ 30871, 7635, 17063, 12615, 15877, 32288, 31295, 16959, 8212, 25668,
+ 16666, 10007, 21913, 26326, 25158, 4654, 19647, 27486, 23799, 13948,
+ 6898, 26288, 29575, 10882, 9212, 30584, 11195, 30593, 15470, 3861,
+ 9288, 10475, 19266, 7339, 25493, 28695, 11966, 28275, 963, 12344,
+ 26780, 15702, 24555, 1680, 21863, 5819, 9894, 8929, 29480, 6301,
+ 30163, 1061, 31554, 13280, 25492, 28030, 21403, 26853, 6298, 10096,
+ 6908, 12892, 24483, 24910, 21691, 4697, 20032, 18162, 30615, 30122,
+ 27356, 7857, 25571, 24937, 29690, 911, 1255, 7885, 11454, 4014,
+ 8579, 22853, 21167, 2829, 8213, 25288, 8379, 29295, 16797, 4710,
+ 892, 27288, 6175, 28964, 25273, 29631, 15433, 10502, 9264, 28993,
+ 1622, 27245, 19346, 22931, 20018, 15267, 23504, 8826, 30431, 26293,
+ 23957, 15742, 18711, 31105, 12051, 14492, 24883, 3087, 259, 22331,
+ 13387, 16677, 9447, 14177, 28831, 13589, 4243, 22311, 15669, 20186,
+ 15083, 3690, 7364, 10083, 13806, 20676, 30673, 31535, 10740, 19386,
+ 4632, 23066, 5683, 13623, 28461, 2423, 31368, 24122, 27235, 19550,
+ 20085, 24011, 1517, 1607, 26982, 26675, 13635, 27608, 16440, 9836,
+ 9928, 13820, 7163, 8663, 20649, 2869, 11767, 6189, 17672, 4915,
+ 9454, 19384, 4442, 26789, 10145, 9155, 11533, 23887, 22677, 12623,
+ 15214, 17501, 18199, 27655, 9419, 14071, 29054, 15222, 19156, 1813,
+ 15536, 8312, 23623, 21653, 1256, 4846, 3021, 30859, 11190, 26550,
+ 11807, 15064, 18247, 21211, 876, 1534, 22246, 23048, 12287, 3378,
+ 8387, 19267, 10269, 6323, 7411, 3031, 4908, 27739, 4537, 21394,
+ 27163, 31859, 17668, 10289, 21757, 25804, 26424, 11545, 3063, 22027,
+ 6961, 6984, 16221, 27973, 16262, 30090, 19224, 10700, 23818, 19696,
+ 14667, 30024, 24217, 10622, 22582, 29193, 30225, 27428, 26458, 923,
+ 21150, 14064, 8157, 17819, 3131, 17537, 7217, 25802, 26741, 8127,
+ 25329, 3680, 23666, 13001, 6411, 27043, 28723, 11311, 7972, 20407,
+ 26390, 5474, 7736, 13752, 20895, 11624, 18305, 32006, 27767, 23508,
+ 19355, 7648, 28853, 20470, 19685, 24629, 14685, 8271, 20778, 5814,
+ 25126, 32327, 30337, 4144, 17281, 21027, 28529, 13081, 28630, 21297,
+ 2649, 30569, 5649, 28741, 18447, 12971, 27997, 7273, 17864, 27219,
+ 3631, 21457, 32312, 8274, 23687, 27917, 9722, 19944, 26483, 2690,
+ 10033, 185, 25044, 16411, 112, 20004, 6244, 16700, 2775, 4304,
+ 2296, 11000, 27519, 9351, 32515, 16003, 13337, 5192, 22876, 8170,
+ 30417, 28311, 23873, 27905, 20857, 13336, 15003, 16541, 13283, 5212,
+ 9603, 30212, 25998, 27899, 10502, 16546, 3717, 16099, 5925, 27646,
+ 18309, 3567, 14880, 22508, 30046, 24252, 10997, 1283, 29595, 18104,
+ 28963, 17745, 21093, 17019, 20403, 25934, 11173, 18011, 25465, 24847,
+ 21353, 15674, 30360, 31164, 26505, 27043, 11588, 16196, 650, 23830,
+ 28620, 25167, 5570, 31135, 13783, 25205, 11965, 12717, 5869, 27821,
+ 11232, 31266, 17466, 32264, 9292, 8871, 20367, 7839, 1798, 2114,
+ 25514, 18633, 13652, 22058, 20919, 20626, 7274, 18650, 6167, 24425,
+ 4677, 10084, 18015, 22553, 31192, 26376, 25252, 14075, 29286, 11525,
+ 13302, 17001, 5679, 8879, 5674, 8053, 3150, 20418, 15069, 7899,
+ 29154, 28406, 31669, 22069, 24172, 28883, 8682, 22894, 1912, 8391,
+ 18181, 10361, 18304, 8310, 13032, 9539, 3085, 11601, 23311, 9702,
+ 28447, 25706, 26389, 30495, 32719, 30854, 24186, 25346, 32307, 3700,
+ 25507, 4076, 3714, 13214, 8226, 19386, 10104, 8926, 17976, 5944,
+ 16380, 19347, 19352, 1500, 1, 20211, 16750, 17845, 30890, 26531,
+ 28064, 25502, 10161, 28549, 2388, 8119, 18953, 30673, 18610, 26134,
+ 16834, 10087, 4075, 16313, 4910, 21347, 31098, 20415, 15682, 1522,
+ 4522, 12504, 28990, 26469, 27480, 18171, 28049, 15748, 29178, 22871,
+ 32758, 29989, 7392, 2187, 29412, 27133, 26554, 29977, 27173, 24757,
+ 13403, 10776, 29380, 26432, 31164, 8234, 18989, 3949, 25668, 27822,
+ 8336, 14264, 19270, 28983, 23174, 22118, 8140, 7996, 5623, 31441,
+ 14483, 9233, 30267, 30976, 8022, 4373, 31615, 29562, 17231, 21550,
+ 26987, 14172, 13564, 5234, 258, 7850, 20255, 18215, 4553, 27875,
+ 28936, 4334, 9771, 23000, 11798, 18235, 20252, 16061, 5756, 9736,
+ 21245, 6529, 32065, 3531, 17343, 23131, 24459, 23973, 16460, 12198,
+ 20764, 15836, 25890, 17390, 4637, 28299, 12353, 8779, 12826, 28312,
+ 23624, 13549, 25679, 3815, 30427, 4601, 26914, 17869, 13895, 2708,
+ 12528, 22216, 21097, 12348, 7180, 8813, 25804, 17503, 31749, 12961,
+ 5137, 17958, 14888, 22284, 3732, 4754, 18246, 26059, 6220, 19147,
+ 14520, 29797, 12275, 29877, 13983, 7425, 3943, 2499, 8048, 9174,
+ 2897, 26640, 1201, 4322, 5636, 22956, 25853, 4575, 27048, 9779,
+ 18254, 14451, 7575, 25253, 7036, 26791, 11015, 29553, 1024, 2970,
+ 9450, 29907, 27902, 23159, 10002, 32096, 5251, 21924, 16537, 28384,
+ 26635, 15420, 23936, 18779, 23366, 6080, 29590, 13431, 7195, 12297,
+ 30363, 13057, 18414, 31617, 22438, 13513, 1566, 24467, 5060, 31411,
+ 11218, 21856, 5602, 267, 19702, 18100, 28653, 25625, 24192, 14136,
+ 12087, 29429, 19960, 3561, 20509, 25757, 12855, 4808, 5351, 25413,
+ 31087, 29907, 17391, 25070, 14443, 27701, 4358, 28730, 32536, 19642,
+ 13843, 127, 22085, 7301, 32509, 21530, 19111, 773, 19659, 518,
+ 10528, 9253, 21514, 19373, 20544, 15299, 6767, 13309, 15117, 3428,
+ 30654, 3263, 10495, 31782, 7658, 28196, 1871, 24310, 27774, 19617,
+ 32626, 25858, 4923, 8445, 20192, 7793, 18435, 22185, 19481, 32082,
+ 5110, 29775, 15594, 25299, 31706, 12973, 25068, 3252, 1984, 30116,
+ 23375, 30459, 28132, 23436, 19157, 1512, 25814, 22219, 22305, 3115,
+ 24791, 1446, 29746, 341, 16518, 15447, 5419, 31885, 11452, 30047,
+ 11093, 18308, 12212, 7197, 5734, 7595, 18287, 26016, 27140, 27555,
+ 30550, 11194, 11397, 8948, 7458, 32341, 29433, 30211, 3321, 24330,
+ 32362, 4158, 14553, 23280, 15970, 7834, 26426, 30386, 23726, 15423,
+ 15599, 8421, 13922, 6017, 7758, 7832, 26141, 25363, 11152, 9772,
+ 17294, 26487, 23675, 7270, 31799, 18617, 32574, 10178, 10609, 21597,
+ 7836, 3594, 1969, 27542, 4940, 4136, 13065, 23993, 17568, 14393,
+ 3314, 18160, 23654, 19938, 12104, 18227, 29196, 25831, 4246, 9588,
+ 28935, 14841, 15764, 13082, 15988, 20944, 19438, 945, 25088, 3706,
+ 27207, 19680, 13830, 12019, 12670, 667, 25336, 27893, 6960, 921,
+ 10752, 11537, 16766, 27145, 17127, 29951, 19472, 21633, 20789, 7219,
+ 11865, 15159, 13466, 27312, 6941, 9587, 14476, 6689, 20785, 21316,
+ 26418, 27942, 9603, 12147, 897, 20716, 28250, 7605, 28325, 15616,
+ 13278, 31012, 31906, 17765, 18906, 22256, 31803, 4836, 14017, 24914,
+ 30227, 13731, 3055, 24258, 26386, 1529, 4914, 14698, 31242, 1921,
+ 30089, 6874, 1178, 621, 16171, 28669, 19283, 18205, 25803, 26956,
+ 20762, 20465, 11803, 19265, 13773, 13659, 10639, 8975, 26666, 10296,
+ 3427, 13200, 12012, 26208, 10719, 11903, 19766, 23931, 20698, 3559,
+ 17973, 28695, 22141, 8667, 1026, 4344, 3913, 9832, 26053, 10415,
+ 28507, 30152, 31008, 31087, 12015, 10968, 25291, 29979, 6180, 18381,
+ 14971, 14755, 25087, 13602, 24073, 10129, 15537, 11476, 32720, 18143,
+ 29469, 26066, 29783, 28172, 17813, 5039, 816, 24431, 25060, 3739,
+ 16159, 20682, 7314, 14225, 10623, 4386, 20323, 27858, 9442, 16590,
+ 289, 8849, 31480, 20431, 15003, 29680, 31154, 13919, 11502, 16427,
+ 27558, 7116, 3331, 10259, 28598, 24455, 18521, 32703, 29676, 14456,
+ 30469, 2174, 22441, 24213, 12023, 1807, 30975, 29363, 7294, 2581,
+ 12635, 6300, 1039, 29893, 1383, 30561, 4418, 8674, 3118, 5106,
+ 5917, 13035, 20866, 14827, 9621, 24467, 14234, 26289, 6226, 22897,
+ 7168, 27326, 691, 6137, 17323, 13625, 7442, 8363, 21095, 32202,
+ 5961, 8074, 20862, 16556, 29812, 25552, 2449, 16644, 21497, 5344,
+ 13255, 1393, 19398, 13180, 17962, 740, 14298, 15160, 24397, 27058,
+ 8967, 30766, 5426, 18663, 11510, 25844, 11116, 31710, 4459, 9419,
+ 29825, 5646, 13514, 28185, 25234, 16679, 23003, 31002, 2878, 16734,
+ 25802, 18130, 8899, 5124, 20338, 21574, 12902, 23646, 13018, 3563,
+ 3606, 4785, 2560, 5983, 19788, 10652, 4566, 15191, 19253, 7594,
+ 27275, 6105, 29203, 9000, 24075, 23211, 21985, 26164, 28617, 8715,
+ 25141, 4375, 6588, 21920, 8043, 3285, 23207, 2993, 21248, 12290,
+ 31134, 20117, 32572, 20438, 8902, 22122, 1556, 26500, 16732, 2826,
+ 29518, 18888, 15097, 25147, 12774, 4287, 28692, 28198, 12465, 16380,
+ 9672, 12299, 14912, 19672, 15575, 818, 1031, 265, 23024, 13349,
+ 14526, 27511, 25389, 6172, 520, 21323, 30432, 14521, 21843, 24904,
+ 16271, 26613, 2047, 29534, 18749, 20571, 28354, 20092, 15339, 21876,
+ 3147, 8871, 8031, 22658, 4901, 5449, 3108, 13680, 16095, 17867,
+ 28114, 3082, 18538, 101, 14992, 10602, 31170, 4917, 17366, 9650,
+ 9424, 31119, 1144, 2561, 400, 20885, 4064, 4767, 14191, 20487,
+ 1690, 24955, 5623, 9820, 13335, 13528, 16557, 3857, 14762, 30275,
+ 21050, 29761, 27351, 13768, 15050, 25718, 16077, 25957, 23986, 18879,
+ 31537, 26815, 12885, 5890, 31773, 19732, 27720, 24468, 15721, 15729,
+ 28340, 3335, 2345, 1829, 3836, 10051, 28534, 17013, 27296, 25304,
+ 27506, 29585, 21602, 27027, 22918, 14279, 7335, 4432, 8942, 21239,
+ 14623, 29966, 17016, 12615, 4008, 9289, 1672, 12567, 26736, 23684,
+ 13408, 18744, 19290, 293, 28830, 24408, 19620, 17797, 4358, 25281,
+ 3270, 15688, 15234, 32580, 28573, 18154, 30311, 31855, 20168, 1179,
+ 3578, 7431, 11091, 22349, 29491, 4786, 8850, 4107, 30657, 23027,
+ 10832, 19340, 2893, 4699, 22570, 11272, 24067, 9982, 14389, 25930,
+ 3151, 23333, 30439, 20231, 14308, 3906, 25140, 29038, 12803, 21033,
+ 1527, 16384, 6906, 4732, 26516, 30370, 6891, 1127, 9435, 19696,
+ 6094, 3982, 31280, 29653, 3257, 22852, 29673, 4440, 26207, 16126,
+ 20216, 11961, 2264, 21767, 19658, 19645, 25248, 15733, 32367, 4678,
+ 12513, 27483, 19194, 18726, 22773, 9792, 13611, 7477, 31526, 25040,
+ 9291, 20898, 8889, 15826, 13400, 24710, 14124, 16986, 20834, 14527,
+ 4795, 11328, 8757, 3579, 25129, 24016, 1592, 28435, 12732, 18371,
+ 10901, 5787, 19338, 24175, 31386, 10679, 19187, 28474, 28512, 22831,
+ 2415, 27220, 682, 6342, 18570, 29862, 18703, 24776, 15660, 22021,
+ 30556, 11747, 24606, 6060, 22324, 13111, 10186, 26345, 28409, 29360,
+ 3906, 4118, 24816, 12180, 3716, 9675, 17823, 28504, 26621, 10322,
+ 1402, 31928, 28491, 16731, 30143, 8455, 11591, 26609, 15519, 1987,
+ 1347, 173, 16542, 108, 16272, 20010, 10044, 4758, 7492, 17848,
+ 9941, 6206, 22841, 7253, 12230, 21082, 14937, 8153, 12497, 11187,
+ 6937, 12400, 31427, 7671, 2628, 28237, 1875, 27914, 26874, 28573,
+ 10062, 11422, 10744, 4794, 23537, 17411, 5658, 16546, 24470, 25664,
+ 14877, 13223, 8596, 9314, 25002, 5736, 14688, 14356, 17296, 3839,
+ 5368, 29808, 17234, 2684, 26241, 5909, 27617, 23699, 5422, 890,
+ 1962, 1937, 13669, 27266, 31187, 16532, 19485, 4176, 15554, 1020,
+ 24971, 9308, 10720, 19997, 9981, 24518, 28316, 19510, 13318, 24043,
+ 21170, 6567, 7899, 25399, 13229, 23902, 29693, 1594, 22954, 23443,
+ 20760, 28413, 2400, 20405, 10027, 8342, 30557, 8868, 26602, 250,
+ 146, 20768, 8801, 4883, 19474, 5762, 21209, 5906, 14871, 12201,
+ 27135, 1287, 17478, 19000, 20291, 5550, 13108, 29695, 25215, 19852,
+ 19752, 7862, 16601, 15931, 25123, 3057, 20714, 29187, 22813, 13648,
+ 23072, 13738, 8850, 1270, 11104, 13452, 13373, 29245, 5360, 6894,
+ 29220, 22184, 14741, 12943, 10452, 3866, 31480, 11648, 31982, 15685,
+ 1358, 4918, 29666, 15716, 15928, 990, 31227, 9261, 6888, 17904,
+ 2460, 22785, 8582, 20999, 22473, 8295, 6610, 20720, 10728, 10936,
+ 12554, 16384, 14537, 31516, 5390, 12203, 17637, 15028, 19138, 20563,
+ 16355, 19481, 17332, 16734, 12129, 13062, 30463, 22155, 11504, 9297,
+ 367, 18310, 10080, 21024, 4325, 32186, 18751, 18521, 7933, 29798,
+ 10396, 27994, 16111, 24307, 9232, 31467, 691, 2437, 4352, 880,
+ 15209, 10192, 7964, 22372, 6391, 1581, 5419, 24322, 27892, 20716,
+ 19211, 15429, 5317, 26092, 1267, 18707, 20229, 25706, 5116, 17845,
+ 43, 28439, 24544, 19339, 10854, 21613, 15873, 22526, 7372, 4418,
+ 14765, 949, 7604, 24990, 12704, 14860, 5216, 21450, 28362, 1218,
+ 30176, 4521, 6227, 16369, 31026, 21579, 10461, 19012, 22190, 13760,
+ 18697, 1380, 5794, 21802, 13116, 15027, 13113, 278, 1187, 14397,
+ 4513, 23565, 8052, 14828, 5740, 12133, 631, 29435, 22839, 24669,
+ 14790, 19372, 15242, 15210, 19665, 10046, 26368, 2507, 19876, 17945,
+ 30376, 9571, 28013, 6221, 20394, 32456, 14904, 5178, 27950, 18840,
+ 27134, 26000, 9081, 17164, 22238, 2171, 7769, 18127, 4266, 9495,
+ 7876, 9744, 10149, 16170, 15292, 29910, 5259, 3602, 10869, 16787,
+ 25042, 4348, 20922, 27389, 31280, 13143, 11405, 2073, 16477, 5513,
+ 16398, 5784, 21530, 19936, 10398, 25447, 10354, 13771, 579, 24962,
+ 20288, 5962, 12366, 25353, 7665, 20131, 18492, 26773, 3979, 13399,
+ 9179, 31436, 2030, 25428, 24238, 16947, 23643, 12140, 17041, 20804,
+ 17714, 24582, 26528, 21697, 7424, 787, 2902, 7751, 4280, 27716,
+ 25330, 15654, 9537, 13434, 27935, 6512, 13873, 19839, 1747, 17744,
+ 20953, 32243, 18296, 30877, 5761, 22921, 26698, 27311, 29940, 2419,
+ 15104, 32370, 31808, 31002, 29614, 29880, 4791, 15123, 18922, 6356,
+ 16441, 14926, 13614, 7012, 28086, 2961, 18557, 3950, 15854, 29477,
+ 29001, 15791, 25467, 29392, 7573, 16943, 6162, 29699, 3415, 10265,
+ 6406, 25171, 21280, 30666, 19725, 18989, 18430, 27432, 30535, 20422,
+ 30370, 15413, 7036, 4690, 16830, 16868, 30630, 20342, 18865, 20267,
+ 13999, 23295, 21862, 2137, 16507, 16084, 17017, 8874, 19241, 5929,
+ 16540, 16920, 4502, 32502, 23610, 26997, 21283, 8360, 7258, 12471,
+ 185, 16150, 14277, 13715, 15114, 19126, 9579, 31309, 1561, 22289,
+ 3075, 9934, 22012, 1140, 21746, 24567, 22752, 12777, 26222, 10549,
+ 8783, 2917, 18659, 1109, 7086, 18499, 15253, 17306, 24074, 11761,
+ 31880, 16909, 22804, 10986, 18333, 30229, 27497, 7652, 20733, 4679,
+ 20503, 7498, 16058, 10367, 1373, 21228, 26036, 816, 4275, 16374,
+ 19898, 10488, 17418, 32030, 16626, 15992, 26709, 19234, 27259, 14946,
+ 29000, 1906, 18512, 8147, 7776, 22825, 29808, 13028, 11555, 10818,
+ 2364, 23420, 169, 16649, 9504, 10856, 25179, 3535, 20853, 13485,
+ 16379, 226, 20646, 14620, 2789, 31933, 6034, 17448, 7316, 14459,
+ 30258, 17909, 17511, 9874, 13180, 20145, 25253, 13245, 8327, 25895,
+ 13504, 29242, 26351, 11153, 14038, 1334, 5755, 18094, 15997, 24710,
+ 13821, 15125, 12992, 12439, 23418, 13513, 1381, 32424, 3979, 27917,
+ 20850, 25910, 3, 8826, 17135, 26808, 17874, 22350, 11244, 18573,
+ 16938, 18951, 27334, 23603, 22240, 23601, 1447, 20665, 32276, 23420,
+ 8012, 23159, 1300, 24849, 10507, 12028, 28286, 15142, 30228, 23368,
+ 16293, 5328, 5111, 19004, 15670, 20505, 3174, 3918, 23324, 18003,
+ 29756, 18817, 25504, 25260, 27583, 12949, 6613, 19202, 29730, 11898,
+ 23347, 2808, 15951, 28427, 1154, 30025, 22243, 32761, 7674, 12124,
+ 21369, 20229, 4776, 6937, 25899, 1139, 30483, 4860, 29782, 16315,
+ 8992, 11367, 10654, 3201, 9011, 29757, 2098, 9159, 17559, 22956,
+ 32081, 19810, 16672, 15178, 2318, 30122, 19982, 19044, 25680, 19318,
+ 4661, 14482, 18460, 31304, 18267, 25487, 14871, 21700, 2786, 29512,
+ 582, 871, 8615, 7731, 11801, 2933, 13097, 2018, 17576, 16947,
+ 16366, 28120, 4156, 87, 22306, 5787, 8465, 10685, 20354, 14091,
+ 27994, 23899, 1912, 16881, 12934, 24951, 28807, 21979, 31682, 8215,
+ 27114, 15656, 29119, 18362, 11896, 13407, 22453, 25669, 22987, 27333,
+ 22952, 1088, 18593, 28974, 4074, 15938, 22658, 2835, 23521, 10922,
+ 19108, 5605, 522, 9616, 19979, 31393, 9534, 27900, 29940, 23973,
+ 1844, 28501, 6516, 194, 12872, 24092, 30045, 2962, 28794, 22746,
+ 29025, 11787, 13242, 17494, 28538, 20821, 21347, 8716, 5257, 19161,
+ 17157, 31707, 21821, 17819, 9831, 14334, 18998, 21961, 26316, 26941,
+ 3946, 27284, 11638, 28516, 13000, 4670, 26473, 31733, 30236, 17524,
+ 13937, 20250, 26675, 9951, 29542, 16605, 6463, 32758, 9647, 27291,
+ 28284, 19478, 5125, 1206, 22804, 10452, 21113, 19595, 29761, 2706,
+ 29113, 1700, 20145, 28752, 13199, 28974, 25390, 2501, 26794, 15021,
+ 1150, 942, 23457, 20718, 16520, 28263, 27957, 7229, 32441, 29368,
+ 17879, 31449, 23974, 18673, 16490, 4261, 5107, 9785, 29257, 16160,
+ 22643, 5155, 29836, 22935, 5520, 26242, 21127, 27034, 27630, 17279,
+ 16788, 6060, 18507, 29160, 1555, 3134, 4266, 25035, 10670, 23775,
+ 11440, 9028, 26338, 22957, 27982, 16275, 28090, 20239, 6048, 10353,
+ 26078, 4006, 5909, 12709, 20941, 23168, 6865, 18642, 14183, 29071,
+ 8783, 24467, 12718, 29786, 15691, 15305, 20429, 21235, 735, 8756,
+ 25946, 27945, 1004, 3905, 12248, 12798, 15547, 29219, 30080, 21340,
+ 18916, 7717, 321, 25091, 25711, 26175, 8197, 26054, 26938, 5863,
+ 822, 17911, 28570, 16937, 11392, 5664, 13125, 4602, 18137, 6899,
+ 21872, 5322, 4287, 7044, 14644, 14424, 15297, 21174, 32566, 26314,
+ 25921, 5363, 25735, 31229, 3192, 32289, 2249, 31002, 10683, 15313,
+ 24468, 21610, 19196, 18361, 20760, 4971, 22931, 9828, 19971, 10531,
+ 27967, 32296, 23205, 25268, 20583, 6745, 21841, 9265, 6566, 11964,
+ 31751, 26544, 32391, 28478, 30033, 12960, 17293, 20454, 24683, 30045,
+ 28023, 265, 12454, 2306, 6081, 31677, 22542, 16255, 5230, 12943,
+ 1355, 14827, 14597, 14969, 30917, 31003, 31962, 14, 13580, 23667,
+ 19598, 23800, 3702, 764, 14041, 8612, 24074, 17079, 22151, 26428,
+ 23452, 10801, 7617, 15830, 25402, 16472, 26254, 2795, 10695, 30349,
+ 27802, 11274, 9446, 250, 5173, 12749, 10778, 2342, 8862, 18189,
+ 2347, 28358, 19330, 6226, 9675, 2775, 14272, 20365, 21625, 10473,
+ 26991, 30730, 32422, 10942, 8482, 24224, 21014, 2579, 10346, 16939,
+ 32650, 11454, 9629, 26684, 19612, 16121, 23766, 27150, 31978, 2046,
+ 573, 19900, 22134, 27860, 393, 16306, 17741, 5480, 24259, 97,
+ 25191, 26591, 5196, 23096, 25039, 20011, 4641, 13263, 11267, 31196,
+ 16990, 4709, 9886, 6713, 14081, 8332, 28724, 14480, 25841, 3363,
+ 4990, 11978, 4159, 22149, 30135, 27714, 19883, 22016, 1093, 31960,
+ 15722, 8073, 26012, 1601, 25382, 2477, 12640, 12193, 16199, 29131,
+ 29641, 10075, 3441, 4225, 76, 15143, 19533, 29284, 22392, 13926,
+ 29325, 26868, 9246, 31411, 29994, 1999, 5044, 1723, 752, 548,
+ 3579, 24398, 6461, 31851, 4064, 3766, 22022, 9811, 11680, 11847,
+ 11034, 12540, 48, 11831, 22187, 30055, 476, 20400, 17674, 24363,
+ 7726, 1316, 16306, 28521, 30993, 11489, 3464, 27649, 12598, 23013,
+ 26721, 3846, 8631, 7923, 27589, 19056, 26363, 4070, 24819, 29713,
+ 10969, 27974, 3108, 28107, 31744, 11801, 24340, 7679, 13462, 23547,
+ 13503, 19528, 13343, 30065, 31336, 13930, 28833, 19067, 27104, 29061,
+ 8965, 1896, 14597, 27535, 4801, 25070, 25225, 8448, 17588, 7290,
+ 27637, 23247, 4433, 21445, 19693, 2206, 26112, 19112, 23477, 2866,
+ 13761, 10289, 25332, 805, 23827, 23542, 17592, 30687, 32020, 7337,
+ 20155, 27330, 4585, 13549, 9189, 10917, 18528, 4712, 24337, 31620,
+ 22228, 19226, 21268, 26229, 23890, 3309, 3067, 17886, 4345, 11149,
+ 30101, 25062, 13991, 16505, 19250, 12585, 12498, 4443, 13481, 4528,
+ 9395, 12437, 13472, 3616, 31402, 3100, 19463, 817, 15838, 24201,
+ 30438, 14690, 7972, 13933, 26201, 18156, 7970, 2021, 7128, 19956,
+ 9140, 31855, 18876, 27396, 31886, 29948, 7423, 26556, 6947, 29255,
+ 21572, 1477, 454, 22372, 18455, 30215, 11791, 15004, 18549, 20508,
+ 641, 14456, 29583, 7684, 29545, 32028, 27083, 20506, 31497, 30678,
+ 780, 11590, 6390, 27895, 26931, 4981, 24767, 23010, 15334, 7238,
+ 23503, 24418, 8592, 31238, 17045, 9793, 27048, 8415, 20706, 29206,
+ 9271, 4172, 14738, 22110, 21140, 20688, 32110, 16846, 5490, 31208,
+ 10577, 21480, 31773, 21566, 16266, 12493, 22785, 27679, 20610, 18258,
+ 16236, 10287, 1695, 15701, 3733, 14428, 10599, 30290, 11740, 28944,
+ 23529, 26673, 24147, 26283, 6744, 12898, 17790, 23856, 15098, 11052,
+ 5463, 24638, 30272, 22338, 30101, 5955, 14903, 32664, 4654, 10732,
+ 19743, 22900, 29467, 18656, 856, 29896, 347, 11949, 3206, 25791,
+ 23866, 11522, 7149, 22166, 27091, 6688, 28701, 2733, 12756, 12939,
+ 32212, 25566, 2433, 17157, 16928, 269, 4604, 11964, 32708, 5376,
+ 451, 9667, 27613, 28785, 22138, 8127, 3525, 29282, 21483, 28387,
+ 22072, 21169, 29771, 32542, 12725, 31468, 11710, 5522, 6695, 24934,
+ 12574, 9289, 27589, 6795, 1528, 1571, 311, 5232, 10200, 14099,
+ 23290, 12463, 2247, 23691, 22021, 12401, 7441, 12853, 13741, 9932,
+ 21580, 12004, 1222, 25936, 9109, 30154, 4619, 5852, 1309, 26603,
+ 3008, 31926, 4325, 27089, 32405, 475, 4805, 12674, 15310, 6292,
+ 16819, 12463, 27297, 5706, 31810, 28462, 18655, 411, 11881, 27051,
+ 24279, 1710, 17542, 18586, 10872, 1475, 20386, 879, 1461, 28686,
+ 16119, 17426, 19502, 26309, 21167, 7821, 1036, 20600, 11247, 28936,
+ 3628, 22689, 7700, 32760, 8577, 3452, 9533, 8851, 5555, 4120,
+ 9737, 4999, 16652, 2734, 23202, 14827, 28053, 24883, 4346, 32374,
+ 10620, 20521, 7764, 239, 30393, 28090, 11271, 16868, 7665, 16647,
+ 16766, 5279, 10395, 25534, 12164, 27990, 18017, 25066, 16574, 24482,
+ 8649, 19472, 21369, 24882, 26644, 12151, 16551, 9409, 2151, 26823,
+ 13347, 8517, 28200, 1238, 23101, 6506, 15019, 9150, 1650, 14142,
+ 16910, 4659, 14203, 4142, 20321, 3347, 7306, 9521, 29706, 25407,
+ 32720, 13123, 26216, 27050, 14914, 26645, 13239, 30127, 5277, 20227,
+ 18740, 20904, 14759, 2630, 6273, 24508, 7608, 11371, 23370, 24312,
+ 32634, 17923, 14889, 1697, 26093, 31645, 23239, 27593, 16302, 14321,
+ 6469, 25889, 1912, 20062, 28890, 24846, 4587, 8599, 22461, 25087,
+ 26764, 8857, 4677, 5373, 22030, 15328, 16718, 13956, 2000, 31962,
+ 12256, 14737, 26790, 6556, 9227, 25852, 6364, 4820, 14101, 23304,
+ 10104, 6654, 30936, 16185, 28864, 1499, 25189, 28261, 17916, 27423,
+ 23533, 32014, 17021, 11626, 23010, 28655, 29150, 7290, 21849, 25301,
+ 11146, 29087, 9139, 4528, 18302, 16751, 29052, 30698, 4177, 13754,
+ 25747, 31223, 5745, 9153, 10635, 19758, 18607, 21154, 28754, 4567,
+ 30206, 1559, 7184, 21381, 7287, 8544, 10834, 25510, 10657, 30334,
+ 5480, 16984, 4080, 5538, 13835, 2430, 21899, 12517, 26692, 3603,
+ 82, 26681, 30601, 11199, 800, 4512, 5672, 28328, 4173, 20892,
+ 25577, 3979, 30072, 6118, 18414, 30219, 25731, 21602, 8671, 13641,
+ 19934, 30803, 5700, 14004, 12297, 6092, 31282, 1827, 84, 16231,
+ 8746, 31265, 4330, 21048, 6206, 6023, 6157, 1028, 32117, 1873,
+ 15523, 17327, 6769, 28586, 19442, 10740, 25423, 31049, 31912, 16473,
+ 29391, 28160, 25374, 13409, 16565, 9618, 31453, 19203, 5999, 13510,
+ 26978, 10331, 3319, 4793, 24094, 16288, 763, 10360, 13249, 32598,
+ 29244, 32462, 14008, 3524, 1332, 32347, 13556, 10665, 17915, 30182,
+ 15086, 811, 25451, 23285, 8680, 8464, 20867, 30874, 21365, 9776,
+ 18697, 143, 26171, 2858, 27251, 12933, 30712, 8279, 2056, 3514,
+ 26819, 27644, 23363, 16586, 23445, 14532, 10616, 19399, 8199, 26733,
+ 7097, 2187, 26973, 24257, 19963, 3405, 30404, 6344, 22901, 7539,
+ 4312, 17468, 24137, 7335, 105, 27453, 20582, 14381, 25215, 2118,
+ 2989, 14964, 32155, 5728, 29523, 15595, 31808, 29077, 8326, 11285,
+ 12466, 7080, 25683, 20960, 17918, 14595, 8391, 23091, 570, 23025,
+ 15700, 1478, 32270, 25613, 14967, 32566, 30068, 12283, 10392, 1625,
+ 5563, 12117, 1586, 26063, 27858, 12008, 18739, 26329, 24003, 2337,
+ 6054, 14190, 15998, 23746, 29583, 30348, 728, 7129, 24086, 23245,
+ 6355, 1779, 13800, 10042, 23072, 26765, 21723, 25187, 14050, 9419,
+ 12497, 944, 32181, 29037, 990, 2802, 25839, 18942, 16301, 13885,
+ 14630, 29774, 20511, 18938, 21746, 10531, 28982, 7992, 17907, 13612,
+ 7218, 27715, 17174, 9782, 20473, 31608, 22549, 22690, 14524, 17495,
+ 27197, 30999, 31448, 6874, 31348, 20084, 9466, 26885, 18554, 24585,
+ 3463, 9919, 15215, 19462, 7995, 992, 13206, 25139, 22800, 30859,
+ 10584, 22242, 1377, 12222, 15756, 8739, 27727, 39, 7925, 24374,
+ 1380, 26426, 26892, 16454, 27766, 14976, 24576, 27220, 7630, 818,
+ 11772, 19825, 15754, 14342, 1448, 19760, 28224, 18761, 19954, 19803,
+ 31460, 13102, 15118, 30437, 22508, 2662, 30907, 18720, 16305, 14064,
+ 18889, 19248, 28185, 20787, 16600, 29120, 16243, 21834, 30306, 3315,
+ 13986, 8351, 24572, 21149, 11902, 28091, 11480, 22708, 14967, 16988,
+ 19343, 5121, 31356, 968, 32029, 12059, 26139, 9570, 6445, 19862,
+ 21225, 9595, 26520, 3960, 14884, 19562, 13096, 26860, 407, 25055,
+ 31137, 8763, 19390, 19572, 23810, 5111, 4907, 20357, 14856, 29562,
+ 5416, 23362, 2036, 17295, 20382, 8962, 25998, 15726, 5685, 28123,
+ 30570, 17902, 701, 21871, 31594, 17142, 17613, 26376, 13700, 25908,
+ 5289, 23272, 6597, 14866, 19817, 21978, 22422, 6630, 29272, 26893,
+ 10815, 18025, 9115, 17442, 4777, 19819, 17939, 19844, 24168, 965,
+ 25220, 5368, 8184, 11406, 32758, 21621, 31815, 8338, 32091, 29493,
+ 29044, 2559, 11891, 16140, 31447, 2146, 16365, 20473, 13889, 20690,
+ 9935, 18939, 28293, 7787, 7959, 28965, 12087, 1791, 32162, 17397,
+ 17843, 2055, 22862, 4066, 21345, 24544, 20316, 13364, 21816, 1844,
+ 26392, 1816, 17537, 24246, 22715, 4340, 13534, 25874, 15248, 4600,
+ 5002, 2339, 24406, 1526, 27618, 27751, 21734, 6771, 21797, 10673,
+ 27157, 19198, 28024, 29726, 7388, 6080, 1581, 8778, 18870, 2645,
+ 25924, 31172, 6474, 31962, 16434, 20159, 29002, 22343, 21474, 19466,
+ 27803, 14079, 15866, 30530, 7862, 13478, 31583, 17734, 9806, 15411,
+ 12283, 21227, 21299, 11078, 7102, 5617, 25462, 10683, 24802, 6710,
+ 7118, 28799, 32628, 7978, 16186, 29346, 10768, 10627, 10728, 7342,
+ 22508, 23858, 4950, 7736, 14359, 13205, 15287, 29108, 27139, 25070,
+ 2200, 5774, 8002, 1044, 21699, 12662, 2701, 24424, 30563, 1787,
+ 16394, 21003, 18026, 1115, 27343, 16974, 6192, 19097, 31650, 8810,
+ 2140, 28625, 13570, 23666, 1032, 27337, 14444, 14981, 24864, 23752,
+ 30935, 8008, 1291, 11691, 13953, 8851, 24206, 11829, 26605, 26219,
+ 14061, 13479, 13356, 14385, 7763, 26512, 25181, 21016, 30579, 10983,
+ 25200, 20701, 26224, 25431, 21295, 12722, 9978, 986, 10622, 27771,
+ 3515, 6537, 23777, 32316, 14577, 18867, 15680, 30674, 13404, 30252,
+ 21991, 25826, 5210, 31719, 465, 7952, 19537, 16327, 5414, 24945,
+ 17485, 32179, 16386, 12354, 29162, 3561, 3704, 26842, 30837, 5268,
+ 10711, 3549, 5198, 20384, 16171, 9139, 21904, 30413, 12039, 12600,
+ 28148, 25090, 27266, 14517, 5619, 27109, 8576, 15632, 19755, 13992,
+ 9779, 10047, 31236, 28965, 10721, 8194, 11411, 2606, 14055, 12754,
+ 2239, 3102, 3070, 18196, 7074, 10932, 15549, 22675, 8242, 1314,
+ 15199, 24621, 30496, 20064, 12231, 25549, 22016, 20422, 16321, 11417,
+ 29099, 31194, 11403, 32364, 10209, 30567, 27028, 25478, 27699, 30415,
+ 4227, 24706, 31776, 7585, 22139, 9353, 7807, 23150, 26269, 2502,
+ 29213, 2265, 17871, 31257, 4006, 7150, 9148, 3088, 713, 17077,
+ 15644, 27667, 24215, 15110, 13110, 26078, 28972, 18078, 31907, 8757,
+ 23186, 30323, 21332, 27858, 2786, 16453, 17367, 5795, 27564, 4726,
+ 16853, 18482, 14489, 23067, 26080, 22629, 19279, 12115, 14443, 31591,
+ 24213, 7128, 11802, 24038, 3256, 12243, 14653, 127, 3373, 22773,
+ 5271, 26486, 30071, 12227, 11107, 29355, 332, 12081, 17049, 29129,
+ 9715, 2675, 18285, 18625, 29936, 5392, 26392, 14455, 4579, 28984,
+ 21468, 8122, 16302, 30807, 23362, 18554, 18646, 4586, 12711, 5429,
+ 18220, 27794, 5878, 8883, 3756, 19814, 14519, 12787, 16293, 27022,
+ 30025, 28261, 17434, 32270, 25707, 25690, 15464, 6623, 18690, 15288,
+ 7978, 20036, 20502, 2802, 4186, 14683, 16669, 22071, 13241, 7922,
+ 892, 3818, 32368, 925, 7499, 10067, 19447, 32261, 3928, 3732,
+ 14902, 12931, 12911, 10462, 4330, 11502, 31193, 6116, 14411, 3249,
+ 16163, 26512, 748, 14112, 31521, 29429, 20194, 1036, 4145, 5510,
+ 16936, 6292, 2500, 31877, 9794, 25663, 29979, 11454, 10017, 29768,
+ 14159, 4212, 31047, 4409, 1172, 8604, 11051, 23227, 23742, 1097,
+ 9695, 21933, 12549, 9576, 8432, 8307, 5893, 12717, 3470, 16785,
+ 11529, 30925, 15596, 17528, 5000, 4334, 17898, 6303, 8176, 20059,
+ 28146, 26326, 11427, 25469, 6431, 20696, 10815, 15623, 1445, 20255,
+ 22051, 28272, 22125, 8444, 14895, 17062, 12543, 742, 22986, 17665,
+ 29349, 7955, 12330, 22133, 16589, 27717, 25552, 8973, 30896, 28391,
+ 21329, 2964, 16945, 4184, 24412, 22421, 18952, 135, 5625, 17287,
+ 26399, 21952, 8975, 16193, 12092, 24261, 10793, 28852, 16097, 23329,
+ 28025, 20184, 14449, 3513, 26142, 26855, 16019, 23972, 12706, 11722,
+ 28123, 31036, 30919, 18384, 6568, 12149, 13187, 24742, 20552, 29550,
+ 28233, 24964, 27235, 15942, 29834, 932, 10646, 17201, 1148, 17656,
+ 10846, 10699, 28698, 5404, 11576, 17068, 20332, 20106, 31494, 27196,
+ 10248, 20493, 26805, 3528, 11737, 19064, 15901, 1750, 287, 5783,
+ 1064, 16566, 3511, 10086, 32311, 23642, 28573, 27777, 21185, 18024,
+ 175, 14556, 10045, 29580, 29619, 436, 13123, 14099, 8348, 2501,
+ 3822, 26550, 26121, 19646, 16516, 18099, 17423, 16114, 19801, 23843,
+ 5176, 13648, 20976, 17287, 715, 2453, 25956, 1956, 11598, 20160,
+ 19462, 9361, 2634, 10694, 15688, 16654, 32334, 8840, 16602, 10263,
+ 16950, 258, 26386, 12217, 32429, 2757, 24721, 549, 16625, 13479,
+ 14628, 32003, 11479, 7353, 14824, 6920, 4110, 24697, 14002, 7115,
+ 15015, 9033, 19117, 24020, 16597, 22816, 18501, 7926, 2546, 10624,
+ 24644, 5856, 20675, 32424, 17467, 8174, 30973, 5386, 18468, 25157,
+ 24072, 7935, 18245, 13598, 32514, 20666, 20568, 10850, 11271, 26746,
+ 23784, 30840, 6320, 1796, 6142, 13914, 30681, 27729, 30717, 7663,
+ 1192, 27780, 12235, 18581, 7371, 12575, 15153, 6652, 20480, 6773,
+ 2693, 19771, 2267, 21859, 4486, 22557, 12996, 31035, 15751, 6332,
+ 319, 16897, 5840, 338, 15472, 15066, 4417, 13899, 14046, 27841,
+ 20536, 21151, 20599, 25980, 25013, 18014, 10964, 10958, 13500, 909,
+ 29375, 28143, 20219, 27952, 25330, 4921, 1453, 15528, 25634, 25124,
+ 15806, 20799, 28220, 29044, 30512, 7682, 3823, 9137, 10173, 10703,
+ 14698, 18392, 10430, 21934, 17255, 12880, 15435, 23908, 13160, 25119,
+ 28068, 17990, 17472, 1630, 20687, 12364, 16854, 30698, 25987, 15718,
+ 8998, 31581, 8517, 787, 1416, 24381, 25809, 14895, 27957, 19059,
+ 24763, 8460, 28423, 20222, 11606, 17349, 10112, 5352, 6613, 7887,
+ 8974, 12665, 30384, 20433, 7053, 32428, 24394, 18614, 12046, 1759,
+ 18128, 14592, 29655, 22734, 19556, 8543, 3499, 22466, 6779, 17794,
+ 10315, 23558, 21891, 28717, 31548, 14235, 24010, 15756, 15051, 29484,
+ 26779, 24519, 6735, 22340, 13482, 4566, 17326, 5567, 23985, 11415,
+ 26658, 10111, 4956, 4637, 20029, 12896, 14179, 25419, 299, 2925,
+ 9973, 13218, 1336, 10580, 13149, 12120, 13713, 6935, 3552, 26538,
+ 12111, 22277, 10980, 14707, 28081, 30185, 24664, 508, 31657, 11905,
+ 17231, 5654, 24219, 9521, 2286, 12134, 7777, 25593, 28297, 17409,
+ 3730, 3749, 27913, 31801, 15620, 10051, 15249, 15030, 10639, 30426,
+ 25953, 27336, 11028, 28249, 30458, 2299, 9662, 5070, 1666, 6636,
+ 30344, 20440, 7019, 860, 14336, 12127, 14672, 31619, 17482, 28034,
+ 4639, 678, 6247, 22993, 9085, 6892, 31928, 28349, 17254, 12910,
+ 5821, 11340, 24596, 29581, 18467, 2834, 30499, 28552, 32510, 7004,
+ 2034, 22350, 23379, 9390, 1356, 13968, 19929, 22896, 2632, 25883,
+ 5120, 29412, 22125, 8805, 13619, 18779, 21786, 3941, 25946, 15529,
+ 13349, 31400, 28836, 214, 19907, 12962, 5251, 8982, 27048, 21058,
+ 27128, 23291, 6511, 15305, 17680, 31722, 13371, 13787, 11695, 6860,
+ 13727, 24278, 21900, 15365, 955, 27236, 12157, 7594, 24744, 23884,
+ 3061, 29166, 2839, 15246, 24266, 7646, 21044, 23726, 4668, 20559,
+ 8401, 23120, 2868, 1300, 17344, 19717, 17097, 18548, 28544, 19301,
+ 6408, 20187, 18717, 24414, 17653, 13519, 30289, 26059, 1485, 31526,
+ 30959, 3144, 31118, 4982, 22913, 24901, 15545, 4302, 25904, 10842,
+ 14167, 20643, 741, 29914, 15162, 12301, 25518, 5291, 22405, 8500,
+ 4707, 1365, 1391, 13572, 9865, 24920, 4675, 27945, 7798, 25539,
+ 27307, 27191, 9398, 10242, 11055, 18984, 17582, 7160, 6649, 19212,
+ 21119, 22606, 28123, 1532, 2606, 21258, 1683, 22096, 10753, 8291,
+ 31309, 16658, 3116, 13779, 7273, 28850, 940, 25455, 24959, 6394,
+ 116, 30580, 17568, 22341, 16071, 16418, 4575, 25324, 1509, 24525,
+ 14864, 8706, 14825, 10033, 5072, 30273, 17650, 27142, 11718, 22083,
+ 7041, 468, 5672, 1782, 24610, 29449, 15232, 2378, 27215, 26697,
+ 19120, 4140, 13457, 30725, 11827, 4792, 30184, 26703, 4775, 20138,
+ 27245, 25836, 5256, 20246, 3894, 23467, 31551, 19290, 21882, 29430,
+ 9563, 29264, 4341, 20135, 2590, 30152, 9614, 5917, 29755, 27189,
+ 14392, 30350, 23006, 20134, 26390, 158, 30189, 20728, 19682, 14385,
+ 1677, 8778, 21391, 10110, 21737, 28594, 6701, 15974, 27183, 21294,
+ 29198, 27395, 5594, 20702, 14119, 8323, 10551, 13424, 1976, 16439,
+ 3106, 25307, 7984, 6375, 3857, 29776, 22603, 28777, 7765, 10861,
+ 6781, 19313, 15004, 5813, 13971, 26539, 23225, 1341, 30360, 7175,
+ 6824, 32679, 25845, 4949, 23500, 31828, 3805, 5393, 14972, 3542,
+ 17896, 20608, 31934, 9892, 9470, 24060, 24146, 17682, 23671, 27275,
+ 24051, 7040, 2432, 16823, 28633, 2257, 7361, 10650, 14722, 29983,
+ 5181, 17721, 15026, 26284, 3193, 28947, 1977, 25372, 27872, 19961,
+ 30964, 28898, 13158, 28191, 29590, 19705, 9068, 22644, 12200, 10452,
+ 23523, 22063, 8015, 1175, 6325, 16042, 23374, 31111, 9056, 13684,
+ 14539, 2239, 14052, 3746, 27734, 16934, 23264, 19813, 24103, 22429,
+ 31224, 28898, 5031, 28797, 14201, 829, 21043, 20800, 18496, 7927,
+ 24348, 11134, 21208, 24187, 242, 10780, 6882, 27123, 9730, 3520,
+ 31674, 5984, 21533, 28039, 30295, 20714, 17819, 28667, 22131, 13684,
+ 22432, 4159, 13036, 10100, 11678, 17293, 19819, 15874, 11803, 4835,
+ 5443, 19503, 15541, 31992, 20892, 29335, 21859, 13429, 14032, 28474,
+ 27901, 3682, 27413, 8071, 15103, 13534, 15965, 26810, 20618, 29204,
+ 6522, 31336, 8363, 10090, 26758, 8024, 24032, 17659, 1154, 4245,
+ 20696, 21832, 24637, 32449, 3195, 28970, 31863, 17836, 9002, 12300,
+ 26439, 32294, 16712, 26710, 19130, 25105, 20729, 21548, 20157, 14010,
+ 2857, 28249, 21053, 12649, 6609, 7046, 16268, 2614, 12149, 29616,
+ 7, 12575, 14322, 16345, 21238, 22872, 1654, 32765, 2995, 20194,
+ 9424, 3399, 31503, 19039, 10218, 11397, 2033, 14117, 11667, 9434,
+ 15168, 8081, 26498, 11954, 17155, 13213, 22424, 20219, 12487, 7605,
+ 8550, 29331, 30529, 6599, 5359, 24060, 27445, 666, 22191, 17751,
+ 19351, 18784, 18652, 8336, 5359, 2958, 6635, 4054, 9218, 15083,
+ 7254, 25678, 27566, 3047, 19357, 8456, 16918, 7727, 8843, 2098,
+ 2303, 4990, 9914, 2187, 13690, 2230, 19801, 7963, 31428, 9519,
+ 7469, 290, 7274, 13391, 12758, 8782, 11184, 32091, 1108, 27440,
+ 13364, 19852, 7369, 13297, 7119, 26726, 4480, 22337, 14780, 21061,
+ 30511, 29073, 26876, 10553, 9849, 8322, 6648, 19, 31415, 22173,
+ 10089, 28608, 28152, 5956, 29301, 21206, 13894, 12008, 2586, 24429,
+ 18476, 15229, 25040, 4912, 25205, 6443, 23402, 9652, 1845, 1863,
+ 10302, 29960, 1550, 6529, 17797, 8333, 31660, 18783, 6149, 17927,
+ 27282, 15338, 27373, 5365, 20761, 4007, 22016, 11294, 24757, 18120,
+ 20213, 30061, 14971, 8612, 27166, 29694, 21728, 32101, 3657, 14457,
+ 28356, 2816, 8164, 28575, 13231, 29291, 26468, 16162, 30042, 13834,
+ 14055, 25786, 7793, 27242, 4887, 19317, 17047, 5681, 25426, 2895,
+ 28587, 20053, 27913, 1794, 9289, 25229, 7782, 7199, 3988, 11781,
+ 27698, 6494, 32307, 24662, 18165, 28466, 6298, 21173, 27487, 20129,
+ 22155, 15722, 4582, 10835, 19420, 24965, 16817, 19945, 12922, 31436,
+ 19125, 32656, 21934, 3575, 11038, 24533, 17055, 26400, 25584, 31675,
+ 25113, 23669, 238, 17674, 24460, 10544, 22459, 25835, 344, 29897,
+ 16959, 7346, 22087, 23145, 22604, 10491, 23643, 1187, 27777, 23288,
+ 1227, 12639, 20591, 23561, 14664, 12822, 9211, 20365, 18052, 15429,
+ 13315, 18169, 20469, 7707, 11333, 15399, 12503, 11125, 8316, 1520,
+ 28272, 30477, 12491, 31484, 8087, 11246, 19807, 14041, 28023, 6956,
+ 23889, 13643, 4497, 20945, 19657, 14307, 29952, 19226, 18025, 10707,
+ 21761, 4836, 7145, 30209, 4274, 27745, 8702, 858, 1050, 20751,
+ 897, 19305, 5226, 23531, 20429, 16168, 20866, 29922, 18537, 28182,
+ 20663, 20616, 12775, 9097, 9428, 6156, 11275, 28230, 5982, 19820,
+ 21808, 17999, 1821, 16357, 15592, 17660, 4055, 9390, 27107, 9037,
+ 24415, 10213, 30482, 29311, 23503, 2506, 3083, 17117, 32529, 7211,
+ 13488, 11481, 2980, 13343, 23563, 28763, 32412, 25591, 28285, 7769,
+ 25323, 4466, 26392, 168, 27104, 15408, 19529, 13330, 27885, 2153,
+ 24506, 10408, 15533, 25055, 1398, 31833, 24869, 19217, 9807, 25540,
+ 12107, 11442, 4477, 5451, 22468, 14681, 8583, 27241, 21234, 14714,
+ 10343, 11077, 20014, 21397, 26345, 14471, 32338, 9389, 4948, 1898,
+ 31611, 15612, 13132, 9234, 2573, 21733, 19703, 11809, 29943, 20010,
+ 13151, 901, 23864, 21855, 29207, 3475, 8866, 14239, 7202, 25690,
+ 18909, 16509, 528, 15409, 944, 13373, 4970, 20883, 14716, 14917,
+ 28496, 18221, 17161, 19406, 26721, 10804, 10629, 31455, 32731, 4348,
+ 7114, 9596, 7171, 1991, 30688, 26907, 32200, 16347, 3523, 27223,
+ 14755, 13527, 32614, 17640, 14273, 15430, 25079, 14291, 32612, 13173,
+ 1125, 25054, 20871, 16258, 32544, 8775, 22209, 21430, 28960, 29109,
+ 25707, 29204, 3624, 18287, 7429, 23090, 25164, 24268, 28630, 6728,
+ 28337, 28907, 15315, 13959, 916, 13987, 6594, 23212, 31629, 18109,
+ 4511, 18900, 15381, 9313, 16191, 146, 8007, 4559, 10803, 15679,
+ 10979, 31568, 21743, 25233, 14488, 3691, 18220, 26735, 29571, 20827,
+ 6026, 20228, 20211, 20161, 14458, 18451, 23151, 10647, 3163, 2698,
+ 5882, 11621, 1251, 1113, 12693, 11959, 20929, 24196, 18182, 20430,
+ 25216, 1911, 5336, 32150, 16303, 14235, 15267, 14552, 32575, 9254,
+ 30349, 32689, 22572, 21559, 27665, 27459, 6496, 19490, 31743, 21930,
+ 2004, 776, 11972, 7217, 26616, 22188, 10732, 20934, 13909, 29057,
+ 19941, 30124, 21360, 22280, 24838, 624, 9970, 2648, 27599, 26910,
+ 32263, 766, 10867, 19636, 10500, 25608, 14227, 4567, 7244, 10589,
+ 21581, 5829, 6260, 16208, 29045, 10123, 7589, 14452, 24098, 632,
+ 11842, 5553, 16237, 209, 9419, 21655, 13685, 14278, 8450, 14323,
+ 20903, 9637, 20556, 32416, 16956, 16206, 5465, 31904, 22274, 29159,
+ 21255, 19051, 17248, 27857, 24196, 32391, 16788, 18394, 23731, 9561,
+ 31552, 22964, 3794, 27451, 23333, 21158, 21081, 11471, 11310, 28545,
+ 22565, 24978, 10672, 22742, 22229, 5300, 25840, 614, 15477, 24615,
+ 9190, 7898, 9050, 7670, 7488, 31668, 3660, 17368, 13738, 22918,
+ 12267, 7429, 8781, 5217, 16715, 22088, 5269, 12433, 11234, 4181,
+ 21304, 8071, 2724, 27742, 25716, 20759, 18028, 18145, 11672, 25828,
+ 20894, 5316, 11205, 4120, 18186, 5795, 10742, 2904, 28692, 22121,
+ 6206, 7415, 30226, 8989, 26705, 4969, 17142, 32511, 4934, 17403,
+ 21805, 13268, 11419, 25026, 2759, 382, 9850, 16593, 10199, 6863,
+ 11066, 22959, 7197, 25759, 12329, 8457, 19426, 11036, 9609, 1955,
+ 24612, 16738, 26584, 13972, 25075, 16204, 22101, 23475, 9499, 20873,
+ 12991, 6733, 17923, 20466, 11872, 29721, 16085, 3610, 18506, 15981,
+ 22495, 6695, 24801, 30641, 30522, 24033, 9881, 4373, 5033, 22025,
+ 16385, 127, 20163, 21484, 22273, 11975, 31317, 32056, 26975, 5671,
+ 3330, 32269, 648, 9453, 18988, 8535, 17038, 14451, 8472, 17244,
+ 22125, 17489, 1868, 21137, 17810, 31185, 21052, 21170, 14494, 932,
+ 21542, 5649, 7527, 10707, 16443, 8495, 19519, 29176, 6655, 27785,
+ 4730, 4013, 13298, 30900, 17962, 14661, 368, 26796, 18221, 13498,
+ 16342, 5738, 4458, 12519, 15078, 21940, 17495, 16119, 12397, 22841,
+ 17343, 30, 5922, 28125, 21954, 23431, 19666, 82, 25117, 20621,
+ 28602, 8424, 13995, 14637, 26421, 31142, 29996, 4283, 24471, 27289,
+ 3654, 4821, 15704, 16492, 28105, 18070, 19317, 14649, 15415, 18955,
+ 10515, 19359, 22916, 29163, 14949, 25621, 29978, 4482, 8401, 3197,
+ 26400, 32495, 32334, 12797, 12028, 10127, 2065, 32010, 15126, 18617,
+ 11368, 28613, 24031, 8364, 20454, 16011, 5139, 11205, 26048, 5831,
+ 59, 16886, 26487, 18443, 16245, 10355, 28599, 864, 31607, 27566,
+ 31872, 9434, 24018, 5510, 7299, 15215, 18548, 5051, 3023, 17160,
+ 30577, 25254, 940, 17625, 28675, 20519, 16839, 20974, 24783, 27358,
+ 2704, 3079, 22377, 29086, 10977, 12454, 28443, 22302, 15584, 23142,
+ 23778, 11762, 13350, 27790, 31930, 4282, 29985, 23782, 17435, 23194,
+ 31670, 20426, 15812, 17386, 21803, 14972, 29367, 14126, 28997, 32703,
+ 25733, 29256, 3757, 15009, 31947, 18412, 18072, 11160, 5629, 5461,
+ 31655, 31696, 354, 16438, 12300, 19140, 11872, 20724, 1775, 14860,
+ 22266, 32018, 29968, 27509, 21911, 13805, 25773, 9559, 2053, 4009,
+ 20646, 4387, 25533, 5227, 6879, 18492, 8041, 22472, 8678, 8968,
+ 5539, 24190, 22998, 32326, 17664, 11874, 27771, 27298, 4429, 6810,
+ 9398, 31366, 10776, 8204, 10531, 8756, 14963, 26134, 18938, 24082,
+ 17908, 14208, 26163, 4932, 22272, 1967, 11246, 24192, 25161, 22555,
+ 14353, 17694, 918, 4611, 22835, 31855, 30659, 10335, 31161, 15184,
+ 30728, 5654, 30014, 18943, 23166, 3185, 23865, 17453, 7134, 26063,
+ 28889, 16724, 13964, 12443, 19508, 22346, 27349, 26236, 4769, 11031,
+ 23669, 9163, 6242, 1028, 10589, 29514, 20359, 5364, 23987, 531,
+ 31758, 28663, 26905, 20430, 29519, 22557, 31026, 12071, 27288, 25992,
+ 23906, 10880, 6420, 12229, 22486, 8418, 12529, 29277, 32709, 12090,
+ 29633, 24486, 6389, 14786, 26145, 5599, 1152, 10685, 26265, 27260,
+ 11992, 13159, 11204, 32703, 7945, 14380, 28081, 22664, 2878, 6424,
+ 16008, 24174, 5767, 3471, 22129, 3598, 7129, 21054, 22193, 15779,
+ 10839, 17489, 18454, 12760, 5839, 15590, 22678, 29914, 18056, 16578,
+ 7219, 9136, 5947, 22595, 21794, 9679, 2143, 9110, 1835, 745,
+ 2473, 32554, 23123, 19207, 4820, 19557, 4281, 17623, 26782, 12949,
+ 5054, 22087, 13075, 27689, 23656, 23378, 18701, 29729, 15113, 24346,
+ 21756, 10179, 16923, 27448, 14051, 12432, 22639, 24912, 18339, 19062,
+ 13959, 4840, 24956, 14919, 21312, 2938, 20945, 2154, 947, 16583,
+ 6187, 21457, 21086, 7535, 5761, 20778, 20863, 6591, 5815, 19034,
+ 27841, 22218, 18788, 12839, 32282, 28603, 8664, 8244, 10740, 30057,
+ 13150, 18739, 18059, 18476, 29630, 18262, 21142, 17392, 1798, 18182,
+ 16169, 29319, 30858, 27608, 4314, 14404, 1322, 445, 7203, 11973,
+ 23251, 20089, 24839, 8720, 29001, 5974, 18936, 25570, 24611, 12057,
+ 20985, 26947, 22039, 8245, 22016, 26206, 5495, 18239, 5534, 23696,
+ 6652, 29090, 9953, 20159, 19395, 21652, 24954, 4077, 25493, 28744,
+ 1307, 24588, 25707, 13157, 7971, 19220, 20017, 29368, 29565, 32340,
+ 28107, 2341, 27845, 2053, 28246, 13284, 22445, 13605, 4016, 32490,
+ 28064, 387, 9786, 21924, 29349, 19990, 18396, 3051, 27269, 20882,
+ 19018, 29493, 10544, 30525, 30342, 20488, 16989, 8191, 5543, 17333,
+ 7281, 31161, 15064, 32322, 10914, 24792, 28323, 19624, 4700, 42,
+ 8048, 22335, 16355, 8944, 31560, 9334, 11835, 27956, 5855, 13255,
+ 26181, 28253, 1490, 17642, 31018, 16896, 18477, 8009, 31228, 13049,
+ 12592, 28085, 15003, 5307, 11091, 599, 20438, 18148, 32135, 5865,
+ 8403, 5909, 30143, 23846, 1457, 29952, 7343, 29566, 14699, 11458,
+ 22227, 4623, 8960, 7028, 5812, 977, 14801, 4604, 1127, 16400,
+ 2378, 23081, 15958, 14368, 6084, 4608, 5955, 11596, 13482, 20816,
+ 30089, 8975, 29147, 19853, 14245, 16775, 19536, 28634, 16886, 15398,
+ 18431, 4456, 6593, 4267, 767, 20991, 12664, 12880, 1004, 15578,
+ 19004, 30021, 18317, 12216, 3744, 20062, 20916, 14384, 19120, 15113,
+ 17766, 23365, 25906, 25986, 18492, 31546, 32299, 22858, 13577, 20392,
+ 22181, 23509, 25021, 9165, 26032, 15746, 31882, 20263, 16039, 14033,
+ 17477, 7233, 11444, 9681, 8206, 4558, 10134, 16343, 23091, 20980,
+ 1442, 2933, 594, 1002, 3848, 13994, 15038, 31685, 22104, 7511,
+ 29988, 5263, 31301, 5106, 25199, 28826, 13480, 19070, 6632, 5139,
+ 23240, 23483, 15266, 3546, 13016, 23706, 4629, 8849, 17089, 32755,
+ 30473, 11764, 31778, 8826, 32694, 11880, 27029, 21232, 13353, 11990,
+ 16693, 10902, 21993, 697, 93, 2535, 31195, 2166, 29874, 3462,
+ 31075, 26093, 22115, 20342, 32460, 29517, 22447, 18569, 12522, 18476,
+ 19880, 26139, 16893, 7895, 22071, 10239, 26073, 486, 8033, 23226,
+ 29508, 30740, 13256, 16879, 13472, 8782, 28789, 18203, 11210, 10,
+ 2004, 131, 19777, 19930, 13824, 9322, 30347, 12865, 2625, 15494,
+ 9172, 11461, 27092, 11701, 10457, 31557, 12266, 26605, 28932, 27021,
+ 3826, 21105, 2776, 16168, 5915, 18507, 656, 16245, 1557, 14582,
+ 20483, 28670, 17432, 16731, 23499, 6404, 12840, 20735, 24486, 13407,
+ 11671, 12154, 9756, 16005, 27851, 30251, 28003, 7656, 6466, 21034,
+ 29055, 5253, 19154, 8830, 25005, 28601, 18486, 18064, 17666, 27223,
+ 12486, 12512, 4688, 29945, 29574, 4599, 32585, 22675, 14178, 12189,
+ 19175, 26446, 6328, 15435, 1803, 12179, 24599, 17123, 9572, 25957,
+ 5703, 31391, 19346, 30197, 6537, 5959, 12939, 31088, 6175, 27048,
+ 5438, 30492, 5135, 25665, 29303, 12195, 21541, 22591, 9731, 25007,
+ 26167, 32428, 7444, 15542, 5804, 8675, 10727, 30232, 319, 31559,
+ 15011, 13415, 7937, 6452, 30597, 17669, 30109, 24886, 3130, 20469,
+ 19424, 633, 8332, 32235, 1913, 27777, 17473, 17573, 6141, 7707,
+ 21056, 19838, 4910, 24724, 3830, 10817, 26236, 17192, 1528, 19515,
+ 16844, 27325, 27370, 29076, 8057, 2514, 415, 31967, 3480, 5298,
+ 20865, 27375, 7297, 1517, 10292, 23276, 5771, 18184, 12150, 23719,
+ 25878, 4468, 6730, 31019, 18127, 23485, 11605, 10645, 15151, 9988,
+ 9864, 12325, 18245, 16559, 18431, 1940, 30646, 19551, 2601, 23720,
+ 17410, 10786, 14634, 17927, 14088, 3307, 381, 11849, 205, 21823,
+ 12254, 9296, 21881, 1072, 10343, 1500, 15778, 23183, 22777, 14426,
+ 15309, 30814, 10973, 25597, 27442, 4228, 14251, 25872, 31680, 1220,
+ 17771, 26507, 12129, 32240, 19963, 24804, 15487, 21594, 5553, 23591,
+ 14791, 23692, 5440, 19529, 30509, 27705, 15072, 22714, 26672, 11123,
+ 18089, 22585, 863, 1565, 17984, 28140, 15132, 20900, 29622, 31920,
+ 29600, 31466, 31661, 25774, 6719, 20611, 28349, 16175, 16877, 15652,
+ 25110, 3249, 26882, 1624, 870, 2361, 19514, 25461, 9213, 6892,
+ 27392, 207, 32559, 3801, 8428, 17195, 16377, 6170, 30858, 24439,
+ 2536, 17691, 7005, 6840, 2359, 24377, 803, 17987, 20023, 26767,
+ 20571, 19504, 30708, 11276, 27141, 24588, 29206, 5065, 19113, 10190,
+ 18949, 14746, 7834, 28940, 24401, 26084, 6012, 18031, 29520, 28846,
+ 6404, 31077, 23561, 14586, 8959, 29717, 24144, 9813, 7318, 26520,
+ 29491, 26797, 25808, 10854, 31893, 27235, 19544, 23310, 11545, 10401,
+ 23681, 6955, 10050, 26094, 3975, 30355, 6104, 27391, 24088, 19153,
+ 20365, 18896, 17938, 17110, 8160, 22260, 11919, 15083, 32578, 19754,
+ 19743, 8426, 14455, 20272, 28756, 9390, 10560, 15324, 21380, 19656,
+ 21559, 2152, 24522, 17267, 18938, 5390, 32334, 28619, 11659, 12244,
+ 24518, 12089, 22519, 14762, 23869, 17202, 24374, 8626, 22035, 18209,
+ 1107, 10975, 12102, 17057, 19661, 12225, 22511, 11248, 19260, 22687,
+ 30480, 28320, 23351, 30663, 9868, 19088, 21622, 34, 24439, 7963,
+ 31028, 18955, 31632, 30351, 9175, 6753, 28684, 26081, 30675, 8155,
+ 9622, 5279, 6604, 23196, 4499, 293, 13051, 8712, 29866, 21780,
+ 17362, 15573, 25220, 24064, 2531, 16229, 30416, 32361, 31998, 9299,
+ 23435, 10989, 10137, 21324, 1150, 18363, 24181, 2592, 17416, 31307,
+ 7039, 23576, 7453, 17229, 32757, 15243, 30351, 29919, 16841, 16812,
+ 5004, 22786, 2122, 10406, 30057, 7247, 31745, 11243, 2717, 20710,
+ 3545, 17096, 20241, 7592, 14724, 26942, 16791, 28070, 18201, 27405,
+ 21175, 13272, 20482, 25873, 12466, 5907, 2837, 28881, 5313, 6709,
+ 9217, 11862, 30110, 5283, 8684, 8249, 17221, 3829, 8538, 3584,
+ 4092, 22511, 25937, 24747, 19089, 26035, 955, 11657, 28131, 22326,
+ 12555, 25424, 18851, 10737, 28451, 19821, 18524, 30681, 9077, 24985,
+ 22193, 20880, 22633, 2989, 20455, 2269, 11775, 27575, 5027, 32602,
+ 15798, 14925, 10484, 19820, 30124, 18209, 4755, 21880, 12038, 17878,
+ 14442, 5972, 914, 23826, 2644, 22524, 9899, 11221, 16420, 29063,
+ 17758, 14601, 23272, 24409, 12747, 346, 19311, 23193, 24013, 5959,
+ 25096, 6886, 26845, 2425, 27533, 3909, 17715, 852, 8096, 9054,
+ 14383, 23501, 17461, 25833, 14840, 1659, 10833, 7523, 30819, 6896,
+ 26640, 13317, 278, 26185, 29677, 27638, 22253, 15108, 1342, 21184,
+ 30364, 29458, 24062, 29441, 3734, 22573, 25039, 8035, 28206, 26220,
+ 7743, 27085, 28668, 7445, 10315, 6875, 25475, 20914, 29474, 15756,
+ 14864, 14695, 1067, 4923, 31461, 7298, 10312, 977, 17047, 26708,
+ 3677, 24120, 20917, 4928, 27404, 32019, 28330, 1809, 2499, 9132,
+ 7909, 1424, 28409, 10029, 31543, 15191, 28596, 14356, 9084, 29920,
+ 25167, 24545, 5501, 10721, 19578, 1809, 27413, 21212, 12930, 5968,
+ 17299, 15601, 27603, 3563, 23648, 20472, 8379, 4740, 7394, 31436,
+ 21872, 26121, 6559, 14825, 9813, 15847, 21158, 27706, 6521, 24442,
+ 12587, 27180, 10592, 4040, 2161, 4871, 27911, 11120, 7661, 17534,
+ 290, 31453, 31912, 28805, 5800, 5823, 6117, 17762, 19089, 28860,
+ 260, 7175, 10975, 21602, 13478, 8351, 3291, 29793, 17170, 26983,
+ 6305, 22519, 22487, 28607, 11742, 15531, 25779, 8065, 1497, 16446,
+ 29620, 28817, 14000, 26335, 25757, 16053, 31716, 20894, 6539, 21415,
+ 26648, 14627, 22232, 22377, 25622, 160, 23104, 6873, 7955, 29956,
+};
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c
new file mode 100644
index 00000000..bf14f0b1
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/MtrrLib/UnitTest/Support.c
@@ -0,0 +1,987 @@
+/** @file
+ Unit tests of the MtrrLib instance of the MtrrLib class
+
+ Copyright (c) 2018 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "MtrrLibUnitTest.h"
+
+MTRR_MEMORY_CACHE_TYPE mMemoryCacheTypes[] = {
+ CacheUncacheable, CacheWriteCombining, CacheWriteThrough, CacheWriteProtected, CacheWriteBack
+ };
+
+UINT64 mFixedMtrrsValue[MTRR_NUMBER_OF_FIXED_MTRR];
+MSR_IA32_MTRR_PHYSBASE_REGISTER mVariableMtrrsPhysBase[MTRR_NUMBER_OF_VARIABLE_MTRR];
+MSR_IA32_MTRR_PHYSMASK_REGISTER mVariableMtrrsPhysMask[MTRR_NUMBER_OF_VARIABLE_MTRR];
+MSR_IA32_MTRR_DEF_TYPE_REGISTER mDefTypeMsr;
+MSR_IA32_MTRRCAP_REGISTER mMtrrCapMsr;
+CPUID_VERSION_INFO_EDX mCpuidVersionInfoEdx;
+CPUID_VIR_PHY_ADDRESS_SIZE_EAX mCpuidVirPhyAddressSizeEax;
+
+BOOLEAN mRandomInput;
+UINTN mNumberIndex = 0;
+extern UINTN mNumbers[];
+extern UINTN mNumberCount;
+
+/**
+ Return a random number between 0 and RAND_MAX.
+
+ If mRandomInput is TRUE, the routine directly calls rand().
+ Otherwise, the routine returns the pre-generated numbers.
+
+ @return a number between 0 and RAND_MAX.
+**/
+UINTN
+Rand (
+ VOID
+ )
+{
+ if (mRandomInput) {
+ return rand ();
+ } else {
+ DEBUG ((DEBUG_INFO, "random: %d\n", mNumberIndex));
+ return mNumbers[mNumberIndex++ % (mNumberCount - 1)];
+ }
+}
+
+CHAR8 mContentTemplate[] = {
+ "/** @file\n"
+ " Pre-generated random number used by MtrrLib test.\n"
+ "\n"
+ " Copyright (c) 2020, Intel Corporation. All rights reserved.<BR>\n"
+ " SPDX-License-Identifier: BSD-2-Clause-Patent\n"
+ "**/\n"
+ "UINTN mNumberCount = %d;\n"
+ "UINTN mNumbers[] = {"
+};
+
+/**
+ Generate Count random numbers in FilePath.
+
+ @param FilePath The file path to put the generated random numbers.
+ @param Count Count of random numbers.
+**/
+VOID
+GenerateRandomNumbers (
+ CHAR8 *FilePath,
+ UINTN Count
+ )
+{
+ FILE *File;
+ UINTN Index;
+
+ File = fopen (FilePath, "w");
+ fprintf (File, mContentTemplate, Count);
+ for (Index = 0; Index < Count; Index++) {
+ if (Index % 10 == 0) {
+ fprintf (File, "\n ");
+ }
+ fprintf (File, " %d,", rand ());
+ }
+ fprintf (File, "\n};\n");
+ fclose (File);
+}
+
+/**
+ Retrieves CPUID information.
+
+ Executes the CPUID instruction with EAX set to the value specified by Index.
+ This function always returns Index.
+ If Eax is not NULL, then the value of EAX after CPUID is returned in Eax.
+ If Ebx is not NULL, then the value of EBX after CPUID is returned in Ebx.
+ If Ecx is not NULL, then the value of ECX after CPUID is returned in Ecx.
+ If Edx is not NULL, then the value of EDX after CPUID is returned in Edx.
+ This function is only available on IA-32 and x64.
+
+ @param Index The 32-bit value to load into EAX prior to invoking the CPUID
+ instruction.
+ @param Eax The pointer to the 32-bit EAX value returned by the CPUID
+ instruction. This is an optional parameter that may be NULL.
+ @param Ebx The pointer to the 32-bit EBX value returned by the CPUID
+ instruction. This is an optional parameter that may be NULL.
+ @param Ecx The pointer to the 32-bit ECX value returned by the CPUID
+ instruction. This is an optional parameter that may be NULL.
+ @param Edx The pointer to the 32-bit EDX value returned by the CPUID
+ instruction. This is an optional parameter that may be NULL.
+
+ @return Index.
+
+**/
+UINT32
+EFIAPI
+UnitTestMtrrLibAsmCpuid (
+ IN UINT32 Index,
+ OUT UINT32 *Eax, OPTIONAL
+ OUT UINT32 *Ebx, OPTIONAL
+ OUT UINT32 *Ecx, OPTIONAL
+ OUT UINT32 *Edx OPTIONAL
+ )
+{
+ switch (Index) {
+ case CPUID_VERSION_INFO:
+ if (Edx != NULL) {
+ *Edx = mCpuidVersionInfoEdx.Uint32;
+ }
+ return Index;
+ break;
+ case CPUID_EXTENDED_FUNCTION:
+ if (Eax != NULL) {
+ *Eax = CPUID_VIR_PHY_ADDRESS_SIZE;
+ }
+ return Index;
+ break;
+ case CPUID_VIR_PHY_ADDRESS_SIZE:
+ if (Eax != NULL) {
+ *Eax = mCpuidVirPhyAddressSizeEax.Uint32;
+ }
+ return Index;
+ break;
+ }
+
+ //
+ // Should never fall through to here
+ //
+ ASSERT(FALSE);
+ return Index;
+}
+
+/**
+ Returns a 64-bit Machine Specific Register(MSR).
+
+ Reads and returns the 64-bit MSR specified by Index. No parameter checking is
+ performed on Index, and some Index values may cause CPU exceptions. The
+ caller must either guarantee that Index is valid, or the caller must set up
+ exception handlers to catch the exceptions. This function is only available
+ on IA-32 and x64.
+
+ @param MsrIndex The 32-bit MSR index to read.
+
+ @return The value of the MSR identified by MsrIndex.
+
+**/
+UINT64
+EFIAPI
+UnitTestMtrrLibAsmReadMsr64(
+ IN UINT32 MsrIndex
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
+ if (MsrIndex == mFixedMtrrsIndex[Index]) {
+ return mFixedMtrrsValue[Index];
+ }
+ }
+
+ if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&
+ (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {
+ if (MsrIndex % 2 == 0) {
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;
+ return mVariableMtrrsPhysBase[Index].Uint64;
+ } else {
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
+ return mVariableMtrrsPhysMask[Index].Uint64;
+ }
+ }
+
+ if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
+ return mDefTypeMsr.Uint64;
+ }
+
+ if (MsrIndex == MSR_IA32_MTRRCAP) {
+ return mMtrrCapMsr.Uint64;
+ }
+
+ //
+ // Should never fall through to here
+ //
+ ASSERT(FALSE);
+ return 0;
+}
+
+/**
+ Writes a 64-bit value to a Machine Specific Register(MSR), and returns the
+ value.
+
+ Writes the 64-bit value specified by Value to the MSR specified by Index. The
+ 64-bit value written to the MSR is returned. No parameter checking is
+ performed on Index or Value, and some of these may cause CPU exceptions. The
+ caller must either guarantee that Index and Value are valid, or the caller
+ must establish proper exception handlers. This function is only available on
+ IA-32 and x64.
+
+ @param MsrIndex The 32-bit MSR index to write.
+ @param Value The 64-bit value to write to the MSR.
+
+ @return Value
+
+**/
+UINT64
+EFIAPI
+UnitTestMtrrLibAsmWriteMsr64(
+ IN UINT32 MsrIndex,
+ IN UINT64 Value
+ )
+{
+ UINT32 Index;
+
+ for (Index = 0; Index < ARRAY_SIZE (mFixedMtrrsValue); Index++) {
+ if (MsrIndex == mFixedMtrrsIndex[Index]) {
+ mFixedMtrrsValue[Index] = Value;
+ return Value;
+ }
+ }
+
+ if ((MsrIndex >= MSR_IA32_MTRR_PHYSBASE0) &&
+ (MsrIndex <= MSR_IA32_MTRR_PHYSMASK0 + (MTRR_NUMBER_OF_VARIABLE_MTRR << 1))) {
+ if (MsrIndex % 2 == 0) {
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSBASE0) >> 1;
+ mVariableMtrrsPhysBase[Index].Uint64 = Value;
+ return Value;
+ } else {
+ Index = (MsrIndex - MSR_IA32_MTRR_PHYSMASK0) >> 1;
+ mVariableMtrrsPhysMask[Index].Uint64 = Value;
+ return Value;
+ }
+ }
+
+ if (MsrIndex == MSR_IA32_MTRR_DEF_TYPE) {
+ mDefTypeMsr.Uint64 = Value;
+ return Value;
+ }
+
+ if (MsrIndex == MSR_IA32_MTRRCAP) {
+ mMtrrCapMsr.Uint64 = Value;
+ return Value;
+ }
+
+ //
+ // Should never fall through to here
+ //
+ ASSERT(FALSE);
+ return 0;
+}
+
+/**
+ Initialize the MTRR registers.
+
+ @param SystemParameter System parameter that controls the MTRR registers initialization.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+InitializeMtrrRegs (
+ IN MTRR_LIB_SYSTEM_PARAMETER *SystemParameter
+ )
+{
+ UINT32 Index;
+
+ SetMem (mFixedMtrrsValue, sizeof (mFixedMtrrsValue), SystemParameter->DefaultCacheType);
+
+ for (Index = 0; Index < ARRAY_SIZE (mVariableMtrrsPhysBase); Index++) {
+ mVariableMtrrsPhysBase[Index].Uint64 = 0;
+ mVariableMtrrsPhysBase[Index].Bits.Type = SystemParameter->DefaultCacheType;
+ mVariableMtrrsPhysBase[Index].Bits.Reserved1 = 0;
+
+ mVariableMtrrsPhysMask[Index].Uint64 = 0;
+ mVariableMtrrsPhysMask[Index].Bits.V = 0;
+ mVariableMtrrsPhysMask[Index].Bits.Reserved1 = 0;
+ }
+
+ mDefTypeMsr.Bits.E = 1;
+ mDefTypeMsr.Bits.FE = 1;
+ mDefTypeMsr.Bits.Type = SystemParameter->DefaultCacheType;
+ mDefTypeMsr.Bits.Reserved1 = 0;
+ mDefTypeMsr.Bits.Reserved2 = 0;
+ mDefTypeMsr.Bits.Reserved3 = 0;
+
+ mMtrrCapMsr.Bits.SMRR = 0;
+ mMtrrCapMsr.Bits.WC = 0;
+ mMtrrCapMsr.Bits.VCNT = SystemParameter->VariableMtrrCount;
+ mMtrrCapMsr.Bits.FIX = SystemParameter->FixedMtrrSupported;
+ mMtrrCapMsr.Bits.Reserved1 = 0;
+ mMtrrCapMsr.Bits.Reserved2 = 0;
+ mMtrrCapMsr.Bits.Reserved3 = 0;
+
+ mCpuidVersionInfoEdx.Bits.MTRR = SystemParameter->MtrrSupported;
+ mCpuidVirPhyAddressSizeEax.Bits.PhysicalAddressBits = SystemParameter->PhysicalAddressBits;
+
+ //
+ // Hook BaseLib functions used by MtrrLib that require some emulation.
+ //
+ gUnitTestHostBaseLib.X86->AsmCpuid = UnitTestMtrrLibAsmCpuid;
+ gUnitTestHostBaseLib.X86->AsmReadMsr64 = UnitTestMtrrLibAsmReadMsr64;
+ gUnitTestHostBaseLib.X86->AsmWriteMsr64 = UnitTestMtrrLibAsmWriteMsr64;
+
+ return UNIT_TEST_PASSED;
+}
+
+/**
+ Initialize the MTRR registers.
+
+ @param Context System parameter that controls the MTRR registers initialization.
+**/
+UNIT_TEST_STATUS
+EFIAPI
+InitializeSystem (
+ IN UNIT_TEST_CONTEXT Context
+ )
+{
+ return InitializeMtrrRegs ((MTRR_LIB_SYSTEM_PARAMETER *) Context);
+}
+
+/**
+ Collect the test result.
+
+ @param DefaultType Default memory type.
+ @param PhysicalAddressBits Physical address bits.
+ @param VariableMtrrCount Count of variable MTRRs.
+ @param Mtrrs MTRR settings to collect from.
+ @param Ranges Return the memory ranges.
+ @param RangeCount Return the count of memory ranges.
+ @param MtrrCount Return the count of variable MTRRs being used.
+**/
+VOID
+CollectTestResult (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT32 PhysicalAddressBits,
+ IN UINT32 VariableMtrrCount,
+ IN MTRR_SETTINGS *Mtrrs,
+ OUT MTRR_MEMORY_RANGE *Ranges,
+ IN OUT UINTN *RangeCount,
+ OUT UINT32 *MtrrCount
+ )
+{
+ UINTN Index;
+ UINT64 MtrrValidBitsMask;
+ UINT64 MtrrValidAddressMask;
+ MTRR_MEMORY_RANGE RawMemoryRanges[ARRAY_SIZE (Mtrrs->Variables.Mtrr)];
+
+ ASSERT (Mtrrs != NULL);
+ ASSERT (VariableMtrrCount <= ARRAY_SIZE (Mtrrs->Variables.Mtrr));
+
+ MtrrValidBitsMask = (1ull << PhysicalAddressBits) - 1;
+ MtrrValidAddressMask = MtrrValidBitsMask & ~0xFFFull;
+
+ *MtrrCount = 0;
+ for (Index = 0; Index < VariableMtrrCount; Index++) {
+ if (((MSR_IA32_MTRR_PHYSMASK_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Mask)->Bits.V == 1) {
+ RawMemoryRanges[*MtrrCount].BaseAddress = Mtrrs->Variables.Mtrr[Index].Base & MtrrValidAddressMask;
+ RawMemoryRanges[*MtrrCount].Type =
+ ((MSR_IA32_MTRR_PHYSBASE_REGISTER *) &Mtrrs->Variables.Mtrr[Index].Base)->Bits.Type;
+ RawMemoryRanges[*MtrrCount].Length =
+ ((~(Mtrrs->Variables.Mtrr[Index].Mask & MtrrValidAddressMask)) & MtrrValidBitsMask) + 1;
+ (*MtrrCount)++;
+ }
+ }
+
+ GetEffectiveMemoryRanges (DefaultType, PhysicalAddressBits, RawMemoryRanges, *MtrrCount, Ranges, RangeCount);
+}
+
+/**
+ Return a 32bit random number.
+
+ @param Start Start of the random number range.
+ @param Limit Limit of the random number range.
+ @return 32bit random number
+**/
+UINT32
+Random32 (
+ UINT32 Start,
+ UINT32 Limit
+ )
+{
+ return (UINT32) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
+}
+
+/**
+ Return a 64bit random number.
+
+ @param Start Start of the random number range.
+ @param Limit Limit of the random number range.
+ @return 64bit random number
+**/
+UINT64
+Random64 (
+ UINT64 Start,
+ UINT64 Limit
+ )
+{
+ return (UINT64) (((double) Rand () / RAND_MAX) * (Limit - Start)) + Start;
+}
+
+/**
+ Generate random MTRR BASE/MASK for a specified type.
+
+ @param PhysicalAddressBits Physical address bits.
+ @param CacheType Cache type.
+ @param MtrrPair Return the random MTRR.
+ @param MtrrMemoryRange Return the random memory range.
+**/
+VOID
+GenerateRandomMtrrPair (
+ IN UINT32 PhysicalAddressBits,
+ IN MTRR_MEMORY_CACHE_TYPE CacheType,
+ OUT MTRR_VARIABLE_SETTING *MtrrPair, OPTIONAL
+ OUT MTRR_MEMORY_RANGE *MtrrMemoryRange OPTIONAL
+ )
+{
+ MSR_IA32_MTRR_PHYSBASE_REGISTER PhysBase;
+ MSR_IA32_MTRR_PHYSMASK_REGISTER PhysMask;
+ UINT32 SizeShift;
+ UINT32 BaseShift;
+ UINT64 RandomBoundary;
+ UINT64 MaxPhysicalAddress;
+ UINT64 RangeSize;
+ UINT64 RangeBase;
+ UINT64 PhysBasePhyMaskValidBitsMask;
+
+ MaxPhysicalAddress = 1ull << PhysicalAddressBits;
+ do {
+ SizeShift = Random32 (12, PhysicalAddressBits - 1);
+ RangeSize = 1ull << SizeShift;
+
+ BaseShift = Random32 (SizeShift, PhysicalAddressBits - 1);
+ RandomBoundary = Random64 (0, 1ull << (PhysicalAddressBits - BaseShift));
+ RangeBase = RandomBoundary << BaseShift;
+ } while (RangeBase < SIZE_1MB || RangeBase > MaxPhysicalAddress - 1);
+
+ PhysBasePhyMaskValidBitsMask = (MaxPhysicalAddress - 1) & 0xfffffffffffff000ULL;
+
+ PhysBase.Uint64 = 0;
+ PhysBase.Bits.Type = CacheType;
+ PhysBase.Uint64 |= RangeBase & PhysBasePhyMaskValidBitsMask;
+ PhysMask.Uint64 = 0;
+ PhysMask.Bits.V = 1;
+ PhysMask.Uint64 |= ((~RangeSize) + 1) & PhysBasePhyMaskValidBitsMask;
+
+ if (MtrrPair != NULL) {
+ MtrrPair->Base = PhysBase.Uint64;
+ MtrrPair->Mask = PhysMask.Uint64;
+ }
+
+ if (MtrrMemoryRange != NULL) {
+ MtrrMemoryRange->BaseAddress = RangeBase;
+ MtrrMemoryRange->Length = RangeSize;
+ MtrrMemoryRange->Type = CacheType;
+ }
+}
+
+
+/**
+ Check whether the Range overlaps with any one in Ranges.
+
+ @param Range The memory range to check.
+ @param Ranges The memory ranges.
+ @param Count Count of memory ranges.
+
+ @return TRUE when overlap exists.
+**/
+BOOLEAN
+RangesOverlap (
+ IN MTRR_MEMORY_RANGE *Range,
+ IN MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN Count
+ )
+{
+ while (Count-- != 0) {
+ //
+ // Two ranges overlap when:
+ // 1. range#2.base is in the middle of range#1
+ // 2. range#1.base is in the middle of range#2
+ //
+ if ((Range->BaseAddress <= Ranges[Count].BaseAddress && Ranges[Count].BaseAddress < Range->BaseAddress + Range->Length)
+ || (Ranges[Count].BaseAddress <= Range->BaseAddress && Range->BaseAddress < Ranges[Count].BaseAddress + Ranges[Count].Length)) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Generate random MTRRs.
+
+ @param PhysicalAddressBits Physical address bits.
+ @param RawMemoryRanges Return the randomly generated MTRRs.
+ @param UcCount Count of Uncacheable MTRRs.
+ @param WtCount Count of Write Through MTRRs.
+ @param WbCount Count of Write Back MTRRs.
+ @param WpCount Count of Write Protected MTRRs.
+ @param WcCount Count of Write Combine MTRRs.
+**/
+VOID
+GenerateValidAndConfigurableMtrrPairs (
+ IN UINT32 PhysicalAddressBits,
+ IN OUT MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 UcCount,
+ IN UINT32 WtCount,
+ IN UINT32 WbCount,
+ IN UINT32 WpCount,
+ IN UINT32 WcCount
+ )
+{
+ UINT32 Index;
+
+ //
+ // 1. Generate UC, WT, WB in order.
+ //
+ for (Index = 0; Index < UcCount; Index++) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheUncacheable, NULL, &RawMemoryRanges[Index]);
+ }
+
+ for (Index = UcCount; Index < UcCount + WtCount; Index++) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteThrough, NULL, &RawMemoryRanges[Index]);
+ }
+
+ for (Index = UcCount + WtCount; Index < UcCount + WtCount + WbCount; Index++) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteBack, NULL, &RawMemoryRanges[Index]);
+ }
+
+ //
+ // 2. Generate WP MTRR and DO NOT overlap with WT, WB.
+ //
+ for (Index = UcCount + WtCount + WbCount; Index < UcCount + WtCount + WbCount + WpCount; Index++) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);
+ while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount)) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteProtected, NULL, &RawMemoryRanges[Index]);
+ }
+ }
+
+ //
+ // 3. Generate WC MTRR and DO NOT overlap with WT, WB, WP.
+ //
+ for (Index = UcCount + WtCount + WbCount + WpCount; Index < UcCount + WtCount + WbCount + WpCount + WcCount; Index++) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);
+ while (RangesOverlap (&RawMemoryRanges[Index], &RawMemoryRanges[UcCount], WtCount + WbCount + WpCount)) {
+ GenerateRandomMtrrPair (PhysicalAddressBits, CacheWriteCombining, NULL, &RawMemoryRanges[Index]);
+ }
+ }
+}
+
+/**
+ Return a random memory cache type.
+**/
+MTRR_MEMORY_CACHE_TYPE
+GenerateRandomCacheType (
+ VOID
+ )
+{
+ return mMemoryCacheTypes[Random32 (0, ARRAY_SIZE (mMemoryCacheTypes) - 1)];
+}
+
+/**
+ Compare function used by qsort().
+**/
+
+/**
+ Compare function used by qsort().
+
+ @param Left Left operand to compare.
+ @param Right Right operand to compare.
+
+ @retval 0 Left == Right
+ @retval -1 Left < Right
+ @retval 1 Left > Right
+**/
+INT32
+CompareFuncUint64 (
+ CONST VOID * Left,
+ CONST VOID * Right
+ )
+{
+ INT64 Delta;
+ Delta = (*(UINT64*)Left - *(UINT64*)Right);
+ if (Delta > 0) {
+ return 1;
+ } else if (Delta == 0) {
+ return 0;
+ } else {
+ return -1;
+ }
+}
+
+/**
+ Determin the memory cache type for the Range.
+
+ @param DefaultType Default cache type.
+ @param Range The memory range to determin the cache type.
+ @param Ranges The entire memory ranges.
+ @param RangeCount Count of the entire memory ranges.
+**/
+VOID
+DetermineMemoryCacheType (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN OUT MTRR_MEMORY_RANGE *Range,
+ IN MTRR_MEMORY_RANGE *Ranges,
+ IN UINT32 RangeCount
+ )
+{
+ UINT32 Index;
+ Range->Type = CacheInvalid;
+ for (Index = 0; Index < RangeCount; Index++) {
+ if (RangesOverlap (Range, &Ranges[Index], 1)) {
+ if (Ranges[Index].Type < Range->Type) {
+ Range->Type = Ranges[Index].Type;
+ }
+ }
+ }
+
+ if (Range->Type == CacheInvalid) {
+ Range->Type = DefaultType;
+ }
+}
+
+/**
+ Get the index of the element that does NOT equals to Array[Index].
+
+ @param Index Current element.
+ @param Array Array to scan.
+ @param Count Count of the array.
+
+ @return Next element that doesn't equal to current one.
+**/
+UINT32
+GetNextDifferentElementInSortedArray (
+ IN UINT32 Index,
+ IN UINT64 *Array,
+ IN UINT32 Count
+ )
+{
+ UINT64 CurrentElement;
+ CurrentElement = Array[Index];
+ while (CurrentElement == Array[Index] && Index < Count) {
+ Index++;
+ }
+ return Index;
+}
+
+/**
+ Remove the duplicates from the array.
+
+ @param Array The array to operate on.
+ @param Count Count of the array.
+**/
+VOID
+RemoveDuplicatesInSortedArray (
+ IN OUT UINT64 *Array,
+ IN OUT UINT32 *Count
+ )
+{
+ UINT32 Index;
+ UINT32 NewCount;
+
+ Index = 0;
+ NewCount = 0;
+ while (Index < *Count) {
+ Array[NewCount] = Array[Index];
+ NewCount++;
+ Index = GetNextDifferentElementInSortedArray (Index, Array, *Count);
+ }
+ *Count = NewCount;
+}
+
+/**
+ Return TRUE when Address is in the Range.
+
+ @param Address The address to check.
+ @param Range The range to check.
+ @return TRUE when Address is in the Range.
+**/
+BOOLEAN
+AddressInRange (
+ IN UINT64 Address,
+ IN MTRR_MEMORY_RANGE Range
+ )
+{
+ return (Address >= Range.BaseAddress) && (Address <= Range.BaseAddress + Range.Length - 1);
+}
+
+/**
+ Get the overlap bit flag.
+
+ @param RawMemoryRanges Raw memory ranges.
+ @param RawMemoryRangeCount Count of raw memory ranges.
+ @param Address The address to check.
+**/
+UINT64
+GetOverlapBitFlag (
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 RawMemoryRangeCount,
+ IN UINT64 Address
+ )
+{
+ UINT64 OverlapBitFlag;
+ UINT32 Index;
+ OverlapBitFlag = 0;
+ for (Index = 0; Index < RawMemoryRangeCount; Index++) {
+ if (AddressInRange (Address, RawMemoryRanges[Index])) {
+ OverlapBitFlag |= (1ull << Index);
+ }
+ }
+
+ return OverlapBitFlag;
+}
+
+/**
+ Return the relationship between flags.
+
+ @param Flag1 Flag 1
+ @param Flag2 Flag 2
+
+ @retval 0 Flag1 == Flag2
+ @retval 1 Flag1 is a subset of Flag2
+ @retval 2 Flag2 is a subset of Flag1
+ @retval 3 No subset relations between Flag1 and Flag2.
+**/
+UINT32
+CheckOverlapBitFlagsRelation (
+ IN UINT64 Flag1,
+ IN UINT64 Flag2
+ )
+{
+ if (Flag1 == Flag2) return 0;
+ if ((Flag1 | Flag2) == Flag2) return 1;
+ if ((Flag1 | Flag2) == Flag1) return 2;
+ return 3;
+}
+
+/**
+ Return TRUE when the Endpoint is in any of the Ranges.
+
+ @param Endpoint The endpoint to check.
+ @param Ranges The memory ranges.
+ @param RangeCount Count of memory ranges.
+
+ @retval TRUE Endpoint is in one of the range.
+ @retval FALSE Endpoint is not in any of the ranges.
+**/
+BOOLEAN
+IsEndpointInRanges (
+ IN UINT64 Endpoint,
+ IN MTRR_MEMORY_RANGE *Ranges,
+ IN UINTN RangeCount
+ )
+{
+ UINT32 Index;
+ for (Index = 0; Index < RangeCount; Index++) {
+ if (AddressInRange (Endpoint, Ranges[Index])) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+
+/**
+ Compact adjacent ranges of the same type.
+
+ @param DefaultType Default memory type.
+ @param PhysicalAddressBits Physical address bits.
+ @param EffectiveMtrrMemoryRanges Memory ranges to compact.
+ @param EffectiveMtrrMemoryRangesCount Return the new count of memory ranges.
+**/
+VOID
+CompactAndExtendEffectiveMtrrMemoryRanges (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT32 PhysicalAddressBits,
+ IN OUT MTRR_MEMORY_RANGE **EffectiveMtrrMemoryRanges,
+ IN OUT UINTN *EffectiveMtrrMemoryRangesCount
+ )
+{
+ UINT64 MaxAddress;
+ UINTN NewRangesCountAtMost;
+ MTRR_MEMORY_RANGE *NewRanges;
+ UINTN NewRangesCountActual;
+ MTRR_MEMORY_RANGE *CurrentRangeInNewRanges;
+ MTRR_MEMORY_CACHE_TYPE CurrentRangeTypeInOldRanges;
+
+ MTRR_MEMORY_RANGE *OldRanges;
+ MTRR_MEMORY_RANGE OldLastRange;
+ UINTN OldRangesIndex;
+
+ NewRangesCountActual = 0;
+ NewRangesCountAtMost = *EffectiveMtrrMemoryRangesCount + 2; // At most with 2 more range entries.
+ NewRanges = (MTRR_MEMORY_RANGE *) calloc (NewRangesCountAtMost, sizeof (MTRR_MEMORY_RANGE));
+ OldRanges = *EffectiveMtrrMemoryRanges;
+ if (OldRanges[0].BaseAddress > 0) {
+ NewRanges[NewRangesCountActual].BaseAddress = 0;
+ NewRanges[NewRangesCountActual].Length = OldRanges[0].BaseAddress;
+ NewRanges[NewRangesCountActual].Type = DefaultType;
+ NewRangesCountActual++;
+ }
+
+ OldRangesIndex = 0;
+ while (OldRangesIndex < *EffectiveMtrrMemoryRangesCount) {
+ CurrentRangeTypeInOldRanges = OldRanges[OldRangesIndex].Type;
+ CurrentRangeInNewRanges = NULL;
+ if (NewRangesCountActual > 0) // We need to check CurrentNewRange first before generate a new NewRange.
+ {
+ CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
+ }
+ if (CurrentRangeInNewRanges != NULL && CurrentRangeInNewRanges->Type == CurrentRangeTypeInOldRanges) {
+ CurrentRangeInNewRanges->Length += OldRanges[OldRangesIndex].Length;
+ } else {
+ NewRanges[NewRangesCountActual].BaseAddress = OldRanges[OldRangesIndex].BaseAddress;
+ NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;
+ NewRanges[NewRangesCountActual].Type = CurrentRangeTypeInOldRanges;
+ while (OldRangesIndex + 1 < *EffectiveMtrrMemoryRangesCount && OldRanges[OldRangesIndex + 1].Type == CurrentRangeTypeInOldRanges)
+ {
+ OldRangesIndex++;
+ NewRanges[NewRangesCountActual].Length += OldRanges[OldRangesIndex].Length;
+ }
+ NewRangesCountActual++;
+ }
+
+ OldRangesIndex++;
+ }
+
+ MaxAddress = (1ull << PhysicalAddressBits) - 1;
+ OldLastRange = OldRanges[(*EffectiveMtrrMemoryRangesCount) - 1];
+ CurrentRangeInNewRanges = &NewRanges[NewRangesCountActual - 1];
+ if (OldLastRange.BaseAddress + OldLastRange.Length - 1 < MaxAddress) {
+ if (CurrentRangeInNewRanges->Type == DefaultType) {
+ CurrentRangeInNewRanges->Length = MaxAddress - CurrentRangeInNewRanges->BaseAddress + 1;
+ } else {
+ NewRanges[NewRangesCountActual].BaseAddress = OldLastRange.BaseAddress + OldLastRange.Length;
+ NewRanges[NewRangesCountActual].Length = MaxAddress - NewRanges[NewRangesCountActual].BaseAddress + 1;
+ NewRanges[NewRangesCountActual].Type = DefaultType;
+ NewRangesCountActual++;
+ }
+ }
+
+ free (*EffectiveMtrrMemoryRanges);
+ *EffectiveMtrrMemoryRanges = NewRanges;
+ *EffectiveMtrrMemoryRangesCount = NewRangesCountActual;
+}
+
+/**
+ Collect all the endpoints in the raw memory ranges.
+
+ @param Endpoints Return the collected endpoints.
+ @param EndPointCount Return the count of endpoints.
+ @param RawMemoryRanges Raw memory ranges.
+ @param RawMemoryRangeCount Count of raw memory ranges.
+**/
+VOID
+CollectEndpoints (
+ IN OUT UINT64 *Endpoints,
+ IN OUT UINT32 *EndPointCount,
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 RawMemoryRangeCount
+ )
+{
+ UINT32 Index;
+ UINT32 RawRangeIndex;
+
+ ASSERT ((RawMemoryRangeCount << 1) == *EndPointCount);
+
+ for (Index = 0; Index < *EndPointCount; Index += 2) {
+ RawRangeIndex = Index >> 1;
+ Endpoints[Index] = RawMemoryRanges[RawRangeIndex].BaseAddress;
+ Endpoints[Index + 1] = RawMemoryRanges[RawRangeIndex].BaseAddress + RawMemoryRanges[RawRangeIndex].Length - 1;
+ }
+
+ qsort (Endpoints, *EndPointCount, sizeof (UINT64), CompareFuncUint64);
+ RemoveDuplicatesInSortedArray (Endpoints, EndPointCount);
+}
+
+/**
+ Convert the MTRR BASE/MASK array to memory ranges.
+
+ @param DefaultType Default memory type.
+ @param PhysicalAddressBits Physical address bits.
+ @param RawMemoryRanges Raw memory ranges.
+ @param RawMemoryRangeCount Count of raw memory ranges.
+ @param MemoryRanges Memory ranges.
+ @param MemoryRangeCount Count of memory ranges.
+**/
+VOID
+GetEffectiveMemoryRanges (
+ IN MTRR_MEMORY_CACHE_TYPE DefaultType,
+ IN UINT32 PhysicalAddressBits,
+ IN MTRR_MEMORY_RANGE *RawMemoryRanges,
+ IN UINT32 RawMemoryRangeCount,
+ OUT MTRR_MEMORY_RANGE *MemoryRanges,
+ OUT UINTN *MemoryRangeCount
+ )
+{
+ UINTN Index;
+ UINT32 AllEndPointsCount;
+ UINT64 *AllEndPointsInclusive;
+ UINT32 AllRangePiecesCountMax;
+ MTRR_MEMORY_RANGE *AllRangePieces;
+ UINTN AllRangePiecesCountActual;
+ UINT64 OverlapBitFlag1;
+ UINT64 OverlapBitFlag2;
+ INT32 OverlapFlagRelation;
+
+ if (RawMemoryRangeCount == 0) {
+ MemoryRanges[0].BaseAddress = 0;
+ MemoryRanges[0].Length = (1ull << PhysicalAddressBits);
+ MemoryRanges[0].Type = DefaultType;
+ *MemoryRangeCount = 1;
+ return;
+ }
+
+ AllEndPointsCount = RawMemoryRangeCount << 1;
+ AllEndPointsInclusive = calloc (AllEndPointsCount, sizeof (UINT64));
+ AllRangePiecesCountMax = RawMemoryRangeCount * 3 + 1;
+ AllRangePieces = calloc (AllRangePiecesCountMax, sizeof (MTRR_MEMORY_RANGE));
+ CollectEndpoints (AllEndPointsInclusive, &AllEndPointsCount, RawMemoryRanges, RawMemoryRangeCount);
+
+ for (Index = 0, AllRangePiecesCountActual = 0; Index < AllEndPointsCount - 1; Index++) {
+ OverlapBitFlag1 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index]);
+ OverlapBitFlag2 = GetOverlapBitFlag (RawMemoryRanges, RawMemoryRangeCount, AllEndPointsInclusive[Index + 1]);
+ OverlapFlagRelation = CheckOverlapBitFlagsRelation (OverlapBitFlag1, OverlapBitFlag2);
+ switch (OverlapFlagRelation) {
+ case 0: // [1, 2]
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
+ AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - AllEndPointsInclusive[Index] + 1;
+ AllRangePiecesCountActual++;
+ break;
+ case 1: // [1, 2)
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
+ AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - AllEndPointsInclusive[Index] + 1;
+ AllRangePiecesCountActual++;
+ break;
+ case 2: // (1, 2]
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
+ AllRangePieces[AllRangePiecesCountActual].Length = AllEndPointsInclusive[Index + 1] - (AllEndPointsInclusive[Index] + 1) + 1;
+ AllRangePiecesCountActual++;
+
+ if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
+ AllRangePieces[AllRangePiecesCountActual].Length = 1;
+ AllRangePiecesCountActual++;
+ }
+ break;
+ case 3: // (1, 2)
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index] + 1;
+ AllRangePieces[AllRangePiecesCountActual].Length = (AllEndPointsInclusive[Index + 1] - 1) - (AllEndPointsInclusive[Index] + 1) + 1;
+ if (AllRangePieces[AllRangePiecesCountActual].Length == 0) // Only in case 3 can exists Length=0, we should skip such "segment".
+ break;
+ AllRangePiecesCountActual++;
+ if (!IsEndpointInRanges (AllEndPointsInclusive[Index], AllRangePieces, AllRangePiecesCountActual)) {
+ AllRangePieces[AllRangePiecesCountActual].BaseAddress = AllEndPointsInclusive[Index];
+ AllRangePieces[AllRangePiecesCountActual].Length = 1;
+ AllRangePiecesCountActual++;
+ }
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ }
+
+ for (Index = 0; Index < AllRangePiecesCountActual; Index++) {
+ DetermineMemoryCacheType (DefaultType, &AllRangePieces[Index], RawMemoryRanges, RawMemoryRangeCount);
+ }
+
+ CompactAndExtendEffectiveMtrrMemoryRanges (DefaultType, PhysicalAddressBits, &AllRangePieces, &AllRangePiecesCountActual);
+ ASSERT (*MemoryRangeCount >= AllRangePiecesCountActual);
+ memcpy (MemoryRanges, AllRangePieces, AllRangePiecesCountActual * sizeof (MTRR_MEMORY_RANGE));
+ *MemoryRangeCount = AllRangePiecesCountActual;
+
+ free (AllEndPointsInclusive);
+ free (AllRangePieces);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c
new file mode 100644
index 00000000..c5d4c3c0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.c
@@ -0,0 +1,84 @@
+/** @file
+Null instance of Platform Sec Lib.
+
+Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Ppi/SecPlatformInformation.h>
+
+/**
+ A developer supplied function to perform platform specific operations.
+
+ It's a developer supplied function to perform any operations appropriate to a
+ given platform. It's invoked just before passing control to PEI core by SEC
+ core. Platform developer may modify the SecCoreData passed to PEI Core.
+ It returns a platform specific PPI list that platform wishes to pass to PEI core.
+ The Generic SEC core module will merge this list to join the final list passed to
+ PEI core.
+
+ @param SecCoreData The same parameter as passing to PEI core. It
+ could be overridden by this function.
+
+ @return The platform specific PPI list to be passed to PEI core or
+ NULL if there is no need of such platform specific PPI list.
+
+**/
+EFI_PEI_PPI_DESCRIPTOR *
+EFIAPI
+SecPlatformMain (
+ IN OUT EFI_SEC_PEI_HAND_OFF *SecCoreData
+ )
+{
+ return NULL;
+}
+
+/**
+ This interface conveys state information out of the Security (SEC) phase into PEI.
+
+ @param PeiServices Pointer to the PEI Services Table.
+ @param StructureSize Pointer to the variable describing size of the input buffer.
+ @param PlatformInformationRecord Pointer to the EFI_SEC_PLATFORM_INFORMATION_RECORD.
+
+ @retval EFI_SUCCESS The data was successfully returned.
+ @retval EFI_BUFFER_TOO_SMALL The buffer was too small.
+
+**/
+EFI_STATUS
+EFIAPI
+SecPlatformInformation (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN OUT UINT64 *StructureSize,
+ OUT EFI_SEC_PLATFORM_INFORMATION_RECORD *PlatformInformationRecord
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ This interface disables temporary memory in SEC Phase.
+**/
+VOID
+EFIAPI
+SecPlatformDisableTemporaryMemory (
+ VOID
+ )
+{
+}
+
+/**
+ This function provides dummy function so that SecCore can pass build
+ validation. All real platform library instances need to implement the real
+ entry point in assembly.
+**/
+VOID
+EFIAPI
+_ModuleEntryPoint (
+ VOID
+ )
+{
+ return;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
new file mode 100644
index 00000000..876bc854
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.inf
@@ -0,0 +1,31 @@
+## @file
+# Library functions for PlatformSecLib.
+#
+# Null instance of Platform Sec Lib.
+#
+# Copyright (c) 2013 - 2015, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformSecLibNull
+ MODULE_UNI_FILE = PlatformSecLibNull.uni
+ FILE_GUID = 6695974D-968C-420b-80B9-7870CD20118F
+ MODULE_TYPE = SEC
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformSecLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ PlatformSecLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni
new file mode 100644
index 00000000..42f46137
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/PlatformSecLibNull/PlatformSecLibNull.uni
@@ -0,0 +1,14 @@
+// /** @file
+// Library functions for PlatformSecLib.
+//
+// Null instance of Platform Sec Library.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "Library functions for PlatformSecLib"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Null instance of Platform Sec Library."
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c
new file mode 100644
index 00000000..9c1c95c4
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c
@@ -0,0 +1,1190 @@
+/** @file
+ CPU Features Initialize functions.
+
+ Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RegisterCpuFeatures.h"
+
+CHAR16 *mDependTypeStr[] = {L"None", L"Thread", L"Core", L"Package", L"Invalid" };
+
+/**
+ Worker function to save PcdCpuFeaturesCapability.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+SetCapabilityPcd (
+ IN UINT8 *SupportedFeatureMask,
+ IN UINTN BitMaskSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PcdSetPtrS (PcdCpuFeaturesCapability, &BitMaskSize, SupportedFeatureMask);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to save PcdCpuFeaturesSetting.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+**/
+VOID
+SetSettingPcd (
+ IN UINT8 *SupportedFeatureMask,
+ IN UINTN BitMaskSize
+ )
+{
+ EFI_STATUS Status;
+
+ Status = PcdSetPtrS (PcdCpuFeaturesSetting, &BitMaskSize, SupportedFeatureMask);
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Collects CPU type and feature information.
+
+ @param[in, out] CpuInfo The pointer to CPU feature information
+**/
+VOID
+FillProcessorInfo (
+ IN OUT REGISTER_CPU_FEATURE_INFORMATION *CpuInfo
+ )
+{
+ CPUID_VERSION_INFO_EAX Eax;
+ CPUID_VERSION_INFO_ECX Ecx;
+ CPUID_VERSION_INFO_EDX Edx;
+ UINT32 DisplayedFamily;
+ UINT32 DisplayedModel;
+
+ AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, &Ecx.Uint32, &Edx.Uint32);
+
+ DisplayedFamily = Eax.Bits.FamilyId;
+ if (Eax.Bits.FamilyId == 0x0F) {
+ DisplayedFamily |= (Eax.Bits.ExtendedFamilyId << 4);
+ }
+
+ DisplayedModel = Eax.Bits.Model;
+ if (Eax.Bits.FamilyId == 0x06 || Eax.Bits.FamilyId == 0x0f) {
+ DisplayedModel |= (Eax.Bits.ExtendedModelId << 4);
+ }
+
+ CpuInfo->DisplayFamily = DisplayedFamily;
+ CpuInfo->DisplayModel = DisplayedModel;
+ CpuInfo->SteppingId = Eax.Bits.SteppingId;
+ CpuInfo->ProcessorType = Eax.Bits.ProcessorType;
+ CpuInfo->CpuIdVersionInfoEcx.Uint32 = Ecx.Uint32;
+ CpuInfo->CpuIdVersionInfoEdx.Uint32 = Edx.Uint32;
+}
+
+/**
+ Prepares for private data used for CPU features.
+
+**/
+VOID
+CpuInitDataInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorNumber;
+ EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;
+ CPU_FEATURES_ENTRY *CpuFeature;
+ CPU_FEATURES_INIT_ORDER *InitOrder;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ LIST_ENTRY *Entry;
+ UINT32 Core;
+ UINT32 Package;
+ UINT32 Thread;
+ EFI_CPU_PHYSICAL_LOCATION *Location;
+ UINT32 PackageIndex;
+ UINT32 CoreIndex;
+ UINTN Pages;
+ UINT32 FirstPackage;
+ UINT32 *FirstCore;
+ UINT32 *FirstThread;
+ ACPI_CPU_DATA *AcpiCpuData;
+ CPU_STATUS_INFORMATION *CpuStatus;
+ UINT32 *ThreadCountPerPackage;
+ UINT8 *ThreadCountPerCore;
+ UINTN NumberOfCpus;
+ UINTN NumberOfEnabledProcessors;
+
+ Core = 0;
+ Package = 0;
+ Thread = 0;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+
+ //
+ // Initialize CpuFeaturesData->MpService as early as possile, so later function can use it.
+ //
+ CpuFeaturesData->MpService = GetMpService ();
+
+ GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);
+
+ CpuFeaturesData->InitOrder = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (CPU_FEATURES_INIT_ORDER) * NumberOfCpus));
+ ASSERT (CpuFeaturesData->InitOrder != NULL);
+ ZeroMem (CpuFeaturesData->InitOrder, sizeof (CPU_FEATURES_INIT_ORDER) * NumberOfCpus);
+
+ //
+ // Collect CPU Features information
+ //
+ Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
+ while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+ ASSERT (CpuFeature->InitializeFunc != NULL);
+ if (CpuFeature->GetConfigDataFunc != NULL) {
+ CpuFeature->ConfigData = CpuFeature->GetConfigDataFunc (NumberOfCpus);
+ }
+ Entry = Entry->ForwardLink;
+ }
+
+ CpuFeaturesData->NumberOfCpus = (UINT32) NumberOfCpus;
+
+ AcpiCpuData = GetAcpiCpuData ();
+ ASSERT (AcpiCpuData != NULL);
+ CpuFeaturesData->AcpiCpuData= AcpiCpuData;
+
+ CpuStatus = &AcpiCpuData->CpuStatus;
+ Location = AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION) * NumberOfCpus);
+ ASSERT (Location != NULL);
+ AcpiCpuData->ApLocation = (EFI_PHYSICAL_ADDRESS)(UINTN)Location;
+
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ InitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
+ InitOrder->FeaturesSupportedMask = AllocateZeroPool (CpuFeaturesData->BitMaskSize);
+ ASSERT (InitOrder->FeaturesSupportedMask != NULL);
+ InitializeListHead (&InitOrder->OrderList);
+ Status = GetProcessorInformation (ProcessorNumber, &ProcessorInfoBuffer);
+ ASSERT_EFI_ERROR (Status);
+ CopyMem (
+ &InitOrder->CpuInfo.ProcessorInfo,
+ &ProcessorInfoBuffer,
+ sizeof (EFI_PROCESSOR_INFORMATION)
+ );
+ CopyMem (
+ &Location[ProcessorNumber],
+ &ProcessorInfoBuffer.Location,
+ sizeof (EFI_CPU_PHYSICAL_LOCATION)
+ );
+
+ //
+ // Collect CPU package count info.
+ //
+ if (Package < ProcessorInfoBuffer.Location.Package) {
+ Package = ProcessorInfoBuffer.Location.Package;
+ }
+ //
+ // Collect CPU max core count info.
+ //
+ if (Core < ProcessorInfoBuffer.Location.Core) {
+ Core = ProcessorInfoBuffer.Location.Core;
+ }
+ //
+ // Collect CPU max thread count info.
+ //
+ if (Thread < ProcessorInfoBuffer.Location.Thread) {
+ Thread = ProcessorInfoBuffer.Location.Thread;
+ }
+ }
+ CpuStatus->PackageCount = Package + 1;
+ CpuStatus->MaxCoreCount = Core + 1;
+ CpuStatus->MaxThreadCount = Thread + 1;
+ DEBUG ((DEBUG_INFO, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
+ CpuStatus->PackageCount,
+ CpuStatus->MaxCoreCount,
+ CpuStatus->MaxThreadCount));
+
+ //
+ // Collect valid core count in each package because not all cores are valid.
+ //
+ ThreadCountPerPackage = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount);
+ ASSERT (ThreadCountPerPackage != NULL);
+ CpuStatus->ThreadCountPerPackage = (EFI_PHYSICAL_ADDRESS)(UINTN)ThreadCountPerPackage;
+
+ ThreadCountPerCore = AllocateZeroPool (sizeof (UINT8) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount);
+ ASSERT (ThreadCountPerCore != NULL);
+ CpuStatus->ThreadCountPerCore = (EFI_PHYSICAL_ADDRESS)(UINTN)ThreadCountPerCore;
+
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;
+ ThreadCountPerPackage[Location->Package]++;
+ ThreadCountPerCore[Location->Package * CpuStatus->MaxCoreCount + Location->Core]++;
+ }
+
+ for (PackageIndex = 0; PackageIndex < CpuStatus->PackageCount; PackageIndex++) {
+ if (ThreadCountPerPackage[PackageIndex] != 0) {
+ DEBUG ((DEBUG_INFO, "P%02d: Thread Count = %d\n", PackageIndex, ThreadCountPerPackage[PackageIndex]));
+ for (CoreIndex = 0; CoreIndex < CpuStatus->MaxCoreCount; CoreIndex++) {
+ if (ThreadCountPerCore[PackageIndex * CpuStatus->MaxCoreCount + CoreIndex] != 0) {
+ DEBUG ((
+ DEBUG_INFO, " P%02d C%04d, Thread Count = %d\n", PackageIndex, CoreIndex,
+ ThreadCountPerCore[PackageIndex * CpuStatus->MaxCoreCount + CoreIndex]
+ ));
+ }
+ }
+ }
+ }
+
+ CpuFeaturesData->CpuFlags.CoreSemaphoreCount = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount);
+ ASSERT (CpuFeaturesData->CpuFlags.CoreSemaphoreCount != NULL);
+ CpuFeaturesData->CpuFlags.PackageSemaphoreCount = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount);
+ ASSERT (CpuFeaturesData->CpuFlags.PackageSemaphoreCount != NULL);
+
+ //
+ // Initialize CpuFeaturesData->InitOrder[].CpuInfo.First
+ // Use AllocatePages () instead of AllocatePool () because pool cannot be freed in PEI phase but page can.
+ //
+ Pages = EFI_SIZE_TO_PAGES (CpuStatus->PackageCount * sizeof (UINT32) + CpuStatus->PackageCount * CpuStatus->MaxCoreCount * sizeof (UINT32));
+ FirstCore = AllocatePages (Pages);
+ ASSERT (FirstCore != NULL);
+ FirstThread = FirstCore + CpuStatus->PackageCount;
+
+ //
+ // Set FirstPackage, FirstCore[], FirstThread[] to maximum package ID, core ID, thread ID.
+ //
+ FirstPackage = MAX_UINT32;
+ SetMem32 (FirstCore, CpuStatus->PackageCount * sizeof (UINT32), MAX_UINT32);
+ SetMem32 (FirstThread, CpuStatus->PackageCount * CpuStatus->MaxCoreCount * sizeof (UINT32), MAX_UINT32);
+
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;
+
+ //
+ // Save the minimum package ID in the platform.
+ //
+ FirstPackage = MIN (Location->Package, FirstPackage);
+
+ //
+ // Save the minimum core ID per package.
+ //
+ FirstCore[Location->Package] = MIN (Location->Core, FirstCore[Location->Package]);
+
+ //
+ // Save the minimum thread ID per core.
+ //
+ FirstThread[Location->Package * CpuStatus->MaxCoreCount + Location->Core] = MIN (
+ Location->Thread,
+ FirstThread[Location->Package * CpuStatus->MaxCoreCount + Location->Core]
+ );
+ }
+
+ //
+ // Update the First field.
+ //
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;
+
+ if (Location->Package == FirstPackage) {
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Package = 1;
+ }
+
+ //
+ // Set First.Die/Tile/Module for each thread assuming:
+ // single Die under each package, single Tile under each Die, single Module under each Tile
+ //
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Die = 1;
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Tile = 1;
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Module = 1;
+
+ if (Location->Core == FirstCore[Location->Package]) {
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Core = 1;
+ }
+ if (Location->Thread == FirstThread[Location->Package * CpuStatus->MaxCoreCount + Location->Core]) {
+ CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.First.Thread = 1;
+ }
+ }
+
+ FreePages (FirstCore, Pages);
+}
+
+/**
+ Worker function to do OR operation on CPU feature supported bits mask buffer.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] OrFeatureBitMask The feature bit mask to do OR operation
+ @param[in] BitMaskSize The CPU feature bits mask buffer size.
+
+**/
+VOID
+SupportedMaskOr (
+ IN UINT8 *SupportedFeatureMask,
+ IN UINT8 *OrFeatureBitMask,
+ IN UINT32 BitMaskSize
+ )
+{
+ UINTN Index;
+ UINT8 *Data1;
+ UINT8 *Data2;
+
+ Data1 = SupportedFeatureMask;
+ Data2 = OrFeatureBitMask;
+ for (Index = 0; Index < BitMaskSize; Index++) {
+ *(Data1++) |= *(Data2++);
+ }
+}
+
+/**
+ Worker function to do AND operation on CPU feature supported bits mask buffer.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] AndFeatureBitMask The feature bit mask to do AND operation
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+SupportedMaskAnd (
+ IN UINT8 *SupportedFeatureMask,
+ IN CONST UINT8 *AndFeatureBitMask,
+ IN UINT32 BitMaskSize
+ )
+{
+ UINTN Index;
+ UINT8 *Data1;
+ CONST UINT8 *Data2;
+
+ Data1 = SupportedFeatureMask;
+ Data2 = AndFeatureBitMask;
+ for (Index = 0; Index < BitMaskSize; Index++) {
+ *(Data1++) &= *(Data2++);
+ }
+}
+
+/**
+ Worker function to clean bit operation on CPU feature supported bits mask buffer.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+**/
+VOID
+SupportedMaskCleanBit (
+ IN UINT8 *SupportedFeatureMask,
+ IN UINT8 *AndFeatureBitMask,
+ IN UINT32 BitMaskSize
+ )
+{
+ UINTN Index;
+ UINT8 *Data1;
+ UINT8 *Data2;
+
+ Data1 = SupportedFeatureMask;
+ Data2 = AndFeatureBitMask;
+ for (Index = 0; Index < BitMaskSize; Index++) {
+ *(Data1++) &= ~(*(Data2++));
+ }
+}
+
+/**
+ Worker function to check if the compared CPU feature set in the CPU feature
+ supported bits mask buffer.
+
+ @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
+ @param[in] ComparedFeatureBitMask The feature bit mask to be compared
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+ @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
+ mask buffer.
+ @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
+ mask buffer.
+**/
+BOOLEAN
+IsBitMaskMatch (
+ IN UINT8 *SupportedFeatureMask,
+ IN UINT8 *ComparedFeatureBitMask,
+ IN UINT32 BitMaskSize
+ )
+{
+ UINTN Index;
+ UINT8 *Data1;
+ UINT8 *Data2;
+
+ Data1 = SupportedFeatureMask;
+ Data2 = ComparedFeatureBitMask;
+ for (Index = 0; Index < BitMaskSize; Index++) {
+ if (((*(Data1++)) & (*(Data2++))) != 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Collects processor data for calling processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+**/
+VOID
+EFIAPI
+CollectProcessorData (
+ IN OUT VOID *Buffer
+ )
+{
+ UINTN ProcessorNumber;
+ CPU_FEATURES_ENTRY *CpuFeature;
+ REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;
+ LIST_ENTRY *Entry;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = (CPU_FEATURES_DATA *)Buffer;
+ ProcessorNumber = GetProcessorIndex (CpuFeaturesData);
+ CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;
+ //
+ // collect processor information
+ //
+ FillProcessorInfo (CpuInfo);
+ Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
+ while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+ if (CpuFeature->SupportFunc == NULL) {
+ //
+ // If SupportFunc is NULL, then the feature is supported.
+ //
+ SupportedMaskOr (
+ CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
+ CpuFeature->FeatureMask,
+ CpuFeaturesData->BitMaskSize
+ );
+ } else if (CpuFeature->SupportFunc (ProcessorNumber, CpuInfo, CpuFeature->ConfigData)) {
+ SupportedMaskOr (
+ CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
+ CpuFeature->FeatureMask,
+ CpuFeaturesData->BitMaskSize
+ );
+ }
+ Entry = Entry->ForwardLink;
+ }
+}
+
+/**
+ Dump the contents of a CPU register table.
+
+ @param[in] ProcessorNumber The index of the CPU to show the register table contents
+
+ @note This service could be called by BSP only.
+**/
+VOID
+DumpRegisterTableOnProcessor (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ UINTN FeatureIndex;
+ CPU_REGISTER_TABLE *RegisterTable;
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
+ UINT32 DebugPrintErrorLevel;
+
+ DebugPrintErrorLevel = (ProcessorNumber == 0) ? DEBUG_INFO : DEBUG_VERBOSE;
+ CpuFeaturesData = GetCpuFeaturesData ();
+ //
+ // Debug information
+ //
+ RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];
+ DEBUG ((DebugPrintErrorLevel, "RegisterTable->TableLength = %d\n", RegisterTable->TableLength));
+
+ RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
+
+ for (FeatureIndex = 0; FeatureIndex < RegisterTable->TableLength; FeatureIndex++) {
+ RegisterTableEntry = &RegisterTableEntryHead[FeatureIndex];
+ switch (RegisterTableEntry->RegisterType) {
+ case Msr:
+ DEBUG ((
+ DebugPrintErrorLevel,
+ "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
+ (UINT32) ProcessorNumber,
+ (UINT32) FeatureIndex,
+ RegisterTableEntry->Index,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitLength,
+ RegisterTableEntry->Value
+ ));
+ break;
+ case ControlRegister:
+ DEBUG ((
+ DebugPrintErrorLevel,
+ "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
+ (UINT32) ProcessorNumber,
+ (UINT32) FeatureIndex,
+ RegisterTableEntry->Index,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitLength,
+ RegisterTableEntry->Value
+ ));
+ break;
+ case MemoryMapped:
+ DEBUG ((
+ DebugPrintErrorLevel,
+ "Processor: %04d: Index %04d, MMIO : %016lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
+ (UINT32) ProcessorNumber,
+ (UINT32) FeatureIndex,
+ RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32),
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitLength,
+ RegisterTableEntry->Value
+ ));
+ break;
+ case CacheControl:
+ DEBUG ((
+ DebugPrintErrorLevel,
+ "Processor: %04d: Index %04d, CACHE: %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
+ (UINT32) ProcessorNumber,
+ (UINT32) FeatureIndex,
+ RegisterTableEntry->Index,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitLength,
+ RegisterTableEntry->Value
+ ));
+ break;
+ case Semaphore:
+ DEBUG ((
+ DebugPrintErrorLevel,
+ "Processor: %04d: Index %04d, SEMAP: %s\r\n",
+ (UINT32) ProcessorNumber,
+ (UINT32) FeatureIndex,
+ mDependTypeStr[MIN ((UINT32)RegisterTableEntry->Value, InvalidDepType)]
+ ));
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ Get the biggest dependence type.
+ PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
+
+ @param[in] BeforeDep Before dependence type.
+ @param[in] AfterDep After dependence type.
+ @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
+ @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
+
+ @retval Return the biggest dependence type.
+**/
+CPU_FEATURE_DEPENDENCE_TYPE
+BiggestDep (
+ IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep,
+ IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep,
+ IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep,
+ IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
+ )
+{
+ CPU_FEATURE_DEPENDENCE_TYPE Bigger;
+
+ Bigger = MAX (BeforeDep, AfterDep);
+ Bigger = MAX (Bigger, NoneNeibBeforeDep);
+ return MAX(Bigger, NoneNeibAfterDep);
+}
+
+/**
+ Analysis register CPU features on each processor and save CPU setting in CPU register table.
+
+ @param[in] NumberOfCpus Number of processor in system
+
+**/
+VOID
+AnalysisProcessorFeatures (
+ IN UINTN NumberOfCpus
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorNumber;
+ CPU_FEATURES_ENTRY *CpuFeature;
+ CPU_FEATURES_ENTRY *CpuFeatureInOrder;
+ CPU_FEATURES_INIT_ORDER *CpuInitOrder;
+ REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;
+ LIST_ENTRY *Entry;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ LIST_ENTRY *NextEntry;
+ CPU_FEATURES_ENTRY *NextCpuFeatureInOrder;
+ BOOLEAN Success;
+ CPU_FEATURE_DEPENDENCE_TYPE BeforeDep;
+ CPU_FEATURE_DEPENDENCE_TYPE AfterDep;
+ CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep;
+ CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuFeaturesData->CapabilityPcd = AllocatePool (CpuFeaturesData->BitMaskSize);
+ ASSERT (CpuFeaturesData->CapabilityPcd != NULL);
+ SetMem (CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize, 0xFF);
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ CpuInitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
+ //
+ // Calculate the last capability on all processors
+ //
+ SupportedMaskAnd (CpuFeaturesData->CapabilityPcd, CpuInitOrder->FeaturesSupportedMask, CpuFeaturesData->BitMaskSize);
+ }
+ //
+ // Calculate the last setting
+ //
+ CpuFeaturesData->SettingPcd = AllocateCopyPool (CpuFeaturesData->BitMaskSize, CpuFeaturesData->CapabilityPcd);
+ ASSERT (CpuFeaturesData->SettingPcd != NULL);
+ SupportedMaskAnd (CpuFeaturesData->SettingPcd, PcdGetPtr (PcdCpuFeaturesSetting), CpuFeaturesData->BitMaskSize);
+
+ //
+ // Dump the last CPU feature list
+ //
+ DEBUG_CODE (
+ DEBUG ((DEBUG_INFO, "Last CPU features list...\n"));
+ Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
+ while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+ if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize)) {
+ if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->SettingPcd, CpuFeaturesData->BitMaskSize)) {
+ DEBUG ((DEBUG_INFO, "[Enable ] "));
+ } else {
+ DEBUG ((DEBUG_INFO, "[Disable ] "));
+ }
+ } else {
+ DEBUG ((DEBUG_INFO, "[Unsupport] "));
+ }
+ DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize);
+ Entry = Entry->ForwardLink;
+ }
+ DEBUG ((DEBUG_INFO, "PcdCpuFeaturesCapability:\n"));
+ DumpCpuFeatureMask (CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize);
+ DEBUG ((DEBUG_INFO, "Origin PcdCpuFeaturesSetting:\n"));
+ DumpCpuFeatureMask (PcdGetPtr (PcdCpuFeaturesSetting), CpuFeaturesData->BitMaskSize);
+ DEBUG ((DEBUG_INFO, "Final PcdCpuFeaturesSetting:\n"));
+ DumpCpuFeatureMask (CpuFeaturesData->SettingPcd, CpuFeaturesData->BitMaskSize);
+ );
+
+ //
+ // Save PCDs and display CPU PCDs
+ //
+ SetCapabilityPcd (CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize);
+ SetSettingPcd (CpuFeaturesData->SettingPcd, CpuFeaturesData->BitMaskSize);
+
+ for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
+ CpuInitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
+ Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
+ while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
+ //
+ // Insert each feature into processor's order list
+ //
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+ if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize)) {
+ CpuFeatureInOrder = AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY), CpuFeature);
+ ASSERT (CpuFeatureInOrder != NULL);
+ InsertTailList (&CpuInitOrder->OrderList, &CpuFeatureInOrder->Link);
+ }
+ Entry = Entry->ForwardLink;
+ }
+ //
+ // Go through ordered feature list to initialize CPU features
+ //
+ CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;
+ Entry = GetFirstNode (&CpuInitOrder->OrderList);
+ while (!IsNull (&CpuInitOrder->OrderList, Entry)) {
+ CpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+
+ Success = FALSE;
+ if (IsBitMaskMatch (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->SettingPcd, CpuFeaturesData->BitMaskSize)) {
+ Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, TRUE);
+ if (EFI_ERROR (Status)) {
+ //
+ // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
+ //
+ SupportedMaskCleanBit (CpuFeaturesData->SettingPcd, CpuFeatureInOrder->FeatureMask, CpuFeaturesData->BitMaskSize);
+ if (CpuFeatureInOrder->FeatureName != NULL) {
+ DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder->FeatureName));
+ } else {
+ DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Mask = "));
+ DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->BitMaskSize);
+ }
+ } else {
+ Success = TRUE;
+ }
+ } else {
+ Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, FALSE);
+ if (EFI_ERROR (Status)) {
+ if (CpuFeatureInOrder->FeatureName != NULL) {
+ DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder->FeatureName));
+ } else {
+ DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Mask = "));
+ DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->BitMaskSize);
+ }
+ } else {
+ Success = TRUE;
+ }
+ }
+
+ if (Success) {
+ NextEntry = Entry->ForwardLink;
+ if (!IsNull (&CpuInitOrder->OrderList, NextEntry)) {
+ NextCpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);
+
+ //
+ // If feature has dependence with the next feature (ONLY care core/package dependency).
+ // and feature initialize succeed, add sync semaphere here.
+ //
+ BeforeDep = DetectFeatureScope (CpuFeatureInOrder, TRUE, NextCpuFeatureInOrder->FeatureMask);
+ AfterDep = DetectFeatureScope (NextCpuFeatureInOrder, FALSE, CpuFeatureInOrder->FeatureMask);
+ //
+ // Check whether next feature has After type dependence with not neighborhood CPU
+ // Features in former CPU features.
+ //
+ NoneNeibAfterDep = DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder, FALSE, &CpuInitOrder->OrderList);
+ } else {
+ BeforeDep = NoneDepType;
+ AfterDep = NoneDepType;
+ NoneNeibAfterDep = NoneDepType;
+ }
+ //
+ // Check whether current feature has Before type dependence with none neighborhood
+ // CPU features in after Cpu features.
+ //
+ NoneNeibBeforeDep = DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder, TRUE, &CpuInitOrder->OrderList);
+
+ //
+ // Get the biggest dependence and add semaphore for it.
+ // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
+ //
+ BeforeDep = BiggestDep(BeforeDep, AfterDep, NoneNeibBeforeDep, NoneNeibAfterDep);
+ if (BeforeDep > ThreadDepType) {
+ CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber, Semaphore, 0, BeforeDep);
+ }
+ }
+
+ Entry = Entry->ForwardLink;
+ }
+
+ //
+ // Dump PcdCpuFeaturesSetting again because this value maybe updated
+ // again during initialize the features.
+ //
+ DEBUG ((DEBUG_INFO, "Dump final value for PcdCpuFeaturesSetting:\n"));
+ DumpCpuFeatureMask (CpuFeaturesData->SettingPcd, CpuFeaturesData->BitMaskSize);
+
+ //
+ // Dump the RegisterTable
+ //
+ DumpRegisterTableOnProcessor (ProcessorNumber);
+ }
+}
+
+/**
+ Increment semaphore by 1.
+
+ @param Sem IN: 32-bit unsigned integer
+
+**/
+VOID
+LibReleaseSemaphore (
+ IN OUT volatile UINT32 *Sem
+ )
+{
+ InterlockedIncrement (Sem);
+}
+
+/**
+ Decrement the semaphore by 1 if it is not zero.
+
+ Performs an atomic decrement operation for semaphore.
+ The compare exchange operation must be performed using
+ MP safe mechanisms.
+
+ @param Sem IN: 32-bit unsigned integer
+
+**/
+VOID
+LibWaitForSemaphore (
+ IN OUT volatile UINT32 *Sem
+ )
+{
+ UINT32 Value;
+
+ do {
+ Value = *Sem;
+ } while (Value == 0 ||
+ InterlockedCompareExchange32 (
+ Sem,
+ Value,
+ Value - 1
+ ) != Value);
+}
+
+/**
+ Read / write CR value.
+
+ @param[in] CrIndex The CR index which need to read/write.
+ @param[in] Read Read or write. TRUE is read.
+ @param[in,out] CrValue CR value.
+
+ @retval EFI_SUCCESS means read/write success, else return EFI_UNSUPPORTED.
+**/
+UINTN
+ReadWriteCr (
+ IN UINT32 CrIndex,
+ IN BOOLEAN Read,
+ IN OUT UINTN *CrValue
+ )
+{
+ switch (CrIndex) {
+ case 0:
+ if (Read) {
+ *CrValue = AsmReadCr0 ();
+ } else {
+ AsmWriteCr0 (*CrValue);
+ }
+ break;
+ case 2:
+ if (Read) {
+ *CrValue = AsmReadCr2 ();
+ } else {
+ AsmWriteCr2 (*CrValue);
+ }
+ break;
+ case 3:
+ if (Read) {
+ *CrValue = AsmReadCr3 ();
+ } else {
+ AsmWriteCr3 (*CrValue);
+ }
+ break;
+ case 4:
+ if (Read) {
+ *CrValue = AsmReadCr4 ();
+ } else {
+ AsmWriteCr4 (*CrValue);
+ }
+ break;
+ default:
+ return EFI_UNSUPPORTED;;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize the CPU registers from a register table.
+
+ @param[in] RegisterTable The register table for this AP.
+ @param[in] ApLocation AP location info for this ap.
+ @param[in] CpuStatus CPU status info for this CPU.
+ @param[in] CpuFlags Flags data structure used when program the register.
+
+ @note This service could be called by BSP/APs.
+**/
+VOID
+ProgramProcessorRegister (
+ IN CPU_REGISTER_TABLE *RegisterTable,
+ IN EFI_CPU_PHYSICAL_LOCATION *ApLocation,
+ IN CPU_STATUS_INFORMATION *CpuStatus,
+ IN PROGRAM_CPU_REGISTER_FLAGS *CpuFlags
+ )
+{
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
+ UINTN Index;
+ UINTN Value;
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
+ volatile UINT32 *SemaphorePtr;
+ UINT32 FirstThread;
+ UINT32 CurrentThread;
+ UINT32 CurrentCore;
+ UINTN ProcessorIndex;
+ UINT32 *ThreadCountPerPackage;
+ UINT8 *ThreadCountPerCore;
+ EFI_STATUS Status;
+ UINT64 CurrentValue;
+
+ //
+ // Traverse Register Table of this logical processor
+ //
+ RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
+
+ for (Index = 0; Index < RegisterTable->TableLength; Index++) {
+
+ RegisterTableEntry = &RegisterTableEntryHead[Index];
+
+ //
+ // Check the type of specified register
+ //
+ switch (RegisterTableEntry->RegisterType) {
+ //
+ // The specified register is Control Register
+ //
+ case ControlRegister:
+ Status = ReadWriteCr (RegisterTableEntry->Index, TRUE, &Value);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ if (RegisterTableEntry->TestThenWrite) {
+ CurrentValue = BitFieldRead64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1
+ );
+ if (CurrentValue == RegisterTableEntry->Value) {
+ break;
+ }
+ }
+ Value = (UINTN) BitFieldWrite64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ RegisterTableEntry->Value
+ );
+ ReadWriteCr (RegisterTableEntry->Index, FALSE, &Value);
+ break;
+
+ //
+ // The specified register is Model Specific Register
+ //
+ case Msr:
+ if (RegisterTableEntry->TestThenWrite) {
+ Value = (UINTN)AsmReadMsr64 (RegisterTableEntry->Index);
+ if (RegisterTableEntry->ValidBitLength >= 64) {
+ if (Value == RegisterTableEntry->Value) {
+ break;
+ }
+ } else {
+ CurrentValue = BitFieldRead64 (
+ Value,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1
+ );
+ if (CurrentValue == RegisterTableEntry->Value) {
+ break;
+ }
+ }
+ }
+
+ if (RegisterTableEntry->ValidBitLength >= 64) {
+ //
+ // If length is not less than 64 bits, then directly write without reading
+ //
+ AsmWriteMsr64 (
+ RegisterTableEntry->Index,
+ RegisterTableEntry->Value
+ );
+ } else {
+ //
+ // Set the bit section according to bit start and length
+ //
+ AsmMsrBitFieldWrite64 (
+ RegisterTableEntry->Index,
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ RegisterTableEntry->Value
+ );
+ }
+ break;
+ //
+ // MemoryMapped operations
+ //
+ case MemoryMapped:
+ AcquireSpinLock (&CpuFlags->MemoryMappedLock);
+ MmioBitFieldWrite32 (
+ (UINTN)(RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32)),
+ RegisterTableEntry->ValidBitStart,
+ RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
+ (UINT32)RegisterTableEntry->Value
+ );
+ ReleaseSpinLock (&CpuFlags->MemoryMappedLock);
+ break;
+ //
+ // Enable or disable cache
+ //
+ case CacheControl:
+ //
+ // If value of the entry is 0, then disable cache. Otherwise, enable cache.
+ //
+ if (RegisterTableEntry->Value == 0) {
+ AsmDisableCache ();
+ } else {
+ AsmEnableCache ();
+ }
+ break;
+
+ case Semaphore:
+ // Semaphore works logic like below:
+ //
+ // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
+ // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
+ //
+ // All threads (T0...Tn) waits in P() line and continues running
+ // together.
+ //
+ //
+ // T0 T1 ... Tn
+ //
+ // V(0...n) V(0...n) ... V(0...n)
+ // n * P(0) n * P(1) ... n * P(n)
+ //
+ switch (RegisterTableEntry->Value) {
+ case CoreDepType:
+ SemaphorePtr = CpuFlags->CoreSemaphoreCount;
+ ThreadCountPerCore = (UINT8 *)(UINTN)CpuStatus->ThreadCountPerCore;
+
+ CurrentCore = ApLocation->Package * CpuStatus->MaxCoreCount + ApLocation->Core;
+ //
+ // Get Offset info for the first thread in the core which current thread belongs to.
+ //
+ FirstThread = CurrentCore * CpuStatus->MaxThreadCount;
+ CurrentThread = FirstThread + ApLocation->Thread;
+
+ //
+ // Different cores may have different valid threads in them. If driver maintail clearly
+ // thread index in different cores, the logic will be much complicated.
+ // Here driver just simply records the max thread number in all cores and use it as expect
+ // thread number for all cores.
+ // In below two steps logic, first current thread will Release semaphore for each thread
+ // in current core. Maybe some threads are not valid in this core, but driver don't
+ // care. Second, driver will let current thread wait semaphore for all valid threads in
+ // current core. Because only the valid threads will do release semaphore for this
+ // thread, driver here only need to wait the valid thread count.
+ //
+
+ //
+ // First Notify ALL THREADs in current Core that this thread is ready.
+ //
+ for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {
+ LibReleaseSemaphore (&SemaphorePtr[FirstThread + ProcessorIndex]);
+ }
+ //
+ // Second, check whether all VALID THREADs (not all threads) in current core are ready.
+ //
+ for (ProcessorIndex = 0; ProcessorIndex < ThreadCountPerCore[CurrentCore]; ProcessorIndex ++) {
+ LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
+ }
+ break;
+
+ case PackageDepType:
+ SemaphorePtr = CpuFlags->PackageSemaphoreCount;
+ ThreadCountPerPackage = (UINT32 *)(UINTN)CpuStatus->ThreadCountPerPackage;
+ //
+ // Get Offset info for the first thread in the package which current thread belongs to.
+ //
+ FirstThread = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount;
+ //
+ // Get the possible threads count for current package.
+ //
+ CurrentThread = FirstThread + CpuStatus->MaxThreadCount * ApLocation->Core + ApLocation->Thread;
+
+ //
+ // Different packages may have different valid threads in them. If driver maintail clearly
+ // thread index in different packages, the logic will be much complicated.
+ // Here driver just simply records the max thread number in all packages and use it as expect
+ // thread number for all packages.
+ // In below two steps logic, first current thread will Release semaphore for each thread
+ // in current package. Maybe some threads are not valid in this package, but driver don't
+ // care. Second, driver will let current thread wait semaphore for all valid threads in
+ // current package. Because only the valid threads will do release semaphore for this
+ // thread, driver here only need to wait the valid thread count.
+ //
+
+ //
+ // First Notify ALL THREADS in current package that this thread is ready.
+ //
+ for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount * CpuStatus->MaxCoreCount; ProcessorIndex ++) {
+ LibReleaseSemaphore (&SemaphorePtr[FirstThread + ProcessorIndex]);
+ }
+ //
+ // Second, check whether VALID THREADS (not all threads) in current package are ready.
+ //
+ for (ProcessorIndex = 0; ProcessorIndex < ThreadCountPerPackage[ApLocation->Package]; ProcessorIndex ++) {
+ LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
+ }
+ break;
+
+ default:
+ break;
+ }
+ break;
+
+ default:
+ break;
+ }
+ }
+}
+
+/**
+ Programs registers for the calling processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+
+**/
+VOID
+EFIAPI
+SetProcessorRegister (
+ IN OUT VOID *Buffer
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ CPU_REGISTER_TABLE *RegisterTable;
+ CPU_REGISTER_TABLE *RegisterTables;
+ UINT32 InitApicId;
+ UINTN ProcIndex;
+ UINTN Index;
+ ACPI_CPU_DATA *AcpiCpuData;
+
+ CpuFeaturesData = (CPU_FEATURES_DATA *) Buffer;
+ AcpiCpuData = CpuFeaturesData->AcpiCpuData;
+
+ RegisterTables = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable;
+
+ InitApicId = GetInitialApicId ();
+ RegisterTable = NULL;
+ ProcIndex = (UINTN)-1;
+ for (Index = 0; Index < AcpiCpuData->NumberOfCpus; Index++) {
+ if (RegisterTables[Index].InitialApicId == InitApicId) {
+ RegisterTable = &RegisterTables[Index];
+ ProcIndex = Index;
+ break;
+ }
+ }
+ ASSERT (RegisterTable != NULL);
+
+ ProgramProcessorRegister (
+ RegisterTable,
+ (EFI_CPU_PHYSICAL_LOCATION *)(UINTN)AcpiCpuData->ApLocation + ProcIndex,
+ &AcpiCpuData->CpuStatus,
+ &CpuFeaturesData->CpuFlags
+ );
+}
+
+/**
+ Performs CPU features detection.
+
+ This service will invoke MP service to check CPU features'
+ capabilities on BSP/APs.
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+CpuFeaturesDetect (
+ VOID
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData();
+
+ CpuInitDataInitialize ();
+
+ if (CpuFeaturesData->NumberOfCpus > 1) {
+ //
+ // Wakeup all APs for data collection.
+ //
+ StartupAllAPsWorker (CollectProcessorData, NULL);
+ }
+
+ //
+ // Collect data on BSP
+ //
+ CollectProcessorData (CpuFeaturesData);
+
+ AnalysisProcessorFeatures (CpuFeaturesData->NumberOfCpus);
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.c
new file mode 100644
index 00000000..df43c63d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.c
@@ -0,0 +1,276 @@
+/** @file
+ CPU Register Table Library functions.
+
+ Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiDxe.h>
+
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+
+#include "RegisterCpuFeatures.h"
+
+CPU_FEATURES_DATA mCpuFeaturesData = {0};
+
+/**
+ Worker function to get CPU_FEATURES_DATA pointer.
+
+ @return Pointer to CPU_FEATURES_DATA.
+**/
+CPU_FEATURES_DATA *
+GetCpuFeaturesData (
+ VOID
+ )
+{
+ return &mCpuFeaturesData;
+}
+
+/**
+ Worker function to get EFI_MP_SERVICES_PROTOCOL pointer.
+
+ @return MP_SERVICES variable.
+**/
+MP_SERVICES
+GetMpService (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ MP_SERVICES MpService;
+
+ //
+ // Get MP Services Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **)&MpService.Protocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return MpService;
+}
+
+/**
+ Worker function to return processor index.
+
+ @param CpuFeaturesData Cpu Feature Data structure.
+
+ @return The processor index.
+**/
+UINTN
+GetProcessorIndex (
+ IN CPU_FEATURES_DATA *CpuFeaturesData
+ )
+{
+ EFI_STATUS Status;
+ UINTN ProcessorIndex;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+
+ MpServices = CpuFeaturesData->MpService.Protocol;
+ Status = MpServices->WhoAmI(MpServices, &ProcessorIndex);
+ ASSERT_EFI_ERROR (Status);
+ return ProcessorIndex;
+}
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @return Status of MpServices->GetProcessorInfo().
+**/
+EFI_STATUS
+GetProcessorInformation (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ MpServices = CpuFeaturesData->MpService.Protocol;
+
+ Status = MpServices->GetProcessorInfo (
+ MpServices,
+ ProcessorNumber,
+ ProcessorInfoBuffer
+ );
+ return Status;
+}
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] MpEvent A pointer to the event to be used later
+ to check whether procedure has done.
+**/
+VOID
+StartupAllAPsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN EFI_EVENT MpEvent
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ MpServices = CpuFeaturesData->MpService.Protocol;
+
+ //
+ // Wakeup all APs
+ //
+ Status = MpServices->StartupAllAPs (
+ MpServices,
+ Procedure,
+ FALSE,
+ MpEvent,
+ 0,
+ CpuFeaturesData,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+**/
+VOID
+SwitchNewBsp (
+ IN UINTN ProcessorNumber
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ MpServices = CpuFeaturesData->MpService.Protocol;
+
+ //
+ // Wakeup all APs
+ //
+ Status = MpServices->SwitchBSP (
+ MpServices,
+ ProcessorNumber,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to retrieve the number of logical processor in the platform.
+
+ @param[out] NumberOfCpus 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 system, including
+ the BSP.
+**/
+VOID
+GetNumberOfProcessor (
+ OUT UINTN *NumberOfCpus,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ EFI_STATUS Status;
+ EFI_MP_SERVICES_PROTOCOL *MpServices;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ MpServices = CpuFeaturesData->MpService.Protocol;
+
+ //
+ // Get the number of CPUs
+ //
+ Status = MpServices->GetNumberOfProcessors (
+ MpServices,
+ NumberOfCpus,
+ NumberOfEnabledProcessors
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Performs CPU features Initialization.
+
+ This service will invoke MP service to perform CPU features
+ initialization on BSP/APs per user configuration.
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+CpuFeaturesInitialize (
+ VOID
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ UINTN OldBspNumber;
+ EFI_EVENT MpEvent;
+ EFI_STATUS Status;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+
+ OldBspNumber = GetProcessorIndex (CpuFeaturesData);
+ CpuFeaturesData->BspNumber = OldBspNumber;
+
+ //
+ //
+ // Initialize MpEvent to suppress incorrect compiler/analyzer warnings.
+ //
+ MpEvent = NULL;
+
+ if (CpuFeaturesData->NumberOfCpus > 1) {
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_CALLBACK,
+ EfiEventEmptyFunction,
+ NULL,
+ &MpEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Wakeup all APs for programming.
+ //
+ StartupAllAPsWorker (SetProcessorRegister, MpEvent);
+ }
+
+ //
+ // Programming BSP
+ //
+ SetProcessorRegister (CpuFeaturesData);
+
+ if (CpuFeaturesData->NumberOfCpus > 1) {
+ //
+ // Wait all processors to finish the task.
+ //
+ do {
+ Status = gBS->CheckEvent (MpEvent);
+ } while (Status == EFI_NOT_READY);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Switch to new BSP if required
+ //
+ if (CpuFeaturesData->BspNumber != OldBspNumber) {
+ SwitchNewBsp (CpuFeaturesData->BspNumber);
+ }
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf
new file mode 100644
index 00000000..7eca3c85
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/DxeRegisterCpuFeaturesLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Register CPU Features Library DXE instance.
+#
+# Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeRegisterCpuFeaturesLib
+ MODULE_UNI_FILE = RegisterCpuFeaturesLib.uni
+ FILE_GUID = ADE8F745-AA2E-49f6-8ED4-746B34867E52
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RegisterCpuFeaturesLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ DxeRegisterCpuFeaturesLib.c
+ RegisterCpuFeaturesLib.c
+ RegisterCpuFeatures.h
+ CpuFeaturesInitialize.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ PcdLib
+ LocalApicLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ SynchronizationLib
+ UefiBootServicesTableLib
+ IoLib
+ UefiBootServicesTableLib
+ UefiLib
+
+[Protocols]
+ gEfiMpServiceProtocolGuid ## CONSUMES
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSupport ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesCapability ## PRODUCES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSetting ## PRODUCES ## CONSUMES
+
+[Depex]
+ gEfiMpServiceProtocolGuid AND gEdkiiCpuFeaturesSetDoneGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.c
new file mode 100644
index 00000000..860a5295
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.c
@@ -0,0 +1,309 @@
+/** @file
+ CPU Register Table Library functions.
+
+ Copyright (c) 2016 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiPei.h>
+
+#include <Library/HobLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Ppi/MpServices2.h>
+
+#include "RegisterCpuFeatures.h"
+
+#define REGISTER_CPU_FEATURES_GUID \
+ { \
+ 0xa694c467, 0x697a, 0x446b, { 0xb9, 0x29, 0x5b, 0x14, 0xa0, 0xcf, 0x39, 0xf } \
+ }
+
+EFI_GUID mRegisterCpuFeaturesHobGuid = REGISTER_CPU_FEATURES_GUID;
+
+/**
+ Worker function to get CPU_FEATURES_DATA pointer.
+
+ @return Pointer to CPU_FEATURES_DATA.
+**/
+CPU_FEATURES_DATA *
+GetCpuFeaturesData (
+ VOID
+ )
+{
+ CPU_FEATURES_DATA *CpuInitData;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ VOID *DataInHob;
+ UINT64 Data64;
+
+ CpuInitData = NULL;
+ GuidHob = GetFirstGuidHob (&mRegisterCpuFeaturesHobGuid);
+ if (GuidHob != NULL) {
+ DataInHob = GET_GUID_HOB_DATA (GuidHob);
+ CpuInitData = (CPU_FEATURES_DATA *) (*(UINTN *) DataInHob);
+ ASSERT (CpuInitData != NULL);
+ } else {
+ CpuInitData = AllocateZeroPool (sizeof (CPU_FEATURES_DATA));
+ ASSERT (CpuInitData != NULL);
+ //
+ // Build location of CPU MP DATA buffer in HOB
+ //
+ Data64 = (UINT64) (UINTN) CpuInitData;
+ BuildGuidDataHob (
+ &mRegisterCpuFeaturesHobGuid,
+ (VOID *) &Data64,
+ sizeof (UINT64)
+ );
+ }
+
+ return CpuInitData;
+}
+
+/**
+ Worker function to get MP PPI service pointer.
+
+ @return MP_SERVICES variable.
+**/
+MP_SERVICES
+GetMpService (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ MP_SERVICES MpService;
+
+ //
+ // Get MP Services2 Ppi
+ //
+ Status = PeiServicesLocatePpi (
+ &gEdkiiPeiMpServices2PpiGuid,
+ 0,
+ NULL,
+ (VOID **)&MpService.Ppi
+ );
+ ASSERT_EFI_ERROR (Status);
+ return MpService;
+}
+
+/**
+ Worker function to return processor index.
+
+ @param CpuFeaturesData Cpu Feature Data structure.
+
+ @return The processor index.
+**/
+UINTN
+GetProcessorIndex (
+ IN CPU_FEATURES_DATA *CpuFeaturesData
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ UINTN ProcessorIndex;
+
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+
+ //
+ // For two reasons which use NULL for WhoAmI:
+ // 1. This function will be called by APs and AP should not use PeiServices Table
+ // 2. Check WhoAmI implementation, this parameter will not be used.
+ //
+ Status = CpuMp2Ppi->WhoAmI (CpuMp2Ppi, &ProcessorIndex);
+ ASSERT_EFI_ERROR (Status);
+ return ProcessorIndex;
+}
+
+/**
+ Worker function to MP-related information on the requested processor at the
+ instant this call is made.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @return Status of MpServices->GetProcessorInfo().
+**/
+EFI_STATUS
+GetProcessorInformation (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ )
+{
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ EFI_STATUS Status;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+
+ Status = CpuMp2Ppi->GetProcessorInfo (
+ CpuMp2Ppi,
+ ProcessorNumber,
+ ProcessorInfoBuffer
+ );
+ return Status;
+}
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] MpEvent The Event used to sync the result.
+
+**/
+VOID
+StartupAllAPsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN EFI_EVENT MpEvent
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+
+ //
+ // Wakeup all APs for data collection.
+ //
+ Status = CpuMp2Ppi->StartupAllAPs (
+ CpuMp2Ppi,
+ Procedure,
+ FALSE,
+ 0,
+ CpuFeaturesData
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to execute a caller provided function on all enabled CPUs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled CPUs of the system.
+
+**/
+VOID
+StartupAllCPUsWorker (
+ IN EFI_AP_PROCEDURE Procedure
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+
+ //
+ // Get MP Services2 Ppi
+ //
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+ Status = CpuMp2Ppi->StartupAllCPUs (
+ CpuMp2Ppi,
+ Procedure,
+ 0,
+ CpuFeaturesData
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+**/
+VOID
+SwitchNewBsp (
+ IN UINTN ProcessorNumber
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+
+ //
+ // Wakeup all APs for data collection.
+ //
+ Status = CpuMp2Ppi->SwitchBSP (
+ CpuMp2Ppi,
+ ProcessorNumber,
+ TRUE
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Worker function to retrieve the number of logical processor in the platform.
+
+ @param[out] NumberOfCpus 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 system, including
+ the BSP.
+**/
+VOID
+GetNumberOfProcessor (
+ OUT UINTN *NumberOfCpus,
+ OUT UINTN *NumberOfEnabledProcessors
+ )
+{
+ EFI_STATUS Status;
+ EDKII_PEI_MP_SERVICES2_PPI *CpuMp2Ppi;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuMp2Ppi = CpuFeaturesData->MpService.Ppi;
+
+ //
+ // Get the number of CPUs
+ //
+ Status = CpuMp2Ppi->GetNumberOfProcessors (
+ CpuMp2Ppi,
+ NumberOfCpus,
+ NumberOfEnabledProcessors
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+ Performs CPU features Initialization.
+
+ This service will invoke MP service to perform CPU features
+ initialization on BSP/APs per user configuration.
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+CpuFeaturesInitialize (
+ VOID
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ UINTN OldBspNumber;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+
+ OldBspNumber = GetProcessorIndex (CpuFeaturesData);
+ CpuFeaturesData->BspNumber = OldBspNumber;
+
+ //
+ // Start to program register for all CPUs.
+ //
+ StartupAllCPUsWorker (SetProcessorRegister);
+
+ //
+ // Switch to new BSP if required
+ //
+ if (CpuFeaturesData->BspNumber != OldBspNumber) {
+ SwitchNewBsp (CpuFeaturesData->BspNumber);
+ }
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf
new file mode 100644
index 00000000..159cba73
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/PeiRegisterCpuFeaturesLib.inf
@@ -0,0 +1,57 @@
+## @file
+# Register CPU Features Library PEI instance.
+#
+# Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiRegisterCpuFeaturesLib
+ MODULE_UNI_FILE = RegisterCpuFeaturesLib.uni
+ FILE_GUID = D8855DB3-8348-41B5-BDA4-385351767D41
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RegisterCpuFeaturesLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources.common]
+ PeiRegisterCpuFeaturesLib.c
+ RegisterCpuFeaturesLib.c
+ RegisterCpuFeatures.h
+ CpuFeaturesInitialize.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ PcdLib
+ LocalApicLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ SynchronizationLib
+ HobLib
+ PeiServicesLib
+ PeiServicesTablePointerLib
+ IoLib
+
+[Ppis]
+ gEdkiiPeiMpServices2PpiGuid ## CONSUMES
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuS3DataAddress ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSupport ## CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesCapability ## PRODUCES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuFeaturesSetting ## CONSUMES ## PRODUCES
+
+[Depex]
+ gEdkiiPeiMpServices2PpiGuid AND gEdkiiCpuFeaturesSetDoneGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h
new file mode 100644
index 00000000..d798993a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeatures.h
@@ -0,0 +1,268 @@
+/** @file
+ CPU Register Table Library definitions.
+
+ Copyright (c) 2017 - 2020, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _REGISTER_CPU_FEATURES_H_
+#define _REGISTER_CPU_FEATURES_H_
+#include <PiPei.h>
+#include <PiDxe.h>
+#include <Ppi/MpServices2.h>
+#include <Protocol/MpService.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PcdLib.h>
+#include <Library/RegisterCpuFeaturesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/IoLib.h>
+#include <Library/LocalApicLib.h>
+
+#include <AcpiCpuData.h>
+
+#define CPU_FEATURE_ENTRY_SIGNATURE SIGNATURE_32 ('C', 'F', 'E', 'S')
+
+#define CPU_FEATURE_NAME_SIZE 128
+
+typedef struct {
+ REGISTER_CPU_FEATURE_INFORMATION CpuInfo;
+ UINT8 *FeaturesSupportedMask;
+ LIST_ENTRY OrderList;
+} CPU_FEATURES_INIT_ORDER;
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINT8 *FeatureMask;
+ CHAR8 *FeatureName;
+ CPU_FEATURE_GET_CONFIG_DATA GetConfigDataFunc;
+ CPU_FEATURE_SUPPORT SupportFunc;
+ CPU_FEATURE_INITIALIZE InitializeFunc;
+ UINT8 *ThreadBeforeFeatureBitMask;
+ UINT8 *ThreadAfterFeatureBitMask;
+ UINT8 *CoreBeforeFeatureBitMask;
+ UINT8 *CoreAfterFeatureBitMask;
+ UINT8 *PackageBeforeFeatureBitMask;
+ UINT8 *PackageAfterFeatureBitMask;
+ VOID *ConfigData;
+ BOOLEAN BeforeAll;
+ BOOLEAN AfterAll;
+} CPU_FEATURES_ENTRY;
+
+//
+// Flags used when program the register.
+//
+typedef struct {
+ volatile UINTN MemoryMappedLock; // Spinlock used to program mmio
+ volatile UINT32 *CoreSemaphoreCount; // Semaphore containers used to program Core semaphore.
+ volatile UINT32 *PackageSemaphoreCount; // Semaphore containers used to program Package semaphore.
+} PROGRAM_CPU_REGISTER_FLAGS;
+
+typedef union {
+ EFI_MP_SERVICES_PROTOCOL *Protocol;
+ EDKII_PEI_MP_SERVICES2_PPI *Ppi;
+} MP_SERVICES;
+
+typedef struct {
+ UINTN FeaturesCount;
+ UINT32 BitMaskSize;
+ LIST_ENTRY FeatureList;
+
+ CPU_FEATURES_INIT_ORDER *InitOrder;
+ UINT8 *CapabilityPcd;
+ UINT8 *SettingPcd;
+
+ UINT32 NumberOfCpus;
+ ACPI_CPU_DATA *AcpiCpuData;
+
+ CPU_REGISTER_TABLE *RegisterTable;
+ CPU_REGISTER_TABLE *PreSmmRegisterTable;
+ UINTN BspNumber;
+
+ PROGRAM_CPU_REGISTER_FLAGS CpuFlags;
+
+ MP_SERVICES MpService;
+} CPU_FEATURES_DATA;
+
+#define CPU_FEATURE_ENTRY_FROM_LINK(a) \
+ CR ( \
+ (a), \
+ CPU_FEATURES_ENTRY, \
+ Link, \
+ CPU_FEATURE_ENTRY_SIGNATURE \
+ )
+
+/**
+ Worker function to get CPU_FEATURES_DATA pointer.
+
+ @return Pointer to CPU_FEATURES_DATA.
+**/
+CPU_FEATURES_DATA *
+GetCpuFeaturesData (
+ VOID
+ );
+
+/**
+ Worker function to return processor index.
+
+ @param CpuFeaturesData Cpu Feature Data structure.
+
+ @return The processor index.
+**/
+UINTN
+GetProcessorIndex (
+ IN CPU_FEATURES_DATA *CpuFeaturesData
+ );
+
+/**
+ Gets detailed MP-related information on the requested processor at the
+ instant this call is made.
+
+ @param[in] ProcessorNumber The handle number of processor.
+ @param[out] ProcessorInfoBuffer A pointer to the buffer where information for
+ the requested processor is deposited.
+
+ @return Status of MpServices->GetProcessorInfo().
+**/
+EFI_STATUS
+GetProcessorInformation (
+ IN UINTN ProcessorNumber,
+ OUT EFI_PROCESSOR_INFORMATION *ProcessorInfoBuffer
+ );
+
+/**
+ Worker function to execute a caller provided function on all enabled APs.
+
+ @param[in] Procedure A pointer to the function to be run on
+ enabled APs of the system.
+ @param[in] MpEvent A pointer to the event to be used later
+ to check whether procedure has done.
+**/
+VOID
+StartupAllAPsWorker (
+ IN EFI_AP_PROCEDURE Procedure,
+ IN EFI_EVENT MpEvent
+ );
+
+/**
+ Worker function to retrieve the number of logical processor in the platform.
+
+ @param[out] NumberOfCpus 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 system, including
+ the BSP.
+**/
+VOID
+GetNumberOfProcessor (
+ OUT UINTN *NumberOfCpus,
+ OUT UINTN *NumberOfEnabledProcessors
+ );
+
+/**
+ Worker function to switch the requested AP to be the BSP from that point onward.
+
+ @param[in] ProcessorNumber The handle number of AP that is to become the new BSP.
+**/
+VOID
+SwitchNewBsp (
+ IN UINTN ProcessorNumber
+ );
+
+/**
+ Function that uses DEBUG() macros to display the contents of a a CPU feature bit mask.
+
+ @param[in] FeatureMask A pointer to the CPU feature bit mask.
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+DumpCpuFeatureMask (
+ IN UINT8 *FeatureMask,
+ IN UINT32 BitMaskSize
+ );
+
+/**
+ Dump CPU feature name or CPU feature bit mask.
+
+ @param[in] CpuFeature Pointer to CPU_FEATURES_ENTRY
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+DumpCpuFeature (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN UINT32 BitMaskSize
+ );
+
+/**
+ Return feature dependence result.
+
+ @param[in] CpuFeature Pointer to CPU feature.
+ @param[in] Before Check before dependence or after.
+ @param[in] NextCpuFeatureMask Pointer to next CPU feature Mask.
+
+ @retval return the dependence result.
+**/
+CPU_FEATURE_DEPENDENCE_TYPE
+DetectFeatureScope (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN BOOLEAN Before,
+ IN UINT8 *NextCpuFeatureMask
+ );
+
+/**
+ Return feature dependence result.
+
+ @param[in] CpuFeature Pointer to CPU feature.
+ @param[in] Before Check before dependence or after.
+ @param[in] FeatureList Pointer to CPU feature list.
+
+ @retval return the dependence result.
+**/
+CPU_FEATURE_DEPENDENCE_TYPE
+DetectNoneNeighborhoodFeatureScope (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN BOOLEAN Before,
+ IN LIST_ENTRY *FeatureList
+ );
+
+/**
+ Programs registers for the calling processor.
+
+ @param[in,out] Buffer The pointer to private data buffer.
+
+**/
+VOID
+EFIAPI
+SetProcessorRegister (
+ IN OUT VOID *Buffer
+ );
+
+/**
+ Return ACPI_CPU_DATA data.
+
+ @return Pointer to ACPI_CPU_DATA data.
+**/
+ACPI_CPU_DATA *
+GetAcpiCpuData (
+ VOID
+ );
+
+/**
+ Worker function to get MP service pointer.
+
+ @return MP_SERVICES variable.
+**/
+MP_SERVICES
+GetMpService (
+ VOID
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c
new file mode 100644
index 00000000..2661690e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.c
@@ -0,0 +1,1291 @@
+/** @file
+ CPU Register Table Library functions.
+
+ Copyright (c) 2017 - 2021, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include "RegisterCpuFeatures.h"
+
+/**
+ Function that uses DEBUG() macros to display the contents of a a CPU feature bit mask.
+
+ @param[in] FeatureMask A pointer to the CPU feature bit mask.
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+DumpCpuFeatureMask (
+ IN UINT8 *FeatureMask,
+ IN UINT32 BitMaskSize
+ )
+{
+ UINTN Index;
+ UINT8 *Data8;
+
+ Data8 = (UINT8 *) FeatureMask;
+ for (Index = 0; Index < BitMaskSize; Index++) {
+ DEBUG ((DEBUG_INFO, " %02x ", *Data8++));
+ }
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+ Dump CPU feature name or CPU feature bit mask.
+
+ @param[in] CpuFeature Pointer to CPU_FEATURES_ENTRY
+ @param[in] BitMaskSize CPU feature bits mask buffer size.
+
+**/
+VOID
+DumpCpuFeature (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN UINT32 BitMaskSize
+ )
+{
+
+ if (CpuFeature->FeatureName != NULL) {
+ DEBUG ((DEBUG_INFO, "FeatureName: %a\n", CpuFeature->FeatureName));
+ } else {
+ DEBUG ((DEBUG_INFO, "FeatureMask = "));
+ DumpCpuFeatureMask (CpuFeature->FeatureMask, BitMaskSize);
+ }
+}
+
+/**
+ Determines if the feature bit mask is in dependent CPU feature bit mask buffer.
+
+ @param[in] FeatureMask Pointer to CPU feature bit mask
+ @param[in] DependentBitMask Pointer to dependent CPU feature bit mask buffer
+
+ @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer.
+ @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer.
+**/
+BOOLEAN
+IsBitMaskMatchCheck (
+ IN UINT8 *FeatureMask,
+ IN UINT8 *DependentBitMask
+ )
+{
+ UINTN Index;
+ UINT8 *Data1;
+ UINT8 *Data2;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+
+ Data1 = FeatureMask;
+ Data2 = DependentBitMask;
+ for (Index = 0; Index < CpuFeaturesData->BitMaskSize; Index++) {
+ if (((*(Data1++)) & (*(Data2++))) != 0) {
+ return TRUE;
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Try to find the specify cpu featuren in former/after feature list.
+
+ @param[in] FeatureList Pointer to dependent CPU feature list
+ @param[in] CurrentEntry Pointer to current CPU feature entry.
+ @param[in] SearchFormer Find in former feature or after features.
+ @param[in] FeatureMask Pointer to CPU feature bit mask
+
+ @retval TRUE The feature bit mask is in dependent CPU feature bit mask buffer.
+ @retval FALSE The feature bit mask is not in dependent CPU feature bit mask buffer.
+**/
+BOOLEAN
+FindSpecifyFeature (
+ IN LIST_ENTRY *FeatureList,
+ IN LIST_ENTRY *CurrentEntry,
+ IN BOOLEAN SearchFormer,
+ IN UINT8 *FeatureMask
+ )
+{
+ CPU_FEATURES_ENTRY *CpuFeature;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Check whether exist the not neighborhood entry first.
+ // If not exist, return FALSE means not found status.
+ //
+ if (SearchFormer) {
+ NextEntry = CurrentEntry->BackLink;
+ if (IsNull (FeatureList, NextEntry)) {
+ return FALSE;
+ }
+
+ NextEntry = NextEntry->BackLink;
+ if (IsNull (FeatureList, NextEntry)) {
+ return FALSE;
+ }
+
+ NextEntry = CurrentEntry->BackLink->BackLink;
+ } else {
+ NextEntry = CurrentEntry->ForwardLink;
+ if (IsNull (FeatureList, NextEntry)) {
+ return FALSE;
+ }
+
+ NextEntry = NextEntry->ForwardLink;
+ if (IsNull (FeatureList, NextEntry)) {
+ return FALSE;
+ }
+
+ NextEntry = CurrentEntry->ForwardLink->ForwardLink;
+ }
+
+ while (!IsNull (FeatureList, NextEntry)) {
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);
+
+ if (IsBitMaskMatchCheck (FeatureMask, CpuFeature->FeatureMask)) {
+ return TRUE;
+ }
+
+ if (SearchFormer) {
+ NextEntry = NextEntry->BackLink;
+ } else {
+ NextEntry = NextEntry->ForwardLink;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Return feature dependence result.
+
+ @param[in] CpuFeature Pointer to CPU feature.
+ @param[in] Before Check before dependence or after.
+ @param[in] NextCpuFeatureMask Pointer to next CPU feature Mask.
+
+ @retval return the dependence result.
+**/
+CPU_FEATURE_DEPENDENCE_TYPE
+DetectFeatureScope (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN BOOLEAN Before,
+ IN UINT8 *NextCpuFeatureMask
+ )
+{
+ //
+ // if need to check before type dependence but the feature after current feature is not
+ // exist, means this before type dependence not valid, just return NoneDepType.
+ // Just like Feature A has a dependence of feature B, but Feature B not installed, so
+ // Feature A maybe insert to the last entry of the list. In this case, for below code,
+ // Featrure A has depend of feature B, but it is the last entry of the list, so the
+ // NextCpuFeatureMask is NULL, so the dependence for feature A here is useless and code
+ // just return NoneDepType.
+ //
+ if (NextCpuFeatureMask == NULL) {
+ return NoneDepType;
+ }
+
+ if (Before) {
+ if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageBeforeFeatureBitMask)) {
+ return PackageDepType;
+ }
+
+ if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreBeforeFeatureBitMask)) {
+ return CoreDepType;
+ }
+
+ if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadBeforeFeatureBitMask)) {
+ return ThreadDepType;
+ }
+
+ return NoneDepType;
+ }
+
+ if ((CpuFeature->PackageAfterFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->PackageAfterFeatureBitMask)) {
+ return PackageDepType;
+ }
+
+ if ((CpuFeature->CoreAfterFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->CoreAfterFeatureBitMask)) {
+ return CoreDepType;
+ }
+
+ if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) &&
+ IsBitMaskMatchCheck (NextCpuFeatureMask, CpuFeature->ThreadAfterFeatureBitMask)) {
+ return ThreadDepType;
+ }
+
+ return NoneDepType;
+}
+
+/**
+ Return feature dependence result.
+
+ @param[in] CpuFeature Pointer to CPU feature.
+ @param[in] Before Check before dependence or after.
+ @param[in] FeatureList Pointer to CPU feature list.
+
+ @retval return the dependence result.
+**/
+CPU_FEATURE_DEPENDENCE_TYPE
+DetectNoneNeighborhoodFeatureScope (
+ IN CPU_FEATURES_ENTRY *CpuFeature,
+ IN BOOLEAN Before,
+ IN LIST_ENTRY *FeatureList
+ )
+{
+ if (Before) {
+ if ((CpuFeature->PackageBeforeFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->PackageBeforeFeatureBitMask)) {
+ return PackageDepType;
+ }
+
+ if ((CpuFeature->CoreBeforeFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->CoreBeforeFeatureBitMask)) {
+ return CoreDepType;
+ }
+
+ if ((CpuFeature->ThreadBeforeFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, FALSE, CpuFeature->ThreadBeforeFeatureBitMask)) {
+ return ThreadDepType;
+ }
+
+ return NoneDepType;
+ }
+
+ if ((CpuFeature->PackageAfterFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->PackageAfterFeatureBitMask)) {
+ return PackageDepType;
+ }
+
+ if ((CpuFeature->CoreAfterFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->CoreAfterFeatureBitMask)) {
+ return CoreDepType;
+ }
+
+ if ((CpuFeature->ThreadAfterFeatureBitMask != NULL) &&
+ FindSpecifyFeature(FeatureList, &CpuFeature->Link, TRUE, CpuFeature->ThreadAfterFeatureBitMask)) {
+ return ThreadDepType;
+ }
+
+ return NoneDepType;
+}
+
+/**
+ Base on dependence relationship to asjust feature dependence.
+
+ ONLY when the feature before(or after) the find feature also has
+ dependence with the find feature. In this case, driver need to base
+ on dependce relationship to decide how to insert current feature and
+ adjust the feature dependence.
+
+ @param[in, out] PreviousFeature CPU feature current before the find one.
+ @param[in, out] CurrentFeature Cpu feature need to adjust.
+ @param[in] FindFeature Cpu feature which current feature depends.
+ @param[in] Before Before or after dependence relationship.
+
+ @retval TRUE means the current feature dependence has been adjusted.
+
+ @retval FALSE means the previous feature dependence has been adjusted.
+ or previous feature has no dependence with the find one.
+
+**/
+BOOLEAN
+AdjustFeaturesDependence (
+ IN OUT CPU_FEATURES_ENTRY *PreviousFeature,
+ IN OUT CPU_FEATURES_ENTRY *CurrentFeature,
+ IN CPU_FEATURES_ENTRY *FindFeature,
+ IN BOOLEAN Before
+ )
+{
+ CPU_FEATURE_DEPENDENCE_TYPE PreDependType;
+ CPU_FEATURE_DEPENDENCE_TYPE CurrentDependType;
+
+ PreDependType = DetectFeatureScope(PreviousFeature, Before, FindFeature->FeatureMask);
+ CurrentDependType = DetectFeatureScope(CurrentFeature, Before, FindFeature->FeatureMask);
+
+ //
+ // If previous feature has no dependence with the find featue.
+ // return FALSE.
+ //
+ if (PreDependType == NoneDepType) {
+ return FALSE;
+ }
+
+ //
+ // If both feature have dependence, keep the one which needs use more
+ // processors and clear the dependence for the other one.
+ //
+ if (PreDependType >= CurrentDependType) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Base on dependence relationship to asjust feature order.
+
+ @param[in] FeatureList Pointer to CPU feature list
+ @param[in, out] FindEntry The entry this feature depend on.
+ @param[in, out] CurrentEntry The entry for this feature.
+ @param[in] Before Before or after dependence relationship.
+
+**/
+VOID
+AdjustEntry (
+ IN LIST_ENTRY *FeatureList,
+ IN OUT LIST_ENTRY *FindEntry,
+ IN OUT LIST_ENTRY *CurrentEntry,
+ IN BOOLEAN Before
+ )
+{
+ LIST_ENTRY *PreviousEntry;
+ CPU_FEATURES_ENTRY *PreviousFeature;
+ CPU_FEATURES_ENTRY *CurrentFeature;
+ CPU_FEATURES_ENTRY *FindFeature;
+
+ //
+ // For CPU feature which has core or package type dependence, later code need to insert
+ // AcquireSpinLock/ReleaseSpinLock logic to sequency the execute order.
+ // So if driver finds both feature A and B need to execute before feature C, driver will
+ // base on dependence type of feature A and B to update the logic here.
+ // For example, feature A has package type dependence and feature B has core type dependence,
+ // because package type dependence need to wait for more processors which has strong dependence
+ // than core type dependence. So driver will adjust the feature order to B -> A -> C. and driver
+ // will remove the feature dependence in feature B.
+ // Driver just needs to make sure before feature C been executed, feature A has finished its task
+ // in all all thread. Feature A finished in all threads also means feature B have finshed in all
+ // threads.
+ //
+ if (Before) {
+ PreviousEntry = GetPreviousNode (FeatureList, FindEntry);
+ } else {
+
+ PreviousEntry = GetNextNode (FeatureList, FindEntry);
+ }
+
+ CurrentFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry);
+ RemoveEntryList (CurrentEntry);
+
+ if (IsNull (FeatureList, PreviousEntry)) {
+ //
+ // If not exist the previous or next entry, just insert the current entry.
+ //
+ if (Before) {
+ InsertTailList (FindEntry, CurrentEntry);
+ } else {
+ InsertHeadList (FindEntry, CurrentEntry);
+ }
+ } else {
+ //
+ // If exist the previous or next entry, need to check it before insert curent entry.
+ //
+ PreviousFeature = CPU_FEATURE_ENTRY_FROM_LINK (PreviousEntry);
+ FindFeature = CPU_FEATURE_ENTRY_FROM_LINK (FindEntry);
+
+ if (AdjustFeaturesDependence (PreviousFeature, CurrentFeature, FindFeature, Before)) {
+ //
+ // Return TRUE means current feature dependence has been cleared and the previous
+ // feature dependence has been kept and used. So insert current feature before (or after)
+ // the previous feature.
+ //
+ if (Before) {
+ InsertTailList (PreviousEntry, CurrentEntry);
+ } else {
+ InsertHeadList (PreviousEntry, CurrentEntry);
+ }
+ } else {
+ if (Before) {
+ InsertTailList (FindEntry, CurrentEntry);
+ } else {
+ InsertHeadList (FindEntry, CurrentEntry);
+ }
+ }
+ }
+}
+
+
+/**
+ Checks and adjusts current CPU features per dependency relationship.
+
+ @param[in] FeatureList Pointer to CPU feature list
+ @param[in] CurrentEntry Pointer to current checked CPU feature
+ @param[in] FeatureMask The feature bit mask.
+
+ @retval return Swapped info.
+**/
+BOOLEAN
+InsertToBeforeEntry (
+ IN LIST_ENTRY *FeatureList,
+ IN LIST_ENTRY *CurrentEntry,
+ IN UINT8 *FeatureMask
+ )
+{
+ LIST_ENTRY *CheckEntry;
+ CPU_FEATURES_ENTRY *CheckFeature;
+ BOOLEAN Swapped;
+
+ Swapped = FALSE;
+
+ //
+ // Check all features dispatched before this entry
+ //
+ CheckEntry = GetFirstNode (FeatureList);
+ while (CheckEntry != CurrentEntry) {
+ CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);
+ if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) {
+ AdjustEntry (FeatureList, CheckEntry, CurrentEntry, TRUE);
+ Swapped = TRUE;
+ break;
+ }
+ CheckEntry = CheckEntry->ForwardLink;
+ }
+
+ return Swapped;
+}
+
+/**
+ Checks and adjusts current CPU features per dependency relationship.
+
+ @param[in] FeatureList Pointer to CPU feature list
+ @param[in] CurrentEntry Pointer to current checked CPU feature
+ @param[in] FeatureMask The feature bit mask.
+
+ @retval return Swapped info.
+**/
+BOOLEAN
+InsertToAfterEntry (
+ IN LIST_ENTRY *FeatureList,
+ IN LIST_ENTRY *CurrentEntry,
+ IN UINT8 *FeatureMask
+ )
+{
+ LIST_ENTRY *CheckEntry;
+ CPU_FEATURES_ENTRY *CheckFeature;
+ BOOLEAN Swapped;
+
+ Swapped = FALSE;
+
+ //
+ // Check all features dispatched after this entry
+ //
+ CheckEntry = GetNextNode (FeatureList, CurrentEntry);
+ while (!IsNull (FeatureList, CheckEntry)) {
+ CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);
+ if (IsBitMaskMatchCheck (CheckFeature->FeatureMask, FeatureMask)) {
+ AdjustEntry (FeatureList, CheckEntry, CurrentEntry, FALSE);
+ Swapped = TRUE;
+ break;
+ }
+ CheckEntry = CheckEntry->ForwardLink;
+ }
+
+ return Swapped;
+}
+
+/**
+ Checks and adjusts CPU features order per dependency relationship.
+
+ @param[in] FeatureList Pointer to CPU feature list
+**/
+VOID
+CheckCpuFeaturesDependency (
+ IN LIST_ENTRY *FeatureList
+ )
+{
+ LIST_ENTRY *CurrentEntry;
+ CPU_FEATURES_ENTRY *CpuFeature;
+ LIST_ENTRY *CheckEntry;
+ CPU_FEATURES_ENTRY *CheckFeature;
+ BOOLEAN Swapped;
+ LIST_ENTRY *TempEntry;
+ LIST_ENTRY *NextEntry;
+
+ CurrentEntry = GetFirstNode (FeatureList);
+ while (!IsNull (FeatureList, CurrentEntry)) {
+ Swapped = FALSE;
+ CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (CurrentEntry);
+ NextEntry = CurrentEntry->ForwardLink;
+ if (CpuFeature->BeforeAll) {
+ //
+ // Check all features dispatched before this entry
+ //
+ CheckEntry = GetFirstNode (FeatureList);
+ while (CheckEntry != CurrentEntry) {
+ CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);
+ if (!CheckFeature->BeforeAll) {
+ //
+ // If this feature has no BeforeAll flag and is dispatched before CpuFeature,
+ // insert currentEntry before Checked feature
+ //
+ RemoveEntryList (CurrentEntry);
+ InsertTailList (CheckEntry, CurrentEntry);
+ Swapped = TRUE;
+ break;
+ }
+ CheckEntry = CheckEntry->ForwardLink;
+ }
+ if (Swapped) {
+ CurrentEntry = NextEntry;
+ continue;
+ }
+ }
+
+ if (CpuFeature->AfterAll) {
+ //
+ // Check all features dispatched after this entry
+ //
+ CheckEntry = GetNextNode (FeatureList, CurrentEntry);
+ while (!IsNull (FeatureList, CheckEntry)) {
+ CheckFeature = CPU_FEATURE_ENTRY_FROM_LINK (CheckEntry);
+ if (!CheckFeature->AfterAll) {
+ //
+ // If this feature has no AfterAll flag and is dispatched after CpuFeature,
+ // insert currentEntry after Checked feature
+ //
+ TempEntry = GetNextNode (FeatureList, CurrentEntry);
+ RemoveEntryList (CurrentEntry);
+ InsertHeadList (CheckEntry, CurrentEntry);
+ CurrentEntry = TempEntry;
+ Swapped = TRUE;
+ break;
+ }
+ CheckEntry = CheckEntry->ForwardLink;
+ }
+ if (Swapped) {
+ CurrentEntry = NextEntry;
+ continue;
+ }
+ }
+
+ if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) {
+ Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->ThreadBeforeFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ if (CpuFeature->ThreadAfterFeatureBitMask != NULL) {
+ Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->ThreadAfterFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ if (CpuFeature->CoreBeforeFeatureBitMask != NULL) {
+ Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->CoreBeforeFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ if (CpuFeature->CoreAfterFeatureBitMask != NULL) {
+ Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->CoreAfterFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ if (CpuFeature->PackageBeforeFeatureBitMask != NULL) {
+ Swapped = InsertToBeforeEntry (FeatureList, CurrentEntry, CpuFeature->PackageBeforeFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ if (CpuFeature->PackageAfterFeatureBitMask != NULL) {
+ Swapped = InsertToAfterEntry (FeatureList, CurrentEntry, CpuFeature->PackageAfterFeatureBitMask);
+ if (Swapped) {
+ continue;
+ }
+ }
+
+ CurrentEntry = CurrentEntry->ForwardLink;
+ }
+}
+
+/**
+ Worker function to register CPU Feature.
+
+ @param[in] CpuFeaturesData Pointer to CPU feature data structure.
+ @param[in] CpuFeature Pointer to CPU feature entry
+
+ @retval RETURN_SUCCESS The CPU feature was successfully registered.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register
+ the CPU feature.
+ @retval RETURN_UNSUPPORTED Registration of the CPU feature is not
+ supported due to a circular dependency between
+ BEFORE and AFTER features.
+**/
+RETURN_STATUS
+RegisterCpuFeatureWorker (
+ IN CPU_FEATURES_DATA *CpuFeaturesData,
+ IN CPU_FEATURES_ENTRY *CpuFeature
+ )
+{
+ EFI_STATUS Status;
+ CPU_FEATURES_ENTRY *CpuFeatureEntry;
+ LIST_ENTRY *Entry;
+ BOOLEAN FeatureExist;
+
+ FeatureExist = FALSE;
+ CpuFeatureEntry = NULL;
+ Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
+ while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
+ CpuFeatureEntry = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
+ if (CompareMem (CpuFeature->FeatureMask, CpuFeatureEntry->FeatureMask, CpuFeaturesData->BitMaskSize) == 0) {
+ //
+ // If this feature already registered
+ //
+ FeatureExist = TRUE;
+ break;
+ }
+ Entry = Entry->ForwardLink;
+ }
+
+ if (!FeatureExist) {
+ DEBUG ((DEBUG_INFO, "[NEW] "));
+ DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize);
+ InsertTailList (&CpuFeaturesData->FeatureList, &CpuFeature->Link);
+ CpuFeaturesData->FeaturesCount++;
+ } else {
+ DEBUG ((DEBUG_INFO, "[OVERRIDE] "));
+ DumpCpuFeature (CpuFeature, CpuFeaturesData->BitMaskSize);
+ ASSERT (CpuFeatureEntry != NULL);
+ //
+ // Overwrite original parameters of CPU feature
+ //
+ if (CpuFeature->GetConfigDataFunc != NULL) {
+ CpuFeatureEntry->GetConfigDataFunc = CpuFeature->GetConfigDataFunc;
+ }
+ if (CpuFeature->SupportFunc != NULL) {
+ CpuFeatureEntry->SupportFunc = CpuFeature->SupportFunc;
+ }
+ if (CpuFeature->InitializeFunc != NULL) {
+ CpuFeatureEntry->InitializeFunc = CpuFeature->InitializeFunc;
+ }
+ if (CpuFeature->FeatureName != NULL) {
+ if (CpuFeatureEntry->FeatureName == NULL) {
+ CpuFeatureEntry->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE);
+ ASSERT (CpuFeatureEntry->FeatureName != NULL);
+ }
+ Status = AsciiStrCpyS (CpuFeatureEntry->FeatureName, CPU_FEATURE_NAME_SIZE, CpuFeature->FeatureName);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (CpuFeature->FeatureName);
+ }
+ if (CpuFeature->ThreadBeforeFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->ThreadBeforeFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->ThreadBeforeFeatureBitMask);
+ }
+ CpuFeatureEntry->ThreadBeforeFeatureBitMask = CpuFeature->ThreadBeforeFeatureBitMask;
+ }
+ if (CpuFeature->ThreadAfterFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->ThreadAfterFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->ThreadAfterFeatureBitMask);
+ }
+ CpuFeatureEntry->ThreadAfterFeatureBitMask = CpuFeature->ThreadAfterFeatureBitMask;
+ }
+ if (CpuFeature->CoreBeforeFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->CoreBeforeFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->CoreBeforeFeatureBitMask);
+ }
+ CpuFeatureEntry->CoreBeforeFeatureBitMask = CpuFeature->CoreBeforeFeatureBitMask;
+ }
+ if (CpuFeature->CoreAfterFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->CoreAfterFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->CoreAfterFeatureBitMask);
+ }
+ CpuFeatureEntry->CoreAfterFeatureBitMask = CpuFeature->CoreAfterFeatureBitMask;
+ }
+ if (CpuFeature->PackageBeforeFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->PackageBeforeFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->PackageBeforeFeatureBitMask);
+ }
+ CpuFeatureEntry->PackageBeforeFeatureBitMask = CpuFeature->PackageBeforeFeatureBitMask;
+ }
+ if (CpuFeature->PackageAfterFeatureBitMask != NULL) {
+ if (CpuFeatureEntry->PackageAfterFeatureBitMask != NULL) {
+ FreePool (CpuFeatureEntry->PackageAfterFeatureBitMask);
+ }
+ CpuFeatureEntry->PackageAfterFeatureBitMask = CpuFeature->PackageAfterFeatureBitMask;
+ }
+
+ CpuFeatureEntry->BeforeAll = CpuFeature->BeforeAll;
+ CpuFeatureEntry->AfterAll = CpuFeature->AfterAll;
+
+ FreePool (CpuFeature->FeatureMask);
+ FreePool (CpuFeature);
+ }
+ //
+ // Verify CPU features dependency can change CPU feature order
+ //
+ CheckCpuFeaturesDependency (&CpuFeaturesData->FeatureList);
+ return RETURN_SUCCESS;
+}
+
+/**
+ Sets CPU feature bit mask in CPU feature bit mask buffer.
+
+ @param[in] FeaturesBitMask Pointer to CPU feature bit mask buffer
+ @param[in] Feature The bit number of the CPU feature
+ @param[in] BitMaskSize CPU feature bit mask buffer size
+**/
+VOID
+SetCpuFeaturesBitMask (
+ IN UINT8 **FeaturesBitMask,
+ IN UINT32 Feature,
+ IN UINTN BitMaskSize
+ )
+{
+ UINT8 *CpuFeaturesBitMask;
+
+ ASSERT (FeaturesBitMask != NULL);
+ CpuFeaturesBitMask = *FeaturesBitMask;
+ if (CpuFeaturesBitMask == NULL) {
+ CpuFeaturesBitMask = AllocateZeroPool (BitMaskSize);
+ ASSERT (CpuFeaturesBitMask != NULL);
+ *FeaturesBitMask = CpuFeaturesBitMask;
+ }
+
+ CpuFeaturesBitMask += (Feature / 8);
+ *CpuFeaturesBitMask |= (UINT8) (1 << (Feature % 8));
+}
+
+/**
+ Registers a CPU Feature.
+
+ @param[in] FeatureName A Null-terminated Ascii string indicates CPU feature
+ name.
+ @param[in] GetConfigDataFunc CPU feature get configuration data function. This
+ is an optional parameter that may be NULL. If NULL,
+ then the most recently registered function for the
+ CPU feature is used. If no functions are registered
+ for a CPU feature, then the CPU configuration data
+ for the registered feature is NULL.
+ @param[in] SupportFunc CPU feature support function. This is an optional
+ parameter that may be NULL. If NULL, then the most
+ recently registered function for the CPU feature is
+ used. If no functions are registered for a CPU
+ feature, then the CPU feature is assumed to be
+ supported by all CPUs.
+ @param[in] InitializeFunc CPU feature initialize function. This is an optional
+ parameter that may be NULL. If NULL, then the most
+ recently registered function for the CPU feature is
+ used. If no functions are registered for a CPU
+ feature, then the CPU feature initialization is
+ skipped.
+ @param[in] ... Variable argument list of UINT32 CPU feature value.
+ Values with no modifiers are the features provided
+ by the registered functions.
+ Values with CPU_FEATURE_BEFORE modifier are features
+ that must be initialized after the features provided
+ by the registered functions are used.
+ Values with CPU_FEATURE_AFTER modifier are features
+ that must be initialized before the features provided
+ by the registered functions are used.
+ The last argument in this variable argument list must
+ always be CPU_FEATURE_END.
+
+ @retval RETURN_SUCCESS The CPU feature was successfully registered.
+ @retval RETURN_OUT_OF_RESOURCES There are not enough resources to register
+ the CPU feature.
+ @retval RETURN_UNSUPPORTED Registration of the CPU feature is not
+ supported due to a circular dependency between
+ BEFORE and AFTER features.
+ @retval RETURN_NOT_READY CPU feature PCD PcdCpuFeaturesUserConfiguration
+ not updated by Platform driver yet.
+
+ @note This service could be called by BSP only.
+**/
+RETURN_STATUS
+EFIAPI
+RegisterCpuFeature (
+ IN CHAR8 *FeatureName, OPTIONAL
+ IN CPU_FEATURE_GET_CONFIG_DATA GetConfigDataFunc, OPTIONAL
+ IN CPU_FEATURE_SUPPORT SupportFunc, OPTIONAL
+ IN CPU_FEATURE_INITIALIZE InitializeFunc, OPTIONAL
+ ...
+ )
+{
+ EFI_STATUS Status;
+ VA_LIST Marker;
+ UINT32 Feature;
+ CPU_FEATURES_ENTRY *CpuFeature;
+ UINT8 *FeatureMask;
+ UINT8 *ThreadBeforeFeatureBitMask;
+ UINT8 *ThreadAfterFeatureBitMask;
+ UINT8 *CoreBeforeFeatureBitMask;
+ UINT8 *CoreAfterFeatureBitMask;
+ UINT8 *PackageBeforeFeatureBitMask;
+ UINT8 *PackageAfterFeatureBitMask;
+ BOOLEAN BeforeAll;
+ BOOLEAN AfterAll;
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ FeatureMask = NULL;
+ ThreadBeforeFeatureBitMask = NULL;
+ ThreadAfterFeatureBitMask = NULL;
+ CoreBeforeFeatureBitMask = NULL;
+ CoreAfterFeatureBitMask = NULL;
+ PackageBeforeFeatureBitMask = NULL;
+ PackageAfterFeatureBitMask = NULL;
+ BeforeAll = FALSE;
+ AfterAll = FALSE;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ if (CpuFeaturesData->FeaturesCount == 0) {
+ InitializeListHead (&CpuFeaturesData->FeatureList);
+ InitializeSpinLock (&CpuFeaturesData->CpuFlags.MemoryMappedLock);
+ //
+ // Code assumes below three PCDs have PCD same buffer size.
+ //
+ ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesCapability));
+ ASSERT (PcdGetSize (PcdCpuFeaturesSetting) == PcdGetSize (PcdCpuFeaturesSupport));
+ CpuFeaturesData->BitMaskSize = (UINT32) PcdGetSize (PcdCpuFeaturesSetting);
+ }
+
+ VA_START (Marker, InitializeFunc);
+ Feature = VA_ARG (Marker, UINT32);
+ while (Feature != CPU_FEATURE_END) {
+ //
+ // It's invalid to require a feature is before AND after all other features.
+ //
+ ASSERT ((Feature & (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL))
+ != (CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL));
+
+ //
+ // It's invalid to require feature A is before AND after before feature B,
+ // either in thread level, core level or package level.
+ //
+ ASSERT ((Feature & (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER))
+ != (CPU_FEATURE_THREAD_BEFORE | CPU_FEATURE_THREAD_AFTER));
+ ASSERT ((Feature & (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER))
+ != (CPU_FEATURE_CORE_BEFORE | CPU_FEATURE_CORE_AFTER));
+ ASSERT ((Feature & (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER))
+ != (CPU_FEATURE_PACKAGE_BEFORE | CPU_FEATURE_PACKAGE_AFTER));
+ if (Feature < CPU_FEATURE_THREAD_BEFORE) {
+ BeforeAll = ((Feature & CPU_FEATURE_BEFORE_ALL) != 0) ? TRUE : FALSE;
+ AfterAll = ((Feature & CPU_FEATURE_AFTER_ALL) != 0) ? TRUE : FALSE;
+ Feature &= ~(CPU_FEATURE_BEFORE_ALL | CPU_FEATURE_AFTER_ALL);
+ ASSERT (FeatureMask == NULL);
+ SetCpuFeaturesBitMask (&FeatureMask, Feature, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_THREAD_BEFORE) != 0) {
+ SetCpuFeaturesBitMask (&ThreadBeforeFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_BEFORE, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_THREAD_AFTER) != 0) {
+ SetCpuFeaturesBitMask (&ThreadAfterFeatureBitMask, Feature & ~CPU_FEATURE_THREAD_AFTER, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_CORE_BEFORE) != 0) {
+ SetCpuFeaturesBitMask (&CoreBeforeFeatureBitMask, Feature & ~CPU_FEATURE_CORE_BEFORE, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_CORE_AFTER) != 0) {
+ SetCpuFeaturesBitMask (&CoreAfterFeatureBitMask, Feature & ~CPU_FEATURE_CORE_AFTER, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_PACKAGE_BEFORE) != 0) {
+ SetCpuFeaturesBitMask (&PackageBeforeFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_BEFORE, CpuFeaturesData->BitMaskSize);
+ } else if ((Feature & CPU_FEATURE_PACKAGE_AFTER) != 0) {
+ SetCpuFeaturesBitMask (&PackageAfterFeatureBitMask, Feature & ~CPU_FEATURE_PACKAGE_AFTER, CpuFeaturesData->BitMaskSize);
+ }
+ Feature = VA_ARG (Marker, UINT32);
+ }
+ VA_END (Marker);
+
+ CpuFeature = AllocateZeroPool (sizeof (CPU_FEATURES_ENTRY));
+ ASSERT (CpuFeature != NULL);
+ CpuFeature->Signature = CPU_FEATURE_ENTRY_SIGNATURE;
+ CpuFeature->FeatureMask = FeatureMask;
+ CpuFeature->ThreadBeforeFeatureBitMask = ThreadBeforeFeatureBitMask;
+ CpuFeature->ThreadAfterFeatureBitMask = ThreadAfterFeatureBitMask;
+ CpuFeature->CoreBeforeFeatureBitMask = CoreBeforeFeatureBitMask;
+ CpuFeature->CoreAfterFeatureBitMask = CoreAfterFeatureBitMask;
+ CpuFeature->PackageBeforeFeatureBitMask = PackageBeforeFeatureBitMask;
+ CpuFeature->PackageAfterFeatureBitMask = PackageAfterFeatureBitMask;
+ CpuFeature->BeforeAll = BeforeAll;
+ CpuFeature->AfterAll = AfterAll;
+ CpuFeature->GetConfigDataFunc = GetConfigDataFunc;
+ CpuFeature->SupportFunc = SupportFunc;
+ CpuFeature->InitializeFunc = InitializeFunc;
+ if (FeatureName != NULL) {
+ CpuFeature->FeatureName = AllocatePool (CPU_FEATURE_NAME_SIZE);
+ ASSERT (CpuFeature->FeatureName != NULL);
+ Status = AsciiStrCpyS (CpuFeature->FeatureName, CPU_FEATURE_NAME_SIZE, FeatureName);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = RegisterCpuFeatureWorker (CpuFeaturesData, CpuFeature);
+ ASSERT_EFI_ERROR (Status);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Return ACPI_CPU_DATA data.
+
+ @return Pointer to ACPI_CPU_DATA data.
+**/
+ACPI_CPU_DATA *
+GetAcpiCpuData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumberOfCpus;
+ UINTN NumberOfEnabledProcessors;
+ ACPI_CPU_DATA *AcpiCpuData;
+ UINTN TableSize;
+ CPU_REGISTER_TABLE *RegisterTable;
+ UINTN Index;
+ EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;
+
+ AcpiCpuData = (ACPI_CPU_DATA *) (UINTN) PcdGet64 (PcdCpuS3DataAddress);
+ if (AcpiCpuData == NULL) {
+ AcpiCpuData = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (ACPI_CPU_DATA)));
+ ASSERT (AcpiCpuData != NULL);
+ ZeroMem (AcpiCpuData, sizeof (ACPI_CPU_DATA));
+
+ //
+ // Set PcdCpuS3DataAddress to the base address of the ACPI_CPU_DATA structure
+ //
+ Status = PcdSet64S (PcdCpuS3DataAddress, (UINT64)(UINTN)AcpiCpuData);
+ ASSERT_EFI_ERROR (Status);
+
+ GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);
+ AcpiCpuData->NumberOfCpus = (UINT32)NumberOfCpus;
+ }
+
+ if (AcpiCpuData->RegisterTable == 0 ||
+ AcpiCpuData->PreSmmInitRegisterTable == 0) {
+ //
+ // Allocate buffer for empty RegisterTable and PreSmmInitRegisterTable for all CPUs
+ //
+ NumberOfCpus = AcpiCpuData->NumberOfCpus;
+ TableSize = 2 * NumberOfCpus * sizeof (CPU_REGISTER_TABLE);
+ RegisterTable = AllocatePages (EFI_SIZE_TO_PAGES (TableSize));
+ ASSERT (RegisterTable != NULL);
+
+ for (Index = 0; Index < NumberOfCpus; Index++) {
+ Status = GetProcessorInformation (Index, &ProcessorInfoBuffer);
+ ASSERT_EFI_ERROR (Status);
+
+ RegisterTable[Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;
+ RegisterTable[Index].TableLength = 0;
+ RegisterTable[Index].AllocatedSize = 0;
+ RegisterTable[Index].RegisterTableEntry = 0;
+
+ RegisterTable[NumberOfCpus + Index].InitialApicId = (UINT32)ProcessorInfoBuffer.ProcessorId;
+ RegisterTable[NumberOfCpus + Index].TableLength = 0;
+ RegisterTable[NumberOfCpus + Index].AllocatedSize = 0;
+ RegisterTable[NumberOfCpus + Index].RegisterTableEntry = 0;
+ }
+ if (AcpiCpuData->RegisterTable == 0) {
+ AcpiCpuData->RegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)RegisterTable;
+ }
+ if (AcpiCpuData->PreSmmInitRegisterTable == 0) {
+ AcpiCpuData->PreSmmInitRegisterTable = (EFI_PHYSICAL_ADDRESS)(UINTN)(RegisterTable + NumberOfCpus);
+ }
+ }
+
+ return AcpiCpuData;
+}
+
+/**
+ Enlarges CPU register table for each processor.
+
+ @param[in, out] RegisterTable Pointer processor's CPU register table
+**/
+STATIC
+VOID
+EnlargeRegisterTable (
+ IN OUT CPU_REGISTER_TABLE *RegisterTable
+ )
+{
+ EFI_PHYSICAL_ADDRESS Address;
+ UINTN UsedPages;
+
+ UsedPages = RegisterTable->AllocatedSize / EFI_PAGE_SIZE;
+ Address = (UINTN)AllocatePages (UsedPages + 1);
+ ASSERT (Address != 0);
+
+ //
+ // If there are records existing in the register table, then copy its contents
+ // to new region and free the old one.
+ //
+ if (RegisterTable->AllocatedSize > 0) {
+ CopyMem (
+ (VOID *) (UINTN) Address,
+ (VOID *) (UINTN) RegisterTable->RegisterTableEntry,
+ RegisterTable->AllocatedSize
+ );
+
+ FreePages ((VOID *)(UINTN)RegisterTable->RegisterTableEntry, UsedPages);
+ }
+
+ //
+ // Adjust the allocated size and register table base address.
+ //
+ RegisterTable->AllocatedSize += EFI_PAGE_SIZE;
+ RegisterTable->RegisterTableEntry = Address;
+}
+
+/**
+ Add an entry in specified register table.
+
+ This function adds an entry in specified register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] PreSmmFlag If TRUE, entry will be added into PreSmm register table
+ If FALSE, entry will be added into register table
+ @param[in] ProcessorNumber The index of the CPU to add a register table entry
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValidBitStart Start of the bit section
+ @param[in] ValidBitLength Length of the bit section
+ @param[in] Value Value to write
+ @param[in] TestThenWrite Whether need to test current Value before writing.
+
+**/
+VOID
+CpuRegisterTableWriteWorker (
+ IN BOOLEAN PreSmmFlag,
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT64 Index,
+ IN UINT8 ValidBitStart,
+ IN UINT8 ValidBitLength,
+ IN UINT64 Value,
+ IN BOOLEAN TestThenWrite
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+ ACPI_CPU_DATA *AcpiCpuData;
+ CPU_REGISTER_TABLE *RegisterTable;
+ CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ if (CpuFeaturesData->RegisterTable == NULL) {
+ AcpiCpuData = GetAcpiCpuData ();
+ ASSERT ((AcpiCpuData != NULL) && (AcpiCpuData->RegisterTable != 0));
+ CpuFeaturesData->RegisterTable = (CPU_REGISTER_TABLE *) (UINTN) AcpiCpuData->RegisterTable;
+ CpuFeaturesData->PreSmmRegisterTable = (CPU_REGISTER_TABLE *) (UINTN) AcpiCpuData->PreSmmInitRegisterTable;
+ }
+
+ if (PreSmmFlag) {
+ RegisterTable = &CpuFeaturesData->PreSmmRegisterTable[ProcessorNumber];
+ } else {
+ RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];
+ }
+
+ if (RegisterTable->TableLength == RegisterTable->AllocatedSize / sizeof (CPU_REGISTER_TABLE_ENTRY)) {
+ EnlargeRegisterTable (RegisterTable);
+ }
+
+ //
+ // Append entry in the register table.
+ //
+ RegisterTableEntry = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
+ RegisterTableEntry[RegisterTable->TableLength].RegisterType = RegisterType;
+ RegisterTableEntry[RegisterTable->TableLength].Index = (UINT32) Index;
+ RegisterTableEntry[RegisterTable->TableLength].HighIndex = (UINT32) RShiftU64 (Index, 32);
+ RegisterTableEntry[RegisterTable->TableLength].ValidBitStart = ValidBitStart;
+ RegisterTableEntry[RegisterTable->TableLength].ValidBitLength = ValidBitLength;
+ RegisterTableEntry[RegisterTable->TableLength].Value = Value;
+ RegisterTableEntry[RegisterTable->TableLength].TestThenWrite = TestThenWrite;
+
+ RegisterTable->TableLength++;
+}
+
+/**
+ Adds an entry in specified register table.
+
+ This function adds an entry in specified register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] ProcessorNumber The index of the CPU to add a register table entry
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValueMask Mask of bits in register to write
+ @param[in] Value Value to write
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+CpuRegisterTableWrite (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT64 Index,
+ IN UINT64 ValueMask,
+ IN UINT64 Value
+ )
+{
+ UINT8 Start;
+ UINT8 End;
+ UINT8 Length;
+
+ Start = (UINT8)LowBitSet64 (ValueMask);
+ End = (UINT8)HighBitSet64 (ValueMask);
+ Length = End - Start + 1;
+ CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE);
+}
+
+/**
+ Adds an entry in specified register table.
+
+ This function adds an entry in specified register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] ProcessorNumber The index of the CPU to add a register table entry
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValueMask Mask of bits in register to write
+ @param[in] Value Value to write
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+CpuRegisterTableTestThenWrite (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT64 Index,
+ IN UINT64 ValueMask,
+ IN UINT64 Value
+ )
+{
+ UINT8 Start;
+ UINT8 End;
+ UINT8 Length;
+
+ Start = (UINT8)LowBitSet64 (ValueMask);
+ End = (UINT8)HighBitSet64 (ValueMask);
+ Length = End - Start + 1;
+ CpuRegisterTableWriteWorker (FALSE, ProcessorNumber, RegisterType, Index, Start, Length, Value, TRUE);
+}
+
+/**
+ Adds an entry in specified Pre-SMM register table.
+
+ This function adds an entry in specified register table, with given register type,
+ register index, bit section and value.
+
+ @param[in] ProcessorNumber The index of the CPU to add a register table entry.
+ @param[in] RegisterType Type of the register to program
+ @param[in] Index Index of the register to program
+ @param[in] ValueMask Mask of bits in register to write
+ @param[in] Value Value to write
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+PreSmmCpuRegisterTableWrite (
+ IN UINTN ProcessorNumber,
+ IN REGISTER_TYPE RegisterType,
+ IN UINT64 Index,
+ IN UINT64 ValueMask,
+ IN UINT64 Value
+ )
+{
+ UINT8 Start;
+ UINT8 End;
+ UINT8 Length;
+
+ Start = (UINT8)LowBitSet64 (ValueMask);
+ End = (UINT8)HighBitSet64 (ValueMask);
+ Length = End - Start + 1;
+ CpuRegisterTableWriteWorker (TRUE, ProcessorNumber, RegisterType, Index, Start, Length, Value, FALSE);
+}
+
+/**
+ Worker function to determine if a CPU feature is set in input CPU feature bit mask buffer.
+
+ @param[in] CpuBitMask CPU feature bit mask buffer
+ @param[in] CpuBitMaskSize The size of CPU feature bit mask buffer
+ @param[in] Feature The bit number of the CPU feature
+
+ @retval TRUE The CPU feature is set in CpuBitMask.
+ @retval FALSE The CPU feature is not set in CpuBitMask.
+
+**/
+BOOLEAN
+IsCpuFeatureSetInCpuPcd (
+ IN UINT8 *CpuBitMask,
+ IN UINTN CpuBitMaskSize,
+ IN UINT32 Feature
+ )
+{
+ if ((Feature >> 3) >= CpuBitMaskSize) {
+ return FALSE;
+ }
+ return ((*(CpuBitMask + (Feature >> 3)) & (1 << (Feature & 0x07))) != 0);
+}
+
+/**
+ Determines if a CPU feature is enabled in PcdCpuFeaturesSupport bit mask.
+ If a CPU feature is disabled in PcdCpuFeaturesSupport then all the code/data
+ associated with that feature should be optimized away if compiler
+ optimizations are enabled.
+
+ @param[in] Feature The bit number of the CPU feature to check in the PCD
+ PcdCpuFeaturesSupport
+
+ @retval TRUE The CPU feature is set in PcdCpuFeaturesSupport.
+ @retval FALSE The CPU feature is not set in PcdCpuFeaturesSupport.
+
+ @note This service could be called by BSP only.
+**/
+BOOLEAN
+EFIAPI
+IsCpuFeatureSupported (
+ IN UINT32 Feature
+ )
+{
+ return IsCpuFeatureSetInCpuPcd (
+ (UINT8 *)PcdGetPtr (PcdCpuFeaturesSupport),
+ PcdGetSize (PcdCpuFeaturesSupport),
+ Feature
+ );
+}
+
+/**
+ Determines if a CPU feature is set in PcdCpuFeaturesSetting bit mask.
+
+ @param[in] Feature The bit number of the CPU feature to check in the PCD
+ PcdCpuFeaturesSetting
+
+ @retval TRUE The CPU feature is set in PcdCpuFeaturesSetting.
+ @retval FALSE The CPU feature is not set in PcdCpuFeaturesSetting.
+
+ @note This service could be called by BSP only.
+**/
+BOOLEAN
+EFIAPI
+IsCpuFeatureInSetting (
+ IN UINT32 Feature
+ )
+{
+ return IsCpuFeatureSetInCpuPcd (
+ (UINT8 *)PcdGetPtr (PcdCpuFeaturesSetting),
+ PcdGetSize (PcdCpuFeaturesSetting),
+ Feature
+ );
+}
+
+/**
+ Switches to assigned BSP after CPU features initialization.
+
+ @param[in] ProcessorNumber The index of the CPU executing this function.
+
+ @note This service could be called by BSP only.
+**/
+VOID
+EFIAPI
+SwitchBspAfterFeaturesInitialize (
+ IN UINTN ProcessorNumber
+ )
+{
+ CPU_FEATURES_DATA *CpuFeaturesData;
+
+ CpuFeaturesData = GetCpuFeaturesData ();
+ CpuFeaturesData->BspNumber = ProcessorNumber;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.uni
new file mode 100644
index 00000000..fee90471
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib/RegisterCpuFeaturesLib.uni
@@ -0,0 +1,16 @@
+// /** @file
+// Register CPU Features Library instance.
+//
+// Register CPU Features Library instance.
+//
+// Copyright (c) 2017, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Register CPU Features Library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Register CPU Features Library instance."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
new file mode 100644
index 00000000..9b418381
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.inf
@@ -0,0 +1,54 @@
+## @file
+# Instance of Timer Library only using CPU resources.
+#
+# Timer Library that only uses CPU resources to provide calibrated delays
+# on IA-32, x64, and IPF.
+# Note: A driver of type DXE_RUNTIME_DRIVER and DXE_SMM_DRIVER can use this TimerLib
+# in their initialization without any issues. They only have to be careful in
+# the implementation of runtime services and SMI handlers.
+# Because CPU Local APIC and ITC could be programmed by OS, it cannot be
+# used by SMM drivers and runtime drivers, ACPI timer is recommended for SMM
+# drivers and runtime drivers.
+#
+# This library differs with the SecPeiDxeTimerLibCpu library in the MdePkg in
+# that it uses the local APIC library so that it supports x2APIC mode.
+#
+# Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+#
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SecPeiDxeTimerLibUefiCpu
+ MODULE_UNI_FILE = SecPeiDxeTimerLibUefiCpu.uni
+ FILE_GUID = 4FFF2014-2086-4ee6-9B58-886D1967861C
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = TimerLib
+
+
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ X86TimerLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+
+[LibraryClasses]
+ PcdLib
+ DebugLib
+ LocalApicLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdFSBClock ## SOMETIMES_CONSUMES
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.uni
new file mode 100644
index 00000000..e40ee106
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/SecPeiDxeTimerLibUefiCpu.uni
@@ -0,0 +1,26 @@
+// /** @file
+// Instance of Timer Library only using CPU resources.
+//
+// Timer Library that only uses CPU resources to provide calibrated delays
+// on IA-32, x64, and IPF.
+// Note: A driver of type DXE_RUNTIME_DRIVER and DXE_SMM_DRIVER can use this TimerLib
+// in their initialization without any issues. They only have to be careful in
+// the implementation of runtime services and SMI handlers.
+// Because CPU Local APIC and ITC could be programmed by OS, it cannot be
+// used by SMM drivers and runtime drivers, ACPI timer is recommended for SMM
+// drivers and runtime drivers.
+//
+// This library differs with the SecPeiDxeTimerLibCpu library in the MdePkg in
+// that it uses the local APIC library so that it supports x2APIC mode.
+//
+// Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "Instance of Timer Library only using CPU resources"
+
+#string STR_MODULE_DESCRIPTION #language en-US "Timer Library that only uses CPU resources to provide calibrated delays on IA-32, x64, and IPF. Note: A driver of type DXE_RUNTIME_DRIVER and DXE_SMM_DRIVER can use this TimerLib in their initialization without any issues. They only have to be careful in the implementation of runtime services and SMI handlers. Because CPU Local APIC and ITC could be programmed by OS, it cannot be used by SMM drivers and runtime drivers, ACPI timer is recommended for SMM drivers and runtime drivers. This library differs with the SecPeiDxeTimerLibCpu library in the MdePkg in that it uses the local APIC library so that it supports x2APIC mode."
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c
new file mode 100644
index 00000000..03683be8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SecPeiDxeTimerLibUefiCpu/X86TimerLib.c
@@ -0,0 +1,260 @@
+/** @file
+ Timer Library functions built upon local APIC on IA32/x64.
+
+ This library uses the local APIC library so that it supports x2APIC mode.
+
+ Copyright (c) 2010 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/TimerLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/LocalApicLib.h>
+
+/**
+ Internal function to return the frequency of the local APIC timer.
+
+ @return The frequency of the timer in Hz.
+
+**/
+UINT32
+EFIAPI
+InternalX86GetTimerFrequency (
+ VOID
+ )
+{
+ UINTN Divisor;
+
+ GetApicTimerState (&Divisor, NULL, NULL);
+ return PcdGet32(PcdFSBClock) / (UINT32)Divisor;
+}
+
+/**
+ Stalls the CPU for at least the given number of ticks.
+
+ Stalls the CPU for at least the given number of ticks. It's invoked by
+ MicroSecondDelay() and NanoSecondDelay().
+
+ This function will ASSERT if the APIC timer intial count returned from
+ GetApicTimerInitCount() is zero.
+
+ @param Delay A period of time to delay in ticks.
+
+**/
+VOID
+EFIAPI
+InternalX86Delay (
+ IN UINT32 Delay
+ )
+{
+ INT32 Ticks;
+ UINT32 Times;
+ UINT32 InitCount;
+ UINT32 StartTick;
+
+ //
+ // In case Delay is too larger, separate it into several small delay slot.
+ // Devided Delay by half value of Init Count is to avoid Delay close to
+ // the Init Count, timeout maybe missing if the time consuming between 2
+ // GetApicTimerCurrentCount() invoking is larger than the time gap between
+ // Delay and the Init Count.
+ //
+ InitCount = GetApicTimerInitCount ();
+ ASSERT (InitCount != 0);
+ Times = Delay / (InitCount / 2);
+ Delay = Delay % (InitCount / 2);
+
+ //
+ // Get Start Tick and do delay
+ //
+ StartTick = GetApicTimerCurrentCount ();
+ do {
+ //
+ // Wait until time out by Delay value
+ //
+ do {
+ CpuPause ();
+ //
+ // Get Ticks from Start to Current.
+ //
+ Ticks = StartTick - GetApicTimerCurrentCount ();
+ //
+ // Ticks < 0 means Timer wrap-arounds happens.
+ //
+ if (Ticks < 0) {
+ Ticks += InitCount;
+ }
+ } while ((UINT32)Ticks < Delay);
+
+ //
+ // Update StartTick and Delay for next delay slot
+ //
+ StartTick -= (StartTick > Delay) ? Delay : (Delay - InitCount);
+ Delay = InitCount / 2;
+ } while (Times-- > 0);
+}
+
+/**
+ Stalls the CPU for at least the given number of microseconds.
+
+ Stalls the CPU for the number of microseconds specified by MicroSeconds.
+
+ @param MicroSeconds The minimum number of microseconds to delay.
+
+ @return The value of MicroSeconds inputted.
+
+**/
+UINTN
+EFIAPI
+MicroSecondDelay (
+ IN UINTN MicroSeconds
+ )
+{
+ InternalX86Delay (
+ (UINT32)DivU64x32 (
+ MultU64x64 (
+ InternalX86GetTimerFrequency (),
+ MicroSeconds
+ ),
+ 1000000u
+ )
+ );
+ return MicroSeconds;
+}
+
+/**
+ Stalls the CPU for at least the given number of nanoseconds.
+
+ Stalls the CPU for the number of nanoseconds specified by NanoSeconds.
+
+ @param NanoSeconds The minimum number of nanoseconds to delay.
+
+ @return The value of NanoSeconds inputted.
+
+**/
+UINTN
+EFIAPI
+NanoSecondDelay (
+ IN UINTN NanoSeconds
+ )
+{
+ InternalX86Delay (
+ (UINT32)DivU64x32 (
+ MultU64x64 (
+ InternalX86GetTimerFrequency (),
+ NanoSeconds
+ ),
+ 1000000000u
+ )
+ );
+ return NanoSeconds;
+}
+
+/**
+ Retrieves the current value of a 64-bit free running performance counter.
+
+ The counter can either count up by 1 or count down by 1. If the physical
+ performance counter counts by a larger increment, then the counter values
+ must be translated. The properties of the counter can be retrieved from
+ GetPerformanceCounterProperties().
+
+ @return The current value of the free running performance counter.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounter (
+ VOID
+ )
+{
+ return (UINT64)GetApicTimerCurrentCount ();
+}
+
+/**
+ Retrieves the 64-bit frequency in Hz and the range of performance counter
+ values.
+
+ If StartValue is not NULL, then the value that the performance counter starts
+ with immediately after is it rolls over is returned in StartValue. If
+ EndValue is not NULL, then the value that the performance counter end with
+ immediately before it rolls over is returned in EndValue. The 64-bit
+ frequency of the performance counter in Hz is always returned. If StartValue
+ is less than EndValue, then the performance counter counts up. If StartValue
+ is greater than EndValue, then the performance counter counts down. For
+ example, a 64-bit free running counter that counts up would have a StartValue
+ of 0 and an EndValue of 0xFFFFFFFFFFFFFFFF. A 24-bit free running counter
+ that counts down would have a StartValue of 0xFFFFFF and an EndValue of 0.
+
+ @param StartValue The value the performance counter starts with when it
+ rolls over.
+ @param EndValue The value that the performance counter ends with before
+ it rolls over.
+
+ @return The frequency in Hz.
+
+**/
+UINT64
+EFIAPI
+GetPerformanceCounterProperties (
+ OUT UINT64 *StartValue, OPTIONAL
+ OUT UINT64 *EndValue OPTIONAL
+ )
+{
+ if (StartValue != NULL) {
+ *StartValue = (UINT64)GetApicTimerInitCount ();
+ }
+
+ if (EndValue != NULL) {
+ *EndValue = 0;
+ }
+
+ return (UINT64) InternalX86GetTimerFrequency ();
+}
+
+/**
+ Converts elapsed ticks of performance counter to time in nanoseconds.
+
+ This function converts the elapsed ticks of running performance counter to
+ time value in unit of nanoseconds.
+
+ @param Ticks The number of elapsed ticks of running performance counter.
+
+ @return The elapsed time in nanoseconds.
+
+**/
+UINT64
+EFIAPI
+GetTimeInNanoSecond (
+ IN UINT64 Ticks
+ )
+{
+ UINT64 Frequency;
+ UINT64 NanoSeconds;
+ UINT64 Remainder;
+ INTN Shift;
+
+ Frequency = GetPerformanceCounterProperties (NULL, NULL);
+
+ //
+ // Ticks
+ // Time = --------- x 1,000,000,000
+ // Frequency
+ //
+ NanoSeconds = MultU64x32 (DivU64x64Remainder (Ticks, Frequency, &Remainder), 1000000000u);
+
+ //
+ // Ensure (Remainder * 1,000,000,000) will not overflow 64-bit.
+ // Since 2^29 < 1,000,000,000 = 0x3B9ACA00 < 2^30, Remainder should < 2^(64-30) = 2^34,
+ // i.e. highest bit set in Remainder should <= 33.
+ //
+ Shift = MAX (0, HighBitSet64 (Remainder) - 33);
+ Remainder = RShiftU64 (Remainder, (UINTN) Shift);
+ Frequency = RShiftU64 (Frequency, (UINTN) Shift);
+ NanoSeconds += DivU64x64Remainder (MultU64x32 (Remainder, 1000000000u), Frequency, NULL);
+
+ return NanoSeconds;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/CpuFeaturesLib.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/CpuFeaturesLib.h
new file mode 100644
index 00000000..5928fbb8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/CpuFeaturesLib.h
@@ -0,0 +1,48 @@
+/** @file
+ Internal library function definitions.
+
+ Copyright (c) Microsoft Corporation.
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef CPU_FEATURES_LIB_H_
+#define CPU_FEATURES_LIB_H_
+
+/**
+ Performs library initialization.
+
+ This initialization function contains common functionality shared betwen all
+ library instance constructors.
+
+**/
+VOID
+CpuFeaturesLibInitialization (
+ VOID
+ );
+
+/**
+ Internal worker function that is called to complete CPU initialization at the
+ end of SmmCpuFeaturesInitializeProcessor().
+
+**/
+VOID
+FinishSmmCpuFeaturesInitializeProcessor (
+ VOID
+ );
+
+/**
+ Gets the maximum number of logical processors from the PCD PcdCpuMaxLogicalProcessorNumber.
+
+ This access is abstracted from the PCD services to enforce that the PCD be
+ FixedAtBuild in the Standalone MM build of this driver.
+
+ @return The value of PcdCpuMaxLogicalProcessorNumber.
+
+**/
+UINT32
+GetCpuMaxLogicalProcessorNumber (
+ VOID
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiEntry.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiEntry.nasm
new file mode 100644
index 00000000..2ff64510
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiEntry.nasm
@@ -0,0 +1,276 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; SmiEntry.nasm
+;
+; Abstract:
+;
+; Code template of the SMI handler for a particular processor
+;
+;-------------------------------------------------------------------------------
+
+%include "StuffRsbNasm.inc"
+
+%define MSR_IA32_MISC_ENABLE 0x1A0
+%define MSR_EFER 0xc0000080
+%define MSR_EFER_XD 0x800
+
+;
+; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
+;
+%define DSC_OFFSET 0xfb00
+%define DSC_GDTPTR 0x48
+%define DSC_GDTSIZ 0x50
+%define DSC_CS 0x14
+%define DSC_DS 0x16
+%define DSC_SS 0x18
+%define DSC_OTHERSEG 0x1a
+
+%define PROTECT_MODE_CS 0x8
+%define PROTECT_MODE_DS 0x20
+%define TSS_SEGMENT 0x40
+
+extern ASM_PFX(SmiRendezvous)
+extern ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))
+extern ASM_PFX(CpuSmmDebugEntry)
+extern ASM_PFX(CpuSmmDebugExit)
+
+global ASM_PFX(gcStmSmiHandlerTemplate)
+global ASM_PFX(gcStmSmiHandlerSize)
+global ASM_PFX(gcStmSmiHandlerOffset)
+global ASM_PFX(gStmSmiCr3)
+global ASM_PFX(gStmSmiStack)
+global ASM_PFX(gStmSmbase)
+global ASM_PFX(gStmXdSupported)
+extern ASM_PFX(gStmSmiHandlerIdtr)
+
+ASM_PFX(gStmSmiCr3) EQU StmSmiCr3Patch - 4
+ASM_PFX(gStmSmiStack) EQU StmSmiStackPatch - 4
+ASM_PFX(gStmSmbase) EQU StmSmbasePatch - 4
+ASM_PFX(gStmXdSupported) EQU StmXdSupportedPatch - 1
+
+ SECTION .text
+
+BITS 16
+ASM_PFX(gcStmSmiHandlerTemplate):
+_StmSmiEntryPoint:
+ mov bx, _StmGdtDesc - _StmSmiEntryPoint + 0x8000
+ mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
+ dec ax
+ mov [cs:bx], ax
+ mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
+ mov [cs:bx + 2], eax
+ mov ebp, eax ; ebp = GDT base
+o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
+ mov ax, PROTECT_MODE_CS
+ mov [cs:bx-0x2],ax
+o32 mov edi, strict dword 0
+StmSmbasePatch:
+ lea eax, [edi + (@32bit - _StmSmiEntryPoint) + 0x8000]
+ mov [cs:bx-0x6],eax
+ mov ebx, cr0
+ and ebx, 0x9ffafff3
+ or ebx, 0x23
+ mov cr0, ebx
+ jmp dword 0x0:0x0
+_StmGdtDesc:
+ DW 0
+ DD 0
+
+BITS 32
+@32bit:
+ mov ax, PROTECT_MODE_DS
+o16 mov ds, ax
+o16 mov es, ax
+o16 mov fs, ax
+o16 mov gs, ax
+o16 mov ss, ax
+ mov esp, strict dword 0
+StmSmiStackPatch:
+ mov eax, ASM_PFX(gStmSmiHandlerIdtr)
+ lidt [eax]
+ jmp ProtFlatMode
+
+ProtFlatMode:
+ mov eax, strict dword 0
+StmSmiCr3Patch:
+ mov cr3, eax
+;
+; Need to test for CR4 specific bit support
+;
+ mov eax, 1
+ cpuid ; use CPUID to determine if specific CR4 bits are supported
+ xor eax, eax ; Clear EAX
+ test edx, BIT2 ; Check for DE capabilities
+ jz .0
+ or eax, BIT3
+.0:
+ test edx, BIT6 ; Check for PAE capabilities
+ jz .1
+ or eax, BIT5
+.1:
+ test edx, BIT7 ; Check for MCE capabilities
+ jz .2
+ or eax, BIT6
+.2:
+ test edx, BIT24 ; Check for FXSR capabilities
+ jz .3
+ or eax, BIT9
+.3:
+ test edx, BIT25 ; Check for SSE capabilities
+ jz .4
+ or eax, BIT10
+.4: ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
+
+ cmp byte [dword ASM_PFX(FeaturePcdGet (PcdCpuSmmStackGuard))], 0
+ jz .6
+; Load TSS
+ mov byte [ebp + TSS_SEGMENT + 5], 0x89 ; clear busy flag
+ mov eax, TSS_SEGMENT
+ ltr ax
+.6:
+
+; enable NXE if supported
+ mov al, strict byte 1
+StmXdSupportedPatch:
+ cmp al, 0
+ jz @SkipXd
+;
+; Check XD disable bit
+;
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ push edx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .5
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.5:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+ jmp @XdDone
+@SkipXd:
+ sub esp, 4
+@XdDone:
+
+ mov ebx, cr0
+ or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
+ mov cr0, ebx
+ lea ebx, [edi + DSC_OFFSET]
+ mov ax, [ebx + DSC_DS]
+ mov ds, eax
+ mov ax, [ebx + DSC_OTHERSEG]
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ax, [ebx + DSC_SS]
+ mov ss, eax
+
+CommonHandler:
+ mov ebx, [esp + 4] ; CPU Index
+ push ebx
+ mov eax, ASM_PFX(CpuSmmDebugEntry)
+ call eax
+ add esp, 4
+
+ push ebx
+ mov eax, ASM_PFX(SmiRendezvous)
+ call eax
+ add esp, 4
+
+ push ebx
+ mov eax, ASM_PFX(CpuSmmDebugExit)
+ call eax
+ add esp, 4
+
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz .7
+ pop edx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .7
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.7:
+ StuffRsb32
+ rsm
+
+
+_StmSmiHandler:
+;
+; Check XD disable bit
+;
+ xor esi, esi
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz @StmXdDone
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov esi, edx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .5
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.5:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone:
+ push esi
+
+ ; below step is needed, because STM does not run above code.
+ ; we have to run below code to set IDT/CR0/CR4
+ mov eax, ASM_PFX(gStmSmiHandlerIdtr)
+ lidt [eax]
+
+ mov eax, cr0
+ or eax, 0x80010023 ; enable paging + WP + NE + MP + PE
+ mov cr0, eax
+;
+; Need to test for CR4 specific bit support
+;
+ mov eax, 1
+ cpuid ; use CPUID to determine if specific CR4 bits are supported
+ mov eax, cr4 ; init EAX
+ test edx, BIT2 ; Check for DE capabilities
+ jz .0
+ or eax, BIT3
+.0:
+ test edx, BIT6 ; Check for PAE capabilities
+ jz .1
+ or eax, BIT5
+.1:
+ test edx, BIT7 ; Check for MCE capabilities
+ jz .2
+ or eax, BIT6
+.2:
+ test edx, BIT24 ; Check for FXSR capabilities
+ jz .3
+ or eax, BIT9
+.3:
+ test edx, BIT25 ; Check for SSE capabilities
+ jz .4
+ or eax, BIT10
+.4: ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, eax ; in PreModifyMtrrs() to flush TLB.
+ ; STM init finish
+ jmp CommonHandler
+
+ASM_PFX(gcStmSmiHandlerSize) : DW $ - _StmSmiEntryPoint
+ASM_PFX(gcStmSmiHandlerOffset) : DW _StmSmiHandler - _StmSmiEntryPoint
+
+global ASM_PFX(SmmCpuFeaturesLibStmSmiEntryFixupAddress)
+ASM_PFX(SmmCpuFeaturesLibStmSmiEntryFixupAddress):
+ ret
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiException.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiException.nasm
new file mode 100644
index 00000000..d9ae5493
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmiException.nasm
@@ -0,0 +1,173 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; SmiException.nasm
+;
+; Abstract:
+;
+; Exception handlers used in SM mode
+;
+;-------------------------------------------------------------------------------
+
+%include "StuffRsbNasm.inc"
+
+global ASM_PFX(gcStmPsd)
+
+extern ASM_PFX(SmmStmExceptionHandler)
+extern ASM_PFX(SmmStmSetup)
+extern ASM_PFX(SmmStmTeardown)
+extern ASM_PFX(gStmXdSupported)
+extern ASM_PFX(gStmSmiHandlerIdtr)
+
+%define MSR_IA32_MISC_ENABLE 0x1A0
+%define MSR_EFER 0xc0000080
+%define MSR_EFER_XD 0x800
+
+CODE_SEL equ 0x08
+DATA_SEL equ 0x20
+TSS_SEL equ 0x40
+
+ SECTION .data
+
+ASM_PFX(gcStmPsd):
+ DB 'TXTPSSIG'
+ DW PSD_SIZE
+ DW 1 ; Version
+ DD 0 ; LocalApicId
+ DB 0x05 ; Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
+ DB 0 ; BIOS to STM
+ DB 0 ; STM to BIOS
+ DB 0
+ DW CODE_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW TSS_SEL
+ DW 0
+ DQ 0 ; SmmCr3
+ DD ASM_PFX(OnStmSetup)
+ DD 0
+ DD ASM_PFX(OnStmTeardown)
+ DD 0
+ DQ 0 ; SmmSmiHandlerRip - SMM guest entrypoint
+ DQ 0 ; SmmSmiHandlerRsp
+ DQ 0
+ DD 0
+ DD 0x80010100 ; RequiredStmSmmRevId
+ DD ASM_PFX(OnException)
+ DD 0
+ DQ 0 ; ExceptionStack
+ DW DATA_SEL
+ DW 0x01F ; ExceptionFilter
+ DD 0
+ DD 0
+ DD 0
+ DQ 0 ; BiosHwResourceRequirementsPtr
+ DQ 0 ; AcpiRsdp
+ DB 0 ; PhysicalAddressBits
+PSD_SIZE equ $ - ASM_PFX(gcStmPsd)
+
+ SECTION .text
+;------------------------------------------------------------------------------
+; SMM Exception handlers
+;------------------------------------------------------------------------------
+global ASM_PFX(OnException)
+ASM_PFX(OnException):
+ mov ecx, esp
+ push ecx
+ call ASM_PFX(SmmStmExceptionHandler)
+ add esp, 4
+
+ mov ebx, eax
+ mov eax, 4
+ vmcall
+ jmp $
+
+global ASM_PFX(OnStmSetup)
+ASM_PFX(OnStmSetup):
+;
+; Check XD disable bit
+;
+ xor esi, esi
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz @StmXdDone1
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov esi, edx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .51
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.51:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone1:
+ push esi
+
+ call ASM_PFX(SmmStmSetup)
+
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz .71
+ pop edx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .71
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.71:
+ StuffRsb32
+ rsm
+
+global ASM_PFX(OnStmTeardown)
+ASM_PFX(OnStmTeardown):
+;
+; Check XD disable bit
+;
+ xor esi, esi
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz @StmXdDone2
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov esi, edx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .52
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.52:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone2:
+ push esi
+
+ call ASM_PFX(SmmStmTeardown)
+
+ mov eax, ASM_PFX(gStmXdSupported)
+ mov al, [eax]
+ cmp al, 0
+ jz .72
+ pop edx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .72
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.72:
+ StuffRsb32
+ rsm
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmmStmSupport.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmmStmSupport.c
new file mode 100644
index 00000000..d6166b75
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/Ia32/SmmStmSupport.c
@@ -0,0 +1,77 @@
+/** @file
+ SMM STM support functions
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/DebugLib.h>
+
+#include "SmmStm.h"
+
+///
+/// Page Table Entry
+///
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+/**
+
+ Create 4G page table for STM.
+ 4M Non-PAE page table in IA32 version.
+
+ @param PageTableBase The page table base in MSEG
+
+**/
+VOID
+StmGen4GPageTable (
+ IN UINTN PageTableBase
+ )
+{
+ UINTN Index;
+ UINT32 *Pte;
+ UINT32 Address;
+
+ Pte = (UINT32*)(UINTN)PageTableBase;
+
+ Address = 0;
+ for (Index = 0; Index < SIZE_4KB / sizeof (*Pte); Index++) {
+ *Pte = Address | IA32_PG_PS | IA32_PG_RW | IA32_PG_P;
+ Pte++;
+ Address += SIZE_4MB;
+ }
+}
+
+/**
+ This is SMM exception handle.
+ Consumed by STM when exception happen.
+
+ @param Context STM protection exception stack frame
+
+ @return the EBX value for STM reference.
+ EBX = 0: resume SMM guest using register state found on exception stack.
+ EBX = 1 to 0x0F: EBX contains a BIOS error code which the STM must record in the
+ TXT.ERRORCODE register and subsequently reset the system via
+ TXT.CMD.SYS_RESET. The value of the TXT.ERRORCODE register is calculated as
+ follows: TXT.ERRORCODE = (EBX & 0x0F) | STM_CRASH_BIOS_PANIC
+ EBX = 0x10 to 0xFFFFFFFF - reserved, do not use.
+
+**/
+UINT32
+EFIAPI
+SmmStmExceptionHandler (
+ IN OUT STM_PROTECTION_EXCEPTION_STACK_FRAME Context
+ )
+{
+ // TBD - SmmStmExceptionHandler, record information
+ DEBUG ((DEBUG_ERROR, "SmmStmExceptionHandler ...\n"));
+ //
+ // Skip this instruction and continue;
+ //
+ Context.Ia32StackFrame->Rip += Context.Ia32StackFrame->VmcsExitInstructionLength;
+
+ return 0;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
new file mode 100644
index 00000000..7cb6639d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.c
@@ -0,0 +1,31 @@
+/** @file
+Implementation specific to the SmmCpuFeatureLib library instance.
+
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include "CpuFeaturesLib.h"
+
+/**
+ The constructor function for the Traditional MM library instance without STM.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ CpuFeaturesLibInitialization ();
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
new file mode 100644
index 00000000..e504218a
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.inf
@@ -0,0 +1,37 @@
+## @file
+# The CPU specific programming for PiSmmCpuDxeSmm module.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuFeaturesLib
+ MODULE_UNI_FILE = SmmCpuFeaturesLib.uni
+ FILE_GUID = FC3DC10D-D271-422a-AFF3-CBCF70344431
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmCpuFeaturesLib
+ CONSTRUCTOR = SmmCpuFeaturesLibConstructor
+
+[Sources]
+ CpuFeaturesLib.h
+ SmmCpuFeaturesLib.c
+ SmmCpuFeaturesLibCommon.c
+ SmmCpuFeaturesLibNoStm.c
+ TraditionalMmCpuFeaturesLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PcdLib
+ MemoryAllocationLib
+ DebugLib
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
new file mode 100644
index 00000000..6ee54e92
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLib.uni
@@ -0,0 +1,12 @@
+// /** @file
+// The CPU specific programming for PiSmmCpuDxeSmm module.
+//
+// Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."
+
+#string STR_MODULE_DESCRIPTION #language en-US "The CPU specific programming for PiSmmCpuDxeSmm module."
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibCommon.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibCommon.c
new file mode 100644
index 00000000..b5c55f38
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibCommon.c
@@ -0,0 +1,613 @@
+/** @file
+Implementation shared across all library instances.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include <Library/BaseLib.h>
+#include <Library/MtrrLib.h>
+#include <Library/PcdLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DebugLib.h>
+#include <Register/Intel/Cpuid.h>
+#include <Register/Intel/SmramSaveStateMap.h>
+#include "CpuFeaturesLib.h"
+
+//
+// Machine Specific Registers (MSRs)
+//
+#define SMM_FEATURES_LIB_IA32_MTRR_CAP 0x0FE
+#define SMM_FEATURES_LIB_IA32_FEATURE_CONTROL 0x03A
+#define SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE 0x1F2
+#define SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK 0x1F3
+#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE 0x0A0
+#define SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK 0x0A1
+#define EFI_MSR_SMRR_MASK 0xFFFFF000
+#define EFI_MSR_SMRR_PHYS_MASK_VALID BIT11
+#define SMM_FEATURES_LIB_SMM_FEATURE_CONTROL 0x4E0
+
+//
+// MSRs required for configuration of SMM Code Access Check
+//
+#define SMM_FEATURES_LIB_IA32_MCA_CAP 0x17D
+#define SMM_CODE_ACCESS_CHK_BIT BIT58
+
+//
+// Set default value to assume SMRR is not supported
+//
+BOOLEAN mSmrrSupported = FALSE;
+
+//
+// Set default value to assume MSR_SMM_FEATURE_CONTROL is not supported
+//
+BOOLEAN mSmmFeatureControlSupported = FALSE;
+
+//
+// Set default value to assume IA-32 Architectural MSRs are used
+//
+UINT32 mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSBASE;
+UINT32 mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_SMRR_PHYSMASK;
+
+//
+// Set default value to assume MTRRs need to be configured on each SMI
+//
+BOOLEAN mNeedConfigureMtrrs = TRUE;
+
+//
+// Array for state of SMRR enable on all CPUs
+//
+BOOLEAN *mSmrrEnabled;
+
+/**
+ Performs library initialization.
+
+ This initialization function contains common functionality shared betwen all
+ library instance constructors.
+
+**/
+VOID
+CpuFeaturesLibInitialization (
+ VOID
+ )
+{
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINTN FamilyId;
+ UINTN ModelId;
+
+ //
+ // Retrieve CPU Family and Model
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
+ FamilyId = (RegEax >> 8) & 0xf;
+ ModelId = (RegEax >> 4) & 0xf;
+ if (FamilyId == 0x06 || FamilyId == 0x0f) {
+ ModelId = ModelId | ((RegEax >> 12) & 0xf0);
+ }
+
+ //
+ // Check CPUID(CPUID_VERSION_INFO).EDX[12] for MTRR capability
+ //
+ if ((RegEdx & BIT12) != 0) {
+ //
+ // Check MTRR_CAP MSR bit 11 for SMRR support
+ //
+ if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MTRR_CAP) & BIT11) != 0) {
+ mSmrrSupported = TRUE;
+ }
+ }
+
+ //
+ // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ // Volume 3C, Section 35.3 MSRs in the Intel(R) Atom(TM) Processor Family
+ //
+ // If CPU Family/Model is 06_1CH, 06_26H, 06_27H, 06_35H or 06_36H, then
+ // SMRR Physical Base and SMM Physical Mask MSRs are not available.
+ //
+ if (FamilyId == 0x06) {
+ if (ModelId == 0x1C || ModelId == 0x26 || ModelId == 0x27 || ModelId == 0x35 || ModelId == 0x36) {
+ mSmrrSupported = FALSE;
+ }
+ }
+
+ //
+ // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
+ //
+ // If CPU Family/Model is 06_0F or 06_17, then use Intel(R) Core(TM) 2
+ // Processor Family MSRs
+ //
+ if (FamilyId == 0x06) {
+ if (ModelId == 0x17 || ModelId == 0x0f) {
+ mSmrrPhysBaseMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE;
+ mSmrrPhysMaskMsr = SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSMASK;
+ }
+ }
+
+ //
+ // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ // Volume 3C, Section 34.4.2 SMRAM Caching
+ // An IA-32 processor does not automatically write back and invalidate its
+ // caches before entering SMM or before exiting SMM. Because of this behavior,
+ // care must be taken in the placement of the SMRAM in system memory and in
+ // the caching of the SMRAM to prevent cache incoherence when switching back
+ // and forth between SMM and protected mode operation.
+ //
+ // An IA-32 processor is a processor that does not support the Intel 64
+ // Architecture. Support for the Intel 64 Architecture can be detected from
+ // CPUID(CPUID_EXTENDED_CPU_SIG).EDX[29]
+ //
+ // If an IA-32 processor is detected, then set mNeedConfigureMtrrs to TRUE,
+ // so caches are flushed on SMI entry and SMI exit, the interrupted code
+ // MTRRs are saved/restored, and MTRRs for SMM are loaded.
+ //
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= CPUID_EXTENDED_CPU_SIG) {
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT29) != 0) {
+ mNeedConfigureMtrrs = FALSE;
+ }
+ }
+
+ //
+ // Allocate array for state of SMRR enable on all CPUs
+ //
+ mSmrrEnabled = (BOOLEAN *)AllocatePool (sizeof (BOOLEAN) * GetCpuMaxLogicalProcessorNumber ());
+ ASSERT (mSmrrEnabled != NULL);
+}
+
+/**
+ Called during the very first SMI into System Management Mode to initialize
+ CPU features, including SMBASE, for the currently executing CPU. Since this
+ is the first SMI, the SMRAM Save State Map is at the default address of
+ SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET. The currently executing
+ CPU is specified by CpuIndex and CpuIndex can be used to access information
+ about the currently executing CPU in the ProcessorInfo array and the
+ HotPlugCpuData data structure.
+
+ @param[in] CpuIndex The index of the CPU to initialize. The value
+ must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] IsMonarch TRUE if the CpuIndex is the index of the CPU that
+ was elected as monarch during System Management
+ Mode initialization.
+ FALSE if the CpuIndex is not the index of the CPU
+ that was elected as monarch during System
+ Management Mode initialization.
+ @param[in] ProcessorInfo Pointer to an array of EFI_PROCESSOR_INFORMATION
+ structures. ProcessorInfo[CpuIndex] contains the
+ information for the currently executing CPU.
+ @param[in] CpuHotPlugData Pointer to the CPU_HOT_PLUG_DATA structure that
+ contains the ApidId and SmBase arrays.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesInitializeProcessor (
+ IN UINTN CpuIndex,
+ IN BOOLEAN IsMonarch,
+ IN EFI_PROCESSOR_INFORMATION *ProcessorInfo,
+ IN CPU_HOT_PLUG_DATA *CpuHotPlugData
+ )
+{
+ SMRAM_SAVE_STATE_MAP *CpuState;
+ UINT64 FeatureControl;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINTN FamilyId;
+ UINTN ModelId;
+
+ //
+ // Configure SMBASE.
+ //
+ CpuState = (SMRAM_SAVE_STATE_MAP *)(UINTN)(SMM_DEFAULT_SMBASE + SMRAM_SAVE_STATE_MAP_OFFSET);
+ CpuState->x86.SMBASE = (UINT32)CpuHotPlugData->SmBase[CpuIndex];
+
+ //
+ // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ // Volume 3C, Section 35.2 MSRs in the Intel(R) Core(TM) 2 Processor Family
+ //
+ // If Intel(R) Core(TM) Core(TM) 2 Processor Family MSRs are being used, then
+ // make sure SMRR Enable(BIT3) of MSR_FEATURE_CONTROL MSR(0x3A) is set before
+ // accessing SMRR base/mask MSRs. If Lock(BIT0) of MSR_FEATURE_CONTROL MSR(0x3A)
+ // is set, then the MSR is locked and can not be modified.
+ //
+ if (mSmrrSupported && mSmrrPhysBaseMsr == SMM_FEATURES_LIB_IA32_CORE_SMRR_PHYSBASE) {
+ FeatureControl = AsmReadMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL);
+ if ((FeatureControl & BIT3) == 0) {
+ if ((FeatureControl & BIT0) == 0) {
+ AsmWriteMsr64 (SMM_FEATURES_LIB_IA32_FEATURE_CONTROL, FeatureControl | BIT3);
+ } else {
+ mSmrrSupported = FALSE;
+ }
+ }
+ }
+
+ //
+ // If SMRR is supported, then program SMRR base/mask MSRs.
+ // The EFI_MSR_SMRR_PHYS_MASK_VALID bit is not set until the first normal SMI.
+ // The code that initializes SMM environment is running in normal mode
+ // from SMRAM region. If SMRR is enabled here, then the SMRAM region
+ // is protected and the normal mode code execution will fail.
+ //
+ if (mSmrrSupported) {
+ //
+ // SMRR size cannot be less than 4-KBytes
+ // SMRR size must be of length 2^n
+ // SMRR base alignment cannot be less than SMRR length
+ //
+ if ((CpuHotPlugData->SmrrSize < SIZE_4KB) ||
+ (CpuHotPlugData->SmrrSize != GetPowerOfTwo32 (CpuHotPlugData->SmrrSize)) ||
+ ((CpuHotPlugData->SmrrBase & ~(CpuHotPlugData->SmrrSize - 1)) != CpuHotPlugData->SmrrBase)) {
+ //
+ // Print message and halt if CPU is Monarch
+ //
+ if (IsMonarch) {
+ DEBUG ((DEBUG_ERROR, "SMM Base/Size does not meet alignment/size requirement!\n"));
+ CpuDeadLoop ();
+ }
+ } else {
+ AsmWriteMsr64 (mSmrrPhysBaseMsr, CpuHotPlugData->SmrrBase | MTRR_CACHE_WRITE_BACK);
+ AsmWriteMsr64 (mSmrrPhysMaskMsr, (~(CpuHotPlugData->SmrrSize - 1) & EFI_MSR_SMRR_MASK));
+ mSmrrEnabled[CpuIndex] = FALSE;
+ }
+ }
+
+ //
+ // Retrieve CPU Family and Model
+ //
+ AsmCpuid (CPUID_VERSION_INFO, &RegEax, NULL, NULL, &RegEdx);
+ FamilyId = (RegEax >> 8) & 0xf;
+ ModelId = (RegEax >> 4) & 0xf;
+ if (FamilyId == 0x06 || FamilyId == 0x0f) {
+ ModelId = ModelId | ((RegEax >> 12) & 0xf0);
+ }
+
+ //
+ // Intel(R) 64 and IA-32 Architectures Software Developer's Manual
+ // Volume 3C, Section 35.10.1 MSRs in 4th Generation Intel(R) Core(TM)
+ // Processor Family.
+ //
+ // If CPU Family/Model is 06_3C, 06_45, or 06_46 then use 4th Generation
+ // Intel(R) Core(TM) Processor Family MSRs.
+ //
+ if (FamilyId == 0x06) {
+ if (ModelId == 0x3C || ModelId == 0x45 || ModelId == 0x46 ||
+ ModelId == 0x3D || ModelId == 0x47 || ModelId == 0x4E || ModelId == 0x4F ||
+ ModelId == 0x3F || ModelId == 0x56 || ModelId == 0x57 || ModelId == 0x5C ||
+ ModelId == 0x8C) {
+ //
+ // Check to see if the CPU supports the SMM Code Access Check feature
+ // Do not access this MSR unless the CPU supports the SmmRegFeatureControl
+ //
+ if ((AsmReadMsr64 (SMM_FEATURES_LIB_IA32_MCA_CAP) & SMM_CODE_ACCESS_CHK_BIT) != 0) {
+ mSmmFeatureControlSupported = TRUE;
+ }
+ }
+ }
+
+ //
+ // Call internal worker function that completes the CPU initialization
+ //
+ FinishSmmCpuFeaturesInitializeProcessor ();
+}
+
+/**
+ This function updates the SMRAM save state on the currently executing CPU
+ to resume execution at a specific address after an RSM instruction. This
+ function must evaluate the SMRAM save state to determine the execution mode
+ the RSM instruction resumes and update the resume execution address with
+ either NewInstructionPointer32 or NewInstructionPoint. The auto HALT restart
+ flag in the SMRAM save state must always be cleared. This function returns
+ the value of the instruction pointer from the SMRAM save state that was
+ replaced. If this function returns 0, then the SMRAM save state was not
+ modified.
+
+ This function is called during the very first SMI on each CPU after
+ SmmCpuFeaturesInitializeProcessor() to set a flag in normal execution mode
+ to signal that the SMBASE of each CPU has been updated before the default
+ SMBASE address is used for the first SMI to the next CPU.
+
+ @param[in] CpuIndex The index of the CPU to hook. The value
+ must be between 0 and the NumberOfCpus
+ field in the System Management System Table
+ (SMST).
+ @param[in] CpuState Pointer to SMRAM Save State Map for the
+ currently executing CPU.
+ @param[in] NewInstructionPointer32 Instruction pointer to use if resuming to
+ 32-bit execution mode from 64-bit SMM.
+ @param[in] NewInstructionPointer Instruction pointer to use if resuming to
+ same execution mode as SMM.
+
+ @retval 0 This function did modify the SMRAM save state.
+ @retval > 0 The original instruction pointer value from the SMRAM save state
+ before it was replaced.
+**/
+UINT64
+EFIAPI
+SmmCpuFeaturesHookReturnFromSmm (
+ IN UINTN CpuIndex,
+ IN SMRAM_SAVE_STATE_MAP *CpuState,
+ IN UINT64 NewInstructionPointer32,
+ IN UINT64 NewInstructionPointer
+ )
+{
+ return 0;
+}
+
+/**
+ Hook point in normal execution mode that allows the one CPU that was elected
+ as monarch during System Management Mode initialization to perform additional
+ initialization actions immediately after all of the CPUs have processed their
+ first SMI and called SmmCpuFeaturesInitializeProcessor() relocating SMBASE
+ into a buffer in SMRAM and called SmmCpuFeaturesHookReturnFromSmm().
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSmmRelocationComplete (
+ VOID
+ )
+{
+}
+
+/**
+ Determines if MTRR registers must be configured to set SMRAM cache-ability
+ when executing in System Management Mode.
+
+ @retval TRUE MTRR registers must be configured to set SMRAM cache-ability.
+ @retval FALSE MTRR registers do not need to be configured to set SMRAM
+ cache-ability.
+**/
+BOOLEAN
+EFIAPI
+SmmCpuFeaturesNeedConfigureMtrrs (
+ VOID
+ )
+{
+ return mNeedConfigureMtrrs;
+}
+
+/**
+ Disable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
+ returns TRUE.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesDisableSmrr (
+ VOID
+ )
+{
+ if (mSmrrSupported && mNeedConfigureMtrrs) {
+ AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) & ~EFI_MSR_SMRR_PHYS_MASK_VALID);
+ }
+}
+
+/**
+ Enable SMRR register if SMRR is supported and SmmCpuFeaturesNeedConfigureMtrrs()
+ returns TRUE.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesReenableSmrr (
+ VOID
+ )
+{
+ if (mSmrrSupported && mNeedConfigureMtrrs) {
+ AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64(mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
+ }
+}
+
+/**
+ Processor specific hook point each time a CPU enters System Management Mode.
+
+ @param[in] CpuIndex The index of the CPU that has entered SMM. The value
+ must be between 0 and the NumberOfCpus field in the
+ System Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousEntry (
+ IN UINTN CpuIndex
+ )
+{
+ //
+ // If SMRR is supported and this is the first normal SMI, then enable SMRR
+ //
+ if (mSmrrSupported && !mSmrrEnabled[CpuIndex]) {
+ AsmWriteMsr64 (mSmrrPhysMaskMsr, AsmReadMsr64 (mSmrrPhysMaskMsr) | EFI_MSR_SMRR_PHYS_MASK_VALID);
+ mSmrrEnabled[CpuIndex] = TRUE;
+ }
+}
+
+/**
+ Processor specific hook point each time a CPU exits System Management Mode.
+
+ @param[in] CpuIndex The index of the CPU that is exiting SMM. The value must
+ be between 0 and the NumberOfCpus field in the System
+ Management System Table (SMST).
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesRendezvousExit (
+ IN UINTN CpuIndex
+ )
+{
+}
+
+/**
+ Check to see if an SMM register is supported by a specified CPU.
+
+ @param[in] CpuIndex The index of the CPU to check for SMM register support.
+ The value must be between 0 and the NumberOfCpus field
+ in the System Management System Table (SMST).
+ @param[in] RegName Identifies the SMM register to check for support.
+
+ @retval TRUE The SMM register specified by RegName is supported by the CPU
+ specified by CpuIndex.
+ @retval FALSE The SMM register specified by RegName is not supported by the
+ CPU specified by CpuIndex.
+**/
+BOOLEAN
+EFIAPI
+SmmCpuFeaturesIsSmmRegisterSupported (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName
+ )
+{
+ if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+/**
+ Returns the current value of the SMM register for the specified CPU.
+ If the SMM register is not supported, then 0 is returned.
+
+ @param[in] CpuIndex The index of the CPU to read the SMM register. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] RegName Identifies the SMM register to read.
+
+ @return The value of the SMM register specified by RegName from the CPU
+ specified by CpuIndex.
+**/
+UINT64
+EFIAPI
+SmmCpuFeaturesGetSmmRegister (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName
+ )
+{
+ if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
+ return AsmReadMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL);
+ }
+ return 0;
+}
+
+/**
+ Sets the value of an SMM register on a specified CPU.
+ If the SMM register is not supported, then no action is performed.
+
+ @param[in] CpuIndex The index of the CPU to write the SMM register. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] RegName Identifies the SMM register to write.
+ registers are read-only.
+ @param[in] Value The value to write to the SMM register.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesSetSmmRegister (
+ IN UINTN CpuIndex,
+ IN SMM_REG_NAME RegName,
+ IN UINT64 Value
+ )
+{
+ if (mSmmFeatureControlSupported && RegName == SmmRegFeatureControl) {
+ AsmWriteMsr64 (SMM_FEATURES_LIB_SMM_FEATURE_CONTROL, Value);
+ }
+}
+
+/**
+ Read an SMM Save State register on the target processor. If this function
+ returns EFI_UNSUPPORTED, then the caller is responsible for reading the
+ SMM Save Sate register.
+
+ @param[in] CpuIndex The index of the CPU to read the SMM Save State. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] Register The SMM Save State register to read.
+ @param[in] Width The number of bytes to read from the CPU save state.
+ @param[out] Buffer Upon return, this holds the CPU register value read
+ from the save state.
+
+ @retval EFI_SUCCESS The register was read from Save State.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED This function does not support reading Register.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesReadSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN Width,
+ OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Writes an SMM Save State register on the target processor. If this function
+ returns EFI_UNSUPPORTED, then the caller is responsible for writing the
+ SMM Save Sate register.
+
+ @param[in] CpuIndex The index of the CPU to write the SMM Save State. The
+ value must be between 0 and the NumberOfCpus field in
+ the System Management System Table (SMST).
+ @param[in] Register The SMM Save State register to write.
+ @param[in] Width The number of bytes to write to the CPU save state.
+ @param[in] Buffer Upon entry, this holds the new CPU register value.
+
+ @retval EFI_SUCCESS The register was written to Save State.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED This function does not support writing Register.
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesWriteSaveStateRegister (
+ IN UINTN CpuIndex,
+ IN EFI_SMM_SAVE_STATE_REGISTER Register,
+ IN UINTN Width,
+ IN CONST VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ This function is hook point called after the gEfiSmmReadyToLockProtocolGuid
+ notification is completely processed.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesCompleteSmmReadyToLock (
+ VOID
+ )
+{
+}
+
+/**
+ This API provides a method for a CPU to allocate a specific region for storing page tables.
+
+ This API can be called more once to allocate memory for page tables.
+
+ Allocates the number of 4KB pages of type EfiRuntimeServicesData and returns a pointer to the
+ allocated buffer. The buffer returned is aligned on a 4KB boundary. If Pages is 0, then NULL
+ is returned. If there is not enough memory remaining to satisfy the request, then NULL is
+ returned.
+
+ This function can also return NULL if there is no preference on where the page tables are allocated in SMRAM.
+
+ @param Pages The number of 4 KB pages to allocate.
+
+ @return A pointer to the allocated buffer for page tables.
+ @retval NULL Fail to allocate a specific region for storing page tables,
+ Or there is no preference on where the page tables are allocated in SMRAM.
+
+**/
+VOID *
+EFIAPI
+SmmCpuFeaturesAllocatePageTableMemory (
+ IN UINTN Pages
+ )
+{
+ return NULL;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibNoStm.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibNoStm.c
new file mode 100644
index 00000000..6baa6030
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibNoStm.c
@@ -0,0 +1,84 @@
+/** @file
+The CPU specific programming for PiSmmCpuDxeSmm module when STM support
+is not included.
+
+Copyright (c) 2010 - 2016, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/SmmCpuFeaturesLib.h>
+#include "CpuFeaturesLib.h"
+
+/**
+ Internal worker function that is called to complete CPU initialization at the
+ end of SmmCpuFeaturesInitializeProcessor().
+
+**/
+VOID
+FinishSmmCpuFeaturesInitializeProcessor (
+ VOID
+ )
+{
+}
+
+/**
+ Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
+ returned, then a custom SMI handler is not provided by this library,
+ and the default SMI handler must be used.
+
+ @retval 0 Use the default SMI handler.
+ @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
+ The caller is required to allocate enough SMRAM for each CPU to
+ support the size of the custom SMI handler.
+**/
+UINTN
+EFIAPI
+SmmCpuFeaturesGetSmiHandlerSize (
+ VOID
+ )
+{
+ return 0;
+}
+
+/**
+ Install a custom SMI handler for the CPU specified by CpuIndex. This function
+ is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
+ than zero and is called by the CPU that was elected as monarch during System
+ Management Mode initialization.
+
+ @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
+ The value must be between 0 and the NumberOfCpus field
+ in the System Management System Table (SMST).
+ @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
+ @param[in] SmiStack The stack to use when an SMI is processed by the
+ the CPU specified by CpuIndex.
+ @param[in] StackSize The size, in bytes, if the stack used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] GdtBase The base address of the GDT to use when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] IdtBase The base address of the IDT to use when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] Cr3 The base address of the page tables to use when an SMI
+ is processed by the CPU specified by CpuIndex.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesInstallSmiHandler (
+ IN UINTN CpuIndex,
+ IN UINT32 SmBase,
+ IN VOID *SmiStack,
+ IN UINTN StackSize,
+ IN UINTN GdtBase,
+ IN UINTN GdtSize,
+ IN UINTN IdtBase,
+ IN UINTN IdtSize,
+ IN UINT32 Cr3
+ )
+{
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
new file mode 100644
index 00000000..6583b3bd
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmCpuFeaturesLibStm.inf
@@ -0,0 +1,74 @@
+## @file
+# The CPU specific programming for PiSmmCpuDxeSmm module when STM support
+# is included.
+#
+# Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuFeaturesLibStm
+ MODULE_UNI_FILE = SmmCpuFeaturesLib.uni
+ FILE_GUID = 374DE830-81C5-4CC8-B2AB-28F0AB73710B
+ MODULE_TYPE = DXE_SMM_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmCpuFeaturesLib
+ CONSTRUCTOR = SmmCpuFeaturesLibStmConstructor
+
+[Sources]
+ CpuFeaturesLib.h
+ SmmCpuFeaturesLibCommon.c
+ SmmStm.c
+ SmmStm.h
+ TraditionalMmCpuFeaturesLib.c
+
+[Sources.Ia32]
+ Ia32/SmmStmSupport.c
+
+
+ Ia32/SmiEntry.nasm
+ Ia32/SmiException.nasm
+
+[Sources.X64]
+ X64/SmmStmSupport.c
+
+
+ X64/SmiEntry.nasm
+ X64/SmiException.nasm
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ PcdLib
+ HobLib
+ MemoryAllocationLib
+ DebugLib
+ UefiBootServicesTableLib
+ SmmServicesTableLib
+ TpmMeasurementLib
+
+[Protocols]
+ gEfiMpServiceProtocolGuid ## CONSUMES
+ gEfiSmmEndOfDxeProtocolGuid ## CONSUMES
+ gEfiSmMonitorInitProtocolGuid ## PRODUCES
+
+[Guids]
+ gMsegSmramGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+
+[Pcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMsegSize ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStmExceptionStackSize ## SOMETIMES_CONSUMES
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuSmmStackGuard ## CONSUMES
+
+[Depex]
+ gEfiMpServiceProtocolGuid
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c
new file mode 100644
index 00000000..6ae8fb92
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.c
@@ -0,0 +1,1281 @@
+/** @file
+ SMM STM support functions
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/HobLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/SmmServicesTableLib.h>
+#include <Library/TpmMeasurementLib.h>
+#include <Register/Intel/Cpuid.h>
+#include <Register/Intel/ArchitecturalMsr.h>
+#include <Register/Intel/SmramSaveStateMap.h>
+
+#include <Protocol/MpService.h>
+
+#include "CpuFeaturesLib.h"
+#include "SmmStm.h"
+
+#define TXT_EVTYPE_BASE 0x400
+#define TXT_EVTYPE_STM_HASH (TXT_EVTYPE_BASE + 14)
+
+#define RDWR_ACCS 3
+#define FULL_ACCS 7
+
+EFI_HANDLE mStmSmmCpuHandle = NULL;
+
+BOOLEAN mLockLoadMonitor = FALSE;
+
+//
+// Template of STM_RSC_END structure for copying.
+//
+GLOBAL_REMOVE_IF_UNREFERENCED STM_RSC_END mRscEndNode = {
+ {END_OF_RESOURCES, sizeof (STM_RSC_END)},
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT8 *mStmResourcesPtr = NULL;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceTotalSize = 0x0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeUsed = 0x0;
+GLOBAL_REMOVE_IF_UNREFERENCED UINTN mStmResourceSizeAvailable = 0x0;
+
+GLOBAL_REMOVE_IF_UNREFERENCED UINT32 mStmState = 0;
+
+//
+// System Configuration Table pointing to STM Configuration Table
+//
+GLOBAL_REMOVE_IF_UNREFERENCED
+EFI_SM_MONITOR_INIT_PROTOCOL mSmMonitorInitProtocol = {
+ LoadMonitor,
+ AddPiResource,
+ DeletePiResource,
+ GetPiResource,
+ GetMonitorState,
+};
+
+
+
+
+#define CPUID1_EDX_XD_SUPPORT 0x100000
+
+//
+// External global variables associated with SMI Handler Template
+//
+extern CONST TXT_PROCESSOR_SMM_DESCRIPTOR gcStmPsd;
+extern UINT32 gStmSmbase;
+extern volatile UINT32 gStmSmiStack;
+extern UINT32 gStmSmiCr3;
+extern volatile UINT8 gcStmSmiHandlerTemplate[];
+extern CONST UINT16 gcStmSmiHandlerSize;
+extern UINT16 gcStmSmiHandlerOffset;
+extern BOOLEAN gStmXdSupported;
+
+//
+// Variables used by SMI Handler
+//
+IA32_DESCRIPTOR gStmSmiHandlerIdtr;
+
+//
+// MP Services Protocol
+//
+EFI_MP_SERVICES_PROTOCOL *mSmmCpuFeaturesLibMpService = NULL;
+
+//
+// MSEG Base and Length in SMRAM
+//
+UINTN mMsegBase = 0;
+UINTN mMsegSize = 0;
+
+BOOLEAN mStmConfigurationTableInitialized = FALSE;
+
+/**
+ The constructor function for the Traditional MM library instance with STM.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+SmmCpuFeaturesLibStmConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ CPUID_VERSION_INFO_ECX RegEcx;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ EFI_SMRAM_DESCRIPTOR *SmramDescriptor;
+
+ //
+ // Initialize address fixup
+ //
+ SmmCpuFeaturesLibStmSmiEntryFixupAddress ();
+
+ //
+ // Perform library initialization common across all instances
+ //
+ CpuFeaturesLibInitialization ();
+
+ //
+ // Lookup the MP Services Protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID **)&mSmmCpuFeaturesLibMpService
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // If CPU supports VMX, then determine SMRAM range for MSEG.
+ //
+ AsmCpuid (CPUID_VERSION_INFO, NULL, NULL, &RegEcx.Uint32, NULL);
+ if (RegEcx.Bits.VMX == 1) {
+ GuidHob = GetFirstGuidHob (&gMsegSmramGuid);
+ if (GuidHob != NULL) {
+ //
+ // Retrieve MSEG location from MSEG SRAM HOB
+ //
+ SmramDescriptor = (EFI_SMRAM_DESCRIPTOR *) GET_GUID_HOB_DATA (GuidHob);
+ if (SmramDescriptor->PhysicalSize > 0) {
+ mMsegBase = (UINTN)SmramDescriptor->CpuStart;
+ mMsegSize = (UINTN)SmramDescriptor->PhysicalSize;
+ }
+ } else if (PcdGet32 (PcdCpuMsegSize) > 0) {
+ //
+ // Allocate MSEG from SMRAM memory
+ //
+ mMsegBase = (UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuMsegSize)));
+ if (mMsegBase > 0) {
+ mMsegSize = ALIGN_VALUE (PcdGet32 (PcdCpuMsegSize), EFI_PAGE_SIZE);
+ } else {
+ DEBUG ((DEBUG_ERROR, "Not enough SMRAM resource to allocate MSEG size %08x\n", PcdGet32 (PcdCpuMsegSize)));
+ }
+ }
+ if (mMsegBase > 0) {
+ DEBUG ((DEBUG_INFO, "MsegBase: 0x%08x, MsegSize: 0x%08x\n", mMsegBase, mMsegSize));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal worker function that is called to complete CPU initialization at the
+ end of SmmCpuFeaturesInitializeProcessor().
+
+**/
+VOID
+FinishSmmCpuFeaturesInitializeProcessor (
+ VOID
+ )
+{
+ MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
+
+ //
+ // Set MSEG Base Address in SMM Monitor Control MSR.
+ //
+ if (mMsegBase > 0) {
+ SmmMonitorCtl.Uint64 = 0;
+ SmmMonitorCtl.Bits.MsegBase = (UINT32)mMsegBase >> 12;
+ SmmMonitorCtl.Bits.Valid = 1;
+ AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
+ }
+}
+
+/**
+ Return the size, in bytes, of a custom SMI Handler in bytes. If 0 is
+ returned, then a custom SMI handler is not provided by this library,
+ and the default SMI handler must be used.
+
+ @retval 0 Use the default SMI handler.
+ @retval > 0 Use the SMI handler installed by SmmCpuFeaturesInstallSmiHandler()
+ The caller is required to allocate enough SMRAM for each CPU to
+ support the size of the custom SMI handler.
+**/
+UINTN
+EFIAPI
+SmmCpuFeaturesGetSmiHandlerSize (
+ VOID
+ )
+{
+ return gcStmSmiHandlerSize;
+}
+
+/**
+ Install a custom SMI handler for the CPU specified by CpuIndex. This function
+ is only called if SmmCpuFeaturesGetSmiHandlerSize() returns a size is greater
+ than zero and is called by the CPU that was elected as monarch during System
+ Management Mode initialization.
+
+ @param[in] CpuIndex The index of the CPU to install the custom SMI handler.
+ The value must be between 0 and the NumberOfCpus field
+ in the System Management System Table (SMST).
+ @param[in] SmBase The SMBASE address for the CPU specified by CpuIndex.
+ @param[in] SmiStack The stack to use when an SMI is processed by the
+ the CPU specified by CpuIndex.
+ @param[in] StackSize The size, in bytes, if the stack used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] GdtBase The base address of the GDT to use when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] GdtSize The size, in bytes, of the GDT used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] IdtBase The base address of the IDT to use when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] IdtSize The size, in bytes, of the IDT used when an SMI is
+ processed by the CPU specified by CpuIndex.
+ @param[in] Cr3 The base address of the page tables to use when an SMI
+ is processed by the CPU specified by CpuIndex.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesInstallSmiHandler (
+ IN UINTN CpuIndex,
+ IN UINT32 SmBase,
+ IN VOID *SmiStack,
+ IN UINTN StackSize,
+ IN UINTN GdtBase,
+ IN UINTN GdtSize,
+ IN UINTN IdtBase,
+ IN UINTN IdtSize,
+ IN UINT32 Cr3
+ )
+{
+ EFI_STATUS Status;
+ TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
+ VOID *Hob;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ EFI_PROCESSOR_INFORMATION ProcessorInfo;
+
+ CopyMem ((VOID *)((UINTN)SmBase + TXT_SMM_PSD_OFFSET), &gcStmPsd, sizeof (gcStmPsd));
+ Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)(VOID *)((UINTN)SmBase + TXT_SMM_PSD_OFFSET);
+ Psd->SmmGdtPtr = GdtBase;
+ Psd->SmmGdtSize = (UINT32)GdtSize;
+
+ //
+ // Initialize values in template before copy
+ //
+ gStmSmiStack = (UINT32)((UINTN)SmiStack + StackSize - sizeof (UINTN));
+ gStmSmiCr3 = Cr3;
+ gStmSmbase = SmBase;
+ gStmSmiHandlerIdtr.Base = IdtBase;
+ gStmSmiHandlerIdtr.Limit = (UINT16)(IdtSize - 1);
+
+ if (gStmXdSupported) {
+ AsmCpuid (CPUID_EXTENDED_FUNCTION, &RegEax, NULL, NULL, NULL);
+ if (RegEax <= CPUID_EXTENDED_FUNCTION) {
+ //
+ // Extended CPUID functions are not supported on this processor.
+ //
+ gStmXdSupported = FALSE;
+ }
+
+ AsmCpuid (CPUID_EXTENDED_CPU_SIG, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & CPUID1_EDX_XD_SUPPORT) == 0) {
+ //
+ // Execute Disable Bit feature is not supported on this processor.
+ //
+ gStmXdSupported = FALSE;
+ }
+ }
+
+ //
+ // Set the value at the top of the CPU stack to the CPU Index
+ //
+ *(UINTN*)(UINTN)gStmSmiStack = CpuIndex;
+
+ //
+ // Copy template to CPU specific SMI handler location
+ //
+ CopyMem (
+ (VOID*)((UINTN)SmBase + SMM_HANDLER_OFFSET),
+ (VOID*)gcStmSmiHandlerTemplate,
+ gcStmSmiHandlerSize
+ );
+
+ Psd->SmmSmiHandlerRip = SmBase + SMM_HANDLER_OFFSET + gcStmSmiHandlerOffset;
+ Psd->SmmSmiHandlerRsp = (UINTN)SmiStack + StackSize - sizeof(UINTN);
+ Psd->SmmCr3 = Cr3;
+
+ DEBUG((DEBUG_INFO, "CpuSmmStmExceptionStackSize - %x\n", PcdGet32(PcdCpuSmmStmExceptionStackSize)));
+ DEBUG((DEBUG_INFO, "Pages - %x\n", EFI_SIZE_TO_PAGES(PcdGet32(PcdCpuSmmStmExceptionStackSize))));
+ Psd->StmProtectionExceptionHandler.SpeRsp = (UINT64)(UINTN)AllocatePages (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
+ Psd->StmProtectionExceptionHandler.SpeRsp += EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (PcdGet32 (PcdCpuSmmStmExceptionStackSize)));
+
+ Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)GetStmResource ();
+
+ //
+ // Get the APIC ID for the CPU specified by CpuIndex
+ //
+ Status = mSmmCpuFeaturesLibMpService->GetProcessorInfo (
+ mSmmCpuFeaturesLibMpService,
+ CpuIndex,
+ &ProcessorInfo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Psd->LocalApicId = (UINT32)ProcessorInfo.ProcessorId;
+ Psd->AcpiRsdp = 0;
+
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ Psd->PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ } else {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ Psd->PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ Psd->PhysicalAddressBits = 36;
+ }
+ }
+
+ if (!mStmConfigurationTableInitialized) {
+ StmSmmConfigurationTableInit ();
+ mStmConfigurationTableInitialized = TRUE;
+ }
+}
+
+/**
+ SMM End Of Dxe event notification handler.
+
+ STM support need patch AcpiRsdp in TXT_PROCESSOR_SMM_DESCRIPTOR.
+
+ @param[in] Protocol Points to the protocol's unique identifier.
+ @param[in] Interface Points to the interface instance.
+ @param[in] Handle The handle on which the interface was installed.
+
+ @retval EFI_SUCCESS Notification handler runs successfully.
+**/
+EFI_STATUS
+EFIAPI
+SmmEndOfDxeEventNotify (
+ IN CONST EFI_GUID *Protocol,
+ IN VOID *Interface,
+ IN EFI_HANDLE Handle
+ )
+{
+ VOID *Rsdp;
+ UINTN Index;
+ TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
+
+ DEBUG ((DEBUG_INFO, "SmmEndOfDxeEventNotify\n"));
+
+ //
+ // found ACPI table RSD_PTR from system table
+ //
+ Rsdp = NULL;
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi20TableGuid)) {
+ //
+ // A match was found.
+ //
+ Rsdp = gST->ConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+ if (Rsdp == NULL) {
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), &gEfiAcpi10TableGuid)) {
+ //
+ // A match was found.
+ //
+ Rsdp = gST->ConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+ }
+
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
+ DEBUG ((DEBUG_INFO, "Index=%d Psd=%p Rsdp=%p\n", Index, Psd, Rsdp));
+ Psd->AcpiRsdp = (UINT64)(UINTN)Rsdp;
+ }
+
+ mLockLoadMonitor = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function initializes the STM configuration table.
+**/
+VOID
+StmSmmConfigurationTableInit (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ VOID *Registration;
+
+ Status = gSmst->SmmInstallProtocolInterface (
+ &mStmSmmCpuHandle,
+ &gEfiSmMonitorInitProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSmMonitorInitProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ //
+ // Register SMM End of DXE Event
+ //
+ Status = gSmst->SmmRegisterProtocolNotify (
+ &gEfiSmmEndOfDxeProtocolGuid,
+ SmmEndOfDxeEventNotify,
+ &Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
+/**
+
+ Get STM state.
+
+ @return STM state
+
+**/
+EFI_SM_MONITOR_STATE
+EFIAPI
+GetMonitorState (
+ VOID
+ )
+{
+ return mStmState;
+}
+
+/**
+
+ Handle single Resource to see if it can be merged into Record.
+
+ @param Resource A pointer to resource node to be added
+ @param Record A pointer to record node to be merged
+
+ @retval TRUE resource handled
+ @retval FALSE resource is not handled
+
+**/
+BOOLEAN
+HandleSingleResource (
+ IN STM_RSC *Resource,
+ IN STM_RSC *Record
+ )
+{
+ UINT64 ResourceLo;
+ UINT64 ResourceHi;
+ UINT64 RecordLo;
+ UINT64 RecordHi;
+
+ ResourceLo = 0;
+ ResourceHi = 0;
+ RecordLo = 0;
+ RecordHi = 0;
+
+ //
+ // Calling code is responsible for making sure that
+ // Resource->Header.RscType == (*Record)->Header.RscType
+ // thus we use just one of them as switch variable.
+ //
+ switch (Resource->Header.RscType) {
+ case MEM_RANGE:
+ case MMIO_RANGE:
+ ResourceLo = Resource->Mem.Base;
+ ResourceHi = Resource->Mem.Base + Resource->Mem.Length;
+ RecordLo = Record->Mem.Base;
+ RecordHi = Record->Mem.Base + Record->Mem.Length;
+ if (Resource->Mem.RWXAttributes != Record->Mem.RWXAttributes) {
+ if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
+ Record->Mem.RWXAttributes = Resource->Mem.RWXAttributes | Record->Mem.RWXAttributes;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ break;
+ case IO_RANGE:
+ case TRAPPED_IO_RANGE:
+ ResourceLo = (UINT64) Resource->Io.Base;
+ ResourceHi = (UINT64) Resource->Io.Base + (UINT64) Resource->Io.Length;
+ RecordLo = (UINT64) Record->Io.Base;
+ RecordHi = (UINT64) Record->Io.Base + (UINT64) Record->Io.Length;
+ break;
+ case PCI_CFG_RANGE:
+ if ((Resource->PciCfg.OriginatingBusNumber != Record->PciCfg.OriginatingBusNumber) ||
+ (Resource->PciCfg.LastNodeIndex != Record->PciCfg.LastNodeIndex)) {
+ return FALSE;
+ }
+ if (CompareMem (Resource->PciCfg.PciDevicePath, Record->PciCfg.PciDevicePath, sizeof(STM_PCI_DEVICE_PATH_NODE) * (Resource->PciCfg.LastNodeIndex + 1)) != 0) {
+ return FALSE;
+ }
+ ResourceLo = (UINT64) Resource->PciCfg.Base;
+ ResourceHi = (UINT64) Resource->PciCfg.Base + (UINT64) Resource->PciCfg.Length;
+ RecordLo = (UINT64) Record->PciCfg.Base;
+ RecordHi = (UINT64) Record->PciCfg.Base + (UINT64) Record->PciCfg.Length;
+ if (Resource->PciCfg.RWAttributes != Record->PciCfg.RWAttributes) {
+ if ((ResourceLo == RecordLo) && (ResourceHi == RecordHi)) {
+ Record->PciCfg.RWAttributes = Resource->PciCfg.RWAttributes | Record->PciCfg.RWAttributes;
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+ }
+ break;
+ case MACHINE_SPECIFIC_REG:
+ //
+ // Special case - merge MSR masks in place.
+ //
+ if (Resource->Msr.MsrIndex != Record->Msr.MsrIndex) {
+ return FALSE;
+ }
+ Record->Msr.ReadMask |= Resource->Msr.ReadMask;
+ Record->Msr.WriteMask |= Resource->Msr.WriteMask;
+ return TRUE;
+ default:
+ return FALSE;
+ }
+ //
+ // If resources are disjoint
+ //
+ if ((ResourceHi < RecordLo) || (ResourceLo > RecordHi)) {
+ return FALSE;
+ }
+
+ //
+ // If resource is consumed by record.
+ //
+ if ((ResourceLo >= RecordLo) && (ResourceHi <= RecordHi)) {
+ return TRUE;
+ }
+ //
+ // Resources are overlapping.
+ // Resource and record are merged.
+ //
+ ResourceLo = (ResourceLo < RecordLo) ? ResourceLo : RecordLo;
+ ResourceHi = (ResourceHi > RecordHi) ? ResourceHi : RecordHi;
+
+ switch (Resource->Header.RscType) {
+ case MEM_RANGE:
+ case MMIO_RANGE:
+ Record->Mem.Base = ResourceLo;
+ Record->Mem.Length = ResourceHi - ResourceLo;
+ break;
+ case IO_RANGE:
+ case TRAPPED_IO_RANGE:
+ Record->Io.Base = (UINT16) ResourceLo;
+ Record->Io.Length = (UINT16) (ResourceHi - ResourceLo);
+ break;
+ case PCI_CFG_RANGE:
+ Record->PciCfg.Base = (UINT16) ResourceLo;
+ Record->PciCfg.Length = (UINT16) (ResourceHi - ResourceLo);
+ break;
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ Add resource node.
+
+ @param Resource A pointer to resource node to be added
+
+**/
+VOID
+AddSingleResource (
+ IN STM_RSC *Resource
+ )
+{
+ STM_RSC *Record;
+
+ Record = (STM_RSC *)mStmResourcesPtr;
+
+ while (TRUE) {
+ if (Record->Header.RscType == END_OF_RESOURCES) {
+ break;
+ }
+ //
+ // Go to next record if resource and record types don't match.
+ //
+ if (Resource->Header.RscType != Record->Header.RscType) {
+ Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
+ continue;
+ }
+ //
+ // Record is handled inside of procedure - don't adjust.
+ //
+ if (HandleSingleResource (Resource, Record)) {
+ return ;
+ }
+ Record = (STM_RSC *)((UINTN)Record + Record->Header.Length);
+ }
+
+ //
+ // Add resource to the end of area.
+ //
+ CopyMem (
+ mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode),
+ Resource,
+ Resource->Header.Length
+ );
+ CopyMem (
+ mStmResourcesPtr + mStmResourceSizeUsed - sizeof(mRscEndNode) + Resource->Header.Length,
+ &mRscEndNode,
+ sizeof(mRscEndNode)
+ );
+ mStmResourceSizeUsed += Resource->Header.Length;
+ mStmResourceSizeAvailable = mStmResourceTotalSize - mStmResourceSizeUsed;
+
+ return ;
+}
+
+/**
+
+ Add resource list.
+
+ @param ResourceList A pointer to resource list to be added
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+**/
+VOID
+AddResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ )
+{
+ UINT32 Count;
+ UINTN Index;
+ STM_RSC *Resource;
+
+ if (NumEntries == 0) {
+ Count = 0xFFFFFFFF;
+ } else {
+ Count = NumEntries;
+ }
+
+ Resource = ResourceList;
+
+ for (Index = 0; Index < Count; Index++) {
+ if (Resource->Header.RscType == END_OF_RESOURCES) {
+ return ;
+ }
+ AddSingleResource (Resource);
+ Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
+ }
+ return ;
+}
+
+/**
+
+ Validate resource list.
+
+ @param ResourceList A pointer to resource list to be added
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval TRUE resource valid
+ @retval FALSE resource invalid
+
+**/
+BOOLEAN
+ValidateResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ )
+{
+ UINT32 Count;
+ UINTN Index;
+ STM_RSC *Resource;
+ UINTN SubIndex;
+
+ //
+ // If NumEntries == 0 make it very big. Scan will be terminated by
+ // END_OF_RESOURCES.
+ //
+ if (NumEntries == 0) {
+ Count = 0xFFFFFFFF;
+ } else {
+ Count = NumEntries;
+ }
+
+ //
+ // Start from beginning of resource list.
+ //
+ Resource = ResourceList;
+
+ for (Index = 0; Index < Count; Index++) {
+ DEBUG ((DEBUG_INFO, "ValidateResource (%d) - RscType(%x)\n", Index, Resource->Header.RscType));
+ //
+ // Validate resource.
+ //
+ switch (Resource->Header.RscType) {
+ case END_OF_RESOURCES:
+ if (Resource->Header.Length != sizeof (STM_RSC_END)) {
+ return FALSE;
+ }
+ //
+ // If we are passed actual number of resources to add,
+ // END_OF_RESOURCES structure between them is considered an
+ // error. If NumEntries == 0 END_OF_RESOURCES is a termination.
+ //
+ if (NumEntries != 0) {
+ return FALSE;
+ } else {
+ //
+ // If NumEntries == 0 and list reached end - return success.
+ //
+ return TRUE;
+ }
+ break;
+
+ case MEM_RANGE:
+ case MMIO_RANGE:
+ if (Resource->Header.Length != sizeof (STM_RSC_MEM_DESC)) {
+ return FALSE;
+ }
+
+ if (Resource->Mem.RWXAttributes > FULL_ACCS) {
+ return FALSE;
+ }
+ break;
+
+ case IO_RANGE:
+ case TRAPPED_IO_RANGE:
+ if (Resource->Header.Length != sizeof (STM_RSC_IO_DESC)) {
+ return FALSE;
+ }
+
+ if ((Resource->Io.Base + Resource->Io.Length) > 0xFFFF) {
+ return FALSE;
+ }
+ break;
+
+ case PCI_CFG_RANGE:
+ DEBUG ((DEBUG_INFO, "ValidateResource - PCI (0x%02x, 0x%08x, 0x%02x, 0x%02x)\n", Resource->PciCfg.OriginatingBusNumber, Resource->PciCfg.LastNodeIndex, Resource->PciCfg.PciDevicePath[0].PciDevice, Resource->PciCfg.PciDevicePath[0].PciFunction));
+ if (Resource->Header.Length != sizeof (STM_RSC_PCI_CFG_DESC) + (sizeof(STM_PCI_DEVICE_PATH_NODE) * Resource->PciCfg.LastNodeIndex)) {
+ return FALSE;
+ }
+ for (SubIndex = 0; SubIndex <= Resource->PciCfg.LastNodeIndex; SubIndex++) {
+ if ((Resource->PciCfg.PciDevicePath[SubIndex].PciDevice > 0x1F) || (Resource->PciCfg.PciDevicePath[SubIndex].PciFunction > 7)) {
+ return FALSE;
+ }
+ }
+ if ((Resource->PciCfg.Base + Resource->PciCfg.Length) > 0x1000) {
+ return FALSE;
+ }
+ break;
+
+ case MACHINE_SPECIFIC_REG:
+ if (Resource->Header.Length != sizeof (STM_RSC_MSR_DESC)) {
+ return FALSE;
+ }
+ break;
+
+ default :
+ DEBUG ((DEBUG_ERROR, "ValidateResource - Unknown RscType(%x)\n", Resource->Header.RscType));
+ return FALSE;
+ }
+ Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
+ }
+ return TRUE;
+}
+
+/**
+
+ Get resource list.
+ EndResource is excluded.
+
+ @param ResourceList A pointer to resource list to be added
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval TRUE resource valid
+ @retval FALSE resource invalid
+
+**/
+UINTN
+GetResourceSize (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ )
+{
+ UINT32 Count;
+ UINTN Index;
+ STM_RSC *Resource;
+
+ Resource = ResourceList;
+
+ //
+ // If NumEntries == 0 make it very big. Scan will be terminated by
+ // END_OF_RESOURCES.
+ //
+ if (NumEntries == 0) {
+ Count = 0xFFFFFFFF;
+ } else {
+ Count = NumEntries;
+ }
+
+ //
+ // Start from beginning of resource list.
+ //
+ Resource = ResourceList;
+
+ for (Index = 0; Index < Count; Index++) {
+ if (Resource->Header.RscType == END_OF_RESOURCES) {
+ break;
+ }
+ Resource = (STM_RSC *)((UINTN)Resource + Resource->Header.Length);
+ }
+
+ return (UINTN)Resource - (UINTN)ResourceList;
+}
+
+/**
+
+ Add resources in list to database. Allocate new memory areas as needed.
+
+ @param ResourceList A pointer to resource list to be added
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval EFI_SUCCESS If resources are added
+ @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
+ @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
+
+**/
+EFI_STATUS
+EFIAPI
+AddPiResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN ResourceSize;
+ EFI_PHYSICAL_ADDRESS NewResource;
+ UINTN NewResourceSize;
+
+ DEBUG ((DEBUG_INFO, "AddPiResource - Enter\n"));
+
+ if (!ValidateResource (ResourceList, NumEntries)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ResourceSize = GetResourceSize (ResourceList, NumEntries);
+ DEBUG ((DEBUG_INFO, "ResourceSize - 0x%08x\n", ResourceSize));
+ if (ResourceSize == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (mStmResourcesPtr == NULL) {
+ //
+ // First time allocation
+ //
+ NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (ResourceSize + sizeof(mRscEndNode)));
+ DEBUG ((DEBUG_INFO, "Allocate - 0x%08x\n", NewResourceSize));
+ Status = gSmst->SmmAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (NewResourceSize),
+ &NewResource
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Copy EndResource for initialization
+ //
+ mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
+ mStmResourceTotalSize = NewResourceSize;
+ CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
+ mStmResourceSizeUsed = sizeof(mRscEndNode);
+ mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
+
+ //
+ // Let SmmCore change resource ptr
+ //
+ NotifyStmResourceChange (mStmResourcesPtr);
+ } else if (mStmResourceSizeAvailable < ResourceSize) {
+ //
+ // Need enlarge
+ //
+ NewResourceSize = mStmResourceTotalSize + (ResourceSize - mStmResourceSizeAvailable);
+ NewResourceSize = EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (NewResourceSize));
+ DEBUG ((DEBUG_INFO, "ReAllocate - 0x%08x\n", NewResourceSize));
+ Status = gSmst->SmmAllocatePages (
+ AllocateAnyPages,
+ EfiRuntimeServicesData,
+ EFI_SIZE_TO_PAGES (NewResourceSize),
+ &NewResource
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem ((VOID *)(UINTN)NewResource, mStmResourcesPtr, mStmResourceSizeUsed);
+ mStmResourceSizeAvailable = NewResourceSize - mStmResourceSizeUsed;
+
+ gSmst->SmmFreePages (
+ (EFI_PHYSICAL_ADDRESS)(UINTN)mStmResourcesPtr,
+ EFI_SIZE_TO_PAGES (mStmResourceTotalSize)
+ );
+
+ mStmResourceTotalSize = NewResourceSize;
+ mStmResourcesPtr = (UINT8 *)(UINTN)NewResource;
+
+ //
+ // Let SmmCore change resource ptr
+ //
+ NotifyStmResourceChange (mStmResourcesPtr);
+ }
+
+ //
+ // Check duplication
+ //
+ AddResource (ResourceList, NumEntries);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Delete resources in list to database.
+
+ @param ResourceList A pointer to resource list to be deleted
+ NULL means delete all resources.
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval EFI_SUCCESS If resources are deleted
+ @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
+
+**/
+EFI_STATUS
+EFIAPI
+DeletePiResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ )
+{
+ if (ResourceList != NULL) {
+ // TBD
+ ASSERT (FALSE);
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Delete all
+ //
+ CopyMem (mStmResourcesPtr, &mRscEndNode, sizeof(mRscEndNode));
+ mStmResourceSizeUsed = sizeof(mRscEndNode);
+ mStmResourceSizeAvailable = mStmResourceTotalSize - sizeof(mRscEndNode);
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get BIOS resources.
+
+ @param ResourceList A pointer to resource list to be filled
+ @param ResourceSize On input it means size of resource list input.
+ On output it means size of resource list filled,
+ or the size of resource list to be filled if size of too small.
+
+ @retval EFI_SUCCESS If resources are returned.
+ @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPiResource (
+ OUT STM_RSC *ResourceList,
+ IN OUT UINT32 *ResourceSize
+ )
+{
+ if (*ResourceSize < mStmResourceSizeUsed) {
+ *ResourceSize = (UINT32)mStmResourceSizeUsed;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ CopyMem (ResourceList, mStmResourcesPtr, mStmResourceSizeUsed);
+ *ResourceSize = (UINT32)mStmResourceSizeUsed;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Set valid bit for MSEG MSR.
+
+ @param Buffer Ap function buffer. (not used)
+
+**/
+VOID
+EFIAPI
+EnableMsegMsr (
+ IN VOID *Buffer
+ )
+{
+ MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
+
+ SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
+ SmmMonitorCtl.Bits.Valid = 1;
+ AsmWriteMsr64 (MSR_IA32_SMM_MONITOR_CTL, SmmMonitorCtl.Uint64);
+}
+
+/**
+
+ Get 4K page aligned VMCS size.
+
+ @return 4K page aligned VMCS size
+
+**/
+UINT32
+GetVmcsSize (
+ VOID
+ )
+{
+ MSR_IA32_VMX_BASIC_REGISTER VmxBasic;
+
+ //
+ // Read VMCS size and and align to 4KB
+ //
+ VmxBasic.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_BASIC);
+ return ALIGN_VALUE (VmxBasic.Bits.VmcsSize, SIZE_4KB);
+}
+
+/**
+
+ Check STM image size.
+
+ @param StmImage STM image
+ @param StmImageSize STM image size
+
+ @retval TRUE check pass
+ @retval FALSE check fail
+**/
+BOOLEAN
+StmCheckStmImage (
+ IN EFI_PHYSICAL_ADDRESS StmImage,
+ IN UINTN StmImageSize
+ )
+{
+ UINTN MinMsegSize;
+ STM_HEADER *StmHeader;
+ IA32_VMX_MISC_REGISTER VmxMiscMsr;
+
+ //
+ // Check to see if STM image is compatible with CPU
+ //
+ StmHeader = (STM_HEADER *)(UINTN)StmImage;
+ VmxMiscMsr.Uint64 = AsmReadMsr64 (MSR_IA32_VMX_MISC);
+ if (StmHeader->HwStmHdr.MsegHeaderRevision != VmxMiscMsr.Bits.MsegRevisionIdentifier) {
+ DEBUG ((DEBUG_ERROR, "STM Image not compatible with CPU\n"));
+ DEBUG ((DEBUG_ERROR, " StmHeader->HwStmHdr.MsegHeaderRevision = %08x\n", StmHeader->HwStmHdr.MsegHeaderRevision));
+ DEBUG ((DEBUG_ERROR, " VmxMiscMsr.Bits.MsegRevisionIdentifier = %08x\n", VmxMiscMsr.Bits.MsegRevisionIdentifier));
+ return FALSE;
+ }
+
+ //
+ // Get Minimal required Mseg size
+ //
+ MinMsegSize = (EFI_PAGES_TO_SIZE (EFI_SIZE_TO_PAGES (StmHeader->SwStmHdr.StaticImageSize)) +
+ StmHeader->SwStmHdr.AdditionalDynamicMemorySize +
+ (StmHeader->SwStmHdr.PerProcDynamicMemorySize + GetVmcsSize () * 2) * gSmst->NumberOfCpus);
+ if (MinMsegSize < StmImageSize) {
+ MinMsegSize = StmImageSize;
+ }
+
+ if (StmHeader->HwStmHdr.Cr3Offset >= StmHeader->SwStmHdr.StaticImageSize) {
+ //
+ // We will create page table, just in case that SINIT does not create it.
+ //
+ if (MinMsegSize < StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6)) {
+ MinMsegSize = StmHeader->HwStmHdr.Cr3Offset + EFI_PAGES_TO_SIZE(6);
+ }
+ }
+
+ //
+ // Check if it exceeds MSEG size
+ //
+ if (MinMsegSize > mMsegSize) {
+ DEBUG ((DEBUG_ERROR, "MSEG too small. Min MSEG Size = %08x Current MSEG Size = %08x\n", MinMsegSize, mMsegSize));
+ DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.StaticImageSize = %08x\n", StmHeader->SwStmHdr.StaticImageSize));
+ DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.AdditionalDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.AdditionalDynamicMemorySize));
+ DEBUG ((DEBUG_ERROR, " StmHeader->SwStmHdr.PerProcDynamicMemorySize = %08x\n", StmHeader->SwStmHdr.PerProcDynamicMemorySize));
+ DEBUG ((DEBUG_ERROR, " VMCS Size = %08x\n", GetVmcsSize ()));
+ DEBUG ((DEBUG_ERROR, " Max CPUs = %08x\n", gSmst->NumberOfCpus));
+ DEBUG ((DEBUG_ERROR, " StmHeader->HwStmHdr.Cr3Offset = %08x\n", StmHeader->HwStmHdr.Cr3Offset));
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+
+ Load STM image to MSEG.
+
+ @param StmImage STM image
+ @param StmImageSize STM image size
+
+**/
+VOID
+StmLoadStmImage (
+ IN EFI_PHYSICAL_ADDRESS StmImage,
+ IN UINTN StmImageSize
+ )
+{
+ MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
+ UINT32 MsegBase;
+ STM_HEADER *StmHeader;
+
+ //
+ // Get MSEG base address from MSR_IA32_SMM_MONITOR_CTL
+ //
+ SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
+ MsegBase = SmmMonitorCtl.Bits.MsegBase << 12;
+
+ //
+ // Zero all of MSEG base address
+ //
+ ZeroMem ((VOID *)(UINTN)MsegBase, mMsegSize);
+
+ //
+ // Copy STM Image into MSEG
+ //
+ CopyMem ((VOID *)(UINTN)MsegBase, (VOID *)(UINTN)StmImage, StmImageSize);
+
+ //
+ // STM Header is at the beginning of the STM Image
+ //
+ StmHeader = (STM_HEADER *)(UINTN)StmImage;
+
+ StmGen4GPageTable ((UINTN)MsegBase + StmHeader->HwStmHdr.Cr3Offset);
+}
+
+/**
+
+ Load STM image to MSEG.
+
+ @param StmImage STM image
+ @param StmImageSize STM image size
+
+ @retval EFI_SUCCESS Load STM to MSEG successfully
+ @retval EFI_ALREADY_STARTED STM image is already loaded to MSEG
+ @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
+ @retval EFI_UNSUPPORTED MSEG is not enabled
+
+**/
+EFI_STATUS
+EFIAPI
+LoadMonitor (
+ IN EFI_PHYSICAL_ADDRESS StmImage,
+ IN UINTN StmImageSize
+ )
+{
+ MSR_IA32_SMM_MONITOR_CTL_REGISTER SmmMonitorCtl;
+
+ if (mLockLoadMonitor) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ SmmMonitorCtl.Uint64 = AsmReadMsr64 (MSR_IA32_SMM_MONITOR_CTL);
+ if (SmmMonitorCtl.Bits.MsegBase == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (!StmCheckStmImage (StmImage, StmImageSize)) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ // Record STM_HASH to PCR 0, just in case it is NOT TXT launch, we still need provide the evidence.
+ TpmMeasureAndLogData(
+ 0, // PcrIndex
+ TXT_EVTYPE_STM_HASH, // EventType
+ NULL, // EventLog
+ 0, // LogLen
+ (VOID *)(UINTN)StmImage, // HashData
+ StmImageSize // HashDataLen
+ );
+
+ StmLoadStmImage (StmImage, StmImageSize);
+
+ mStmState |= EFI_SM_MONITOR_STATE_ENABLED;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function return BIOS STM resource.
+ Produced by SmmStm.
+ Consumed by SmmMpService when Init.
+
+ @return BIOS STM resource
+
+**/
+VOID *
+GetStmResource(
+ VOID
+ )
+{
+ return mStmResourcesPtr;
+}
+
+/**
+ This function notify STM resource change.
+
+ @param StmResource BIOS STM resource
+
+**/
+VOID
+NotifyStmResourceChange (
+ VOID *StmResource
+ )
+{
+ UINTN Index;
+ TXT_PROCESSOR_SMM_DESCRIPTOR *Psd;
+
+ for (Index = 0; Index < gSmst->NumberOfCpus; Index++) {
+ Psd = (TXT_PROCESSOR_SMM_DESCRIPTOR *)((UINTN)gSmst->CpuSaveState[Index] - SMRAM_SAVE_STATE_MAP_OFFSET + TXT_SMM_PSD_OFFSET);
+ Psd->BiosHwResourceRequirementsPtr = (UINT64)(UINTN)StmResource;
+ }
+ return ;
+}
+
+
+/**
+ This is STM setup BIOS callback.
+**/
+VOID
+EFIAPI
+SmmStmSetup (
+ VOID
+ )
+{
+ mStmState |= EFI_SM_MONITOR_STATE_ACTIVATED;
+}
+
+/**
+ This is STM teardown BIOS callback.
+**/
+VOID
+EFIAPI
+SmmStmTeardown (
+ VOID
+ )
+{
+ mStmState &= ~EFI_SM_MONITOR_STATE_ACTIVATED;
+}
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.h b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.h
new file mode 100644
index 00000000..417b3945
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/SmmStm.h
@@ -0,0 +1,179 @@
+/** @file
+ SMM STM support
+
+ Copyright (c) 2015 - 2018, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#ifndef _SMM_STM_H_
+#define _SMM_STM_H_
+
+#include <Protocol/SmMonitorInit.h>
+
+/**
+
+ Create 4G page table for STM.
+ 2M PAE page table in X64 version.
+
+ @param PageTableBase The page table base in MSEG
+
+**/
+VOID
+StmGen4GPageTable (
+ IN UINTN PageTableBase
+ );
+
+/**
+ This is SMM exception handle.
+ Consumed by STM when exception happen.
+
+ @param Context STM protection exception stack frame
+
+ @return the EBX value for STM reference.
+ EBX = 0: resume SMM guest using register state found on exception stack.
+ EBX = 1 to 0x0F: EBX contains a BIOS error code which the STM must record in the
+ TXT.ERRORCODE register and subsequently reset the system via
+ TXT.CMD.SYS_RESET. The value of the TXT.ERRORCODE register is calculated as
+ follows: TXT.ERRORCODE = (EBX & 0x0F) | STM_CRASH_BIOS_PANIC
+ EBX = 0x10 to 0xFFFFFFFF - reserved, do not use.
+
+**/
+UINT32
+EFIAPI
+SmmStmExceptionHandler (
+ IN OUT STM_PROTECTION_EXCEPTION_STACK_FRAME Context
+ );
+
+
+/**
+
+ Get STM state.
+
+ @return STM state
+
+**/
+EFI_SM_MONITOR_STATE
+EFIAPI
+GetMonitorState (
+ VOID
+ );
+
+/**
+
+ Load STM image to MSEG.
+
+ @param StmImage STM image
+ @param StmImageSize STM image size
+
+ @retval EFI_SUCCESS Load STM to MSEG successfully
+ @retval EFI_BUFFER_TOO_SMALL MSEG is smaller than minimal requirement of STM image
+
+**/
+EFI_STATUS
+EFIAPI
+LoadMonitor (
+ IN EFI_PHYSICAL_ADDRESS StmImage,
+ IN UINTN StmImageSize
+ );
+
+/**
+
+ Add resources in list to database. Allocate new memory areas as needed.
+
+ @param ResourceList A pointer to resource list to be added
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval EFI_SUCCESS If resources are added
+ @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
+ @retval EFI_OUT_OF_RESOURCES If nested procedure returned it and we cannot allocate more areas.
+
+**/
+EFI_STATUS
+EFIAPI
+AddPiResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ );
+
+/**
+
+ Delete resources in list to database.
+
+ @param ResourceList A pointer to resource list to be deleted
+ NULL means delete all resources.
+ @param NumEntries Optional number of entries.
+ If 0, list must be terminated by END_OF_RESOURCES.
+
+ @retval EFI_SUCCESS If resources are deleted
+ @retval EFI_INVALID_PARAMETER If nested procedure detected resource failer
+
+**/
+EFI_STATUS
+EFIAPI
+DeletePiResource (
+ IN STM_RSC *ResourceList,
+ IN UINT32 NumEntries OPTIONAL
+ );
+
+/**
+
+ Get BIOS resources.
+
+ @param ResourceList A pointer to resource list to be filled
+ @param ResourceSize On input it means size of resource list input.
+ On output it means size of resource list filled,
+ or the size of resource list to be filled if size of too small.
+
+ @retval EFI_SUCCESS If resources are returned.
+ @retval EFI_BUFFER_TOO_SMALL If resource list buffer is too small to hold the whole resources.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPiResource (
+ OUT STM_RSC *ResourceList,
+ IN OUT UINT32 *ResourceSize
+ );
+
+/**
+ This function initialize STM configuration table.
+**/
+VOID
+StmSmmConfigurationTableInit (
+ VOID
+ );
+
+/**
+ This function notify STM resource change.
+
+ @param StmResource BIOS STM resource
+
+**/
+VOID
+NotifyStmResourceChange (
+ IN VOID *StmResource
+ );
+
+/**
+ This function return BIOS STM resource.
+
+ @return BIOS STM resource
+
+**/
+VOID *
+GetStmResource (
+ VOID
+ );
+
+/**
+ This function fixes up the address of the global variable or function
+ referred in SmiEntry assembly files to be the absolute address.
+**/
+VOID
+EFIAPI
+SmmCpuFeaturesLibStmSmiEntryFixupAddress (
+ );
+
+#endif
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c
new file mode 100644
index 00000000..ea985200
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.c
@@ -0,0 +1,50 @@
+/** @file
+Standalone MM CPU specific programming.
+
+Copyright (c) 2010 - 2019, Intel Corporation. All rights reserved.<BR>
+Copyright (c) Microsoft Corporation.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/PcdLib.h>
+#include "CpuFeaturesLib.h"
+
+/**
+ Gets the maximum number of logical processors from the PCD PcdCpuMaxLogicalProcessorNumber.
+
+ This access is abstracted from the PCD services to enforce that the PCD be
+ FixedAtBuild in the Standalone MM build of this driver.
+
+ @return The value of PcdCpuMaxLogicalProcessorNumber.
+
+**/
+UINT32
+GetCpuMaxLogicalProcessorNumber (
+ VOID
+ )
+{
+ return FixedPcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+}
+
+/**
+ The Standalone MM library constructor.
+
+ @param[in] ImageHandle Image handle of this driver.
+ @param[in] SystemTable A Pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS This constructor always returns success.
+
+**/
+EFI_STATUS
+EFIAPI
+StandaloneMmCpuFeaturesLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_MM_SYSTEM_TABLE *SystemTable
+ )
+{
+ CpuFeaturesLibInitialization ();
+
+ return EFI_SUCCESS;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
new file mode 100644
index 00000000..ecd1cd4d
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/StandaloneMmCpuFeaturesLib.inf
@@ -0,0 +1,38 @@
+## @file
+# Standalone MM CPU specific programming.
+#
+# Copyright (c) 2009 - 2016, Intel Corporation. All rights reserved.<BR>
+# Copyright (c) Microsoft Corporation.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StandaloneMmCpuFeaturesLib
+ MODULE_UNI_FILE = SmmCpuFeaturesLib.uni
+ FILE_GUID = BB554A2D-F5DF-41D3-8C62-46476A2B2B18
+ MODULE_TYPE = MM_STANDALONE
+ VERSION_STRING = 1.0
+ PI_SPECIFICATION_VERSION = 0x00010032
+ LIBRARY_CLASS = SmmCpuFeaturesLib
+ CONSTRUCTOR = StandaloneMmCpuFeaturesLibConstructor
+
+[Sources]
+ CpuFeaturesLib.h
+ StandaloneMmCpuFeaturesLib.c
+ SmmCpuFeaturesLibCommon.c
+ SmmCpuFeaturesLibNoStm.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+
+[FixedPcd]
+ gUefiCpuPkgTokenSpaceGuid.PcdCpuMaxLogicalProcessorNumber ## SOMETIMES_CONSUMES
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c
new file mode 100644
index 00000000..8a7b7ead
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/TraditionalMmCpuFeaturesLib.c
@@ -0,0 +1,28 @@
+/** @file
+ Traditional MM CPU specific programming.
+
+ Copyright (c) Microsoft Corporation.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Library/PcdLib.h>
+#include "CpuFeaturesLib.h"
+
+/**
+ Gets the maximum number of logical processors from the PCD PcdCpuMaxLogicalProcessorNumber.
+
+ This access is abstracted from the PCD services to enforce that the PCD be
+ FixedAtBuild in the Standalone MM build of this driver.
+
+ @return The value of PcdCpuMaxLogicalProcessorNumber.
+
+**/
+UINT32
+GetCpuMaxLogicalProcessorNumber (
+ VOID
+ )
+{
+ return PcdGet32 (PcdCpuMaxLogicalProcessorNumber);
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiEntry.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiEntry.nasm
new file mode 100644
index 00000000..13850b0b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiEntry.nasm
@@ -0,0 +1,276 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; SmiEntry.nasm
+;
+; Abstract:
+;
+; Code template of the SMI handler for a particular processor
+;
+;-------------------------------------------------------------------------------
+
+%include "StuffRsbNasm.inc"
+
+;
+; Variables referenced by C code
+;
+
+%define MSR_IA32_MISC_ENABLE 0x1A0
+%define MSR_EFER 0xc0000080
+%define MSR_EFER_XD 0x800
+
+;
+; Constants relating to TXT_PROCESSOR_SMM_DESCRIPTOR
+;
+%define DSC_OFFSET 0xfb00
+%define DSC_GDTPTR 0x48
+%define DSC_GDTSIZ 0x50
+%define DSC_CS 0x14
+%define DSC_DS 0x16
+%define DSC_SS 0x18
+%define DSC_OTHERSEG 0x1a
+;
+; Constants relating to CPU State Save Area
+;
+%define SSM_DR6 0xffd0
+%define SSM_DR7 0xffc8
+
+%define PROTECT_MODE_CS 0x8
+%define PROTECT_MODE_DS 0x20
+%define LONG_MODE_CS 0x38
+%define TSS_SEGMENT 0x40
+%define GDT_SIZE 0x50
+
+extern ASM_PFX(SmiRendezvous)
+extern ASM_PFX(gStmSmiHandlerIdtr)
+extern ASM_PFX(CpuSmmDebugEntry)
+extern ASM_PFX(CpuSmmDebugExit)
+
+global ASM_PFX(gStmSmbase)
+global ASM_PFX(gStmXdSupported)
+global ASM_PFX(gStmSmiStack)
+global ASM_PFX(gStmSmiCr3)
+global ASM_PFX(gcStmSmiHandlerTemplate)
+global ASM_PFX(gcStmSmiHandlerSize)
+global ASM_PFX(gcStmSmiHandlerOffset)
+
+ASM_PFX(gStmSmbase) EQU StmSmbasePatch - 4
+ASM_PFX(gStmSmiStack) EQU StmSmiStackPatch - 4
+ASM_PFX(gStmSmiCr3) EQU StmSmiCr3Patch - 4
+ASM_PFX(gStmXdSupported) EQU StmXdSupportedPatch - 1
+
+ DEFAULT REL
+ SECTION .text
+
+BITS 16
+ASM_PFX(gcStmSmiHandlerTemplate):
+_StmSmiEntryPoint:
+ mov bx, _StmGdtDesc - _StmSmiEntryPoint + 0x8000
+ mov ax,[cs:DSC_OFFSET + DSC_GDTSIZ]
+ dec ax
+ mov [cs:bx], ax
+ mov eax, [cs:DSC_OFFSET + DSC_GDTPTR]
+ mov [cs:bx + 2], eax
+o32 lgdt [cs:bx] ; lgdt fword ptr cs:[bx]
+ mov ax, PROTECT_MODE_CS
+ mov [cs:bx-0x2],ax
+o32 mov edi, strict dword 0
+StmSmbasePatch:
+ lea eax, [edi + (@ProtectedMode - _StmSmiEntryPoint) + 0x8000]
+ mov [cs:bx-0x6],eax
+ mov ebx, cr0
+ and ebx, 0x9ffafff3
+ or ebx, 0x23
+ mov cr0, ebx
+ jmp dword 0x0:0x0
+_StmGdtDesc:
+ DW 0
+ DD 0
+
+BITS 32
+@ProtectedMode:
+ mov ax, PROTECT_MODE_DS
+o16 mov ds, ax
+o16 mov es, ax
+o16 mov fs, ax
+o16 mov gs, ax
+o16 mov ss, ax
+ mov esp, strict dword 0
+StmSmiStackPatch:
+ jmp ProtFlatMode
+
+BITS 64
+ProtFlatMode:
+ mov eax, strict dword 0
+StmSmiCr3Patch:
+ mov cr3, rax
+ mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
+; Load TSS
+ sub esp, 8 ; reserve room in stack
+ sgdt [rsp]
+ mov eax, [rsp + 2] ; eax = GDT base
+ add esp, 8
+ mov dl, 0x89
+ mov [rax + TSS_SEGMENT + 5], dl ; clear busy flag
+ mov eax, TSS_SEGMENT
+ ltr ax
+
+; enable NXE if supported
+ mov al, strict byte 1
+StmXdSupportedPatch:
+ cmp al, 0
+ jz @SkipXd
+;
+; Check XD disable bit
+;
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ sub esp, 4
+ push rdx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .0
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.0:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+ jmp @XdDone
+@SkipXd:
+ sub esp, 8
+@XdDone:
+
+; Switch into @LongMode
+ push LONG_MODE_CS ; push cs hardcore here
+ call Base ; push return address for retf later
+Base:
+ add dword [rsp], @LongMode - Base; offset for far retf, seg is the 1st arg
+
+ mov ecx, MSR_EFER
+ rdmsr
+ or ah, 1 ; enable LME
+ wrmsr
+ mov rbx, cr0
+ or ebx, 0x80010023 ; enable paging + WP + NE + MP + PE
+ mov cr0, rbx
+ retf
+@LongMode: ; long mode (64-bit code) starts here
+ mov rax, strict qword 0 ; mov rax, ASM_PFX(gStmSmiHandlerIdtr)
+StmSmiEntrySmiHandlerIdtrAbsAddr:
+ lidt [rax]
+ lea ebx, [rdi + DSC_OFFSET]
+ mov ax, [rbx + DSC_DS]
+ mov ds, eax
+ mov ax, [rbx + DSC_OTHERSEG]
+ mov es, eax
+ mov fs, eax
+ mov gs, eax
+ mov ax, [rbx + DSC_SS]
+ mov ss, eax
+ mov rax, strict qword 0 ; mov rax, CommonHandler
+StmSmiEntryCommonHandlerAbsAddr:
+ jmp rax
+CommonHandler:
+ mov rbx, [rsp + 0x08] ; rbx <- CpuIndex
+
+ ;
+ ; Save FP registers
+ ;
+ sub rsp, 0x200
+ fxsave64 [rsp]
+
+ add rsp, -0x20
+
+ mov rcx, rbx
+ call ASM_PFX(CpuSmmDebugEntry)
+
+ mov rcx, rbx
+ call ASM_PFX(SmiRendezvous)
+
+ mov rcx, rbx
+ call ASM_PFX(CpuSmmDebugExit)
+
+ add rsp, 0x20
+
+ ;
+ ; Restore FP registers
+ ;
+ fxrstor64 [rsp]
+
+ add rsp, 0x200
+
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz .1
+ pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .1
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.1:
+ StuffRsb64
+ rsm
+
+_StmSmiHandler:
+;
+; Check XD disable bit
+;
+ xor r8, r8
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz @StmXdDone
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov r8, rdx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .0
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.0:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone:
+ push r8
+
+ ; below step is needed, because STM does not run above code.
+ ; we have to run below code to set IDT/CR0/CR4
+ mov rax, strict qword 0 ; mov rax, ASM_PFX(gStmSmiHandlerIdtr)
+StmSmiHandlerIdtrAbsAddr:
+ lidt [rax]
+
+ mov rax, cr0
+ or eax, 0x80010023 ; enable paging + WP + NE + MP + PE
+ mov cr0, rax
+ mov rax, cr4
+ mov eax, 0x668 ; as cr4.PGE is not set here, refresh cr3
+ mov cr4, rax ; in PreModifyMtrrs() to flush TLB.
+ ; STM init finish
+ jmp CommonHandler
+
+ASM_PFX(gcStmSmiHandlerSize) : DW $ - _StmSmiEntryPoint
+ASM_PFX(gcStmSmiHandlerOffset) : DW _StmSmiHandler - _StmSmiEntryPoint
+
+global ASM_PFX(SmmCpuFeaturesLibStmSmiEntryFixupAddress)
+ASM_PFX(SmmCpuFeaturesLibStmSmiEntryFixupAddress):
+ lea rax, [ASM_PFX(gStmSmiHandlerIdtr)]
+ lea rcx, [StmSmiEntrySmiHandlerIdtrAbsAddr]
+ mov qword [rcx - 8], rax
+ lea rcx, [StmSmiHandlerIdtrAbsAddr]
+ mov qword [rcx - 8], rax
+
+ lea rax, [CommonHandler]
+ lea rcx, [StmSmiEntryCommonHandlerAbsAddr]
+ mov qword [rcx - 8], rax
+ ret
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiException.nasm b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiException.nasm
new file mode 100644
index 00000000..c3b92ac8
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmiException.nasm
@@ -0,0 +1,176 @@
+;------------------------------------------------------------------------------ ;
+; Copyright (c) 2016 - 2018, Intel Corporation. All rights reserved.<BR>
+; SPDX-License-Identifier: BSD-2-Clause-Patent
+;
+; Module Name:
+;
+; SmiException.nasm
+;
+; Abstract:
+;
+; Exception handlers used in SM mode
+;
+;-------------------------------------------------------------------------------
+
+%include "StuffRsbNasm.inc"
+
+global ASM_PFX(gcStmPsd)
+
+extern ASM_PFX(SmmStmExceptionHandler)
+extern ASM_PFX(SmmStmSetup)
+extern ASM_PFX(SmmStmTeardown)
+extern ASM_PFX(gStmXdSupported)
+extern ASM_PFX(gStmSmiHandlerIdtr)
+
+%define MSR_IA32_MISC_ENABLE 0x1A0
+%define MSR_EFER 0xc0000080
+%define MSR_EFER_XD 0x800
+
+CODE_SEL equ 0x38
+DATA_SEL equ 0x20
+TR_SEL equ 0x40
+
+ SECTION .data
+
+;
+; This structure serves as a template for all processors.
+;
+ASM_PFX(gcStmPsd):
+ DB 'TXTPSSIG'
+ DW PSD_SIZE
+ DW 1 ; Version
+ DD 0 ; LocalApicId
+ DB 0x0F ; Cr4Pse;Cr4Pae;Intel64Mode;ExecutionDisableOutsideSmrr
+ DB 0 ; BIOS to STM
+ DB 0 ; STM to BIOS
+ DB 0
+ DW CODE_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW DATA_SEL
+ DW TR_SEL
+ DW 0
+ DQ 0 ; SmmCr3
+ DQ ASM_PFX(OnStmSetup)
+ DQ ASM_PFX(OnStmTeardown)
+ DQ 0 ; SmmSmiHandlerRip - SMM guest entrypoint
+ DQ 0 ; SmmSmiHandlerRsp
+ DQ 0
+ DD 0
+ DD 0x80010100 ; RequiredStmSmmRevId
+ DQ ASM_PFX(OnException)
+ DQ 0 ; ExceptionStack
+ DW DATA_SEL
+ DW 0x01F ; ExceptionFilter
+ DD 0
+ DQ 0
+ DQ 0 ; BiosHwResourceRequirementsPtr
+ DQ 0 ; AcpiRsdp
+ DB 0 ; PhysicalAddressBits
+PSD_SIZE equ $ - ASM_PFX(gcStmPsd)
+
+ DEFAULT REL
+ SECTION .text
+;------------------------------------------------------------------------------
+; SMM Exception handlers
+;------------------------------------------------------------------------------
+global ASM_PFX(OnException)
+ASM_PFX(OnException):
+ mov rcx, rsp
+ add rsp, -0x28
+ call ASM_PFX(SmmStmExceptionHandler)
+ add rsp, 0x28
+ mov ebx, eax
+ mov eax, 4
+ vmcall
+ jmp $
+
+global ASM_PFX(OnStmSetup)
+ASM_PFX(OnStmSetup):
+;
+; Check XD disable bit
+;
+ xor r8, r8
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz @StmXdDone1
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov r8, rdx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .01
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.01:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone1:
+ push r8
+
+ add rsp, -0x20
+ call ASM_PFX(SmmStmSetup)
+ add rsp, 0x20
+
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz .11
+ pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .11
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.11:
+ StuffRsb64
+ rsm
+
+global ASM_PFX(OnStmTeardown)
+ASM_PFX(OnStmTeardown):
+;
+; Check XD disable bit
+;
+ xor r8, r8
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz @StmXdDone2
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ mov r8, rdx ; save MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2 ; MSR_IA32_MISC_ENABLE[34]
+ jz .02
+ and dx, 0xFFFB ; clear XD Disable bit if it is set
+ wrmsr
+.02:
+ mov ecx, MSR_EFER
+ rdmsr
+ or ax, MSR_EFER_XD ; enable NXE
+ wrmsr
+@StmXdDone2:
+ push r8
+
+ add rsp, -0x20
+ call ASM_PFX(SmmStmTeardown)
+ add rsp, 0x20
+
+ lea rax, [ASM_PFX(gStmXdSupported)]
+ mov al, [rax]
+ cmp al, 0
+ jz .12
+ pop rdx ; get saved MSR_IA32_MISC_ENABLE[63-32]
+ test edx, BIT2
+ jz .12
+ mov ecx, MSR_IA32_MISC_ENABLE
+ rdmsr
+ or dx, BIT2 ; set XD Disable bit if it was set before entering into SMM
+ wrmsr
+
+.12:
+ StuffRsb64
+ rsm
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmmStmSupport.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmmStmSupport.c
new file mode 100644
index 00000000..9ba17dd6
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuFeaturesLib/X64/SmmStmSupport.c
@@ -0,0 +1,89 @@
+/** @file
+ SMM STM support functions
+
+ Copyright (c) 2015 - 2016, Intel Corporation. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <PiMm.h>
+#include <Library/DebugLib.h>
+
+#include "SmmStm.h"
+
+///
+/// Page Table Entry
+///
+#define IA32_PG_P BIT0
+#define IA32_PG_RW BIT1
+#define IA32_PG_PS BIT7
+
+/**
+
+ Create 4G page table for STM.
+ 2M PAE page table in X64 version.
+
+ @param PageTableBase The page table base in MSEG
+
+**/
+VOID
+StmGen4GPageTable (
+ IN UINTN PageTableBase
+ )
+{
+ UINTN Index;
+ UINTN SubIndex;
+ UINT64 *Pde;
+ UINT64 *Pte;
+ UINT64 *Pml4;
+
+ Pml4 = (UINT64*)(UINTN)PageTableBase;
+ PageTableBase += SIZE_4KB;
+ *Pml4 = PageTableBase | IA32_PG_RW | IA32_PG_P;
+
+ Pde = (UINT64*)(UINTN)PageTableBase;
+ PageTableBase += SIZE_4KB;
+ Pte = (UINT64 *)(UINTN)PageTableBase;
+
+ for (Index = 0; Index < 4; Index++) {
+ *Pde = PageTableBase | IA32_PG_RW | IA32_PG_P;
+ Pde++;
+ PageTableBase += SIZE_4KB;
+
+ for (SubIndex = 0; SubIndex < SIZE_4KB / sizeof (*Pte); SubIndex++) {
+ *Pte = (((Index << 9) + SubIndex) << 21) | IA32_PG_PS | IA32_PG_RW | IA32_PG_P;
+ Pte++;
+ }
+ }
+}
+
+/**
+ This is SMM exception handle.
+ Consumed by STM when exception happen.
+
+ @param Context STM protection exception stack frame
+
+ @return the EBX value for STM reference.
+ EBX = 0: resume SMM guest using register state found on exception stack.
+ EBX = 1 to 0x0F: EBX contains a BIOS error code which the STM must record in the
+ TXT.ERRORCODE register and subsequently reset the system via
+ TXT.CMD.SYS_RESET. The value of the TXT.ERRORCODE register is calculated as
+ follows: TXT.ERRORCODE = (EBX & 0x0F) | STM_CRASH_BIOS_PANIC
+ EBX = 0x10 to 0xFFFFFFFF - reserved, do not use.
+
+**/
+UINT32
+EFIAPI
+SmmStmExceptionHandler (
+ IN OUT STM_PROTECTION_EXCEPTION_STACK_FRAME Context
+ )
+{
+ // TBD - SmmStmExceptionHandler, record information
+ DEBUG ((DEBUG_ERROR, "SmmStmExceptionHandler ...\n"));
+ //
+ // Skip this instruction and continue;
+ //
+ Context.X64StackFrame->Rip += Context.X64StackFrame->VmcsExitInstructionLength;
+
+ return 0;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
new file mode 100644
index 00000000..4b4204e0
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.c
@@ -0,0 +1,102 @@
+/** @file
+SMM CPU Platform Hook NULL library instance.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+#include <PiSmm.h>
+#include <Library/SmmCpuPlatformHookLib.h>
+
+/**
+ Checks if platform produces a valid SMI.
+
+ This function checks if platform produces a valid SMI. This function is
+ called at SMM entry to detect if this is a spurious SMI. This function
+ must be implemented in an MP safe way because it is called by multiple CPU
+ threads.
+
+ @retval TRUE There is a valid SMI
+ @retval FALSE There is no valid SMI
+
+**/
+BOOLEAN
+EFIAPI
+PlatformValidSmi (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+/**
+ Clears platform top level SMI status bit.
+
+ This function clears platform top level SMI status bit.
+
+ @retval TRUE The platform top level SMI status is cleared.
+ @retval FALSE The platform top level SMI status cannot be cleared.
+
+**/
+BOOLEAN
+EFIAPI
+ClearTopLevelSmiStatus (
+ VOID
+ )
+{
+ return TRUE;
+}
+
+/**
+ Performs platform specific way of SMM BSP election.
+
+ This function performs platform specific way of SMM BSP election.
+
+ @param IsBsp Output parameter. TRUE: the CPU this function executes
+ on is elected to be the SMM BSP. FALSE: the CPU this
+ function executes on is to be SMM AP.
+
+ @retval EFI_SUCCESS The function executes successfully.
+ @retval EFI_NOT_READY The function does not determine whether this CPU should be
+ BSP or AP. This may occur if hardware init sequence to
+ enable the determination is yet to be done, or the function
+ chooses not to do BSP election and will let SMM CPU driver to
+ use its default BSP election process.
+ @retval EFI_DEVICE_ERROR The function cannot determine whether this CPU should be
+ BSP or AP due to hardware error.
+
+**/
+EFI_STATUS
+EFIAPI
+PlatformSmmBspElection (
+ OUT BOOLEAN *IsBsp
+ )
+{
+ return EFI_NOT_READY;
+}
+
+/**
+ Get platform page table attribute.
+
+ This function gets page table attribute of platform.
+
+ @param Address Input parameter. Obtain the page table entries attribute on this address.
+ @param PageSize Output parameter. The size of the page.
+ @param NumOfPages Output parameter. Number of page.
+ @param PageAttribute Output parameter. Paging Attributes (WB, UC, etc).
+
+ @retval EFI_SUCCESS The platform page table attribute from the address is determined.
+ @retval EFI_UNSUPPORTED The platform does not support getting page table attribute for the address.
+
+**/
+EFI_STATUS
+EFIAPI
+GetPlatformPageTableAttribute (
+ IN UINT64 Address,
+ IN OUT SMM_PAGE_SIZE_TYPE *PageSize,
+ IN OUT UINTN *NumOfPages,
+ IN OUT UINTN *PageAttribute
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
new file mode 100644
index 00000000..7f147d8b
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.inf
@@ -0,0 +1,34 @@
+## @file
+# SMM CPU Platform Hook NULL library instance.
+#
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmCpuPlatformHookLibNull
+ MODULE_UNI_FILE = SmmCpuPlatformHookLibNull.uni
+ FILE_GUID = D6494E1B-E06F-4ab5-B64D-48B25AA9EB33
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = SmmCpuPlatformHookLib
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ SmmCpuPlatformHookLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni
new file mode 100644
index 00000000..b00beee9
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/SmmCpuPlatformHookLibNull/SmmCpuPlatformHookLibNull.uni
@@ -0,0 +1,12 @@
+// /** @file
+// SMM CPU Platform Hook NULL library instance.
+//
+// Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+//
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+#string STR_MODULE_ABSTRACT #language en-US "SMM CPU Platform Hook NULL library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "SMM CPU Platform Hook NULL library instance."
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c
new file mode 100644
index 00000000..c1b36573
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.c
@@ -0,0 +1,165 @@
+/** @file
+ VMGEXIT Base Support Library.
+
+ Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+ SPDX-License-Identifier: BSD-2-Clause-Patent
+
+**/
+
+#include <Base.h>
+#include <Uefi.h>
+#include <Library/VmgExitLib.h>
+
+/**
+ Perform VMGEXIT.
+
+ Sets the necessary fields of the GHCB, invokes the VMGEXIT instruction and
+ then handles the return actions.
+
+ The base library function returns an error in the form of a
+ GHCB_EVENT_INJECTION representing a GP_EXCEPTION.
+
+ @param[in, out] Ghcb A pointer to the GHCB
+ @param[in] ExitCode VMGEXIT code to be assigned to the SwExitCode
+ field of the GHCB.
+ @param[in] ExitInfo1 VMGEXIT information to be assigned to the
+ SwExitInfo1 field of the GHCB.
+ @param[in] ExitInfo2 VMGEXIT information to be assigned to the
+ SwExitInfo2 field of the GHCB.
+
+ @retval 0 VMGEXIT succeeded.
+ @return Exception number to be propagated, VMGEXIT
+ processing did not succeed.
+
+**/
+UINT64
+EFIAPI
+VmgExit (
+ IN OUT GHCB *Ghcb,
+ IN UINT64 ExitCode,
+ IN UINT64 ExitInfo1,
+ IN UINT64 ExitInfo2
+ )
+{
+ GHCB_EVENT_INJECTION Event;
+
+ Event.Uint64 = 0;
+ Event.Elements.Vector = GP_EXCEPTION;
+ Event.Elements.Type = GHCB_EVENT_INJECTION_TYPE_EXCEPTION;
+ Event.Elements.Valid = 1;
+
+ return Event.Uint64;
+}
+
+/**
+ Perform pre-VMGEXIT initialization/preparation.
+
+ Performs the necessary steps in preparation for invoking VMGEXIT. Must be
+ called before setting any fields within the GHCB.
+
+ @param[in, out] Ghcb A pointer to the GHCB
+ @param[in, out] InterruptState A pointer to hold the current interrupt
+ state, used for restoring in VmgDone ()
+
+**/
+VOID
+EFIAPI
+VmgInit (
+ IN OUT GHCB *Ghcb,
+ IN OUT BOOLEAN *InterruptState
+ )
+{
+}
+
+/**
+ Perform post-VMGEXIT cleanup.
+
+ Performs the necessary steps to cleanup after invoking VMGEXIT. Must be
+ called after obtaining needed fields within the GHCB.
+
+ @param[in, out] Ghcb A pointer to the GHCB
+ @param[in] InterruptState An indicator to conditionally (re)enable
+ interrupts
+
+**/
+VOID
+EFIAPI
+VmgDone (
+ IN OUT GHCB *Ghcb,
+ IN BOOLEAN InterruptState
+ )
+{
+}
+
+/**
+ Marks a field at the specified offset as valid in the GHCB.
+
+ The ValidBitmap area represents the areas of the GHCB that have been marked
+ valid. Set the bit in ValidBitmap for the input offset.
+
+ @param[in, out] Ghcb Pointer to the Guest-Hypervisor Communication Block
+ @param[in] Offset Qword offset in the GHCB to mark valid
+
+**/
+VOID
+EFIAPI
+VmgSetOffsetValid (
+ IN OUT GHCB *Ghcb,
+ IN GHCB_REGISTER Offset
+ )
+{
+}
+
+/**
+ Checks if a specified offset is valid in the GHCB.
+
+ The ValidBitmap area represents the areas of the GHCB that have been marked
+ valid. Return whether the bit in the ValidBitmap is set for the input offset.
+
+ @param[in] Ghcb A pointer to the GHCB
+ @param[in] Offset Qword offset in the GHCB to mark valid
+
+ @retval TRUE Offset is marked valid in the GHCB
+ @retval FALSE Offset is not marked valid in the GHCB
+
+**/
+BOOLEAN
+EFIAPI
+VmgIsOffsetValid (
+ IN GHCB *Ghcb,
+ IN GHCB_REGISTER Offset
+ )
+{
+ return FALSE;
+}
+
+/**
+ Handle a #VC exception.
+
+ Performs the necessary processing to handle a #VC exception.
+
+ The base library function returns an error equal to VC_EXCEPTION,
+ to be propagated to the standard exception handling stack.
+
+ @param[in, out] ExceptionType Pointer to an EFI_EXCEPTION_TYPE to be set
+ as value to use on error.
+ @param[in, out] SystemContext Pointer to EFI_SYSTEM_CONTEXT
+
+ @retval EFI_SUCCESS Exception handled
+ @retval EFI_UNSUPPORTED #VC not supported, (new) exception value to
+ propagate provided
+ @retval EFI_PROTOCOL_ERROR #VC handling failed, (new) exception value to
+ propagate provided
+
+**/
+EFI_STATUS
+EFIAPI
+VmgExitHandleVc (
+ IN OUT EFI_EXCEPTION_TYPE *ExceptionType,
+ IN OUT EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+ *ExceptionType = VC_EXCEPTION;
+
+ return EFI_UNSUPPORTED;
+}
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
new file mode 100644
index 00000000..fe3e0148
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.inf
@@ -0,0 +1,27 @@
+## @file
+# VMGEXIT Support Library.
+#
+# Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+# SPDX-License-Identifier: BSD-2-Clause-Patent
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VmgExitLibNull
+ MODULE_UNI_FILE = VmgExitLibNull.uni
+ FILE_GUID = 3cd7368f-ef9b-4a9b-9571-2ed93813677e
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = VmgExitLib
+
+[Sources.common]
+ VmgExitLibNull.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ UefiCpuPkg/UefiCpuPkg.dec
+
+[LibraryClasses]
+ BaseLib
+
diff --git a/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni
new file mode 100644
index 00000000..8639bc0e
--- /dev/null
+++ b/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/VmgExitLibNull/VmgExitLibNull.uni
@@ -0,0 +1,15 @@
+// /** @file
+// VMGEXIT support library instance.
+//
+// VMGEXIT support library instance.
+//
+// Copyright (C) 2020, Advanced Micro Devices, Inc. All rights reserved.<BR>
+// SPDX-License-Identifier: BSD-2-Clause-Patent
+//
+// **/
+
+
+#string STR_MODULE_ABSTRACT #language en-US "VMGEXIT support NULL library instance"
+
+#string STR_MODULE_DESCRIPTION #language en-US "VMGEXIT support NULL library instance."
+