From dcf6ad4b98f641d2b92613c7f2ae9580d6056328 Mon Sep 17 00:00:00 2001 From: Requiem Date: Sat, 21 Feb 2026 13:39:18 +0100 Subject: [PATCH 1/2] chore: sync main --- src/vmaware.hpp | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 89e2c6e9..01dec5cc 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -4934,7 +4934,7 @@ struct VM { u64 last = rdtsc(); t2_start.store(last, std::memory_order_release); - // local accumulator (fast) and local index into samples + // local accumulator and local index into samples u64 acc = 0; size_t idx = 0; @@ -5071,7 +5071,7 @@ struct VM { if (!raw) return 0; memset(raw, 0, bufSize); - NTSTATUS status = CallNtPowerInformation( + const NTSTATUS status = CallNtPowerInformation( ProcessorInformation, nullptr, 0, raw, static_cast(bufSize) From b6061e18b067f0dc55831079af910a71bbc6ac7f Mon Sep 17 00:00:00 2001 From: Requiem Date: Sat, 21 Feb 2026 13:41:31 +0100 Subject: [PATCH 2/2] chore: reverted original vm::timer --- src/vmaware.hpp | 119 +++++++++++++++++++++++------------------------- 1 file changed, 57 insertions(+), 62 deletions(-) diff --git a/src/vmaware.hpp b/src/vmaware.hpp index 97265d65..55b1cc86 100644 --- a/src/vmaware.hpp +++ b/src/vmaware.hpp @@ -4612,9 +4612,9 @@ struct VM { cpu::cpuid(regs, 0x80000001); const bool have_rdtscp = (regs[3] & (1u << 27)) != 0; if (!have_rdtscp) { - debug("TIMER: (1/7) RDTSCP instruction not supported"); // __rdtscp should be supported nowadays + debug("TIMER: RDTSCP instruction not supported"); // __rdtscp should be supported nowadays return true; - } + } constexpr u64 ITER_XOR = 100000000ULL; constexpr size_t CPUID_ITER = 100; // per leaf @@ -4627,7 +4627,7 @@ struct VM { if (hw == 0) hw = 1; std::atomic ready_count(0); - std::atomic state(0); + std::atomic state(0); std::atomic t1_start(0), t1_end(0); std::atomic t2_start(0), t2_end(0); @@ -4672,10 +4672,10 @@ struct VM { cpu_set_t cp; CPU_ZERO(&cp); CPU_SET(core, &cp); - (void)pthread_setaffinity_np(ph, sizeof(cp), &cp); + (void)pthread_setaffinity_np(ph, sizeof(cp), &cp); cookie.valid = true; cookie.thread = ph; - cookie.prev_mask = prev; + cookie.prev_mask = prev; } #else (void)t; (void)core; @@ -4928,7 +4928,7 @@ struct VM { // Thread 2: rdtsc and cpuid spammer, forces hypervisor to downscale TSC if patch is present; if interception disabled, caught by cpuid latency std::thread th2([&]() { ready_count.fetch_add(1, std::memory_order_acq_rel); - while (ready_count.load(std::memory_order_acquire) < 2) + while (ready_count.load(std::memory_order_acquire) < 2) _mm_pause(); u64 last = rdtsc(); @@ -4974,7 +4974,7 @@ struct VM { // try to pin to different cores affinity_cookie cookie1{}; affinity_cookie cookie2{}; - if (hw >= 2) { + if (hw >= 2) { if (hw >= 2) { cookie1 = set_affinity(th1, 0); cookie2 = set_affinity(th2, 1); @@ -4990,10 +4990,10 @@ struct VM { // collect results const u64 a = t1_start.load(std::memory_order_acquire); const u64 b = t1_end.load(std::memory_order_acquire); - #ifdef __VMAWARE_DEBUG__ - const u64 c = t2_start.load(std::memory_order_acquire); - const u64 d = t2_end.load(std::memory_order_acquire); - #endif + #ifdef __VMAWARE_DEBUG__ + const u64 c = t2_start.load(std::memory_order_acquire); + const u64 d = t2_end.load(std::memory_order_acquire); + #endif const u64 acc = t2_accum.load(std::memory_order_acquire); const u64 t1_delta = (b > a) ? (b - a) : 0; @@ -5011,18 +5011,15 @@ struct VM { debug("TIMER: vmexit latency: ", cpuid_latency); if (cpuid_latency >= cycle_threshold) { - debug("TIMER: (2/7) CPUID latency is above cycle threshold"); return true; } else if (cpuid_latency <= 25) { // cpuid is fully serializing, no CPU have this low average cycles in real-world scenarios // however, in patches, zero or even negative deltas can be seen oftenly - debug("TIMER: (3/7) CPUID latency is far too low in practice"); return true; } if (t1_delta == 0 || calib_delta == 0) { - debug("TIMER: (4/7) calibration and thread deltas are both null"); return true; } @@ -5031,71 +5028,69 @@ struct VM { // if thread 1 was faster than thread 2, hypervisor downscaled TSC per-vCPU in either cpuid or rdtsc if (ratio < 0.95 || ratio > 1.05) { - debug("TIMER: (5/7) thread 1 was faster than thread 2, hypervisor is downscaling TSC"); return true; } // if calibration was much faster than thread 1, hypervisor downscaled TSC globally while thread 2 was spamming if (calibration_ratio < 0.95) { - debug("TIMER: (6/7) hypervisor is globally downscaling TSC"); return true; } - #if (WINDOWS) - typedef struct _PROCESSOR_POWER_INFORMATION { - u32 Number; - u32 MaxMhz; - u32 CurrentMhz; - u32 MhzLimit; - u32 MaxIdleState; - u32 CurrentIdleState; - } PROCESSOR_POWER_INFORMATION, * PPROCESSOR_POWER_INFORMATION; - - enum POWER_INFORMATION_LEVEL_MIN { - ProcessorInformation = 11 - }; + #if (WINDOWS) + typedef struct _PROCESSOR_POWER_INFORMATION { + u32 Number; + u32 MaxMhz; + u32 CurrentMhz; + u32 MhzLimit; + u32 MaxIdleState; + u32 CurrentIdleState; + } PROCESSOR_POWER_INFORMATION, * PPROCESSOR_POWER_INFORMATION; + + enum POWER_INFORMATION_LEVEL_MIN { + ProcessorInformation = 11 + }; - const HMODULE hPowr = LoadLibraryA("powrprof.dll"); - if (!hPowr) return 0; + const HMODULE hPowr = LoadLibraryA("powrprof.dll"); + if (!hPowr) return 0; - const char* names[] = { "CallNtPowerInformation" }; - void* funcs[1] = { nullptr }; - util::get_function_address(hPowr, names, funcs, 1); - if (!funcs[0]) return 0; + const char* names[] = { "CallNtPowerInformation" }; + void* funcs[1] = { nullptr }; + util::get_function_address(hPowr, names, funcs, 1); + if (!funcs[0]) return 0; - using CallNtPowerInformation_t = NTSTATUS(__stdcall*)(int, PVOID, ULONG, PVOID, ULONG); - CallNtPowerInformation_t CallNtPowerInformation = - reinterpret_cast(funcs[0]); + using CallNtPowerInformation_t = NTSTATUS(__stdcall*)(int, PVOID, ULONG, PVOID, ULONG); + CallNtPowerInformation_t CallNtPowerInformation = + reinterpret_cast(funcs[0]); - SYSTEM_INFO si; - GetSystemInfo(&si); - const DWORD procCount = si.dwNumberOfProcessors; - if (procCount == 0) return 0; + SYSTEM_INFO si; + GetSystemInfo(&si); + const DWORD procCount = si.dwNumberOfProcessors; + if (procCount == 0) return 0; - const SIZE_T bufSize = static_cast(procCount) * sizeof(PROCESSOR_POWER_INFORMATION); - void* raw = _malloca(bufSize); - if (!raw) return 0; - memset(raw, 0, bufSize); + const SIZE_T bufSize = static_cast(procCount) * sizeof(PROCESSOR_POWER_INFORMATION); + void* raw = _malloca(bufSize); + if (!raw) return 0; + memset(raw, 0, bufSize); - const NTSTATUS status = CallNtPowerInformation( - ProcessorInformation, - nullptr, 0, - raw, static_cast(bufSize) - ); + const NTSTATUS status = CallNtPowerInformation( + ProcessorInformation, + nullptr, 0, + raw, static_cast(bufSize) + ); - unsigned speed = 0; - if ((LONG)status >= 0) { - PROCESSOR_POWER_INFORMATION* info = reinterpret_cast(raw); - speed = static_cast(info[0].CurrentMhz); - } + unsigned speed = 0; + if ((LONG)status >= 0) { + PROCESSOR_POWER_INFORMATION* info = reinterpret_cast(raw); + speed = static_cast(info[0].CurrentMhz); + } - _freea(raw); + _freea(raw); - if (speed < 800) { - debug("TIMER: (7/7) VMAware detected a hypervisor offsetting TSC: ", speed); - return true; - } - #endif + if (speed < 800) { + debug("TIMER: VMAware detected an hypervisor offsetting TSC: ", speed); + return true; + } #endif +#endif return false; }