KVM: nVMX: Migrate the VMX-preemption timer
authorJim Mattson <jmattson@google.com>
Fri, 8 May 2020 20:36:43 +0000 (13:36 -0700)
committerPaolo Bonzini <pbonzini@redhat.com>
Fri, 15 May 2020 16:26:26 +0000 (12:26 -0400)
The hrtimer used to emulate the VMX-preemption timer must be pinned to
the same logical processor as the vCPU thread to be interrupted if we
want to have any hope of adhering to the architectural specification
of the VMX-preemption timer. Even with this change, the emulated
VMX-preemption timer VM-exit occasionally arrives too late.

Signed-off-by: Jim Mattson <jmattson@google.com>
Reviewed-by: Peter Shier <pshier@google.com>
Reviewed-by: Oliver Upton <oupton@google.com>
Message-Id: <20200508203643.85477-4-jmattson@google.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
arch/x86/include/asm/kvm_host.h
arch/x86/kvm/irq.c
arch/x86/kvm/vmx/vmx.c

index c3906fb2b93f7eeb625aefe17e20f9c9012a50b3..a3ce391c9e7a2a78573fabf4d05130c61c061615 100644 (file)
@@ -1247,6 +1247,8 @@ struct kvm_x86_ops {
 
        bool (*apic_init_signal_blocked)(struct kvm_vcpu *vcpu);
        int (*enable_direct_tlbflush)(struct kvm_vcpu *vcpu);
+
+       void (*migrate_timers)(struct kvm_vcpu *vcpu);
 };
 
 struct kvm_x86_nested_ops {
index e330e7d125f728f277826acb86cc3a431d1477a1..54f7ea68083bd927e600cace7530f15db5e49de1 100644 (file)
@@ -159,6 +159,8 @@ void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
 {
        __kvm_migrate_apic_timer(vcpu);
        __kvm_migrate_pit_timer(vcpu);
+       if (kvm_x86_ops.migrate_timers)
+               kvm_x86_ops.migrate_timers(vcpu);
 }
 
 bool kvm_arch_irqfd_allowed(struct kvm *kvm, struct kvm_irqfd *args)
index 68f4efb2b9c29ce482a846ed6c67fe37574d154b..6a03c27ff314737a966e0ed264e5e9664998e19b 100644 (file)
@@ -7814,6 +7814,16 @@ static bool vmx_apic_init_signal_blocked(struct kvm_vcpu *vcpu)
        return to_vmx(vcpu)->nested.vmxon;
 }
 
+static void vmx_migrate_timers(struct kvm_vcpu *vcpu)
+{
+       if (is_guest_mode(vcpu)) {
+               struct hrtimer *timer = &to_vmx(vcpu)->nested.preemption_timer;
+
+               if (hrtimer_try_to_cancel(timer) == 1)
+                       hrtimer_start_expires(timer, HRTIMER_MODE_ABS_PINNED);
+       }
+}
+
 static void hardware_unsetup(void)
 {
        if (nested)
@@ -7957,6 +7967,7 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
 
        .need_emulation_on_page_fault = vmx_need_emulation_on_page_fault,
        .apic_init_signal_blocked = vmx_apic_init_signal_blocked,
+       .migrate_timers = vmx_migrate_timers,
 };
 
 static __init int hardware_setup(void)