intel / haxm

Intel® Hardware Accelerated Execution Manager (Intel® HAXM)
BSD 3-Clause "New" or "Revised" License
3.23k stars 877 forks source link

How to use tsc clocksource with haxm? #339

Open eillon opened 3 years ago

eillon commented 3 years ago

Hi, why I can not use tsc clocksource with haxm? When using the haxm as accelerator, the guest kernel will turn off TSC clock:

Measured 38253476481 cycles TSC warp between CPUs, turning off TSC clock.

We runs this on i7-8700, which supports constant TSC. I guess this is caused by inconsistent tsc_offset between vCPUs.

wcwang commented 3 years ago

Thanks for your question. Currently, HAXM only supports HPET as the clock source, It needs some CPUID features enabled in guest to support TSC clock. Which VM do you use, Android Emulator or QEMU?

eillon commented 3 years ago

Android Emulator. The guest kernel version is 4.14+. And I can see the TSC feature in guest cpu flags:

guest:# lscpu
...
Flags    tsc rdtscp constant_tsc

I have tried to modify the tsc_offset in haxm and then I can use tsc clocksource in guest. But I'm not sure there's any other consequence of this change.

diff --git a/core/include/vm.h b/core/include/vm.h
index 36a831c..c6826f3 100644
--- a/core/include/vm.h
+++ b/core/include/vm.h
@@ -83,6 +83,7 @@ struct vm_t {
     uint64_t spare_ramsize;
     uint ram_entry_num;
     struct hax_vcpu_mem *ram_entry;
+    int64_t tsc_offset;
 };

 struct hva_entry {
diff --git a/core/vcpu.c b/core/vcpu.c
index 287b46e..0567538 100644
--- a/core/vcpu.c
+++ b/core/vcpu.c
@@ -593,7 +593,11 @@ static void vcpu_init(struct vcpu_t *vcpu)

     vcpu->ref_count = 1;

-    vcpu->tsc_offset = 0ULL - ia32_rdtsc();
+    if (vcpu->vm->tsc_offset == 0) {
+        vcpu->vm->tsc_offset = 0ULL - ia32_rdtsc();
+    }
+
+    vcpu->tsc_offset = vcpu->vm->tsc_offset;

     // Prepare the vcpu state to Power-up
     state->_rflags = 2;
@@ -3562,7 +3566,7 @@ static int handle_msr_write(struct vcpu_t *vcpu, uint32_t msr, uint64_t val,

     switch (msr) {
         case IA32_TSC: {
-            vcpu->tsc_offset = val - ia32_rdtsc();
+            vcpu->tsc_offset = vcpu->vm->tsc_offset;
             if (vmx(vcpu, pcpu_ctls) & USE_TSC_OFFSETTING) {
                 vmwrite(vcpu, VMX_TSC_OFFSET, vcpu->tsc_offset);
             }
wcwang commented 3 years ago

First, have you enabled constant TSC? If so, the TSC offset may be slightly different on guest vCPUs, but it cannot be as large as you mentioned. Secondly, your change made the TSC offset fixed forcibly, which probably solves your problem, but it should not be the root cause as the logic seems inappropriate. It is suggested to check why the guest reports such large cycles first and then find the cause. Thanks.

eillon commented 3 years ago

I'm sure that I'm using constant TSC. Thanks for your suggestion.