svm: Add test cases around NMI injection
PATCH v2 1/2 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 <[email protected]>
---
v2: Remove redundant NMI_VECTOR
--- x86/svm_tests.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)
x86/svm_tests.c +82 -0
@@ -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 } };
Signature · 1 line
2.20.1
Quoted 102 lines · Cathy Avery
This test checks for NMI delivery to L2 and
intercepted NMI (VMEXIT_NMI) delivery to L1.Signed-off-by Cathy Avery <[email protected]>---
v2: Remove redundantNMI_VECTOR--- x86/svm_tests.c | 82 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 82 insertions(+)x86/svm_tests.c +79
-0@@ -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 }/*
x86/svm_tests.c struct svm_test svm_tests[] = { · line 1533
Quoted 9 lines
x86/svm_tests.c +3
-0@@ -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 } };
Queued (both), thanks.
Paolo