From ead73371d91e8e0cc7ddec2c3cb196beb7ae3634 Mon Sep 17 00:00:00 2001 From: Ryan Houdek Date: Tue, 1 Jul 2025 17:54:59 -0700 Subject: [PATCH] EmulatedFiles: Emulate `current_clocksource` WINE uses this to determine TSC frequency and because it doesn't say `tsc` on ARM devices, it was ignoring TSC and instead using CPU maximum frequency. This was causing Horizon to think the TSC ran at whatever the max frequency of a core was (1.8Ghz to 2.6Ghz depending?) This was causing all of Horizon Zero Dawn's physics to run at slower than real time speeds because our 1Ghz (on Orion) TSC is significantly lower than the max clock speeds of the cores. This is still a bug in Wine that it is using the maximum CPU clock speed in the case of current_clocksource not being TSC, but that's a battle for a different time. --- .../LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp index 4f8f963c0..481582448 100644 --- a/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp +++ b/Source/Tools/LinuxEmulation/LinuxSyscalls/EmulatedFiles/EmulatedFiles.cpp @@ -545,6 +545,19 @@ EmulatedFDManager::EmulatedFDManager(FEXCore::Context::Context* ctx) return FD; }; + // Wine reads this to ensure TSC is trusted by the kernel. Otherwise it falls back to maximum clock speed of the CPU cores. + // Without this, games like Horizon Zero Dawn would run their physics in slow-motion. + FDReadCreators["/sys/devices/system/clocksource/clocksource0/current_clocksource"] = + [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { + int FD = GenTmpFD(pathname, flags); + const char source[] = "tsc\n"; + // + 1 to ensure null at the end + write(FD, source, strlen(source) + 1); + lseek(FD, 0, SEEK_SET); + SealTmpFD(FD); + return FD; + }; + auto NumCPUCores = [&](FEXCore::Context::Context* ctx, int32_t fd, const char* pathname, int32_t flags, mode_t mode) -> int32_t { int FD = GenTmpFD(pathname, flags); write(FD, (void*)&cpus_online.at(0), cpus_online.size());