OpenCore  1.0.4
OpenCore Bootloader
Loading...
Searching...
No Matches
FrequencyDetect.c
Go to the documentation of this file.
1
15#include <Uefi.h>
16
17#include <Guid/OcVariable.h>
18#include <Guid/AppleHob.h>
24#include <Protocol/PciIo.h>
25#include <Pi/PiBootMode.h>
26#include <Pi/PiHob.h>
27#include <Library/BaseLib.h>
28#include <Library/BaseMemoryLib.h>
29#include <Library/BaseOverflowLib.h>
30#include <Library/DebugLib.h>
31#include <Library/HobLib.h>
32#include <Library/IoLib.h>
33#include <Library/MemoryAllocationLib.h>
34#include <Library/OcCpuLib.h>
35#include <Library/PciLib.h>
36#include <Library/OcMiscLib.h>
38#include <Library/UefiBootServicesTableLib.h>
39#include <Library/UefiRuntimeServicesTableLib.h>
41#include <Register/Msr.h>
42
43#include "OcCpuInternals.h"
44
45UINTN
47 OUT CONST CHAR8 **Type OPTIONAL
48 )
49{
50 UINTN TimerAddr;
51 UINT32 CpuVendor;
52 EFI_HOB_GUID_TYPE *HobAcpiDescription;
53 EFI_ACPI_DESCRIPTION *AcpiDescription;
54
55 TimerAddr = 0;
56
57 if (Type != NULL) {
58 *Type = "Failure";
59 }
60
61 //
62 // Intel timer support.
63 // Here we obtain the address of 24-bit or 32-bit PM1_TMR.
64 // TODO: I believe that there is little reason to enforce our timer lib to calculate
65 // CPU frequency through ACPI PM timer on modern Intel CPUs. Starting from Skylake
66 // we have crystal clock, which allows us to get quite reliable values. Perhaps
67 // this code should be put to OcCpuLib, and the best available source is to be used.
68 //
69 if (PciRead16 (PCI_ICH_LPC_ADDRESS (0)) == V_ICH_PCI_VENDOR_ID) {
70 //
71 // On legacy platforms PM1_TMR can be found in ACPI I/O space.
72 // 1. For platforms prior to Intel Skylake (Sunrisepoint PCH) iTCO watchdog
73 // resources reside in LPC device (D31:F0).
74 // 2. For platforms from Intel Skylake till Intel Kaby Lake inclusive they reside in
75 // PMC controller (D31:F2).
76 // Checking whether ACPI I/O space is enabled is done via ACPI_CNTL register bit 0.
77 //
78 // On modern platforms, starting from Intel Coffee Lake, the space is roughly the same,
79 // but it is referred to as PMC I/O space, and the addressing is done through BAR2.
80 // In addition to that on B360 and friends PMC controller may be just missing.
81 //
82 if ((PciRead16 (PCI_ICH_LPC_ADDRESS (2)) == V_VLV_PMC_PCI_DEVICE_ID) || (PciRead16 (PCI_ICH_LPC_ADDRESS (2)) == V_CHT_PMC_PCI_DEVICE_ID)) {
84 if (Type != NULL) {
85 *Type = "Braswell PMC";
86 }
89 if (Type != NULL) {
90 *Type = "LPC";
91 }
92 } else if (PciRead16 (PCI_ICH_PMC_ADDRESS (0)) == V_ICH_PCI_VENDOR_ID) {
95 if (Type != NULL) {
96 *Type = "PMC ACPI";
97 }
98 } else if ((PciRead16 (PCI_ICH_PMC_ADDRESS (R_ICH_PMC_BAR2_BASE)) & B_ICH_PMC_BAR2_BASE_BAR_EN) != 0) {
100 if (Type != NULL) {
101 *Type = "PMC BAR2";
102 }
103 } else if (Type != NULL) {
104 *Type = "Invalid INTEL PMC";
105 }
106 } else if (Type != NULL) {
107 //
108 // This is currently the case for Z390 and B360 boards.
109 //
110 *Type = "Unknown INTEL";
111 }
112
113 //
114 // PIIX4 uses a different PCI device and function for PM registers.
115 //
116 } else if ((PciRead16 (PCI_PIIX4_PMC_ADDRESS (0)) == V_ICH_PCI_VENDOR_ID) && (PciRead16 (PCI_PIIX4_PMC_ADDRESS (2)) == V_PIIX4_PMC_PCI_DEVICE_ID)) {
119 if (Type != NULL) {
120 *Type = "PMC PIIX4 ACPI";
121 }
122 }
123 }
124
125 //
126 // AMD timer support.
127 //
128 if (TimerAddr == 0) {
129 //
130 // In an ideal world I believe we should detect AMD SMBus controller...
131 //
132 CpuVendor = 0;
133 AsmCpuid (CPUID_SIGNATURE, NULL, &CpuVendor, NULL, NULL);
134
135 if (CpuVendor == CPUID_VENDOR_AMD) {
136 TimerAddr = MmioRead32 (
138 );
139 if (TimerAddr == MAX_UINT32) {
140 TimerAddr = 0;
141 } else {
142 if (Type != NULL) {
143 *Type = "AMD";
144 }
145 }
146 }
147 }
148
149 //
150 // Fallback to ACPI table HOB installed by DUET.
151 //
152 if (TimerAddr == 0) {
153 //
154 // Get ACPI description HOB.
155 //
156 HobAcpiDescription = GetFirstGuidHob (&gEfiAcpiDescriptionGuid);
157 if (HobAcpiDescription != NULL) {
158 if (sizeof (EFI_ACPI_DESCRIPTION) >= GET_GUID_HOB_DATA_SIZE (HobAcpiDescription)) {
159 AcpiDescription = (EFI_ACPI_DESCRIPTION *)GET_GUID_HOB_DATA (HobAcpiDescription);
160
161 TimerAddr = (UINTN)AcpiDescription->PM_TMR_BLK.Address;
162 if (Type != NULL) {
163 *Type = "ACPI HOB";
164 }
165 }
166 }
167 }
168
169 return TimerAddr;
170}
171
172UINT64
174 IN BOOLEAN Recalculate
175 )
176{
177 //
178 // Cache the result to speed up multiple calls. For example, we might need
179 // this frequency on module entry to initialise a TimerLib instance, and at
180 // a later point in time to gather CPU information.
181 //
182 STATIC UINT64 TSCFrequency = 0;
183
184 UINT16 TimerAddr;
185 UINTN VariableSize;
186 UINT64 TscTicksDelta;
187 UINT32 AcpiTick0;
188 UINT32 AcpiTick1;
189 UINT32 AcpiTicksDelta;
190 UINT32 AcpiTicksDuration;
191 BOOLEAN HasInterrupts;
192 EFI_TPL PrevTpl;
193 EFI_STATUS Status;
194
195 //
196 // Do not use ACPI PM timer in ring 3 (e.g. emulator).
197 //
198 if ((AsmReadCs () & 3U) == 3) {
199 return EFI_UNSUPPORTED;
200 }
201
202 //
203 // Decide whether we need to store the frequency.
204 //
205 if (TSCFrequency == 0) {
206 VariableSize = sizeof (TSCFrequency);
207 Status = gRT->GetVariable (
210 NULL,
211 &VariableSize,
212 &TSCFrequency
213 );
214 } else {
215 Status = EFI_ALREADY_STARTED;
216 }
217
218 if (Recalculate) {
219 TSCFrequency = 0;
220 }
221
222 if (TSCFrequency == 0) {
223 TimerAddr = (UINT16)InternalGetPmTimerAddr (NULL);
224
225 if (TimerAddr != 0) {
226 //
227 // Check that timer is advancing (it does not on some virtual machines).
228 //
229 AcpiTick0 = IoRead32 (TimerAddr);
230 gBS->Stall (500);
231 AcpiTick1 = IoRead32 (TimerAddr);
232
233 if (AcpiTick0 != AcpiTick1) {
234 //
235 // ACPI PM timers are usually of 24-bit length, but there are some less common cases of 32-bit length also.
236 // When the maximal number is reached, it overflows.
237 // The code below can handle overflow with AcpiTicksTarget of up to 24-bit size,
238 // on both available sizes of ACPI PM Timers (24-bit and 32-bit).
239 //
240 // 357954 clocks of ACPI timer (200ms)
241 //
242 AcpiTicksDuration = V_ACPI_TMR_FREQUENCY / 10;
243
244 //
245 // Disable all events to ensure that nobody interrupts us.
246 //
247 PrevTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
248 HasInterrupts = SaveAndDisableInterrupts ();
249 AsmMeasureTicks (AcpiTicksDuration, TimerAddr, &AcpiTicksDelta, &TscTicksDelta);
250 if (HasInterrupts) {
252 }
253
254 gBS->RestoreTPL (PrevTpl);
255
256 TSCFrequency = DivU64x32 (
257 MultU64x32 (TscTicksDelta, V_ACPI_TMR_FREQUENCY),
258 AcpiTicksDelta
259 );
260 }
261 }
262
263 DEBUG ((DEBUG_VERBOSE, "TscFrequency %lld\n", TSCFrequency));
264
265 //
266 // Set the variable if not present and valid.
267 //
268 if ((TSCFrequency != 0) && (Status == EFI_NOT_FOUND)) {
269 //
270 // Do not use OcSetSystemVariable() as this may be called by a
271 // constructor.
272 //
273 gRT->SetVariable (
276 EFI_VARIABLE_BOOTSERVICE_ACCESS,
277 sizeof (TSCFrequency),
278 &TSCFrequency
279 );
280 }
281 }
282
283 return TSCFrequency;
284}
285
286STATIC
287UINT64
289 IN UINT64 *FsbFrequency,
290 IN UINT32 FsbFrequncyCount
291 )
292{
293 UINT32 Pll;
294
295 if (FsbFrequncyCount < 5) {
296 return 0 /* Invalid */;
297 }
298
299 //
300 // Tested on nForce MCP89 installed in MacBook7,1.
301 //
303
304 DEBUG ((
305 DEBUG_INFO,
306 "OCCPU: Selecting FSB freq by PLL freq %u from %Lu %Lu %Lu %Lu %Lu\n",
307 Pll,
308 FsbFrequency[0],
309 FsbFrequency[1],
310 FsbFrequency[2],
311 FsbFrequency[3],
312 FsbFrequency[4]
313 ));
314
315 Pll /= 1000000;
316
317 if (Pll == 16) {
318 return FsbFrequency[0];
319 }
320
321 if ((Pll >= 1063) && (Pll <= 1069)) {
322 return FsbFrequency[0];
323 }
324
325 if ((Pll >= 530) && (Pll <= 536)) {
326 return FsbFrequency[1];
327 }
328
329 if ((Pll >= 797) && (Pll <= 803)) {
330 return FsbFrequency[2];
331 }
332
333 if ((Pll >= 663) && (Pll <= 669)) {
334 return FsbFrequency[3];
335 }
336
337 if ((Pll >= 1330) && (Pll <= 1336)) {
338 return FsbFrequency[4];
339 }
340
341 return 0 /* Invalid */;
342}
343
344UINT64
346 OUT UINT64 *FSBFrequency OPTIONAL,
347 IN BOOLEAN Recalculate
348 )
349{
350 //
351 // Cache the result to speed up multiple calls.
352 //
353 STATIC BOOLEAN ObtainedFreqs = FALSE;
354 STATIC UINT64 FsbFreq = 0;
355 STATIC UINT64 TscFreq = 0;
356
357 EFI_STATUS Status;
359 UINT32 Size;
360 UINT64 *FsbFreqs;
361 UINT32 Un44;
362 UINT32 Un78;
363 UINT64 Dividend;
364 UINT32 Divisor;
365
366 if (Recalculate) {
367 ObtainedFreqs = FALSE;
368 FsbFreq = 0;
369 TscFreq = 0;
370 }
371
372 if (!ObtainedFreqs) {
373 ObtainedFreqs = TRUE;
374 Size = sizeof (FsbFreq);
375
376 Status = gBS->LocateProtocol (
378 NULL,
379 (VOID **)&PlatformInfo
380 );
381 if (!EFI_ERROR (Status)) {
383 PlatformInfo,
385 &Size,
386 &FsbFreq
387 );
388
389 if (EFI_ERROR (Status)) {
390 DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency first data - %r, trying HOB method\n", Status));
391 Status = OcReadApplePlatformData (
392 PlatformInfo,
395 &Size,
396 &FsbFreq
397 );
398 }
399
400 if (EFI_ERROR (Status)) {
401 DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency data using HOB method - %r, trying legacy\n", Status));
403 PlatformInfo,
405 &Size,
406 (VOID **)&FsbFreqs
407 );
408 if (!EFI_ERROR (Status)) {
409 if ((Size >= sizeof (UINT64)) && (Size % sizeof (UINT64) == 0)) {
410 FsbFreq = InternalSelectAppleFsbFrequency (FsbFreqs, Size / sizeof (UINT64));
411 } else {
412 DEBUG ((DEBUG_INFO, "OCCPU: Invalid FSBFrequency list size %u - %r\n", Size, Status));
413 Status = EFI_INVALID_PARAMETER;
414 }
415
416 FreePool (FsbFreqs);
417 }
418 }
419 } else {
420 DEBUG ((DEBUG_VERBOSE, "OCCPU: Failed to locate ApplePlatformInfo protocol - %r\n", Status));
421 }
422
423 //
424 // This is not necessarily Apple, but keep it here for the time being.
425 // Should work on more or less any MCP79 device.
426 //
427 if (EFI_ERROR (Status)) {
428 DEBUG ((DEBUG_INFO, "OCCPU: Failed to get FSBFrequency data using Apple Platform Info - %r\n", Status));
429
433
434 Dividend = NVIDIA_MCP79_GET_FSB_FREQUENCY_DIVIDEND (Un44, Un78);
435 Divisor = NVIDIA_MCP79_GET_FSB_FREQUENCY_DIVISOR (Un44, Un78);
436
437 DEBUG ((
438 DEBUG_INFO,
439 "OCCPU: Found nForce MCP MC 0x%08X (UN44 0x%08X, UN78 0x%08X, DVD 0x%016Lx, DIV 0x%08X)\n",
441 Un44,
442 Un78,
443 Dividend,
444 Divisor
445 ));
446
447 if (Divisor != 0) {
448 FsbFreq = DivU64x32 (Dividend, Divisor);
449 if (FsbFreq != 0) {
450 Status = EFI_SUCCESS;
451 }
452 }
453 }
454 }
455
456 if (EFI_ERROR (Status)) {
457 return 0;
458 }
459
460 TscFreq = InternalConvertAppleFSBToTSCFrequency (FsbFreq);
461 }
462
463 //
464 // Optionally update FSBFrequency.
465 //
466 if (FSBFrequency != NULL) {
467 *FSBFrequency = FsbFreq;
468 }
469
470 return TscFreq;
471}
472
473UINT64
475 OUT UINT64 *CPUFrequency,
476 OUT UINT64 *TscAdjustPtr OPTIONAL,
477 IN BOOLEAN Recalculate
478 )
479{
480 //
481 // Cache the result to speed up multiple calls. For example, we might need
482 // this frequency on module entry to initialise a TimerLib instance, and at
483 // a later point in time to gather CPU information.
484 //
485 STATIC BOOLEAN ObtainedARTFreq = FALSE;
486 STATIC UINT64 ARTFrequency = 0;
487 STATIC UINT64 CPUFrequencyFromART = 0;
488
489 UINT32 MaxId;
490 UINT32 CpuVendor;
491
492 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EBX CpuidFeatureFlagsEbx;
493 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_ECX CpuidFeatureFlagsEcx;
494 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS_EDX CpuidFeatureFlagsEdx;
495 UINT32 CpuidDenominatorEax;
496 UINT32 CpuidNumeratorEbx;
497 UINT32 CpuidARTFrequencyEcx;
498 CPUID_PROCESSOR_FREQUENCY_EAX CpuidFrequencyEax;
499 UINT64 TscAdjust;
500 UINT64 CPUFrequencyFromTSC;
501 CPUID_VERSION_INFO_EAX CpuidVerEax;
502 UINT8 Model;
503
504 if (Recalculate) {
505 ObtainedARTFreq = FALSE;
506 ARTFrequency = 0;
507 CPUFrequencyFromART = 0;
508 }
509
510 if (!ObtainedARTFreq) {
511 ObtainedARTFreq = TRUE;
512
513 //
514 // Get vendor CPUID 0x00000000
515 //
516 AsmCpuid (CPUID_SIGNATURE, &MaxId, &CpuVendor, NULL, NULL);
517 //
518 // Determine our core crystal clock frequency
519 //
520 if (CpuVendor == CPUID_VENDOR_INTEL) {
521 if (MaxId >= CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS) {
522 AsmCpuidEx (
523 CPUID_STRUCTURED_EXTENDED_FEATURE_FLAGS,
524 0,
525 NULL,
526 &CpuidFeatureFlagsEbx.Uint32,
527 &CpuidFeatureFlagsEcx.Uint32,
528 &CpuidFeatureFlagsEdx.Uint32
529 );
530 if (CpuidFeatureFlagsEbx.Bits.IA32_TSC_ADJUST == 1) {
531 TscAdjust = AsmReadMsr64 (MSR_IA32_TSC_ADJUST);
532 DEBUG ((DEBUG_INFO, "OCCPU: TSC Adjust %Lu\n", TscAdjust));
533
534 if (TscAdjustPtr != NULL) {
535 *TscAdjustPtr = TscAdjust;
536 }
537 }
538 }
539
540 if (MaxId >= CPUID_TIME_STAMP_COUNTER) {
541 AsmCpuid (
542 CPUID_TIME_STAMP_COUNTER,
543 &CpuidDenominatorEax,
544 &CpuidNumeratorEbx,
545 &CpuidARTFrequencyEcx,
546 NULL
547 );
548 if (CpuidARTFrequencyEcx > 0) {
549 ARTFrequency = CpuidARTFrequencyEcx;
550 DEBUG ((DEBUG_INFO, "OCCPU: Queried Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
551 } else {
552 AsmCpuid (CPUID_VERSION_INFO, &CpuidVerEax.Uint32, NULL, NULL, NULL);
553 Model = (UINT8)CpuidVerEax.Bits.Model | (UINT8)(CpuidVerEax.Bits.ExtendedModelId << 4U);
554 //
555 // Fall back to identifying ART frequency based on known models
556 //
557 switch (Model) {
562 ARTFrequency = CLIENT_ART_CLOCK_SOURCE; // 24 Mhz
563 break;
565 ARTFrequency = SERVER_ART_CLOCK_SOURCE; // 25 Mhz
566 break;
568 ARTFrequency = ATOM_ART_CLOCK_SOURCE; // 19.2 Mhz
569 break;
570 }
571
572 if (ARTFrequency > 0) {
573 DEBUG ((DEBUG_INFO, "OCCPU: Known Model Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
574 }
575 }
576
577 if ((CpuidDenominatorEax > 0) && (CpuidNumeratorEbx > 0)) {
578 //
579 // Some Intel chips don't report their core crystal clock frequency.
580 // Calculate it by dividing the TSC frequency by the TSC ratio.
581 //
582 if ((ARTFrequency == 0) && (MaxId >= CPUID_PROCESSOR_FREQUENCY)) {
583 CPUFrequencyFromTSC = InternalCalculateTSCFromPMTimer (Recalculate);
584 ARTFrequency = BaseMultThenDivU64x64x32 (
585 CPUFrequencyFromTSC,
586 CpuidDenominatorEax,
587 CpuidNumeratorEbx,
588 NULL
589 );
590 if (ARTFrequency > 0ULL) {
591 DEBUG ((
592 DEBUG_INFO,
593 "OCCPU: Core Crystal Clock Frequency from TSC %11LuHz = %11LuHz * %u / %u\n",
594 ARTFrequency,
595 CPUFrequencyFromTSC,
596 CpuidDenominatorEax,
597 CpuidNumeratorEbx
598 ));
599 //
600 // Use the reported CPU frequency rather than deriving it from ARTFrequency
601 //
602 AsmCpuid (CPUID_PROCESSOR_FREQUENCY, &CpuidFrequencyEax.Uint32, NULL, NULL, NULL);
603 CPUFrequencyFromART = MultU64x32 (CpuidFrequencyEax.Bits.ProcessorBaseFrequency, 1000000);
604 }
605 }
606
607 //
608 // If we still can't determine the core crystal clock frequency, assume
609 // it's 24 Mhz like most Intel chips to date.
610 //
611 if (ARTFrequency == 0ULL) {
612 ARTFrequency = DEFAULT_ART_CLOCK_SOURCE;
613 DEBUG ((DEBUG_INFO, "OCCPU: Fallback Core Crystal Clock Frequency %11LuHz\n", ARTFrequency));
614 }
615
616 ASSERT (ARTFrequency > 0ULL);
617 if (CPUFrequencyFromART == 0ULL) {
618 CPUFrequencyFromART = BaseMultThenDivU64x64x32 (
619 ARTFrequency,
620 CpuidNumeratorEbx,
621 CpuidDenominatorEax,
622 NULL
623 );
624 }
625
626 ASSERT (CPUFrequencyFromART > 0ULL);
627 DEBUG ((
628 DEBUG_INFO,
629 "OCCPU: CPUFrequencyFromART %11LuHz %5LuMHz = %Lu * %u / %u\n",
630 CPUFrequencyFromART,
631 DivU64x32 (CPUFrequencyFromART, 1000000),
632 ARTFrequency,
633 CpuidNumeratorEbx,
634 CpuidDenominatorEax
635 ));
636 }
637 }
638 }
639 }
640
641 *CPUFrequency = CPUFrequencyFromART;
642 return ARTFrequency;
643}
644
645UINT64
647 OUT UINT64 *FSBFrequency OPTIONAL,
648 OUT BOOLEAN *UnderHypervisor OPTIONAL
649 )
650{
651 UINT32 CpuidEax;
652 UINT32 CpuidEbx;
653 UINT32 CpuidEcx;
654 UINT32 CpuidEdx;
655 CPUID_VERSION_INFO_ECX CpuidVerEcx;
656
657 CHAR8 HvVendor[13];
658 UINT64 Msr;
659
660 AsmCpuid (
661 CPUID_VERSION_INFO,
662 NULL,
663 NULL,
664 &CpuidVerEcx.Uint32,
665 NULL
666 );
667
668 if (FSBFrequency != NULL) {
669 *FSBFrequency = 0;
670 }
671
672 if (UnderHypervisor != NULL) {
673 *UnderHypervisor = CpuidVerEcx.Bits.ParaVirtualized != 0;
674 }
675
676 //
677 // TODO: We do not have Hypervisor support in EDK II CPUID structure yet.
678 // See https://github.com/acidanthera/audk/pull/2.
679 // Get Hypervisor/Virtualization information.
680 //
681 if (CpuidVerEcx.Bits.ParaVirtualized == 0) {
682 return 0;
683 }
684
685 //
686 // If we are under virtualization and cpuid invtsc is enabled, we can just read
687 // TSCFrequency and FSBFrequency from VMWare Timing node instead of reading MSR
688 // (which hypervisors may not implemented yet), at least in QEMU/VMWare it works.
689 // Source:
690 // 1. CPUID usage for interaction between Hypervisors and Linux.:
691 // https://lwn.net/Articles/301888/
692 // 2. [Qemu-devel] [PATCH v2 0/3] x86-kvm: Fix Mac guest timekeeping by exposi:
693 // https://lists.gnu.org/archive/html/qemu-devel/2017-01/msg04344.html
694 //
695 // Hyper-V only implements MSRs for TSC and FSB frequencies in Hz.
696 // These MSRs are supported only on Windows Server 2012 / Windows 8 and newer.
697 // Older platforms will need to use the PIIX4 ACPI PM timer.
698 // See https://docs.microsoft.com/en-us/virtualization/hyper-v-on-windows/reference/tlfs
699 //
700 AsmCpuid (0x40000000, &CpuidEax, &CpuidEbx, &CpuidEcx, &CpuidEdx);
701
702 CopyMem (&HvVendor[0], &CpuidEbx, sizeof (UINT32));
703 CopyMem (&HvVendor[4], &CpuidEcx, sizeof (UINT32));
704 CopyMem (&HvVendor[8], &CpuidEdx, sizeof (UINT32));
705 HvVendor[12] = '\0';
706
707 if (AsciiStrCmp (HvVendor, "Microsoft Hv") == 0) {
708 //
709 // HV_X64_MSR_APIC_FREQUENCY
710 //
711 Msr = AsmReadMsr64 (0x40000023);
712 if (FSBFrequency != NULL) {
713 *FSBFrequency = Msr;
714 }
715
716 //
717 // HV_X64_MSR_TSC_FREQUENCY
718 //
719 Msr = AsmReadMsr64 (0x40000022);
720 return Msr;
721 }
722
723 if (AsciiStrCmp (HvVendor, "XenVMMXenVMM") == 0) {
724 // Xen implement TSC frequency as CPUID leaf (0x40000003/0/ecx).
725 // Hardcoded FSB frequency to 100 MHz, as it's not exposed currently.
726 AsmCpuidEx (0x40000003, 0, NULL, NULL, &CpuidEcx, NULL);
727 if (FSBFrequency != NULL) {
728 *FSBFrequency = 100000000;
729 }
730
731 return CpuidEcx * 1000ULL;
732 }
733
734 //
735 // Other hypervisors implement TSC/FSB frequency as an additional CPUID leaf.
736 //
737 if (CpuidEax < 0x40000010) {
738 return 0;
739 }
740
741 AsmCpuid (0x40000010, &CpuidEax, &CpuidEbx, NULL, NULL);
742 if ((CpuidEax == 0) || (CpuidEbx == 0)) {
743 return 0;
744 }
745
746 //
747 // We get kHZ from node and we should translate it first.
748 //
749 if (FSBFrequency != NULL) {
750 *FSBFrequency = CpuidEbx * 1000ULL;
751 }
752
753 return CpuidEax * 1000ULL;
754}
755
756//
757// This function and everything called by it must not log (after the first early call
758// to it, which can log and cache results), otherwise it will generate a loop when it
759// gets called during first log line.
760//
761UINT64
763 VOID
764 )
765{
766 UINT64 CPUFrequency;
767
768 //
769 // For Intel platforms (the vendor check is covered by the callee), prefer
770 // the CPU Frequency derieved from the ART, as the PM timer might not be
771 // available (e.g. 300 series chipsets).
772 // TODO: For AMD, the base clock can be determined from P-registers.
773 //
774 InternalCalculateARTFrequencyIntel (&CPUFrequency, NULL, FALSE);
775 if (CPUFrequency == 0) {
776 CPUFrequency = InternalCalculateVMTFrequency (NULL, NULL);
777 if (CPUFrequency == 0) {
778 CPUFrequency = InternalCalculateTSCFromApplePlatformInfo (NULL, FALSE);
779 if (CPUFrequency == 0) {
780 CPUFrequency = InternalCalculateTSCFromPMTimer (FALSE);
781 if (CPUFrequency == 0) {
782 //
783 // Assume at least some frequency, so that we always work.
784 //
785 CPUFrequency = OC_FALLBACK_CPU_FREQUENCY;
786 }
787 }
788 }
789 }
790
791 //
792 // For all known models with an invariant TSC, its frequency is equal to the
793 // CPU's specified base clock.
794 //
795 return CPUFrequency;
796}
EFI_GUID gEfiAcpiDescriptionGuid
EFI_GUID gAppleFsbFrequencyPlatformInfoIndexHobGuid
EFI_GUID gAppleFsbFrequencyListPlatformInfoGuid
EFI_GUID gAppleFsbFrequencyPlatformInfoGuid
EFI_GUID gApplePlatformInfoDatabaseProtocolGuid
#define CPUID_VENDOR_INTEL
Definition CpuId.h:214
#define CPUID_VENDOR_AMD
Definition CpuId.h:215
UINT64 OcGetTSCFrequency(VOID)
UINTN InternalGetPmTimerAddr(OUT CONST CHAR8 **Type OPTIONAL)
STATIC UINT64 InternalSelectAppleFsbFrequency(IN UINT64 *FsbFrequency, IN UINT32 FsbFrequncyCount)
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)
#define B_ICH_PMC_BAR2_BASE_BAR
Definition GenericIch.h:77
#define B_ICH_PMC_ACPI_BASE_BAR
Definition GenericIch.h:70
#define V_CHT_PMC_PCI_DEVICE_ID
Intel Bay-Trail/Cherry-Trail PMC device-id.
Definition GenericIch.h:40
#define PCI_ICH_PMC_ADDRESS(Register)
Macro to generate the PCI address of any given ICH PMC Register.
Definition GenericIch.h:106
#define R_ACPI_PM1_TMR
Definition GenericIch.h:93
#define R_ICH_LPC_ACPI_BASE
Definition GenericIch.h:62
#define R_ICH_PMC_BAR2_BASE
Definition GenericIch.h:76
#define B_PIIX4_PMREGMISC_PMIOSE
Definition GenericIch.h:47
#define B_PIIX4_PM_BASE_BAR
Definition GenericIch.h:45
#define R_AMD_ACPI_PM_TMR_BLOCK
AcpiPmTmrBlk (3-289)
Definition GenericIch.h:89
#define B_ICH_PMC_BAR2_BASE_BAR_EN
Definition GenericIch.h:78
#define R_AMD_ACPI_MMIO_BASE
AcpiMMioAddr (3-268)
Definition GenericIch.h:87
#define R_PIIX4_PMREGMISC
See PMIOSE.
Definition GenericIch.h:46
#define R_ICH_PMC_ACPI_BASE
Definition GenericIch.h:69
#define PCI_ICH_LPC_ADDRESS(Register)
Macro to generate the PCI address of any given ICH LPC Register.
Definition GenericIch.h:102
#define R_PIIX4_PM_BASE
Definition GenericIch.h:44
#define B_ICH_LPC_ACPI_CNTL_ACPI_EN
Definition GenericIch.h:65
#define R_AMD_ACPI_MMIO_PMIO_BASE
PMIO (3-268)
Definition GenericIch.h:88
#define V_ACPI_TMR_FREQUENCY
Definition GenericIch.h:94
#define B_ICH_PMC_ACPI_CNTL_ACPI_EN
Definition GenericIch.h:72
#define V_VLV_PMC_PCI_DEVICE_ID
Intel Valley View PMC device-id.
Definition GenericIch.h:39
#define PCI_PIIX4_PMC_ADDRESS(Register)
Macro to generate the PCI address of any given PIIX4 PMC Register.
Definition GenericIch.h:98
#define V_PIIX4_PMC_PCI_DEVICE_ID
Intel PIIX4 PMC device-id.
Definition GenericIch.h:38
#define V_ICH_PCI_VENDOR_ID
Intel vendor-id.
Definition GenericIch.h:37
#define R_BRSW_PMC_ACPI_BASE
Definition GenericIch.h:82
#define R_ICH_PMC_ACPI_CNTL
Definition GenericIch.h:71
#define B_ICH_LPC_ACPI_BASE_BAR
Definition GenericIch.h:63
#define R_ICH_LPC_ACPI_CNTL
Definition GenericIch.h:64
#define B_BRSW_PMC_ACPI_BASE_BAR
Definition GenericIch.h:83
#define B_NVIDIA_MCP_MC_BASE
#define R_NVIDIA_MCP_MC_UN78
#define R_NVIDIA_MCP89_DDR_PLL
#define R_NVIDIA_MCP_MC_UN44
#define V_NVIDIA_MCP_MC_VENDOR
#define NVIDIA_MCP79_GET_FSB_FREQUENCY_DIVIDEND(Un44, Un78)
#define NVIDIA_MCP79_GET_FSB_FREQUENCY_DIVISOR(Un44, Un78)
VOID EFIAPI AsmMeasureTicks(IN UINT32 AcpiTicksDuration, IN UINT16 TimerAddr, OUT UINT32 *AcpiTicksDelta, OUT UINT64 *TscTicksDelta)
DMG_SIZE_DEVICE_PATH Size
EFI_BOOT_SERVICES * gBS
UINT64 InternalConvertAppleFSBToTSCFrequency(IN UINT64 FSBFrequency)
Definition OcCpuLib.c:383
#define OC_FALLBACK_CPU_FREQUENCY
Definition OcCpuLib.h:29
EFI_STATUS OcReadApplePlatformFirstDataAlloc(IN APPLE_PLATFORM_INFO_DATABASE_PROTOCOL *PlatformInfo, IN EFI_GUID *DataGuid, OUT UINT32 *Size, OUT VOID **Data)
EFI_STATUS OcReadApplePlatformFirstData(IN APPLE_PLATFORM_INFO_DATABASE_PROTOCOL *PlatformInfo, IN EFI_GUID *DataGuid, IN OUT UINT32 *Size, OUT VOID *Data)
EFI_STATUS OcReadApplePlatformData(IN APPLE_PLATFORM_INFO_DATABASE_PROTOCOL *PlatformInfo, IN EFI_GUID *DataGuid, IN EFI_GUID *HobGuid, IN OUT UINT32 *Size, OUT VOID *Data)
EFI_GUID gOcVendorVariableGuid
#define OC_ACPI_CPU_FREQUENCY_VARIABLE_NAME
Definition OcVariable.h:75
#define SERVER_ART_CLOCK_SOURCE
#define CPU_MODEL_SKYLAKE_DT
#define CPU_MODEL_DENVERTON
Goldmont Microserver.
#define CLIENT_ART_CLOCK_SOURCE
#define DEFAULT_ART_CLOCK_SOURCE
#define CPU_MODEL_SKYLAKE
Skylake-S.
#define CPU_MODEL_GOLDMONT
Apollo Lake.
#define CPU_MODEL_KABYLAKE_DT
#define CPU_MODEL_KABYLAKE
Kabylake Dektop.
#define ATOM_ART_CLOCK_SOURCE
VOID *EFIAPI CopyMem(OUT VOID *DestinationBuffer, IN CONST VOID *SourceBuffer, IN UINTN Length)
EFI_RUNTIME_SERVICES * gRT
UINT64 EFIAPI MultU64x32(IN UINT64 Multiplicand, IN UINT32 Multiplier)
Definition UserMath.c:96
VOID *EFIAPI GetFirstGuidHob(IN CONST EFI_GUID *Guid)
Definition UserMisc.c:671
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
VOID EFIAPI EnableInterrupts(VOID)
Definition UserMisc.c:38
UINT64 EFIAPI AsmReadMsr64(IN UINT32 Index)
Definition UserMisc.c:223
UINT16 EFIAPI MmioRead16(IN UINTN Address)
Definition UserMisc.c:614
UINT32 EFIAPI MmioRead32(IN UINTN Address)
Definition UserMisc.c:623
UINT16 EFIAPI AsmReadCs(VOID)
Definition UserMisc.c:205
UINT32 EFIAPI IoRead32(IN UINTN Port)
Definition UserMisc.c:318
#define ASSERT(x)
Definition coder.h:55
#define DivU64x32(x, y, z)
EFI_ACPI_3_0_GENERIC_ADDRESS_STRUCTURE PM_TMR_BLK