summaryrefslogtreecommitdiffstats
path: root/src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib
diff options
context:
space:
mode:
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib')
-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
8 files changed, 3464 insertions, 0 deletions
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."
+