mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 02:01:24 +01:00
x86/nmi: Fix mis-classification of watchdog NMIs
It used to be the case that cpu_data[] inherited the BSP's cpuid_level until
the AP had calculated it itself. Following the rework, cpuid_level has a
placeholder 1 until it is calculated properly.
setup_apic_nmi_watchdog() happens to be called on the BSP after SMP bring-up,
meaning that the first call is on CPU1. It is also positioned in the window
where cpu_data[] is wrong.
As a result, setup_p6_watchdog()'s one-time calculation of the performance
counter width falls back into Pentium compatibility mode assuming 32bit
counters. This causes a watchdog NMI which is delayed a little (e.g. from an
SMI), to appear as if it hadn't overflowed, and therefore be considered as not
a watchdog NMI. On systems where unknown NMIs are treated as fatal, this
results in a spurious crash.
Switch setup_p6_watchdog() to use boot_cpu_data.cpuid_level, which is how this
is checked almost everywhere else.
core2_vpmu_init() used the same pattern to look at leaf 0xa. Despite being
init code and only running on the BSP, {boot,current}_cpu_data are different
objects, so switch it over to checking boot_cpu_data.cpuid_level too.
Fixes: 7126b7f806 ("x86/CPU: re-work populating of cpu_data[]")
Signed-off-by: Andrew Cooper <andrew.cooper3@citrix.com>
Reviewed-by: Jan Beulich <jbeulich@suse.com>
master commit: dc5a77c6c4
master date: 2026-08-17 18:46:08 +0100
This commit is contained in:
1 parent
50e6dea12c
commit
aa4c4909b4
2 files changed
+2
-2
No files matched your search
@@ -896,7 +896,7 @@ const struct arch_vpmu_ops *__init core2_vpmu_init(void)
|
||||
unsigned int version = 0;
|
||||
unsigned int i;
|
||||
|
||||
if ( current_cpu_data.cpuid_level >= 0xa )
|
||||
if ( boot_cpu_data.cpuid_level >= 0xa )
|
||||
version = MASK_EXTR(cpuid_eax(0xa), PMU_VERSION_MASK);
|
||||
|
||||
switch ( version )
|
||||
|
||||
+1
-1
@@ -321,7 +321,7 @@ static void setup_p6_watchdog(unsigned counter)
|
||||
{
|
||||
unsigned int evntsel;
|
||||
|
||||
if ( !nmi_p6_event_width && current_cpu_data.cpuid_level >= 0xa )
|
||||
if ( !nmi_p6_event_width && boot_cpu_data.cpuid_level >= 0xa )
|
||||
nmi_p6_event_width = MASK_EXTR(cpuid_eax(0xa), P6_EVENT_WIDTH_MASK);
|
||||
if ( !nmi_p6_event_width )
|
||||
nmi_p6_event_width = P6_EVENT_WIDTH_MIN;
|
||||
|
||||