]> git.proxmox.com Git - mirror_edk2.git/blob - UefiCpuPkg/Library/RegisterCpuFeaturesLib/CpuFeaturesInitialize.c
UefiCpuPkg/RegisterCpuFeaturesLib: Enhance debug message.
[mirror_edk2.git] / UefiCpuPkg / Library / RegisterCpuFeaturesLib / CpuFeaturesInitialize.c
1 /** @file
2 CPU Features Initialize functions.
3
4 Copyright (c) 2017 - 2018, Intel Corporation. All rights reserved.<BR>
5 This program and the accompanying materials
6 are licensed and made available under the terms and conditions of the BSD License
7 which accompanies this distribution. The full text of the license may be found at
8 http://opensource.org/licenses/bsd-license.php
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 @param[in] NumberOfCpus Number of processor in system
138 **/
139 VOID
140 CpuInitDataInitialize (
141 IN UINTN NumberOfCpus
142 )
143 {
144 EFI_STATUS Status;
145 UINTN ProcessorNumber;
146 EFI_PROCESSOR_INFORMATION ProcessorInfoBuffer;
147 CPU_FEATURES_ENTRY *CpuFeature;
148 CPU_FEATURES_INIT_ORDER *InitOrder;
149 CPU_FEATURES_DATA *CpuFeaturesData;
150 LIST_ENTRY *Entry;
151 UINT32 Core;
152 UINT32 Package;
153 UINT32 Thread;
154 EFI_CPU_PHYSICAL_LOCATION *Location;
155 BOOLEAN *CoresVisited;
156 UINTN Index;
157 ACPI_CPU_DATA *AcpiCpuData;
158 CPU_STATUS_INFORMATION *CpuStatus;
159 UINT32 *ValidCoreCountPerPackage;
160
161 Core = 0;
162 Package = 0;
163 Thread = 0;
164
165 CpuFeaturesData = GetCpuFeaturesData ();
166 CpuFeaturesData->InitOrder = AllocateZeroPool (sizeof (CPU_FEATURES_INIT_ORDER) * NumberOfCpus);
167 ASSERT (CpuFeaturesData->InitOrder != NULL);
168
169 //
170 // Collect CPU Features information
171 //
172 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
173 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
174 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
175 ASSERT (CpuFeature->InitializeFunc != NULL);
176 if (CpuFeature->GetConfigDataFunc != NULL) {
177 CpuFeature->ConfigData = CpuFeature->GetConfigDataFunc (NumberOfCpus);
178 }
179 Entry = Entry->ForwardLink;
180 }
181
182 CpuFeaturesData->NumberOfCpus = (UINT32) NumberOfCpus;
183
184 AcpiCpuData = GetAcpiCpuData ();
185 ASSERT (AcpiCpuData != NULL);
186 CpuFeaturesData->AcpiCpuData= AcpiCpuData;
187
188 CpuStatus = &AcpiCpuData->CpuStatus;
189 Location = AllocateZeroPool (sizeof (EFI_CPU_PHYSICAL_LOCATION) * NumberOfCpus);
190 ASSERT (Location != NULL);
191 AcpiCpuData->ApLocation = (EFI_PHYSICAL_ADDRESS)(UINTN)Location;
192
193 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
194 InitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
195 InitOrder->FeaturesSupportedMask = AllocateZeroPool (CpuFeaturesData->BitMaskSize);
196 ASSERT (InitOrder->FeaturesSupportedMask != NULL);
197 InitializeListHead (&InitOrder->OrderList);
198 Status = GetProcessorInformation (ProcessorNumber, &ProcessorInfoBuffer);
199 ASSERT_EFI_ERROR (Status);
200 CopyMem (
201 &InitOrder->CpuInfo.ProcessorInfo,
202 &ProcessorInfoBuffer,
203 sizeof (EFI_PROCESSOR_INFORMATION)
204 );
205 CopyMem (
206 &Location[ProcessorNumber],
207 &ProcessorInfoBuffer.Location,
208 sizeof (EFI_CPU_PHYSICAL_LOCATION)
209 );
210
211 //
212 // Collect CPU package count info.
213 //
214 if (Package < ProcessorInfoBuffer.Location.Package) {
215 Package = ProcessorInfoBuffer.Location.Package;
216 }
217 //
218 // Collect CPU max core count info.
219 //
220 if (Core < ProcessorInfoBuffer.Location.Core) {
221 Core = ProcessorInfoBuffer.Location.Core;
222 }
223 //
224 // Collect CPU max thread count info.
225 //
226 if (Thread < ProcessorInfoBuffer.Location.Thread) {
227 Thread = ProcessorInfoBuffer.Location.Thread;
228 }
229 }
230 CpuStatus->PackageCount = Package + 1;
231 CpuStatus->MaxCoreCount = Core + 1;
232 CpuStatus->MaxThreadCount = Thread + 1;
233 DEBUG ((DEBUG_INFO, "Processor Info: Package: %d, MaxCore : %d, MaxThread: %d\n",
234 CpuStatus->PackageCount,
235 CpuStatus->MaxCoreCount,
236 CpuStatus->MaxThreadCount));
237
238 //
239 // Collect valid core count in each package because not all cores are valid.
240 //
241 ValidCoreCountPerPackage= AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount);
242 ASSERT (ValidCoreCountPerPackage != 0);
243 CpuStatus->ValidCoreCountPerPackage = (EFI_PHYSICAL_ADDRESS)(UINTN)ValidCoreCountPerPackage;
244 CoresVisited = AllocatePool (sizeof (BOOLEAN) * CpuStatus->MaxCoreCount);
245 ASSERT (CoresVisited != NULL);
246
247 for (Index = 0; Index < CpuStatus->PackageCount; Index ++ ) {
248 ZeroMem (CoresVisited, sizeof (BOOLEAN) * CpuStatus->MaxCoreCount);
249 //
250 // Collect valid cores in Current package.
251 //
252 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
253 Location = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo.ProcessorInfo.Location;
254 if (Location->Package == Index && !CoresVisited[Location->Core] ) {
255 //
256 // The ValidCores position for Location->Core is valid.
257 // The possible values in ValidCores[Index] are 0 or 1.
258 // FALSE means no valid threads in this Core.
259 // TRUE means have valid threads in this core, no matter the thead count is 1 or more.
260 //
261 CoresVisited[Location->Core] = TRUE;
262 ValidCoreCountPerPackage[Index]++;
263 }
264 }
265 }
266 FreePool (CoresVisited);
267
268 for (Index = 0; Index <= Package; Index++) {
269 DEBUG ((DEBUG_INFO, "Package: %d, Valid Core : %d\n", Index, ValidCoreCountPerPackage[Index]));
270 }
271
272 CpuFeaturesData->CpuFlags.CoreSemaphoreCount = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount);
273 ASSERT (CpuFeaturesData->CpuFlags.CoreSemaphoreCount != NULL);
274 CpuFeaturesData->CpuFlags.PackageSemaphoreCount = AllocateZeroPool (sizeof (UINT32) * CpuStatus->PackageCount * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount);
275 ASSERT (CpuFeaturesData->CpuFlags.PackageSemaphoreCount != NULL);
276
277 //
278 // Get support and configuration PCDs
279 //
280 CpuFeaturesData->SupportPcd = GetSupportPcd ();
281 CpuFeaturesData->ConfigurationPcd = GetConfigurationPcd ();
282 }
283
284 /**
285 Worker function to do OR operation on CPU feature supported bits mask buffer.
286
287 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
288 @param[in] OrFeatureBitMask The feature bit mask to do OR operation
289 **/
290 VOID
291 SupportedMaskOr (
292 IN UINT8 *SupportedFeatureMask,
293 IN UINT8 *OrFeatureBitMask
294 )
295 {
296 UINTN Index;
297 UINTN BitMaskSize;
298 UINT8 *Data1;
299 UINT8 *Data2;
300
301 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
302 Data1 = SupportedFeatureMask;
303 Data2 = OrFeatureBitMask;
304 for (Index = 0; Index < BitMaskSize; Index++) {
305 *(Data1++) |= *(Data2++);
306 }
307 }
308
309 /**
310 Worker function to do AND operation on CPU feature supported bits mask buffer.
311
312 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
313 @param[in] AndFeatureBitMask The feature bit mask to do AND operation
314 **/
315 VOID
316 SupportedMaskAnd (
317 IN UINT8 *SupportedFeatureMask,
318 IN UINT8 *AndFeatureBitMask
319 )
320 {
321 UINTN Index;
322 UINTN BitMaskSize;
323 UINT8 *Data1;
324 UINT8 *Data2;
325
326 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
327 Data1 = SupportedFeatureMask;
328 Data2 = AndFeatureBitMask;
329 for (Index = 0; Index < BitMaskSize; Index++) {
330 *(Data1++) &= *(Data2++);
331 }
332 }
333
334 /**
335 Worker function to clean bit operation on CPU feature supported bits mask buffer.
336
337 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
338 @param[in] AndFeatureBitMask The feature bit mask to do XOR operation
339 **/
340 VOID
341 SupportedMaskCleanBit (
342 IN UINT8 *SupportedFeatureMask,
343 IN UINT8 *AndFeatureBitMask
344 )
345 {
346 UINTN Index;
347 UINTN BitMaskSize;
348 UINT8 *Data1;
349 UINT8 *Data2;
350
351 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
352 Data1 = SupportedFeatureMask;
353 Data2 = AndFeatureBitMask;
354 for (Index = 0; Index < BitMaskSize; Index++) {
355 *(Data1++) &= ~(*(Data2++));
356 }
357 }
358
359 /**
360 Worker function to check if the compared CPU feature set in the CPU feature
361 supported bits mask buffer.
362
363 @param[in] SupportedFeatureMask The pointer to CPU feature bits mask buffer
364 @param[in] ComparedFeatureBitMask The feature bit mask to be compared
365
366 @retval TRUE The ComparedFeatureBitMask is set in CPU feature supported bits
367 mask buffer.
368 @retval FALSE The ComparedFeatureBitMask is not set in CPU feature supported bits
369 mask buffer.
370 **/
371 BOOLEAN
372 IsBitMaskMatch (
373 IN UINT8 *SupportedFeatureMask,
374 IN UINT8 *ComparedFeatureBitMask
375 )
376 {
377 UINTN Index;
378 UINTN BitMaskSize;
379 UINT8 *Data1;
380 UINT8 *Data2;
381
382 BitMaskSize = PcdGetSize (PcdCpuFeaturesSupport);
383
384 Data1 = SupportedFeatureMask;
385 Data2 = ComparedFeatureBitMask;
386 for (Index = 0; Index < BitMaskSize; Index++) {
387 if (((*(Data1++)) & (*(Data2++))) != 0) {
388 return TRUE;
389 }
390 }
391 return FALSE;
392 }
393
394 /**
395 Collects processor data for calling processor.
396
397 @param[in,out] Buffer The pointer to private data buffer.
398 **/
399 VOID
400 EFIAPI
401 CollectProcessorData (
402 IN OUT VOID *Buffer
403 )
404 {
405 UINTN ProcessorNumber;
406 CPU_FEATURES_ENTRY *CpuFeature;
407 REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;
408 LIST_ENTRY *Entry;
409 CPU_FEATURES_DATA *CpuFeaturesData;
410
411 CpuFeaturesData = (CPU_FEATURES_DATA *)Buffer;
412 ProcessorNumber = GetProcessorIndex ();
413 CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;
414 //
415 // collect processor information
416 //
417 FillProcessorInfo (CpuInfo);
418 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
419 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
420 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
421 if (IsBitMaskMatch (CpuFeaturesData->SupportPcd, CpuFeature->FeatureMask)) {
422 if (CpuFeature->SupportFunc == NULL) {
423 //
424 // If SupportFunc is NULL, then the feature is supported.
425 //
426 SupportedMaskOr (
427 CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
428 CpuFeature->FeatureMask
429 );
430 } else if (CpuFeature->SupportFunc (ProcessorNumber, CpuInfo, CpuFeature->ConfigData)) {
431 SupportedMaskOr (
432 CpuFeaturesData->InitOrder[ProcessorNumber].FeaturesSupportedMask,
433 CpuFeature->FeatureMask
434 );
435 }
436 }
437 Entry = Entry->ForwardLink;
438 }
439 }
440
441 /**
442 Dump the contents of a CPU register table.
443
444 @param[in] ProcessorNumber The index of the CPU to show the register table contents
445
446 @note This service could be called by BSP only.
447 **/
448 VOID
449 DumpRegisterTableOnProcessor (
450 IN UINTN ProcessorNumber
451 )
452 {
453 CPU_FEATURES_DATA *CpuFeaturesData;
454 UINTN FeatureIndex;
455 CPU_REGISTER_TABLE *RegisterTable;
456 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
457 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
458 UINT32 DebugPrintErrorLevel;
459
460 DebugPrintErrorLevel = (ProcessorNumber == 0) ? DEBUG_INFO : DEBUG_VERBOSE;
461 CpuFeaturesData = GetCpuFeaturesData ();
462 //
463 // Debug information
464 //
465 RegisterTable = &CpuFeaturesData->RegisterTable[ProcessorNumber];
466 DEBUG ((DebugPrintErrorLevel, "RegisterTable->TableLength = %d\n", RegisterTable->TableLength));
467
468 RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
469
470 for (FeatureIndex = 0; FeatureIndex < RegisterTable->TableLength; FeatureIndex++) {
471 RegisterTableEntry = &RegisterTableEntryHead[FeatureIndex];
472 switch (RegisterTableEntry->RegisterType) {
473 case Msr:
474 DEBUG ((
475 DebugPrintErrorLevel,
476 "Processor: %04d: Index %04d, MSR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
477 ProcessorNumber,
478 FeatureIndex,
479 RegisterTableEntry->Index,
480 RegisterTableEntry->ValidBitStart,
481 RegisterTableEntry->ValidBitLength,
482 RegisterTableEntry->Value
483 ));
484 break;
485 case ControlRegister:
486 DEBUG ((
487 DebugPrintErrorLevel,
488 "Processor: %04d: Index %04d, CR : %08x, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
489 ProcessorNumber,
490 FeatureIndex,
491 RegisterTableEntry->Index,
492 RegisterTableEntry->ValidBitStart,
493 RegisterTableEntry->ValidBitLength,
494 RegisterTableEntry->Value
495 ));
496 break;
497 case MemoryMapped:
498 DEBUG ((
499 DebugPrintErrorLevel,
500 "Processor: %04d: Index %04d, MMIO : %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
501 ProcessorNumber,
502 FeatureIndex,
503 RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32),
504 RegisterTableEntry->ValidBitStart,
505 RegisterTableEntry->ValidBitLength,
506 RegisterTableEntry->Value
507 ));
508 break;
509 case CacheControl:
510 DEBUG ((
511 DebugPrintErrorLevel,
512 "Processor: %04d: Index %04d, CACHE: %08lx, Bit Start: %02d, Bit Length: %02d, Value: %016lx\r\n",
513 ProcessorNumber,
514 FeatureIndex,
515 RegisterTableEntry->Index,
516 RegisterTableEntry->ValidBitStart,
517 RegisterTableEntry->ValidBitLength,
518 RegisterTableEntry->Value
519 ));
520 break;
521 case Semaphore:
522 DEBUG ((
523 DebugPrintErrorLevel,
524 "Processor: %04d: Index %04d, SEMAP: %s\r\n",
525 ProcessorNumber,
526 FeatureIndex,
527 mDependTypeStr[MIN ((UINT32)RegisterTableEntry->Value, InvalidDepType)]
528 ));
529 break;
530
531 default:
532 break;
533 }
534 }
535 }
536
537 /**
538 Get the biggest dependence type.
539 PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
540
541 @param[in] BeforeDep Before dependence type.
542 @param[in] AfterDep After dependence type.
543 @param[in] NoneNeibBeforeDep Before dependence type for not neighborhood features.
544 @param[in] NoneNeibAfterDep After dependence type for not neighborhood features.
545
546 @retval Return the biggest dependence type.
547 **/
548 CPU_FEATURE_DEPENDENCE_TYPE
549 BiggestDep (
550 IN CPU_FEATURE_DEPENDENCE_TYPE BeforeDep,
551 IN CPU_FEATURE_DEPENDENCE_TYPE AfterDep,
552 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep,
553 IN CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep
554 )
555 {
556 CPU_FEATURE_DEPENDENCE_TYPE Bigger;
557
558 Bigger = MAX (BeforeDep, AfterDep);
559 Bigger = MAX (Bigger, NoneNeibBeforeDep);
560 return MAX(Bigger, NoneNeibAfterDep);
561 }
562
563 /**
564 Analysis register CPU features on each processor and save CPU setting in CPU register table.
565
566 @param[in] NumberOfCpus Number of processor in system
567
568 **/
569 VOID
570 AnalysisProcessorFeatures (
571 IN UINTN NumberOfCpus
572 )
573 {
574 EFI_STATUS Status;
575 UINTN ProcessorNumber;
576 CPU_FEATURES_ENTRY *CpuFeature;
577 CPU_FEATURES_ENTRY *CpuFeatureInOrder;
578 CPU_FEATURES_INIT_ORDER *CpuInitOrder;
579 REGISTER_CPU_FEATURE_INFORMATION *CpuInfo;
580 LIST_ENTRY *Entry;
581 CPU_FEATURES_DATA *CpuFeaturesData;
582 LIST_ENTRY *NextEntry;
583 CPU_FEATURES_ENTRY *NextCpuFeatureInOrder;
584 BOOLEAN Success;
585 CPU_FEATURE_DEPENDENCE_TYPE BeforeDep;
586 CPU_FEATURE_DEPENDENCE_TYPE AfterDep;
587 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibBeforeDep;
588 CPU_FEATURE_DEPENDENCE_TYPE NoneNeibAfterDep;
589
590 CpuFeaturesData = GetCpuFeaturesData ();
591 CpuFeaturesData->CapabilityPcd = AllocatePool (CpuFeaturesData->BitMaskSize);
592 ASSERT (CpuFeaturesData->CapabilityPcd != NULL);
593 SetMem (CpuFeaturesData->CapabilityPcd, CpuFeaturesData->BitMaskSize, 0xFF);
594 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
595 CpuInitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
596 //
597 // Calculate the last capability on all processors
598 //
599 SupportedMaskAnd (CpuFeaturesData->CapabilityPcd, CpuInitOrder->FeaturesSupportedMask);
600 }
601 //
602 // Calculate the last setting
603 //
604
605 CpuFeaturesData->SettingPcd = AllocateCopyPool (CpuFeaturesData->BitMaskSize, CpuFeaturesData->CapabilityPcd);
606 ASSERT (CpuFeaturesData->SettingPcd != NULL);
607 SupportedMaskAnd (CpuFeaturesData->SettingPcd, CpuFeaturesData->ConfigurationPcd);
608
609 //
610 // Save PCDs and display CPU PCDs
611 //
612 SetCapabilityPcd (CpuFeaturesData->CapabilityPcd);
613 SetSettingPcd (CpuFeaturesData->SettingPcd);
614
615 //
616 // Dump the last CPU feature list
617 //
618 DEBUG_CODE (
619 DEBUG ((DEBUG_INFO, "Last CPU features list...\n"));
620 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
621 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
622 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
623 if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->CapabilityPcd)) {
624 if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->SettingPcd)) {
625 DEBUG ((DEBUG_INFO, "[Enable ] "));
626 } else {
627 DEBUG ((DEBUG_INFO, "[Disable ] "));
628 }
629 } else {
630 DEBUG ((DEBUG_INFO, "[Unsupport] "));
631 }
632 DumpCpuFeature (CpuFeature);
633 Entry = Entry->ForwardLink;
634 }
635 DEBUG ((DEBUG_INFO, "PcdCpuFeaturesSupport:\n"));
636 DumpCpuFeatureMask (CpuFeaturesData->SupportPcd);
637 DEBUG ((DEBUG_INFO, "PcdCpuFeaturesUserConfiguration:\n"));
638 DumpCpuFeatureMask (CpuFeaturesData->ConfigurationPcd);
639 DEBUG ((DEBUG_INFO, "PcdCpuFeaturesCapability:\n"));
640 DumpCpuFeatureMask (CpuFeaturesData->CapabilityPcd);
641 DEBUG ((DEBUG_INFO, "PcdCpuFeaturesSetting:\n"));
642 DumpCpuFeatureMask (CpuFeaturesData->SettingPcd);
643 );
644
645 for (ProcessorNumber = 0; ProcessorNumber < NumberOfCpus; ProcessorNumber++) {
646 CpuInitOrder = &CpuFeaturesData->InitOrder[ProcessorNumber];
647 Entry = GetFirstNode (&CpuFeaturesData->FeatureList);
648 while (!IsNull (&CpuFeaturesData->FeatureList, Entry)) {
649 //
650 // Insert each feature into processor's order list
651 //
652 CpuFeature = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
653 if (IsBitMaskMatch (CpuFeature->FeatureMask, CpuFeaturesData->CapabilityPcd)) {
654 CpuFeatureInOrder = AllocateCopyPool (sizeof (CPU_FEATURES_ENTRY), CpuFeature);
655 ASSERT (CpuFeatureInOrder != NULL);
656 InsertTailList (&CpuInitOrder->OrderList, &CpuFeatureInOrder->Link);
657 }
658 Entry = Entry->ForwardLink;
659 }
660 //
661 // Go through ordered feature list to initialize CPU features
662 //
663 CpuInfo = &CpuFeaturesData->InitOrder[ProcessorNumber].CpuInfo;
664 Entry = GetFirstNode (&CpuInitOrder->OrderList);
665 while (!IsNull (&CpuInitOrder->OrderList, Entry)) {
666 CpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (Entry);
667
668 Success = FALSE;
669 if (IsBitMaskMatch (CpuFeatureInOrder->FeatureMask, CpuFeaturesData->SettingPcd)) {
670 Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, TRUE);
671 if (EFI_ERROR (Status)) {
672 //
673 // Clean the CpuFeatureInOrder->FeatureMask in setting PCD.
674 //
675 SupportedMaskCleanBit (CpuFeaturesData->SettingPcd, CpuFeatureInOrder->FeatureMask);
676 if (CpuFeatureInOrder->FeatureName != NULL) {
677 DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Name = %a.\n", CpuFeatureInOrder->FeatureName));
678 } else {
679 DEBUG ((DEBUG_WARN, "Warning :: Failed to enable Feature: Mask = "));
680 DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);
681 }
682 } else {
683 Success = TRUE;
684 }
685 } else {
686 Status = CpuFeatureInOrder->InitializeFunc (ProcessorNumber, CpuInfo, CpuFeatureInOrder->ConfigData, FALSE);
687 if (EFI_ERROR (Status)) {
688 if (CpuFeatureInOrder->FeatureName != NULL) {
689 DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Name = %a.\n", CpuFeatureInOrder->FeatureName));
690 } else {
691 DEBUG ((DEBUG_WARN, "Warning :: Failed to disable Feature: Mask = "));
692 DumpCpuFeatureMask (CpuFeatureInOrder->FeatureMask);
693 }
694 } else {
695 Success = TRUE;
696 }
697 }
698
699 if (Success) {
700 NextEntry = Entry->ForwardLink;
701 if (!IsNull (&CpuInitOrder->OrderList, NextEntry)) {
702 NextCpuFeatureInOrder = CPU_FEATURE_ENTRY_FROM_LINK (NextEntry);
703
704 //
705 // If feature has dependence with the next feature (ONLY care core/package dependency).
706 // and feature initialize succeed, add sync semaphere here.
707 //
708 BeforeDep = DetectFeatureScope (CpuFeatureInOrder, TRUE, NextCpuFeatureInOrder->FeatureMask);
709 AfterDep = DetectFeatureScope (NextCpuFeatureInOrder, FALSE, CpuFeatureInOrder->FeatureMask);
710 //
711 // Check whether next feature has After type dependence with not neighborhood CPU
712 // Features in former CPU features.
713 //
714 NoneNeibAfterDep = DetectNoneNeighborhoodFeatureScope(NextCpuFeatureInOrder, FALSE, &CpuInitOrder->OrderList);
715 } else {
716 BeforeDep = NoneDepType;
717 AfterDep = NoneDepType;
718 NoneNeibAfterDep = NoneDepType;
719 }
720 //
721 // Check whether current feature has Before type dependence with none neighborhood
722 // CPU features in after Cpu features.
723 //
724 NoneNeibBeforeDep = DetectNoneNeighborhoodFeatureScope(CpuFeatureInOrder, TRUE, &CpuInitOrder->OrderList);
725
726 //
727 // Get the biggest dependence and add semaphore for it.
728 // PackageDepType > CoreDepType > ThreadDepType > NoneDepType.
729 //
730 BeforeDep = BiggestDep(BeforeDep, AfterDep, NoneNeibBeforeDep, NoneNeibAfterDep);
731 if (BeforeDep > ThreadDepType) {
732 CPU_REGISTER_TABLE_WRITE32 (ProcessorNumber, Semaphore, 0, BeforeDep);
733 }
734 }
735
736 Entry = Entry->ForwardLink;
737 }
738
739 //
740 // Dump PcdCpuFeaturesSetting again because this value maybe updated
741 // again during initialize the features.
742 //
743 DEBUG ((DEBUG_INFO, "Dump final value for PcdCpuFeaturesSetting:\n"));
744 DumpCpuFeatureMask (CpuFeaturesData->SettingPcd);
745
746 //
747 // Dump the RegisterTable
748 //
749 DumpRegisterTableOnProcessor (ProcessorNumber);
750 }
751 }
752
753 /**
754 Increment semaphore by 1.
755
756 @param Sem IN: 32-bit unsigned integer
757
758 **/
759 VOID
760 LibReleaseSemaphore (
761 IN OUT volatile UINT32 *Sem
762 )
763 {
764 InterlockedIncrement (Sem);
765 }
766
767 /**
768 Decrement the semaphore by 1 if it is not zero.
769
770 Performs an atomic decrement operation for semaphore.
771 The compare exchange operation must be performed using
772 MP safe mechanisms.
773
774 @param Sem IN: 32-bit unsigned integer
775
776 **/
777 VOID
778 LibWaitForSemaphore (
779 IN OUT volatile UINT32 *Sem
780 )
781 {
782 UINT32 Value;
783
784 do {
785 Value = *Sem;
786 } while (Value == 0 ||
787 InterlockedCompareExchange32 (
788 Sem,
789 Value,
790 Value - 1
791 ) != Value);
792 }
793
794 /**
795 Initialize the CPU registers from a register table.
796
797 @param[in] RegisterTable The register table for this AP.
798 @param[in] ApLocation AP location info for this ap.
799 @param[in] CpuStatus CPU status info for this CPU.
800 @param[in] CpuFlags Flags data structure used when program the register.
801
802 @note This service could be called by BSP/APs.
803 **/
804 VOID
805 ProgramProcessorRegister (
806 IN CPU_REGISTER_TABLE *RegisterTable,
807 IN EFI_CPU_PHYSICAL_LOCATION *ApLocation,
808 IN CPU_STATUS_INFORMATION *CpuStatus,
809 IN PROGRAM_CPU_REGISTER_FLAGS *CpuFlags
810 )
811 {
812 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntry;
813 UINTN Index;
814 UINTN Value;
815 CPU_REGISTER_TABLE_ENTRY *RegisterTableEntryHead;
816 volatile UINT32 *SemaphorePtr;
817 UINT32 FirstThread;
818 UINT32 PackageThreadsCount;
819 UINT32 CurrentThread;
820 UINTN ProcessorIndex;
821 UINTN ThreadIndex;
822 UINTN ValidThreadCount;
823 UINT32 *ValidCoreCountPerPackage;
824
825 //
826 // Traverse Register Table of this logical processor
827 //
828 RegisterTableEntryHead = (CPU_REGISTER_TABLE_ENTRY *) (UINTN) RegisterTable->RegisterTableEntry;
829
830 for (Index = 0; Index < RegisterTable->TableLength; Index++) {
831
832 RegisterTableEntry = &RegisterTableEntryHead[Index];
833
834 DEBUG_CODE_BEGIN ();
835 AcquireSpinLock (&CpuFlags->ConsoleLogLock);
836 ThreadIndex = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount +
837 ApLocation->Core * CpuStatus->MaxThreadCount +
838 ApLocation->Thread;
839 DEBUG ((
840 DEBUG_INFO,
841 "Processor = %08lu, Index %08lu, Type = %s!\n",
842 (UINT64)ThreadIndex,
843 (UINT64)Index,
844 mRegisterTypeStr[MIN ((REGISTER_TYPE)RegisterTableEntry->RegisterType, InvalidReg)]
845 ));
846 ReleaseSpinLock (&CpuFlags->ConsoleLogLock);
847 DEBUG_CODE_END ();
848
849 //
850 // Check the type of specified register
851 //
852 switch (RegisterTableEntry->RegisterType) {
853 //
854 // The specified register is Control Register
855 //
856 case ControlRegister:
857 switch (RegisterTableEntry->Index) {
858 case 0:
859 Value = AsmReadCr0 ();
860 Value = (UINTN) BitFieldWrite64 (
861 Value,
862 RegisterTableEntry->ValidBitStart,
863 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
864 RegisterTableEntry->Value
865 );
866 AsmWriteCr0 (Value);
867 break;
868 case 2:
869 Value = AsmReadCr2 ();
870 Value = (UINTN) BitFieldWrite64 (
871 Value,
872 RegisterTableEntry->ValidBitStart,
873 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
874 RegisterTableEntry->Value
875 );
876 AsmWriteCr2 (Value);
877 break;
878 case 3:
879 Value = AsmReadCr3 ();
880 Value = (UINTN) BitFieldWrite64 (
881 Value,
882 RegisterTableEntry->ValidBitStart,
883 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
884 RegisterTableEntry->Value
885 );
886 AsmWriteCr3 (Value);
887 break;
888 case 4:
889 Value = AsmReadCr4 ();
890 Value = (UINTN) BitFieldWrite64 (
891 Value,
892 RegisterTableEntry->ValidBitStart,
893 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
894 RegisterTableEntry->Value
895 );
896 AsmWriteCr4 (Value);
897 break;
898 case 8:
899 //
900 // Do we need to support CR8?
901 //
902 break;
903 default:
904 break;
905 }
906 break;
907 //
908 // The specified register is Model Specific Register
909 //
910 case Msr:
911 if (RegisterTableEntry->ValidBitLength >= 64) {
912 //
913 // If length is not less than 64 bits, then directly write without reading
914 //
915 AsmWriteMsr64 (
916 RegisterTableEntry->Index,
917 RegisterTableEntry->Value
918 );
919 } else {
920 //
921 // Set the bit section according to bit start and length
922 //
923 AsmMsrBitFieldWrite64 (
924 RegisterTableEntry->Index,
925 RegisterTableEntry->ValidBitStart,
926 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
927 RegisterTableEntry->Value
928 );
929 }
930 break;
931 //
932 // MemoryMapped operations
933 //
934 case MemoryMapped:
935 AcquireSpinLock (&CpuFlags->MemoryMappedLock);
936 MmioBitFieldWrite32 (
937 (UINTN)(RegisterTableEntry->Index | LShiftU64 (RegisterTableEntry->HighIndex, 32)),
938 RegisterTableEntry->ValidBitStart,
939 RegisterTableEntry->ValidBitStart + RegisterTableEntry->ValidBitLength - 1,
940 (UINT32)RegisterTableEntry->Value
941 );
942 ReleaseSpinLock (&CpuFlags->MemoryMappedLock);
943 break;
944 //
945 // Enable or disable cache
946 //
947 case CacheControl:
948 //
949 // If value of the entry is 0, then disable cache. Otherwise, enable cache.
950 //
951 if (RegisterTableEntry->Value == 0) {
952 AsmDisableCache ();
953 } else {
954 AsmEnableCache ();
955 }
956 break;
957
958 case Semaphore:
959 // Semaphore works logic like below:
960 //
961 // V(x) = LibReleaseSemaphore (Semaphore[FirstThread + x]);
962 // P(x) = LibWaitForSemaphore (Semaphore[FirstThread + x]);
963 //
964 // All threads (T0...Tn) waits in P() line and continues running
965 // together.
966 //
967 //
968 // T0 T1 ... Tn
969 //
970 // V(0...n) V(0...n) ... V(0...n)
971 // n * P(0) n * P(1) ... n * P(n)
972 //
973 switch (RegisterTableEntry->Value) {
974 case CoreDepType:
975 SemaphorePtr = CpuFlags->CoreSemaphoreCount;
976 //
977 // Get Offset info for the first thread in the core which current thread belongs to.
978 //
979 FirstThread = (ApLocation->Package * CpuStatus->MaxCoreCount + ApLocation->Core) * CpuStatus->MaxThreadCount;
980 CurrentThread = FirstThread + ApLocation->Thread;
981 //
982 // First Notify all threads in current Core that this thread has ready.
983 //
984 for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {
985 LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);
986 }
987 //
988 // Second, check whether all valid threads in current core have ready.
989 //
990 for (ProcessorIndex = 0; ProcessorIndex < CpuStatus->MaxThreadCount; ProcessorIndex ++) {
991 LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
992 }
993 break;
994
995 case PackageDepType:
996 SemaphorePtr = CpuFlags->PackageSemaphoreCount;
997 ValidCoreCountPerPackage = (UINT32 *)(UINTN)CpuStatus->ValidCoreCountPerPackage;
998 //
999 // Get Offset info for the first thread in the package which current thread belongs to.
1000 //
1001 FirstThread = ApLocation->Package * CpuStatus->MaxCoreCount * CpuStatus->MaxThreadCount;
1002 //
1003 // Get the possible threads count for current package.
1004 //
1005 PackageThreadsCount = CpuStatus->MaxThreadCount * CpuStatus->MaxCoreCount;
1006 CurrentThread = FirstThread + CpuStatus->MaxThreadCount * ApLocation->Core + ApLocation->Thread;
1007 //
1008 // Get the valid thread count for current package.
1009 //
1010 ValidThreadCount = CpuStatus->MaxThreadCount * ValidCoreCountPerPackage[ApLocation->Package];
1011
1012 //
1013 // Different packages may have different valid cores in them. If driver maintail clearly
1014 // cores number in different packages, the logic will be much complicated.
1015 // Here driver just simply records the max core number in all packages and use it as expect
1016 // core number for all packages.
1017 // In below two steps logic, first current thread will Release semaphore for each thread
1018 // in current package. Maybe some threads are not valid in this package, but driver don't
1019 // care. Second, driver will let current thread wait semaphore for all valid threads in
1020 // current package. Because only the valid threads will do release semaphore for this
1021 // thread, driver here only need to wait the valid thread count.
1022 //
1023
1024 //
1025 // First Notify ALL THREADS in current package that this thread has ready.
1026 //
1027 for (ProcessorIndex = 0; ProcessorIndex < PackageThreadsCount ; ProcessorIndex ++) {
1028 LibReleaseSemaphore ((UINT32 *) &SemaphorePtr[FirstThread + ProcessorIndex]);
1029 }
1030 //
1031 // Second, check whether VALID THREADS (not all threads) in current package have ready.
1032 //
1033 for (ProcessorIndex = 0; ProcessorIndex < ValidThreadCount; ProcessorIndex ++) {
1034 LibWaitForSemaphore (&SemaphorePtr[CurrentThread]);
1035 }
1036 break;
1037
1038 default:
1039 break;
1040 }
1041 break;
1042
1043 default:
1044 break;
1045 }
1046 }
1047 }
1048
1049 /**
1050 Programs registers for the calling processor.
1051
1052 @param[in,out] Buffer The pointer to private data buffer.
1053
1054 **/
1055 VOID
1056 EFIAPI
1057 SetProcessorRegister (
1058 IN OUT VOID *Buffer
1059 )
1060 {
1061 CPU_FEATURES_DATA *CpuFeaturesData;
1062 CPU_REGISTER_TABLE *RegisterTable;
1063 CPU_REGISTER_TABLE *RegisterTables;
1064 UINT32 InitApicId;
1065 UINTN ProcIndex;
1066 UINTN Index;
1067 ACPI_CPU_DATA *AcpiCpuData;
1068
1069 CpuFeaturesData = (CPU_FEATURES_DATA *) Buffer;
1070 AcpiCpuData = CpuFeaturesData->AcpiCpuData;
1071
1072 RegisterTables = (CPU_REGISTER_TABLE *)(UINTN)AcpiCpuData->RegisterTable;
1073
1074 InitApicId = GetInitialApicId ();
1075 RegisterTable = NULL;
1076 ProcIndex = (UINTN)-1;
1077 for (Index = 0; Index < AcpiCpuData->NumberOfCpus; Index++) {
1078 if (RegisterTables[Index].InitialApicId == InitApicId) {
1079 RegisterTable = &RegisterTables[Index];
1080 ProcIndex = Index;
1081 break;
1082 }
1083 }
1084 ASSERT (RegisterTable != NULL);
1085
1086 ProgramProcessorRegister (
1087 RegisterTable,
1088 (EFI_CPU_PHYSICAL_LOCATION *)(UINTN)AcpiCpuData->ApLocation + ProcIndex,
1089 &AcpiCpuData->CpuStatus,
1090 &CpuFeaturesData->CpuFlags
1091 );
1092 }
1093
1094 /**
1095 Performs CPU features detection.
1096
1097 This service will invoke MP service to check CPU features'
1098 capabilities on BSP/APs.
1099
1100 @note This service could be called by BSP only.
1101 **/
1102 VOID
1103 EFIAPI
1104 CpuFeaturesDetect (
1105 VOID
1106 )
1107 {
1108 UINTN NumberOfCpus;
1109 UINTN NumberOfEnabledProcessors;
1110 CPU_FEATURES_DATA *CpuFeaturesData;
1111
1112 CpuFeaturesData = GetCpuFeaturesData();
1113
1114 GetNumberOfProcessor (&NumberOfCpus, &NumberOfEnabledProcessors);
1115
1116 CpuInitDataInitialize (NumberOfCpus);
1117
1118 //
1119 // Wakeup all APs for data collection.
1120 //
1121 StartupAPsWorker (CollectProcessorData, NULL);
1122
1123 //
1124 // Collect data on BSP
1125 //
1126 CollectProcessorData (CpuFeaturesData);
1127
1128 AnalysisProcessorFeatures (NumberOfCpus);
1129 }
1130