From 06c28a847e0380402c235f86a762c47cfa4017ce Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 5 Jan 2024 00:33:34 -0600 Subject: [PATCH 1/9] Revert "Merge pull request #2441 from ergo720/time_fix" This reverts commit 8cc9c73f58c7b883321d68d0e0f0ea428691b4c7. --- src/core/kernel/exports/EmuKrnlRtl.cpp | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index be1925fbd..96741bfe0 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -42,7 +42,6 @@ namespace NtDll #include "core\kernel\init\CxbxKrnl.h" // For CxbxrAbort() #include "core\kernel\support\Emu.h" // For EmuLog(LOG_LEVEL::WARNING, ) -#include "EmuKrnlKi.h" #include #ifdef _WIN32 @@ -1662,10 +1661,7 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime TimeFields->Hour) * MINSPERHOUR + TimeFields->Minute) * SECSPERMIN + TimeFields->Second) * 1000 + - TimeFields->Millisecond); - - // This function must return a time expressed in 100ns units (the Windows time interval), so it needs a final multiplication here - *Time = RtlExtendedIntegerMultiply(*Time, CLOCK_TIME_INCREMENT); + TimeFields->Millisecond) * TICKSPERMSEC; RETURN(TRUE); } From bf6193202aec581a10cd8eb6b99f0ce27b53d4f9 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 5 Jan 2024 01:15:15 -0600 Subject: [PATCH 2/9] kernel: split RtlTimeFieldsToTime range check into their own if statements for clear reading Plus fixed a bug for leap year's day range --- src/core/kernel/exports/EmuKrnlRtl.cpp | 34 +++++++++++++++++--------- 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index 96741bfe0..f93b56a66 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1622,19 +1622,29 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime int month, year, cleaps, day; - /* FIXME: normalize the TIME_FIELDS structure here */ - /* No, native just returns 0 (error) if the fields are not */ - if (TimeFields->Millisecond < 0 || TimeFields->Millisecond > 999 || - TimeFields->Second < 0 || TimeFields->Second > 59 || - TimeFields->Minute < 0 || TimeFields->Minute > 59 || - TimeFields->Hour < 0 || TimeFields->Hour > 23 || - TimeFields->Month < 1 || TimeFields->Month > 12 || - TimeFields->Day < 1 || - TimeFields->Day > MonthLengths - [TimeFields->Month == 2 || IsLeapYear(TimeFields->Year)] - [TimeFields->Month - 1] || - TimeFields->Year < 1601) + /* Verify each TimeFields' variables are within range */ + if (TimeFields->Millisecond < 0 || TimeFields->Millisecond > 999) { return FALSE; + } + if (TimeFields->Second < 0 || TimeFields->Second > 59) { + return FALSE; + } + if (TimeFields->Minute < 0 || TimeFields->Minute > 59) { + return FALSE; + } + if (TimeFields->Hour < 0 || TimeFields->Hour > 23) { + return FALSE; + } + if (TimeFields->Month < 1 || TimeFields->Month > 12) { + return FALSE; + } + if (TimeFields->Day < 1 || + TimeFields->Day > MonthLengths[IsLeapYear(TimeFields->Year)][TimeFields->Month - 1]) { + return FALSE; + } + if (TimeFields->Year < 1601) { + return FALSE; + } /* now calculate a day count from the date * First start counting years from March. This way the leap days From 131b330a853c2705e9c44e54e9190420f17cad01 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 5 Jan 2024 01:17:43 -0600 Subject: [PATCH 3/9] kernel: Change RtlTimeFieldsToTime's Time format into more readable math operation --- src/core/kernel/exports/EmuKrnlRtl.cpp | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index f93b56a66..c9b07d852 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1667,11 +1667,12 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime 584817; /* zero that on 1601-01-01 */ /* done */ - Time->QuadPart = (((((LONGLONG)day * HOURSPERDAY + - TimeFields->Hour) * MINSPERHOUR + - TimeFields->Minute) * SECSPERMIN + - TimeFields->Second) * 1000 + - TimeFields->Millisecond) * TICKSPERMSEC; + /* Convert into Time format */ + Time->QuadPart = day * HOURSPERDAY; + Time->QuadPart = (Time->QuadPart + TimeFields->Hour) * MINSPERHOUR; + Time->QuadPart = (Time->QuadPart + TimeFields->Minute) * SECSPERMIN; + Time->QuadPart = (Time->QuadPart + TimeFields->Second) * 1000; + Time->QuadPart = (Time->QuadPart + TimeFields->Millisecond) * TICKSPERMSEC; RETURN(TRUE); } From d6b96b8ea1e323df19ed25078741ac24206c795b Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 5 Jan 2024 01:19:10 -0600 Subject: [PATCH 4/9] kernel: clean up RtlTimeFieldsToTime bad indents --- src/core/kernel/exports/EmuKrnlRtl.cpp | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index c9b07d852..f96d99d58 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1660,11 +1660,11 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime month = TimeFields->Month + 1; year = TimeFields->Year; } - cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/ - day = (36525 * year) / 100 - cleaps + /* year * dayperyr, corrected */ - (1959 * month) / 64 + /* months * daypermonth */ - TimeFields->Day - /* day of the month */ - 584817; /* zero that on 1601-01-01 */ + cleaps = (3 * (year / 100) + 3) / 4; /* nr of "century leap years"*/ + day = (36525 * year) / 100 - cleaps + /* year * DayPerYear, corrected */ + (1959 * month) / 64 + /* months * DayPerMonth */ + TimeFields->Day - /* day of the month */ + 584817; /* zero that on 1601-01-01 */ /* done */ /* Convert into Time format */ From d64e172c9ff80e53343376057e33f3f35a3db65e Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Fri, 5 Jan 2024 01:26:08 -0600 Subject: [PATCH 5/9] kernel: RtlTimeFieldsToTime no longer need to be logged --- src/core/kernel/exports/EmuKrnlRtl.cpp | 7 +------ 1 file changed, 1 insertion(+), 6 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index f96d99d58..e3d218c92 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1615,11 +1615,6 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime OUT PLARGE_INTEGER Time ) { - LOG_FUNC_BEGIN - LOG_FUNC_ARG(TimeFields) - LOG_FUNC_ARG_OUT(Time) - LOG_FUNC_END; - int month, year, cleaps, day; /* Verify each TimeFields' variables are within range */ @@ -1674,7 +1669,7 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime Time->QuadPart = (Time->QuadPart + TimeFields->Second) * 1000; Time->QuadPart = (Time->QuadPart + TimeFields->Millisecond) * TICKSPERMSEC; - RETURN(TRUE); + return TRUE; } // ****************************************************************** From b64a3b6faaae8612a23a1afeed2f2ffa7dcd5152 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sat, 13 Jan 2024 16:18:23 -0600 Subject: [PATCH 6/9] kernel: fix comment typo in RtlTimeToTimeFields --- src/core/kernel/exports/EmuKrnlRtl.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index e3d218c92..9371cdf8a 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1719,7 +1719,7 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields yearday = Days - (years * DAYSPERNORMALQUADRENNIUM) / 4; months = (64 * yearday) / 1959; /* the result is based on a year starting on March. - * To convert take 12 from Januari and Februari and + * To convert take 12 from January and February and * increase the year by one. */ if (months < 14) { TimeFields->Month = (USHORT)(months - 1); From 8e5b27d0546478e23affb5d11fe723b8181b3809 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sat, 13 Jan 2024 16:22:05 -0600 Subject: [PATCH 7/9] kernel: fix RtlTimeToTimeFields implement to match test results --- src/core/kernel/exports/EmuKrnlRtl.cpp | 41 +++++++++++++------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index 9371cdf8a..63737085e 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1562,6 +1562,11 @@ no_mapping: #define SECS_1601_TO_1980 ((379 * 365 + 91) * (ULONGLONG)SECSPERDAY) #define TICKS_1601_TO_1980 (SECS_1601_TO_1980 * TICKSPERSEC) +const xbox::LARGE_INTEGER Magic10000 = { .QuadPart = 0xd1b71758e219652ci64 }; +#define SHIFT10000 13 +xbox::LARGE_INTEGER Magic86400000 = { .QuadPart = 0xc6d750ebfa67b90ei64 }; +#define SHIFT86400000 26 + static const int MonthLengths[2][MONSPERYEAR] = { @@ -1686,31 +1691,27 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields LOG_FUNC_ARG_OUT(TimeFields) LOG_FUNC_END; - int SecondsInDay; - long int cleaps, years, yearday, months; - long int Days; - LONGLONG _Time; + LONGLONG Days, cleaps, years, yearday, months; - /* Extract millisecond from time and convert time into seconds */ - TimeFields->Millisecond = - (cshort_xt)((Time->QuadPart % TICKSPERSEC) / TICKSPERMSEC); - _Time = Time->QuadPart / TICKSPERSEC; - - /* The native version of RtlTimeToTimeFields does not take leap seconds - * into account */ - - /* Split the time into days and seconds within the day */ - Days = (long int )(_Time / SECSPERDAY); - SecondsInDay = _Time % SECSPERDAY; + /* Extract milliseconds from time and days from milliseconds */ + // NOTE: Reverse engineered native kernel uses RtlExtendedMagicDivide calls. + // Using similar code of ReactOS does not emulate native kernel's implement for + // one increment over large integer's max value. + xbox::LARGE_INTEGER MillisecondsTotal = RtlExtendedMagicDivide(*Time, Magic10000, SHIFT10000); + Days = RtlExtendedMagicDivide(MillisecondsTotal, Magic86400000, SHIFT86400000).u.LowPart; + MillisecondsTotal.QuadPart -= Days * SECSPERDAY * 1000; /* compute time of day */ - TimeFields->Hour = (cshort_xt)(SecondsInDay / SECSPERHOUR); - SecondsInDay = SecondsInDay % SECSPERHOUR; - TimeFields->Minute = (cshort_xt)(SecondsInDay / SECSPERMIN); - TimeFields->Second = (cshort_xt)(SecondsInDay % SECSPERMIN); + TimeFields->Millisecond = MillisecondsTotal.u.LowPart % 1000; + dword_xt RemainderTime = MillisecondsTotal.u.LowPart / 1000; + TimeFields->Second = RemainderTime % SECSPERMIN; + RemainderTime /= SECSPERMIN; + TimeFields->Minute = RemainderTime % MINSPERHOUR; + RemainderTime /= MINSPERHOUR; + TimeFields->Hour = RemainderTime; // NOTE: Remaining hours did not received 24 hours modulo treatment. /* compute day of week */ - TimeFields->Weekday = (cshort_xt)((EPOCHWEEKDAY + Days) % DAYSPERWEEK); + TimeFields->Weekday = (EPOCHWEEKDAY + Days) % DAYSPERWEEK; /* compute year, month and day of month. */ cleaps = (3 * ((4 * Days + 1227) / DAYSPERQUADRICENTENNIUM) + 3) / 4; From 282c5f56225b503d94cbf47c2588bb0aa9c6ea55 Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Sat, 13 Jan 2024 16:25:58 -0600 Subject: [PATCH 8/9] kernel: RtlTimeToTimeFields no longer need to be logged --- src/core/kernel/exports/EmuKrnlRtl.cpp | 5 ----- 1 file changed, 5 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index 63737085e..f2ad912d1 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1686,11 +1686,6 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields OUT PTIME_FIELDS TimeFields ) { - LOG_FUNC_BEGIN - LOG_FUNC_ARG(Time) - LOG_FUNC_ARG_OUT(TimeFields) - LOG_FUNC_END; - LONGLONG Days, cleaps, years, yearday, months; /* Extract milliseconds from time and days from milliseconds */ From 796e8d2beb4640047e2f0b873574167c262c5eca Mon Sep 17 00:00:00 2001 From: RadWolfie Date: Mon, 15 Jan 2024 05:19:57 -0600 Subject: [PATCH 9/9] kernel: change 1000 to MSECSPERSEC --- src/core/kernel/exports/EmuKrnlRtl.cpp | 9 +++++---- 1 file changed, 5 insertions(+), 4 deletions(-) diff --git a/src/core/kernel/exports/EmuKrnlRtl.cpp b/src/core/kernel/exports/EmuKrnlRtl.cpp index f2ad912d1..b309201f6 100644 --- a/src/core/kernel/exports/EmuKrnlRtl.cpp +++ b/src/core/kernel/exports/EmuKrnlRtl.cpp @@ -1544,6 +1544,7 @@ no_mapping: #define TICKSPERSEC 10000000 #define TICKSPERMSEC 10000 +#define MSECSPERSEC 1000 #define SECSPERDAY 86400 #define SECSPERHOUR 3600 #define SECSPERMIN 60 @@ -1671,7 +1672,7 @@ XBSYSAPI EXPORTNUM(304) xbox::boolean_xt NTAPI xbox::RtlTimeFieldsToTime Time->QuadPart = day * HOURSPERDAY; Time->QuadPart = (Time->QuadPart + TimeFields->Hour) * MINSPERHOUR; Time->QuadPart = (Time->QuadPart + TimeFields->Minute) * SECSPERMIN; - Time->QuadPart = (Time->QuadPart + TimeFields->Second) * 1000; + Time->QuadPart = (Time->QuadPart + TimeFields->Second) * MSECSPERSEC; Time->QuadPart = (Time->QuadPart + TimeFields->Millisecond) * TICKSPERMSEC; return TRUE; @@ -1694,11 +1695,11 @@ XBSYSAPI EXPORTNUM(305) xbox::void_xt NTAPI xbox::RtlTimeToTimeFields // one increment over large integer's max value. xbox::LARGE_INTEGER MillisecondsTotal = RtlExtendedMagicDivide(*Time, Magic10000, SHIFT10000); Days = RtlExtendedMagicDivide(MillisecondsTotal, Magic86400000, SHIFT86400000).u.LowPart; - MillisecondsTotal.QuadPart -= Days * SECSPERDAY * 1000; + MillisecondsTotal.QuadPart -= Days * SECSPERDAY * MSECSPERSEC; /* compute time of day */ - TimeFields->Millisecond = MillisecondsTotal.u.LowPart % 1000; - dword_xt RemainderTime = MillisecondsTotal.u.LowPart / 1000; + TimeFields->Millisecond = MillisecondsTotal.u.LowPart % MSECSPERSEC; + dword_xt RemainderTime = MillisecondsTotal.u.LowPart / MSECSPERSEC; TimeFields->Second = RemainderTime % SECSPERMIN; RemainderTime /= SECSPERMIN; TimeFields->Minute = RemainderTime % MINSPERHOUR;