我遇到了使用我的Hypervisor进行TSC抵消的问题。根据intel手册,您必须确保VM不会退出rdtsc
,因此我禁用了rdtsc_exiting
。我还启用了use tsc offsetting
控件。以这种方式设置VMCS
应该允许我写入tsc_offset
控制字段来改变VM(客户操作系统)读取TSC的方式。
我在退出处理程序中将控制权交还给VM之前就做了,我将-2000
写入TSC偏移字段。
__vmx_vmwrite(Vmcs::kTscOffset, -2000);
我使用此作为我的VmWrite
实现:
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;
}
根据intel手册,这应该足以使用TSC抵消。所以为了测试我写了这个小测试程序(在我的情况下CPUID正在做一个VMEXIT):
auto a1 = __rdtsc();
__cpuid(cpuInfo, 0);
auto a2 = __rdtsc();
result = static_cast<int>(a2 - a1);
在准系统机器上,这需要大约120个CPU周期。从我的VM中运行并且rdtsc退出禁用(未启用偏移)时,需要2200个周期才能完成。
最后一个测试然后实现我上面描述的并运行相同的测试。在我的情况下,最终会有相同的2200个周期。
知道Guest OS为什么忽略我放入的任何偏移量?