Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 33c6d6a7 authored by Don Zickus's avatar Don Zickus Committed by Ingo Molnar
Browse files

x86, perf, nmi: Disable perf if counters are not accessible



In a kvm virt guests, the perf counters are not emulated.  Instead they
return zero on a rdmsrl. The perf nmi handler uses the fact that crossing
a zero means the counter overflowed (for those counters that do not have
specific interrupt bits). Therefore on kvm guests, perf will swallow all
NMIs thinking the counters overflowed.

This causes problems for subsystems like kgdb which needs NMIs to do its
magic. This problem was discovered by running kgdb tests.

The solution is to write garbage into a perf counter during the
initialization and hopefully reading back the same number.  On kvm
guests, the value will be read back as zero and we disable perf as
a result.

Reported-by: default avatarJason Wessel <jason.wessel@windriver.com>
Patch-inspired-by: default avatarPeter Zijlstra <peterz@infradead.org>
Signed-off-by: default avatarDon Zickus <dzickus@redhat.com>
Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Cc: Stephane Eranian <eranian@google.com>
LKML-Reference: <1290462923-30734-1-git-send-email-dzickus@redhat.com>
Signed-off-by: default avatarIngo Molnar <mingo@elte.hu>
parent dddd3379
Loading
Loading
Loading
Loading
+20 −0
Original line number Diff line number Diff line
@@ -381,6 +381,20 @@ static void release_pmc_hardware(void) {}

#endif

static bool check_hw_exists(void)
{
	u64 val, val_new = 0;
	int ret = 0;

	val = 0xabcdUL;
	ret |= checking_wrmsrl(x86_pmu.perfctr, val);
	ret |= rdmsrl_safe(x86_pmu.perfctr, &val_new);
	if (ret || val != val_new)
		return false;

	return true;
}

static void reserve_ds_buffers(void);
static void release_ds_buffers(void);

@@ -1372,6 +1386,12 @@ void __init init_hw_perf_events(void)

	pmu_check_apic();

	/* sanity check that the hardware exists or is emulated */
	if (!check_hw_exists()) {
		pr_cont("Broken PMU hardware detected, software events only.\n");
		return;
	}

	pr_cont("%s PMU driver.\n", x86_pmu.name);

	if (x86_pmu.quirks)