aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorCathy Avery <cavery@redhat.com>2020-04-09 09:32:46 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2020-04-09 09:49:54 -0400
commitd4db486be71938848165c699d07dfa216072ba25 (patch)
treedbe0e2fd75819a1b677a505fec3fa517fb6fe633
parentb16df9ee5f3b1f5246acbcc2c753e5433c98fe9b (diff)
downloadkvm-unit-tests-d4db486be71938848165c699d07dfa216072ba25.tar.gz
svm: Add test cases around NMI injection
This test checks for NMI delivery to L2 and intercepted NMI (VMEXIT_NMI) delivery to L1. Signed-off-by: Cathy Avery <cavery@redhat.com> Message-Id: <20200409133247.16653-2-cavery@redhat.com> Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
-rw-r--r--x86/svm_tests.c82
1 files changed, 82 insertions, 0 deletions
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 16b9dfd..b6c0106 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1340,6 +1340,85 @@ static bool interrupt_check(struct svm_test *test)
return get_test_stage(test) == 5;
}
+static volatile bool nmi_fired;
+
+static void nmi_handler(isr_regs_t *regs)
+{
+ nmi_fired = true;
+ apic_write(APIC_EOI, 0);
+}
+
+static void nmi_prepare(struct svm_test *test)
+{
+ default_prepare(test);
+ nmi_fired = false;
+ handle_irq(NMI_VECTOR, nmi_handler);
+ set_test_stage(test, 0);
+}
+
+static void nmi_test(struct svm_test *test)
+{
+ apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+
+ report(nmi_fired, "direct NMI while running guest");
+
+ if (!nmi_fired)
+ set_test_stage(test, -1);
+
+ vmmcall();
+
+ nmi_fired = false;
+
+ apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 0);
+
+ if (!nmi_fired) {
+ report(nmi_fired, "intercepted pending NMI not dispatched");
+ set_test_stage(test, -1);
+ }
+
+}
+
+static bool nmi_finished(struct svm_test *test)
+{
+ switch (get_test_stage(test)) {
+ case 0:
+ if (vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+ report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
+ vmcb->control.exit_code);
+ return true;
+ }
+ vmcb->save.rip += 3;
+
+ vmcb->control.intercept |= (1ULL << INTERCEPT_NMI);
+ break;
+
+ case 1:
+ if (vmcb->control.exit_code != SVM_EXIT_NMI) {
+ report(false, "VMEXIT not due to NMI intercept. Exit reason 0x%x",
+ vmcb->control.exit_code);
+ return true;
+ }
+
+ report(true, "NMI intercept while running guest");
+ break;
+
+ case 2:
+ break;
+
+ default:
+ return true;
+ }
+
+ inc_test_stage(test);
+
+ return get_test_stage(test) == 3;
+}
+
+static bool nmi_check(struct svm_test *test)
+{
+ return get_test_stage(test) == 3;
+}
+
#define TEST(name) { #name, .v2 = name }
/*
@@ -1446,6 +1525,9 @@ struct svm_test svm_tests[] = {
{ "interrupt", default_supported, interrupt_prepare,
default_prepare_gif_clear, interrupt_test,
interrupt_finished, interrupt_check },
+ { "nmi", default_supported, nmi_prepare,
+ default_prepare_gif_clear, nmi_test,
+ nmi_finished, nmi_check },
TEST(svm_guest_state_test),
{ NULL, NULL, NULL, NULL, NULL, NULL, NULL }
};