]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c
UefiCpuPkg/RegisterCpuFeaturesLib: Replace AcquireSpinLock.
[mirror_edk2.git] / UefiCpuPkg / Library / RegisterCpuFeaturesLib / CpuFeaturesInitialize.c
1 /** @file
2 CPU Features Initialize functions.
3
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
9
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.
12
13 **/
14
15 #include "RegisterCpuFeatures.h"
16
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" };
19
20 /**
21 Worker function to save PcdCpuFeaturesCapability.
22
23 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
24 **/
25 VOID
26 SetCapabilityPcd (
27 IN UINT8 *SupportedFeatureMask
28 )
29 {
30 EFI_STATUS Status;
31 UINTN BitMaskSize;
32
33 BitMaskSize = PcdGetSize (PcdCpuFeaturesCapability);
34 Status = PcdSetPtrS (PcdCpuFeaturesCapability, &BitMaskSize, SupportedFeatureMask);
35 ASSERT_EFI_ERROR (Status);
36 }
37
38 /**
39 Worker function to save PcdCpuFeaturesSetting.
40
41 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
42 **/
43 VOID
44 SetSettingPcd (
45 IN UINT8 *SupportedFeatureMask
46 )
47 {
48 EFI_STATUS Status;
49 UINTN BitMaskSize;
50
51 BitMaskSize = PcdGetSize (PcdCpuFeaturesSetting);
52 Status = PcdSetPtrS (PcdCpuFeaturesSetting, &BitMaskSize, SupportedFeatureMask);
53 ASSERT_EFI_ERROR (Status);
54 }
55
56 /**
57 Worker function to get PcdCpuFeaturesSupport.
58
59 @return The pointer to CPU feature bits mask buffer.
60 **/
61 UINT8 *
62 GetSupportPcd (
63 VOID
64 )
65 {
66 UINT8 *SupportBitMask;
67
68 SupportBitMask = AllocateCopyPool (
69 PcdGetSize (PcdCpuFeaturesSupport),
70 PcdGetPtr (PcdCpuFeaturesSupport)
71 );
72 ASSERT (SupportBitMask != NULL);
73
74 return SupportBitMask;
75 }
76
77 /**
78 Worker function to get PcdCpuFeaturesUserConfiguration.
79
80 @return The pointer to CPU feature bits mask buffer.
81 **/
82 UINT8 *
83 GetConfigurationPcd (
84 VOID
85 )
86 {
87 UINT8 *SupportBitMask;
88
89 SupportBitMask = AllocateCopyPool (
90 PcdGetSize (PcdCpuFeaturesUserConfiguration),
91 PcdGetPtr (PcdCpuFeaturesUserConfiguration)
92 );
93 ASSERT (SupportBitMask != NULL);
94
95 return SupportBitMask;
96 }
97
98 /**
99 Collects CPU type and feature information.
100
101 @param[in, out] CpuInfo The pointer to CPU feature information
102 **/
103 VOID
104 FillProcessorInfo (
105 IN OUT REGISTER_CPU_FEATURE_INFORMATION *CpuInfo
106 )
107 {
108 CPUID_VERSION_INFO_EAX Eax;
109 CPUID_VERSION_INFO_ECX Ecx;
110 CPUID_VERSION_INFO_EDX Edx;
111 UINT32 DisplayedFamily;
112 UINT32 DisplayedModel;
113
114 AsmCpuid (CPUID_VERSION_INFO, &Eax.Uint32, NULL, &Ecx.Uint32, &Edx.Uint32);
115
116 DisplayedFamily = Eax.Bits.FamilyId;
117 if (Eax.Bits.FamilyId == 0x0F) {
118 DisplayedFamily |= (Eax.Bits.ExtendedFamilyId << 4);
119 }
120
121 DisplayedModel = Eax.Bits.Model;
122 if (Eax.Bits.FamilyId == 0x06 || Eax.Bits.FamilyId == 0x0f) {
123 DisplayedModel |= (Eax.Bits.ExtendedModelId << 4);
124 }
125
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;
132 }
133
134 /**
135 Prepares for private data used for CPU features.
136
137 **/
138 VOID
139 CpuInitDataInitialize (
140 VOID
141 )
142 {
143 EFI_STATUS Status;
144 UINTN ProcessorNumber;
145 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;
146 CPU_FEATURES_ENTRY *CpuFeature;
147 CPU_FEATURES_INIT_ORDER *InitOrder;
148 CPU_FEATURES_DATA *CpuFeaturesData;
149 LIST_ENTRY *Entry;
150 UINT32 Core;
151 UINT32 Package;
152 UINT32 Thread;
153 EFI_CPU_PHYSICAL_LOCATION *Location;
154 BOOLEAN *CoresVisited;
155 UINTN Index;
156 ACPI_CPU_DATA *AcpiCpuData;
157 CPU_STATUS_INFORMATION *CpuStatus;
158 UINT32 *ValidCoreCountPerPackage;
159 UINTN NumberOfCpus;
160 UINTN NumberOfEnabledProcessors;
161
162 Core = 0;
163 Package = 0;
164 Thread = 0;
165
166 CpuFeaturesData = GetCpuFeaturesData ();
167
168 //
169 // Initialize CpuFeaturesData->MpService as early as possile, so later function can use it.
170 //
171 CpuFeaturesData->MpService = GetMpService ();
172
173 GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);
174
175 CpuFeaturesData->InitOrder = AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER) * NumberOfCpus);
176 ASSERT (CpuFeaturesData->InitOrder != NULL);
177
178 //
179 // Collect CPU Features information
180 //
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);
187 }
188 Entry = Entry->ForwardLink;
189 }
190
191 CpuFeaturesData->NumberOfCpus = (UINT32) NumberOfCpus;
192
193 AcpiCpuData = GetAcpiCpuData ();
194 ASSERT (AcpiCpuData != NULL);
195 CpuFeaturesData->AcpiCpuData= AcpiCpuData;
196
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;
201
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);
209 CopyMem (
210 &InitOrder->CpuInfo.ProcessorInfo,
211 &ProcessorInfoBuffer,
212 sizeof (EFI_PROCESSOR_INFORMATION)
213 );
214 CopyMem (
215 &Location[ProcessorNumber],
216 &ProcessorInfoBuffer.Location,
217 sizeof (EFI_CPU_PHYSICAL_LOCATION)
218 );
219
220 //
221 // Collect CPU package count info.
222 //
223 if (Package < ProcessorInfoBuffer.Location.Package) {
224 Package = ProcessorInfoBuffer.Location.Package;
225 }
226 //
227 // Collect CPU max core count info.
228 //
229 if (Core < ProcessorInfoBuffer.Location.Core) {
230 Core = ProcessorInfoBuffer.Location.Core;
231 }
232 //
233 // Collect CPU max thread count info.
234 //
235 if (Thread < ProcessorInfoBuffer.Location.Thread) {
236 Thread = ProcessorInfoBuffer.Location.Thread;
237 }
238 }
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));
246
247 //
248 // Collect valid core count in each package because not all cores are valid.
249 //
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);
255
256 for (Index = 0; Index < CpuStatus->PackageCount; Index ++ ) {
257 ZeroMem (CoresVisited, sizeof (BOOLEAN) * CpuStatus->MaxCoreCount);
258 //
259 // Collect valid cores in Current package.
260 //
261 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
262 Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;
263 if (Location->Package == Index && !CoresVisited[Location->Core] ) {
264 //
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.
269 //
270 CoresVisited[Location->Core] = TRUE;
271 ValidCoreCountPerPackage[Index]++;
272 }
273 }
274 }
275 FreePool (CoresVisited);
276
277 for (Index = 0; Index <= Package; Index++) {
278 DEBUG ((DEBUG_INFO, "Package: %d, Valid Core : %d\n", Index, ValidCoreCountPerPackage[Index]));
279 }
280
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);
285
286 //
287 // Get support and configuration PCDs
288 //
289 CpuFeaturesData->SupportPcd = GetSupportPcd ();
290 CpuFeaturesData->ConfigurationPcd = GetConfigurationPcd ();
291 }
292
293 /**
294 Worker function to do OR operation on CPU feature supported bits mask buffer.
295
296 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
297 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
298 **/
299 VOID
300 SupportedMaskOr (
301 IN UINT8 *SupportedFeatureMask,
302 IN UINT8 *OrFeatureBitMask
303 )
304 {
305 UINTN Index;
306 UINTN BitMaskSize;
307 UINT8 *Data1;
308 UINT8 *Data2;
309
310 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
311 Data1 = SupportedFeatureMask;
312 Data2 = OrFeatureBitMask;
313 for (Index = 0; Index < BitMaskSize; Index++) {
314 *(Data1++) |= *(Data2++);
315 }
316 }
317
318 /**
319 Worker function to do AND operation on CPU feature supported bits mask buffer.
320
321 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
322 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
323 **/
324 VOID
325 SupportedMaskAnd (
326 IN UINT8 *SupportedFeatureMask,
327 IN UINT8 *AndFeatureBitMask
328 )
329 {
330 UINTN Index;
331 UINTN BitMaskSize;
332 UINT8 *Data1;
333 UINT8 *Data2;
334
335 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
336 Data1 = SupportedFeatureMask;
337 Data2 = AndFeatureBitMask;
338 for (Index = 0; Index < BitMaskSize; Index++) {
339 *(Data1++) &= *(Data2++);
340 }
341 }
342
343 /**
344 Worker function to clean bit operation on CPU feature supported bits mask buffer.
345
346 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
347 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
348 **/
349 VOID
350 SupportedMaskCleanBit (
351 IN UINT8 *SupportedFeatureMask,
352 IN UINT8 *AndFeatureBitMask
353 )
354 {
355 UINTN Index;
356 UINTN BitMaskSize;
357 UINT8 *Data1;
358 UINT8 *Data2;
359
360 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
361 Data1 = SupportedFeatureMask;
362 Data2 = AndFeatureBitMask;
363 for (Index = 0; Index < BitMaskSize; Index++) {
364 *(Data1++) &= ~(*(Data2++));
365 }
366 }
367
368 /**
369 Worker function to check if the compared CPU feature set in the CPU feature
370 supported bits mask buffer.
371
372 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
373 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
374
375 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
376 mask buffer.
377 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
378 mask buffer.
379 **/
380 BOOLEAN
381 IsBitMaskMatch (
382 IN UINT8 *SupportedFeatureMask,
383 IN UINT8 *ComparedFeatureBitMask
384 )
385 {
386 UINTN Index;
387 UINTN BitMaskSize;
388 UINT8 *Data1;
389 UINT8 *Data2;
390
391 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
392
393 Data1 = SupportedFeatureMask;
394 Data2 = ComparedFeatureBitMask;
395 for (Index = 0; Index < BitMaskSize; Index++) {
396 if (((*(Data1++)) & (*(Data2++))) != 0) {
397 return TRUE;
398 }
399 }
400 return FALSE;
401 }
402
403 /**
404 Collects processor data for calling processor.
405
406 @param[in,out] Buffer The pointer to private data buffer.
407 **/
408 VOID
409 EFIAPI
410 CollectProcessorData (
411 IN OUT VOID *Buffer
412 )
413 {
414 UINTN ProcessorNumber;
415 CPU_FEATURES_ENTRY *CpuFeature;
416 REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;
417 LIST_ENTRY *Entry;
418 CPU_FEATURES_DATA *CpuFeaturesData;
419
420 CpuFeaturesData = (CPU_FEATURES_DATA *)Buffer;
421 ProcessorNumber = GetProcessorIndex (CpuFeaturesData);
422 CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;
423 //
424 // collect processor information
425 //
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) {
432 //
433 // If SupportFunc is NULL, then the feature is supported.
434 //
435 SupportedMaskOr (
436 CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
437 CpuFeature->FeatureMask
438 );
439 } else if (CpuFeature->SupportFunc (ProcessorNumber, CpuInfo, CpuFeature->ConfigData)) {
440 SupportedMaskOr (
441 CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
442 CpuFeature->FeatureMask
443 );
444 }
445 }
446 Entry = Entry->ForwardLink;
447 }
448 }
449
450 /**
451 Dump the contents of a CPU register table.
452
453 @param[in] ProcessorNumber The index of the CPU to show the register table contents
454
455 @note This service could be called by BSP only.
456 **/
457 VOID
458 DumpRegisterTableOnProcessor (
459 IN UINTN ProcessorNumber
460 )
461 {
462 CPU_FEATURES_DATA *CpuFeaturesData;
463 UINTN FeatureIndex;
464 CPU_REGISTER_TABLE *RegisterTable;
465 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
466 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
467 UINT32 DebugPrintErrorLevel;
468
469 DebugPrintErrorLevel = (ProcessorNumber == 0) ? DEBUG_INFO : DEBUG_VERBOSE;
470 CpuFeaturesData = GetCpuFeaturesData ();
471 //
472 // Debug information
473 //
474 RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];
475 DEBUG ((DebugPrintErrorLevel, "RegisterTable->TableLength = %d\n", RegisterTable->TableLength));
476
477 RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
478
479 for (FeatureIndex = 0; FeatureIndex < RegisterTable->TableLength; FeatureIndex++) {
480 RegisterTableEntry = &RegisterTableEntryHead[FeatureIndex];
481 switch (RegisterTableEntry->RegisterType) {
482 case Msr:
483 DEBUG ((
484 DebugPrintErrorLevel,
485 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
486 ProcessorNumber,
487 FeatureIndex,
488 RegisterTableEntry->Index,
489 RegisterTableEntry->ValidBitStart,
490 RegisterTableEntry->ValidBitLength,
491 RegisterTableEntry->Value
492 ));
493 break;
494 case ControlRegister:
495 DEBUG ((
496 DebugPrintErrorLevel,
497 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
498 ProcessorNumber,
499 FeatureIndex,
500 RegisterTableEntry->Index,
501 RegisterTableEntry->ValidBitStart,
502 RegisterTableEntry->ValidBitLength,
503 RegisterTableEntry->Value
504 ));
505 break;
506 case MemoryMapped:
507 DEBUG ((
508 DebugPrintErrorLevel,
509 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
510 ProcessorNumber,
511 FeatureIndex,
512 RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32),
513 RegisterTableEntry->ValidBitStart,
514 RegisterTableEntry->ValidBitLength,
515 RegisterTableEntry->Value
516 ));
517 break;
518 case CacheControl:
519 DEBUG ((
520 DebugPrintErrorLevel,
521 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
522 ProcessorNumber,
523 FeatureIndex,
524 RegisterTableEntry->Index,
525 RegisterTableEntry->ValidBitStart,
526 RegisterTableEntry->ValidBitLength,
527 RegisterTableEntry->Value
528 ));
529 break;
530 case Semaphore:
531 DEBUG ((
532 DebugPrintErrorLevel,
533 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
534 ProcessorNumber,
535 FeatureIndex,
536 mDependTypeStr[MIN ((UINT32)RegisterTableEntry->Value, InvalidDepType)]
537 ));
538 break;
539
540 default:
541 break;
542 }
543 }
544 }
545
546 /**
547 Get the biggest dependence type.
548 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
549
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.
554
555 @retval Return the biggest dependence type.
556 **/
557 CPU_FEATURE_DEPENDENCE_TYPE
558 BiggestDep (
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
563 )
564 {
565 CPU_FEATURE_DEPENDENCE_TYPE Bigger;
566
567 Bigger = MAX (BeforeDep, AfterDep);
568 Bigger = MAX (Bigger, NoneNeibBeforeDep);
569 return MAX(Bigger, NoneNeibAfterDep);
570 }
571
572 /**
573 Analysis register CPU features on each processor and save CPU setting in CPU register table.
574
575 @param[in] NumberOfCpus Number of processor in system
576
577 **/
578 VOID
579 AnalysisProcessorFeatures (
580 IN UINTN NumberOfCpus
581 )
582 {
583 EFI_STATUS Status;
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;
589 LIST_ENTRY *Entry;
590 CPU_FEATURES_DATA *CpuFeaturesData;
591 LIST_ENTRY *NextEntry;
592 CPU_FEATURES_ENTRY *NextCpuFeatureInOrder;
593 BOOLEAN Success;
594 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep;
595 CPU_FEATURE_DEPENDENCE_TYPE AfterDep;
596 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep;
597 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep;
598
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];
605 //
606 // Calculate the last capability on all processors
607 //
608 SupportedMaskAnd (CpuFeaturesData->CapabilityPcd, CpuInitOrder->FeaturesSupportedMask);
609 }
610 //
611 // Calculate the last setting
612 //
613
614 CpuFeaturesData->SettingPcd = AllocateCopyPool (CpuFeaturesData->BitMaskSize, CpuFeaturesData->CapabilityPcd);
615 ASSERT (CpuFeaturesData->SettingPcd != NULL);
616 SupportedMaskAnd (CpuFeaturesData->SettingPcd, CpuFeaturesData->ConfigurationPcd);
617
618 //
619 // Save PCDs and display CPU PCDs
620 //
621 SetCapabilityPcd (CpuFeaturesData->CapabilityPcd);
622 SetSettingPcd (CpuFeaturesData->SettingPcd);
623
624 //
625 // Dump the last CPU feature list
626 //
627 DEBUG_CODE (
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 ] "));
635 } else {
636 DEBUG ((DEBUG_INFO, "[Disable ] "));
637 }
638 } else {
639 DEBUG ((DEBUG_INFO, "[Unsupport] "));
640 }
641 DumpCpuFeature (CpuFeature);
642 Entry = Entry->ForwardLink;
643 }
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);
652 );
653
654 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
655 CpuInitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
656 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
657 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
658 //
659 // Insert each feature into processor's order list
660 //
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);
666 }
667 Entry = Entry->ForwardLink;
668 }
669 //
670 // Go through ordered feature list to initialize CPU features
671 //
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);
676
677 Success = FALSE;
678 if (IsBitMaskMatch (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->SettingPcd)) {
679 Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, TRUE);
680 if (EFI_ERROR (Status)) {
681 //
682 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
683 //
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));
687 } else {
688 DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Mask = "));
689 DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);
690 }
691 } else {
692 Success = TRUE;
693 }
694 } else {
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));
699 } else {
700 DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Mask = "));
701 DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);
702 }
703 } else {
704 Success = TRUE;
705 }
706 }
707
708 if (Success) {
709 NextEntry = Entry->ForwardLink;
710 if (!IsNull (&CpuInitOrder->OrderList, NextEntry)) {
711 NextCpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);
712
713 //
714 // If feature has dependence with the next feature (ONLY care core/package dependency).
715 // and feature initialize succeed, add sync semaphere here.
716 //
717 BeforeDep = DetectFeatureScope (CpuFeatureInOrder, TRUE, NextCpuFeatureInOrder->FeatureMask);
718 AfterDep = DetectFeatureScope (NextCpuFeatureInOrder, FALSE, CpuFeatureInOrder->FeatureMask);
719 //
720 // Check whether next feature has After type dependence with not neighborhood CPU
721 // Features in former CPU features.
722 //
723 NoneNeibAfterDep = DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder, FALSE, &CpuInitOrder->OrderList);
724 } else {
725 BeforeDep = NoneDepType;
726 AfterDep = NoneDepType;
727 NoneNeibAfterDep = NoneDepType;
728 }
729 //
730 // Check whether current feature has Before type dependence with none neighborhood
731 // CPU features in after Cpu features.
732 //
733 NoneNeibBeforeDep = DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder, TRUE, &CpuInitOrder->OrderList);
734
735 //
736 // Get the biggest dependence and add semaphore for it.
737 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
738 //
739 BeforeDep = BiggestDep(BeforeDep, AfterDep, NoneNeibBeforeDep, NoneNeibAfterDep);
740 if (BeforeDep > ThreadDepType) {
741 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber, Semaphore, 0, BeforeDep);
742 }
743 }
744
745 Entry = Entry->ForwardLink;
746 }
747
748 //
749 // Dump PcdCpuFeaturesSetting again because this value maybe updated
750 // again during initialize the features.
751 //
752 DEBUG ((DEBUG_INFO, "Dump final value for PcdCpuFeaturesSetting:\n"));
753 DumpCpuFeatureMask (CpuFeaturesData->SettingPcd);
754
755 //
756 // Dump the RegisterTable
757 //
758 DumpRegisterTableOnProcessor (ProcessorNumber);
759 }
760 }
761
762 /**
763 Increment semaphore by 1.
764
765 @param Sem IN: 32-bit unsigned integer
766
767 **/
768 VOID
769 LibReleaseSemaphore (
770 IN OUT volatile UINT32 *Sem
771 )
772 {
773 InterlockedIncrement (Sem);
774 }
775
776 /**
777 Decrement the semaphore by 1 if it is not zero.
778
779 Performs an atomic decrement operation for semaphore.
780 The compare exchange operation must be performed using
781 MP safe mechanisms.
782
783 @param Sem IN: 32-bit unsigned integer
784
785 **/
786 VOID
787 LibWaitForSemaphore (
788 IN OUT volatile UINT32 *Sem
789 )
790 {
791 UINT32 Value;
792
793 do {
794 Value = *Sem;
795 } while (Value == 0 ||
796 InterlockedCompareExchange32 (
797 Sem,
798 Value,
799 Value - 1
800 ) != Value);
801 }
802
803 /**
804 Initialize the CPU registers from a register table.
805
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.
810
811 @note This service could be called by BSP/APs.
812 **/
813 VOID
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
819 )
820 {
821 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
822 UINTN Index;
823 UINTN Value;
824 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
825 volatile UINT32 *SemaphorePtr;
826 UINT32 FirstThread;
827 UINT32 PackageThreadsCount;
828 UINT32 CurrentThread;
829 UINTN ProcessorIndex;
830 UINTN ThreadIndex;
831 UINTN ValidThreadCount;
832 UINT32 *ValidCoreCountPerPackage;
833
834 //
835 // Traverse Register Table of this logical processor
836 //
837 RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
838
839 for (Index = 0; Index < RegisterTable->TableLength; Index++) {
840
841 RegisterTableEntry = &RegisterTableEntryHead[Index];
842
843 DEBUG_CODE_BEGIN ();
844 //
845 // Wait for the AP to release the MSR spin lock.
846 //
847 while (!AcquireSpinLockOrFail (&CpuFlags->ConsoleLogLock)) {
848 CpuPause ();
849 }
850 ThreadIndex = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount +
851 ApLocation->Core * CpuStatus->MaxThreadCount +
852 ApLocation->Thread;
853 DEBUG ((
854 DEBUG_INFO,
855 "Processor = %08lu, Index %08lu, Type = %s!\n",
856 (UINT64)ThreadIndex,
857 (UINT64)Index,
858 mRegisterTypeStr[MIN ((REGISTER_TYPE)RegisterTableEntry->RegisterType, InvalidReg)]
859 ));
860 ReleaseSpinLock (&CpuFlags->ConsoleLogLock);
861 DEBUG_CODE_END ();
862
863 //
864 // Check the type of specified register
865 //
866 switch (RegisterTableEntry->RegisterType) {
867 //
868 // The specified register is Control Register
869 //
870 case ControlRegister:
871 switch (RegisterTableEntry->Index) {
872 case 0:
873 Value = AsmReadCr0 ();
874 Value = (UINTN) BitFieldWrite64 (
875 Value,
876 RegisterTableEntry->ValidBitStart,
877 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
878 RegisterTableEntry->Value
879 );
880 AsmWriteCr0 (Value);
881 break;
882 case 2:
883 Value = AsmReadCr2 ();
884 Value = (UINTN) BitFieldWrite64 (
885 Value,
886 RegisterTableEntry->ValidBitStart,
887 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
888 RegisterTableEntry->Value
889 );
890 AsmWriteCr2 (Value);
891 break;
892 case 3:
893 Value = AsmReadCr3 ();
894 Value = (UINTN) BitFieldWrite64 (
895 Value,
896 RegisterTableEntry->ValidBitStart,
897 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
898 RegisterTableEntry->Value
899 );
900 AsmWriteCr3 (Value);
901 break;
902 case 4:
903 Value = AsmReadCr4 ();
904 Value = (UINTN) BitFieldWrite64 (
905 Value,
906 RegisterTableEntry->ValidBitStart,
907 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
908 RegisterTableEntry->Value
909 );
910 AsmWriteCr4 (Value);
911 break;
912 case 8:
913 //
914 // Do we need to support CR8?
915 //
916 break;
917 default:
918 break;
919 }
920 break;
921 //
922 // The specified register is Model Specific Register
923 //
924 case Msr:
925 if (RegisterTableEntry->ValidBitLength >= 64) {
926 //
927 // If length is not less than 64 bits, then directly write without reading
928 //
929 AsmWriteMsr64 (
930 RegisterTableEntry->Index,
931 RegisterTableEntry->Value
932 );
933 } else {
934 //
935 // Set the bit section according to bit start and length
936 //
937 AsmMsrBitFieldWrite64 (
938 RegisterTableEntry->Index,
939 RegisterTableEntry->ValidBitStart,
940 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
941 RegisterTableEntry->Value
942 );
943 }
944 break;
945 //
946 // MemoryMapped operations
947 //
948 case MemoryMapped:
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
955 );
956 ReleaseSpinLock (&CpuFlags->MemoryMappedLock);
957 break;
958 //
959 // Enable or disable cache
960 //
961 case CacheControl:
962 //
963 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
964 //
965 if (RegisterTableEntry->Value == 0) {
966 AsmDisableCache ();
967 } else {
968 AsmEnableCache ();
969 }
970 break;
971
972 case Semaphore:
973 // Semaphore works logic like below:
974 //
975 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
976 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
977 //
978 // All threads (T0...Tn) waits in P() line and continues running
979 // together.
980 //
981 //
982 // T0 T1 ... Tn
983 //
984 // V(0...n) V(0...n) ... V(0...n)
985 // n * P(0) n * P(1) ... n * P(n)
986 //
987 switch (RegisterTableEntry->Value) {
988 case CoreDepType:
989 SemaphorePtr = CpuFlags->CoreSemaphoreCount;
990 //
991 // Get Offset info for the first thread in the core which current thread belongs to.
992 //
993 FirstThread = (ApLocation->Package * CpuStatus->MaxCoreCount + ApLocation->Core) * CpuStatus->MaxThreadCount;
994 CurrentThread = FirstThread + ApLocation->Thread;
995 //
996 // First Notify all threads in current Core that this thread has ready.
997 //
998 for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {
999 LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);
1000 }
1001 //
1002 // Second, check whether all valid threads in current core have ready.
1003 //
1004 for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {
1005 LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
1006 }
1007 break;
1008
1009 case PackageDepType:
1010 SemaphorePtr = CpuFlags->PackageSemaphoreCount;
1011 ValidCoreCountPerPackage = (UINT32 *)(UINTN)CpuStatus->ValidCoreCountPerPackage;
1012 //
1013 // Get Offset info for the first thread in the package which current thread belongs to.
1014 //
1015 FirstThread = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount;
1016 //
1017 // Get the possible threads count for current package.
1018 //
1019 PackageThreadsCount = CpuStatus->MaxThreadCount * CpuStatus->MaxCoreCount;
1020 CurrentThread = FirstThread + CpuStatus->MaxThreadCount * ApLocation->Core + ApLocation->Thread;
1021 //
1022 // Get the valid thread count for current package.
1023 //
1024 ValidThreadCount = CpuStatus->MaxThreadCount * ValidCoreCountPerPackage[ApLocation->Package];
1025
1026 //
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.
1036 //
1037
1038 //
1039 // First Notify ALL THREADS in current package that this thread has ready.
1040 //
1041 for (ProcessorIndex = 0; ProcessorIndex < PackageThreadsCount ; ProcessorIndex ++) {
1042 LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);
1043 }
1044 //
1045 // Second, check whether VALID THREADS (not all threads) in current package have ready.
1046 //
1047 for (ProcessorIndex = 0; ProcessorIndex < ValidThreadCount; ProcessorIndex ++) {
1048 LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
1049 }
1050 break;
1051
1052 default:
1053 break;
1054 }
1055 break;
1056
1057 default:
1058 break;
1059 }
1060 }
1061 }
1062
1063 /**
1064 Programs registers for the calling processor.
1065
1066 @param[in,out] Buffer The pointer to private data buffer.
1067
1068 **/
1069 VOID
1070 EFIAPI
1071 SetProcessorRegister (
1072 IN OUT VOID *Buffer
1073 )
1074 {
1075 CPU_FEATURES_DATA *CpuFeaturesData;
1076 CPU_REGISTER_TABLE *RegisterTable;
1077 CPU_REGISTER_TABLE *RegisterTables;
1078 UINT32 InitApicId;
1079 UINTN ProcIndex;
1080 UINTN Index;
1081 ACPI_CPU_DATA *AcpiCpuData;
1082
1083 CpuFeaturesData = (CPU_FEATURES_DATA *) Buffer;
1084 AcpiCpuData = CpuFeaturesData->AcpiCpuData;
1085
1086 RegisterTables = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable;
1087
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];
1094 ProcIndex = Index;
1095 break;
1096 }
1097 }
1098 ASSERT (RegisterTable != NULL);
1099
1100 ProgramProcessorRegister (
1101 RegisterTable,
1102 (EFI_CPU_PHYSICAL_LOCATION *)(UINTN)AcpiCpuData->ApLocation + ProcIndex,
1103 &AcpiCpuData->CpuStatus,
1104 &CpuFeaturesData->CpuFlags
1105 );
1106 }
1107
1108 /**
1109 Performs CPU features detection.
1110
1111 This service will invoke MP service to check CPU features'
1112 capabilities on BSP/APs.
1113
1114 @note This service could be called by BSP only.
1115 **/
1116 VOID
1117 EFIAPI
1118 CpuFeaturesDetect (
1119 VOID
1120 )
1121 {
1122 CPU_FEATURES_DATA *CpuFeaturesData;
1123
1124 CpuFeaturesData = GetCpuFeaturesData();
1125
1126 CpuInitDataInitialize ();
1127
1128 //
1129 // Wakeup all APs for data collection.
1130 //
1131 StartupAPsWorker (CollectProcessorData, NULL);
1132
1133 //
1134 // Collect data on BSP
1135 //
1136 CollectProcessorData (CpuFeaturesData);
1137
1138 AnalysisProcessorFeatures (CpuFeaturesData->NumberOfCpus);
1139 }
1140