From 21fc2667760c75a1090a390873e368798a2e4a8b Mon Sep 17 00:00:00 2001 From: David Woodhouse Date: Thu, 5 Mar 2020 11:35:51 +0100 Subject: [PATCH] x86/smp: reset x2apic_enabled in smp_send_stop() MIME-Version: 1.0 Content-Type: text/plain; charset=utf8 Content-Transfer-Encoding: 8bit Just before smp_send_stop() re-enables interrupts when shutting down for reboot or kexec, it calls __stop_this_cpu() which in turn calls disable_local_APIC(), which puts the APIC back in to the mode Xen found it in at boot. If that means turning x2APIC off and going back into xAPIC mode, then a timer interrupt occurring just after interrupts come back on will lead to a GP# when apic_timer_interrupt() attempts to ack the IRQ through the EOI register in x2APIC MSR 0x80b: (XEN) Executing kexec image on cpu0 (XEN) ----[ Xen-4.14-unstable x86_64 debug=n Not tainted ]---- (XEN) CPU: 0 (XEN) RIP: e008:[] apic_timer_interrupt+0x29/0x40 (XEN) RFLAGS: 0000000000010046 CONTEXT: hypervisor (XEN) rax: 0000000000000000 rbx: 00000000000000fa rcx: 000000000000080b ... (XEN) Xen code around (apic_timer_interrupt+0x29/0x40): (XEN) c0 b9 0b 08 00 00 89 c2 <0f> 30 31 ff e9 0e c9 fb ff 0f 1f 40 00 66 2e 0f ... (XEN) Xen call trace: (XEN) [] R apic_timer_interrupt+0x29/0x40 (XEN) [] S do_IRQ+0x95/0x750 ... (XEN) [] S smp_send_stop+0x42/0xd0 We can't clear the global x2apic_enabled variable in disable_local_APIC() itself because that runs on each CPU. Instead, correct it (by using current_local_apic_mode()) in smp_send_stop() while interrupts are still disabled immediately after calling __stop_this_cpu() for the boot CPU, after all other CPUs have been stopped. cf: d639bdd9bbe ("x86/apic: Disable the LAPIC later in smp_send_stop()") ... which didn't quite fix it completely. Signed-off-by: David Woodhouse Reviewed-by: Roger Pau Monné master commit: 8b1002ab037aeacdece7723c07ab35ca16c1e22e master date: 2020-02-14 18:01:52 +0000 --- xen/arch/x86/smp.c | 1 + 1 file changed, 1 insertion(+) diff --git a/xen/arch/x86/smp.c b/xen/arch/x86/smp.c index 4454224e0f..0c332eb6ec 100644 --- a/xen/arch/x86/smp.c +++ b/xen/arch/x86/smp.c @@ -325,6 +325,7 @@ void smp_send_stop(void) disable_IO_APIC(); hpet_disable(); __stop_this_cpu(); + x2apic_enabled = (current_local_apic_mode() == APIC_MODE_X2APIC); local_irq_enable(); } } -- 2.30.2