Merge pull request #1985 from CookiePLMonster/fix-rdtsc-overflow
Make RDTSC and ACPI timers stateful to fix overflows
This commit is contained in:
commit
efe42f4eba
|
@ -324,43 +324,64 @@ void InitDpcThread()
|
||||||
g_DpcData.DpcEvent = CreateEvent(/*lpEventAttributes=*/nullptr, /*bManualReset=*/FALSE, /*bInitialState=*/FALSE, /*lpName=*/nullptr);
|
g_DpcData.DpcEvent = CreateEvent(/*lpEventAttributes=*/nullptr, /*bManualReset=*/FALSE, /*bInitialState=*/FALSE, /*lpName=*/nullptr);
|
||||||
}
|
}
|
||||||
|
|
||||||
#define XBOX_TSC_FREQUENCY 733333333 // Xbox Time Stamp Counter Frequency = 733333333 (CPU Clock)
|
static constexpr uint32_t XBOX_TSC_FREQUENCY = 733333333; // Xbox Time Stamp Counter Frequency = 733333333 (CPU Clock)
|
||||||
#define XBOX_ACPI_FREQUENCY 3375000 // Xbox ACPI frequency (3.375 mhz)
|
static constexpr uint32_t XBOX_ACPI_FREQUENCY = 3375000; // Xbox ACPI frequency (3.375 mhz)
|
||||||
ULONGLONG NativeToXbox_FactorForRdtsc;
|
static constexpr uint32_t SEC_TO_NSEC = 1000000000; // For seconds -> nanoseconds conversions
|
||||||
ULONGLONG NativeToXbox_FactorForAcpi;
|
static uint64_t NativeToXbox_FactorForRdtsc = 0, NativeToXbox_FactorForAcpi = 0;
|
||||||
|
|
||||||
ULONGLONG CxbxGetPerformanceCounter(bool acpi) {
|
// State for CxbxGetPerformanceCounter - concurrent access should be next to non-existent, but secure against it anyway
|
||||||
LARGE_INTEGER tsc;
|
static std::mutex RdtscLock, AcpiLock;
|
||||||
ULARGE_INTEGER scaledTsc;
|
static LARGE_INTEGER LastRdtscQPC, LastAcpiQPC;
|
||||||
|
static ULONGLONG CurrentRdtsc = 0, CurrentAcpi = 0;
|
||||||
|
static ULONGLONG CurrentRdtscRemainder = 0, CurrentAcpiRemainder = 0;
|
||||||
|
|
||||||
QueryPerformanceCounter(&tsc);
|
ULONGLONG CxbxGetPerformanceCounter(bool acpi)
|
||||||
|
{
|
||||||
|
if (acpi == false && NativeToXbox_FactorForRdtsc != 0) {
|
||||||
|
std::lock_guard<std::mutex> lock(RdtscLock);
|
||||||
|
|
||||||
scaledTsc.QuadPart = 1000000000;
|
LARGE_INTEGER tsc;
|
||||||
scaledTsc.QuadPart *= (ULONGLONG)tsc.QuadPart;
|
QueryPerformanceCounter(&tsc);
|
||||||
|
|
||||||
if (acpi == false && NativeToXbox_FactorForRdtsc) {
|
LARGE_INTEGER lastTsc = std::exchange(LastRdtscQPC, tsc);
|
||||||
scaledTsc.QuadPart /= NativeToXbox_FactorForRdtsc;
|
tsc.QuadPart -= lastTsc.QuadPart;
|
||||||
return scaledTsc.QuadPart;
|
tsc.QuadPart *= SEC_TO_NSEC;
|
||||||
} else if (acpi == true && NativeToXbox_FactorForRdtsc) {
|
tsc.QuadPart += CurrentRdtscRemainder;
|
||||||
scaledTsc.QuadPart /= NativeToXbox_FactorForAcpi;
|
ULONGLONG quotient = tsc.QuadPart / NativeToXbox_FactorForRdtsc;
|
||||||
return scaledTsc.QuadPart;
|
ULONGLONG remainder = tsc.QuadPart % NativeToXbox_FactorForRdtsc;
|
||||||
|
|
||||||
|
CurrentRdtscRemainder = remainder;
|
||||||
|
return CurrentRdtsc += quotient;
|
||||||
|
} else if (acpi == true && NativeToXbox_FactorForAcpi != 0) {
|
||||||
|
std::lock_guard<std::mutex> lock(AcpiLock);
|
||||||
|
|
||||||
|
LARGE_INTEGER tsc;
|
||||||
|
QueryPerformanceCounter(&tsc);
|
||||||
|
|
||||||
|
LARGE_INTEGER lastTsc = std::exchange(LastAcpiQPC, tsc);
|
||||||
|
tsc.QuadPart -= lastTsc.QuadPart;
|
||||||
|
tsc.QuadPart *= SEC_TO_NSEC;
|
||||||
|
tsc.QuadPart += CurrentAcpiRemainder;
|
||||||
|
ULONGLONG quotient = tsc.QuadPart / NativeToXbox_FactorForAcpi;
|
||||||
|
ULONGLONG remainder = tsc.QuadPart % NativeToXbox_FactorForAcpi;
|
||||||
|
|
||||||
|
CurrentAcpiRemainder = remainder;
|
||||||
|
return CurrentAcpi += quotient;
|
||||||
}
|
}
|
||||||
|
|
||||||
return (uint64_t)tsc.QuadPart;
|
LARGE_INTEGER tsc;
|
||||||
|
QueryPerformanceCounter(&tsc);
|
||||||
|
return static_cast<ULONGLONG>(tsc.QuadPart);
|
||||||
}
|
}
|
||||||
|
|
||||||
void CxbxInitPerformanceCounters()
|
void CxbxInitPerformanceCounters()
|
||||||
{
|
{
|
||||||
uint64_t t;
|
NativeToXbox_FactorForRdtsc = Muldiv64(HostClockFrequency, SEC_TO_NSEC, XBOX_TSC_FREQUENCY);
|
||||||
t = 1000000000;
|
NativeToXbox_FactorForAcpi = Muldiv64(HostClockFrequency, SEC_TO_NSEC, XBOX_ACPI_FREQUENCY);
|
||||||
t *= HostClockFrequency;
|
|
||||||
t /= XBOX_TSC_FREQUENCY;
|
|
||||||
NativeToXbox_FactorForRdtsc = t;
|
|
||||||
|
|
||||||
t = 1000000000;
|
LARGE_INTEGER tsc;
|
||||||
t *= HostClockFrequency;
|
QueryPerformanceCounter(&tsc);
|
||||||
t /= XBOX_ACPI_FREQUENCY;
|
LastRdtscQPC = LastAcpiQPC = tsc;
|
||||||
NativeToXbox_FactorForAcpi = t;
|
|
||||||
|
|
||||||
// Let's initialize the Dpc handling thread too,
|
// Let's initialize the Dpc handling thread too,
|
||||||
// here for now (should be called by our caller)
|
// here for now (should be called by our caller)
|
||||||
|
|
Loading…
Reference in New Issue