2 CPU Features Initialize functions.
4 Copyright (c) 2017 - 2019, 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.
139 CpuInitDataInitialize (
144 UINTN ProcessorNumber
;
145 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer
;
146 CPU_FEATURES_ENTRY
*CpuFeature
;
147 CPU_FEATURES_INIT_ORDER
*InitOrder
;
148 CPU_FEATURES_DATA
*CpuFeaturesData
;
153 EFI_CPU_PHYSICAL_LOCATION
*Location
;
154 BOOLEAN
*CoresVisited
;
156 ACPI_CPU_DATA
*AcpiCpuData
;
157 CPU_STATUS_INFORMATION
*CpuStatus
;
158 UINT32
*ValidCoreCountPerPackage
;
160 UINTN NumberOfEnabledProcessors
;
166 CpuFeaturesData
= GetCpuFeaturesData ();
169 // Initialize CpuFeaturesData->MpService as early as possile, so later function can use it.
171 CpuFeaturesData
->MpService
= GetMpService ();
173 GetNumberOfProcessor (&NumberOfCpus
, &NumberOfEnabledProcessors
);
175 CpuFeaturesData
->InitOrder
= AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER
) * NumberOfCpus
);
176 ASSERT (CpuFeaturesData
->InitOrder
!= NULL
);
179 // Collect CPU Features information
181 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
182 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
183 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
184 ASSERT (CpuFeature
->InitializeFunc
!= NULL
);
185 if (CpuFeature
->GetConfigDataFunc
!= NULL
) {
186 CpuFeature
->ConfigData
= CpuFeature
->GetConfigDataFunc (NumberOfCpus
);
188 Entry
= Entry
->ForwardLink
;
191 CpuFeaturesData
->NumberOfCpus
= (UINT32
) NumberOfCpus
;
193 AcpiCpuData
= GetAcpiCpuData ();
194 ASSERT (AcpiCpuData
!= NULL
);
195 CpuFeaturesData
->AcpiCpuData
= AcpiCpuData
;
197 CpuStatus
= &AcpiCpuData
->CpuStatus
;
198 Location
= AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION
) * NumberOfCpus
);
199 ASSERT (Location
!= NULL
);
200 AcpiCpuData
->ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Location
;
202 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
203 InitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
204 InitOrder
->FeaturesSupportedMask
= AllocateZeroPool (CpuFeaturesData
->BitMaskSize
);
205 ASSERT (InitOrder
->FeaturesSupportedMask
!= NULL
);
206 InitializeListHead (&InitOrder
->OrderList
);
207 Status
= GetProcessorInformation (ProcessorNumber
, &ProcessorInfoBuffer
);
208 ASSERT_EFI_ERROR (Status
);
210 &InitOrder
->CpuInfo
.ProcessorInfo
,
211 &ProcessorInfoBuffer
,
212 sizeof (EFI_PROCESSOR_INFORMATION
)
215 &Location
[ProcessorNumber
],
216 &ProcessorInfoBuffer
.Location
,
217 sizeof (EFI_CPU_PHYSICAL_LOCATION
)
221 // Collect CPU package count info.
223 if (Package
< ProcessorInfoBuffer
.Location
.Package
) {
224 Package
= ProcessorInfoBuffer
.Location
.Package
;
227 // Collect CPU max core count info.
229 if (Core
< ProcessorInfoBuffer
.Location
.Core
) {
230 Core
= ProcessorInfoBuffer
.Location
.Core
;
233 // Collect CPU max thread count info.
235 if (Thread
< ProcessorInfoBuffer
.Location
.Thread
) {
236 Thread
= ProcessorInfoBuffer
.Location
.Thread
;
239 CpuStatus
->PackageCount
= Package
+ 1;
240 CpuStatus
->MaxCoreCount
= Core
+ 1;
241 CpuStatus
->MaxThreadCount
= Thread
+ 1;
242 DEBUG ((DEBUG_INFO
, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
243 CpuStatus
->PackageCount
,
244 CpuStatus
->MaxCoreCount
,
245 CpuStatus
->MaxThreadCount
));
248 // Collect valid core count in each package because not all cores are valid.
250 ValidCoreCountPerPackage
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
);
251 ASSERT (ValidCoreCountPerPackage
!= 0);
252 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ValidCoreCountPerPackage
;
253 CoresVisited
= AllocatePool (sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
254 ASSERT (CoresVisited
!= NULL
);
256 for (Index
= 0; Index
< CpuStatus
->PackageCount
; Index
++ ) {
257 ZeroMem (CoresVisited
, sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
259 // Collect valid cores in Current package.
261 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
262 Location
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
.ProcessorInfo
.Location
;
263 if (Location
->Package
== Index
&& !CoresVisited
[Location
->Core
] ) {
265 // The ValidCores position for Location->Core is valid.
266 // The possible values in ValidCores[Index] are 0 or 1.
267 // FALSE means no valid threads in this Core.
268 // TRUE means have valid threads in this core, no matter the thead count is 1 or more.
270 CoresVisited
[Location
->Core
] = TRUE
;
271 ValidCoreCountPerPackage
[Index
]++;
275 FreePool (CoresVisited
);
277 for (Index
= 0; Index
<= Package
; Index
++) {
278 DEBUG ((DEBUG_INFO
, "Package: %d, Valid Core : %d\n", Index
, ValidCoreCountPerPackage
[Index
]));
281 CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
282 ASSERT (CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
!= NULL
);
283 CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
284 ASSERT (CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
!= NULL
);
287 // Get support and configuration PCDs
289 CpuFeaturesData
->SupportPcd
= GetSupportPcd ();
290 CpuFeaturesData
->ConfigurationPcd
= GetConfigurationPcd ();
294 Worker function to do OR operation on CPU feature supported bits mask buffer.
296 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
297 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
301 IN UINT8
*SupportedFeatureMask
,
302 IN UINT8
*OrFeatureBitMask
310 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
311 Data1
= SupportedFeatureMask
;
312 Data2
= OrFeatureBitMask
;
313 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
314 *(Data1
++) |= *(Data2
++);
319 Worker function to do AND operation on CPU feature supported bits mask buffer.
321 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
322 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
326 IN UINT8
*SupportedFeatureMask
,
327 IN UINT8
*AndFeatureBitMask
335 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
336 Data1
= SupportedFeatureMask
;
337 Data2
= AndFeatureBitMask
;
338 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
339 *(Data1
++) &= *(Data2
++);
344 Worker function to clean bit operation on CPU feature supported bits mask buffer.
346 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
347 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
350 SupportedMaskCleanBit (
351 IN UINT8
*SupportedFeatureMask
,
352 IN UINT8
*AndFeatureBitMask
360 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
361 Data1
= SupportedFeatureMask
;
362 Data2
= AndFeatureBitMask
;
363 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
364 *(Data1
++) &= ~(*(Data2
++));
369 Worker function to check if the compared CPU feature set in the CPU feature
370 supported bits mask buffer.
372 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
373 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
375 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
377 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
382 IN UINT8
*SupportedFeatureMask
,
383 IN UINT8
*ComparedFeatureBitMask
391 BitMaskSize
= PcdGetSize (PcdCpuFeaturesSupport
);
393 Data1
= SupportedFeatureMask
;
394 Data2
= ComparedFeatureBitMask
;
395 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
396 if (((*(Data1
++)) & (*(Data2
++))) != 0) {
404 Collects processor data for calling processor.
406 @param[in,out] Buffer The pointer to private data buffer.
410 CollectProcessorData (
414 UINTN ProcessorNumber
;
415 CPU_FEATURES_ENTRY
*CpuFeature
;
416 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
418 CPU_FEATURES_DATA
*CpuFeaturesData
;
420 CpuFeaturesData
= (CPU_FEATURES_DATA
*)Buffer
;
421 ProcessorNumber
= GetProcessorIndex (CpuFeaturesData
);
422 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
424 // collect processor information
426 FillProcessorInfo (CpuInfo
);
427 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
428 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
429 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
430 if (IsBitMaskMatch (CpuFeaturesData
->SupportPcd
, CpuFeature
->FeatureMask
)) {
431 if (CpuFeature
->SupportFunc
== NULL
) {
433 // If SupportFunc is NULL, then the feature is supported.
436 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
437 CpuFeature
->FeatureMask
439 } else if (CpuFeature
->SupportFunc (ProcessorNumber
, CpuInfo
, CpuFeature
->ConfigData
)) {
441 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
442 CpuFeature
->FeatureMask
446 Entry
= Entry
->ForwardLink
;
451 Dump the contents of a CPU register table.
453 @param[in] ProcessorNumber The index of the CPU to show the register table contents
455 @note This service could be called by BSP only.
458 DumpRegisterTableOnProcessor (
459 IN UINTN ProcessorNumber
462 CPU_FEATURES_DATA
*CpuFeaturesData
;
464 CPU_REGISTER_TABLE
*RegisterTable
;
465 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
466 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
467 UINT32 DebugPrintErrorLevel
;
469 DebugPrintErrorLevel
= (ProcessorNumber
== 0) ? DEBUG_INFO
: DEBUG_VERBOSE
;
470 CpuFeaturesData
= GetCpuFeaturesData ();
474 RegisterTable
= &CpuFeaturesData
->RegisterTable
[ProcessorNumber
];
475 DEBUG ((DebugPrintErrorLevel
, "RegisterTable->TableLength = %d\n", RegisterTable
->TableLength
));
477 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
479 for (FeatureIndex
= 0; FeatureIndex
< RegisterTable
->TableLength
; FeatureIndex
++) {
480 RegisterTableEntry
= &RegisterTableEntryHead
[FeatureIndex
];
481 switch (RegisterTableEntry
->RegisterType
) {
484 DebugPrintErrorLevel
,
485 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
488 RegisterTableEntry
->Index
,
489 RegisterTableEntry
->ValidBitStart
,
490 RegisterTableEntry
->ValidBitLength
,
491 RegisterTableEntry
->Value
494 case ControlRegister
:
496 DebugPrintErrorLevel
,
497 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
500 RegisterTableEntry
->Index
,
501 RegisterTableEntry
->ValidBitStart
,
502 RegisterTableEntry
->ValidBitLength
,
503 RegisterTableEntry
->Value
508 DebugPrintErrorLevel
,
509 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
512 RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32),
513 RegisterTableEntry
->ValidBitStart
,
514 RegisterTableEntry
->ValidBitLength
,
515 RegisterTableEntry
->Value
520 DebugPrintErrorLevel
,
521 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
524 RegisterTableEntry
->Index
,
525 RegisterTableEntry
->ValidBitStart
,
526 RegisterTableEntry
->ValidBitLength
,
527 RegisterTableEntry
->Value
532 DebugPrintErrorLevel
,
533 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
536 mDependTypeStr
[MIN ((UINT32
)RegisterTableEntry
->Value
, InvalidDepType
)]
547 Get the biggest dependence type.
548 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
550 @param[in] BeforeDep Before dependence type.
551 @param[in] AfterDep After dependence type.
552 @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
553 @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
555 @retval Return the biggest dependence type.
557 CPU_FEATURE_DEPENDENCE_TYPE
559 IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
,
560 IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep
,
561 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
,
562 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
565 CPU_FEATURE_DEPENDENCE_TYPE Bigger
;
567 Bigger
= MAX (BeforeDep
, AfterDep
);
568 Bigger
= MAX (Bigger
, NoneNeibBeforeDep
);
569 return MAX(Bigger
, NoneNeibAfterDep
);
573 Analysis register CPU features on each processor and save CPU setting in CPU register table.
575 @param[in] NumberOfCpus Number of processor in system
579 AnalysisProcessorFeatures (
580 IN UINTN NumberOfCpus
584 UINTN ProcessorNumber
;
585 CPU_FEATURES_ENTRY
*CpuFeature
;
586 CPU_FEATURES_ENTRY
*CpuFeatureInOrder
;
587 CPU_FEATURES_INIT_ORDER
*CpuInitOrder
;
588 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
590 CPU_FEATURES_DATA
*CpuFeaturesData
;
591 LIST_ENTRY
*NextEntry
;
592 CPU_FEATURES_ENTRY
*NextCpuFeatureInOrder
;
594 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
;
595 CPU_FEATURE_DEPENDENCE_TYPE AfterDep
;
596 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
;
597 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
;
599 CpuFeaturesData
= GetCpuFeaturesData ();
600 CpuFeaturesData
->CapabilityPcd
= AllocatePool (CpuFeaturesData
->BitMaskSize
);
601 ASSERT (CpuFeaturesData
->CapabilityPcd
!= NULL
);
602 SetMem (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
, 0xFF);
603 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
604 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
606 // Calculate the last capability on all processors
608 SupportedMaskAnd (CpuFeaturesData
->CapabilityPcd
, CpuInitOrder
->FeaturesSupportedMask
);
611 // Calculate the last setting
614 CpuFeaturesData
->SettingPcd
= AllocateCopyPool (CpuFeaturesData
->BitMaskSize
, CpuFeaturesData
->CapabilityPcd
);
615 ASSERT (CpuFeaturesData
->SettingPcd
!= NULL
);
616 SupportedMaskAnd (CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->ConfigurationPcd
);
619 // Save PCDs and display CPU PCDs
621 SetCapabilityPcd (CpuFeaturesData
->CapabilityPcd
);
622 SetSettingPcd (CpuFeaturesData
->SettingPcd
);
625 // Dump the last CPU feature list
628 DEBUG ((DEBUG_INFO
, "Last CPU features list...\n"));
629 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
630 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
631 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
632 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
633 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
634 DEBUG ((DEBUG_INFO
, "[Enable ] "));
636 DEBUG ((DEBUG_INFO
, "[Disable ] "));
639 DEBUG ((DEBUG_INFO
, "[Unsupport] "));
641 DumpCpuFeature (CpuFeature
);
642 Entry
= Entry
->ForwardLink
;
644 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesSupport:\n"));
645 DumpCpuFeatureMask (CpuFeaturesData
->SupportPcd
);
646 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesUserConfiguration:\n"));
647 DumpCpuFeatureMask (CpuFeaturesData
->ConfigurationPcd
);
648 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesCapability:\n"));
649 DumpCpuFeatureMask (CpuFeaturesData
->CapabilityPcd
);
650 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesSetting:\n"));
651 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
654 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
655 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
656 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
657 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
659 // Insert each feature into processor's order list
661 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
662 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
)) {
663 CpuFeatureInOrder
= AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY
), CpuFeature
);
664 ASSERT (CpuFeatureInOrder
!= NULL
);
665 InsertTailList (&CpuInitOrder
->OrderList
, &CpuFeatureInOrder
->Link
);
667 Entry
= Entry
->ForwardLink
;
670 // Go through ordered feature list to initialize CPU features
672 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
673 Entry
= GetFirstNode (&CpuInitOrder
->OrderList
);
674 while (!IsNull (&CpuInitOrder
->OrderList
, Entry
)) {
675 CpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
678 if (IsBitMaskMatch (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->SettingPcd
)) {
679 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, TRUE
);
680 if (EFI_ERROR (Status
)) {
682 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
684 SupportedMaskCleanBit (CpuFeaturesData
->SettingPcd
, CpuFeatureInOrder
->FeatureMask
);
685 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
686 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
688 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Mask = "));
689 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
695 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, FALSE
);
696 if (EFI_ERROR (Status
)) {
697 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
698 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
700 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Mask = "));
701 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
);
709 NextEntry
= Entry
->ForwardLink
;
710 if (!IsNull (&CpuInitOrder
->OrderList
, NextEntry
)) {
711 NextCpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (NextEntry
);
714 // If feature has dependence with the next feature (ONLY care core/package dependency).
715 // and feature initialize succeed, add sync semaphere here.
717 BeforeDep
= DetectFeatureScope (CpuFeatureInOrder
, TRUE
, NextCpuFeatureInOrder
->FeatureMask
);
718 AfterDep
= DetectFeatureScope (NextCpuFeatureInOrder
, FALSE
, CpuFeatureInOrder
->FeatureMask
);
720 // Check whether next feature has After type dependence with not neighborhood CPU
721 // Features in former CPU features.
723 NoneNeibAfterDep
= DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder
, FALSE
, &CpuInitOrder
->OrderList
);
725 BeforeDep
= NoneDepType
;
726 AfterDep
= NoneDepType
;
727 NoneNeibAfterDep
= NoneDepType
;
730 // Check whether current feature has Before type dependence with none neighborhood
731 // CPU features in after Cpu features.
733 NoneNeibBeforeDep
= DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder
, TRUE
, &CpuInitOrder
->OrderList
);
736 // Get the biggest dependence and add semaphore for it.
737 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
739 BeforeDep
= BiggestDep(BeforeDep
, AfterDep
, NoneNeibBeforeDep
, NoneNeibAfterDep
);
740 if (BeforeDep
> ThreadDepType
) {
741 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber
, Semaphore
, 0, BeforeDep
);
745 Entry
= Entry
->ForwardLink
;
749 // Dump PcdCpuFeaturesSetting again because this value maybe updated
750 // again during initialize the features.
752 DEBUG ((DEBUG_INFO
, "Dump final value for PcdCpuFeaturesSetting:\n"));
753 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
);
756 // Dump the RegisterTable
758 DumpRegisterTableOnProcessor (ProcessorNumber
);
763 Increment semaphore by 1.
765 @param Sem IN: 32-bit unsigned integer
769 LibReleaseSemaphore (
770 IN OUT
volatile UINT32
*Sem
773 InterlockedIncrement (Sem
);
777 Decrement the semaphore by 1 if it is not zero.
779 Performs an atomic decrement operation for semaphore.
780 The compare exchange operation must be performed using
783 @param Sem IN: 32-bit unsigned integer
787 LibWaitForSemaphore (
788 IN OUT
volatile UINT32
*Sem
795 } while (Value
== 0 ||
796 InterlockedCompareExchange32 (
804 Initialize the CPU registers from a register table.
806 @param[in] RegisterTable The register table for this AP.
807 @param[in] ApLocation AP location info for this ap.
808 @param[in] CpuStatus CPU status info for this CPU.
809 @param[in] CpuFlags Flags data structure used when program the register.
811 @note This service could be called by BSP/APs.
814 ProgramProcessorRegister (
815 IN CPU_REGISTER_TABLE
*RegisterTable
,
816 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
817 IN CPU_STATUS_INFORMATION
*CpuStatus
,
818 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
821 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
824 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
825 volatile UINT32
*SemaphorePtr
;
827 UINT32 PackageThreadsCount
;
828 UINT32 CurrentThread
;
829 UINTN ProcessorIndex
;
831 UINTN ValidThreadCount
;
832 UINT32
*ValidCoreCountPerPackage
;
835 // Traverse Register Table of this logical processor
837 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
839 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
841 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
845 // Wait for the AP to release the MSR spin lock.
847 while (!AcquireSpinLockOrFail (&CpuFlags
->ConsoleLogLock
)) {
850 ThreadIndex
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
+
851 ApLocation
->Core
* CpuStatus
->MaxThreadCount
+
855 "Processor = %08lu, Index %08lu, Type = %s!\n",
858 mRegisterTypeStr
[MIN ((REGISTER_TYPE
)RegisterTableEntry
->RegisterType
, InvalidReg
)]
860 ReleaseSpinLock (&CpuFlags
->ConsoleLogLock
);
864 // Check the type of specified register
866 switch (RegisterTableEntry
->RegisterType
) {
868 // The specified register is Control Register
870 case ControlRegister
:
871 switch (RegisterTableEntry
->Index
) {
873 Value
= AsmReadCr0 ();
874 Value
= (UINTN
) BitFieldWrite64 (
876 RegisterTableEntry
->ValidBitStart
,
877 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
878 RegisterTableEntry
->Value
883 Value
= AsmReadCr2 ();
884 Value
= (UINTN
) BitFieldWrite64 (
886 RegisterTableEntry
->ValidBitStart
,
887 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
888 RegisterTableEntry
->Value
893 Value
= AsmReadCr3 ();
894 Value
= (UINTN
) BitFieldWrite64 (
896 RegisterTableEntry
->ValidBitStart
,
897 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
898 RegisterTableEntry
->Value
903 Value
= AsmReadCr4 ();
904 Value
= (UINTN
) BitFieldWrite64 (
906 RegisterTableEntry
->ValidBitStart
,
907 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
908 RegisterTableEntry
->Value
914 // Do we need to support CR8?
922 // The specified register is Model Specific Register
925 if (RegisterTableEntry
->ValidBitLength
>= 64) {
927 // If length is not less than 64 bits, then directly write without reading
930 RegisterTableEntry
->Index
,
931 RegisterTableEntry
->Value
935 // Set the bit section according to bit start and length
937 AsmMsrBitFieldWrite64 (
938 RegisterTableEntry
->Index
,
939 RegisterTableEntry
->ValidBitStart
,
940 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
941 RegisterTableEntry
->Value
946 // MemoryMapped operations
949 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
950 MmioBitFieldWrite32 (
951 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
952 RegisterTableEntry
->ValidBitStart
,
953 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
954 (UINT32
)RegisterTableEntry
->Value
956 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
959 // Enable or disable cache
963 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
965 if (RegisterTableEntry
->Value
== 0) {
973 // Semaphore works logic like below:
975 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
976 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
978 // All threads (T0...Tn) waits in P() line and continues running
984 // V(0...n) V(0...n) ... V(0...n)
985 // n * P(0) n * P(1) ... n * P(n)
987 switch (RegisterTableEntry
->Value
) {
989 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
991 // Get Offset info for the first thread in the core which current thread belongs to.
993 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
994 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
996 // First Notify all threads in current Core that this thread has ready.
998 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
999 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
1002 // Second, check whether all valid threads in current core have ready.
1004 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
1005 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
1009 case PackageDepType
:
1010 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
1011 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
1013 // Get Offset info for the first thread in the package which current thread belongs to.
1015 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
1017 // Get the possible threads count for current package.
1019 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
1020 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
1022 // Get the valid thread count for current package.
1024 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
1027 // Different packages may have different valid cores in them. If driver maintail clearly
1028 // cores number in different packages, the logic will be much complicated.
1029 // Here driver just simply records the max core number in all packages and use it as expect
1030 // core number for all packages.
1031 // In below two steps logic, first current thread will Release semaphore for each thread
1032 // in current package. Maybe some threads are not valid in this package, but driver don't
1033 // care. Second, driver will let current thread wait semaphore for all valid threads in
1034 // current package. Because only the valid threads will do release semaphore for this
1035 // thread, driver here only need to wait the valid thread count.
1039 // First Notify ALL THREADS in current package that this thread has ready.
1041 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
1042 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
1045 // Second, check whether VALID THREADS (not all threads) in current package have ready.
1047 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
1048 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
1064 Programs registers for the calling processor.
1066 @param[in,out] Buffer The pointer to private data buffer.
1071 SetProcessorRegister (
1075 CPU_FEATURES_DATA
*CpuFeaturesData
;
1076 CPU_REGISTER_TABLE
*RegisterTable
;
1077 CPU_REGISTER_TABLE
*RegisterTables
;
1081 ACPI_CPU_DATA
*AcpiCpuData
;
1083 CpuFeaturesData
= (CPU_FEATURES_DATA
*) Buffer
;
1084 AcpiCpuData
= CpuFeaturesData
->AcpiCpuData
;
1086 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
;
1088 InitApicId
= GetInitialApicId ();
1089 RegisterTable
= NULL
;
1090 ProcIndex
= (UINTN
)-1;
1091 for (Index
= 0; Index
< AcpiCpuData
->NumberOfCpus
; Index
++) {
1092 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
1093 RegisterTable
= &RegisterTables
[Index
];
1098 ASSERT (RegisterTable
!= NULL
);
1100 ProgramProcessorRegister (
1102 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
+ ProcIndex
,
1103 &AcpiCpuData
->CpuStatus
,
1104 &CpuFeaturesData
->CpuFlags
1109 Performs CPU features detection.
1111 This service will invoke MP service to check CPU features'
1112 capabilities on BSP/APs.
1114 @note This service could be called by BSP only.
1122 CPU_FEATURES_DATA
*CpuFeaturesData
;
1124 CpuFeaturesData
= GetCpuFeaturesData();
1126 CpuInitDataInitialize ();
1129 // Wakeup all APs for data collection.
1131 StartupAPsWorker (CollectProcessorData
, NULL
);
1134 // Collect data on BSP
1136 CollectProcessorData (CpuFeaturesData
);
1138 AnalysisProcessorFeatures (CpuFeaturesData
->NumberOfCpus
);