I am having issues getting TSC offsetting to work with my Hypervisor. According to the intel manuals you have to make sure the VM doesn't exit on rdtsc
, so I disabled rdtsc_exiting
. I also enabled the use tsc offsetting
control. Setting up the VMCS
this way should allow me to write to the tsc_offset
control field to alter how the VM (guest OS) reads the TSC.
What I did was right before I give control back to the VM in the exit handler, I write -2000
to the TSC offset field.
__vmx_vmwrite(Vmcs::kTscOffset, -2000);
I am using this as my VmWrite
implementation:
inline unsigned char __vmx_vmwrite(_In_ size_t field, _In_ size_t field_value) {
FlagRegister flags = {};
__asm {
pushad
push field_value
mov eax, field
_emit 0x0F
_emit 0x79
_emit 0x04
_emit 0x24 // VMWRITE EAX, [ESP]
pushfd
pop flags.all
add esp, 4
popad
}
if (flags.fields.cf) {
return 2;
}
if (flags.fields.zf) {
return 1;
}
return 0;
}
According to the intel manuals, this should be enough to be able to use TSC offsetting. So to test I wrote this small test program (a CPUID is doing a VMEXIT in my case):
auto a1 = __rdtsc();
__cpuid(cpuInfo, 0);
auto a2 = __rdtsc();
result = static_cast<int>(a2 - a1);
On a barebone machine, this takes roughly 120 CPU cycles. When run from within my VM and rdtsc exiting disabled (no offsetting enabled) it takes 2200 cycles to complete.
The last test is then implementing what I described above and run the same test. Which in my case ends up with the same 2200 cycles.
Any idea why the Guest OS ignores any offsets I put in?