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@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)
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 }
};