This patch test the issue fixed by KVM commit "KVM: nVMX: Fix loss of pending event before entering L2". The test aim to verify that a pending interrupt while interrupts are disabled is dispatched when we enter into VMX guest instead of being lost. The test configures VMCS to intercept external-interrupts and then queue an interrupt by disabling interrupts and issue a self-IPI. At this point, we enter guest and we expect CPU to immediately exit guest on external-interrupt. To complete the test, we then re-enable interrupts, verify interrupt is dispatched and re-enter guest to verify it completes execution. Reviewed-by: Nikita Leshchenko <nikita.leshchenko@xxxxxxxxxx> Reviewed-by: Darren Kenny <darren.kenny@xxxxxxxxxx> Signed-off-by: Liran Alon <liran.alon@xxxxxxxxxx> --- x86/unittests.cfg | 6 ++++++ x86/vmx_tests.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 54 insertions(+) diff --git a/x86/unittests.cfg b/x86/unittests.cfg index 9d3931921440..8d1c7db1cf6f 100644 --- a/x86/unittests.cfg +++ b/x86/unittests.cfg @@ -554,6 +554,12 @@ extra_params = -cpu host,+vmx -m 2560 -append vmx_cr_load_test arch = x86_64 groups = vmx +[vmx_pending_event_test] +file = vmx.flat +extra_params = -cpu host,+vmx -m 2560 -append vmx_pending_event_test +arch = x86_64 +groups = vmx + [vmx_eoi_bitmap_ioapic_scan] file = vmx.flat smp = 2 diff --git a/x86/vmx_tests.c b/x86/vmx_tests.c index 7a41732d058a..21b474db012b 100644 --- a/x86/vmx_tests.c +++ b/x86/vmx_tests.c @@ -4457,6 +4457,53 @@ static void vmx_cr_load_test(void) TEST_ASSERT(!write_cr4_checking(cr4 & ~X86_CR4_PCIDE)); } +bool vmx_pending_event_ipi_fired; +static void vmx_pending_event_ipi_isr(isr_regs_t *regs) +{ + vmx_pending_event_ipi_fired = true; + eoi(); +} + +bool vmx_pending_event_guest_run; +static void vmx_pending_event_guest(void) +{ + vmx_pending_event_guest_run = true; +} + +static void vmx_pending_event_test(void) +{ + int ipi_vector = 0xf1; + + vmx_pending_event_ipi_fired = false; + handle_irq(ipi_vector, vmx_pending_event_ipi_isr); + + vmx_pending_event_guest_run = false; + test_set_guest(vmx_pending_event_guest); + + vmcs_set_bits(PIN_CONTROLS, PIN_EXTINT); + + irq_disable(); + apic_icr_write(APIC_DEST_SELF | APIC_DEST_PHYSICAL | + APIC_DM_FIXED | ipi_vector, + 0); + + enter_guest(); + + assert_exit_reason(VMX_EXTINT); + report("Guest did not run before host received IPI", + !vmx_pending_event_guest_run); + + irq_enable(); + asm volatile ("nop"); + irq_disable(); + report("Got pending interrupt after IRQ enabled", + vmx_pending_event_ipi_fired); + + enter_guest(); + report("Guest finished running when no interrupt", + vmx_pending_event_guest_run); +} + static bool cpu_has_apicv(void) { return ((ctrl_cpu_rev[1].clr & CPU_APIC_REG_VIRT) && @@ -5016,6 +5063,7 @@ struct vmx_test vmx_tests[] = { TEST(vmx_vmcs_shadow_test), /* Regression tests */ TEST(vmx_cr_load_test), + TEST(vmx_pending_event_test), /* EPT access tests. */ TEST(ept_access_test_not_present), TEST(ept_access_test_read_only), -- 2.16.1