[RFC: timer passthrough 8/9] KVM: vmx: Dynamically open or close the timer-passthrough for pre-vm

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



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




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux