[PATCH kvm-unit-tests 2/2] apic: test nmi-after-sti

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

 



While not required by the spec, some guests (Linux)
rely on nmi being blocked by an IF-enabling sti.  Add
a unit test for this condition.

Signed-off-by: Avi Kivity <avi@xxxxxxxxxx>
---
 x86/apic.c |   67 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 files changed, 67 insertions(+), 0 deletions(-)

diff --git a/x86/apic.c b/x86/apic.c
index 165f820..2207040 100644
--- a/x86/apic.c
+++ b/x86/apic.c
@@ -1,6 +1,7 @@
 #include "libcflat.h"
 #include "apic.h"
 #include "vm.h"
+#include "smp.h"
 
 typedef struct {
     unsigned short offset0;
@@ -274,9 +275,74 @@ static void test_ioapic_simultaneous(void)
            g_66 && g_78 && g_66_after_78 && g_66_rip == g_78_rip);
 }
 
+volatile int nmi_counter_private, nmi_counter, nmi_hlt_counter, sti_loop_active;
+
+void sti_nop(char *p)
+{
+    asm volatile (
+		  ".globl post_sti \n\t"
+		  "sti \n"
+		  /*
+		   * vmx won't exit on external interrupt if blocked-by-sti,
+		   * so give it a reason to exit by accessing an unmapped page.
+		   */
+		  "post_sti: testb $0, %0 \n\t"
+		  "nop \n\t"
+		  "cli"
+		  : : "m"(*p)
+		  );
+    nmi_counter = nmi_counter_private;
+}
+
+static void sti_loop(void *ignore)
+{
+    unsigned k = 0;
+
+    while (sti_loop_active) {
+	sti_nop((char *)(ulong)((k++ * 4096) % (128 * 1024 * 1024)));
+    }
+}
+
+static void nmi_handler(isr_regs_t *regs)
+{
+    extern void post_sti(void);
+    ++nmi_counter_private;
+    nmi_hlt_counter += regs->rip == (ulong)post_sti;
+}
+
+static void update_cr3(void *cr3)
+{
+    write_cr3((ulong)cr3);
+}
+
+static void test_sti_nmi(void)
+{
+    unsigned old_counter;
+
+    if (cpu_count() < 2) {
+	return;
+    }
+
+    set_idt_entry(2, nmi_handler);
+    on_cpu(1, update_cr3, (void *)read_cr3());
+
+    sti_loop_active = 1;
+    on_cpu_async(1, sti_loop, 0);
+    while (nmi_counter < 30000) {
+	old_counter = nmi_counter;
+	apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI | APIC_INT_ASSERT, 1);
+	while (nmi_counter == old_counter) {
+	    ;
+	}
+    }
+    sti_loop_active = 0;
+    report("nmi-after-sti", nmi_hlt_counter == 0);
+}
+
 int main()
 {
     setup_vm();
+    smp_init();
 
     test_lapic_existence();
 
@@ -288,6 +354,7 @@ int main()
 
     test_ioapic_intr();
     test_ioapic_simultaneous();
+    test_sti_nmi();
 
     printf("\nsummary: %d tests, %d failures\n", g_tests, g_fail);
 
-- 
1.7.3.1

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[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