Timer passthrough is default disabled

Signed-off-by: Zhimin Feng <fengzhi...@bytedance.com>
---
 arch/x86/include/asm/kvm_host.h |  3 +--
 arch/x86/kvm/lapic.c            | 10 +-------
 arch/x86/kvm/vmx/vmx.c          | 52 +++++++++++++++++++++++++++++++++++++----
 arch/x86/kvm/x86.c              |  6 +++++
 include/linux/kvm_host.h        |  1 +
 include/uapi/linux/kvm.h        |  2 ++
 tools/include/uapi/linux/kvm.h  |  2 ++
 virt/kvm/kvm_main.c             |  1 +
 8 files changed, 62 insertions(+), 15 deletions(-)

diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 7971c9e755a4..9855ef419793 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -1304,9 +1304,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);
        void (*switch_to_sw_timer)(struct kvm_vcpu *vcpu);
+       int (*set_timer_passth_state)(struct kvm *kvm, void *argp);
 };
 
 struct kvm_x86_nested_ops {
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index 9b2f8b99fbf6..9ba4157f9b81 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -1508,15 +1508,6 @@ 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);
-                       }
-               }
        }
 }
 
@@ -2219,6 +2210,7 @@ void kvm_set_lapic_tscdeadline_msr(struct kvm_vcpu *vcpu, 
u64 data)
 
        hrtimer_cancel(&apic->lapic_timer.timer);
        apic->lapic_timer.tscdeadline = data;
+       vcpu->arch.tscd = data;
        start_apic_timer(apic);
 }
 
diff --git a/arch/x86/kvm/vmx/vmx.c b/arch/x86/kvm/vmx/vmx.c
index 98eca70d4251..b88f744478e9 100644
--- a/arch/x86/kvm/vmx/vmx.c
+++ b/arch/x86/kvm/vmx/vmx.c
@@ -216,6 +216,8 @@ static DEFINE_MUTEX(vmx_l1d_flush_mutex);
 /* Storage for pre module init parameter parsing */
 static enum vmx_l1d_flush_state __read_mostly vmentry_l1d_flush_param = 
VMENTER_L1D_FLUSH_AUTO;
 
+static void vmx_set_timer_passthrough(struct kvm_vcpu *vcpu, bool enable);
+
 static const struct {
        const char *option;
        bool for_parse;
@@ -6742,9 +6744,9 @@ static void vmx_restore_passth_timer(struct kvm_vcpu 
*vcpu)
                host_tscd = local_timer_info->host_tscd;
                rdmsrl(MSR_IA32_TSC_DEADLINE, guest_tscd);
 
-               if (guest_tscd != 0 &&
-                       guest_tscd != host_tscd) {
+               if (guest_tscd != 0 && guest_tscd != host_tscd) {
                        vcpu->arch.tscd = guest_tscd;
+                       vcpu->arch.apic->lapic_timer.tscdeadline = 
vcpu->arch.tscd;
                }
 
                if (host_tscd > rdtsc())
@@ -6873,6 +6875,15 @@ static fastpath_t vmx_vcpu_run(struct kvm_vcpu *vcpu)
 
        kvm_wait_lapic_expire(vcpu);
 
+       if (vcpu->arch.timer_passth_enable) {
+               if (!atomic_read(&vcpu->kvm->timer_passth_state)) {
+                       vcpu->arch.apic->lapic_timer.tscdeadline =
+                               vcpu->arch.tscd;
+                       vmx_set_timer_passthrough(vcpu, false);
+               }
+       } else if (atomic_read(&vcpu->kvm->timer_passth_state)) {
+               vmx_set_timer_passthrough(vcpu, true);
+       }
        vmx_host_lapic_timer_offload(vcpu);
 
        /*
@@ -7838,6 +7849,40 @@ static bool vmx_check_apicv_inhibit_reasons(ulong bit)
        return supported & BIT(bit);
 }
 
+static int vmx_set_timer_passth_state(struct kvm *kvm, void *argp)
+{
+       int r = -1;
+       int i;
+       struct kvm_vcpu *vcpu;
+       int state;
+
+       if (copy_from_user(&state, argp, sizeof(int)))
+               goto out;
+
+       if (!!state) {
+               /* judge whether support timer-pasth */
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       if (!vmx_host_timer_can_passth(vcpu) ||
+                               (vcpu->arch.apic->lapic_timer.timer_mode !=
+                               APIC_LVT_TIMER_TSCDEADLINE)) {
+                               pr_err("host don't support timer 
passthrough\n");
+                               goto out;
+                       }
+               }
+       }
+
+       if (kvm->timer_passth_state.counter != (!!state)) {
+               atomic_set(&kvm->timer_passth_state, !!state);
+               kvm_for_each_vcpu(i, vcpu, kvm) {
+                       kvm_vcpu_kick(vcpu);
+               }
+       }
+       r = 0;
+
+out:
+       return r;
+}
+
 static struct kvm_x86_ops vmx_x86_ops __initdata = {
        .hardware_unsetup = hardware_unsetup,
 
@@ -7966,9 +8011,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,
        .switch_to_sw_timer = vmx_passth_switch_to_sw_timer,
+       .set_timer_passth_state = vmx_set_timer_passth_state,
 };
 
 static __init int hardware_setup(void)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 2b4aa925d6d9..7db74bd9d362 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -5692,6 +5692,12 @@ long kvm_arch_vm_ioctl(struct file *filp,
        case KVM_X86_SET_MSR_FILTER:
                r = kvm_vm_ioctl_set_msr_filter(kvm, argp);
                break;
+       case KVM_SET_TIMER_PASSTH_STATE: {
+               r = -EFAULT;
+               if (kvm_x86_ops.set_timer_passth_state)
+                       r = kvm_x86_ops.set_timer_passth_state(kvm, argp);
+               break;
+       }
        default:
                r = -ENOTTY;
        }
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index 7f2e2a09ebbd..b3de12c3f473 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -505,6 +505,7 @@ struct kvm {
        struct srcu_struct irq_srcu;
        pid_t userspace_pid;
        unsigned int max_halt_poll_ns;
+       atomic_t timer_passth_state;
 };
 
 #define kvm_err(fmt, ...) \
diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h
index ca41220b40b8..6e26bc342599 100644
--- a/include/uapi/linux/kvm.h
+++ b/include/uapi/linux/kvm.h
@@ -1557,6 +1557,8 @@ struct kvm_pv_cmd {
 /* Available with KVM_CAP_X86_MSR_FILTER */
 #define KVM_X86_SET_MSR_FILTER _IOW(KVMIO,  0xc6, struct kvm_msr_filter)
 
+#define KVM_SET_TIMER_PASSTH_STATE  _IO(KVMIO,   0xc7)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
        /* Guest initialization commands */
diff --git a/tools/include/uapi/linux/kvm.h b/tools/include/uapi/linux/kvm.h
index ca41220b40b8..6e26bc342599 100644
--- a/tools/include/uapi/linux/kvm.h
+++ b/tools/include/uapi/linux/kvm.h
@@ -1557,6 +1557,8 @@ struct kvm_pv_cmd {
 /* Available with KVM_CAP_X86_MSR_FILTER */
 #define KVM_X86_SET_MSR_FILTER _IOW(KVMIO,  0xc6, struct kvm_msr_filter)
 
+#define KVM_SET_TIMER_PASSTH_STATE  _IO(KVMIO,   0xc7)
+
 /* Secure Encrypted Virtualization command */
 enum sev_cmd_id {
        /* Guest initialization commands */
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 2541a17ff1c4..7e7a3adede62 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -751,6 +751,7 @@ static struct kvm *kvm_create_vm(unsigned long type)
        mutex_init(&kvm->irq_lock);
        mutex_init(&kvm->slots_lock);
        INIT_LIST_HEAD(&kvm->devices);
+       atomic_set(&kvm->timer_passth_state, 0);
 
        BUILD_BUG_ON(KVM_MEM_SLOTS_NUM > SHRT_MAX);
 
-- 
2.11.0

Reply via email to