diff options
| author | gibbed <rick@gibbed.us> | 2020-11-21 21:31:08 -0600 |
|---|---|---|
| committer | Rick Gibbed <rick@gibbed.us> | 2020-11-22 14:48:36 -0600 |
| commit | 4f25a96928269b9ed4b2ef5e4e072d09698c2c05 (patch) | |
| tree | c29900b351eaff0ec608a7fb78e69a2597359f4a | |
| parent | 63ff7580492677ff0676f649bfc830cce5be3ee9 (diff) | |
[Kernel] Overhaul Rtl time functions.
- Add date third party submodule.
- [Kernel] Add xclock.
- [Kernel] Reimplement RtlTimeToTimeFields using std::chrono/date/xclock.
- [Kernel] Reimplement RtlTimeFieldsToTime using std::chrono/date/xclock.
- Supersedes #1612.
| -rw-r--r-- | .gitmodules | 3 | ||||
| -rw-r--r-- | src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc | 69 | ||||
| -rw-r--r-- | src/xenia/kernel/xclock.h | 78 | ||||
| m--------- | third_party/date | 0 |
4 files changed, 117 insertions, 33 deletions
diff --git a/.gitmodules b/.gitmodules index 597affeb8..b8f139b8a 100644 --- a/.gitmodules +++ b/.gitmodules @@ -70,3 +70,6 @@ [submodule "third_party/premake-androidmk"] path = third_party/premake-androidmk url = https://github.com/Triang3l/premake-androidmk.git +[submodule "third_party/date"] + path = third_party/date + url = https://github.com/HowardHinnant/date.git diff --git a/src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc b/src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc index e06daba48..db3cef5db 100644 --- a/src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc +++ b/src/xenia/kernel/xboxkrnl/xboxkrnl_rtl.cc @@ -21,14 +21,10 @@ #include "xenia/kernel/util/shim_utils.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_private.h" #include "xenia/kernel/xboxkrnl/xboxkrnl_threading.h" +#include "xenia/kernel/xclock.h" #include "xenia/kernel/xevent.h" #include "xenia/kernel/xthread.h" -#if XE_PLATFORM_WIN32 -#include "xenia/base/platform_win.h" -#define timegm _mkgmtime -#endif - namespace xe { namespace kernel { namespace xboxkrnl { @@ -507,44 +503,51 @@ struct X_TIME_FIELDS { xe::be<uint16_t> milliseconds; xe::be<uint16_t> weekday; }; -static_assert(sizeof(X_TIME_FIELDS) == 16, "Must be LARGEINTEGER"); +static_assert_size(X_TIME_FIELDS, 16); -// https://support.microsoft.com/en-us/kb/167296 +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtltimetotimefields void RtlTimeToTimeFields(lpqword_t time_ptr, pointer_t<X_TIME_FIELDS> time_fields_ptr) { - int64_t time_ms = time_ptr.value() / 10000 - 11644473600000LL; - time_t timet = time_ms / 1000; - struct tm* tm = gmtime(&timet); - - time_fields_ptr->year = tm->tm_year + 1900; - time_fields_ptr->month = tm->tm_mon + 1; - time_fields_ptr->day = tm->tm_mday; - time_fields_ptr->hour = tm->tm_hour; - time_fields_ptr->minute = tm->tm_min; - time_fields_ptr->second = tm->tm_sec; - time_fields_ptr->milliseconds = time_ms % 1000; - time_fields_ptr->weekday = tm->tm_wday; + auto tp = XClock::to_sys(XClock::from_file_time(time_ptr.value())); + auto dp = date::floor<date::days>(tp); + auto year_month_day = date::year_month_day{dp}; + auto weekday = date::weekday{dp}; + auto time = date::hh_mm_ss{date::floor<std::chrono::milliseconds>(tp - dp)}; + time_fields_ptr->year = static_cast<int>(year_month_day.year()); + time_fields_ptr->month = static_cast<unsigned>(year_month_day.month()); + time_fields_ptr->day = static_cast<unsigned>(year_month_day.day()); + time_fields_ptr->weekday = weekday.c_encoding(); + time_fields_ptr->hour = time.hours().count(); + time_fields_ptr->minute = time.minutes().count(); + time_fields_ptr->second = static_cast<uint16_t>(time.seconds().count()); + time_fields_ptr->milliseconds = + static_cast<uint16_t>(time.subseconds().count()); } DECLARE_XBOXKRNL_EXPORT1(RtlTimeToTimeFields, kNone, kImplemented); +// https://docs.microsoft.com/en-us/windows-hardware/drivers/ddi/wdm/nf-wdm-rtltimefieldstotime dword_result_t RtlTimeFieldsToTime(pointer_t<X_TIME_FIELDS> time_fields_ptr, lpqword_t time_ptr) { - struct tm tm; - tm.tm_year = time_fields_ptr->year - 1900; - tm.tm_mon = time_fields_ptr->month - 1; - tm.tm_mday = time_fields_ptr->day; - tm.tm_hour = time_fields_ptr->hour; - tm.tm_min = time_fields_ptr->minute; - tm.tm_sec = time_fields_ptr->second; - tm.tm_isdst = 0; - time_t timet = timegm(&tm); - if (timet == -1) { - // set last error = ERROR_INVALID_PARAMETER + if (time_fields_ptr->year < 1601 || time_fields_ptr->month < 1 || + time_fields_ptr->month > 11 || time_fields_ptr->day < 1 || + time_fields_ptr->hour > 23 || time_fields_ptr->minute > 59 || + time_fields_ptr->second > 59 || time_fields_ptr->milliseconds > 999) { + return 0; + } + auto year = date::year{time_fields_ptr->year}; + auto month = date::month{time_fields_ptr->month}; + auto day = date::day{time_fields_ptr->day}; + auto year_month_day = date::year_month_day{year, month, day}; + if (!year_month_day.ok()) { return 0; } - uint64_t time = - ((timet + 11644473600LL) * 1000 + time_fields_ptr->milliseconds) * 10000; - *time_ptr = time; + auto dp = static_cast<date::sys_days>(year_month_day); + std::chrono::system_clock::time_point time = dp; + time += std::chrono::hours{time_fields_ptr->hour}; + time += std::chrono::minutes{time_fields_ptr->minute}; + time += std::chrono::seconds{time_fields_ptr->second}; + time += std::chrono::milliseconds{time_fields_ptr->milliseconds}; + *time_ptr = XClock::to_file_time(XClock::from_sys(time)); return 1; } DECLARE_XBOXKRNL_EXPORT1(RtlTimeFieldsToTime, kNone, kImplemented); diff --git a/src/xenia/kernel/xclock.h b/src/xenia/kernel/xclock.h new file mode 100644 index 000000000..809dfd775 --- /dev/null +++ b/src/xenia/kernel/xclock.h @@ -0,0 +1,78 @@ +/** + ****************************************************************************** + * Xenia : Xbox 360 Emulator Research Project * + ****************************************************************************** + * Copyright 2020 Ben Vanik. All rights reserved. * + * Released under the BSD license - see LICENSE in the root for more details. * + ****************************************************************************** + */ + +#ifndef XENIA_KERNEL_XCLOCK_H_ +#define XENIA_KERNEL_XCLOCK_H_ + +#include <chrono> + +#include "xenia/base/clock.h" + +#include "third_party/date/include/date/date.h" + +namespace xe { +namespace kernel { + +struct XClock { + using rep = int64_t; + using period = std::ratio_multiply<std::ratio<100>, std::nano>; + using duration = std::chrono::duration<rep, period>; + using time_point = std::chrono::time_point<XClock>; + static constexpr bool is_steady = false; + + static time_point now() noexcept { + return from_file_time(Clock::QueryGuestSystemTime()); + } + + static uint64_t to_file_time(time_point const& tp) noexcept { + return static_cast<uint64_t>(tp.time_since_epoch().count()); + } + + static time_point from_file_time(uint64_t const& tp) noexcept { + return time_point{duration{tp}}; + } + + static std::chrono::system_clock::time_point to_sys(time_point const& tp) { + // TODO(gibbed): verify behavior under Linux + using sys_duration = std::chrono::system_clock::duration; + using sys_time = std::chrono::system_clock::time_point; + auto dp = tp; + dp += system_clock_delta(); + auto cdp = std::chrono::time_point_cast<sys_duration>(dp); + return sys_time{cdp.time_since_epoch()}; + } + + static time_point from_sys(std::chrono::system_clock::time_point const& tp) { + // TODO(gibbed): verify behavior under Linux + auto ctp = std::chrono::time_point_cast<duration>(tp); + auto dp = time_point{ctp.time_since_epoch()}; + dp -= system_clock_delta(); + return dp; + } + + private: + // The delta between std::chrono::system_clock (Jan 1 1970) and Xenon file + // time (Jan 1 1601), in seconds. In the spec std::chrono::system_clock's + // epoch is undefined, but C++20 cements it as Jan 1 1970. + static constexpr std::chrono::seconds system_clock_delta() { + auto filetime_epoch = date::year{1601} / date::month{1} / date::day{1}; + auto system_clock_epoch = date::year{1970} / date::month{1} / date::day{1}; + std::chrono::system_clock::time_point fp{ + static_cast<date::sys_days>(filetime_epoch)}; + std::chrono::system_clock::time_point sp{ + static_cast<date::sys_days>(system_clock_epoch)}; + return std::chrono::floor<std::chrono::seconds>(fp.time_since_epoch() - + sp.time_since_epoch()); + } +}; + +} // namespace kernel +} // namespace xe + +#endif // XENIA_KERNEL_XCLOCK_H_ diff --git a/third_party/date b/third_party/date new file mode 160000 +Subproject 97246a638a6d8f0269f4555c5e31106a86e3fd9 |
