[kvm-unit-tests PATCH v4 2/2] x86: nSVM: Add support for VNMI test

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

 



From: Santosh Shukla <santosh.shukla@xxxxxxx>

Add a VNMI test case to test Virtual NMI in a nested environment,
The test covers the Virtual NMI (VNMI) delivery.

Signed-off-by: Santosh Shukla <santosh.shukla@xxxxxxx>
[sean: reuse pieces of NMI test framework, fix formatting issues]
Signed-off-by: Sean Christopherson <seanjc@xxxxxxxxxx>
---
 lib/x86/processor.h |  1 +
 x86/svm.c           |  5 +++
 x86/svm.h           |  8 +++++
 x86/svm_tests.c     | 78 +++++++++++++++++++++++++++++++++++++++++++++
 4 files changed, 92 insertions(+)

diff --git a/lib/x86/processor.h b/lib/x86/processor.h
index 3d58ef72..3802c1e2 100644
--- a/lib/x86/processor.h
+++ b/lib/x86/processor.h
@@ -267,6 +267,7 @@ static inline bool is_intel(void)
 #define X86_FEATURE_PAUSEFILTER		(CPUID(0x8000000A, 0, EDX, 10))
 #define X86_FEATURE_PFTHRESHOLD		(CPUID(0x8000000A, 0, EDX, 12))
 #define	X86_FEATURE_VGIF		(CPUID(0x8000000A, 0, EDX, 16))
+#define X86_FEATURE_V_NMI               (CPUID(0x8000000A, 0, EDX, 25))
 #define	X86_FEATURE_AMD_PMU_V2		(CPUID(0x80000022, 0, EAX, 0))
 
 static inline bool this_cpu_has(u64 feature)
diff --git a/x86/svm.c b/x86/svm.c
index ba435b4a..022a0fde 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -99,6 +99,11 @@ bool npt_supported(void)
 	return this_cpu_has(X86_FEATURE_NPT);
 }
 
+bool vnmi_supported(void)
+{
+       return this_cpu_has(X86_FEATURE_V_NMI);
+}
+
 int get_test_stage(struct svm_test *test)
 {
 	barrier();
diff --git a/x86/svm.h b/x86/svm.h
index 766ff7e3..4631c2ff 100644
--- a/x86/svm.h
+++ b/x86/svm.h
@@ -131,6 +131,13 @@ struct __attribute__ ((__packed__)) vmcb_control_area {
 #define V_INTR_MASKING_SHIFT 24
 #define V_INTR_MASKING_MASK (1 << V_INTR_MASKING_SHIFT)
 
+#define V_NMI_PENDING_SHIFT	11
+#define V_NMI_PENDING_MASK	(1 << V_NMI_PENDING_SHIFT)
+#define V_NMI_BLOCKING_SHIFT	12
+#define V_NMI_BLOCKING_MASK	(1 << V_NMI_BLOCKING_SHIFT)
+#define V_NMI_ENABLE_SHIFT	26
+#define V_NMI_ENABLE_MASK	(1 << V_NMI_ENABLE_SHIFT)
+
 #define SVM_INTERRUPT_SHADOW_MASK 1
 
 #define SVM_IOIO_STR_SHIFT 2
@@ -419,6 +426,7 @@ void default_prepare(struct svm_test *test);
 void default_prepare_gif_clear(struct svm_test *test);
 bool default_finished(struct svm_test *test);
 bool npt_supported(void);
+bool vnmi_supported(void);
 int get_test_stage(struct svm_test *test);
 void set_test_stage(struct svm_test *test, int s);
 void inc_test_stage(struct svm_test *test);
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index e87db3fa..3d2ca0f6 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1419,6 +1419,81 @@ static bool nmi_hlt_check(struct svm_test *test)
 	return get_test_stage(test) == 3;
 }
 
+static void vnmi_prepare(struct svm_test *test)
+{
+	nmi_prepare(test);
+
+	/*
+	 * Disable NMI interception to start.  Enabling vNMI without
+	 * intercepting "real" NMIs should result in an ERR VM-Exit.
+	 */
+	vmcb->control.intercept &= ~(1ULL << INTERCEPT_NMI);
+	vmcb->control.int_ctl = V_NMI_ENABLE_MASK;
+	vmcb->control.int_vector = NMI_VECTOR;
+}
+
+static void vnmi_test(struct svm_test *test)
+{
+	report_svm_guest(!nmi_fired, test, "No vNMI before injection");
+	vmmcall();
+
+	report_svm_guest(nmi_fired, test, "vNMI delivered after injection");
+	vmmcall();
+}
+
+static bool vnmi_finished(struct svm_test *test)
+{
+	switch (get_test_stage(test)) {
+	case 0:
+		if (vmcb->control.exit_code != SVM_EXIT_ERR) {
+			report_fail("Wanted ERR VM-Exit, got 0x%x",
+				    vmcb->control.exit_code);
+			return true;
+		}
+		report(!nmi_fired, "vNMI enabled but NMI_INTERCEPT unset!");
+		vmcb->control.intercept |= (1ULL << INTERCEPT_NMI);
+		vmcb->save.rip += 3;
+		break;
+
+	case 1:
+		if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+			report_fail("Wanted VMMCALL VM-Exit, got 0x%x",
+				    vmcb->control.exit_code);
+			return true;
+		}
+		report(!nmi_fired, "vNMI with vector 2 not injected");
+		vmcb->control.int_ctl |= V_NMI_PENDING_MASK;
+		vmcb->save.rip += 3;
+		break;
+
+	case 2:
+		if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+			report_fail("Wanted VMMCALL VM-Exit, got 0x%x",
+				    vmcb->control.exit_code);
+			return true;
+		}
+		if (vmcb->control.int_ctl & V_NMI_BLOCKING_MASK) {
+			report_fail("V_NMI_BLOCKING_MASK not cleared on VMEXIT");
+			return true;
+		}
+		report_pass("VNMI serviced");
+		vmcb->save.rip += 3;
+		break;
+
+	default:
+		return true;
+	}
+
+	inc_test_stage(test);
+
+	return get_test_stage(test) == 3;
+}
+
+static bool vnmi_check(struct svm_test *test)
+{
+	return get_test_stage(test) == 3;
+}
+
 static volatile int count_exc = 0;
 
 static void my_isr(struct ex_regs *r)
@@ -3298,6 +3373,9 @@ struct svm_test svm_tests[] = {
 	{ "nmi_hlt", smp_supported, nmi_prepare,
 	  default_prepare_gif_clear, nmi_hlt_test,
 	  nmi_hlt_finished, nmi_hlt_check },
+        { "vnmi", vnmi_supported, vnmi_prepare,
+          default_prepare_gif_clear, vnmi_test,
+          vnmi_finished, vnmi_check },
 	{ "virq_inject", default_supported, virq_inject_prepare,
 	  default_prepare_gif_clear, virq_inject_test,
 	  virq_inject_finished, virq_inject_check },
-- 
2.40.0.348.gf938b09366-goog




[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