2 CPU Features Initialize functions.
4 Copyright (c) 2017 - 2019, Intel Corporation. All rights reserved.<BR>
5 SPDX-License-Identifier: BSD-2-Clause-Patent
9 #include "RegisterCpuFeatures.h"
11 CHAR16
*mDependTypeStr
[] = {L
"None", L
"Thread", L
"Core", L
"Package", L
"Invalid" };
12 CHAR16
*mRegisterTypeStr
[] = {L
"MSR", L
"CR", L
"MMIO", L
"CACHE", L
"SEMAP", L
"INVALID" };
15 Worker function to save PcdCpuFeaturesCapability.
17 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
18 @param[in] FeatureMaskSize CPU feature bits mask buffer size.
23 IN UINT8
*SupportedFeatureMask
,
24 IN UINT32 FeatureMaskSize
30 BitMaskSize
= PcdGetSize (PcdCpuFeaturesCapability
);
31 ASSERT (FeatureMaskSize
== BitMaskSize
);
33 Status
= PcdSetPtrS (PcdCpuFeaturesCapability
, &BitMaskSize
, SupportedFeatureMask
);
34 ASSERT_EFI_ERROR (Status
);
38 Worker function to save PcdCpuFeaturesSetting.
40 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
44 IN UINT8
*SupportedFeatureMask
50 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
51 Status
= PcdSetPtrS (PcdCpuFeaturesSetting
, &BitMaskSize
, SupportedFeatureMask
);
52 ASSERT_EFI_ERROR (Status
);
56 Collects CPU type and feature information.
58 @param[in, out] CpuInfo The pointer to CPU feature information
62 IN OUT REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
65 CPUID_VERSION_INFO_EAX Eax
;
66 CPUID_VERSION_INFO_ECX Ecx
;
67 CPUID_VERSION_INFO_EDX Edx
;
68 UINT32 DisplayedFamily
;
69 UINT32 DisplayedModel
;
71 AsmCpuid (CPUID_VERSION_INFO
, &Eax
.Uint32
, NULL
, &Ecx
.Uint32
, &Edx
.Uint32
);
73 DisplayedFamily
= Eax
.Bits
.FamilyId
;
74 if (Eax
.Bits
.FamilyId
== 0x0F) {
75 DisplayedFamily
|= (Eax
.Bits
.ExtendedFamilyId
<< 4);
78 DisplayedModel
= Eax
.Bits
.Model
;
79 if (Eax
.Bits
.FamilyId
== 0x06 || Eax
.Bits
.FamilyId
== 0x0f) {
80 DisplayedModel
|= (Eax
.Bits
.ExtendedModelId
<< 4);
83 CpuInfo
->DisplayFamily
= DisplayedFamily
;
84 CpuInfo
->DisplayModel
= DisplayedModel
;
85 CpuInfo
->SteppingId
= Eax
.Bits
.SteppingId
;
86 CpuInfo
->ProcessorType
= Eax
.Bits
.ProcessorType
;
87 CpuInfo
->CpuIdVersionInfoEcx
.Uint32
= Ecx
.Uint32
;
88 CpuInfo
->CpuIdVersionInfoEdx
.Uint32
= Edx
.Uint32
;
92 Prepares for private data used for CPU features.
96 CpuInitDataInitialize (
101 UINTN ProcessorNumber
;
102 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer
;
103 CPU_FEATURES_ENTRY
*CpuFeature
;
104 CPU_FEATURES_INIT_ORDER
*InitOrder
;
105 CPU_FEATURES_DATA
*CpuFeaturesData
;
110 EFI_CPU_PHYSICAL_LOCATION
*Location
;
111 BOOLEAN
*CoresVisited
;
113 ACPI_CPU_DATA
*AcpiCpuData
;
114 CPU_STATUS_INFORMATION
*CpuStatus
;
115 UINT32
*ValidCoreCountPerPackage
;
117 UINTN NumberOfEnabledProcessors
;
123 CpuFeaturesData
= GetCpuFeaturesData ();
126 // Initialize CpuFeaturesData->MpService as early as possile, so later function can use it.
128 CpuFeaturesData
->MpService
= GetMpService ();
130 GetNumberOfProcessor (&NumberOfCpus
, &NumberOfEnabledProcessors
);
132 CpuFeaturesData
->InitOrder
= AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER
) * NumberOfCpus
);
133 ASSERT (CpuFeaturesData
->InitOrder
!= NULL
);
136 // Collect CPU Features information
138 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
139 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
140 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
141 ASSERT (CpuFeature
->InitializeFunc
!= NULL
);
142 if (CpuFeature
->GetConfigDataFunc
!= NULL
) {
143 CpuFeature
->ConfigData
= CpuFeature
->GetConfigDataFunc (NumberOfCpus
);
145 Entry
= Entry
->ForwardLink
;
148 CpuFeaturesData
->NumberOfCpus
= (UINT32
) NumberOfCpus
;
150 AcpiCpuData
= GetAcpiCpuData ();
151 ASSERT (AcpiCpuData
!= NULL
);
152 CpuFeaturesData
->AcpiCpuData
= AcpiCpuData
;
154 CpuStatus
= &AcpiCpuData
->CpuStatus
;
155 Location
= AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION
) * NumberOfCpus
);
156 ASSERT (Location
!= NULL
);
157 AcpiCpuData
->ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Location
;
159 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
160 InitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
161 InitOrder
->FeaturesSupportedMask
= AllocateZeroPool (CpuFeaturesData
->BitMaskSize
);
162 ASSERT (InitOrder
->FeaturesSupportedMask
!= NULL
);
163 InitializeListHead (&InitOrder
->OrderList
);
164 Status
= GetProcessorInformation (ProcessorNumber
, &ProcessorInfoBuffer
);
165 ASSERT_EFI_ERROR (Status
);
167 &InitOrder
->CpuInfo
.ProcessorInfo
,
168 &ProcessorInfoBuffer
,
169 sizeof (EFI_PROCESSOR_INFORMATION
)
172 &Location
[ProcessorNumber
],
173 &ProcessorInfoBuffer
.Location
,
174 sizeof (EFI_CPU_PHYSICAL_LOCATION
)
178 // Collect CPU package count info.
180 if (Package
< ProcessorInfoBuffer
.Location
.Package
) {
181 Package
= ProcessorInfoBuffer
.Location
.Package
;
184 // Collect CPU max core count info.
186 if (Core
< ProcessorInfoBuffer
.Location
.Core
) {
187 Core
= ProcessorInfoBuffer
.Location
.Core
;
190 // Collect CPU max thread count info.
192 if (Thread
< ProcessorInfoBuffer
.Location
.Thread
) {
193 Thread
= ProcessorInfoBuffer
.Location
.Thread
;
196 CpuStatus
->PackageCount
= Package
+ 1;
197 CpuStatus
->MaxCoreCount
= Core
+ 1;
198 CpuStatus
->MaxThreadCount
= Thread
+ 1;
199 DEBUG ((DEBUG_INFO
, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
200 CpuStatus
->PackageCount
,
201 CpuStatus
->MaxCoreCount
,
202 CpuStatus
->MaxThreadCount
));
205 // Collect valid core count in each package because not all cores are valid.
207 ValidCoreCountPerPackage
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
);
208 ASSERT (ValidCoreCountPerPackage
!= 0);
209 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ValidCoreCountPerPackage
;
210 CoresVisited
= AllocatePool (sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
211 ASSERT (CoresVisited
!= NULL
);
213 for (Index
= 0; Index
< CpuStatus
->PackageCount
; Index
++ ) {
214 ZeroMem (CoresVisited
, sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
216 // Collect valid cores in Current package.
218 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
219 Location
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
.ProcessorInfo
.Location
;
220 if (Location
->Package
== Index
&& !CoresVisited
[Location
->Core
] ) {
222 // The ValidCores position for Location->Core is valid.
223 // The possible values in ValidCores[Index] are 0 or 1.
224 // FALSE means no valid threads in this Core.
225 // TRUE means have valid threads in this core, no matter the thead count is 1 or more.
227 CoresVisited
[Location
->Core
] = TRUE
;
228 ValidCoreCountPerPackage
[Index
]++;
232 FreePool (CoresVisited
);
234 for (Index
= 0; Index
<= Package
; Index
++) {
235 DEBUG ((DEBUG_INFO
, "Package: %d, Valid Core : %d\n", Index
, ValidCoreCountPerPackage
[Index
]));
238 CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
239 ASSERT (CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
!= NULL
);
240 CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
241 ASSERT (CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
!= NULL
);
245 Worker function to do OR operation on CPU feature supported bits mask buffer.
247 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
248 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
252 IN UINT8
*SupportedFeatureMask
,
253 IN UINT8
*OrFeatureBitMask
261 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
262 Data1
= SupportedFeatureMask
;
263 Data2
= OrFeatureBitMask
;
264 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
265 *(Data1
++) |= *(Data2
++);
270 Worker function to do AND operation on CPU feature supported bits mask buffer.
272 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
273 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
277 IN UINT8
*SupportedFeatureMask
,
278 IN CONST UINT8
*AndFeatureBitMask
286 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
287 Data1
= SupportedFeatureMask
;
288 Data2
= AndFeatureBitMask
;
289 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
290 *(Data1
++) &= *(Data2
++);
295 Worker function to clean bit operation on CPU feature supported bits mask buffer.
297 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
298 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
301 SupportedMaskCleanBit (
302 IN UINT8
*SupportedFeatureMask
,
303 IN UINT8
*AndFeatureBitMask
311 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
312 Data1
= SupportedFeatureMask
;
313 Data2
= AndFeatureBitMask
;
314 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
315 *(Data1
++) &= ~(*(Data2
++));
320 Worker function to check if the compared CPU feature set in the CPU feature
321 supported bits mask buffer.
323 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
324 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
326 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
328 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
333 IN UINT8
*SupportedFeatureMask
,
334 IN UINT8
*ComparedFeatureBitMask
342 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
344 Data1
= SupportedFeatureMask
;
345 Data2
= ComparedFeatureBitMask
;
346 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
347 if (((*(Data1
++)) & (*(Data2
++))) != 0) {
355 Collects processor data for calling processor.
357 @param[in,out] Buffer The pointer to private data buffer.
361 CollectProcessorData (
365 UINTN ProcessorNumber
;
366 CPU_FEATURES_ENTRY
*CpuFeature
;
367 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
369 CPU_FEATURES_DATA
*CpuFeaturesData
;
371 CpuFeaturesData
= (CPU_FEATURES_DATA
*)Buffer
;
372 ProcessorNumber
= GetProcessorIndex (CpuFeaturesData
);
373 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
375 // collect processor information
377 FillProcessorInfo (CpuInfo
);
378 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
379 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
380 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
381 if (CpuFeature
->SupportFunc
== NULL
) {
383 // If SupportFunc is NULL, then the feature is supported.
386 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
387 CpuFeature
->FeatureMask
389 } else if (CpuFeature
->SupportFunc (ProcessorNumber
, CpuInfo
, CpuFeature
->ConfigData
)) {
391 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
392 CpuFeature
->FeatureMask
395 Entry
= Entry
->ForwardLink
;
400 Dump the contents of a CPU register table.
402 @param[in] ProcessorNumber The index of the CPU to show the register table contents
404 @note This service could be called by BSP only.
407 DumpRegisterTableOnProcessor (
408 IN UINTN ProcessorNumber
411 CPU_FEATURES_DATA
*CpuFeaturesData
;
413 CPU_REGISTER_TABLE
*RegisterTable
;
414 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
415 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
416 UINT32 DebugPrintErrorLevel
;
418 DebugPrintErrorLevel
= (ProcessorNumber
== 0) ? DEBUG_INFO
: DEBUG_VERBOSE
;
419 CpuFeaturesData
= GetCpuFeaturesData ();
423 RegisterTable
= &CpuFeaturesData
->RegisterTable
[ProcessorNumber
];
424 DEBUG ((DebugPrintErrorLevel
, "RegisterTable->TableLength = %d\n", RegisterTable
->TableLength
));
426 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
428 for (FeatureIndex
= 0; FeatureIndex
< RegisterTable
->TableLength
; FeatureIndex
++) {
429 RegisterTableEntry
= &RegisterTableEntryHead
[FeatureIndex
];
430 switch (RegisterTableEntry
->RegisterType
) {
433 DebugPrintErrorLevel
,
434 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
437 RegisterTableEntry
->Index
,
438 RegisterTableEntry
->ValidBitStart
,
439 RegisterTableEntry
->ValidBitLength
,
440 RegisterTableEntry
->Value
443 case ControlRegister
:
445 DebugPrintErrorLevel
,
446 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
449 RegisterTableEntry
->Index
,
450 RegisterTableEntry
->ValidBitStart
,
451 RegisterTableEntry
->ValidBitLength
,
452 RegisterTableEntry
->Value
457 DebugPrintErrorLevel
,
458 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
461 RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32),
462 RegisterTableEntry
->ValidBitStart
,
463 RegisterTableEntry
->ValidBitLength
,
464 RegisterTableEntry
->Value
469 DebugPrintErrorLevel
,
470 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
473 RegisterTableEntry
->Index
,
474 RegisterTableEntry
->ValidBitStart
,
475 RegisterTableEntry
->ValidBitLength
,
476 RegisterTableEntry
->Value
481 DebugPrintErrorLevel
,
482 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
485 mDependTypeStr
[MIN ((UINT32
)RegisterTableEntry
->Value
, InvalidDepType
)]
496 Get the biggest dependence type.
497 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
499 @param[in] BeforeDep Before dependence type.
500 @param[in] AfterDep After dependence type.
501 @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
502 @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
504 @retval Return the biggest dependence type.
506 CPU_FEATURE_DEPENDENCE_TYPE
508 IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
,
509 IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep
,
510 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
,
511 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
514 CPU_FEATURE_DEPENDENCE_TYPE Bigger
;
516 Bigger
= MAX (BeforeDep
, AfterDep
);
517 Bigger
= MAX (Bigger
, NoneNeibBeforeDep
);
518 return MAX(Bigger
, NoneNeibAfterDep
);
522 Analysis register CPU features on each processor and save CPU setting in CPU register table.
524 @param[in] NumberOfCpus Number of processor in system
528 AnalysisProcessorFeatures (
529 IN UINTN NumberOfCpus
533 UINTN ProcessorNumber
;
534 CPU_FEATURES_ENTRY
*CpuFeature
;
535 CPU_FEATURES_ENTRY
*CpuFeatureInOrder
;
536 CPU_FEATURES_INIT_ORDER
*CpuInitOrder
;
537 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
539 CPU_FEATURES_DATA
*CpuFeaturesData
;
540 LIST_ENTRY
*NextEntry
;
541 CPU_FEATURES_ENTRY
*NextCpuFeatureInOrder
;
543 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
;
544 CPU_FEATURE_DEPENDENCE_TYPE AfterDep
;
545 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
;
546 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
;
548 CpuFeaturesData
= GetCpuFeaturesData ();
549 CpuFeaturesData
->CapabilityPcd
= AllocatePool (CpuFeaturesData
->BitMaskSize
);
550 ASSERT (CpuFeaturesData
->CapabilityPcd
!= NULL
);
551 SetMem (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
, 0xFF);
552 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
553 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
555 // Calculate the last capability on all processors
557 SupportedMaskAnd (CpuFeaturesData
->CapabilityPcd
, CpuInitOrder
->FeaturesSupportedMask
);
560 // Calculate the last setting
562 CpuFeaturesData
->SettingPcd
= AllocateCopyPool (CpuFeaturesData
->BitMaskSize
, CpuFeaturesData
->CapabilityPcd
);
563 ASSERT (CpuFeaturesData
->SettingPcd
!= NULL
);
564 SupportedMaskAnd (CpuFeaturesData
->SettingPcd
, PcdGetPtr (PcdCpuFeaturesSetting
));
567 // Dump the last CPU feature list
570 DEBUG ((DEBUG_INFO
, "Last CPU features list...\n"));
571 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
572 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
573 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
574 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
575 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
576 DEBUG ((DEBUG_INFO
, "[Enable ] "));
578 DEBUG ((DEBUG_INFO
, "[Disable ] "));
581 DEBUG ((DEBUG_INFO
, "[Unsupport] "));
583 DumpCpuFeature (CpuFeature
);
584 Entry
= Entry
->ForwardLink
;
586 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesCapability:\n"));
587 DumpCpuFeatureMask (CpuFeaturesData
->CapabilityPcd
);
588 DEBUG ((DEBUG_INFO
, "Origin PcdCpuFeaturesSetting:\n"));
589 DumpCpuFeatureMask (PcdGetPtr (PcdCpuFeaturesSetting
));
590 DEBUG ((DEBUG_INFO
, "Final PcdCpuFeaturesSetting:\n"));
591 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
595 // Save PCDs and display CPU PCDs
597 SetCapabilityPcd (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
);
598 SetSettingPcd (CpuFeaturesData
->SettingPcd
);
600 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
601 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
602 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
603 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
605 // Insert each feature into processor's order list
607 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
608 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
609 CpuFeatureInOrder
= AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY
), CpuFeature
);
610 ASSERT (CpuFeatureInOrder
!= NULL
);
611 InsertTailList (&CpuInitOrder
->OrderList
, &CpuFeatureInOrder
->Link
);
613 Entry
= Entry
->ForwardLink
;
616 // Go through ordered feature list to initialize CPU features
618 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
619 Entry
= GetFirstNode (&CpuInitOrder
->OrderList
);
620 while (!IsNull (&CpuInitOrder
->OrderList
, Entry
)) {
621 CpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
624 if (IsBitMaskMatch (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
625 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, TRUE
);
626 if (EFI_ERROR (Status
)) {
628 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
630 SupportedMaskCleanBit (CpuFeaturesData
->SettingPcd
, CpuFeatureInOrder
->FeatureMask
);
631 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
632 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
634 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Mask = "));
635 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
641 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, FALSE
);
642 if (EFI_ERROR (Status
)) {
643 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
644 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
646 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Mask = "));
647 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
655 NextEntry
= Entry
->ForwardLink
;
656 if (!IsNull (&CpuInitOrder
->OrderList
, NextEntry
)) {
657 NextCpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (NextEntry
);
660 // If feature has dependence with the next feature (ONLY care core/package dependency).
661 // and feature initialize succeed, add sync semaphere here.
663 BeforeDep
= DetectFeatureScope (CpuFeatureInOrder
, TRUE
, NextCpuFeatureInOrder
->FeatureMask
);
664 AfterDep
= DetectFeatureScope (NextCpuFeatureInOrder
, FALSE
, CpuFeatureInOrder
->FeatureMask
);
666 // Check whether next feature has After type dependence with not neighborhood CPU
667 // Features in former CPU features.
669 NoneNeibAfterDep
= DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder
, FALSE
, &CpuInitOrder
->OrderList
);
671 BeforeDep
= NoneDepType
;
672 AfterDep
= NoneDepType
;
673 NoneNeibAfterDep
= NoneDepType
;
676 // Check whether current feature has Before type dependence with none neighborhood
677 // CPU features in after Cpu features.
679 NoneNeibBeforeDep
= DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder
, TRUE
, &CpuInitOrder
->OrderList
);
682 // Get the biggest dependence and add semaphore for it.
683 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
685 BeforeDep
= BiggestDep(BeforeDep
, AfterDep
, NoneNeibBeforeDep
, NoneNeibAfterDep
);
686 if (BeforeDep
> ThreadDepType
) {
687 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber
, Semaphore
, 0, BeforeDep
);
691 Entry
= Entry
->ForwardLink
;
695 // Dump PcdCpuFeaturesSetting again because this value maybe updated
696 // again during initialize the features.
698 DEBUG ((DEBUG_INFO
, "Dump final value for PcdCpuFeaturesSetting:\n"));
699 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
702 // Dump the RegisterTable
704 DumpRegisterTableOnProcessor (ProcessorNumber
);
709 Increment semaphore by 1.
711 @param Sem IN: 32-bit unsigned integer
715 LibReleaseSemaphore (
716 IN OUT
volatile UINT32
*Sem
719 InterlockedIncrement (Sem
);
723 Decrement the semaphore by 1 if it is not zero.
725 Performs an atomic decrement operation for semaphore.
726 The compare exchange operation must be performed using
729 @param Sem IN: 32-bit unsigned integer
733 LibWaitForSemaphore (
734 IN OUT
volatile UINT32
*Sem
741 } while (Value
== 0 ||
742 InterlockedCompareExchange32 (
750 Initialize the CPU registers from a register table.
752 @param[in] RegisterTable The register table for this AP.
753 @param[in] ApLocation AP location info for this ap.
754 @param[in] CpuStatus CPU status info for this CPU.
755 @param[in] CpuFlags Flags data structure used when program the register.
757 @note This service could be called by BSP/APs.
760 ProgramProcessorRegister (
761 IN CPU_REGISTER_TABLE
*RegisterTable
,
762 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
763 IN CPU_STATUS_INFORMATION
*CpuStatus
,
764 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
767 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
770 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
771 volatile UINT32
*SemaphorePtr
;
773 UINT32 PackageThreadsCount
;
774 UINT32 CurrentThread
;
775 UINTN ProcessorIndex
;
777 UINTN ValidThreadCount
;
778 UINT32
*ValidCoreCountPerPackage
;
781 // Traverse Register Table of this logical processor
783 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
785 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
787 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
791 // Wait for the AP to release the MSR spin lock.
793 while (!AcquireSpinLockOrFail (&CpuFlags
->ConsoleLogLock
)) {
796 ThreadIndex
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
+
797 ApLocation
->Core
* CpuStatus
->MaxThreadCount
+
801 "Processor = %08lu, Index %08lu, Type = %s!\n",
804 mRegisterTypeStr
[MIN ((REGISTER_TYPE
)RegisterTableEntry
->RegisterType
, InvalidReg
)]
806 ReleaseSpinLock (&CpuFlags
->ConsoleLogLock
);
810 // Check the type of specified register
812 switch (RegisterTableEntry
->RegisterType
) {
814 // The specified register is Control Register
816 case ControlRegister
:
817 switch (RegisterTableEntry
->Index
) {
819 Value
= AsmReadCr0 ();
820 Value
= (UINTN
) BitFieldWrite64 (
822 RegisterTableEntry
->ValidBitStart
,
823 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
824 RegisterTableEntry
->Value
829 Value
= AsmReadCr2 ();
830 Value
= (UINTN
) BitFieldWrite64 (
832 RegisterTableEntry
->ValidBitStart
,
833 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
834 RegisterTableEntry
->Value
839 Value
= AsmReadCr3 ();
840 Value
= (UINTN
) BitFieldWrite64 (
842 RegisterTableEntry
->ValidBitStart
,
843 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
844 RegisterTableEntry
->Value
849 Value
= AsmReadCr4 ();
850 Value
= (UINTN
) BitFieldWrite64 (
852 RegisterTableEntry
->ValidBitStart
,
853 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
854 RegisterTableEntry
->Value
860 // Do we need to support CR8?
868 // The specified register is Model Specific Register
871 if (RegisterTableEntry
->ValidBitLength
>= 64) {
873 // If length is not less than 64 bits, then directly write without reading
876 RegisterTableEntry
->Index
,
877 RegisterTableEntry
->Value
881 // Set the bit section according to bit start and length
883 AsmMsrBitFieldWrite64 (
884 RegisterTableEntry
->Index
,
885 RegisterTableEntry
->ValidBitStart
,
886 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
887 RegisterTableEntry
->Value
892 // MemoryMapped operations
895 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
896 MmioBitFieldWrite32 (
897 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
898 RegisterTableEntry
->ValidBitStart
,
899 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
900 (UINT32
)RegisterTableEntry
->Value
902 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
905 // Enable or disable cache
909 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
911 if (RegisterTableEntry
->Value
== 0) {
919 // Semaphore works logic like below:
921 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
922 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
924 // All threads (T0...Tn) waits in P() line and continues running
930 // V(0...n) V(0...n) ... V(0...n)
931 // n * P(0) n * P(1) ... n * P(n)
933 switch (RegisterTableEntry
->Value
) {
935 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
937 // Get Offset info for the first thread in the core which current thread belongs to.
939 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
940 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
942 // First Notify all threads in current Core that this thread has ready.
944 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
945 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
948 // Second, check whether all valid threads in current core have ready.
950 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
951 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
956 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
957 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
959 // Get Offset info for the first thread in the package which current thread belongs to.
961 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
963 // Get the possible threads count for current package.
965 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
966 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
968 // Get the valid thread count for current package.
970 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
973 // Different packages may have different valid cores in them. If driver maintail clearly
974 // cores number in different packages, the logic will be much complicated.
975 // Here driver just simply records the max core number in all packages and use it as expect
976 // core number for all packages.
977 // In below two steps logic, first current thread will Release semaphore for each thread
978 // in current package. Maybe some threads are not valid in this package, but driver don't
979 // care. Second, driver will let current thread wait semaphore for all valid threads in
980 // current package. Because only the valid threads will do release semaphore for this
981 // thread, driver here only need to wait the valid thread count.
985 // First Notify ALL THREADS in current package that this thread has ready.
987 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
988 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
991 // Second, check whether VALID THREADS (not all threads) in current package have ready.
993 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
994 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
1010 Programs registers for the calling processor.
1012 @param[in,out] Buffer The pointer to private data buffer.
1017 SetProcessorRegister (
1021 CPU_FEATURES_DATA
*CpuFeaturesData
;
1022 CPU_REGISTER_TABLE
*RegisterTable
;
1023 CPU_REGISTER_TABLE
*RegisterTables
;
1027 ACPI_CPU_DATA
*AcpiCpuData
;
1029 CpuFeaturesData
= (CPU_FEATURES_DATA
*) Buffer
;
1030 AcpiCpuData
= CpuFeaturesData
->AcpiCpuData
;
1032 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
;
1034 InitApicId
= GetInitialApicId ();
1035 RegisterTable
= NULL
;
1036 ProcIndex
= (UINTN
)-1;
1037 for (Index
= 0; Index
< AcpiCpuData
->NumberOfCpus
; Index
++) {
1038 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
1039 RegisterTable
= &RegisterTables
[Index
];
1044 ASSERT (RegisterTable
!= NULL
);
1046 ProgramProcessorRegister (
1048 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
+ ProcIndex
,
1049 &AcpiCpuData
->CpuStatus
,
1050 &CpuFeaturesData
->CpuFlags
1055 Performs CPU features detection.
1057 This service will invoke MP service to check CPU features'
1058 capabilities on BSP/APs.
1060 @note This service could be called by BSP only.
1068 CPU_FEATURES_DATA
*CpuFeaturesData
;
1070 CpuFeaturesData
= GetCpuFeaturesData();
1072 CpuInitDataInitialize ();
1075 // Wakeup all APs for data collection.
1077 StartupAPsWorker (CollectProcessorData
, NULL
);
1080 // Collect data on BSP
1082 CollectProcessorData (CpuFeaturesData
);
1084 AnalysisProcessorFeatures (CpuFeaturesData
->NumberOfCpus
);