reactos/boot/environ/lib/platform/time.c

106 lines
2.8 KiB
C
Raw Normal View History

/*
* COPYRIGHT: See COPYING.ARM in the top level directory
* PROJECT: ReactOS UEFI Boot Library
* FILE: boot/environ/lib/platform/time.c
* PURPOSE: Boot Library Time Management Routines
* PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org)
*/
/* INCLUDES ******************************************************************/
#include "bl.h"
/* DATA VARIABLES ************************************************************/
ULONGLONG BlpTimePerformanceFrequency;
/* FUNCTIONS *****************************************************************/
NTSTATUS
BlpTimeMeasureTscFrequency (
VOID
)
{
ULONG Count;
INT CpuInfo[4];
ULONGLONG TimeStamp1, TimeStamp2, Delta;
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
__cpuid(CpuInfo, 1);
Count = CpuInfo[2] & 0x80000000 ? 10 : 1;
/* Loop trying to get an accurate TSC */
do
{
/* Stall for 1us and get count 1 */
EfiStall(1);
TimeStamp1 = __rdtsc();
/* Stall for 1000us and get count 2*/
EfiStall(1000);
TimeStamp2 = __rdtsc();
/* Stall for 9000us and get the difference */
EfiStall(9000);
Delta = __rdtsc() - TimeStamp2;
/* Keep going as long as the TSC is fluctuating */
--Count;
} while (((TimeStamp2 - TimeStamp1) > Delta) && (Count));
/* Set the frequency based on the two measurements we took */
BlpTimePerformanceFrequency = 125 * (Delta - (TimeStamp2 - TimeStamp1)) & 0x1FFFFFFFFFFFFFF;
return STATUS_SUCCESS;
}
NTSTATUS
BlpTimeCalibratePerformanceCounter (
VOID
)
{
INT CpuInfo[4];
/* Check if the ISVM bit it set, meaning we're in a hypervisor */
__cpuid(CpuInfo, 1);
if (CpuInfo[2] & 0x80000000)
{
/* Get the Hypervisor Identification Leaf */
__cpuid(CpuInfo, 0x40000001);
/* Is this Hyper-V? */
if (CpuInfo[0] == '1#vH')
{
/* Get the Hypervisor Feature Identification Leaf */
__cpuid(CpuInfo, 0x40000003);
/* Check if HV_X64_MSR_REFERENCE_TSC is present */
if (CpuInfo[3] & 0x100)
{
/* Read the TSC frequency from the MSR */
BlpTimePerformanceFrequency = __readmsr(0x40000022);
EfiPrintf(L"Using Hyper-V frequency as: %I64d\r\n", BlpTimePerformanceFrequency);
return STATUS_SUCCESS;
}
}
}
/* On other systems, compute it */
return BlpTimeMeasureTscFrequency();
}
ULONGLONG
BlTimeQueryPerformanceCounter (
_Out_opt_ PLARGE_INTEGER Frequency
)
{
/* Check if caller wants frequency */
if (Frequency)
{
/* Return it */
Frequency->QuadPart = BlpTimePerformanceFrequency;
}
/* Return the TSC value */
return __rdtsc();
};