2 CPU Features Initialize functions.
4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
10 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
11 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
15 #include "RegisterCpuFeatures.h"
17 CHAR16
*mDependTypeStr
[] = {L
"None", L
"Thread", L
"Core", L
"Package", L
"Invalid" };
18 CHAR16
*mRegisterTypeStr
[] = {L
"MSR", L
"CR", L
"MMIO", L
"CACHE", L
"SEMAP", L
"INVALID" };
21 Worker function to save PcdCpuFeaturesCapability.
23 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
27 IN UINT8
*SupportedFeatureMask
33 BitMaskSize
= PcdGetSize (PcdCpuFeaturesCapability
);
34 Status
= PcdSetPtrS (PcdCpuFeaturesCapability
, &BitMaskSize
, SupportedFeatureMask
);
35 ASSERT_EFI_ERROR (Status
);
39 Worker function to save PcdCpuFeaturesSetting.
41 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
45 IN UINT8
*SupportedFeatureMask
51 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSetting
);
52 Status
= PcdSetPtrS (PcdCpuFeaturesSetting
, &BitMaskSize
, SupportedFeatureMask
);
53 ASSERT_EFI_ERROR (Status
);
57 Worker function to get PcdCpuFeaturesSupport.
59 @return The pointer to CPU feature bits mask buffer.
66 UINT8
*SupportBitMask
;
68 SupportBitMask
= AllocateCopyPool (
69 PcdGetSize (PcdCpuFeaturesSupport
),
70 PcdGetPtr (PcdCpuFeaturesSupport
)
72 ASSERT (SupportBitMask
!= NULL
);
74 return SupportBitMask
;
78 Worker function to get PcdCpuFeaturesUserConfiguration.
80 @return The pointer to CPU feature bits mask buffer.
87 UINT8
*SupportBitMask
;
89 SupportBitMask
= AllocateCopyPool (
90 PcdGetSize (PcdCpuFeaturesUserConfiguration
),
91 PcdGetPtr (PcdCpuFeaturesUserConfiguration
)
93 ASSERT (SupportBitMask
!= NULL
);
95 return SupportBitMask
;
99 Collects CPU type and feature information.
101 @param[in, out] CpuInfo The pointer to CPU feature information
105 IN OUT REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
108 CPUID_VERSION_INFO_EAX Eax
;
109 CPUID_VERSION_INFO_ECX Ecx
;
110 CPUID_VERSION_INFO_EDX Edx
;
111 UINT32 DisplayedFamily
;
112 UINT32 DisplayedModel
;
114 AsmCpuid (CPUID_VERSION_INFO
, &Eax
.Uint32
, NULL
, &Ecx
.Uint32
, &Edx
.Uint32
);
116 DisplayedFamily
= Eax
.Bits
.FamilyId
;
117 if (Eax
.Bits
.FamilyId
== 0x0F) {
118 DisplayedFamily
|= (Eax
.Bits
.ExtendedFamilyId
<< 4);
121 DisplayedModel
= Eax
.Bits
.Model
;
122 if (Eax
.Bits
.FamilyId
== 0x06 || Eax
.Bits
.FamilyId
== 0x0f) {
123 DisplayedModel
|= (Eax
.Bits
.ExtendedModelId
<< 4);
126 CpuInfo
->DisplayFamily
= DisplayedFamily
;
127 CpuInfo
->DisplayModel
= DisplayedModel
;
128 CpuInfo
->SteppingId
= Eax
.Bits
.SteppingId
;
129 CpuInfo
->ProcessorType
= Eax
.Bits
.ProcessorType
;
130 CpuInfo
->CpuIdVersionInfoEcx
.Uint32
= Ecx
.Uint32
;
131 CpuInfo
->CpuIdVersionInfoEdx
.Uint32
= Edx
.Uint32
;
135 Prepares for private data used for CPU features.
137 @param[in] NumberOfCpus Number of processor in system
140 CpuInitDataInitialize (
141 IN UINTN NumberOfCpus
145 UINTN ProcessorNumber
;
146 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer
;
147 CPU_FEATURES_ENTRY
*CpuFeature
;
148 CPU_FEATURES_INIT_ORDER
*InitOrder
;
149 CPU_FEATURES_DATA
*CpuFeaturesData
;
154 EFI_CPU_PHYSICAL_LOCATION
*Location
;
155 BOOLEAN
*CoresVisited
;
157 ACPI_CPU_DATA
*AcpiCpuData
;
158 CPU_STATUS_INFORMATION
*CpuStatus
;
159 UINT32
*ValidCoreCountPerPackage
;
165 CpuFeaturesData
= GetCpuFeaturesData ();
166 CpuFeaturesData
->InitOrder
= AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER
) * NumberOfCpus
);
167 ASSERT (CpuFeaturesData
->InitOrder
!= NULL
);
170 // Collect CPU Features information
172 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
173 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
174 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
175 ASSERT (CpuFeature
->InitializeFunc
!= NULL
);
176 if (CpuFeature
->GetConfigDataFunc
!= NULL
) {
177 CpuFeature
->ConfigData
= CpuFeature
->GetConfigDataFunc (NumberOfCpus
);
179 Entry
= Entry
->ForwardLink
;
182 CpuFeaturesData
->NumberOfCpus
= (UINT32
) NumberOfCpus
;
184 AcpiCpuData
= GetAcpiCpuData ();
185 ASSERT (AcpiCpuData
!= NULL
);
186 CpuFeaturesData
->AcpiCpuData
= AcpiCpuData
;
188 CpuStatus
= &AcpiCpuData
->CpuStatus
;
189 Location
= AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION
) * NumberOfCpus
);
190 ASSERT (Location
!= NULL
);
191 AcpiCpuData
->ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Location
;
193 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
194 InitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
195 InitOrder
->FeaturesSupportedMask
= AllocateZeroPool (CpuFeaturesData
->BitMaskSize
);
196 ASSERT (InitOrder
->FeaturesSupportedMask
!= NULL
);
197 InitializeListHead (&InitOrder
->OrderList
);
198 Status
= GetProcessorInformation (ProcessorNumber
, &ProcessorInfoBuffer
);
199 ASSERT_EFI_ERROR (Status
);
201 &InitOrder
->CpuInfo
.ProcessorInfo
,
202 &ProcessorInfoBuffer
,
203 sizeof (EFI_PROCESSOR_INFORMATION
)
206 &Location
[ProcessorNumber
],
207 &ProcessorInfoBuffer
.Location
,
208 sizeof (EFI_CPU_PHYSICAL_LOCATION
)
212 // Collect CPU package count info.
214 if (Package
< ProcessorInfoBuffer
.Location
.Package
) {
215 Package
= ProcessorInfoBuffer
.Location
.Package
;
218 // Collect CPU max core count info.
220 if (Core
< ProcessorInfoBuffer
.Location
.Core
) {
221 Core
= ProcessorInfoBuffer
.Location
.Core
;
224 // Collect CPU max thread count info.
226 if (Thread
< ProcessorInfoBuffer
.Location
.Thread
) {
227 Thread
= ProcessorInfoBuffer
.Location
.Thread
;
230 CpuStatus
->PackageCount
= Package
+ 1;
231 CpuStatus
->MaxCoreCount
= Core
+ 1;
232 CpuStatus
->MaxThreadCount
= Thread
+ 1;
233 DEBUG ((DEBUG_INFO
, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
234 CpuStatus
->PackageCount
,
235 CpuStatus
->MaxCoreCount
,
236 CpuStatus
->MaxThreadCount
));
239 // Collect valid core count in each package because not all cores are valid.
241 ValidCoreCountPerPackage
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
);
242 ASSERT (ValidCoreCountPerPackage
!= 0);
243 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ValidCoreCountPerPackage
;
244 CoresVisited
= AllocatePool (sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
245 ASSERT (CoresVisited
!= NULL
);
247 for (Index
= 0; Index
< CpuStatus
->PackageCount
; Index
++ ) {
248 ZeroMem (CoresVisited
, sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
250 // Collect valid cores in Current package.
252 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
253 Location
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
.ProcessorInfo
.Location
;
254 if (Location
->Package
== Index
&& !CoresVisited
[Location
->Core
] ) {
256 // The ValidCores position for Location->Core is valid.
257 // The possible values in ValidCores[Index] are 0 or 1.
258 // FALSE means no valid threads in this Core.
259 // TRUE means have valid threads in this core, no matter the thead count is 1 or more.
261 CoresVisited
[Location
->Core
] = TRUE
;
262 ValidCoreCountPerPackage
[Index
]++;
266 FreePool (CoresVisited
);
268 for (Index
= 0; Index
<= Package
; Index
++) {
269 DEBUG ((DEBUG_INFO
, "Package: %d, Valid Core : %d\n", Index
, ValidCoreCountPerPackage
[Index
]));
272 CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
273 ASSERT (CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
!= NULL
);
274 CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
275 ASSERT (CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
!= NULL
);
278 // Get support and configuration PCDs
280 CpuFeaturesData
->SupportPcd
= GetSupportPcd ();
281 CpuFeaturesData
->ConfigurationPcd
= GetConfigurationPcd ();
285 Worker function to do OR operation on CPU feature supported bits mask buffer.
287 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
288 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
292 IN UINT8
*SupportedFeatureMask
,
293 IN UINT8
*OrFeatureBitMask
301 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
302 Data1
= SupportedFeatureMask
;
303 Data2
= OrFeatureBitMask
;
304 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
305 *(Data1
++) |= *(Data2
++);
310 Worker function to do AND operation on CPU feature supported bits mask buffer.
312 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
313 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
317 IN UINT8
*SupportedFeatureMask
,
318 IN UINT8
*AndFeatureBitMask
326 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
327 Data1
= SupportedFeatureMask
;
328 Data2
= AndFeatureBitMask
;
329 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
330 *(Data1
++) &= *(Data2
++);
335 Worker function to clean bit operation on CPU feature supported bits mask buffer.
337 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
338 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
341 SupportedMaskCleanBit (
342 IN UINT8
*SupportedFeatureMask
,
343 IN UINT8
*AndFeatureBitMask
351 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
352 Data1
= SupportedFeatureMask
;
353 Data2
= AndFeatureBitMask
;
354 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
355 *(Data1
++) &= ~(*(Data2
++));
360 Worker function to check if the compared CPU feature set in the CPU feature
361 supported bits mask buffer.
363 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
364 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
366 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
368 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
373 IN UINT8
*SupportedFeatureMask
,
374 IN UINT8
*ComparedFeatureBitMask
382 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
384 Data1
= SupportedFeatureMask
;
385 Data2
= ComparedFeatureBitMask
;
386 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
387 if (((*(Data1
++)) & (*(Data2
++))) != 0) {
395 Collects processor data for calling processor.
397 @param[in,out] Buffer The pointer to private data buffer.
401 CollectProcessorData (
405 UINTN ProcessorNumber
;
406 CPU_FEATURES_ENTRY
*CpuFeature
;
407 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
409 CPU_FEATURES_DATA
*CpuFeaturesData
;
411 CpuFeaturesData
= (CPU_FEATURES_DATA
*)Buffer
;
412 ProcessorNumber
= GetProcessorIndex ();
413 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
415 // collect processor information
417 FillProcessorInfo (CpuInfo
);
418 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
419 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
420 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
421 if (IsBitMaskMatch (CpuFeaturesData
->SupportPcd
, CpuFeature
->FeatureMask
)) {
422 if (CpuFeature
->SupportFunc
== NULL
) {
424 // If SupportFunc is NULL, then the feature is supported.
427 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
428 CpuFeature
->FeatureMask
430 } else if (CpuFeature
->SupportFunc (ProcessorNumber
, CpuInfo
, CpuFeature
->ConfigData
)) {
432 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
433 CpuFeature
->FeatureMask
437 Entry
= Entry
->ForwardLink
;
442 Dump the contents of a CPU register table.
444 @param[in] ProcessorNumber The index of the CPU to show the register table contents
446 @note This service could be called by BSP only.
449 DumpRegisterTableOnProcessor (
450 IN UINTN ProcessorNumber
453 CPU_FEATURES_DATA
*CpuFeaturesData
;
455 CPU_REGISTER_TABLE
*RegisterTable
;
456 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
457 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
458 UINT32 DebugPrintErrorLevel
;
460 DebugPrintErrorLevel
= (ProcessorNumber
== 0) ? DEBUG_INFO
: DEBUG_VERBOSE
;
461 CpuFeaturesData
= GetCpuFeaturesData ();
465 RegisterTable
= &CpuFeaturesData
->RegisterTable
[ProcessorNumber
];
466 DEBUG ((DebugPrintErrorLevel
, "RegisterTable->TableLength = %d\n", RegisterTable
->TableLength
));
468 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
470 for (FeatureIndex
= 0; FeatureIndex
< RegisterTable
->TableLength
; FeatureIndex
++) {
471 RegisterTableEntry
= &RegisterTableEntryHead
[FeatureIndex
];
472 switch (RegisterTableEntry
->RegisterType
) {
475 DebugPrintErrorLevel
,
476 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
479 RegisterTableEntry
->Index
,
480 RegisterTableEntry
->ValidBitStart
,
481 RegisterTableEntry
->ValidBitLength
,
482 RegisterTableEntry
->Value
485 case ControlRegister
:
487 DebugPrintErrorLevel
,
488 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
491 RegisterTableEntry
->Index
,
492 RegisterTableEntry
->ValidBitStart
,
493 RegisterTableEntry
->ValidBitLength
,
494 RegisterTableEntry
->Value
499 DebugPrintErrorLevel
,
500 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
503 RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32),
504 RegisterTableEntry
->ValidBitStart
,
505 RegisterTableEntry
->ValidBitLength
,
506 RegisterTableEntry
->Value
511 DebugPrintErrorLevel
,
512 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
515 RegisterTableEntry
->Index
,
516 RegisterTableEntry
->ValidBitStart
,
517 RegisterTableEntry
->ValidBitLength
,
518 RegisterTableEntry
->Value
523 DebugPrintErrorLevel
,
524 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
527 mDependTypeStr
[MIN ((UINT32
)RegisterTableEntry
->Value
, InvalidDepType
)]
538 Get the biggest dependence type.
539 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
541 @param[in] BeforeDep Before dependence type.
542 @param[in] AfterDep After dependence type.
543 @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
544 @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
546 @retval Return the biggest dependence type.
548 CPU_FEATURE_DEPENDENCE_TYPE
550 IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
,
551 IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep
,
552 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
,
553 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
556 CPU_FEATURE_DEPENDENCE_TYPE Bigger
;
558 Bigger
= MAX (BeforeDep
, AfterDep
);
559 Bigger
= MAX (Bigger
, NoneNeibBeforeDep
);
560 return MAX(Bigger
, NoneNeibAfterDep
);
564 Analysis register CPU features on each processor and save CPU setting in CPU register table.
566 @param[in] NumberOfCpus Number of processor in system
570 AnalysisProcessorFeatures (
571 IN UINTN NumberOfCpus
575 UINTN ProcessorNumber
;
576 CPU_FEATURES_ENTRY
*CpuFeature
;
577 CPU_FEATURES_ENTRY
*CpuFeatureInOrder
;
578 CPU_FEATURES_INIT_ORDER
*CpuInitOrder
;
579 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
581 CPU_FEATURES_DATA
*CpuFeaturesData
;
582 LIST_ENTRY
*NextEntry
;
583 CPU_FEATURES_ENTRY
*NextCpuFeatureInOrder
;
585 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
;
586 CPU_FEATURE_DEPENDENCE_TYPE AfterDep
;
587 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
;
588 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
;
590 CpuFeaturesData
= GetCpuFeaturesData ();
591 CpuFeaturesData
->CapabilityPcd
= AllocatePool (CpuFeaturesData
->BitMaskSize
);
592 ASSERT (CpuFeaturesData
->CapabilityPcd
!= NULL
);
593 SetMem (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
, 0xFF);
594 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
595 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
597 // Calculate the last capability on all processors
599 SupportedMaskAnd (CpuFeaturesData
->CapabilityPcd
, CpuInitOrder
->FeaturesSupportedMask
);
602 // Calculate the last setting
605 CpuFeaturesData
->SettingPcd
= AllocateCopyPool (CpuFeaturesData
->BitMaskSize
, CpuFeaturesData
->CapabilityPcd
);
606 ASSERT (CpuFeaturesData
->SettingPcd
!= NULL
);
607 SupportedMaskAnd (CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->ConfigurationPcd
);
610 // Save PCDs and display CPU PCDs
612 SetCapabilityPcd (CpuFeaturesData
->CapabilityPcd
);
613 SetSettingPcd (CpuFeaturesData
->SettingPcd
);
616 // Dump the last CPU feature list
619 DEBUG ((DEBUG_INFO
, "Last CPU features list...\n"));
620 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
621 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
622 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
623 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
624 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
625 DEBUG ((DEBUG_INFO
, "[Enable ] "));
627 DEBUG ((DEBUG_INFO
, "[Disable ] "));
630 DEBUG ((DEBUG_INFO
, "[Unsupport] "));
632 DumpCpuFeature (CpuFeature
);
633 Entry
= Entry
->ForwardLink
;
635 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesSupport:\n"));
636 DumpCpuFeatureMask (CpuFeaturesData
->SupportPcd
);
637 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesUserConfiguration:\n"));
638 DumpCpuFeatureMask (CpuFeaturesData
->ConfigurationPcd
);
639 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesCapability:\n"));
640 DumpCpuFeatureMask (CpuFeaturesData
->CapabilityPcd
);
641 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesSetting:\n"));
642 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
645 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
646 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
647 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
648 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
650 // Insert each feature into processor's order list
652 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
653 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
654 CpuFeatureInOrder
= AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY
), CpuFeature
);
655 ASSERT (CpuFeatureInOrder
!= NULL
);
656 InsertTailList (&CpuInitOrder
->OrderList
, &CpuFeatureInOrder
->Link
);
658 Entry
= Entry
->ForwardLink
;
661 // Go through ordered feature list to initialize CPU features
663 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
664 Entry
= GetFirstNode (&CpuInitOrder
->OrderList
);
665 while (!IsNull (&CpuInitOrder
->OrderList
, Entry
)) {
666 CpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
669 if (IsBitMaskMatch (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
670 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, TRUE
);
671 if (EFI_ERROR (Status
)) {
673 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
675 SupportedMaskCleanBit (CpuFeaturesData
->SettingPcd
, CpuFeatureInOrder
->FeatureMask
);
676 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
677 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
679 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Mask = "));
680 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
686 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, FALSE
);
687 if (EFI_ERROR (Status
)) {
688 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
689 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
691 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Mask = "));
692 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
700 NextEntry
= Entry
->ForwardLink
;
701 if (!IsNull (&CpuInitOrder
->OrderList
, NextEntry
)) {
702 NextCpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (NextEntry
);
705 // If feature has dependence with the next feature (ONLY care core/package dependency).
706 // and feature initialize succeed, add sync semaphere here.
708 BeforeDep
= DetectFeatureScope (CpuFeatureInOrder
, TRUE
, NextCpuFeatureInOrder
->FeatureMask
);
709 AfterDep
= DetectFeatureScope (NextCpuFeatureInOrder
, FALSE
, CpuFeatureInOrder
->FeatureMask
);
711 // Check whether next feature has After type dependence with not neighborhood CPU
712 // Features in former CPU features.
714 NoneNeibAfterDep
= DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder
, FALSE
, &CpuInitOrder
->OrderList
);
716 BeforeDep
= NoneDepType
;
717 AfterDep
= NoneDepType
;
718 NoneNeibAfterDep
= NoneDepType
;
721 // Check whether current feature has Before type dependence with none neighborhood
722 // CPU features in after Cpu features.
724 NoneNeibBeforeDep
= DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder
, TRUE
, &CpuInitOrder
->OrderList
);
727 // Get the biggest dependence and add semaphore for it.
728 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
730 BeforeDep
= BiggestDep(BeforeDep
, AfterDep
, NoneNeibBeforeDep
, NoneNeibAfterDep
);
731 if (BeforeDep
> ThreadDepType
) {
732 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber
, Semaphore
, 0, BeforeDep
);
736 Entry
= Entry
->ForwardLink
;
740 // Dump PcdCpuFeaturesSetting again because this value maybe updated
741 // again during initialize the features.
743 DEBUG ((DEBUG_INFO
, "Dump final value for PcdCpuFeaturesSetting:\n"));
744 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
747 // Dump the RegisterTable
749 DumpRegisterTableOnProcessor (ProcessorNumber
);
754 Increment semaphore by 1.
756 @param Sem IN: 32-bit unsigned integer
760 LibReleaseSemaphore (
761 IN OUT
volatile UINT32
*Sem
764 InterlockedIncrement (Sem
);
768 Decrement the semaphore by 1 if it is not zero.
770 Performs an atomic decrement operation for semaphore.
771 The compare exchange operation must be performed using
774 @param Sem IN: 32-bit unsigned integer
778 LibWaitForSemaphore (
779 IN OUT
volatile UINT32
*Sem
786 } while (Value
== 0 ||
787 InterlockedCompareExchange32 (
795 Initialize the CPU registers from a register table.
797 @param[in] RegisterTable The register table for this AP.
798 @param[in] ApLocation AP location info for this ap.
799 @param[in] CpuStatus CPU status info for this CPU.
800 @param[in] CpuFlags Flags data structure used when program the register.
802 @note This service could be called by BSP/APs.
805 ProgramProcessorRegister (
806 IN CPU_REGISTER_TABLE
*RegisterTable
,
807 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
808 IN CPU_STATUS_INFORMATION
*CpuStatus
,
809 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
812 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
815 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
816 volatile UINT32
*SemaphorePtr
;
818 UINT32 PackageThreadsCount
;
819 UINT32 CurrentThread
;
820 UINTN ProcessorIndex
;
822 UINTN ValidThreadCount
;
823 UINT32
*ValidCoreCountPerPackage
;
826 // Traverse Register Table of this logical processor
828 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
830 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
832 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
835 AcquireSpinLock (&CpuFlags
->ConsoleLogLock
);
836 ThreadIndex
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
+
837 ApLocation
->Core
* CpuStatus
->MaxThreadCount
+
841 "Processor = %08lu, Index %08lu, Type = %s!\n",
844 mRegisterTypeStr
[MIN ((REGISTER_TYPE
)RegisterTableEntry
->RegisterType
, InvalidReg
)]
846 ReleaseSpinLock (&CpuFlags
->ConsoleLogLock
);
850 // Check the type of specified register
852 switch (RegisterTableEntry
->RegisterType
) {
854 // The specified register is Control Register
856 case ControlRegister
:
857 switch (RegisterTableEntry
->Index
) {
859 Value
= AsmReadCr0 ();
860 Value
= (UINTN
) BitFieldWrite64 (
862 RegisterTableEntry
->ValidBitStart
,
863 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
864 RegisterTableEntry
->Value
869 Value
= AsmReadCr2 ();
870 Value
= (UINTN
) BitFieldWrite64 (
872 RegisterTableEntry
->ValidBitStart
,
873 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
874 RegisterTableEntry
->Value
879 Value
= AsmReadCr3 ();
880 Value
= (UINTN
) BitFieldWrite64 (
882 RegisterTableEntry
->ValidBitStart
,
883 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
884 RegisterTableEntry
->Value
889 Value
= AsmReadCr4 ();
890 Value
= (UINTN
) BitFieldWrite64 (
892 RegisterTableEntry
->ValidBitStart
,
893 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
894 RegisterTableEntry
->Value
900 // Do we need to support CR8?
908 // The specified register is Model Specific Register
911 if (RegisterTableEntry
->ValidBitLength
>= 64) {
913 // If length is not less than 64 bits, then directly write without reading
916 RegisterTableEntry
->Index
,
917 RegisterTableEntry
->Value
921 // Set the bit section according to bit start and length
923 AsmMsrBitFieldWrite64 (
924 RegisterTableEntry
->Index
,
925 RegisterTableEntry
->ValidBitStart
,
926 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
927 RegisterTableEntry
->Value
932 // MemoryMapped operations
935 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
936 MmioBitFieldWrite32 (
937 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
938 RegisterTableEntry
->ValidBitStart
,
939 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
940 (UINT32
)RegisterTableEntry
->Value
942 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
945 // Enable or disable cache
949 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
951 if (RegisterTableEntry
->Value
== 0) {
959 // Semaphore works logic like below:
961 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
962 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
964 // All threads (T0...Tn) waits in P() line and continues running
970 // V(0...n) V(0...n) ... V(0...n)
971 // n * P(0) n * P(1) ... n * P(n)
973 switch (RegisterTableEntry
->Value
) {
975 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
977 // Get Offset info for the first thread in the core which current thread belongs to.
979 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
980 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
982 // First Notify all threads in current Core that this thread has ready.
984 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
985 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
988 // Second, check whether all valid threads in current core have ready.
990 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
991 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
996 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
997 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
999 // Get Offset info for the first thread in the package which current thread belongs to.
1001 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
1003 // Get the possible threads count for current package.
1005 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
1006 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
1008 // Get the valid thread count for current package.
1010 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
1013 // Different packages may have different valid cores in them. If driver maintail clearly
1014 // cores number in different packages, the logic will be much complicated.
1015 // Here driver just simply records the max core number in all packages and use it as expect
1016 // core number for all packages.
1017 // In below two steps logic, first current thread will Release semaphore for each thread
1018 // in current package. Maybe some threads are not valid in this package, but driver don't
1019 // care. Second, driver will let current thread wait semaphore for all valid threads in
1020 // current package. Because only the valid threads will do release semaphore for this
1021 // thread, driver here only need to wait the valid thread count.
1025 // First Notify ALL THREADS in current package that this thread has ready.
1027 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
1028 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
1031 // Second, check whether VALID THREADS (not all threads) in current package have ready.
1033 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
1034 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
1050 Programs registers for the calling processor.
1052 @param[in,out] Buffer The pointer to private data buffer.
1057 SetProcessorRegister (
1061 CPU_FEATURES_DATA
*CpuFeaturesData
;
1062 CPU_REGISTER_TABLE
*RegisterTable
;
1063 CPU_REGISTER_TABLE
*RegisterTables
;
1067 ACPI_CPU_DATA
*AcpiCpuData
;
1069 CpuFeaturesData
= (CPU_FEATURES_DATA
*) Buffer
;
1070 AcpiCpuData
= CpuFeaturesData
->AcpiCpuData
;
1072 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
;
1074 InitApicId
= GetInitialApicId ();
1075 RegisterTable
= NULL
;
1076 ProcIndex
= (UINTN
)-1;
1077 for (Index
= 0; Index
< AcpiCpuData
->NumberOfCpus
; Index
++) {
1078 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
1079 RegisterTable
= &RegisterTables
[Index
];
1084 ASSERT (RegisterTable
!= NULL
);
1086 ProgramProcessorRegister (
1088 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
+ ProcIndex
,
1089 &AcpiCpuData
->CpuStatus
,
1090 &CpuFeaturesData
->CpuFlags
1095 Performs CPU features detection.
1097 This service will invoke MP service to check CPU features'
1098 capabilities on BSP/APs.
1100 @note This service could be called by BSP only.
1109 UINTN NumberOfEnabledProcessors
;
1110 CPU_FEATURES_DATA
*CpuFeaturesData
;
1112 CpuFeaturesData
= GetCpuFeaturesData();
1114 GetNumberOfProcessor (&NumberOfCpus
, &NumberOfEnabledProcessors
);
1116 CpuInitDataInitialize (NumberOfCpus
);
1119 // Wakeup all APs for data collection.
1121 StartupAPsWorker (CollectProcessorData
, NULL
);
1124 // Collect data on BSP
1126 CollectProcessorData (CpuFeaturesData
);
1128 AnalysisProcessorFeatures (NumberOfCpus
);