Allow Guest to write tscdeadline msr directly.

Signed-off-by: Zhimin Feng <fengzhi...@bytedance.com>
---
 arch/x86/include/asm/kvm_host.h |  3 +++
 arch/x86/kvm/lapic.c            |  9 +++++++
 arch/x86/kvm/vmx/vmx.c          | 56 +++++++++++++++++++++++++++++++++++++++++
 3 files changed, 68 insertions(+)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 82a51f0d01a2..500fa031297d 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -533,6 +533,7 @@ struct tick_device {
 
 struct timer_passth_info {
        u64 host_tscd;
+       bool host_in_tscdeadline;
        struct clock_event_device *curr_dev;
 
        void (*orig_event_handler)(struct clock_event_device *dev);
@@ -1302,6 +1303,8 @@ struct kvm_x86_ops {
 
        void (*migrate_timers)(struct kvm_vcpu *vcpu);
        void (*msr_filter_changed)(struct kvm_vcpu *vcpu);
+       void (*set_timer_passthrough)(struct kvm_vcpu *vcpu, bool enable);
+       int (*host_timer_can_passth)(struct kvm_vcpu *vcpu);
 };
 
 struct kvm_x86_nested_ops {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 86c33d53c90a..9b2f8b99fbf6 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1508,6 +1508,15 @@ static void apic_update_lvtt(struct kvm_lapic *apic)
                }
                apic->lapic_timer.timer_mode = timer_mode;
                limit_periodic_timer_frequency(apic);
+
+               if (kvm_x86_ops.host_timer_can_passth(apic->vcpu)) {
+                       if (apic_lvtt_tscdeadline(apic)) {
+                               kvm_x86_ops.set_timer_passthrough(apic->vcpu, 
true);
+                       } else {
+                               if (apic->vcpu->arch.timer_passth_enable)
+                                       
kvm_x86_ops.set_timer_passthrough(apic->vcpu, false);
+                       }
+               }
        }
 }
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 0bf9941df842..0c1b5ee4bb8e 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -47,6 +47,7 @@
 #include <asm/spec-ctrl.h>
 #include <asm/virtext.h>
 #include <asm/vmx.h>
+#include <asm/apicdef.h>
 
 #include "capabilities.h"
 #include "cpuid.h"
@@ -705,6 +706,8 @@ static bool is_valid_passthrough_msr(u32 msr)
        case MSR_IA32_RTIT_ADDR0_A ... MSR_IA32_RTIT_ADDR3_B:
                /* PT MSRs. These are handled in pt_update_intercept_for_msr() 
*/
                return true;
+       case MSR_IA32_TSC_DEADLINE:
+               return true;
        }
 
        r = possible_passthrough_msr_slot(msr) != -ENOENT;
@@ -7670,6 +7673,54 @@ static void vmx_migrate_timers(struct kvm_vcpu *vcpu)
        }
 }
 
+static void host_lapic_timer_in_deadline(void *junk)
+{
+       unsigned int v;
+       struct timer_passth_info *local_timer_info;
+       int cpu = smp_processor_id();
+
+       local_timer_info = &per_cpu(passth_info, cpu);
+       v = apic_read(APIC_LVTT);
+       local_timer_info->host_in_tscdeadline = (v & 
APIC_LVT_TIMER_TSCDEADLINE);
+}
+
+static bool host_all_cpu_in_tscdeadline(void)
+{
+       int cpu;
+       struct timer_passth_info *local_timer_info;
+
+       for_each_online_cpu(cpu) {
+               local_timer_info = &per_cpu(passth_info, cpu);
+               if (!local_timer_info->host_in_tscdeadline)
+                       return false;
+       }
+
+       return true;
+}
+
+static int vmx_host_timer_can_passth(struct kvm_vcpu *vcpu)
+{
+       if (!enable_timer_passth || !cpu_has_vmx_msr_bitmap() ||
+                       !host_all_cpu_in_tscdeadline())
+               return 0;
+       return 1;
+}
+
+static void vmx_set_timer_passthrough(struct kvm_vcpu *vcpu, bool enable)
+{
+       if (enable) {
+               vmx_disable_intercept_for_msr(vcpu, MSR_IA32_TSC_DEADLINE,
+                                                                         
MSR_TYPE_RW);
+               vcpu->arch.timer_passth_enable = 1;
+       } else {
+               vmx_enable_intercept_for_msr(vcpu, MSR_IA32_TSC_DEADLINE,
+                                                                        
MSR_TYPE_RW);
+               vmcs_clear_bits(PIN_BASED_VM_EXEC_CONTROL,
+                               PIN_BASED_VMX_PREEMPTION_TIMER);
+               vcpu->arch.timer_passth_enable = 0;
+       }
+}
+
 static void hardware_unsetup(void)
 {
        if (enable_timer_passth)
@@ -7817,6 +7868,8 @@ static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .migrate_timers = vmx_migrate_timers,
 
        .msr_filter_changed = vmx_msr_filter_changed,
+       .set_timer_passthrough = vmx_set_timer_passthrough,
+       .host_timer_can_passth = vmx_host_timer_can_passth,
 };
 
 static __init int hardware_setup(void)
@@ -7987,6 +8040,9 @@ static __init int hardware_setup(void)
        vmx_set_cpu_caps();
 
        if (enable_timer_passth)
+               on_each_cpu(host_lapic_timer_in_deadline, NULL, 1);
+
+       if (enable_timer_passth)
                on_each_cpu(vmx_host_timer_passth_init, NULL, 1);
 
        r = alloc_kvm_area();
-- 
2.11.0

Reply via email to