aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPaolo Bonzini <pbonzini@redhat.com>2020-04-09 05:42:52 -0400
committerPaolo Bonzini <pbonzini@redhat.com>2020-04-15 10:56:00 -0400
commit4b4fb247215957fe57a9ebd04bc4e73e1d0ade33 (patch)
tree983ff3e54ef6db4bd62efdc47b0e69e670e6c5e0
parent9da1f4d89d16a6049f7f2ac941c1101f2a34a5b9 (diff)
downloadkvm-unit-tests-4b4fb247215957fe57a9ebd04bc4e73e1d0ade33.tar.gz
svm: add a test for exception injection
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>
-rw-r--r--x86/svm_tests.c70
1 files changed, 70 insertions, 0 deletions
diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 2ec7275..b4ba999 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1519,6 +1519,73 @@ static bool nmi_hlt_check(struct svm_test *test)
return get_test_stage(test) == 3;
}
+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_EVTINJ_TYPE_EXEPT | SVM_EVTINJ_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_EVTINJ_TYPE_EXEPT | SVM_EVTINJ_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_EVTINJ_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 }
/*
@@ -1615,6 +1682,9 @@ struct svm_test svm_tests[] = {
{ "latency_svm_insn", default_supported, lat_svm_insn_prepare,
default_prepare_gif_clear, null_test,
lat_svm_insn_finished, lat_svm_insn_check },
+ { "exc_inject", default_supported, exc_inject_prepare,
+ default_prepare_gif_clear, exc_inject_test,
+ exc_inject_finished, exc_inject_check },
{ "pending_event", default_supported, pending_event_prepare,
default_prepare_gif_clear,
pending_event_test, pending_event_finished, pending_event_check },