Message ID | 20200409094303.949992-1-pbonzini@redhat.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | [kvm-unit-tests] svm: add a test for exception injection | expand |
On 4/9/20 2:43 AM, Paolo Bonzini wrote: > 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@redhat.com> > --- > 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) I see existing #defines in svm.h: #define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) #define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) #define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) #define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) #define SVM_EVTINJ_VALID (1 << 31) #define SVM_EVTINJ_VALID_ERR (1 << 11) > + > #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 } > };
On 11/04/20 02:24, Krish Sadhukhan wrote: > > On 4/9/20 2:43 AM, Paolo Bonzini wrote: >> 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@redhat.com> >> --- >> 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) > > > I see existing #defines in svm.h: > > #define SVM_EVTINJ_TYPE_INTR (0 << SVM_EVTINJ_TYPE_SHIFT) > #define SVM_EVTINJ_TYPE_NMI (2 << SVM_EVTINJ_TYPE_SHIFT) > #define SVM_EVTINJ_TYPE_EXEPT (3 << SVM_EVTINJ_TYPE_SHIFT) > #define SVM_EVTINJ_TYPE_SOFT (4 << SVM_EVTINJ_TYPE_SHIFT) > #define SVM_EVTINJ_VALID (1 << 31) > #define SVM_EVTINJ_VALID_ERR (1 << 11) Indeed. I queued the patch with these defines instead. Paolo >> + >> #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 } >> }; >
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 } };
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@redhat.com> --- x86/svm.h | 7 +++++ x86/svm_tests.c | 70 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 77 insertions(+)