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