Cover VMRUN's testing whether EVENTINJ.TYPE = 3 (exception) has been specified with a vector that does not correspond to an exception. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/svm.h | 7 +++++ x86/svm_tests.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+) diff --git a/x86/svm.h b/x86/svm.h index 645deb7..bb5c552 100644 --- a/x86/svm.h +++ b/x86/svm.h @@ -324,6 +324,13 @@ struct __attribute__ ((__packed__)) vmcb { #define SVM_CR0_SELECTIVE_MASK (X86_CR0_TS | X86_CR0_MP) +#define SVM_EVENT_INJ_HWINT (0 << 8) +#define SVM_EVENT_INJ_NMI (2 << 8) +#define SVM_EVENT_INJ_EXC (3 << 8) +#define SVM_EVENT_INJ_SWINT (4 << 8) +#define SVM_EVENT_INJ_ERRCODE (1 << 11) +#define SVM_EVENT_INJ_VALID (1 << 31) + #define MSR_BITMAP_SIZE 8192 struct svm_test { diff --git a/x86/svm_tests.c b/x86/svm_tests.c index 16b9dfd..6292e68 100644 --- a/x86/svm_tests.c +++ b/x86/svm_tests.c @@ -1340,6 +1340,73 @@ static bool interrupt_check(struct svm_test *test) return get_test_stage(test) == 5; } +static volatile int count_exc = 0; + +static void my_isr(struct ex_regs *r) +{ + count_exc++; +} + +static void exc_inject_prepare(struct svm_test *test) +{ + handle_exception(DE_VECTOR, my_isr); + handle_exception(NMI_VECTOR, my_isr); +} + + +static void exc_inject_test(struct svm_test *test) +{ + asm volatile ("vmmcall\n\tvmmcall\n\t"); +} + +static bool exc_inject_finished(struct svm_test *test) +{ + vmcb->save.rip += 3; + + 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->control.event_inj = NMI_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID; + break; + + case 1: + if (vmcb->control.exit_code != SVM_EXIT_ERR) { + report(false, "VMEXIT not due to error. Exit reason 0x%x", + vmcb->control.exit_code); + return true; + } + report(count_exc == 0, "exception with vector 2 not injected"); + vmcb->control.event_inj = DE_VECTOR | SVM_EVENT_INJ_EXC | SVM_EVENT_INJ_VALID; + break; + + case 2: + 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; + } + report(count_exc == 1, "divide overflow exception injected"); + report(!(vmcb->control.event_inj & SVM_EVENT_INJ_VALID), "eventinj.VALID cleared"); + break; + + default: + return true; + } + + inc_test_stage(test); + + return get_test_stage(test) == 3; +} + +static bool exc_inject_check(struct svm_test *test) +{ + return count_exc == 1 && get_test_stage(test) == 3; +} + #define TEST(name) { #name, .v2 = name } /* @@ -1446,6 +1513,9 @@ struct svm_test svm_tests[] = { { "interrupt", default_supported, interrupt_prepare, default_prepare_gif_clear, interrupt_test, interrupt_finished, interrupt_check }, + { "exc_inject", default_supported, exc_inject_prepare, + default_prepare_gif_clear, exc_inject_test, + exc_inject_finished, exc_inject_check }, TEST(svm_guest_state_test), { NULL, NULL, NULL, NULL, NULL, NULL, NULL } }; -- 2.18.2