1 /* 2 * COPYRIGHT: See COPYING.ARM in the top level directory 3 * PROJECT: ReactOS UEFI Boot Library 4 * FILE: boot/environ/lib/platform/time.c 5 * PURPOSE: Boot Library Time Management Routines 6 * PROGRAMMER: Alex Ionescu (alex.ionescu@reactos.org) 7 */ 8 9 /* INCLUDES ******************************************************************/ 10 11 #include "bl.h" 12 13 /* DATA VARIABLES ************************************************************/ 14 15 ULONGLONG BlpTimePerformanceFrequency; 16 17 /* FUNCTIONS *****************************************************************/ 18 19 NTSTATUS 20 BlpTimeMeasureTscFrequency ( 21 VOID 22 ) 23 { 24 #if defined(_M_IX86) || defined(_M_X64) 25 ULONG Count; 26 INT CpuInfo[4]; 27 ULONGLONG TimeStamp1, TimeStamp2, Delta; 28 29 /* Check if the ISVM bit it set, meaning we're in a hypervisor */ 30 __cpuid(CpuInfo, 1); 31 Count = CpuInfo[2] & 0x80000000 ? 10 : 1; 32 33 /* Loop trying to get an accurate TSC */ 34 do 35 { 36 /* Stall for 1us and get count 1 */ 37 EfiStall(1); 38 TimeStamp1 = __rdtsc(); 39 40 /* Stall for 1000us and get count 2*/ 41 EfiStall(1000); 42 TimeStamp2 = __rdtsc(); 43 44 /* Stall for 9000us and get the difference */ 45 EfiStall(9000); 46 Delta = __rdtsc() - TimeStamp2; 47 48 /* Keep going as long as the TSC is fluctuating */ 49 --Count; 50 } while (((TimeStamp2 - TimeStamp1) > Delta) && (Count)); 51 52 /* Set the frequency based on the two measurements we took */ 53 BlpTimePerformanceFrequency = 125 * (Delta - (TimeStamp2 - TimeStamp1)) & 0x1FFFFFFFFFFFFFF; 54 return STATUS_SUCCESS; 55 #else 56 EfiPrintf(L"BlpTimeMeasureTscFrequency not implemented for this platform.\r\n"); 57 return STATUS_NOT_IMPLEMENTED; 58 #endif 59 } 60 61 NTSTATUS 62 BlpTimeCalibratePerformanceCounter ( 63 VOID 64 ) 65 { 66 #if defined(_M_IX86) || defined(_M_X64) 67 INT CpuInfo[4]; 68 69 /* Check if the ISVM bit it set, meaning we're in a hypervisor */ 70 __cpuid(CpuInfo, 1); 71 if (CpuInfo[2] & 0x80000000) 72 { 73 /* Get the Hypervisor Identification Leaf */ 74 __cpuid(CpuInfo, 0x40000001); 75 76 /* Is this Hyper-V? */ 77 if (CpuInfo[0] == '1#vH') 78 { 79 /* Get the Hypervisor Feature Identification Leaf */ 80 __cpuid(CpuInfo, 0x40000003); 81 82 /* Check if HV_X64_MSR_REFERENCE_TSC is present */ 83 if (CpuInfo[3] & 0x100) 84 { 85 /* Read the TSC frequency from the MSR */ 86 BlpTimePerformanceFrequency = __readmsr(0x40000022); 87 return STATUS_SUCCESS; 88 } 89 } 90 } 91 92 /* On other systems, compute it */ 93 return BlpTimeMeasureTscFrequency(); 94 #else 95 EfiPrintf(L"BlpTimeCalibratePerformanceCounter not implemented for this platform.\r\n"); 96 return STATUS_NOT_IMPLEMENTED; 97 #endif 98 } 99 100 ULONGLONG 101 BlTimeQueryPerformanceCounter ( 102 _Out_opt_ PLARGE_INTEGER Frequency 103 ) 104 { 105 #if defined(_M_IX86) || defined(_M_X64) 106 /* Check if caller wants frequency */ 107 if (Frequency) 108 { 109 /* Return it */ 110 Frequency->QuadPart = BlpTimePerformanceFrequency; 111 } 112 113 /* Return the TSC value */ 114 return __rdtsc(); 115 #else 116 EfiPrintf(L"BlTimeQueryPerformanceCounter not implemented for this platform.\r\n"); 117 return 0; 118 #endif 119 }; 120