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