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