Several changes for timestamp bundle:

Fully defined the structure.
Single copy of it + single timer across all modules, managing it is now the responsibility of KernelState.

add global_critical_region::PrepareToAcquire, which uses Prefetchw on the global crit. We now know we can use Prefetchw on all cpus that have AVX.
add  KeQueryInterruptTime, which is used by some dashboards.

add threading::NanoSleep
This commit is contained in:
chss95cs@gmail.com
2023-04-16 10:08:01 -04:00
parent 12c9135843
commit ab21e1e0f0
15 changed files with 147 additions and 54 deletions

View File

@@ -50,8 +50,7 @@ uint64_t last_guest_tick_count_ = 0;
// Last sampled host tick count.
uint64_t last_host_tick_count_ = Clock::QueryHostTickCount();
using tick_mutex_type = std::mutex;
using tick_mutex_type = std::mutex;
// Mutex to ensure last_host_tick_count_ and last_guest_tick_count_ are in sync
// std::mutex tick_mutex_;
@@ -180,6 +179,10 @@ uint64_t Clock::QueryGuestSystemTime() {
return guest_system_time_base_ + guest_system_time_offset;
}
uint64_t Clock::QueryGuestInterruptTime() {
return Clock::QueryHostInterruptTime();
}
uint32_t Clock::QueryGuestUptimeMillis() {
return static_cast<uint32_t>(
std::min<uint64_t>(QueryGuestSystemTimeOffset() / 10000,

View File

@@ -54,6 +54,8 @@ class Clock {
// Queries the milliseconds since the host began.
static uint64_t QueryHostUptimeMillis();
static uint64_t QueryHostInterruptTime();
// Guest time scalar.
static double guest_time_scalar();
// Sets the guest time scalar, adjusting tick and wall clock speed.
@@ -81,6 +83,8 @@ class Clock {
// Queries the milliseconds since the guest began, accounting for scaling.
static uint32_t QueryGuestUptimeMillis();
static uint64_t QueryGuestInterruptTime();
// Sets the system time of the guest.
static void SetGuestSystemTime(uint64_t system_time);

View File

@@ -47,5 +47,10 @@ uint64_t Clock::QueryHostSystemTime() {
uint64_t Clock::QueryHostUptimeMillis() {
return host_tick_count_platform() * 1000 / host_tick_frequency_platform();
}
// todo: we only take the low part of interrupttime! this is actually a 96-bit
// int!
uint64_t Clock::QueryHostInterruptTime() {
return *reinterpret_cast<uint64_t*>(KUserShared() +
KUSER_SHARED_INTERRUPTTIME_OFFSET);
}
} // namespace xe

View File

@@ -25,17 +25,6 @@ class StartupCpuFeatureCheck {
"the "
"FAQ for system requirements at https://xenia.jp";
}
#if 0
if (!error_message) {
unsigned int data[4];
Xbyak::util::Cpu::getCpuid(0x80000001, data);
if (!(data[2] & (1U << 8))) {
error_message =
"Your cpu does not support PrefetchW, which Xenia Canary "
"requires.";
}
}
#endif
if (error_message == nullptr) {
return;
} else {

View File

@@ -11,7 +11,7 @@
#define XENIA_BASE_MUTEX_H_
#include <mutex>
#include "platform.h"
#include "memory.h"
#define XE_ENABLE_FAST_WIN32_MUTEX 1
namespace xe {
@@ -149,6 +149,12 @@ class global_critical_region {
return global_unique_lock_type(mutex());
}
static inline void PrepareToAcquire() {
#if XE_PLATFORM_WIN32 == 1
swcache::PrefetchW(&mutex());
#endif
}
// Acquires a deferred lock on the global critical section.
static inline global_unique_lock_type AcquireDeferred() {
return global_unique_lock_type(mutex(), std::defer_lock);

View File

@@ -35,8 +35,9 @@
#undef GetFirstChild
#define XE_USE_NTDLL_FUNCTIONS 1
//chrispy: disabling this for now, more research needs to be done imo, although it does work very well on my machine
//
// chrispy: disabling this for now, more research needs to be done imo, although
// it does work very well on my machine
//
#define XE_USE_KUSER_SHARED 0
#if XE_USE_NTDLL_FUNCTIONS == 1
/*
@@ -63,7 +64,11 @@
#define XE_NTDLL_IMPORT(name, cls, clsvar) static constexpr bool clsvar = false
#endif
#if XE_USE_KUSER_SHARED==1
static constexpr size_t KSUER_SHARED_SYSTEMTIME_OFFSET = 0x14;
static constexpr size_t KUSER_SHARED_INTERRUPTTIME_OFFSET = 8;
static unsigned char* KUserShared() { return (unsigned char*)0x7FFE0000ULL; }
#if XE_USE_KUSER_SHARED == 1
// KUSER_SHARED
struct __declspec(align(4)) _KSYSTEM_TIME {
unsigned int LowPart;
@@ -71,8 +76,6 @@ struct __declspec(align(4)) _KSYSTEM_TIME {
int High2Time;
};
static constexpr size_t KSUER_SHARED_SYSTEMTIME_OFFSET = 0x14;
static unsigned char* KUserShared() { return (unsigned char*)0x7FFE0000ULL; }
static volatile _KSYSTEM_TIME* GetKUserSharedSystemTime() {
return reinterpret_cast<volatile _KSYSTEM_TIME*>(
KUserShared() + KSUER_SHARED_SYSTEMTIME_OFFSET);

View File

@@ -115,6 +115,7 @@ void SyncMemory();
// Sleeps the current thread for at least as long as the given duration.
void Sleep(std::chrono::microseconds duration);
void NanoSleep(int64_t ns);
template <typename Rep, typename Period>
void Sleep(std::chrono::duration<Rep, Period> duration) {
Sleep(std::chrono::duration_cast<std::chrono::microseconds>(duration));
@@ -148,7 +149,7 @@ bool SetTlsValue(TlsHandle handle, uintptr_t value);
// be kept short or else all timers will be impacted. This is a simplified
// wrapper around QueueTimerRecurring which automatically cancels the timer on
// destruction.
//only used by XboxkrnlModule::XboxkrnlModule
// only used by XboxkrnlModule::XboxkrnlModule
class HighResolutionTimer {
HighResolutionTimer(std::chrono::milliseconds interval,
std::function<void()> callback) {
@@ -302,14 +303,14 @@ class Event : public WaitHandle {
// the nonsignaled state after releasing the appropriate number of waiting
// threads.
virtual void Pulse() = 0;
virtual EventInfo Query() = 0;
#if XE_PLATFORM_WIN32 ==1
//SetEvent, but if there is a waiter we immediately transfer execution to it
#if XE_PLATFORM_WIN32 == 1
// SetEvent, but if there is a waiter we immediately transfer execution to it
virtual void SetBoostPriority() = 0;
#else
#else
void SetBoostPriority() { Set(); }
#endif
#endif
};
// Models a Win32-like semaphore object.

View File

@@ -148,7 +148,16 @@ void MaybeYield() {
// memorybarrier is really not necessary here...
// MemoryBarrier();
}
void NanoSleep(int64_t ns) {
//nanosleep is done in 100 nanosecond increments
int64_t in_nt_increments = ns / 100LL;
if (in_nt_increments == 0 && ns != 0) {
//if we're explicitly requesting a delay of 0 ns, let it go through, otherwise if it was less than a 100ns increment we round up to 100ns
in_nt_increments = 1;
}
in_nt_increments = -in_nt_increments;
NtDelayExecutionPointer.invoke(0, &in_nt_increments);
}
void SyncMemory() { MemoryBarrier(); }
void Sleep(std::chrono::microseconds duration) {