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