Git conversion: Make reactos the root directory, move rosapps, rostests, wallpapers...
[reactos.git] / boot / environ / lib / platform / time.c
diff --git a/boot/environ/lib/platform/time.c b/boot/environ/lib/platform/time.c
new file mode 100644 (file)
index 0000000..bef1b46
--- /dev/null
@@ -0,0 +1,119 @@
+/*
+ * 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
+    )
+{
+#if defined(_M_IX86) || defined(_M_X64)
+    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;
+#else
+    EfiPrintf(L"BlpTimeMeasureTscFrequency not implemented for this platform.\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+NTSTATUS
+BlpTimeCalibratePerformanceCounter (
+    VOID
+    )
+{
+#if defined(_M_IX86) || defined(_M_X64)
+    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);
+                return STATUS_SUCCESS;
+            }
+        }
+    }
+
+    /* On other systems, compute it */
+    return BlpTimeMeasureTscFrequency();
+#else
+    EfiPrintf(L"BlpTimeCalibratePerformanceCounter not implemented for this platform.\r\n");
+    return STATUS_NOT_IMPLEMENTED;
+#endif
+}
+
+ULONGLONG
+BlTimeQueryPerformanceCounter (
+    _Out_opt_ PLARGE_INTEGER Frequency
+    )
+{
+#if defined(_M_IX86) || defined(_M_X64)
+    /* Check if caller wants frequency */
+    if (Frequency)
+    {
+        /* Return it */
+        Frequency->QuadPart = BlpTimePerformanceFrequency;
+    }
+
+    /* Return the TSC value */
+    return __rdtsc();
+#else
+    EfiPrintf(L"BlTimeQueryPerformanceCounter not implemented for this platform.\r\n");
+    return 0;
+#endif
+};