OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
OcCpuLib.c
Go to the documentation of this file.
1
15#include <PiDxe.h>
16
19#include <Protocol/MpService.h>
20#include <Library/BaseLib.h>
21#include <Library/BaseMemoryLib.h>
22#include <Library/BaseOverflowLib.h>
23#include <Library/DebugLib.h>
24#include <Library/OcCpuLib.h>
25#include <Library/MemoryAllocationLib.h>
26#include <Library/UefiBootServicesTableLib.h>
28#include <Register/Microcode.h>
29#include <Register/Msr.h>
30#include <Register/Intel/Msr/SandyBridgeMsr.h>
31#include <Register/Intel/Msr/NehalemMsr.h>
32
33#include "OcCpuInternals.h"
34
35STATIC
36EFI_STATUS
38 IN EFI_MP_SERVICES_PROTOCOL *MpServices,
39 OUT OC_CPU_INFO *Cpu,
40 OUT UINTN *NumberOfProcessors,
41 OUT UINTN *NumberOfEnabledProcessors
42 )
43{
44 EFI_STATUS Status;
45 UINTN Index;
46 EFI_PROCESSOR_INFORMATION Info;
47
48 ASSERT (MpServices != NULL);
49 ASSERT (Cpu != NULL);
50 ASSERT (NumberOfProcessors != NULL);
51 ASSERT (NumberOfEnabledProcessors != NULL);
52
53 Status = MpServices->GetNumberOfProcessors (
54 MpServices,
55 NumberOfProcessors,
56 NumberOfEnabledProcessors
57 );
58
59 if (EFI_ERROR (Status)) {
60 return Status;
61 }
62
63 if (*NumberOfProcessors == 0) {
64 return EFI_NOT_FOUND;
65 }
66
67 //
68 // This code assumes that all CPUs have same amount of cores and threads.
69 //
70 for (Index = 0; Index < *NumberOfProcessors; ++Index) {
71 Status = MpServices->GetProcessorInfo (MpServices, Index, &Info);
72
73 if (EFI_ERROR (Status)) {
74 DEBUG ((
75 DEBUG_INFO,
76 "OCCPU: Failed to get info for processor %Lu - %r\n",
77 (UINT64)Index,
78 Status
79 ));
80
81 continue;
82 }
83
84 if (Info.Location.Package + 1 >= Cpu->PackageCount) {
85 Cpu->PackageCount = (UINT16)(Info.Location.Package + 1);
86 }
87
88 if (Info.Location.Core + 1 >= Cpu->CoreCount) {
89 Cpu->CoreCount = (UINT16)(Info.Location.Core + 1);
90 }
91
92 if (Info.Location.Thread + 1 >= Cpu->ThreadCount) {
93 Cpu->ThreadCount = (UINT16)(Info.Location.Thread + 1);
94 }
95 }
96
97 return Status;
98}
99
100STATIC
101EFI_STATUS
103 IN FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices,
104 OUT OC_CPU_INFO *Cpu,
105 OUT UINTN *NumberOfProcessors,
106 OUT UINTN *NumberOfEnabledProcessors
107 )
108{
109 EFI_STATUS Status;
110 UINTN Index;
111 EFI_MP_PROC_CONTEXT Context;
112 UINTN ContextSize;
113
114 ASSERT (FrameworkMpServices != NULL);
115 ASSERT (Cpu != NULL);
116 ASSERT (NumberOfProcessors != NULL);
117 ASSERT (NumberOfEnabledProcessors != NULL);
118
119 Status = FrameworkMpServices->GetGeneralMPInfo (
120 FrameworkMpServices,
121 NumberOfProcessors,
122 NULL,
123 NumberOfEnabledProcessors,
124 NULL,
125 NULL
126 );
127
128 if (EFI_ERROR (Status)) {
129 return Status;
130 }
131
132 if (*NumberOfProcessors == 0) {
133 return EFI_NOT_FOUND;
134 }
135
136 //
137 // This code assumes that all CPUs have same amount of cores and threads.
138 //
139 for (Index = 0; Index < *NumberOfProcessors; ++Index) {
140 ContextSize = sizeof (Context);
141
142 Status = FrameworkMpServices->GetProcessorContext (
143 FrameworkMpServices,
144 Index,
145 &ContextSize,
146 &Context
147 );
148
149 if (EFI_ERROR (Status)) {
150 DEBUG ((
151 DEBUG_INFO,
152 "OCCPU: Failed to get context for processor %Lu - %r\n",
153 (UINT64)Index,
154 Status
155 ));
156
157 continue;
158 }
159
160 if (Context.PackageNumber + 1 >= Cpu->PackageCount) {
161 Cpu->PackageCount = (UINT16)(Context.PackageNumber + 1);
162 }
163
164 //
165 // According to the FrameworkMpServices header, EFI_MP_PROC_CONTEXT.NumberOfCores is the
166 // zero-indexed physical core number for the current processor. However, Apple appears to
167 // set this to the total number of physical cores (observed on Xserve3,1 with 2x Xeon X5550).
168 //
169 // This number may not be accurate; on MacPro5,1 with 2x Xeon X5690, NumberOfCores is 16 when
170 // it should be 12 (even though NumberOfProcessors is correct). Regardless, CoreCount and
171 // ThreadCount will be corrected in ScanIntelProcessor.
172 //
173 // We will follow Apple's implementation, as the FrameworkMpServices fallback was added for
174 // legacy Macs.
175 //
176 if (Context.NumberOfCores >= Cpu->CoreCount) {
177 Cpu->CoreCount = (UINT16)(Context.NumberOfCores);
178 }
179
180 //
181 // Similarly, EFI_MP_PROC_CONTEXT.NumberOfThreads is supposed to be the zero-indexed logical
182 // thread number for the current processor. On Xserve3,1 and MacPro5,1 this was set to 2
183 // (presumably to indicate that there are 2 threads per physical core).
184 //
185 if (Context.NumberOfCores * Context.NumberOfThreads >= Cpu->ThreadCount) {
186 Cpu->ThreadCount = (UINT16)(Context.NumberOfCores * Context.NumberOfThreads);
187 }
188 }
189
190 return Status;
191}
192
193STATIC
194EFI_STATUS
196 OUT OC_CPU_INFO *Cpu
197 )
198{
199 EFI_STATUS Status;
200 EFI_MP_SERVICES_PROTOCOL *MpServices;
201 FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices;
202 UINTN NumberOfProcessors;
203 UINTN NumberOfEnabledProcessors;
204
205 Cpu->PackageCount = 1;
206 Cpu->CoreCount = 1;
207 Cpu->ThreadCount = 1;
208 NumberOfProcessors = 0;
209 NumberOfEnabledProcessors = 0;
210
211 Status = gBS->LocateProtocol (
213 NULL,
214 (VOID **)&MpServices
215 );
216
217 if (EFI_ERROR (Status)) {
218 Status = gBS->LocateProtocol (
220 NULL,
221 (VOID **)&FrameworkMpServices
222 );
223
224 if (EFI_ERROR (Status)) {
225 DEBUG ((DEBUG_INFO, "OCCPU: No MP services - %r\n", Status));
226 return Status;
227 }
228
229 Status = ScanFrameworkMpServices (
230 FrameworkMpServices,
231 Cpu,
232 &NumberOfProcessors,
233 &NumberOfEnabledProcessors
234 );
235 } else {
236 Status = ScanMpServices (
237 MpServices,
238 Cpu,
239 &NumberOfProcessors,
240 &NumberOfEnabledProcessors
241 );
242 }
243
244 DEBUG ((
245 DEBUG_INFO,
246 "OCCPU: MP services threads %Lu (enabled %Lu) - %r\n",
247 (UINT64)NumberOfProcessors,
248 (UINT64)NumberOfEnabledProcessors,
249 Status
250 ));
251
252 if (EFI_ERROR (Status)) {
253 return Status;
254 }
255
256 DEBUG ((
257 DEBUG_INFO,
258 "OCCPU: MP services Pkg %u Cores %u Threads %u - %r\n",
259 Cpu->PackageCount,
260 Cpu->CoreCount,
261 Cpu->ThreadCount,
262 Status
263 ));
264
265 //
266 // Several implementations may not report virtual threads.
267 //
268 if (Cpu->ThreadCount < Cpu->CoreCount) {
269 Cpu->ThreadCount = Cpu->CoreCount;
270 }
271
272 return Status;
273}
274
275STATIC
276VOID
278 IN OC_CPU_INFO *CpuInfo OPTIONAL,
279 OUT UINT8 *MaxBusRatio,
280 OUT UINT8 *MaxBusRatioDiv
281 )
282{
283 MSR_IA32_PERF_STATUS_REGISTER PerfStatus;
284 MSR_NEHALEM_PLATFORM_INFO_REGISTER PlatformInfo;
285 CPUID_VERSION_INFO_EAX Eax;
286 UINT8 CpuModel;
287
288 ASSERT (MaxBusRatio != NULL);
289 ASSERT (MaxBusRatioDiv != NULL);
290
291 if (CpuInfo != NULL) {
292 CpuModel = CpuInfo->Model;
293 } else {
294 //
295 // Assuming Intel machines used on Apple hardware.
296 //
297 AsmCpuid (
298 CPUID_VERSION_INFO,
299 &Eax.Uint32,
300 NULL,
301 NULL,
302 NULL
303 );
304 CpuModel = (UINT8)Eax.Bits.Model | (UINT8)(Eax.Bits.ExtendedModelId << 4U);
305 }
306
307 //
308 // Refer to Intel SDM (MSRs in Processors Based on Intel... table).
309 //
310 if ((CpuModel >= CPU_MODEL_NEHALEM) && (CpuModel != CPU_MODEL_BONNELL)) {
311 PlatformInfo.Uint64 = AsmReadMsr64 (MSR_NEHALEM_PLATFORM_INFO);
312 *MaxBusRatio = (UINT8)PlatformInfo.Bits.MaximumNonTurboRatio;
313 *MaxBusRatioDiv = 0;
314 } else {
315 PerfStatus.Uint64 = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
316 *MaxBusRatio = (UINT8)(RShiftU64 (PerfStatus.Uint64, 40) & 0x1FU);
317 *MaxBusRatioDiv = (UINT8)(RShiftU64 (PerfStatus.Uint64, 46) & BIT0);
318 }
319
320 //
321 // Fall back to 1 if *MaxBusRatio has zero.
322 //
323 if (*MaxBusRatio == 0) {
324 *MaxBusRatio = 1;
325 }
326}
327
328STATIC
329VOID
331 IN OC_CPU_INFO *CpuInfo
332 )
333{
334 UINT8 MaxBusRatio;
335 UINT8 MaxBusRatioDiv;
336
337 ASSERT (CpuInfo != NULL);
338
339 //
340 // Do not reset if CpuInfo->FSBFrequency is already set.
341 //
342 if (CpuInfo->FSBFrequency > 0) {
343 return;
344 }
345
346 SetMaxBusRatioAndMaxBusRatioDiv (CpuInfo, &MaxBusRatio, &MaxBusRatioDiv);
347
348 //
349 // There may be some quirks with virtual CPUs (VMware is fine).
350 // Formerly we checked Cpu->MinBusRatio > 0, and MaxBusRatio falls back to 1 if it is 0.
351 //
352 if (CpuInfo->CPUFrequency > 0) {
353 if (MaxBusRatioDiv == 0) {
354 CpuInfo->FSBFrequency = DivU64x32 (CpuInfo->CPUFrequency, MaxBusRatio);
355 } else {
356 CpuInfo->FSBFrequency = BaseMultThenDivU64x64x32 (
357 CpuInfo->CPUFrequency,
358 2,
359 2 * MaxBusRatio + 1,
360 NULL
361 );
362 }
363 } else {
364 //
365 // TODO: It seems to be possible that CPU frequency == 0 here...
366 //
367 CpuInfo->FSBFrequency = 100000000; // 100 MHz
368 }
369
370 DEBUG ((
371 DEBUG_INFO,
372 "OCCPU: Intel TSC: %11LuHz, %5LuMHz; FSB: %11LuHz, %5LuMHz; MaxBusRatio: %u%a\n",
373 CpuInfo->CPUFrequency,
374 DivU64x32 (CpuInfo->CPUFrequency, 1000000),
375 CpuInfo->FSBFrequency,
376 DivU64x32 (CpuInfo->FSBFrequency, 1000000),
377 MaxBusRatio,
378 MaxBusRatioDiv != 0 ? ".5" : ""
379 ));
380}
381
382UINT64
384 IN UINT64 FSBFrequency
385 )
386{
387 UINT8 MaxBusRatio;
388 UINT8 MaxBusRatioDiv;
389
390 SetMaxBusRatioAndMaxBusRatioDiv (NULL, &MaxBusRatio, &MaxBusRatioDiv);
391
392 //
393 // When MaxBusRatioDiv is 1, the multiplier is MaxBusRatio + 0.5.
394 //
395 if (MaxBusRatioDiv == 1) {
396 return FSBFrequency * MaxBusRatio + FSBFrequency / 2;
397 }
398
399 return FSBFrequency * MaxBusRatio;
400}
401
402STATIC
403VOID
405 IN OUT OC_CPU_INFO *Cpu
406 )
407{
408 UINT8 AppleMajorType;
409
410 AppleMajorType = InternalDetectAppleMajorType (Cpu->BrandString);
411 Cpu->AppleProcessorType = InternalDetectAppleProcessorType (
412 Cpu->Model,
413 Cpu->Stepping,
414 AppleMajorType,
415 Cpu->CoreCount,
416 (Cpu->ExtFeatures & CPUID_EXTFEATURE_EM64T) != 0
417 );
418
419 DEBUG ((DEBUG_INFO, "OCCPU: Detected Apple Processor Type: %02X -> %04X\n", AppleMajorType, Cpu->AppleProcessorType));
420}
421
422STATIC
423VOID
425 IN OUT OC_CPU_INFO *Cpu
426 )
427{
428 UINT64 Msr;
429 CPUID_CACHE_PARAMS_EAX CpuidCacheEax;
430 CPUID_CACHE_PARAMS_EBX CpuidCacheEbx;
431 CPUID_EXTENDED_TOPOLOGY_EAX CpuidExTopologyEax;
432 CPUID_EXTENDED_TOPOLOGY_EBX CpuidExTopologyEbx;
433 CPUID_EXTENDED_TOPOLOGY_ECX CpuidExTopologyEcx;
434 MSR_SANDY_BRIDGE_PKG_CST_CONFIG_CONTROL_REGISTER PkgCstConfigControl;
435 UINT16 CoreCount;
436 CONST CHAR8 *TimerSourceType;
437 UINTN TimerAddr;
438 BOOLEAN Recalculate;
439
440 if ( ((Cpu->Family != 0x06) || (Cpu->Model < 0x0c))
441 && ((Cpu->Family != 0x0f) || (Cpu->Model < 0x03)))
442 {
444 return;
445 }
446
447 Cpu->CpuGeneration = InternalDetectIntelProcessorGeneration (Cpu);
448
449 //
450 // Some virtual machines like QEMU 5.0 with KVM will fail to read this value.
451 // REF: https://github.com/acidanthera/bugtracker/issues/914
452 //
453 if ((Cpu->CpuGeneration >= OcCpuGenerationSandyBridge) && !Cpu->Hypervisor) {
454 PkgCstConfigControl.Uint64 = AsmReadMsr64 (MSR_SANDY_BRIDGE_PKG_CST_CONFIG_CONTROL);
455 Cpu->CstConfigLock = PkgCstConfigControl.Bits.CFGLock == 1;
456 } else {
457 Cpu->CstConfigLock = FALSE;
458 }
459
460 DEBUG ((DEBUG_INFO, "OCCPU: EIST CFG Lock %d\n", Cpu->CstConfigLock));
461
462 //
463 // When the CPU is virtualized and cpuid invtsc is enabled, then we already get
464 // the information we want outside the function, skip anyway.
465 // Things may be different in other hypervisors, but should work with QEMU/VMWare for now.
466 //
467 if (Cpu->CPUFrequencyFromVMT == 0) {
468 //
469 // For logging purposes (the first call to these functions might happen
470 // before logging is fully initialised), do not use the cached results in
471 // DEBUG builds.
472 //
473 Recalculate = FALSE;
474
475 DEBUG_CODE_BEGIN ();
476 Recalculate = TRUE;
477 DEBUG_CODE_END ();
478
479 //
480 // Determine our core crystal clock frequency
481 //
482 Cpu->ARTFrequency = InternalCalculateARTFrequencyIntel (
483 &Cpu->CPUFrequencyFromART,
484 &Cpu->TscAdjust,
485 Recalculate
486 );
487
488 //
489 // Calculate the TSC frequency only if ART frequency is not available or we are in debug builds.
490 //
491 if ((Cpu->CPUFrequencyFromART == 0) || Recalculate) {
492 DEBUG_CODE_BEGIN ();
493 TimerAddr = InternalGetPmTimerAddr (&TimerSourceType);
494 DEBUG ((DEBUG_INFO, "OCCPU: Timer address is %Lx from %a\n", (UINT64)TimerAddr, TimerSourceType));
495 DEBUG_CODE_END ();
496 Cpu->CPUFrequencyFromApple = InternalCalculateTSCFromApplePlatformInfo (NULL, Recalculate);
497 if ((Cpu->CPUFrequencyFromApple == 0) || Recalculate) {
498 Cpu->CPUFrequencyFromTSC = InternalCalculateTSCFromPMTimer (Recalculate);
499 }
500 }
501
502 //
503 // Calculate CPU frequency firstly based on ART if present.
504 //
505 if (Cpu->CPUFrequencyFromART != 0) {
506 Cpu->CPUFrequency = Cpu->CPUFrequencyFromART;
507 } else {
508 //
509 // If ART is not available, then try the value from Apple Platform Info.
510 //
511 if (Cpu->CPUFrequencyFromApple != 0) {
512 Cpu->CPUFrequency = Cpu->CPUFrequencyFromApple;
513 } else {
514 //
515 // If still not available, finally use TSC.
516 //
517 Cpu->CPUFrequency = Cpu->CPUFrequencyFromTSC;
518 }
519 }
520
521 //
522 // Verify that ART/TSC CPU frequency calculations do not differ substantially.
523 //
524 if ( (Cpu->CPUFrequencyFromART > 0) && (Cpu->CPUFrequencyFromTSC > 0)
525 && (ABS ((INT64)Cpu->CPUFrequencyFromART - (INT64)Cpu->CPUFrequencyFromTSC) > OC_CPU_FREQUENCY_TOLERANCE))
526 {
527 DEBUG ((
528 DEBUG_WARN,
529 "OCCPU: ART based CPU frequency differs substantially from TSC: %11LuHz != %11LuHz\n",
530 Cpu->CPUFrequencyFromART,
531 Cpu->CPUFrequencyFromTSC
532 ));
533 }
534
535 //
536 // Verify that Apple/TSC CPU frequency calculations do not differ substantially.
537 //
538 if ( (Cpu->CPUFrequencyFromApple > 0) && (Cpu->CPUFrequencyFromTSC > 0)
539 && (ABS ((INT64)Cpu->CPUFrequencyFromApple - (INT64)Cpu->CPUFrequencyFromTSC) > OC_CPU_FREQUENCY_TOLERANCE))
540 {
541 DEBUG ((
542 DEBUG_WARN,
543 "OCCPU: Apple based CPU frequency differs substantially from TSC: %11LuHz != %11LuHz\n",
544 Cpu->CPUFrequencyFromApple,
545 Cpu->CPUFrequencyFromTSC
546 ));
547 }
548
550 }
551
552 //
553 // Calculate number of cores.
554 // If we are under virtualization, then we should get the topology from CPUID the same was as with Penryn.
555 //
556 if ( (Cpu->MaxId >= CPUID_CACHE_PARAMS)
557 && ( (Cpu->CpuGeneration == OcCpuGenerationPreYonah)
558 || (Cpu->CpuGeneration == OcCpuGenerationYonahMerom)
559 || (Cpu->CpuGeneration == OcCpuGenerationPenryn)
560 || (Cpu->CpuGeneration == OcCpuGenerationBonnell)
561 || Cpu->Hypervisor))
562 {
563 AsmCpuidEx (CPUID_CACHE_PARAMS, 0, &CpuidCacheEax.Uint32, &CpuidCacheEbx.Uint32, NULL, NULL);
564 if (CpuidCacheEax.Bits.CacheType != CPUID_CACHE_PARAMS_CACHE_TYPE_NULL) {
565 CoreCount = (UINT16)GetPowerOfTwo32 (CpuidCacheEax.Bits.MaximumAddressableIdsForProcessorCores + 1);
566 if (CoreCount < CpuidCacheEax.Bits.MaximumAddressableIdsForProcessorCores + 1) {
567 CoreCount *= 2;
568 }
569
570 Cpu->CoreCount = CoreCount;
571 //
572 // We should not be blindly relying on Cpu->Features & CPUID_FEATURE_HTT.
573 // On Penryn CPUs it is set even without Hyper Threading.
574 //
575 if (Cpu->ThreadCount < Cpu->CoreCount) {
576 Cpu->ThreadCount = Cpu->CoreCount;
577 }
578 }
579 } else if (Cpu->CpuGeneration == OcCpuGenerationSilvermont) {
580 //
581 // MSR 0x35 is unsupported, and CPUID leaf 4 does not give correct information on Silvermont Celeron/Atom processors.
582 // Use CPUID leaf 11 instead.
583 // No Hyperthreading on these processors, should be ok to assume logical processor count == core count.
584 //
585 // Level 0 - threads per core.
586 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 0, &CpuidExTopologyEax.Uint32, &CpuidExTopologyEbx.Uint32, &CpuidExTopologyEcx.Uint32, NULL);
587
588 // Level 1 - total logical processor count.
589 AsmCpuidEx (CPUID_EXTENDED_TOPOLOGY, 1, &CpuidExTopologyEax.Uint32, &CpuidExTopologyEbx.Uint32, &CpuidExTopologyEcx.Uint32, NULL);
590 Cpu->CoreCount = (UINT16)GetPowerOfTwo32 (CpuidExTopologyEbx.Bits.LogicalProcessors);
591 Cpu->ThreadCount = Cpu->CoreCount;
592 } else if (Cpu->CpuGeneration == OcCpuGenerationWestmere) {
594 Cpu->CoreCount = (UINT16)BitFieldRead64 (Msr, 16, 19);
595 Cpu->ThreadCount = (UINT16)BitFieldRead64 (Msr, 0, 15);
596 } else if (Cpu->CpuGeneration == OcCpuGenerationBanias) {
597 //
598 // Banias and Dothan (Pentium M and Celeron M) never had
599 // multiple cores or threads, and do not support the MSR below.
600 //
601 Cpu->CoreCount = 0;
602 Cpu->ThreadCount = 0;
603 } else if ( (Cpu->CpuGeneration == OcCpuGenerationPreYonah)
604 && (Cpu->MaxId < CPUID_CACHE_PARAMS))
605 {
606 //
607 // Legacy Pentium 4, e.g. 541.
608 // REF: https://github.com/acidanthera/bugtracker/issues/1783
609 //
610 Cpu->CoreCount = 1;
611 } else {
613 Cpu->CoreCount = (UINT16)BitFieldRead64 (Msr, 16, 31);
614 Cpu->ThreadCount = (UINT16)BitFieldRead64 (Msr, 0, 15);
615 }
616
617 if (Cpu->CoreCount == 0) {
618 Cpu->CoreCount = 1;
619 }
620
621 if (Cpu->ThreadCount == 0) {
622 Cpu->ThreadCount = 1;
623 }
624
626}
627
628STATIC
629VOID
631 IN OUT OC_CPU_INFO *Cpu
632 )
633{
634 UINT32 CpuidEbx;
635 UINT32 CpuidEcx;
636 UINT64 CofVid;
637 UINT8 CoreFrequencyID;
638 UINT8 CoreDivisorID;
639 UINT8 Divisor;
640 UINT8 MaxBusRatio;
641 BOOLEAN Recalculate;
642
643 //
644 // For logging purposes (the first call to these functions might happen
645 // before logging is fully initialised), do not use the cached results in
646 // DEBUG builds.
647 //
648 Recalculate = FALSE;
649
650 DEBUG_CODE_BEGIN ();
651 Recalculate = TRUE;
652 DEBUG_CODE_END ();
653
654 //
655 // get TSC Frequency calculated in OcTimerLib, unless we got it already from virtualization extensions.
656 // FIXME(1): This code assumes the CPU operates in P0. Either ensure it does
657 // and raise the mode on demand, or adapt the logic to consider
658 // both the operating and the nominal frequency, latter for
659 // the invariant TSC.
660 //
661 if (Cpu->CPUFrequencyFromVMT == 0) {
662 Cpu->CPUFrequencyFromTSC = InternalCalculateTSCFromPMTimer (Recalculate);
663 Cpu->CPUFrequency = Cpu->CPUFrequencyFromTSC;
664 }
665
666 //
667 // Get core and thread count from CPUID
668 //
669 if (Cpu->MaxExtId >= 0x80000008) {
670 AsmCpuid (0x80000008, NULL, NULL, &CpuidEcx, NULL);
671 Cpu->ThreadCount = (UINT16)(BitFieldRead32 (CpuidEcx, 0, 7) + 1);
672 }
673
674 //
675 // Faking an Intel processor with matching core count if possible.
676 // This value is purely cosmetic, but it makes sense to fake something
677 // that is somewhat representative of the kind of Processor that's actually
678 // in the system
679 //
680 if (Cpu->ThreadCount >= 8) {
681 Cpu->AppleProcessorType = AppleProcessorTypeXeonW;
682 } else {
683 Cpu->AppleProcessorType = AppleProcessorTypeCorei5Type5;
684 }
685
686 if (Cpu->Family == AMD_CPU_FAMILY) {
687 Divisor = 0;
688 CoreFrequencyID = 0;
689 CoreDivisorID = 0;
690 MaxBusRatio = 0;
691
692 switch (Cpu->ExtFamily) {
694 if (Cpu->CPUFrequencyFromVMT == 0) {
696 CoreFrequencyID = (UINT8)BitFieldRead64 (CofVid, 0, 11); // 12-bit field for FID
697
698 // On AMD Family 1Ah and later, if the Frequency ID (FID) exceeds 0x0f,
699 // the core frequency is scaled by a factor of 5. This scaling behavior
700 // is based on Linux kernel logic for handling higher frequency multipliers
701 // in newer AMD CPUs, where the FID no longer directly correlates to the
702 // bus ratio.
703 if (CoreFrequencyID > 0x0f) {
704 CoreFrequencyID *= 5;
705 }
706
707 MaxBusRatio = (UINT8)(CoreFrequencyID);
708 }
709
710 //
711 // Get core count from CPUID
712 //
713 if (Cpu->MaxExtId >= 0x8000001E) {
714 AsmCpuid (0x8000001E, NULL, &CpuidEbx, NULL, NULL);
715 Cpu->CoreCount = (UINT16)DivU64x32 (
716 Cpu->ThreadCount,
717 (BitFieldRead32 (CpuidEbx, 8, 15) + 1)
718 );
719 }
720
721 break;
724 if (Cpu->CPUFrequencyFromVMT == 0) {
726 CoreFrequencyID = (UINT8)BitFieldRead64 (CofVid, 0, 7);
727 CoreDivisorID = (UINT8)BitFieldRead64 (CofVid, 8, 13);
728 if (CoreDivisorID > 0ULL) {
729 //
730 // Sometimes incorrect hypervisor configuration will lead to dividing by zero,
731 // but these variables will not be used under hypervisor, so just skip these.
732 //
733 MaxBusRatio = (UINT8)(CoreFrequencyID / CoreDivisorID * 2);
734 }
735 }
736
737 //
738 // Get core count from CPUID
739 //
740 if (Cpu->MaxExtId >= 0x8000001E) {
741 AsmCpuid (0x8000001E, NULL, &CpuidEbx, NULL, NULL);
742 Cpu->CoreCount = (UINT16)DivU64x32 (
743 Cpu->ThreadCount,
744 (BitFieldRead32 (CpuidEbx, 8, 15) + 1)
745 );
746 }
747
748 break;
752 if (Cpu->CPUFrequencyFromVMT == 0) {
753 // FIXME: Please refer to FIXME(1) for the MSR used here.
755 CoreFrequencyID = (UINT8)BitFieldRead64 (CofVid, 0, 5);
756 CoreDivisorID = (UINT8)BitFieldRead64 (CofVid, 6, 8);
757 Divisor = 1U << CoreDivisorID;
758 //
759 // BKDG for AMD Family 15h Models 10h-1Fh Processors (42300 Rev 3.12)
760 // Core current operating frequency in MHz. CoreCOF = 100 *
761 // (MSRC001_00[6B:64][CpuFid] + 10h) / (2 ^ MSRC001_00[6B:64][CpuDid]).
762 //
763 if (Divisor > 0ULL) {
764 //
765 // Sometimes incorrect hypervisor configuration will lead to dividing by zero,
766 // but these variables will not be used under hypervisor, so just skip these.
767 //
768 MaxBusRatio = (UINT8)((CoreFrequencyID + 0x10) / Divisor);
769 }
770 }
771
772 //
773 // AMD 10h, 15h, and 16h CPUs don't support hyperthreading,
774 // so the core count is equal to the thread count.
775 //
776 Cpu->CoreCount = Cpu->ThreadCount;
777 break;
779 if (Cpu->CPUFrequencyFromVMT == 0) {
780 // FIXME: Please refer to FIXME(1) for the MSR used here.
782 CoreFrequencyID = (UINT8)BitFieldRead64 (CofVid, 0, 5);
783
784 // Frequency ID directly specifies the clock multiplier as a 6-bit coding.
785 // Coding starts at x4.
786 MaxBusRatio = (CoreFrequencyID / 2) + 4;
787 }
788
789 //
790 // AMD 0Fh CPUs don't support hyperthreading,
791 // so the core count is equal to the thread count.
792 //
793 Cpu->CoreCount = Cpu->ThreadCount;
794 break;
795 default:
796 return;
797 }
798
799 DEBUG ((
800 DEBUG_INFO,
801 "OCCPU: FID %u DID %u Divisor %u MaxBR %u\n",
802 CoreFrequencyID,
803 CoreDivisorID,
804 Divisor,
805 MaxBusRatio
806 ));
807
808 //
809 // When under virtualization this information is already available to us.
810 //
811 if (Cpu->CPUFrequencyFromVMT == 0) {
812 //
813 // Sometimes incorrect hypervisor configuration will lead to dividing by zero.
814 //
815 if (MaxBusRatio == 0) {
816 Cpu->FSBFrequency = 100000000; // 100 MHz like Intel part.
817 } else if (Cpu->ExtFamily == AMD_CPU_EXT_FAMILY_1AH) {
818 Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, CoreFrequencyID); // No divisor for Family 1Ah
819 } else {
820 Cpu->FSBFrequency = DivU64x32 (Cpu->CPUFrequency, MaxBusRatio);
821 }
822 }
823 }
824}
825
831VOID
833 IN OUT OC_CPU_INFO *Cpu
834 )
835{
836 UINT32 CpuidEax;
837 UINT32 CpuidEbx;
838 UINT32 CpuidEcx;
839 UINT32 CpuidEdx;
840
841 ASSERT (Cpu != NULL);
842
843 ZeroMem (Cpu, sizeof (*Cpu));
844
845 //
846 // Get vendor CPUID 0x00000000
847 //
848 AsmCpuid (CPUID_SIGNATURE, &CpuidEax, &Cpu->Vendor[0], &Cpu->Vendor[2], &Cpu->Vendor[1]);
849
850 Cpu->MaxId = CpuidEax;
851
852 //
853 // Get extended CPUID 0x80000000
854 //
855 AsmCpuid (CPUID_EXTENDED_FUNCTION, &CpuidEax, &CpuidEbx, &CpuidEcx, &CpuidEdx);
856
857 Cpu->MaxExtId = CpuidEax;
858
859 //
860 // Get brand string CPUID 0x80000002 - 0x80000004
861 //
862 if (Cpu->MaxExtId >= CPUID_BRAND_STRING3) {
863 //
864 // The brandstring 48 bytes max, guaranteed NULL terminated.
865 //
866 UINT32 *BrandString = (UINT32 *)Cpu->BrandString;
867
868 AsmCpuid (
869 CPUID_BRAND_STRING1,
870 BrandString,
871 (BrandString + 1),
872 (BrandString + 2),
873 (BrandString + 3)
874 );
875
876 AsmCpuid (
877 CPUID_BRAND_STRING2,
878 (BrandString + 4),
879 (BrandString + 5),
880 (BrandString + 6),
881 (BrandString + 7)
882 );
883
884 AsmCpuid (
885 CPUID_BRAND_STRING3,
886 (BrandString + 8),
887 (BrandString + 9),
888 (BrandString + 10),
889 (BrandString + 11)
890 );
891 }
892
893 ScanThreadCount (Cpu);
894
895 //
896 // Get processor signature and decode
897 //
898 if (Cpu->MaxId >= CPUID_VERSION_INFO) {
899 if (Cpu->Vendor[0] == CPUID_VENDOR_INTEL) {
900 Cpu->MicrocodeRevision = AsmReadIntelMicrocodeRevision ();
901 }
902
903 AsmCpuid (
904 CPUID_VERSION_INFO,
905 &Cpu->CpuidVerEax.Uint32,
906 &Cpu->CpuidVerEbx.Uint32,
907 &Cpu->CpuidVerEcx.Uint32,
908 &Cpu->CpuidVerEdx.Uint32
909 );
910
911 Cpu->Signature = Cpu->CpuidVerEax.Uint32;
912 Cpu->Stepping = (UINT8)Cpu->CpuidVerEax.Bits.SteppingId;
913 Cpu->ExtModel = (UINT8)Cpu->CpuidVerEax.Bits.ExtendedModelId;
914 Cpu->Model = (UINT8)Cpu->CpuidVerEax.Bits.Model | (UINT8)(Cpu->CpuidVerEax.Bits.ExtendedModelId << 4U);
915 Cpu->Family = (UINT8)Cpu->CpuidVerEax.Bits.FamilyId;
916 Cpu->Type = (UINT8)Cpu->CpuidVerEax.Bits.ProcessorType;
917 Cpu->ExtFamily = (UINT8)Cpu->CpuidVerEax.Bits.ExtendedFamilyId;
918 Cpu->Brand = (UINT8)Cpu->CpuidVerEbx.Bits.BrandIndex;
919 Cpu->Features = LShiftU64 (Cpu->CpuidVerEcx.Uint32, 32) | Cpu->CpuidVerEdx.Uint32;
920
921 if (Cpu->Features & CPUID_FEATURE_HTT) {
922 Cpu->ThreadCount = (UINT16)Cpu->CpuidVerEbx.Bits.MaximumAddressableIdsForLogicalProcessors;
923 }
924 }
925
926 //
927 // Get extended processor signature.
928 //
929 if (Cpu->MaxExtId >= CPUID_EXTENDED_CPU_SIG) {
930 AsmCpuid (
931 CPUID_EXTENDED_CPU_SIG,
932 &CpuidEax,
933 &CpuidEbx,
934 &Cpu->CpuidExtSigEcx.Uint32,
935 &Cpu->CpuidExtSigEdx.Uint32
936 );
937
938 Cpu->ExtFeatures = LShiftU64 (Cpu->CpuidExtSigEcx.Uint32, 32) | Cpu->CpuidExtSigEdx.Uint32;
939 }
940
941 DEBUG ((DEBUG_INFO, "OCCPU: Found %a\n", Cpu->BrandString));
942
943 DEBUG ((
944 DEBUG_INFO,
945 "OCCPU: Signature %0X Stepping %0X Model %0X Family %0X Type %0X ExtModel %0X ExtFamily %0X uCode %0X CPUID MAX (%0X/%0X)\n",
946 Cpu->Signature,
947 Cpu->Stepping,
948 Cpu->Model,
949 Cpu->Family,
950 Cpu->Type,
951 Cpu->ExtModel,
952 Cpu->ExtFamily,
953 Cpu->MicrocodeRevision,
954 Cpu->MaxId,
955 Cpu->MaxExtId
956 ));
957
958 Cpu->CPUFrequencyFromVMT = InternalCalculateVMTFrequency (
959 &Cpu->FSBFrequency,
960 &Cpu->Hypervisor
961 );
962
963 if (Cpu->Hypervisor) {
964 DEBUG ((DEBUG_INFO, "OCCPU: Hypervisor detected\n"));
965 }
966
967 if (Cpu->CPUFrequencyFromVMT > 0) {
968 Cpu->CPUFrequency = Cpu->CPUFrequencyFromVMT;
969
970 DEBUG ((
971 DEBUG_INFO,
972 "OCCPU: VMWare TSC: %11LuHz, %5LuMHz; FSB: %11LuHz, %5LuMHz\n",
973 Cpu->CPUFrequency,
974 DivU64x32 (Cpu->CPUFrequency, 1000000),
975 Cpu->FSBFrequency,
976 DivU64x32 (Cpu->FSBFrequency, 1000000)
977 ));
978 }
979
980 if (Cpu->Vendor[0] == CPUID_VENDOR_INTEL) {
981 ScanIntelProcessor (Cpu);
982 } else if (Cpu->Vendor[0] == CPUID_VENDOR_AMD) {
983 ScanAmdProcessor (Cpu);
984 } else {
985 DEBUG ((DEBUG_WARN, "OCCPU: Found unsupported CPU vendor: %0X", Cpu->Vendor[0]));
986 return;
987 }
988
989 //
990 // SMBIOS Type4 ExternalClock field is assumed to have X*4 FSB frequency in MT/s.
991 // This value is cosmetics, but we still want to set it properly.
992 // Magic 4 value comes from 4 links in pretty much every modern Intel CPU.
993 // On modern CPUs this is now named Base clock (BCLK).
994 // Note, that this value was incorrect for most Macs since iMac12,x till iMac18,x inclusive.
995 // REF: https://github.com/acidanthera/bugtracker/issues/622#issuecomment-570811185
996 //
997 Cpu->ExternalClock = (UINT16)DivU64x32 (Cpu->FSBFrequency, 1000000);
998 //
999 // This is again cosmetics by errors in FSBFrequency calculation.
1000 //
1001 if ((Cpu->ExternalClock >= 99) && (Cpu->ExternalClock <= 101)) {
1002 Cpu->ExternalClock = 100;
1003 } else if ((Cpu->ExternalClock >= 132) && (Cpu->ExternalClock <= 134)) {
1004 Cpu->ExternalClock = 133;
1005 } else if ((Cpu->ExternalClock >= 265) && (Cpu->ExternalClock <= 267)) {
1006 Cpu->ExternalClock = 266;
1007 }
1008
1009 DEBUG ((
1010 DEBUG_INFO,
1011 "OCCPU: CPUFrequencyFromTSC %11LuHz %5LuMHz\n",
1012 Cpu->CPUFrequencyFromTSC,
1013 DivU64x32 (Cpu->CPUFrequencyFromTSC, 1000000)
1014 ));
1015
1016 if (Cpu->CPUFrequencyFromApple > 0) {
1017 DEBUG ((
1018 DEBUG_INFO,
1019 "OCCPU: CPUFrequencyFromApple %11LuHz %5LuMHz\n",
1020 Cpu->CPUFrequencyFromApple,
1021 DivU64x32 (Cpu->CPUFrequencyFromApple, 1000000)
1022 ));
1023 }
1024
1025 DEBUG ((
1026 DEBUG_INFO,
1027 "OCCPU: CPUFrequency %11LuHz %5LuMHz\n",
1028 Cpu->CPUFrequency,
1029 DivU64x32 (Cpu->CPUFrequency, 1000000)
1030 ));
1031
1032 DEBUG ((
1033 DEBUG_INFO,
1034 "OCCPU: FSBFrequency %11LuHz %5LuMHz\n",
1035 Cpu->FSBFrequency,
1036 DivU64x32 (Cpu->FSBFrequency, 1000000)
1037 ));
1038
1039 DEBUG ((
1040 DEBUG_INFO,
1041 "OCCPU: Pkg %u Cores %u Threads %u\n",
1042 Cpu->PackageCount,
1043 Cpu->CoreCount,
1044 Cpu->ThreadCount
1045 ));
1046}
1047
1048VOID
1050 IN OC_CPU_INFO *CpuInfo,
1051 OUT OC_CPU_MSR_REPORT *Report
1052 )
1053{
1054 ASSERT (CpuInfo != NULL);
1055 ASSERT (Report != NULL);
1056
1057 ZeroMem (Report, sizeof (*Report));
1058
1059 //
1060 // The CPU model must be Intel, as MSRs are not available on other platforms.
1061 //
1062 if (CpuInfo->Vendor[0] != CPUID_VENDOR_INTEL) {
1063 return;
1064 }
1065
1066 //
1067 // Hypervisors virtualise MSRs so the values are either not present
1068 // and cause a crash or are irrelevant as they report placeholders.
1069 //
1070 if (CpuInfo->Hypervisor) {
1071 return;
1072 }
1073
1074 if (CpuInfo->CpuGeneration >= OcCpuGenerationNehalem) {
1075 //
1076 // MSR_PLATFORM_INFO
1077 //
1078 Report->CpuHasMsrPlatformInfo = TRUE;
1079 Report->CpuMsrPlatformInfoValue = AsmReadMsr64 (MSR_NEHALEM_PLATFORM_INFO);
1080
1081 //
1082 // MSR_TURBO_RATIO_LIMIT
1083 //
1084 Report->CpuHasMsrTurboRatioLimit = TRUE;
1085 Report->CpuMsrTurboRatioLimitValue = AsmReadMsr64 (MSR_NEHALEM_TURBO_RATIO_LIMIT);
1086
1087 if (CpuInfo->CpuGeneration >= OcCpuGenerationSandyBridge) {
1088 //
1089 // MSR_PKG_POWER_INFO (TODO: To be confirmed)
1090 //
1091 Report->CpuHasMsrPkgPowerInfo = TRUE;
1092 Report->CpuMsrPkgPowerInfoValue = AsmReadMsr64 (MSR_GOLDMONT_PKG_POWER_INFO);
1093
1094 //
1095 // MSR_BROADWELL_PKG_CST_CONFIG_CONTROL_REGISTER (MSR 0xE2)
1096 //
1097 Report->CpuHasMsrE2 = TRUE;
1098 Report->CpuMsrE2Value = AsmReadMsr64 (MSR_BROADWELL_PKG_CST_CONFIG_CONTROL);
1099 }
1100 } else if (CpuInfo->CpuGeneration >= OcCpuGenerationPreYonah) {
1101 if (CpuInfo->CpuGeneration >= OcCpuGenerationYonahMerom) {
1102 //
1103 // MSR_IA32_EXT_CONFIG
1104 //
1105 Report->CpuHasMsrIa32ExtConfig = TRUE;
1106 Report->CpuMsrIa32ExtConfigValue = AsmReadMsr64 (MSR_IA32_EXT_CONFIG);
1107
1108 //
1109 // MSR_CORE_FSB_FREQ
1110 //
1111 Report->CpuHasMsrFsbFreq = TRUE;
1112 Report->CpuMsrFsbFreqValue = AsmReadMsr64 (MSR_CORE_FSB_FREQ);
1113 }
1114
1115 //
1116 // MSR_IA32_MISC_ENABLE
1117 //
1118 Report->CpuHasMsrIa32MiscEnable = TRUE;
1119 Report->CpuMsrIa32MiscEnableValue = AsmReadMsr64 (MSR_IA32_MISC_ENABLE);
1120
1121 //
1122 // MSR_IA32_PERF_STATUS
1123 //
1124 Report->CpuHasMsrIa32PerfStatus = TRUE;
1125 Report->CpuMsrIa32PerfStatusValue = AsmReadMsr64 (MSR_IA32_PERF_STATUS);
1126 }
1127}
1128
1129VOID
1130EFIAPI
1132 IN OUT VOID *Buffer
1133 )
1134{
1136 EFI_STATUS Status;
1137 UINTN CoreIndex;
1138
1140
1141 Status = Argument->MpServices->WhoAmI (
1142 Argument->MpServices,
1143 &CoreIndex
1144 );
1145 if (EFI_ERROR (Status)) {
1146 return;
1147 }
1148
1149 OcCpuGetMsrReport (Argument->CpuInfo, &Argument->Reports[CoreIndex]);
1150}
1151
1154 IN OC_CPU_INFO *CpuInfo,
1155 OUT UINTN *EntryCount
1156 )
1157{
1158 OC_CPU_MSR_REPORT *Reports;
1159 EFI_STATUS Status;
1160 EFI_MP_SERVICES_PROTOCOL *MpServices;
1161 UINTN NumberOfProcessors;
1162 UINTN NumberOfEnabledProcessors;
1164
1165 ASSERT (CpuInfo != NULL);
1166 ASSERT (EntryCount != NULL);
1167
1168 MpServices = NULL;
1169
1170 Status = gBS->LocateProtocol (
1172 NULL,
1173 (VOID **)&MpServices
1174 );
1175 if (!EFI_ERROR (Status)) {
1176 Status = MpServices->GetNumberOfProcessors (
1177 MpServices,
1178 &NumberOfProcessors,
1179 &NumberOfEnabledProcessors
1180 );
1181 if (EFI_ERROR (Status)) {
1182 DEBUG ((DEBUG_INFO, "OCCPU: Failed to get the number of processors - %r, assuming one core\n", Status));
1183 NumberOfProcessors = 1;
1184 }
1185 } else {
1186 DEBUG ((DEBUG_INFO, "OCCPU: Failed to find mp services - %r, assuming one core\n", Status));
1187 MpServices = NULL;
1188 NumberOfProcessors = 1;
1189 }
1190
1191 Reports = (OC_CPU_MSR_REPORT *)AllocateZeroPool (NumberOfProcessors * sizeof (OC_CPU_MSR_REPORT));
1192 if (Reports == NULL) {
1193 return NULL;
1194 }
1195
1196 //
1197 // Call OcCpuGetMsrReport on the 0th member firstly.
1198 //
1199 OcCpuGetMsrReport (CpuInfo, &Reports[0]);
1200 //
1201 // Then call StartupAllAPs to fill in the rest.
1202 //
1203 if (MpServices != NULL) {
1204 //
1205 // Pass data to the wrapped Argument.
1206 //
1207 Argument.MpServices = MpServices;
1208 Argument.Reports = Reports;
1209 Argument.CpuInfo = CpuInfo;
1210
1211 Status = MpServices->StartupAllAPs (
1212 MpServices,
1214 TRUE,
1215 NULL,
1216 5000000,
1217 &Argument,
1218 NULL
1219 );
1220 }
1221
1222 //
1223 // Update number of cores.
1224 //
1225 *EntryCount = NumberOfProcessors;
1226
1227 return Reports;
1228}
1229
1230VOID
1232 IN OC_CPU_INFO *Cpu
1233 )
1234{
1235 UINT64 Msr;
1236 UINT64 FlexRatio;
1237
1238 if ( (Cpu->Vendor[0] == CPUID_VENDOR_INTEL)
1239 && (Cpu->CpuGeneration != OcCpuGenerationBonnell)
1240 && (Cpu->CpuGeneration != OcCpuGenerationSilvermont))
1241 {
1243 if (Msr & FLEX_RATIO_EN) {
1244 FlexRatio = BitFieldRead64 (Msr, 8, 15);
1245 if (FlexRatio == 0) {
1246 //
1247 // Disable Flex Ratio if current value is 0.
1248 //
1249 AsmWriteMsr64 (MSR_FLEX_RATIO, Msr & ~((UINT64)FLEX_RATIO_EN));
1250 }
1251 }
1252 }
1253}
1254
1255EFI_STATUS
1257 VOID
1258 )
1259{
1260 CPUID_VERSION_INFO_ECX RegEcx;
1261 MSR_IA32_FEATURE_CONTROL_REGISTER Msr;
1262
1263 AsmCpuid (1, 0, 0, &RegEcx.Uint32, 0);
1264 if (RegEcx.Bits.VMX == 0) {
1265 return EFI_UNSUPPORTED;
1266 }
1267
1268 Msr.Uint64 = AsmReadMsr64 (MSR_IA32_FEATURE_CONTROL);
1269 if (Msr.Bits.Lock != 0) {
1270 return EFI_WRITE_PROTECTED;
1271 }
1272
1273 //
1274 // Unclear if pre-existing valid bits should ever be present if register is unlocked.
1275 //
1276 Msr.Bits.Lock = 1;
1277 Msr.Bits.EnableVmxOutsideSmx = 1;
1278 AsmWriteMsr64 (MSR_IA32_FEATURE_CONTROL, Msr.Uint64);
1279
1280 return EFI_SUCCESS;
1281}
1282
1283STATIC
1284VOID
1285EFIAPI
1287 IN VOID *Buffer
1288 )
1289{
1290 OC_CPU_TSC_SYNC *Sync;
1291
1292 Sync = Buffer;
1294 while (Sync->CurrentCount < Sync->APThreadCount) {
1295 //
1296 // Busy-wait on AP CPU cores.
1297 //
1298 }
1299
1300 AsmWriteMsr64 (MSR_IA32_TIME_STAMP_COUNTER, Sync->Tsc);
1301}
1302
1303STATIC
1304VOID
1305EFIAPI
1307 IN VOID *Buffer
1308 )
1309{
1310 OC_CPU_TSC_SYNC *Sync;
1311
1312 Sync = Buffer;
1314 while (Sync->CurrentCount < Sync->APThreadCount) {
1315 //
1316 // Busy-wait on AP CPU cores.
1317 //
1318 }
1319
1320 AsmWriteMsr64 (MSR_IA32_TSC_ADJUST, 0);
1321}
1322
1323EFI_STATUS
1325 IN OC_CPU_INFO *Cpu,
1326 IN UINTN Timeout
1327 )
1328{
1329 EFI_STATUS Status;
1330 EFI_MP_SERVICES_PROTOCOL *MpServices;
1331 FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices;
1332 OC_CPU_TSC_SYNC Sync;
1333 EFI_TPL OldTpl;
1334 BOOLEAN InterruptState;
1335
1336 if (Cpu->ThreadCount <= 1) {
1337 DEBUG ((DEBUG_INFO, "OCCPU: Thread count is too low for sync - %u\n", Cpu->ThreadCount));
1338 return EFI_UNSUPPORTED;
1339 }
1340
1341 Status = gBS->LocateProtocol (
1343 NULL,
1344 (VOID **)&MpServices
1345 );
1346
1347 if (EFI_ERROR (Status)) {
1348 MpServices = NULL;
1349 Status = gBS->LocateProtocol (
1351 NULL,
1352 (VOID **)&FrameworkMpServices
1353 );
1354
1355 if (EFI_ERROR (Status)) {
1356 DEBUG ((DEBUG_INFO, "OCCPU: Failed to find mp services - %r\n", Status));
1357 return Status;
1358 }
1359 }
1360
1361 Sync.CurrentCount = 0;
1362 Sync.APThreadCount = Cpu->ThreadCount - 1;
1363
1364 OldTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
1365 InterruptState = SaveAndDisableInterrupts ();
1366
1367 if (Cpu->TscAdjust > 0) {
1368 if (MpServices != NULL) {
1369 Status = MpServices->StartupAllAPs (MpServices, ResetAdjustTsc, FALSE, NULL, Timeout, &Sync, NULL);
1370 } else {
1371 Status = FrameworkMpServices->StartupAllAPs (FrameworkMpServices, ResetAdjustTsc, FALSE, NULL, Timeout, &Sync, NULL);
1372 }
1373
1374 AsmWriteMsr64 (MSR_IA32_TSC_ADJUST, 0);
1375 } else {
1376 Sync.Tsc = AsmReadTsc ();
1377
1378 if (MpServices != NULL) {
1379 Status = MpServices->StartupAllAPs (MpServices, SyncTscOnCpu, FALSE, NULL, Timeout, &Sync, NULL);
1380 } else {
1381 Status = FrameworkMpServices->StartupAllAPs (FrameworkMpServices, SyncTscOnCpu, FALSE, NULL, Timeout, &Sync, NULL);
1382 }
1383
1384 AsmWriteMsr64 (MSR_IA32_TIME_STAMP_COUNTER, Sync.Tsc);
1385 }
1386
1387 SetInterruptState (InterruptState);
1388 gBS->RestoreTPL (OldTpl);
1389
1390 DEBUG ((DEBUG_INFO, "OCCPU: Completed TSC sync with code - %r\n", Status));
1391
1392 return Status;
1393}
1394
1397 IN OC_CPU_INFO *CpuInfo
1398 )
1399{
1400 OC_CPU_GENERATION CpuGeneration;
1401
1402 CpuGeneration = OcCpuGenerationUnknown;
1403 if (CpuInfo->Family == 6) {
1404 switch (CpuInfo->Model) {
1405 case CPU_MODEL_BANIAS:
1406 case CPU_MODEL_DOTHAN:
1407 CpuGeneration = OcCpuGenerationBanias;
1408 break;
1409 case CPU_MODEL_YONAH:
1410 case CPU_MODEL_MEROM:
1411 CpuGeneration = OcCpuGenerationYonahMerom;
1412 break;
1413 case CPU_MODEL_PENRYN:
1414 CpuGeneration = OcCpuGenerationPenryn;
1415 break;
1416 case CPU_MODEL_NEHALEM:
1417 case CPU_MODEL_FIELDS:
1418 case CPU_MODEL_DALES:
1420 CpuGeneration = OcCpuGenerationNehalem;
1421 break;
1422 case CPU_MODEL_BONNELL:
1424 CpuGeneration = OcCpuGenerationBonnell;
1425 break;
1427 case CPU_MODEL_WESTMERE:
1429 CpuGeneration = OcCpuGenerationWestmere;
1430 break;
1432 case CPU_MODEL_JAKETOWN:
1433 CpuGeneration = OcCpuGenerationSandyBridge;
1434 break;
1436 case CPU_MODEL_GOLDMONT:
1437 case CPU_MODEL_AIRMONT:
1438 case CPU_MODEL_AVOTON:
1439 CpuGeneration = OcCpuGenerationSilvermont;
1440 break;
1443 CpuGeneration = OcCpuGenerationIvyBridge;
1444 break;
1445 case CPU_MODEL_HASWELL:
1449 CpuGeneration = OcCpuGenerationHaswell;
1450 break;
1454 CpuGeneration = OcCpuGenerationBroadwell;
1455 break;
1456 case CPU_MODEL_SKYLAKE:
1459 CpuGeneration = OcCpuGenerationSkylake;
1460 break;
1461 case CPU_MODEL_KABYLAKE:
1463 //
1464 // Kaby has 0x9 stepping, and Coffee use 0xA / 0xB stepping.
1465 //
1466 if (CpuInfo->Stepping == 9) {
1467 CpuGeneration = OcCpuGenerationKabyLake;
1468 } else {
1469 CpuGeneration = OcCpuGenerationCoffeeLake;
1470 }
1471
1472 break;
1474 CpuGeneration = OcCpuGenerationCannonLake;
1475 break;
1478 CpuGeneration = OcCpuGenerationCometLake;
1479 break;
1481 CpuGeneration = OcCpuGenerationRocketLake;
1482 break;
1486 CpuGeneration = OcCpuGenerationIceLake;
1487 break;
1489 CpuGeneration = OcCpuGenerationTigerLake;
1490 break;
1492 CpuGeneration = OcCpuGenerationAlderLake;
1493 break;
1496 CpuGeneration = OcCpuGenerationRaptorLake;
1497 break;
1501 CpuGeneration = OcCpuGenerationArrowLake;
1502 break;
1503 default:
1504 if (CpuInfo->Model < CPU_MODEL_PENRYN) {
1505 CpuGeneration = OcCpuGenerationPreYonah;
1506 } else if (CpuInfo->Model >= CPU_MODEL_SANDYBRIDGE) {
1507 CpuGeneration = OcCpuGenerationPostSandyBridge;
1508 }
1509 }
1510 } else {
1511 CpuGeneration = OcCpuGenerationPreYonah;
1512 }
1513
1514 DEBUG ((
1515 DEBUG_VERBOSE,
1516 "OCCPU: Discovered CpuFamily %d CpuModel %d CpuStepping %d CpuGeneration %d\n",
1517 CpuInfo->Family,
1518 CpuInfo->Model,
1519 CpuInfo->Stepping,
1520 CpuGeneration
1521 ));
1522
1523 return CpuGeneration;
1524}
UINT16 InternalDetectAppleProcessorType(IN UINT8 Model, IN UINT8 Stepping, IN UINT8 AppleMajorType, IN UINT16 CoreCount, IN BOOLEAN Is64Bit)
UINT8 InternalDetectAppleMajorType(IN CONST CHAR8 *BrandString)
@ AppleProcessorTypeXeonW
@ AppleProcessorTypeCorei5Type5
#define CPUID_EXTFEATURE_EM64T
Extended Mem 64 Technology.
Definition CpuId.h:101
#define CPUID_VENDOR_INTEL
Definition CpuId.h:214
#define CPUID_VENDOR_AMD
Definition CpuId.h:215
#define CPUID_FEATURE_HTT
Hyper-Threading Technology.
Definition CpuId.h:51
EFI_GUID gFrameworkEfiMpServiceProtocolGuid
UINTN InternalGetPmTimerAddr(OUT CONST CHAR8 **Type OPTIONAL)
UINT64 InternalCalculateVMTFrequency(OUT UINT64 *FSBFrequency OPTIONAL, OUT BOOLEAN *UnderHypervisor OPTIONAL)
UINT64 InternalCalculateARTFrequencyIntel(OUT UINT64 *CPUFrequency, OUT UINT64 *TscAdjustPtr OPTIONAL, IN BOOLEAN Recalculate)
UINT64 InternalCalculateTSCFromApplePlatformInfo(OUT UINT64 *FSBFrequency OPTIONAL, IN BOOLEAN Recalculate)
UINT64 InternalCalculateTSCFromPMTimer(IN BOOLEAN Recalculate)
EFI_BOOT_SERVICES * gBS
UINT32 EFIAPI AsmReadIntelMicrocodeRevision(VOID)
Definition UserMisc.c:187
#define OC_CPU_FREQUENCY_TOLERANCE
UINT32 EFIAPI AsmIncrementUint32(IN volatile UINT32 *Value)
Definition UserMisc.c:176
STATIC VOID EFIAPI SyncTscOnCpu(IN VOID *Buffer)
Definition OcCpuLib.c:1286
STATIC EFI_STATUS ScanThreadCount(OUT OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:195
EFI_STATUS OcCpuEnableVmx(VOID)
Definition OcCpuLib.c:1256
EFI_STATUS OcCpuCorrectTscSync(IN OC_CPU_INFO *Cpu, IN UINTN Timeout)
Definition OcCpuLib.c:1324
OC_CPU_GENERATION InternalDetectIntelProcessorGeneration(IN OC_CPU_INFO *CpuInfo)
Definition OcCpuLib.c:1396
VOID OcCpuScanProcessor(IN OUT OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:832
STATIC VOID ScanIntelProcessorApple(IN OUT OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:404
VOID OcCpuCorrectFlexRatio(IN OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:1231
VOID OcCpuGetMsrReport(IN OC_CPU_INFO *CpuInfo, OUT OC_CPU_MSR_REPORT *Report)
Definition OcCpuLib.c:1049
STATIC EFI_STATUS ScanFrameworkMpServices(IN FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpServices, OUT OC_CPU_INFO *Cpu, OUT UINTN *NumberOfProcessors, OUT UINTN *NumberOfEnabledProcessors)
Definition OcCpuLib.c:102
VOID EFIAPI OcCpuGetMsrReportPerCore(IN OUT VOID *Buffer)
Definition OcCpuLib.c:1131
STATIC VOID EFIAPI ResetAdjustTsc(IN VOID *Buffer)
Definition OcCpuLib.c:1306
OC_CPU_MSR_REPORT * OcCpuGetMsrReports(IN OC_CPU_INFO *CpuInfo, OUT UINTN *EntryCount)
Definition OcCpuLib.c:1153
STATIC VOID ScanAmdProcessor(IN OUT OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:630
STATIC EFI_STATUS ScanMpServices(IN EFI_MP_SERVICES_PROTOCOL *MpServices, OUT OC_CPU_INFO *Cpu, OUT UINTN *NumberOfProcessors, OUT UINTN *NumberOfEnabledProcessors)
Definition OcCpuLib.c:37
STATIC VOID SetMaxBusRatioAndMaxBusRatioDiv(IN OC_CPU_INFO *CpuInfo OPTIONAL, OUT UINT8 *MaxBusRatio, OUT UINT8 *MaxBusRatioDiv)
Definition OcCpuLib.c:277
UINT64 InternalConvertAppleFSBToTSCFrequency(IN UINT64 FSBFrequency)
Definition OcCpuLib.c:383
STATIC VOID ScanIntelProcessor(IN OUT OC_CPU_INFO *Cpu)
Definition OcCpuLib.c:424
STATIC VOID ScanIntelFSBFrequency(IN OC_CPU_INFO *CpuInfo)
Definition OcCpuLib.c:330
OC_CPU_GENERATION
Definition OcCpuLib.h:35
@ OcCpuGenerationPenryn
Definition OcCpuLib.h:40
@ OcCpuGenerationBroadwell
Definition OcCpuLib.h:49
@ OcCpuGenerationNehalem
Definition OcCpuLib.h:42
@ OcCpuGenerationRaptorLake
Definition OcCpuLib.h:59
@ OcCpuGenerationHaswell
Definition OcCpuLib.h:48
@ OcCpuGenerationWestmere
Definition OcCpuLib.h:43
@ OcCpuGenerationIceLake
Definition OcCpuLib.h:56
@ OcCpuGenerationCoffeeLake
Definition OcCpuLib.h:52
@ OcCpuGenerationUnknown
Definition OcCpuLib.h:36
@ OcCpuGenerationArrowLake
Definition OcCpuLib.h:60
@ OcCpuGenerationBonnell
Definition OcCpuLib.h:41
@ OcCpuGenerationSilvermont
Definition OcCpuLib.h:44
@ OcCpuGenerationIvyBridge
Definition OcCpuLib.h:47
@ OcCpuGenerationTigerLake
Definition OcCpuLib.h:57
@ OcCpuGenerationKabyLake
Definition OcCpuLib.h:51
@ OcCpuGenerationSandyBridge
Definition OcCpuLib.h:45
@ OcCpuGenerationRocketLake
Definition OcCpuLib.h:54
@ OcCpuGenerationAlderLake
Definition OcCpuLib.h:58
@ OcCpuGenerationCometLake
Definition OcCpuLib.h:53
@ OcCpuGenerationYonahMerom
Definition OcCpuLib.h:39
@ OcCpuGenerationPostSandyBridge
Definition OcCpuLib.h:46
@ OcCpuGenerationCannonLake
Definition OcCpuLib.h:55
@ OcCpuGenerationBanias
Definition OcCpuLib.h:37
@ OcCpuGenerationSkylake
Definition OcCpuLib.h:50
@ OcCpuGenerationPreYonah
Definition OcCpuLib.h:38
OC_TYPING_BUFFER_ENTRY Buffer[OC_TYPING_BUFFER_SIZE]
Definition OcTypingLib.h:42
#define AMD_CPU_EXT_FAMILY_17H
#define CPU_MODEL_SKYLAKE_W
#define CPU_MODEL_IVYBRIDGE_EP
#define CPU_MODEL_TIGERLAKE_U
#define AMD_CPU_EXT_FAMILY_19H
#define K10_PSTATE_STATUS
#define CPU_MODEL_MEROM
Allendale, Conroe, Kentsfield, Woodcrest, Clovertown, Tigerton, Merom.
#define CPU_MODEL_IVYBRIDGE
Ivy Bridge.
#define K10_COFVID_STATUS
#define CPU_MODEL_ARROWLAKE_U
#define CPU_MODEL_ROCKETLAKE_S
desktop RocketLake
#define CPU_MODEL_SKYLAKE_DT
#define CPU_MODEL_CANNONLAKE
#define CPU_MODEL_AIRMONT
CherryTrail / Braswell.
#define CPU_MODEL_BANIAS
Banias.
#define CPU_MODEL_ARROWLAKE_S
desktop ArrowLake
#define CPU_MODEL_SILVERMONT
Bay Trail.
#define CPU_MODEL_ARROWLAKE_HX
#define CPU_MODEL_RAPTORLAKE_S
Raptor Lake B0 stepping.
#define CPU_MODEL_JAKETOWN
Sandy Bridge Xeon E5, Core i7 Extreme.
#define CPU_MODEL_YONAH
Sossaman, Yonah.
#define CPU_MODEL_BROADWELL_EP
Broadwell_EP.
#define CPU_MODEL_COMETLAKE_S
desktop CometLake
#define CPU_MODEL_NEHALEM
Bloomfield, Nehalem-EP, Nehalem-WS, Gainestown.
#define CPU_MODEL_COMETLAKE_U
#define AMD_CPU_EXT_FAMILY_16H
#define AMD_CPU_EXT_FAMILY_10H
#define CPU_MODEL_BRYSTALWELL
#define CPU_MODEL_ICELAKE_U
#define CPU_MODEL_HASWELL
#define CPU_MODEL_CRYSTALWELL
#define CPU_MODEL_WESTMERE
Gulftown, Westmere-EP, Westmere-WS.
#define CPU_MODEL_WESTMERE_EX
#define CPU_MODEL_HASWELL_ULT
Haswell ULT.
#define CPU_MODEL_ICELAKE_Y
#define AMD_CPU_FAMILY
#define AMD_CPU_EXT_FAMILY_15H
#define CPU_MODEL_PENRYN
Wolfdale, Yorkfield, Harpertown, Penryn.
#define CPU_MODEL_RAPTORLAKE_HX
Raptor Lake C0 stepping.
#define CPU_MODEL_HASWELL_EP
Haswell MB.
#define CPU_MODEL_SKYLAKE
Skylake-S.
#define K8_FIDVID_STATUS
#define CPU_MODEL_FIELDS
Lynnfield, Clarksfield, Jasper Forest.
#define CPU_MODEL_AVOTON
Avaton/Rangely.
#define MSR_CORE_THREAD_COUNT
#define AMD_CPU_EXT_FAMILY_0FH
#define MSR_IA32_EXT_CONFIG
#define CPU_MODEL_NEHALEM_EX
Beckton.
#define MSR_FLEX_RATIO
#define CPU_MODEL_DALES_32NM
Clarkdale, Arrandale.
#define AMD_CPU_EXT_FAMILY_1AH
#define CPU_MODEL_ALDERLAKE_S
#define CPU_MODEL_ICELAKE_SP
Some variation of Ice Lake.
#define CPU_MODEL_DOTHAN
Dothan.
#define CPU_MODEL_BONNELL
Bonnell, Silverthorne, Diamondville, Pineview.
#define CPU_MODEL_BROADWELL
Broadwell.
#define CPU_MODEL_GOLDMONT
Apollo Lake.
#define CPU_MODEL_KABYLAKE_DT
#define CPU_MODEL_KABYLAKE
Kabylake Dektop.
#define CPU_MODEL_DALES
Havendale, Auburndale.
#define FLEX_RATIO_EN
#define CPU_MODEL_BONNELL_MID
Bonnell, Lincroft.
#define CPU_MODEL_SANDYBRIDGE
Sandy Bridge.
VOID *EFIAPI ZeroMem(OUT VOID *Buffer, IN UINTN Length)
EFI_GUID gEfiMpServiceProtocolGuid
UINT64 EFIAPI RShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:86
UINT64 EFIAPI LShiftU64(IN UINT64 Operand, IN UINTN Count)
Definition UserMath.c:76
UINT64 EFIAPI AsmReadTsc(VOID)
Definition UserMisc.c:232
UINT32 AsmCpuid(IN UINT32 Index, OUT UINT32 *Eax, OPTIONAL OUT UINT32 *Ebx, OPTIONAL OUT UINT32 *Ecx, OPTIONAL OUT UINT32 *Edx OPTIONAL)
Definition UserMisc.c:45
UINT32 AsmCpuidEx(IN UINT32 Index, IN UINT32 SubIndex, OUT UINT32 *Eax, OPTIONAL OUT UINT32 *Ebx, OPTIONAL OUT UINT32 *Ecx, OPTIONAL OUT UINT32 *Edx OPTIONAL)
Definition UserMisc.c:109
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition UserMisc.c:223
UINT64 EFIAPI AsmWriteMsr64(IN UINT32 Index, IN UINT64 Value)
Definition UserMisc.c:250
#define ASSERT(x)
Definition coder.h:55
#define DivU64x32(x, y, z)
FRAMEWORK_EFI_MP_SERVICES_STARTUP_ALL_APS StartupAllAPs
EFI_MP_SERVICES_PROTOCOL * MpServices
Definition OcCpuLib.h:226
volatile UINT32 CurrentCount