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] BitMaskSize CPU feature bits mask buffer size.
23 IN UINT8
*SupportedFeatureMask
,
29 Status
= PcdSetPtrS (PcdCpuFeaturesCapability
, &BitMaskSize
, SupportedFeatureMask
);
30 ASSERT_EFI_ERROR (Status
);
34 Worker function to save PcdCpuFeaturesSetting.
36 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
37 @param[in] BitMaskSize CPU feature bits mask buffer size.
41 IN UINT8
*SupportedFeatureMask
,
47 Status
= PcdSetPtrS (PcdCpuFeaturesSetting
, &BitMaskSize
, SupportedFeatureMask
);
48 ASSERT_EFI_ERROR (Status
);
52 Collects CPU type and feature information.
54 @param[in, out] CpuInfo The pointer to CPU feature information
58 IN OUT REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
61 CPUID_VERSION_INFO_EAX Eax
;
62 CPUID_VERSION_INFO_ECX Ecx
;
63 CPUID_VERSION_INFO_EDX Edx
;
64 UINT32 DisplayedFamily
;
65 UINT32 DisplayedModel
;
67 AsmCpuid (CPUID_VERSION_INFO
, &Eax
.Uint32
, NULL
, &Ecx
.Uint32
, &Edx
.Uint32
);
69 DisplayedFamily
= Eax
.Bits
.FamilyId
;
70 if (Eax
.Bits
.FamilyId
== 0x0F) {
71 DisplayedFamily
|= (Eax
.Bits
.ExtendedFamilyId
<< 4);
74 DisplayedModel
= Eax
.Bits
.Model
;
75 if (Eax
.Bits
.FamilyId
== 0x06 || Eax
.Bits
.FamilyId
== 0x0f) {
76 DisplayedModel
|= (Eax
.Bits
.ExtendedModelId
<< 4);
79 CpuInfo
->DisplayFamily
= DisplayedFamily
;
80 CpuInfo
->DisplayModel
= DisplayedModel
;
81 CpuInfo
->SteppingId
= Eax
.Bits
.SteppingId
;
82 CpuInfo
->ProcessorType
= Eax
.Bits
.ProcessorType
;
83 CpuInfo
->CpuIdVersionInfoEcx
.Uint32
= Ecx
.Uint32
;
84 CpuInfo
->CpuIdVersionInfoEdx
.Uint32
= Edx
.Uint32
;
88 Prepares for private data used for CPU features.
92 CpuInitDataInitialize (
97 UINTN ProcessorNumber
;
98 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer
;
99 CPU_FEATURES_ENTRY
*CpuFeature
;
100 CPU_FEATURES_INIT_ORDER
*InitOrder
;
101 CPU_FEATURES_DATA
*CpuFeaturesData
;
106 EFI_CPU_PHYSICAL_LOCATION
*Location
;
107 BOOLEAN
*CoresVisited
;
109 ACPI_CPU_DATA
*AcpiCpuData
;
110 CPU_STATUS_INFORMATION
*CpuStatus
;
111 UINT32
*ValidCoreCountPerPackage
;
113 UINTN NumberOfEnabledProcessors
;
119 CpuFeaturesData
= GetCpuFeaturesData ();
122 // Initialize CpuFeaturesData->MpService as early as possile, so later function can use it.
124 CpuFeaturesData
->MpService
= GetMpService ();
126 GetNumberOfProcessor (&NumberOfCpus
, &NumberOfEnabledProcessors
);
128 CpuFeaturesData
->InitOrder
= AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER
) * NumberOfCpus
);
129 ASSERT (CpuFeaturesData
->InitOrder
!= NULL
);
132 // Collect CPU Features information
134 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
135 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
136 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
137 ASSERT (CpuFeature
->InitializeFunc
!= NULL
);
138 if (CpuFeature
->GetConfigDataFunc
!= NULL
) {
139 CpuFeature
->ConfigData
= CpuFeature
->GetConfigDataFunc (NumberOfCpus
);
141 Entry
= Entry
->ForwardLink
;
144 CpuFeaturesData
->NumberOfCpus
= (UINT32
) NumberOfCpus
;
146 AcpiCpuData
= GetAcpiCpuData ();
147 ASSERT (AcpiCpuData
!= NULL
);
148 CpuFeaturesData
->AcpiCpuData
= AcpiCpuData
;
150 CpuStatus
= &AcpiCpuData
->CpuStatus
;
151 Location
= AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION
) * NumberOfCpus
);
152 ASSERT (Location
!= NULL
);
153 AcpiCpuData
->ApLocation
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)Location
;
155 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
156 InitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
157 InitOrder
->FeaturesSupportedMask
= AllocateZeroPool (CpuFeaturesData
->BitMaskSize
);
158 ASSERT (InitOrder
->FeaturesSupportedMask
!= NULL
);
159 InitializeListHead (&InitOrder
->OrderList
);
160 Status
= GetProcessorInformation (ProcessorNumber
, &ProcessorInfoBuffer
);
161 ASSERT_EFI_ERROR (Status
);
163 &InitOrder
->CpuInfo
.ProcessorInfo
,
164 &ProcessorInfoBuffer
,
165 sizeof (EFI_PROCESSOR_INFORMATION
)
168 &Location
[ProcessorNumber
],
169 &ProcessorInfoBuffer
.Location
,
170 sizeof (EFI_CPU_PHYSICAL_LOCATION
)
174 // Collect CPU package count info.
176 if (Package
< ProcessorInfoBuffer
.Location
.Package
) {
177 Package
= ProcessorInfoBuffer
.Location
.Package
;
180 // Collect CPU max core count info.
182 if (Core
< ProcessorInfoBuffer
.Location
.Core
) {
183 Core
= ProcessorInfoBuffer
.Location
.Core
;
186 // Collect CPU max thread count info.
188 if (Thread
< ProcessorInfoBuffer
.Location
.Thread
) {
189 Thread
= ProcessorInfoBuffer
.Location
.Thread
;
192 CpuStatus
->PackageCount
= Package
+ 1;
193 CpuStatus
->MaxCoreCount
= Core
+ 1;
194 CpuStatus
->MaxThreadCount
= Thread
+ 1;
195 DEBUG ((DEBUG_INFO
, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
196 CpuStatus
->PackageCount
,
197 CpuStatus
->MaxCoreCount
,
198 CpuStatus
->MaxThreadCount
));
201 // Collect valid core count in each package because not all cores are valid.
203 ValidCoreCountPerPackage
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
);
204 ASSERT (ValidCoreCountPerPackage
!= 0);
205 CpuStatus
->ValidCoreCountPerPackage
= (EFI_PHYSICAL_ADDRESS
)(UINTN
)ValidCoreCountPerPackage
;
206 CoresVisited
= AllocatePool (sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
207 ASSERT (CoresVisited
!= NULL
);
209 for (Index
= 0; Index
< CpuStatus
->PackageCount
; Index
++ ) {
210 ZeroMem (CoresVisited
, sizeof (BOOLEAN
) * CpuStatus
->MaxCoreCount
);
212 // Collect valid cores in Current package.
214 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
215 Location
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
.ProcessorInfo
.Location
;
216 if (Location
->Package
== Index
&& !CoresVisited
[Location
->Core
] ) {
218 // The ValidCores position for Location->Core is valid.
219 // The possible values in ValidCores[Index] are 0 or 1.
220 // FALSE means no valid threads in this Core.
221 // TRUE means have valid threads in this core, no matter the thead count is 1 or more.
223 CoresVisited
[Location
->Core
] = TRUE
;
224 ValidCoreCountPerPackage
[Index
]++;
228 FreePool (CoresVisited
);
230 for (Index
= 0; Index
<= Package
; Index
++) {
231 DEBUG ((DEBUG_INFO
, "Package: %d, Valid Core : %d\n", Index
, ValidCoreCountPerPackage
[Index
]));
234 CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
235 ASSERT (CpuFeaturesData
->CpuFlags
.CoreSemaphoreCount
!= NULL
);
236 CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
= AllocateZeroPool (sizeof (UINT32
) * CpuStatus
->PackageCount
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
);
237 ASSERT (CpuFeaturesData
->CpuFlags
.PackageSemaphoreCount
!= NULL
);
241 Worker function to do OR operation on CPU feature supported bits mask buffer.
243 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
244 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
245 @param[in] BitMaskSize The CPU feature bits mask buffer size.
250 IN UINT8
*SupportedFeatureMask
,
251 IN UINT8
*OrFeatureBitMask
,
252 IN UINT32 BitMaskSize
259 Data1
= SupportedFeatureMask
;
260 Data2
= OrFeatureBitMask
;
261 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
262 *(Data1
++) |= *(Data2
++);
267 Worker function to do AND operation on CPU feature supported bits mask buffer.
269 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
270 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
271 @param[in] BitMaskSize CPU feature bits mask buffer size.
276 IN UINT8
*SupportedFeatureMask
,
277 IN CONST UINT8
*AndFeatureBitMask
,
278 IN UINT32 BitMaskSize
285 Data1
= SupportedFeatureMask
;
286 Data2
= AndFeatureBitMask
;
287 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
288 *(Data1
++) &= *(Data2
++);
293 Worker function to clean bit operation on CPU feature supported bits mask buffer.
295 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
296 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
297 @param[in] BitMaskSize CPU feature bits mask buffer size.
300 SupportedMaskCleanBit (
301 IN UINT8
*SupportedFeatureMask
,
302 IN UINT8
*AndFeatureBitMask
,
303 IN UINT32 BitMaskSize
310 Data1
= SupportedFeatureMask
;
311 Data2
= AndFeatureBitMask
;
312 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
313 *(Data1
++) &= ~(*(Data2
++));
318 Worker function to check if the compared CPU feature set in the CPU feature
319 supported bits mask buffer.
321 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
322 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
323 @param[in] BitMaskSize CPU feature bits mask buffer size.
325 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
327 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
332 IN UINT8
*SupportedFeatureMask
,
333 IN UINT8
*ComparedFeatureBitMask
,
334 IN UINT32 BitMaskSize
341 Data1
= SupportedFeatureMask
;
342 Data2
= ComparedFeatureBitMask
;
343 for (Index
= 0; Index
< BitMaskSize
; Index
++) {
344 if (((*(Data1
++)) & (*(Data2
++))) != 0) {
352 Collects processor data for calling processor.
354 @param[in,out] Buffer The pointer to private data buffer.
358 CollectProcessorData (
362 UINTN ProcessorNumber
;
363 CPU_FEATURES_ENTRY
*CpuFeature
;
364 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
366 CPU_FEATURES_DATA
*CpuFeaturesData
;
368 CpuFeaturesData
= (CPU_FEATURES_DATA
*)Buffer
;
369 ProcessorNumber
= GetProcessorIndex (CpuFeaturesData
);
370 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
372 // collect processor information
374 FillProcessorInfo (CpuInfo
);
375 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
376 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
377 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
378 if (CpuFeature
->SupportFunc
== NULL
) {
380 // If SupportFunc is NULL, then the feature is supported.
383 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
384 CpuFeature
->FeatureMask
,
385 CpuFeaturesData
->BitMaskSize
387 } else if (CpuFeature
->SupportFunc (ProcessorNumber
, CpuInfo
, CpuFeature
->ConfigData
)) {
389 CpuFeaturesData
->InitOrder
[ProcessorNumber
].FeaturesSupportedMask
,
390 CpuFeature
->FeatureMask
,
391 CpuFeaturesData
->BitMaskSize
394 Entry
= Entry
->ForwardLink
;
399 Dump the contents of a CPU register table.
401 @param[in] ProcessorNumber The index of the CPU to show the register table contents
403 @note This service could be called by BSP only.
406 DumpRegisterTableOnProcessor (
407 IN UINTN ProcessorNumber
410 CPU_FEATURES_DATA
*CpuFeaturesData
;
412 CPU_REGISTER_TABLE
*RegisterTable
;
413 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
414 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
415 UINT32 DebugPrintErrorLevel
;
417 DebugPrintErrorLevel
= (ProcessorNumber
== 0) ? DEBUG_INFO
: DEBUG_VERBOSE
;
418 CpuFeaturesData
= GetCpuFeaturesData ();
422 RegisterTable
= &CpuFeaturesData
->RegisterTable
[ProcessorNumber
];
423 DEBUG ((DebugPrintErrorLevel
, "RegisterTable->TableLength = %d\n", RegisterTable
->TableLength
));
425 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
427 for (FeatureIndex
= 0; FeatureIndex
< RegisterTable
->TableLength
; FeatureIndex
++) {
428 RegisterTableEntry
= &RegisterTableEntryHead
[FeatureIndex
];
429 switch (RegisterTableEntry
->RegisterType
) {
432 DebugPrintErrorLevel
,
433 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
436 RegisterTableEntry
->Index
,
437 RegisterTableEntry
->ValidBitStart
,
438 RegisterTableEntry
->ValidBitLength
,
439 RegisterTableEntry
->Value
442 case ControlRegister
:
444 DebugPrintErrorLevel
,
445 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
448 RegisterTableEntry
->Index
,
449 RegisterTableEntry
->ValidBitStart
,
450 RegisterTableEntry
->ValidBitLength
,
451 RegisterTableEntry
->Value
456 DebugPrintErrorLevel
,
457 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
460 RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32),
461 RegisterTableEntry
->ValidBitStart
,
462 RegisterTableEntry
->ValidBitLength
,
463 RegisterTableEntry
->Value
468 DebugPrintErrorLevel
,
469 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
472 RegisterTableEntry
->Index
,
473 RegisterTableEntry
->ValidBitStart
,
474 RegisterTableEntry
->ValidBitLength
,
475 RegisterTableEntry
->Value
480 DebugPrintErrorLevel
,
481 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
484 mDependTypeStr
[MIN ((UINT32
)RegisterTableEntry
->Value
, InvalidDepType
)]
495 Get the biggest dependence type.
496 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
498 @param[in] BeforeDep Before dependence type.
499 @param[in] AfterDep After dependence type.
500 @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
501 @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
503 @retval Return the biggest dependence type.
505 CPU_FEATURE_DEPENDENCE_TYPE
507 IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
,
508 IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep
,
509 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
,
510 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
513 CPU_FEATURE_DEPENDENCE_TYPE Bigger
;
515 Bigger
= MAX (BeforeDep
, AfterDep
);
516 Bigger
= MAX (Bigger
, NoneNeibBeforeDep
);
517 return MAX(Bigger
, NoneNeibAfterDep
);
521 Analysis register CPU features on each processor and save CPU setting in CPU register table.
523 @param[in] NumberOfCpus Number of processor in system
527 AnalysisProcessorFeatures (
528 IN UINTN NumberOfCpus
532 UINTN ProcessorNumber
;
533 CPU_FEATURES_ENTRY
*CpuFeature
;
534 CPU_FEATURES_ENTRY
*CpuFeatureInOrder
;
535 CPU_FEATURES_INIT_ORDER
*CpuInitOrder
;
536 REGISTER_CPU_FEATURE_INFORMATION
*CpuInfo
;
538 CPU_FEATURES_DATA
*CpuFeaturesData
;
539 LIST_ENTRY
*NextEntry
;
540 CPU_FEATURES_ENTRY
*NextCpuFeatureInOrder
;
542 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep
;
543 CPU_FEATURE_DEPENDENCE_TYPE AfterDep
;
544 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep
;
545 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
;
547 CpuFeaturesData
= GetCpuFeaturesData ();
548 CpuFeaturesData
->CapabilityPcd
= AllocatePool (CpuFeaturesData
->BitMaskSize
);
549 ASSERT (CpuFeaturesData
->CapabilityPcd
!= NULL
);
550 SetMem (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
, 0xFF);
551 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
552 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
554 // Calculate the last capability on all processors
556 SupportedMaskAnd (CpuFeaturesData
->CapabilityPcd
, CpuInitOrder
->FeaturesSupportedMask
, CpuFeaturesData
->BitMaskSize
);
559 // Calculate the last setting
561 CpuFeaturesData
->SettingPcd
= AllocateCopyPool (CpuFeaturesData
->BitMaskSize
, CpuFeaturesData
->CapabilityPcd
);
562 ASSERT (CpuFeaturesData
->SettingPcd
!= NULL
);
563 SupportedMaskAnd (CpuFeaturesData
->SettingPcd
, PcdGetPtr (PcdCpuFeaturesSetting
), CpuFeaturesData
->BitMaskSize
);
566 // Dump the last CPU feature list
569 DEBUG ((DEBUG_INFO
, "Last CPU features list...\n"));
570 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
571 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
572 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
573 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
)) {
574 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->BitMaskSize
)) {
575 DEBUG ((DEBUG_INFO
, "[Enable ] "));
577 DEBUG ((DEBUG_INFO
, "[Disable ] "));
580 DEBUG ((DEBUG_INFO
, "[Unsupport] "));
582 DumpCpuFeature (CpuFeature
, CpuFeaturesData
->BitMaskSize
);
583 Entry
= Entry
->ForwardLink
;
585 DEBUG ((DEBUG_INFO
, "PcdCpuFeaturesCapability:\n"));
586 DumpCpuFeatureMask (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
);
587 DEBUG ((DEBUG_INFO
, "Origin PcdCpuFeaturesSetting:\n"));
588 DumpCpuFeatureMask (PcdGetPtr (PcdCpuFeaturesSetting
), CpuFeaturesData
->BitMaskSize
);
589 DEBUG ((DEBUG_INFO
, "Final PcdCpuFeaturesSetting:\n"));
590 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->BitMaskSize
);
594 // Save PCDs and display CPU PCDs
596 SetCapabilityPcd (CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
);
597 SetSettingPcd (CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->BitMaskSize
);
599 for (ProcessorNumber
= 0; ProcessorNumber
< NumberOfCpus
; ProcessorNumber
++) {
600 CpuInitOrder
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
];
601 Entry
= GetFirstNode (&CpuFeaturesData
->FeatureList
);
602 while (!IsNull (&CpuFeaturesData
->FeatureList
, Entry
)) {
604 // Insert each feature into processor's order list
606 CpuFeature
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
607 if (IsBitMaskMatch (CpuFeature
->FeatureMask
, CpuFeaturesData
->CapabilityPcd
, CpuFeaturesData
->BitMaskSize
)) {
608 CpuFeatureInOrder
= AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY
), CpuFeature
);
609 ASSERT (CpuFeatureInOrder
!= NULL
);
610 InsertTailList (&CpuInitOrder
->OrderList
, &CpuFeatureInOrder
->Link
);
612 Entry
= Entry
->ForwardLink
;
615 // Go through ordered feature list to initialize CPU features
617 CpuInfo
= &CpuFeaturesData
->InitOrder
[ProcessorNumber
].CpuInfo
;
618 Entry
= GetFirstNode (&CpuInitOrder
->OrderList
);
619 while (!IsNull (&CpuInitOrder
->OrderList
, Entry
)) {
620 CpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (Entry
);
623 if (IsBitMaskMatch (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->BitMaskSize
)) {
624 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, TRUE
);
625 if (EFI_ERROR (Status
)) {
627 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
629 SupportedMaskCleanBit (CpuFeaturesData
->SettingPcd
, CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->BitMaskSize
);
630 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
631 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
633 DEBUG ((DEBUG_WARN
, "Warning :: Failed to enable Feature: Mask = "));
634 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->BitMaskSize
);
640 Status
= CpuFeatureInOrder
->InitializeFunc (ProcessorNumber
, CpuInfo
, CpuFeatureInOrder
->ConfigData
, FALSE
);
641 if (EFI_ERROR (Status
)) {
642 if (CpuFeatureInOrder
->FeatureName
!= NULL
) {
643 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder
->FeatureName
));
645 DEBUG ((DEBUG_WARN
, "Warning :: Failed to disable Feature: Mask = "));
646 DumpCpuFeatureMask (CpuFeatureInOrder
->FeatureMask
, CpuFeaturesData
->BitMaskSize
);
654 NextEntry
= Entry
->ForwardLink
;
655 if (!IsNull (&CpuInitOrder
->OrderList
, NextEntry
)) {
656 NextCpuFeatureInOrder
= CPU_FEATURE_ENTRY_FROM_LINK (NextEntry
);
659 // If feature has dependence with the next feature (ONLY care core/package dependency).
660 // and feature initialize succeed, add sync semaphere here.
662 BeforeDep
= DetectFeatureScope (CpuFeatureInOrder
, TRUE
, NextCpuFeatureInOrder
->FeatureMask
);
663 AfterDep
= DetectFeatureScope (NextCpuFeatureInOrder
, FALSE
, CpuFeatureInOrder
->FeatureMask
);
665 // Check whether next feature has After type dependence with not neighborhood CPU
666 // Features in former CPU features.
668 NoneNeibAfterDep
= DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder
, FALSE
, &CpuInitOrder
->OrderList
);
670 BeforeDep
= NoneDepType
;
671 AfterDep
= NoneDepType
;
672 NoneNeibAfterDep
= NoneDepType
;
675 // Check whether current feature has Before type dependence with none neighborhood
676 // CPU features in after Cpu features.
678 NoneNeibBeforeDep
= DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder
, TRUE
, &CpuInitOrder
->OrderList
);
681 // Get the biggest dependence and add semaphore for it.
682 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
684 BeforeDep
= BiggestDep(BeforeDep
, AfterDep
, NoneNeibBeforeDep
, NoneNeibAfterDep
);
685 if (BeforeDep
> ThreadDepType
) {
686 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber
, Semaphore
, 0, BeforeDep
);
690 Entry
= Entry
->ForwardLink
;
694 // Dump PcdCpuFeaturesSetting again because this value maybe updated
695 // again during initialize the features.
697 DEBUG ((DEBUG_INFO
, "Dump final value for PcdCpuFeaturesSetting:\n"));
698 DumpCpuFeatureMask (CpuFeaturesData
->SettingPcd
, CpuFeaturesData
->BitMaskSize
);
701 // Dump the RegisterTable
703 DumpRegisterTableOnProcessor (ProcessorNumber
);
708 Increment semaphore by 1.
710 @param Sem IN: 32-bit unsigned integer
714 LibReleaseSemaphore (
715 IN OUT
volatile UINT32
*Sem
718 InterlockedIncrement (Sem
);
722 Decrement the semaphore by 1 if it is not zero.
724 Performs an atomic decrement operation for semaphore.
725 The compare exchange operation must be performed using
728 @param Sem IN: 32-bit unsigned integer
732 LibWaitForSemaphore (
733 IN OUT
volatile UINT32
*Sem
740 } while (Value
== 0 ||
741 InterlockedCompareExchange32 (
749 Initialize the CPU registers from a register table.
751 @param[in] RegisterTable The register table for this AP.
752 @param[in] ApLocation AP location info for this ap.
753 @param[in] CpuStatus CPU status info for this CPU.
754 @param[in] CpuFlags Flags data structure used when program the register.
756 @note This service could be called by BSP/APs.
759 ProgramProcessorRegister (
760 IN CPU_REGISTER_TABLE
*RegisterTable
,
761 IN EFI_CPU_PHYSICAL_LOCATION
*ApLocation
,
762 IN CPU_STATUS_INFORMATION
*CpuStatus
,
763 IN PROGRAM_CPU_REGISTER_FLAGS
*CpuFlags
766 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntry
;
769 CPU_REGISTER_TABLE_ENTRY
*RegisterTableEntryHead
;
770 volatile UINT32
*SemaphorePtr
;
772 UINT32 PackageThreadsCount
;
773 UINT32 CurrentThread
;
774 UINTN ProcessorIndex
;
776 UINTN ValidThreadCount
;
777 UINT32
*ValidCoreCountPerPackage
;
780 // Traverse Register Table of this logical processor
782 RegisterTableEntryHead
= (CPU_REGISTER_TABLE_ENTRY
*) (UINTN
) RegisterTable
->RegisterTableEntry
;
784 for (Index
= 0; Index
< RegisterTable
->TableLength
; Index
++) {
786 RegisterTableEntry
= &RegisterTableEntryHead
[Index
];
790 // Wait for the AP to release the MSR spin lock.
792 while (!AcquireSpinLockOrFail (&CpuFlags
->ConsoleLogLock
)) {
795 ThreadIndex
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
+
796 ApLocation
->Core
* CpuStatus
->MaxThreadCount
+
800 "Processor = %08lu, Index %08lu, Type = %s!\n",
803 mRegisterTypeStr
[MIN ((REGISTER_TYPE
)RegisterTableEntry
->RegisterType
, InvalidReg
)]
805 ReleaseSpinLock (&CpuFlags
->ConsoleLogLock
);
809 // Check the type of specified register
811 switch (RegisterTableEntry
->RegisterType
) {
813 // The specified register is Control Register
815 case ControlRegister
:
816 switch (RegisterTableEntry
->Index
) {
818 Value
= AsmReadCr0 ();
819 Value
= (UINTN
) BitFieldWrite64 (
821 RegisterTableEntry
->ValidBitStart
,
822 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
823 RegisterTableEntry
->Value
828 Value
= AsmReadCr2 ();
829 Value
= (UINTN
) BitFieldWrite64 (
831 RegisterTableEntry
->ValidBitStart
,
832 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
833 RegisterTableEntry
->Value
838 Value
= AsmReadCr3 ();
839 Value
= (UINTN
) BitFieldWrite64 (
841 RegisterTableEntry
->ValidBitStart
,
842 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
843 RegisterTableEntry
->Value
848 Value
= AsmReadCr4 ();
849 Value
= (UINTN
) BitFieldWrite64 (
851 RegisterTableEntry
->ValidBitStart
,
852 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
853 RegisterTableEntry
->Value
859 // Do we need to support CR8?
867 // The specified register is Model Specific Register
870 if (RegisterTableEntry
->ValidBitLength
>= 64) {
872 // If length is not less than 64 bits, then directly write without reading
875 RegisterTableEntry
->Index
,
876 RegisterTableEntry
->Value
880 // Set the bit section according to bit start and length
882 AsmMsrBitFieldWrite64 (
883 RegisterTableEntry
->Index
,
884 RegisterTableEntry
->ValidBitStart
,
885 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
886 RegisterTableEntry
->Value
891 // MemoryMapped operations
894 AcquireSpinLock (&CpuFlags
->MemoryMappedLock
);
895 MmioBitFieldWrite32 (
896 (UINTN
)(RegisterTableEntry
->Index
| LShiftU64 (RegisterTableEntry
->HighIndex
, 32)),
897 RegisterTableEntry
->ValidBitStart
,
898 RegisterTableEntry
->ValidBitStart
+ RegisterTableEntry
->ValidBitLength
- 1,
899 (UINT32
)RegisterTableEntry
->Value
901 ReleaseSpinLock (&CpuFlags
->MemoryMappedLock
);
904 // Enable or disable cache
908 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
910 if (RegisterTableEntry
->Value
== 0) {
918 // Semaphore works logic like below:
920 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
921 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
923 // All threads (T0...Tn) waits in P() line and continues running
929 // V(0...n) V(0...n) ... V(0...n)
930 // n * P(0) n * P(1) ... n * P(n)
932 switch (RegisterTableEntry
->Value
) {
934 SemaphorePtr
= CpuFlags
->CoreSemaphoreCount
;
936 // Get Offset info for the first thread in the core which current thread belongs to.
938 FirstThread
= (ApLocation
->Package
* CpuStatus
->MaxCoreCount
+ ApLocation
->Core
) * CpuStatus
->MaxThreadCount
;
939 CurrentThread
= FirstThread
+ ApLocation
->Thread
;
941 // First Notify all threads in current Core that this thread has ready.
943 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
944 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
947 // Second, check whether all valid threads in current core have ready.
949 for (ProcessorIndex
= 0; ProcessorIndex
< CpuStatus
->MaxThreadCount
; ProcessorIndex
++) {
950 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
955 SemaphorePtr
= CpuFlags
->PackageSemaphoreCount
;
956 ValidCoreCountPerPackage
= (UINT32
*)(UINTN
)CpuStatus
->ValidCoreCountPerPackage
;
958 // Get Offset info for the first thread in the package which current thread belongs to.
960 FirstThread
= ApLocation
->Package
* CpuStatus
->MaxCoreCount
* CpuStatus
->MaxThreadCount
;
962 // Get the possible threads count for current package.
964 PackageThreadsCount
= CpuStatus
->MaxThreadCount
* CpuStatus
->MaxCoreCount
;
965 CurrentThread
= FirstThread
+ CpuStatus
->MaxThreadCount
* ApLocation
->Core
+ ApLocation
->Thread
;
967 // Get the valid thread count for current package.
969 ValidThreadCount
= CpuStatus
->MaxThreadCount
* ValidCoreCountPerPackage
[ApLocation
->Package
];
972 // Different packages may have different valid cores in them. If driver maintail clearly
973 // cores number in different packages, the logic will be much complicated.
974 // Here driver just simply records the max core number in all packages and use it as expect
975 // core number for all packages.
976 // In below two steps logic, first current thread will Release semaphore for each thread
977 // in current package. Maybe some threads are not valid in this package, but driver don't
978 // care. Second, driver will let current thread wait semaphore for all valid threads in
979 // current package. Because only the valid threads will do release semaphore for this
980 // thread, driver here only need to wait the valid thread count.
984 // First Notify ALL THREADS in current package that this thread has ready.
986 for (ProcessorIndex
= 0; ProcessorIndex
< PackageThreadsCount
; ProcessorIndex
++) {
987 LibReleaseSemaphore ((UINT32
*) &SemaphorePtr
[FirstThread
+ ProcessorIndex
]);
990 // Second, check whether VALID THREADS (not all threads) in current package have ready.
992 for (ProcessorIndex
= 0; ProcessorIndex
< ValidThreadCount
; ProcessorIndex
++) {
993 LibWaitForSemaphore (&SemaphorePtr
[CurrentThread
]);
1009 Programs registers for the calling processor.
1011 @param[in,out] Buffer The pointer to private data buffer.
1016 SetProcessorRegister (
1020 CPU_FEATURES_DATA
*CpuFeaturesData
;
1021 CPU_REGISTER_TABLE
*RegisterTable
;
1022 CPU_REGISTER_TABLE
*RegisterTables
;
1026 ACPI_CPU_DATA
*AcpiCpuData
;
1028 CpuFeaturesData
= (CPU_FEATURES_DATA
*) Buffer
;
1029 AcpiCpuData
= CpuFeaturesData
->AcpiCpuData
;
1031 RegisterTables
= (CPU_REGISTER_TABLE
*)(UINTN
)AcpiCpuData
->RegisterTable
;
1033 InitApicId
= GetInitialApicId ();
1034 RegisterTable
= NULL
;
1035 ProcIndex
= (UINTN
)-1;
1036 for (Index
= 0; Index
< AcpiCpuData
->NumberOfCpus
; Index
++) {
1037 if (RegisterTables
[Index
].InitialApicId
== InitApicId
) {
1038 RegisterTable
= &RegisterTables
[Index
];
1043 ASSERT (RegisterTable
!= NULL
);
1045 ProgramProcessorRegister (
1047 (EFI_CPU_PHYSICAL_LOCATION
*)(UINTN
)AcpiCpuData
->ApLocation
+ ProcIndex
,
1048 &AcpiCpuData
->CpuStatus
,
1049 &CpuFeaturesData
->CpuFlags
1054 Performs CPU features detection.
1056 This service will invoke MP service to check CPU features'
1057 capabilities on BSP/APs.
1059 @note This service could be called by BSP only.
1067 CPU_FEATURES_DATA
*CpuFeaturesData
;
1069 CpuFeaturesData
= GetCpuFeaturesData();
1071 CpuInitDataInitialize ();
1073 if (CpuFeaturesData
->NumberOfCpus
> 1) {
1075 // Wakeup all APs for data collection.
1077 StartupAllAPsWorker (CollectProcessorData
, NULL
);
1081 // Collect data on BSP
1083 CollectProcessorData (CpuFeaturesData
);
1085 AnalysisProcessorFeatures (CpuFeaturesData
->NumberOfCpus
);