You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: src/vmaware.hpp
+11-81Lines changed: 11 additions & 81 deletions
Original file line number
Diff line number
Diff line change
@@ -4585,7 +4585,7 @@ struct VM {
4585
4585
// will be used in cpuid measurements later
4586
4586
u16 cycle_threshold = 1000;
4587
4587
if (util::hyper_x() == HYPERV_ARTIFACT_VM) {
4588
-
cycle_threshold = 7500; // if we're running under Hyper-V, make VMAware detect nested virtualization
4588
+
cycle_threshold = 3500; // if we're running under Hyper-V, make VMAware detect nested virtualization
4589
4589
}
4590
4590
4591
4591
#if (WINDOWS)
@@ -4767,6 +4767,11 @@ struct VM {
4767
4767
}
4768
4768
4769
4769
// RDTSC trap detection
4770
+
// This detection uses two clocks and two loops, a loop that the hypervisor can spoof and a loop that the hypervisor cannot
4771
+
// When RDTSC is hooked, the hypervisor usually "downscales" the result to hide the time passed or doesnt let TSC advance for the time it was vm-exiting
4772
+
// However, the hypervisor have absolutely no way to downscale time for the second loop because it runs natively on the CPU without exiting
4773
+
// This creates a discrepancy in the ratio of both loops
4774
+
// The hypervisor cannot easily rewind the system wall clock (second loop, QIT/KUSER_SHARED_DATA) without causing system instability (network timeouts, audio lag)
4770
4775
staticthread_localvolatileu64 g_sink = 0; // thread_local volatile so that it doesnt need to be captured by the lambda
4771
4776
4772
4777
// First we start by randomizing counts WITHOUT syscalls and WITHOUT using instructions that can be trapped by hypervisors, this was a hard task
@@ -4867,16 +4872,18 @@ struct VM {
4867
4872
4868
4873
// first measurement
4869
4874
ULONG64 beforeqit = 0;
4870
-
QueryInterruptTime(&beforeqit); //the kernel routine that backs up this api runs at CLOCK_LEVEL(13), only preempted by IPI, POWER_LEVEL and NMIs
4875
+
QueryInterruptTime(&beforeqit); //never touches RDTSC/RDTSCP or transitions to kernel-mode, just reads from KUSER_SHARED_DATA, reason why we use it
4871
4876
const ULONG64 beforetsc = __rdtsc();
4872
4877
4873
4878
volatileu64 dummy = 0;
4874
4879
for (ULONG64 x = 0; x < count_first; ++x) {
4875
4880
dummy = rd_ptr(); // this loop will be intercepted by a RDTSC trap, downscaling our TSC
4876
4881
}
4877
4882
4883
+
// the kernel routine that backs up this api runs at CLOCK_LEVEL(13), only preempted by IPI, POWER_LEVEL and NMIs
4884
+
// meaning it's highly accurate even with kernel noise, hence we don't need cluster or median computations to get precise ratios
4878
4885
ULONG64 afterqit = 0;
4879
-
QueryInterruptTime(&afterqit);
4886
+
QueryInterruptTime(&afterqit);
4880
4887
const ULONG64 aftertsc = __rdtsc();
4881
4888
4882
4889
const ULONG64 dtsc1 = aftertsc - beforetsc;
@@ -6619,77 +6626,6 @@ struct VM {
6619
6626
if (EnumSystemFirmwareTables(acpi_signature, tables.data(), acpi_enum_size) != acpi_enum_size)
0 commit comments