[NTOS:KE/x64] Calculate the CPU frequency on AMD64

This should be performed early enough before CM initialization,
but after the TSC has been initialized and calibrated by HAL.

Based on existing i386 kiinit code. CORE-17971 CORE-14922
This commit is contained in:
Stanislav Motylkov 2023-07-12 15:28:48 +03:00
parent 1896383eb0
commit e2a587c2ef

View File

@ -30,6 +30,89 @@ KiInitializeKernel(IN PKPROCESS InitProcess,
IN PLOADER_PARAMETER_BLOCK LoaderBlock);
CODE_SEG("INIT")
VOID
KiCalculateCpuFrequency(
IN PKPRCB Prcb)
{
if (Prcb->FeatureBits & KF_RDTSC)
{
ULONG Sample = 0;
CPU_INFO CpuInfo;
KI_SAMPLE_MAP Samples[10];
PKI_SAMPLE_MAP CurrentSample = Samples;
/* Start sampling loop */
for (;;)
{
/* Do a dummy CPUID to start the sample */
KiCpuId(&CpuInfo, 0);
/* Fill out the starting data */
CurrentSample->PerfStart = KeQueryPerformanceCounter(NULL);
CurrentSample->TSCStart = __rdtsc();
CurrentSample->PerfFreq.QuadPart = -50000;
/* Sleep for this sample */
KeStallExecutionProcessor(CurrentSample->PerfFreq.QuadPart * -1 / 10);
/* Do another dummy CPUID */
KiCpuId(&CpuInfo, 0);
/* Fill out the ending data */
CurrentSample->PerfEnd =
KeQueryPerformanceCounter(&CurrentSample->PerfFreq);
CurrentSample->TSCEnd = __rdtsc();
/* Calculate the differences */
CurrentSample->PerfDelta = CurrentSample->PerfEnd.QuadPart -
CurrentSample->PerfStart.QuadPart;
CurrentSample->TSCDelta = CurrentSample->TSCEnd -
CurrentSample->TSCStart;
/* Compute CPU Speed */
CurrentSample->MHz = (ULONG)((CurrentSample->TSCDelta *
CurrentSample->
PerfFreq.QuadPart + 500000) /
(CurrentSample->PerfDelta *
1000000));
/* Check if this isn't the first sample */
if (Sample)
{
/* Check if we got a good precision within 1MHz */
if ((CurrentSample->MHz == CurrentSample[-1].MHz) ||
(CurrentSample->MHz == CurrentSample[-1].MHz + 1) ||
(CurrentSample->MHz == CurrentSample[-1].MHz - 1))
{
/* We did, stop sampling */
break;
}
}
/* Move on */
CurrentSample++;
Sample++;
if (Sample == RTL_NUMBER_OF(Samples))
{
/* No luck. Average the samples and be done */
ULONG TotalMHz = 0;
while (Sample--)
{
TotalMHz += Samples[Sample].MHz;
}
CurrentSample[-1].MHz = TotalMHz / RTL_NUMBER_OF(Samples);
DPRINT1("Sampling CPU frequency failed. Using average of %lu MHz\n", CurrentSample[-1].MHz);
break;
}
}
/* Save the CPU Speed */
Prcb->MHz = CurrentSample[-1].MHz;
}
}
VOID
NTAPI
KiInitializeHandBuiltThread(
@ -105,6 +188,9 @@ KiSystemStartupBootStack(VOID)
}
}
/* Calculate the CPU frequency */
KiCalculateCpuFrequency(Prcb);
/* Raise to Dispatch */
KfRaiseIrql(DISPATCH_LEVEL);