VirtualBox

source: vbox/trunk/src/VBox/Runtime/r3/nt/time-nt.cpp@ 107381

Last change on this file since 107381 was 107192, checked in by vboxsync, 2 months ago

IPRT,VMM/TM: Support for GIP time on win.arm64. jiraref:VBP-1266

  • Property svn:eol-style set to native
  • Property svn:keywords set to Id Revision
File size: 7.8 KB
Line 
1/* $Id: time-nt.cpp 107192 2024-11-29 14:42:15Z vboxsync $ */
2/** @file
3 * IPRT - Time, Windows.
4 */
5
6/*
7 * Copyright (C) 2006-2024 Oracle and/or its affiliates.
8 *
9 * This file is part of VirtualBox base platform packages, as
10 * available from https://www.virtualbox.org.
11 *
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation, in version 3 of the
15 * License.
16 *
17 * This program is distributed in the hope that it will be useful, but
18 * WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20 * General Public License for more details.
21 *
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, see <https://www.gnu.org/licenses>.
24 *
25 * The contents of this file may alternatively be used under the terms
26 * of the Common Development and Distribution License Version 1.0
27 * (CDDL), a copy of it is provided in the "COPYING.CDDL" file included
28 * in the VirtualBox distribution, in which case the provisions of the
29 * CDDL are applicable instead of those of the GPL.
30 *
31 * You may elect to license modified versions of this file under the
32 * terms and conditions of either the GPL or the CDDL or both.
33 *
34 * SPDX-License-Identifier: GPL-3.0-only OR CDDL-1.0
35 */
36
37
38/*********************************************************************************************************************************
39* Header Files *
40*********************************************************************************************************************************/
41#define LOG_GROUP RTLOGGROUP_TIME
42#include "internal-r3-nt.h"
43
44#include <iprt/time.h>
45#include <iprt/asm.h>
46#include <iprt/assert.h>
47#include <iprt/errcore.h>
48#include <iprt/ldr.h>
49#include <iprt/uint128.h>
50#include "internal/time.h"
51
52
53/*********************************************************************************************************************************
54* Global Variables *
55*********************************************************************************************************************************/
56/** Whether we've tried to resolve g_pfnRtlGetSystemTimePrecise or not. */
57static bool g_fInitialized = false;
58/** Pointer to RtlGetSystemTimePrecise, added in 6.2 (windows 8). */
59static PFNRTLGETSYSTEMTIMEPRECISE g_pfnRtlGetSystemTimePrecise = NULL;
60
61
62/**
63 * Initializes globals.
64 */
65static void rtTimeNtInitialize(void)
66{
67 /*
68 * Make sure we don't recurse here when calling into RTLdr.
69 */
70 if (ASMAtomicCmpXchgBool(&g_fInitialized, true, false))
71 {
72/** @todo there is a RtlGetInterruptTimePrecise export since W10 */
73 void *pvFunc = RTLdrGetSystemSymbol("ntdll.dll", "RtlGetSystemTimePrecise");
74 if (pvFunc)
75 ASMAtomicWritePtr((void * volatile *)&g_pfnRtlGetSystemTimePrecise, pvFunc);
76 ASMCompilerBarrier();
77 }
78}
79
80
81static uint64_t rtTimeGetSystemNanoTS(void)
82{
83 if (RT_UNLIKELY(!g_fInitialized))
84 rtTimeNtInitialize();
85
86 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
87
88#if 1
89 /*
90 * If there is precise time, get the precise system time and calculate the
91 * interrupt time from it. (Microsoft doesn't expose interrupt time to user
92 * application, which is very unfortunate as there are a lot place where
93 * monotonic time is applicable but developers are "forced" to use the wall
94 * clock.)
95 */
96 if (g_pfnRtlGetSystemTimePrecise)
97 {
98 for (;;)
99 {
100 uint64_t uUpdateLockBefore;
101 while ((uUpdateLockBefore = pUserSharedData->TimeUpdateLock) & 1)
102 ASMNopPause();
103
104 uint64_t uInterruptTime = *(uint64_t volatile *)&pUserSharedData->InterruptTime;
105 uint64_t uBaselineInterruptTimeQpc = pUserSharedData->BaselineInterruptTimeQpc;
106 uint64_t uQpcInterruptTimeIncrement = pUserSharedData->QpcInterruptTimeIncrement;
107 uint8_t uQpcInterruptTimeIncrementShift = pUserSharedData->QpcInterruptTimeIncrementShift;
108 LARGE_INTEGER QpcValue;
109 RtlQueryPerformanceCounter(&QpcValue);
110
111 if (pUserSharedData->TimeUpdateLock == uUpdateLockBefore)
112 {
113 uint64_t uQpcValue = QpcValue.QuadPart;
114 if (uQpcValue <= uBaselineInterruptTimeQpc)
115 return uInterruptTime * 100;
116
117 /* Calc QPC delta since base line. */
118 uQpcValue -= uBaselineInterruptTimeQpc;
119 uQpcValue--;
120
121 /* Multiply by 10 million. */
122 uQpcValue *= UINT32_C(10000000);
123
124 /* Multiply by QPC interrupt time increment value. */
125 RTUINT128U Tmp128;
126 RTUInt128MulU64ByU64(&Tmp128, uQpcValue, uQpcInterruptTimeIncrement);
127
128 /* Shift the upper 64 bits by the increment shift factor. */
129 uint64_t uResult = Tmp128.s.Hi >> uQpcInterruptTimeIncrementShift;
130
131 /* Add to base interrupt time value. */
132 uResult += uInterruptTime;
133
134 /* Convert from NT unit to nano seconds. */
135 return uResult * 100;
136 }
137
138 ASMNopPause();
139 }
140 }
141#endif
142
143 /*
144 * Just read interrupt time.
145 */
146#if ARCH_BITS >= 64
147 uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->InterruptTime; /* This is what KeQueryInterruptTime does. */
148 uRet *= 100;
149 return uRet;
150#else
151
152 LARGE_INTEGER NtTime;
153 do
154 {
155 NtTime.HighPart = pUserSharedData->InterruptTime.High1Time;
156 NtTime.LowPart = pUserSharedData->InterruptTime.LowPart;
157 } while (pUserSharedData->InterruptTime.High2Time != NtTime.HighPart);
158
159 return (uint64_t)NtTime.QuadPart * 100;
160#endif
161}
162
163
164RTDECL(uint64_t) RTTimeSystemNanoTS(void)
165{
166 return rtTimeGetSystemNanoTS();
167}
168
169
170RTDECL(uint64_t) RTTimeSystemMilliTS(void)
171{
172 return rtTimeGetSystemNanoTS() / RT_NS_1MS;
173}
174
175
176RTDECL(PRTTIMESPEC) RTTimeNow(PRTTIMESPEC pTime)
177{
178 /*
179 * Get the precise time if possible.
180 */
181 if (RT_UNLIKELY(!g_fInitialized))
182 rtTimeNtInitialize();
183 if (g_pfnRtlGetSystemTimePrecise != NULL)
184 return RTTimeSpecSetNtTime(pTime, g_pfnRtlGetSystemTimePrecise());
185
186 /*
187 * Just read system time.
188 */
189 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
190#ifdef RT_ARCH_AMD64
191 uint64_t uRet = *(uint64_t volatile *)&pUserSharedData->SystemTime; /* This is what KeQuerySystemTime does. */
192 return RTTimeSpecSetNtTime(pTime, uRet);
193#else
194
195 LARGE_INTEGER NtTime;
196 do
197 {
198 NtTime.HighPart = pUserSharedData->SystemTime.High1Time;
199 NtTime.LowPart = pUserSharedData->SystemTime.LowPart;
200 } while (pUserSharedData->SystemTime.High2Time != NtTime.HighPart);
201 return RTTimeSpecSetNtTime(pTime, NtTime.QuadPart);
202#endif
203}
204
205
206RTDECL(PRTTIMESPEC) RTTimeLocalNow(PRTTIMESPEC pTime)
207{
208 return RTTimeSpecAddNano(RTTimeNow(pTime), RTTimeLocalDeltaNano());
209}
210
211
212RTDECL(int64_t) RTTimeLocalDeltaNano(void)
213{
214 /*
215 * UTC = local + TimeZoneBias; The bias is given in NT units.
216 */
217 KUSER_SHARED_DATA volatile *pUserSharedData = (KUSER_SHARED_DATA volatile *)MM_SHARED_USER_DATA_VA;
218 LARGE_INTEGER Delta;
219#if ARCH_BITS == 64
220 Delta.QuadPart = *(int64_t volatile *)&pUserSharedData->TimeZoneBias;
221#else
222 do
223 {
224 Delta.HighPart = pUserSharedData->TimeZoneBias.High1Time;
225 Delta.LowPart = pUserSharedData->TimeZoneBias.LowPart;
226 } while (pUserSharedData->TimeZoneBias.High2Time != Delta.HighPart);
227#endif
228 return Delta.QuadPart * -100;
229}
230
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette