[RFC: timer passthrough 3/9] KVM: vmx: enable passthrough timer to guest

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

 



Allow Guest to write tscdeadline msr directly.

Signed-off-by: Zhimin Feng <fengzhimin@xxxxxxxxxxxxx>
---
 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




[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