Timer passthrough is default disabled Signed-off-by: Zhimin Feng <fengzhimin@xxxxxxxxxxxxx> --- 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