diff mbox

[3/3] add support for hyperv time parameter

Message ID 1390291367-21958-4-git-send-email-vrozenfe@redhat.com
State New
Headers show

Commit Message

Vadim Rozenfeld Jan. 21, 2014, 8:02 a.m. UTC
From: Vadim Rozenfeld <vrozenfeld@gamil.com>

Signed-off-by: Vadim Rozenfeld <vrozenfe@redhat.com>
---
 linux-headers/asm-x86/hyperv.h |  3 +++
 linux-headers/linux/kvm.h      |  1 +
 target-i386/cpu-qom.h          |  1 +
 target-i386/cpu.c              |  1 +
 target-i386/cpu.h              |  1 +
 target-i386/kvm.c              | 19 +++++++++++++++++++
 target-i386/machine.c          |  1 +
 7 files changed, 27 insertions(+)

Comments

Paolo Bonzini Jan. 21, 2014, 10:21 a.m. UTC | #1
Il 21/01/2014 09:02, Vadim Rozenfeld ha scritto:
> From: Vadim Rozenfeld <vrozenfeld@gamil.com>
> 
> Signed-off-by: Vadim Rozenfeld <vrozenfe@redhat.com>
> ---
>  linux-headers/asm-x86/hyperv.h |  3 +++
>  linux-headers/linux/kvm.h      |  1 +
>  target-i386/cpu-qom.h          |  1 +
>  target-i386/cpu.c              |  1 +
>  target-i386/cpu.h              |  1 +
>  target-i386/kvm.c              | 19 +++++++++++++++++++
>  target-i386/machine.c          |  1 +
>  7 files changed, 27 insertions(+)
> 
> diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
> index b8f1c01..3b400ee 100644
> --- a/linux-headers/asm-x86/hyperv.h
> +++ b/linux-headers/asm-x86/hyperv.h
> @@ -149,6 +149,9 @@
>  /* MSR used to read the per-partition time reference counter */
>  #define HV_X64_MSR_TIME_REF_COUNT		0x40000020
>  
> +/* A partition's reference time stamp counter (TSC) page */
> +#define HV_X64_MSR_REFERENCE_TSC		0x40000021
> +
>  /* MSR used to retrieve the TSC frequency */
>  #define HV_X64_MSR_TSC_FREQUENCY		0x40000022
>  
> diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> index 5a49671..999fb13 100644
> --- a/linux-headers/linux/kvm.h
> +++ b/linux-headers/linux/kvm.h
> @@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info {
>  #define KVM_CAP_ARM_EL1_32BIT 93
>  #define KVM_CAP_SPAPR_MULTITCE 94
>  #define KVM_CAP_EXT_EMUL_CPUID 95
> +#define KVM_CAP_HYPERV_TIME 96
>  
>  #ifdef KVM_CAP_IRQ_ROUTING
>  
> diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
> index d1751a4..722f11a 100644
> --- a/target-i386/cpu-qom.h
> +++ b/target-i386/cpu-qom.h
> @@ -69,6 +69,7 @@ typedef struct X86CPU {
>      bool hyperv_vapic;
>      bool hyperv_relaxed_timing;
>      int hyperv_spinlock_attempts;
> +    bool hyperv_time;
>      bool check_cpuid;
>      bool enforce_cpuid;
>  
> diff --git a/target-i386/cpu.c b/target-i386/cpu.c
> index 0eea8c7..ff3290c 100644
> --- a/target-i386/cpu.c
> +++ b/target-i386/cpu.c
> @@ -2744,6 +2744,7 @@ static Property x86_cpu_properties[] = {
>      { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
>      DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
>      DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
> +    DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
>      DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
>      DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
>      DEFINE_PROP_END_OF_LIST()
> diff --git a/target-i386/cpu.h b/target-i386/cpu.h
> index 6eeafdc..f7d7689 100644
> --- a/target-i386/cpu.h
> +++ b/target-i386/cpu.h
> @@ -850,6 +850,7 @@ typedef struct CPUX86State {
>      uint64_t msr_hv_hypercall;
>      uint64_t msr_hv_guest_os_id;
>      uint64_t msr_hv_vapic;
> +    uint64_t msr_hv_tsc;
>  
>      /* exception/interrupt handling */
>      int error_code;
> diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> index 5152e64..75ebc5d 100644
> --- a/target-i386/kvm.c
> +++ b/target-i386/kvm.c
> @@ -73,6 +73,7 @@ static bool has_msr_kvm_steal_time;
>  static int lm_capable_kernel;
>  static bool has_msr_hv_hypercall;
>  static bool has_msr_hv_vapic;
> +static bool has_msr_hv_tsc;
>  
>  static bool has_msr_architectural_pmu;
>  static uint32_t num_architectural_pmu_counters;
> @@ -433,6 +434,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs)
>  static bool hyperv_hypercall_available(X86CPU *cpu)
>  {
>      return cpu->hyperv_vapic ||
> +           cpu->hyperv_time  ||
>             (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY);
>  }
>  
> @@ -492,6 +494,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
>              c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
>              has_msr_hv_vapic = true;
>          }
> +        if (cpu->hyperv_time &&
> +            kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
> +            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
> +            c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
> +            c->eax |= 0x200;
> +            has_msr_hv_tsc = true;
> +        }
>  
>          c = &cpuid_data.entries[cpuid_i++];
>          c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
> @@ -1195,6 +1204,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
>              kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
>                                env->msr_hv_vapic);
>          }
> +        if (has_msr_hv_tsc) {
> +            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
> +                              env->msr_hv_tsc);
> +        }
>          if (has_msr_feature_control) {
>              kvm_msr_entry_set(&msrs[n++], MSR_IA32_FEATURE_CONTROL,
>                                env->msr_ia32_feature_control);
> @@ -1480,6 +1493,9 @@ static int kvm_get_msrs(X86CPU *cpu)
>      if (has_msr_hv_vapic) {
>          msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
>      }
> +    if (has_msr_hv_tsc) {
> +        msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
> +    }
>  
>      msr_data.info.nmsrs = n;
>      ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
> @@ -1594,6 +1610,9 @@ static int kvm_get_msrs(X86CPU *cpu)
>          case HV_X64_MSR_APIC_ASSIST_PAGE:
>              env->msr_hv_vapic = msrs[i].data;
>              break;
> +        case HV_X64_MSR_REFERENCE_TSC:
> +            env->msr_hv_tsc = msrs[i].data;
> +            break;
>          }
>      }
>  
> diff --git a/target-i386/machine.c b/target-i386/machine.c
> index 58c5b45..9e9a001 100644
> --- a/target-i386/machine.c
> +++ b/target-i386/machine.c
> @@ -523,6 +523,7 @@ static const VMStateDescription vmstate_msr_hyperv = {
>          VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
>          VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
>          VMSTATE_UINT64(env.msr_hv_vapic, X86CPU),
> +        VMSTATE_UINT64(env.msr_hv_tsc, X86CPU),
>          VMSTATE_END_OF_LIST()
>      }
>  };
> 

If you are planning some level of backwards compatibility with RHEL6, it
may make sense to use separate subsections.

Paolo
Vadim Rozenfeld Jan. 21, 2014, 9:12 p.m. UTC | #2
On Tue, 2014-01-21 at 11:21 +0100, Paolo Bonzini wrote:
> Il 21/01/2014 09:02, Vadim Rozenfeld ha scritto:
> > From: Vadim Rozenfeld <vrozenfeld@gamil.com>
> > 
> > Signed-off-by: Vadim Rozenfeld <vrozenfe@redhat.com>
> > ---
> >  linux-headers/asm-x86/hyperv.h |  3 +++
> >  linux-headers/linux/kvm.h      |  1 +
> >  target-i386/cpu-qom.h          |  1 +
> >  target-i386/cpu.c              |  1 +
> >  target-i386/cpu.h              |  1 +
> >  target-i386/kvm.c              | 19 +++++++++++++++++++
> >  target-i386/machine.c          |  1 +
> >  7 files changed, 27 insertions(+)
> > 
> > diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
> > index b8f1c01..3b400ee 100644
> > --- a/linux-headers/asm-x86/hyperv.h
> > +++ b/linux-headers/asm-x86/hyperv.h
> > @@ -149,6 +149,9 @@
> >  /* MSR used to read the per-partition time reference counter */
> >  #define HV_X64_MSR_TIME_REF_COUNT		0x40000020
> >  
> > +/* A partition's reference time stamp counter (TSC) page */
> > +#define HV_X64_MSR_REFERENCE_TSC		0x40000021
> > +
> >  /* MSR used to retrieve the TSC frequency */
> >  #define HV_X64_MSR_TSC_FREQUENCY		0x40000022
> >  
> > diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
> > index 5a49671..999fb13 100644
> > --- a/linux-headers/linux/kvm.h
> > +++ b/linux-headers/linux/kvm.h
> > @@ -674,6 +674,7 @@ struct kvm_ppc_smmu_info {
> >  #define KVM_CAP_ARM_EL1_32BIT 93
> >  #define KVM_CAP_SPAPR_MULTITCE 94
> >  #define KVM_CAP_EXT_EMUL_CPUID 95
> > +#define KVM_CAP_HYPERV_TIME 96
> >  
> >  #ifdef KVM_CAP_IRQ_ROUTING
> >  
> > diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
> > index d1751a4..722f11a 100644
> > --- a/target-i386/cpu-qom.h
> > +++ b/target-i386/cpu-qom.h
> > @@ -69,6 +69,7 @@ typedef struct X86CPU {
> >      bool hyperv_vapic;
> >      bool hyperv_relaxed_timing;
> >      int hyperv_spinlock_attempts;
> > +    bool hyperv_time;
> >      bool check_cpuid;
> >      bool enforce_cpuid;
> >  
> > diff --git a/target-i386/cpu.c b/target-i386/cpu.c
> > index 0eea8c7..ff3290c 100644
> > --- a/target-i386/cpu.c
> > +++ b/target-i386/cpu.c
> > @@ -2744,6 +2744,7 @@ static Property x86_cpu_properties[] = {
> >      { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
> >      DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
> >      DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
> > +    DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
> >      DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
> >      DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
> >      DEFINE_PROP_END_OF_LIST()
> > diff --git a/target-i386/cpu.h b/target-i386/cpu.h
> > index 6eeafdc..f7d7689 100644
> > --- a/target-i386/cpu.h
> > +++ b/target-i386/cpu.h
> > @@ -850,6 +850,7 @@ typedef struct CPUX86State {
> >      uint64_t msr_hv_hypercall;
> >      uint64_t msr_hv_guest_os_id;
> >      uint64_t msr_hv_vapic;
> > +    uint64_t msr_hv_tsc;
> >  
> >      /* exception/interrupt handling */
> >      int error_code;
> > diff --git a/target-i386/kvm.c b/target-i386/kvm.c
> > index 5152e64..75ebc5d 100644
> > --- a/target-i386/kvm.c
> > +++ b/target-i386/kvm.c
> > @@ -73,6 +73,7 @@ static bool has_msr_kvm_steal_time;
> >  static int lm_capable_kernel;
> >  static bool has_msr_hv_hypercall;
> >  static bool has_msr_hv_vapic;
> > +static bool has_msr_hv_tsc;
> >  
> >  static bool has_msr_architectural_pmu;
> >  static uint32_t num_architectural_pmu_counters;
> > @@ -433,6 +434,7 @@ unsigned long kvm_arch_vcpu_id(CPUState *cs)
> >  static bool hyperv_hypercall_available(X86CPU *cpu)
> >  {
> >      return cpu->hyperv_vapic ||
> > +           cpu->hyperv_time  ||
> >             (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY);
> >  }
> >  
> > @@ -492,6 +494,13 @@ int kvm_arch_init_vcpu(CPUState *cs)
> >              c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
> >              has_msr_hv_vapic = true;
> >          }
> > +        if (cpu->hyperv_time &&
> > +            kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
> > +            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
> > +            c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
> > +            c->eax |= 0x200;
> > +            has_msr_hv_tsc = true;
> > +        }
> >  
> >          c = &cpuid_data.entries[cpuid_i++];
> >          c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
> > @@ -1195,6 +1204,10 @@ static int kvm_put_msrs(X86CPU *cpu, int level)
> >              kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
> >                                env->msr_hv_vapic);
> >          }
> > +        if (has_msr_hv_tsc) {
> > +            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
> > +                              env->msr_hv_tsc);
> > +        }
> >          if (has_msr_feature_control) {
> >              kvm_msr_entry_set(&msrs[n++], MSR_IA32_FEATURE_CONTROL,
> >                                env->msr_ia32_feature_control);
> > @@ -1480,6 +1493,9 @@ static int kvm_get_msrs(X86CPU *cpu)
> >      if (has_msr_hv_vapic) {
> >          msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
> >      }
> > +    if (has_msr_hv_tsc) {
> > +        msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
> > +    }
> >  
> >      msr_data.info.nmsrs = n;
> >      ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
> > @@ -1594,6 +1610,9 @@ static int kvm_get_msrs(X86CPU *cpu)
> >          case HV_X64_MSR_APIC_ASSIST_PAGE:
> >              env->msr_hv_vapic = msrs[i].data;
> >              break;
> > +        case HV_X64_MSR_REFERENCE_TSC:
> > +            env->msr_hv_tsc = msrs[i].data;
> > +            break;
> >          }
> >      }
> >  
> > diff --git a/target-i386/machine.c b/target-i386/machine.c
> > index 58c5b45..9e9a001 100644
> > --- a/target-i386/machine.c
> > +++ b/target-i386/machine.c
> > @@ -523,6 +523,7 @@ static const VMStateDescription vmstate_msr_hyperv = {
> >          VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
> >          VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
> >          VMSTATE_UINT64(env.msr_hv_vapic, X86CPU),
> > +        VMSTATE_UINT64(env.msr_hv_tsc, X86CPU),
> >          VMSTATE_END_OF_LIST()
> >      }
> >  };
> > 
> 
> If you are planning some level of backwards compatibility with RHEL6, it
> may make sense to use separate subsections.

I believe we have to make it backward compatible. In RHEL6 we added
support for relaxed timers only, but upstream doesn't have such bits.
Technically, hypercall page, vapic and iTSC pages will be introduced in
RHEL7 and as you said, they will probably go to a different, new
section, but for upstream the entire section is absolutely new.

Vadim.


> 
> Paolo
>
Paolo Bonzini Jan. 22, 2014, 10:02 a.m. UTC | #3
Il 21/01/2014 22:12, Vadim Rozenfeld ha scritto:
>> >
>> > If you are planning some level of backwards compatibility with RHEL6, it
>> > may make sense to use separate subsections.
> I believe we have to make it backward compatible. In RHEL6 we added
> support for relaxed timers only, but upstream doesn't have such bits.
> Technically, hypercall page, vapic and iTSC pages will be introduced in
> RHEL7 and as you said, they will probably go to a different, new
> section, but for upstream the entire section is absolutely new.

Ok, then upstream we have choice.  Using 2 subsections is not wrong, and 
it makes sense since it's covered by different kernel capabilities.

Paolo
diff mbox

Patch

diff --git a/linux-headers/asm-x86/hyperv.h b/linux-headers/asm-x86/hyperv.h
index b8f1c01..3b400ee 100644
--- a/linux-headers/asm-x86/hyperv.h
+++ b/linux-headers/asm-x86/hyperv.h
@@ -149,6 +149,9 @@ 
 /* MSR used to read the per-partition time reference counter */
 #define HV_X64_MSR_TIME_REF_COUNT		0x40000020
 
+/* A partition's reference time stamp counter (TSC) page */
+#define HV_X64_MSR_REFERENCE_TSC		0x40000021
+
 /* MSR used to retrieve the TSC frequency */
 #define HV_X64_MSR_TSC_FREQUENCY		0x40000022
 
diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h
index 5a49671..999fb13 100644
--- a/linux-headers/linux/kvm.h
+++ b/linux-headers/linux/kvm.h
@@ -674,6 +674,7 @@  struct kvm_ppc_smmu_info {
 #define KVM_CAP_ARM_EL1_32BIT 93
 #define KVM_CAP_SPAPR_MULTITCE 94
 #define KVM_CAP_EXT_EMUL_CPUID 95
+#define KVM_CAP_HYPERV_TIME 96
 
 #ifdef KVM_CAP_IRQ_ROUTING
 
diff --git a/target-i386/cpu-qom.h b/target-i386/cpu-qom.h
index d1751a4..722f11a 100644
--- a/target-i386/cpu-qom.h
+++ b/target-i386/cpu-qom.h
@@ -69,6 +69,7 @@  typedef struct X86CPU {
     bool hyperv_vapic;
     bool hyperv_relaxed_timing;
     int hyperv_spinlock_attempts;
+    bool hyperv_time;
     bool check_cpuid;
     bool enforce_cpuid;
 
diff --git a/target-i386/cpu.c b/target-i386/cpu.c
index 0eea8c7..ff3290c 100644
--- a/target-i386/cpu.c
+++ b/target-i386/cpu.c
@@ -2744,6 +2744,7 @@  static Property x86_cpu_properties[] = {
     { .name  = "hv-spinlocks", .info  = &qdev_prop_spinlocks },
     DEFINE_PROP_BOOL("hv-relaxed", X86CPU, hyperv_relaxed_timing, false),
     DEFINE_PROP_BOOL("hv-vapic", X86CPU, hyperv_vapic, false),
+    DEFINE_PROP_BOOL("hv-time", X86CPU, hyperv_time, false),
     DEFINE_PROP_BOOL("check", X86CPU, check_cpuid, false),
     DEFINE_PROP_BOOL("enforce", X86CPU, enforce_cpuid, false),
     DEFINE_PROP_END_OF_LIST()
diff --git a/target-i386/cpu.h b/target-i386/cpu.h
index 6eeafdc..f7d7689 100644
--- a/target-i386/cpu.h
+++ b/target-i386/cpu.h
@@ -850,6 +850,7 @@  typedef struct CPUX86State {
     uint64_t msr_hv_hypercall;
     uint64_t msr_hv_guest_os_id;
     uint64_t msr_hv_vapic;
+    uint64_t msr_hv_tsc;
 
     /* exception/interrupt handling */
     int error_code;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 5152e64..75ebc5d 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -73,6 +73,7 @@  static bool has_msr_kvm_steal_time;
 static int lm_capable_kernel;
 static bool has_msr_hv_hypercall;
 static bool has_msr_hv_vapic;
+static bool has_msr_hv_tsc;
 
 static bool has_msr_architectural_pmu;
 static uint32_t num_architectural_pmu_counters;
@@ -433,6 +434,7 @@  unsigned long kvm_arch_vcpu_id(CPUState *cs)
 static bool hyperv_hypercall_available(X86CPU *cpu)
 {
     return cpu->hyperv_vapic ||
+           cpu->hyperv_time  ||
            (cpu->hyperv_spinlock_attempts != HYPERV_SPINLOCK_NEVER_RETRY);
 }
 
@@ -492,6 +494,13 @@  int kvm_arch_init_vcpu(CPUState *cs)
             c->eax |= HV_X64_MSR_APIC_ACCESS_AVAILABLE;
             has_msr_hv_vapic = true;
         }
+        if (cpu->hyperv_time &&
+            kvm_check_extension(cs->kvm_state, KVM_CAP_HYPERV_TIME) > 0) {
+            c->eax |= HV_X64_MSR_HYPERCALL_AVAILABLE;
+            c->eax |= HV_X64_MSR_TIME_REF_COUNT_AVAILABLE;
+            c->eax |= 0x200;
+            has_msr_hv_tsc = true;
+        }
 
         c = &cpuid_data.entries[cpuid_i++];
         c->function = HYPERV_CPUID_ENLIGHTMENT_INFO;
@@ -1195,6 +1204,10 @@  static int kvm_put_msrs(X86CPU *cpu, int level)
             kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_APIC_ASSIST_PAGE,
                               env->msr_hv_vapic);
         }
+        if (has_msr_hv_tsc) {
+            kvm_msr_entry_set(&msrs[n++], HV_X64_MSR_REFERENCE_TSC,
+                              env->msr_hv_tsc);
+        }
         if (has_msr_feature_control) {
             kvm_msr_entry_set(&msrs[n++], MSR_IA32_FEATURE_CONTROL,
                               env->msr_ia32_feature_control);
@@ -1480,6 +1493,9 @@  static int kvm_get_msrs(X86CPU *cpu)
     if (has_msr_hv_vapic) {
         msrs[n++].index = HV_X64_MSR_APIC_ASSIST_PAGE;
     }
+    if (has_msr_hv_tsc) {
+        msrs[n++].index = HV_X64_MSR_REFERENCE_TSC;
+    }
 
     msr_data.info.nmsrs = n;
     ret = kvm_vcpu_ioctl(CPU(cpu), KVM_GET_MSRS, &msr_data);
@@ -1594,6 +1610,9 @@  static int kvm_get_msrs(X86CPU *cpu)
         case HV_X64_MSR_APIC_ASSIST_PAGE:
             env->msr_hv_vapic = msrs[i].data;
             break;
+        case HV_X64_MSR_REFERENCE_TSC:
+            env->msr_hv_tsc = msrs[i].data;
+            break;
         }
     }
 
diff --git a/target-i386/machine.c b/target-i386/machine.c
index 58c5b45..9e9a001 100644
--- a/target-i386/machine.c
+++ b/target-i386/machine.c
@@ -523,6 +523,7 @@  static const VMStateDescription vmstate_msr_hyperv = {
         VMSTATE_UINT64(env.msr_hv_hypercall, X86CPU),
         VMSTATE_UINT64(env.msr_hv_guest_os_id, X86CPU),
         VMSTATE_UINT64(env.msr_hv_vapic, X86CPU),
+        VMSTATE_UINT64(env.msr_hv_tsc, X86CPU),
         VMSTATE_END_OF_LIST()
     }
 };