Though explicit documentation is difficult to unearth, x86 guarantees that exactly one NMI will be pended when NMIs are blocked. The SDM essentially calls this out in its section on handling NMIs in SMM: NMI interrupts are blocked upon entry to the SMI handler. If an NMI request occurs during the SMI handler, it is latched and serviced after the processor exits SMM. Only one NMI request will be latched during the SMI handler. Add a test to send multiple NMIs from within an NMI handler to verify that KVM correctly pends exactly *one* NMI when NMIs are blocked. Cc: Nadav Amit <nadav.amit@xxxxxxxxx> Signed-off-by: Sean Christopherson <sean.j.christopherson@xxxxxxxxx> --- x86/apic.c | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/x86/apic.c b/x86/apic.c index 51744cf..9b78288 100644 --- a/x86/apic.c +++ b/x86/apic.c @@ -403,6 +403,34 @@ static void test_multiple_nmi(void) report("multiple nmi", ok); } +static void pending_nmi_handler(isr_regs_t *regs) +{ + int i; + + if (++nmi_received == 1) { + for (i = 0; i < 10; ++i) + apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0); + } +} + +static void test_pending_nmi(void) +{ + int i; + + handle_irq(2, pending_nmi_handler); + for (i = 0; i < 100000; ++i) { + nmi_received = 0; + + apic_icr_write(APIC_DEST_PHYSICAL | APIC_DM_NMI, 0); + while (nmi_received < 2) + pause(); + + if (nmi_received != 2) + break; + } + report("pending nmi", nmi_received == 2); +} + static volatile int lvtt_counter = 0; static void lvtt_handler(isr_regs_t *regs) @@ -615,6 +643,7 @@ int main(void) test_sti_nmi(); test_multiple_nmi(); + test_pending_nmi(); test_apic_timer_one_shot(); test_apic_change_mode(); -- 2.21.0