diff mbox series

[kvm-unit-tests] x86: APIC: Add test for pending NMIs while NMIs are blocked

Message ID 20190424222032.26437-1-sean.j.christopherson@intel.com (mailing list archive)
State New, archived
Headers show
Series [kvm-unit-tests] x86: APIC: Add test for pending NMIs while NMIs are blocked | expand

Commit Message

Sean Christopherson April 24, 2019, 10:20 p.m. UTC
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@gmail.com>
Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
---
 x86/apic.c | 29 +++++++++++++++++++++++++++++
 1 file changed, 29 insertions(+)

Comments

Paolo Bonzini April 30, 2019, 7:13 p.m. UTC | #1
On 25/04/19 00:20, Sean Christopherson wrote:
> 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@gmail.com>
> Signed-off-by: Sean Christopherson <sean.j.christopherson@intel.com>
> ---
>  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();
> 

Queued, thanks.

Paolo
diff mbox series

Patch

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();