[PATCH v2 2/2] x86/apic: include the LDR when clearing out apic registers

From: Bandan Das
Date: Mon Aug 26 2019 - 06:15:58 EST

Although apic initialization will typically clear out the LDR before
setting it, the apic cleanup code should reset the LDR.

This was discovered with a 32 bit kvm guest loading the kdump kernel.
Stale bits in the LDR exposed a bug in the kvm lapic code that creates
logical destination maps for vcpus. If multiple bits are set, kvm
could potentially overwrite a valid logical destination with an
invalid one.

Note that this fix isn't intended to paper over the kvm lapic bug;
clear_local_APIC() should correctly clear out any set bits in the LDR
when resetting apic registers.

Signed-off-by: Bandan Das <bsd@xxxxxxxxxx>
arch/x86/kernel/apic/apic.c | 4 ++++
1 file changed, 4 insertions(+)

diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index aa5495d0f478..e75f3782b915 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -1179,6 +1179,10 @@ void clear_local_APIC(void)
apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
v = apic_read(APIC_LVT1);
apic_write(APIC_LVT1, v | APIC_LVT_MASKED);
+ if (!x2apic_enabled) {
+ v = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
+ apic_write(APIC_LDR, v);
+ }
if (maxlvt >= 4) {
v = apic_read(APIC_LVTPC);
apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);