| /** @file | |
| CPU Features Initialize functions. | |
| Copyright (c) 2017 - 2023, 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; | |
| } | |
| 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->CpuFeatureInitData.CpuStatus; | |
| Location = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (EFI_CPU_PHYSICAL_LOCATION) * NumberOfCpus)); | |
| ASSERT (Location != NULL); | |
| ZeroMem (Location, sizeof (EFI_CPU_PHYSICAL_LOCATION) * NumberOfCpus); | |
| AcpiCpuData->CpuFeatureInitData.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 = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (UINT32) * CpuStatus->PackageCount)); | |
| ASSERT (ThreadCountPerPackage != NULL); | |
| ZeroMem (ThreadCountPerPackage, sizeof (UINT32) * CpuStatus->PackageCount); | |
| CpuStatus->ThreadCountPerPackage = (EFI_PHYSICAL_ADDRESS)(UINTN)ThreadCountPerPackage; | |
| ThreadCountPerCore = AllocatePages (EFI_SIZE_TO_PAGES (sizeof (UINT8) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount)); | |
| ASSERT (ThreadCountPerCore != NULL); | |
| ZeroMem (ThreadCountPerCore, sizeof (UINT8) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount); | |
| 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_BEGIN (); | |
| 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); | |
| DEBUG_CODE_END (); | |
| // | |
| // 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->CpuFeatureInitData.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->CpuFeatureInitData.ApLocation + ProcIndex, | |
| &AcpiCpuData->CpuFeatureInitData.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); | |
| } |