Kernel KVM virtualization development
 help / color / mirror / Atom feed
* [kvm-unit-tests PATCH] x86/pmu: Add option to raise NMI on overflow
@ 2026-08-10 10:10 Sandipan Das
  2026-09-30 21:07 ` Sean Christopherson
  0 siblings, 1 reply; 2+ messages in thread
From: Sandipan Das @ 2026-08-10 10:10 UTC (permalink / raw)
  To: kvm
  Cc: Sean Christopherson, Paolo Bonzini, Dapeng Mi, Zide Chen,
	Nikunj A . Dadhania, Manali Shukla, Sandipan Das

Interrupts raised on counter overflow are currently delivered through
the PMI_VECTOR as regular maskable interrupts. However, for some
configurations, like SVM with PMC virtualization and VNMI enabled, the
guest LVTPC is ignored and the interrupts are always delivered as NMIs.
This causes the test to crash, as seen below, because it does not
expect NMIs.

  Unhandled exception 2 #NMI(0) at ip 0000000000400326
  error_code=0000      rflags=00000056      cs=00000008
  rax=00000000001300c0 rcx=00000000c0010202 rdx=0000000000000000 rbx=0000000001019f58
  rbp=0000000001019ee0 rsi=00000000000f4240 rdi=0000000001019f58
   r8=ffffffffffffe000  r9=00000000000003f8 r10=000000000000000d r11=0000000000000020
  r12=00000000001300c0 r13=ffffffffff6768f0 r14=ffffffffff6768f0 r15=0000000000000001
  cr0=0000000080010011 cr2=0000000000000000 cr3=00000000010fe000 cr4=0000000000000020
  cr8=0000000000000000
          STACK: @400326 400de1 401715 401e51 4001bd

Add an optional "nmi" argument to improve test coverage for such
configurations. When passed, the LVTPC has the delivery mode changed to
NMI (APIC_DM_NMI) and the overflow handler is installed on the
NMI_VECTOR. Otherwise, it keeps using the maskable PMI_VECTOR.

Unlike maskable interrupts, which stay pending until EFLAGS.IF is set,
an NMI is not gated by it and arrives as soon as the counter overflows.
Clearing the interrupt count after the counter has overflowed therefore
misses the early-arriving NMIs. Hence, reset it before arming the
counter so that overflows are counted regardless of the delivery mode.
The downside is that all future users of check_irq() will have to
maintain this ordering.

Signed-off-by: Sandipan Das <sandipan.das@amd.com>
---
 x86/pmu.c | 39 +++++++++++++++++++++++++++++++--------
 1 file changed, 31 insertions(+), 8 deletions(-)

diff --git a/x86/pmu.c b/x86/pmu.c
index ea31a7a3..236c39b9 100644
--- a/x86/pmu.c
+++ b/x86/pmu.c
@@ -250,23 +250,27 @@ static void adjust_events_range(struct pmu_event *gp_events,
 		gp_events[branch_miss_idx].min = 0;
 }
 
+static bool nmi = false;
+static u32 lvtpc = PMI_VECTOR;
 volatile uint64_t irq_received;
 
 static void cnt_overflow(isr_regs_t *regs)
 {
 	irq_received++;
 	apic_write(APIC_LVTPC, apic_read(APIC_LVTPC) & ~APIC_LVT_MASKED);
-	apic_write(APIC_EOI, 0);
+	if (!nmi)
+		apic_write(APIC_EOI, 0);
 }
 
 static bool check_irq(void)
 {
 	int i;
-	irq_received = 0;
-	sti();
+	if (!nmi)
+		sti();
 	for (i = 0; i < 100000 && !irq_received; i++)
 		asm volatile("pause");
-	cli();
+	if (!nmi)
+		cli();
 	return irq_received;
 }
 
@@ -347,7 +351,7 @@ static void __start_event(pmu_counter_t *evt, uint64_t count)
 	    ctrl = (ctrl & ~(0xf << shift)) | (usrospmi << shift);
 	    wrmsr(MSR_CORE_PERF_FIXED_CTR_CTRL, ctrl);
     }
-    apic_write(APIC_LVTPC, PMI_VECTOR);
+    apic_write(APIC_LVTPC, lvtpc);
 }
 
 static void start_event(pmu_counter_t *evt)
@@ -582,6 +586,7 @@ static void check_counter_overflow(void)
 		else
 			cnt.config &= ~EVNTSEL_INT;
 		idx = event_to_global_idx(&cnt);
+		irq_received = 0;
 		__measure(&cnt, cnt.count);
 		if (pmu.is_intel) {
 			if (pmu.errata.instructions_retired_overcount)
@@ -984,14 +989,32 @@ static void check_invalid_rdpmc_gp(void)
 	       "Expected #GP on RDPMC(64)");
 }
 
-int main(int ac, char **av)
+int main(int argc, char **argv)
 {
 	int instruction_idx;
 	int branch_idx;
 	int branch_miss_idx;
+	int i;
+
+	argv++;
+	argc--;
 
 	setup_vm();
-	handle_irq(PMI_VECTOR, cnt_overflow);
+
+	for (i = 0; i < argc; i++) {
+		if (!strcmp(argv[i], "nmi")) {
+			nmi = true;
+			break;
+		}
+	}
+
+	if (nmi) {
+		lvtpc = NMI_VECTOR | APIC_DM_NMI;
+		handle_irq(NMI_VECTOR, cnt_overflow);
+	} else {
+		handle_irq(PMI_VECTOR, cnt_overflow);
+	}
+
 	buf = malloc(N*64);
 
 	if (this_cpu_has_perf_global_ctrl())
@@ -1044,7 +1067,7 @@ int main(int ac, char **av)
 			    "Please update test case.", pmu.nr_fixed_counters,
 			    (unsigned)ARRAY_SIZE(fixed_events));
 
-	apic_write(APIC_LVTPC, PMI_VECTOR);
+	apic_write(APIC_LVTPC, lvtpc);
 
 	check_counters();
 
-- 
2.53.0


^ permalink raw reply related	[flat|nested] 2+ messages in thread

end of thread, other threads:[~2026-09-30 21:07 UTC | newest]

Thread overview: 2+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-08-10 10:10 [kvm-unit-tests PATCH] x86/pmu: Add option to raise NMI on overflow Sandipan Das
2026-09-30 21:07 ` Sean Christopherson

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox