diff options
Diffstat (limited to 'src/VBox/Devices/EFI/Firmware/UefiCpuPkg/Library/RegisterCpuFeaturesLib')
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."
+
|