mirror of
https://github.com/reactos/reactos
synced 2025-10-06 00:12:51 +02:00
[NDK][NTOS][NTDLL][KRNEL32] Fix read/write of KSYSTEM_TIME
Fix KiWriteSystemTime and move it to NDK. The previous implementation of KiWriteSystemTime was broken and updated the fields in the wrong order. Before that it was right for SystemTime and wrong for InterruptTime. ExpSetTimeZoneInformation had it wrong for the TimeZoneBias. Add KiReadSystemTime to read KSYSTEM_TIME values correctly, instead of doing it manually (and partly wrongly) all over the place.
This commit is contained in:
@@ -1221,22 +1221,9 @@ ULONG
|
||||
NTAPI
|
||||
RtlGetTickCount(VOID)
|
||||
{
|
||||
ULARGE_INTEGER TickCount;
|
||||
LARGE_INTEGER TickCount;
|
||||
|
||||
#ifdef _WIN64
|
||||
TickCount.QuadPart = *((volatile ULONG64*)&SharedUserData->TickCount);
|
||||
#else
|
||||
while (TRUE)
|
||||
{
|
||||
TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
|
||||
TickCount.LowPart = SharedUserData->TickCount.LowPart;
|
||||
|
||||
if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time)
|
||||
break;
|
||||
|
||||
YieldProcessor();
|
||||
}
|
||||
#endif
|
||||
TickCount = KiReadSystemTime(&SharedUserData->TickCount);
|
||||
|
||||
return (ULONG)((UInt32x32To64(TickCount.LowPart,
|
||||
SharedUserData->TickCountMultiplier) >> 24) +
|
||||
|
@@ -129,12 +129,7 @@ GetSystemTimeAsFileTime(OUT PFILETIME lpFileTime)
|
||||
{
|
||||
LARGE_INTEGER SystemTime;
|
||||
|
||||
do
|
||||
{
|
||||
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
|
||||
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
|
||||
}
|
||||
while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
|
||||
SystemTime = KiReadSystemTime(&SharedUserData->SystemTime);
|
||||
|
||||
lpFileTime->dwLowDateTime = SystemTime.LowPart;
|
||||
lpFileTime->dwHighDateTime = SystemTime.HighPart;
|
||||
@@ -227,12 +222,8 @@ FileTimeToLocalFileTime(IN CONST FILETIME *lpFileTime,
|
||||
TimePtr = IsTimeZoneRedirectionEnabled() ?
|
||||
&BaseStaticServerData->ktTermsrvClientBias :
|
||||
&SharedUserData->TimeZoneBias;
|
||||
do
|
||||
{
|
||||
TimeZoneBias.HighPart = TimePtr->High1Time;
|
||||
TimeZoneBias.LowPart = TimePtr->LowPart;
|
||||
}
|
||||
while (TimeZoneBias.HighPart != TimePtr->High2Time);
|
||||
|
||||
TimeZoneBias = KiReadSystemTime(TimePtr);
|
||||
|
||||
FileTime.LowPart = lpFileTime->dwLowDateTime;
|
||||
FileTime.HighPart = lpFileTime->dwHighDateTime;
|
||||
@@ -260,12 +251,7 @@ LocalFileTimeToFileTime(IN CONST FILETIME *lpLocalFileTime,
|
||||
&BaseStaticServerData->ktTermsrvClientBias :
|
||||
&SharedUserData->TimeZoneBias;
|
||||
|
||||
do
|
||||
{
|
||||
TimeZoneBias.HighPart = TimePtr->High1Time;
|
||||
TimeZoneBias.LowPart = TimePtr->LowPart;
|
||||
}
|
||||
while (TimeZoneBias.HighPart != TimePtr->High2Time);
|
||||
TimeZoneBias = KiReadSystemTime(TimePtr);
|
||||
|
||||
FileTime.LowPart = lpLocalFileTime->dwLowDateTime;
|
||||
FileTime.HighPart = lpLocalFileTime->dwHighDateTime;
|
||||
@@ -289,22 +275,13 @@ GetLocalTime(OUT LPSYSTEMTIME lpSystemTime)
|
||||
TIME_FIELDS TimeFields;
|
||||
volatile KSYSTEM_TIME *TimePtr;
|
||||
|
||||
do
|
||||
{
|
||||
SystemTime.HighPart = SharedUserData->SystemTime.High1Time;
|
||||
SystemTime.LowPart = SharedUserData->SystemTime.LowPart;
|
||||
}
|
||||
while (SystemTime.HighPart != SharedUserData->SystemTime.High2Time);
|
||||
SystemTime = KiReadSystemTime(&SharedUserData->SystemTime);
|
||||
|
||||
TimePtr = IsTimeZoneRedirectionEnabled() ?
|
||||
&BaseStaticServerData->ktTermsrvClientBias :
|
||||
&SharedUserData->TimeZoneBias;
|
||||
do
|
||||
{
|
||||
TimeZoneBias.HighPart = TimePtr->High1Time;
|
||||
TimeZoneBias.LowPart = TimePtr->LowPart;
|
||||
}
|
||||
while (TimeZoneBias.HighPart != TimePtr->High2Time);
|
||||
|
||||
TimeZoneBias = KiReadSystemTime(TimePtr);
|
||||
|
||||
SystemTime.QuadPart -= TimeZoneBias.QuadPart;
|
||||
RtlTimeToTimeFields(&SystemTime, &TimeFields);
|
||||
|
@@ -8,18 +8,11 @@ ULONGLONG
|
||||
WINAPI
|
||||
GetTickCount64(VOID)
|
||||
{
|
||||
ULARGE_INTEGER TickCount;
|
||||
LARGE_INTEGER TickCount;
|
||||
|
||||
while (TRUE)
|
||||
{
|
||||
TickCount.HighPart = (ULONG)SharedUserData->TickCount.High1Time;
|
||||
TickCount.LowPart = SharedUserData->TickCount.LowPart;
|
||||
TickCount = KiReadSystemTime(&SharedUserData->TickCount);
|
||||
|
||||
if (TickCount.HighPart == (ULONG)SharedUserData->TickCount.High2Time) break;
|
||||
|
||||
YieldProcessor();
|
||||
}
|
||||
|
||||
return (UInt32x32To64(TickCount.LowPart, SharedUserData->TickCountMultiplier) >> 24) +
|
||||
(UInt32x32To64(TickCount.HighPart, SharedUserData->TickCountMultiplier) << 8);
|
||||
ULONG TickCountMultiplier = SharedUserData->TickCountMultiplier;
|
||||
return (UInt32x32To64(TickCount.LowPart, TickCountMultiplier) >> 24) +
|
||||
(UInt32x32To64(TickCount.HighPart, TickCountMultiplier) << 8);
|
||||
}
|
||||
|
@@ -1550,9 +1550,7 @@ Phase1InitializationDiscard(IN PVOID Context)
|
||||
10000000);
|
||||
|
||||
/* Set the boot time-zone bias */
|
||||
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.HighPart;
|
||||
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.LowPart;
|
||||
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.HighPart;
|
||||
KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias);
|
||||
|
||||
/* Convert the boot time to local time, and set it */
|
||||
UniversalBootTime.QuadPart = SystemBootTime.QuadPart +
|
||||
|
@@ -336,9 +336,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
|
||||
ExpTimeZoneBias = NewTimeZoneBias;
|
||||
|
||||
/* Change SharedUserData->TimeZoneBias for user-mode applications */
|
||||
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
|
||||
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
|
||||
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
|
||||
KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias);
|
||||
SharedUserData->TimeZoneId = ExpTimeZoneId;
|
||||
|
||||
/* Convert boot time from local time to UTC */
|
||||
@@ -349,9 +347,7 @@ ExRefreshTimeZoneInformation(IN PLARGE_INTEGER CurrentBootTime)
|
||||
|
||||
/* Change it for user-mode applications */
|
||||
CurrentTime.QuadPart += ExpTimeZoneBias.QuadPart;
|
||||
SharedUserData->SystemTime.High2Time = CurrentTime.u.HighPart;
|
||||
SharedUserData->SystemTime.LowPart = CurrentTime.u.LowPart;
|
||||
SharedUserData->SystemTime.High1Time = CurrentTime.u.HighPart;
|
||||
KiWriteSystemTime(&SharedUserData->SystemTime, CurrentTime);
|
||||
|
||||
/* Return success */
|
||||
return TRUE;
|
||||
@@ -424,9 +420,7 @@ ExpSetTimeZoneInformation(PRTL_TIME_ZONE_INFORMATION TimeZoneInformation)
|
||||
sizeof(RTL_TIME_ZONE_INFORMATION));
|
||||
|
||||
/* Set the new time zone information */
|
||||
SharedUserData->TimeZoneBias.High1Time = ExpTimeZoneBias.u.HighPart;
|
||||
SharedUserData->TimeZoneBias.High2Time = ExpTimeZoneBias.u.HighPart;
|
||||
SharedUserData->TimeZoneBias.LowPart = ExpTimeZoneBias.u.LowPart;
|
||||
KiWriteSystemTime(&SharedUserData->TimeZoneBias, ExpTimeZoneBias);
|
||||
SharedUserData->TimeZoneId = ExpTimeZoneId;
|
||||
|
||||
DPRINT("New time zone bias: %I64d minutes\n",
|
||||
|
@@ -55,9 +55,7 @@ KeSetSystemTime(IN PLARGE_INTEGER NewTime,
|
||||
KeQuerySystemTime(OldTime);
|
||||
|
||||
/* Set the new system time (ordering of these operations is critical) */
|
||||
SharedUserData->SystemTime.High2Time = NewTime->HighPart;
|
||||
SharedUserData->SystemTime.LowPart = NewTime->LowPart;
|
||||
SharedUserData->SystemTime.High1Time = NewTime->HighPart;
|
||||
KiWriteSystemTime(&SharedUserData->SystemTime, *NewTime);
|
||||
|
||||
/* Check if this was for the HAL and set the RTC time */
|
||||
if (HalTime) ExCmosClockIsSane = HalSetRealTimeClock(&TimeFields);
|
||||
@@ -164,15 +162,7 @@ VOID
|
||||
NTAPI
|
||||
KeQueryTickCount(IN PLARGE_INTEGER TickCount)
|
||||
{
|
||||
/* Loop until we get a perfect match */
|
||||
for (;;)
|
||||
{
|
||||
/* Read the tick count value */
|
||||
TickCount->HighPart = KeTickCount.High1Time;
|
||||
TickCount->LowPart = KeTickCount.LowPart;
|
||||
if (TickCount->HighPart == KeTickCount.High2Time) break;
|
||||
YieldProcessor();
|
||||
}
|
||||
*TickCount = KiReadSystemTime(&KeTickCount);
|
||||
}
|
||||
|
||||
#ifndef _M_AMD64
|
||||
|
@@ -20,33 +20,18 @@ BOOLEAN KiTimeAdjustmentEnabled = FALSE;
|
||||
|
||||
/* FUNCTIONS ******************************************************************/
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
KiWriteSystemTime(volatile KSYSTEM_TIME *SystemTime, ULARGE_INTEGER NewTime)
|
||||
{
|
||||
#ifdef _WIN64
|
||||
/* Do a single atomic write */
|
||||
*(ULONGLONG*)SystemTime = NewTime.QuadPart;
|
||||
#else
|
||||
/* Update in 3 steps, so that a reader can recognize partial updates */
|
||||
SystemTime->High1Time = NewTime.HighPart;
|
||||
SystemTime->LowPart = NewTime.LowPart;
|
||||
#endif
|
||||
SystemTime->High2Time = NewTime.HighPart;
|
||||
}
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
KiCheckForTimerExpiration(
|
||||
PKPRCB Prcb,
|
||||
PKTRAP_FRAME TrapFrame,
|
||||
ULARGE_INTEGER InterruptTime)
|
||||
LARGE_INTEGER InterruptTime)
|
||||
{
|
||||
ULONG Hand;
|
||||
|
||||
/* Check for timer expiration */
|
||||
Hand = KeTickCount.LowPart & (TIMER_TABLE_SIZE - 1);
|
||||
if (KiTimerTableListHead[Hand].Time.QuadPart <= InterruptTime.QuadPart)
|
||||
if (KiTimerTableListHead[Hand].Time.QuadPart <= (ULONG64)InterruptTime.QuadPart)
|
||||
{
|
||||
/* Check if we are already doing expiration */
|
||||
if (!Prcb->TimerRequest)
|
||||
@@ -66,7 +51,7 @@ KeUpdateSystemTime(IN PKTRAP_FRAME TrapFrame,
|
||||
IN KIRQL Irql)
|
||||
{
|
||||
PKPRCB Prcb = KeGetCurrentPrcb();
|
||||
ULARGE_INTEGER CurrentTime, InterruptTime;
|
||||
LARGE_INTEGER CurrentTime, InterruptTime;
|
||||
LONG OldTickOffset;
|
||||
|
||||
/* Check if this tick is being skipped */
|
||||
|
@@ -394,6 +394,58 @@ KeRaiseUserException(
|
||||
|
||||
#endif
|
||||
|
||||
#ifndef NONAMELESSUNION
|
||||
|
||||
FORCEINLINE
|
||||
LARGE_INTEGER
|
||||
KiReadSystemTime(
|
||||
_In_ volatile const KSYSTEM_TIME *SystemTime)
|
||||
{
|
||||
LARGE_INTEGER Time;
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Do a single atomic read */
|
||||
Time.QuadPart = *(volatile ULONG64*)SystemTime;
|
||||
#else
|
||||
/* Read in a loop until we get a match */
|
||||
for (;;)
|
||||
{
|
||||
Time.HighPart = SystemTime->High1Time;
|
||||
Time.LowPart = SystemTime->LowPart;
|
||||
if (Time.HighPart == SystemTime->High2Time) break;
|
||||
YieldProcessor();
|
||||
}
|
||||
#endif
|
||||
return Time;
|
||||
}
|
||||
|
||||
#ifndef NTOS_MODE_USER
|
||||
|
||||
FORCEINLINE
|
||||
VOID
|
||||
KiWriteSystemTime(
|
||||
_Out_ volatile KSYSTEM_TIME *SystemTime,
|
||||
_In_ LARGE_INTEGER NewTime)
|
||||
{
|
||||
/* Update High2Time first to indicate an update in progress */
|
||||
SystemTime->High2Time = NewTime.HighPart;
|
||||
|
||||
#ifdef _WIN64
|
||||
/* Do a single 'atomic' write. This isn't actually guaranteed to be atomic,
|
||||
if the address isn't 64 bit aligned. But as long as the entire 64 bits
|
||||
are within a single cache line, we should be good (on x64 at least,
|
||||
when it comes to ARM64, all bets are off) This is also what Windows does. */
|
||||
*(LONGLONG*)SystemTime = NewTime.QuadPart;
|
||||
#else
|
||||
/* Update low part, then high part to allow readers detect partial updates. */
|
||||
SystemTime->LowPart = NewTime.LowPart;
|
||||
SystemTime->High1Time = NewTime.HighPart;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif // !NTOS_MODE_USER
|
||||
#endif // !NONAMELESSUNION
|
||||
|
||||
//
|
||||
// Native Calls
|
||||
//
|
||||
|
Reference in New Issue
Block a user