Add a generic speed test for SMIs and a testcase for https://github.com/tianocore/edk2/issues/91. Signed-off-by: Paolo Bonzini <pbonzini@xxxxxxxxxx> --- x86/Makefile.common | 1 + x86/smm_eventinj.c | 83 +++++++++++++++++++++++++++++++++++++++++++++++++++++ x86/unittests.cfg | 4 +++ x86/vmexit.c | 6 ++++ 4 files changed, 94 insertions(+) create mode 100644 x86/smm_eventinj.c diff --git a/x86/Makefile.common b/x86/Makefile.common index 55e6cde..a04f14a 100644 --- a/x86/Makefile.common +++ b/x86/Makefile.common @@ -45,6 +45,7 @@ tests-common = $(TEST_DIR)/vmexit.flat $(TEST_DIR)/tsc.flat \ $(TEST_DIR)/tsc_adjust.flat $(TEST_DIR)/asyncpf.flat \ $(TEST_DIR)/init.flat $(TEST_DIR)/smap.flat \ $(TEST_DIR)/hyperv_synic.flat $(TEST_DIR)/hyperv_stimer.flat \ + $(TEST_DIR)/smm_eventinj.flat ifdef API tests-common += api/api-sample diff --git a/x86/smm_eventinj.c b/x86/smm_eventinj.c new file mode 100644 index 0000000..1029289 --- /dev/null +++ b/x86/smm_eventinj.c @@ -0,0 +1,83 @@ +#include "libcflat.h" +#include "smp.h" +#include "processor.h" +#include "x86/desc.h" +#include "x86/apic.h" +#include "x86/io.h" + +/* Provoke race between interrupt injection and SMM entry, causing a + * failed vmentry because IF=0 but VM_ENTRY_INTR_INFO_FIELD[31]=1. + */ + +#define MY_IRQ_PIN 0x0e +#define MY_IRQ_VEC 0x21 + +static volatile int stopped; + +static void set_irq_line(unsigned line, int val) +{ + outb(val, 0x2000 + line); +} + +static void set_ioapic_redir(unsigned line, unsigned vec) +{ + /* Edge triggered, CPU 0 */ + ioapic_redir_entry_t e = { + .vector = vec, + }; + + ioapic_write_redir(line, e); +} + +static void ipi(void *x) +{ + while (!stopped) { + int i = 0; + for (i = 0; i < 1000000; i++) asm("pause"); + + set_irq_line(MY_IRQ_PIN, 1); + apic_icr_write(APIC_DM_SMI|APIC_INT_ASSERT, 0); + set_irq_line(MY_IRQ_PIN, 0); + } +} + +extern void dummy(void); +asm("dummy: \n" + "call eoi\n" +#ifndef __x86_64__ + "iret" +#else + "iretq" +#endif + ); + +int main(int ac, char **av) +{ + int i; + + smp_init(); + mask_pic_interrupts(); + + set_ioapic_redir(MY_IRQ_PIN, MY_IRQ_VEC); + set_idt_entry(MY_IRQ_VEC, dummy, 0); + if (cpu_count() < 2) { + printf("SMP needed for this test\n"); + exit(1); + } + + /* Because we use the APIC to inject SMIs, ensure SeaBIOS doesn't find + * a valid "SMM command" in port 0xb2. If it does, it peeks at the + * registers to get the other parameters, and who knows what happens + * then. + */ + outb(42, 0xb2); + + printf("starting IPI thread\n"); + on_cpu_async(1, ipi, 0); + printf("starting HLT loop\n"); + asm("sti"); + for (i = 0; i < 150; i++) + asm("hlt"); + stopped = 1; + return 0; +} diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 61a4d24..6ba11fb 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -188,6 +188,10 @@ arch = x86_64 file = debug.flat arch = x86_64 +[smm_eventinj] +file = smm_eventinj.flat +smp = 2 + [hyperv_synic] file = hyperv_synic.flat smp = 2 diff --git a/x86/vmexit.c b/x86/vmexit.c index 9e04975..f21d054 100644 --- a/x86/vmexit.c +++ b/x86/vmexit.c @@ -134,6 +134,11 @@ static void wr_tsc_adjust_msr(void) wrmsr(MSR_TSC_ADJUST, 0x0); } +static void smi_outb(void) +{ + outb(42, 0xb2); +} + static struct pci_test { unsigned iobar; unsigned ioport; @@ -287,6 +292,7 @@ static struct test tests[] = { { ple_round_robin, "ple-round-robin", .parallel = 1 }, { wr_tsc_adjust_msr, "wr_tsc_adjust_msr", .parallel = 1 }, { rd_tsc_adjust_msr, "rd_tsc_adjust_msr", .parallel = 1 }, + { smi_outb, "smi_outb", .parallel = 0 }, { NULL, "pci-mem", .parallel = 0, .next = pci_mem_next }, { NULL, "pci-io", .parallel = 0, .next = pci_io_next }, }; -- 1.8.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