diff --git a/src/common/utils/time.cpp b/src/common/utils/time.cpp index c643c9da..4f594b0a 100644 --- a/src/common/utils/time.cpp +++ b/src/common/utils/time.cpp @@ -3,8 +3,7 @@ namespace utils { - std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(steady_clock& steady_time, - system_clock& system_time, + std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(clock& c, const LARGE_INTEGER delay_interval) { if (delay_interval.QuadPart <= 0) @@ -15,7 +14,7 @@ namespace utils const auto relative_duration = std::chrono::microseconds(relative_ticks_in_ms) + std::chrono::nanoseconds(relative_fraction_ns); - return steady_time.now() + relative_duration; + return c.steady_now() + relative_duration; } const auto delay_seconds_since_1601 = delay_interval.QuadPart / HUNDRED_NANOSECONDS_IN_ONE_SECOND; @@ -26,12 +25,12 @@ namespace utils const auto target_time = std::chrono::system_clock::from_time_t(delay_seconds_since_1970) + std::chrono::nanoseconds(delay_fraction_ns); - const auto now_system = system_time.now(); + const auto now_system = c.system_now(); const auto duration_until_target = std::chrono::duration_cast(target_time - now_system); - return steady_time.now() + duration_until_target; + return c.steady_now() + duration_until_target; } KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp) diff --git a/src/common/utils/time.hpp b/src/common/utils/time.hpp index 1b6ccea0..b887e789 100644 --- a/src/common/utils/time.hpp +++ b/src/common/utils/time.hpp @@ -10,27 +10,35 @@ constexpr auto WINDOWS_EPOCH_DIFFERENCE = EPOCH_DIFFERENCE_1601_TO_1970_SECONDS namespace utils { - template struct clock { - using base_clock = Clock; - using time_point = typename base_clock::time_point; - using duration = typename base_clock::duration; + using system_time_point = std::chrono::system_clock::time_point; + using steady_time_point = std::chrono::steady_clock::time_point; + + using system_duration = system_time_point::duration; + using steady_duration = steady_time_point::duration; virtual ~clock() = default; - virtual time_point now() + + virtual system_time_point system_now() { - return base_clock::now(); + return std::chrono::system_clock::now(); + } + + virtual steady_time_point steady_now() + { + return std::chrono::steady_clock::now(); } }; - template - class tick_clock : public clock + class tick_clock : public clock { public: - tick_clock(const typename tick_clock::time_point start, const uint64_t frequency) + tick_clock(const uint64_t frequency = 1, const system_time_point system_start = {}, + const steady_time_point steady_start = {}) : frequency_(frequency), - start_(start) + system_start_(system_start), + steady_start_(steady_start) { if (this->frequency_ == 0) { @@ -38,13 +46,14 @@ namespace utils } } - typename tick_clock::time_point now() override + system_time_point system_now() override { - const auto passed_ticks = this->ticks(); - const auto passed_time = - tick_clock::duration(passed_ticks * tick_clock::duration::period::den / this->frequency_); + return this->now(this->system_start_); + } - return this->start_ + passed_time; + steady_time_point steady_now() override + { + return this->now(this->steady_start_); } virtual uint64_t ticks() = 0; @@ -56,15 +65,22 @@ namespace utils private: uint64_t frequency_{1}; - typename tick_clock::time_point start_{}; + system_time_point system_start_{}; + steady_time_point steady_start_{}; + + template + TimePoint now(const TimePoint start) + { + using duration = typename TimePoint::duration; + + const auto passed_ticks = this->ticks(); + const auto passed_time = duration(passed_ticks * duration::period::den / this->frequency_); + + return start + passed_time; + } }; - using system_clock = clock; - using steady_clock = clock; - - std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(steady_clock& steady_time, - system_clock& system_time, - LARGE_INTEGER delay_interval); + std::chrono::steady_clock::time_point convert_delay_interval_to_time_point(clock& c, LARGE_INTEGER delay_interval); KSYSTEM_TIME convert_to_ksystem_time(const std::chrono::system_clock::time_point& tp); void convert_to_ksystem_time(volatile KSYSTEM_TIME* dest, const std::chrono::system_clock::time_point& tp); diff --git a/src/windows-emulator/devices/afd_endpoint.cpp b/src/windows-emulator/devices/afd_endpoint.cpp index 7b55f182..33af053e 100644 --- a/src/windows-emulator/devices/afd_endpoint.cpp +++ b/src/windows-emulator/devices/afd_endpoint.cpp @@ -457,7 +457,7 @@ namespace const auto status = this->execute_ioctl(win_emu, *this->delayed_ioctl_); if (status == STATUS_PENDING) { - if (!this->timeout_ || this->timeout_ > win_emu.steady_clock().now()) + if (!this->timeout_ || this->timeout_ > win_emu.clock().steady_now()) { return; } @@ -593,8 +593,7 @@ namespace std::optional timeout{}; if (info.Timeout.QuadPart != std::numeric_limits::max()) { - timeout = utils::convert_delay_interval_to_time_point(win_emu.steady_clock(), - win_emu.system_clock(), info.Timeout); + timeout = utils::convert_delay_interval_to_time_point(win_emu.clock(), info.Timeout); } this->delay_ioctrl(c, timeout); diff --git a/src/windows-emulator/emulator_thread.cpp b/src/windows-emulator/emulator_thread.cpp index 46596e40..2b3ca72c 100644 --- a/src/windows-emulator/emulator_thread.cpp +++ b/src/windows-emulator/emulator_thread.cpp @@ -148,7 +148,7 @@ bool emulator_thread::is_terminated() const return this->exit_status.has_value(); } -bool emulator_thread::is_thread_ready(process_context& process, utils::steady_clock& steady_clock) +bool emulator_thread::is_thread_ready(process_context& process, utils::clock& clock) { if (this->is_terminated()) { @@ -162,7 +162,7 @@ bool emulator_thread::is_thread_ready(process_context& process, utils::steady_cl this->mark_as_ready(STATUS_ALERTED); return true; } - if (this->is_await_time_over(steady_clock)) + if (this->is_await_time_over(clock)) { this->mark_as_ready(STATUS_TIMEOUT); return true; @@ -194,7 +194,7 @@ bool emulator_thread::is_thread_ready(process_context& process, utils::steady_cl return true; } - if (this->is_await_time_over(steady_clock)) + if (this->is_await_time_over(clock)) { this->mark_as_ready(STATUS_TIMEOUT); return true; @@ -205,7 +205,7 @@ bool emulator_thread::is_thread_ready(process_context& process, utils::steady_cl if (this->await_time.has_value()) { - if (this->is_await_time_over(steady_clock)) + if (this->is_await_time_over(clock)) { this->mark_as_ready(STATUS_SUCCESS); return true; diff --git a/src/windows-emulator/emulator_thread.hpp b/src/windows-emulator/emulator_thread.hpp index 44ed6820..dc64f98c 100644 --- a/src/windows-emulator/emulator_thread.hpp +++ b/src/windows-emulator/emulator_thread.hpp @@ -65,14 +65,14 @@ class emulator_thread : public ref_counted_object void mark_as_ready(NTSTATUS status); - bool is_await_time_over(utils::steady_clock& steady_clock) const + bool is_await_time_over(utils::clock& clock) const { - return this->await_time.has_value() && this->await_time.value() < steady_clock.now(); + return this->await_time.has_value() && this->await_time.value() < clock.steady_now(); } bool is_terminated() const; - bool is_thread_ready(process_context& process, utils::steady_clock& steady_clock); + bool is_thread_ready(process_context& process, utils::clock& clock); void save(x64_emulator& emu) { diff --git a/src/windows-emulator/emulator_utils.hpp b/src/windows-emulator/emulator_utils.hpp index f130143f..05adfcae 100644 --- a/src/windows-emulator/emulator_utils.hpp +++ b/src/windows-emulator/emulator_utils.hpp @@ -45,12 +45,11 @@ class windows_emulator; class module_manager; struct process_context; +using clock_wrapper = object_wrapper; using x64_emulator_wrapper = object_wrapper; using memory_manager_wrapper = object_wrapper; using module_manager_wrapper = object_wrapper; using process_context_wrapper = object_wrapper; -using system_clock_wrapper = object_wrapper; -using steady_clock_wrapper = object_wrapper; using windows_emulator_wrapper = object_wrapper; template diff --git a/src/windows-emulator/kusd_mmio.cpp b/src/windows-emulator/kusd_mmio.cpp index 63b98e23..03fcd950 100644 --- a/src/windows-emulator/kusd_mmio.cpp +++ b/src/windows-emulator/kusd_mmio.cpp @@ -70,7 +70,7 @@ namespace kusd.QpcData.QpcData = 0x0083; kusd.QpcData.QpcBypassEnabled = 0x83; kusd.QpcBias = 0x000000159530c4af; - kusd.QpcFrequency = utils::steady_clock::duration::period::den; + kusd.QpcFrequency = utils::clock::steady_duration::period::den; constexpr std::u16string_view root_dir{u"C:\\WINDOWS"}; memcpy(&kusd.NtSystemRoot.arr[0], root_dir.data(), root_dir.size() * 2); @@ -94,9 +94,9 @@ namespace utils } } -kusd_mmio::kusd_mmio(memory_manager& memory, utils::system_clock& clock) +kusd_mmio::kusd_mmio(memory_manager& memory, utils::clock& clock) : memory_(&memory), - system_clock_(&clock) + clock_(&clock) { } @@ -106,7 +106,7 @@ kusd_mmio::~kusd_mmio() } kusd_mmio::kusd_mmio(utils::buffer_deserializer& buffer) - : kusd_mmio(buffer.read(), buffer.read()) + : kusd_mmio(buffer.read(), buffer.read()) { } @@ -162,7 +162,7 @@ uint64_t kusd_mmio::address() void kusd_mmio::update() { - const auto time = this->system_clock_->now(); + const auto time = this->clock_->system_now(); utils::convert_to_ksystem_time(&this->kusd_.SystemTime, time); } diff --git a/src/windows-emulator/kusd_mmio.hpp b/src/windows-emulator/kusd_mmio.hpp index 645f9471..24c4df53 100644 --- a/src/windows-emulator/kusd_mmio.hpp +++ b/src/windows-emulator/kusd_mmio.hpp @@ -13,7 +13,7 @@ class windows_emulator; class kusd_mmio { public: - kusd_mmio(memory_manager& memory, utils::system_clock& clock); + kusd_mmio(memory_manager& memory, utils::clock& clock); ~kusd_mmio(); kusd_mmio(utils::buffer_deserializer& buffer); @@ -42,7 +42,7 @@ class kusd_mmio private: memory_manager* memory_{}; - utils::system_clock* system_clock_{}; + utils::clock* clock_{}; bool registered_{}; diff --git a/src/windows-emulator/process_context.hpp b/src/windows-emulator/process_context.hpp index 54879bbf..f830912e 100644 --- a/src/windows-emulator/process_context.hpp +++ b/src/windows-emulator/process_context.hpp @@ -38,7 +38,7 @@ struct process_context utils::optional_function on_thread_terminated{}; }; - process_context(x64_emulator& emu, memory_manager& memory, utils::system_clock& clock, callbacks& cb) + process_context(x64_emulator& emu, memory_manager& memory, utils::clock& clock, callbacks& cb) : callbacks_(&cb), base_allocator(emu), peb(emu), diff --git a/src/windows-emulator/syscalls.cpp b/src/windows-emulator/syscalls.cpp index 604c4fe8..b2d0b71a 100644 --- a/src/windows-emulator/syscalls.cpp +++ b/src/windows-emulator/syscalls.cpp @@ -27,7 +27,7 @@ namespace if (performance_counter) { performance_counter.access([&](LARGE_INTEGER& value) { - value.QuadPart = c.win_emu.steady_clock().now().time_since_epoch().count(); + value.QuadPart = c.win_emu.clock().steady_now().time_since_epoch().count(); }); } @@ -3633,8 +3633,7 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), - c.win_emu.system_clock(), timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); } c.win_emu.yield_thread(); @@ -3661,8 +3660,7 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), - c.win_emu.system_clock(), timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); } c.win_emu.yield_thread(); @@ -3699,8 +3697,7 @@ namespace } auto& t = c.win_emu.current_thread(); - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), c.win_emu.system_clock(), - delay_interval.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), delay_interval.read()); c.win_emu.yield_thread(); @@ -3742,8 +3739,7 @@ namespace if (timeout.value() && !t.await_time.has_value()) { - t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.steady_clock(), - c.win_emu.system_clock(), timeout.read()); + t.await_time = utils::convert_delay_interval_to_time_point(c.win_emu.clock(), timeout.read()); } c.win_emu.yield_thread(); diff --git a/src/windows-emulator/windows_emulator.cpp b/src/windows-emulator/windows_emulator.cpp index 9d54a7e4..705ef955 100644 --- a/src/windows-emulator/windows_emulator.cpp +++ b/src/windows-emulator/windows_emulator.cpp @@ -86,7 +86,7 @@ namespace auto& emu = win_emu.emu(); auto& context = win_emu.process; - const auto is_ready = thread.is_thread_ready(context, win_emu.steady_clock()); + const auto is_ready = thread.is_thread_ready(context, win_emu.clock()); if (!is_ready && !force) { @@ -162,13 +162,13 @@ namespace return false; } - template - struct instruction_tick_clock : utils::tick_clock + struct instruction_tick_clock : utils::tick_clock { windows_emulator* win_emu_{}; - instruction_tick_clock(windows_emulator& win_emu, const typename instruction_tick_clock::time_point start = {}) - : utils::tick_clock(start, 1000), + instruction_tick_clock(windows_emulator& win_emu, const system_time_point system_start = {}, + const steady_time_point steady_start = {}) + : tick_clock(1000, system_start, steady_start), win_emu_(&win_emu) { } @@ -184,24 +184,14 @@ namespace } }; - std::unique_ptr get_steady_clock(windows_emulator& win_emu, const bool use_relative_time) + std::unique_ptr get_clock(windows_emulator& win_emu, const bool use_relative_time) { if (use_relative_time) { - return std::make_unique>(win_emu); + return std::make_unique(win_emu); } - return std::make_unique(); - } - - std::unique_ptr get_system_clock(windows_emulator& win_emu, const bool use_relative_time) - { - if (use_relative_time) - { - return std::make_unique>(win_emu); - } - - return std::make_unique(); + return std::make_unique(); } } @@ -222,14 +212,13 @@ windows_emulator::windows_emulator(application_settings app_settings, const emul windows_emulator::windows_emulator(const emulator_settings& settings, std::unique_ptr emu) : emu_(std::move(emu)), - system_clock_(get_system_clock(*this, settings.use_relative_time)), - steady_clock_(get_steady_clock(*this, settings.use_relative_time)), + clock_(get_clock(*this, settings.use_relative_time)), emulation_root{settings.emulation_root.empty() ? settings.emulation_root : absolute(settings.emulation_root)}, file_sys(emulation_root.empty() ? emulation_root : emulation_root / "filesys"), memory(*this->emu_), registry(emulation_root.empty() ? settings.registry_directory : emulation_root / "registry"), mod_manager(memory, file_sys, callbacks), - process(*this->emu_, memory, *this->system_clock_, callbacks) + process(*this->emu_, memory, *this->clock_, callbacks) { this->base_constructed_ = true; @@ -502,7 +491,7 @@ void windows_emulator::start(std::chrono::nanoseconds timeout, size_t count) while (true) { - if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process, this->steady_clock())) + if (this->switch_thread_ || !this->current_thread().is_thread_ready(this->process, this->clock())) { this->perform_thread_switch(); } @@ -569,12 +558,8 @@ void windows_emulator::deserialize(utils::buffer_deserializer& buffer) return windows_emulator_wrapper{*this}; // }); - buffer.register_factory([this] { - return system_clock_wrapper{this->system_clock()}; // - }); - - buffer.register_factory([this] { - return steady_clock_wrapper{this->steady_clock()}; // + buffer.register_factory([this] { + return clock_wrapper{this->clock()}; // }); buffer.read(this->switch_thread_); diff --git a/src/windows-emulator/windows_emulator.hpp b/src/windows-emulator/windows_emulator.hpp index 43015131..680e2a1d 100644 --- a/src/windows-emulator/windows_emulator.hpp +++ b/src/windows-emulator/windows_emulator.hpp @@ -48,8 +48,7 @@ struct emulator_settings class windows_emulator { std::unique_ptr emu_{}; - std::unique_ptr system_clock_{}; - std::unique_ptr steady_clock_{}; + std::unique_ptr clock_{}; public: std::filesystem::path emulation_root{}; @@ -85,24 +84,14 @@ class windows_emulator return *this->emu_; } - utils::system_clock& system_clock() + utils::clock& clock() { - return *this->system_clock_; + return *this->clock_; } - const utils::system_clock& system_clock() const + const utils::clock& clock() const { - return *this->system_clock_; - } - - utils::steady_clock& steady_clock() - { - return *this->steady_clock_; - } - - const utils::steady_clock& steady_clock() const - { - return *this->steady_clock_; + return *this->clock_; } emulator_thread& current_thread() const