KVM: x86: hyper-v: Prevent using not-yet-updated TSC page by secondary CPUs
authorVitaly Kuznetsov <vkuznets@redhat.com>
Tue, 16 Mar 2021 14:37:34 +0000 (15:37 +0100)
committerPaolo Bonzini <pbonzini@redhat.com>
Wed, 17 Mar 2021 08:03:22 +0000 (04:03 -0400)
When KVM_REQ_MASTERCLOCK_UPDATE request is issued (e.g. after migration)
we need to make sure no vCPU sees stale values in PV clock structures and
thus all vCPUs are kicked with KVM_REQ_CLOCK_UPDATE. Hyper-V TSC page
clocksource is global and kvm_guest_time_update() only updates in on vCPU0
but this is not entirely correct: nothing blocks some other vCPU from
entering the guest before we finish the update on CPU0 and it can read
stale values from the page.

Invalidate TSC page in kvm_gen_update_masterclock() to switch all vCPUs
to using MSR based clocksource (HV_X64_MSR_TIME_REF_COUNT).

Signed-off-by: Vitaly Kuznetsov <vkuznets@redhat.com>
Message-Id: <20210316143736.964151-3-vkuznets@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/kvm/hyperv.c
arch/x86/kvm/hyperv.h
arch/x86/kvm/x86.c

index eefb85b86fe84a4bb2d46f2695ed918ee5cc2e5a..a0e3c49233d4cc70758c10201e06f5b05f42cb22 100644 (file)
@@ -1137,6 +1137,29 @@ out_unlock:
        mutex_unlock(&hv->hv_lock);
 }
 
+void kvm_hv_invalidate_tsc_page(struct kvm *kvm)
+{
+       struct kvm_hv *hv = to_kvm_hv(kvm);
+       u64 gfn;
+
+       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+               return;
+
+       mutex_lock(&hv->hv_lock);
+
+       if (!(hv->hv_tsc_page & HV_X64_MSR_TSC_REFERENCE_ENABLE))
+               goto out_unlock;
+
+       gfn = hv->hv_tsc_page >> HV_X64_MSR_TSC_REFERENCE_ADDRESS_SHIFT;
+
+       hv->tsc_ref.tsc_sequence = 0;
+       kvm_write_guest(kvm, gfn_to_gpa(gfn),
+                       &hv->tsc_ref, sizeof(hv->tsc_ref.tsc_sequence));
+
+out_unlock:
+       mutex_unlock(&hv->hv_lock);
+}
+
 static int kvm_hv_set_msr_pw(struct kvm_vcpu *vcpu, u32 msr, u64 data,
                             bool host)
 {
index e951af1fcb2c5929ef7a2d5a119c26b4344f53c7..60547d5cb6d72451e25c8d7ae3df04e0b0267d9a 100644 (file)
@@ -133,6 +133,7 @@ void kvm_hv_process_stimers(struct kvm_vcpu *vcpu);
 
 void kvm_hv_setup_tsc_page(struct kvm *kvm,
                           struct pvclock_vcpu_time_info *hv_clock);
+void kvm_hv_invalidate_tsc_page(struct kvm *kvm);
 
 void kvm_hv_init_vm(struct kvm *kvm);
 void kvm_hv_destroy_vm(struct kvm *kvm);
index 47e021bdcc94ab324d03057b881cad0dcfd78534..a5c5b38735e196bc091fee0ad165254c12e0f48c 100644 (file)
@@ -2551,6 +2551,8 @@ static void kvm_gen_update_masterclock(struct kvm *kvm)
        struct kvm_vcpu *vcpu;
        struct kvm_arch *ka = &kvm->arch;
 
+       kvm_hv_invalidate_tsc_page(kvm);
+
        spin_lock(&ka->pvclock_gtod_sync_lock);
        kvm_make_mclock_inprogress_request(kvm);
        /* no guest entries from this point */