All of lore.kernel.org
 help / color / mirror / Atom feed
From: Maxim Levitsky <mlevitsk@redhat.com>
To: kvm@vger.kernel.org
Cc: Maxim Levitsky <mlevitsk@redhat.com>
Subject: [PATCH] SVM: add two tests for exitintinto on exception
Date: Thu, 25 Feb 2021 18:10:12 +0200	[thread overview]
Message-ID: <20210225161012.408860-1-mlevitsk@redhat.com> (raw)

Test that exitintinfo is set correctly when
exception happens during exception/interrupt delivery
and that exception is intercepted.

Note that those tests currently fail, due to few bugs in KVM.

Also note that those bugs are in KVM's common x86 code,
thus the issue exists on VMX as well and unit tests
that reproduce those on VMX will be written as well.

Signed-off-by: Maxim Levitsky <mlevitsk@redhat.com>
---
 x86/svm_tests.c | 162 +++++++++++++++++++++++++++++++++++++++++++++++-
 1 file changed, 160 insertions(+), 2 deletions(-)

diff --git a/x86/svm_tests.c b/x86/svm_tests.c
index 29a0b59..c14129a 100644
--- a/x86/svm_tests.c
+++ b/x86/svm_tests.c
@@ -1886,7 +1886,7 @@ static bool reg_corruption_finished(struct svm_test *test)
                "No RIP corruption detected after %d timer interrupts",
                isr_cnt);
         set_test_stage(test, 1);
-        return true;
+        goto finished;
     }
 
     if (vmcb->control.exit_code == SVM_EXIT_INTR) {
@@ -1901,11 +1901,14 @@ static bool reg_corruption_finished(struct svm_test *test)
             report(false,
                    "RIP corruption detected after %d timer interrupts",
                    isr_cnt);
-            return true;
+            goto finished;
         }
 
     }
     return false;
+finished:
+    apic_write(APIC_LVTT, APIC_LVT_TIMER_MASK);
+    return true;
 }
 
 static bool reg_corruption_check(struct svm_test *test)
@@ -2382,6 +2385,155 @@ static void svm_vmrun_errata_test(void)
     }
 }
 
+
+/*
+ * Test that nested exceptions are delivered correctly
+ * when parent exception is intercepted
+ */
+
+static void exception_merging_prepare(struct svm_test *test)
+{
+    default_prepare(test);
+    set_test_stage(test, 0);
+
+    vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR);
+
+    /* break UD vector idt entry to get #GP*/
+    boot_idt[UD_VECTOR].type = 1;
+}
+
+static void exception_merging_test(struct svm_test *test)
+{
+    asm volatile (
+        "ud2\n\t" :
+        /* no outputs*/ :
+        /* no inputs*/ :
+        /* no clobbers*/
+    );
+}
+
+static bool exception_merging_finished(struct svm_test *test)
+{
+    u32 vec = vmcb->control.exit_int_info & SVM_EXITINTINFO_VEC_MASK;
+    u32 type = vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
+
+    if (vmcb->control.exit_code != SVM_EXIT_EXCP_BASE + GP_VECTOR) {
+        report(false, "unexpected VM exit");
+        goto out;
+    }
+
+    if (! (vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID)) {
+        report(false, "EXITINTINFO not valid");
+        goto out;
+    }
+
+    if (type != SVM_EXITINTINFO_TYPE_EXEPT) {
+        report(false, "Incorrect event type in EXITINTINFO");
+        goto out;
+    }
+
+    if (vec != UD_VECTOR) {
+        report(false, "Incorrect vector in EXITINTINFO");
+        goto out;
+    }
+
+    set_test_stage(test, 1);
+out:
+    boot_idt[UD_VECTOR].type = 14;
+    return true;
+}
+
+static bool exception_merging_check(struct svm_test *test)
+{
+    return get_test_stage(test) == 1;
+}
+
+
+/*
+ * Test that if exception is raised during interrupt delivery,
+ * and that exception is intercepted, the interrupt is preserved
+ * in EXITINTINFO of the exception
+ */
+
+static void interrupt_merging_prepare(struct svm_test *test)
+{
+    default_prepare(test);
+    set_test_stage(test, 0);
+
+    /* intercept #GP */
+    vmcb->control.intercept_exceptions |= (1ULL << GP_VECTOR);
+
+    /* set local APIC to inject external interrupts */
+    apic_write(APIC_TMICT, 0);
+    apic_write(APIC_TDCR, 0);
+    apic_write(APIC_LVTT, TIMER_VECTOR | APIC_LVT_TIMER_PERIODIC);
+    apic_write(APIC_TMICT, 1000);
+}
+
+static void interrupt_merging_test(struct svm_test *test)
+{
+    /* break timer vector IDT entry to get #GP on interrupt delivery */
+    boot_idt[TIMER_VECTOR].type = 1;
+
+    irq_enable();
+
+    /* just wait forever */
+    for(;;);
+}
+
+static bool interrupt_merging_finished(struct svm_test *test)
+{
+    u32 vec = vmcb->control.exit_int_info & SVM_EXITINTINFO_VEC_MASK;
+    u32 type = vmcb->control.exit_int_info & SVM_EXITINTINFO_TYPE_MASK;
+    u32 error_code = vmcb->control.exit_info_1;
+
+    /* exit on external interrupts is disabled, thus timer interrupt
+     * should be attempted to be delivered, but due to incorrect IDT entry
+     * an #GP should be raised
+     */
+    if (vmcb->control.exit_code != SVM_EXIT_EXCP_BASE + GP_VECTOR) {
+        report(false, "unexpected VM exit");
+        goto out;
+    }
+
+    /* GP error code should be about an IDT entry, and due to external event */
+    if (error_code != (TIMER_VECTOR << 3 | 3)) {
+        report(false, "Incorrect error code of the GP exception");
+        goto out;
+    }
+
+    /* Original interrupt should be preserved in EXITINTINFO */
+    if (! (vmcb->control.exit_int_info & SVM_EXITINTINFO_VALID)) {
+        report(false, "EXITINTINFO not valid");
+        goto out;
+    }
+
+    if (type != SVM_EXITINTINFO_TYPE_INTR) {
+        report(false, "Incorrect event type in EXITINTINFO");
+        goto out;
+    }
+
+    if (vec != TIMER_VECTOR) {
+        report(false, "Incorrect vector in EXITINTINFO");
+        goto out;
+    }
+
+    set_test_stage(test, 1);
+out:
+    boot_idt[TIMER_VECTOR].type = 14;
+    apic_write(APIC_LVTT, APIC_LVT_TIMER_MASK);
+    return true;
+
+}
+
+static bool interrupt_merging_check(struct svm_test *test)
+{
+    return get_test_stage(test) == 1;
+}
+
+////////////////////////////////////////////////
+
+
 struct svm_test svm_tests[] = {
     { "null", default_supported, default_prepare,
       default_prepare_gif_clear, null_test,
@@ -2492,6 +2644,12 @@ struct svm_test svm_tests[] = {
     { "svm_init_intercept_test", smp_supported, init_intercept_prepare,
       default_prepare_gif_clear, init_intercept_test,
       init_intercept_finished, init_intercept_check, .on_vcpu = 2 },
+    { "exception_merging", default_supported, exception_merging_prepare,
+      default_prepare_gif_clear, exception_merging_test,
+      exception_merging_finished, exception_merging_check },
+    { "interrupt_merging", default_supported, interrupt_merging_prepare,
+      default_prepare_gif_clear, interrupt_merging_test,
+      interrupt_merging_finished, interrupt_merging_check },
     TEST(svm_cr4_osxsave_test),
     TEST(svm_guest_state_test),
     TEST(svm_vmrun_errata_test),
-- 
2.26.2


                 reply	other threads:[~2021-02-25 16:13 UTC|newest]

Thread overview: [no followups] expand[flat|nested]  mbox.gz  Atom feed

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20210225161012.408860-1-mlevitsk@redhat.com \
    --to=mlevitsk@redhat.com \
    --cc=kvm@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.