[PATCH kvm-unit-tests 2/2] svm: Add test cases around interrupt injection and halting

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



From: Cathy Avery <cavery@xxxxxxxxxx>

This test checks for interrupt delivery to L2 and
unintercepted hlt in L2. All tests are performed
both with direct interrupt injection and external
interrupt interception.

Based on VMX test by Jan Kiszka <jan.kiszka@xxxxxxxxxxx>

Signed-off-by: Cathy Avery <cavery@xxxxxxxxxx>
Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx>
---
 x86/svm.c | 141 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 141 insertions(+)

diff --git a/x86/svm.c b/x86/svm.c
index f300c8a..df7a7c4 100644
--- a/x86/svm.c
+++ b/x86/svm.c
@@ -1502,6 +1502,144 @@ static bool pending_event_cli_check(struct test *test)
     return get_test_stage(test) == 2;
 }
 
+#define TIMER_VECTOR    222
+
+static volatile bool timer_fired;
+
+static void timer_isr(isr_regs_t *regs)
+{
+    timer_fired = true;
+    apic_write(APIC_EOI, 0);
+}
+
+static void interrupt_prepare(struct test *test)
+{
+    default_prepare(test);
+    handle_irq(TIMER_VECTOR, timer_isr);
+    timer_fired = false;
+    set_test_stage(test, 0);
+}
+
+static void interrupt_test(struct test *test)
+{
+    long long start, loops;
+
+    apic_write(APIC_LVTT, TIMER_VECTOR);
+    irq_enable();
+    apic_write(APIC_TMICT, 1); //Timer Initial Count Register 0x380 one-shot
+    for (loops = 0; loops < 10000000 && !timer_fired; loops++)
+        asm volatile ("nop");
+
+    report(timer_fired, "direct interrupt while running guest");
+
+    if (!timer_fired) {
+        set_test_stage(test, -1);
+        vmmcall();
+    }
+
+    apic_write(APIC_TMICT, 0);
+    irq_disable();
+    vmmcall();
+
+    timer_fired = false;
+    apic_write(APIC_TMICT, 1);
+    for (loops = 0; loops < 10000000 && !timer_fired; loops++)
+        asm volatile ("nop");
+
+    report(timer_fired, "intercepted interrupt while running guest");
+
+    if (!timer_fired) {
+        set_test_stage(test, -1);
+        vmmcall();
+    }
+
+    irq_enable();
+    apic_write(APIC_TMICT, 0);
+    irq_disable();
+
+    timer_fired = false;
+    start = rdtsc();
+    apic_write(APIC_TMICT, 1000000);
+    asm volatile ("sti; hlt");
+
+    report(rdtsc() - start > 10000 && timer_fired,
+          "direct interrupt + hlt");
+
+    if (!timer_fired) {
+        set_test_stage(test, -1);
+        vmmcall();
+    }
+
+    apic_write(APIC_TMICT, 0);
+    irq_disable();
+    vmmcall();
+
+    timer_fired = false;
+    start = rdtsc();
+    apic_write(APIC_TMICT, 1000000);
+    asm volatile ("hlt");
+
+    report(rdtsc() - start > 10000 && timer_fired,
+           "intercepted interrupt + hlt");
+
+    if (!timer_fired) {
+        set_test_stage(test, -1);
+        vmmcall();
+    }
+
+    apic_write(APIC_TMICT, 0);
+    irq_disable();
+}
+
+static bool interrupt_finished(struct test *test)
+{
+    switch (get_test_stage(test)) {
+    case 0:
+    case 2:
+        if (test->vmcb->control.exit_code != SVM_EXIT_VMMCALL) {
+            report(false, "VMEXIT not due to vmmcall. Exit reason 0x%x",
+                   test->vmcb->control.exit_code);
+            return true;
+        }
+        test->vmcb->save.rip += 3;
+
+        test->vmcb->control.intercept |= (1ULL << INTERCEPT_INTR);
+        test->vmcb->control.int_ctl |= V_INTR_MASKING_MASK;
+        break;
+
+    case 1:
+    case 3:
+        if (test->vmcb->control.exit_code != SVM_EXIT_INTR) {
+            report(false, "VMEXIT not due to intr intercept. Exit reason 0x%x",
+                   test->vmcb->control.exit_code);
+            return true;
+        }
+
+        irq_enable();
+        asm volatile ("nop");
+        irq_disable();
+
+        test->vmcb->control.intercept &= ~(1ULL << INTERCEPT_INTR);
+        test->vmcb->control.int_ctl &= ~V_INTR_MASKING_MASK;
+        break;
+
+    case 4:
+        break;
+
+    default:
+        return true;
+    }
+
+    inc_test_stage(test);
+
+    return get_test_stage(test) == 5;
+}
+
+static bool interrupt_check(struct test *test)
+{
+    return get_test_stage(test) == 5;
+}
+
 static struct test tests[] = {
     { "null", default_supported, default_prepare,
       default_prepare_gif_clear, null_test,
@@ -1582,6 +1720,9 @@ static struct test tests[] = {
       pending_event_cli_prepare_gif_clear,
       pending_event_cli_test, pending_event_cli_finished,
       pending_event_cli_check },
+    { "interrupt", default_supported, interrupt_prepare,
+      default_prepare_gif_clear, interrupt_test,
+      interrupt_finished, interrupt_check },
 };
 
 int matched;
-- 
1.8.3.1




[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]

  Powered by Linux