ACPI MADT doesn't allow to offline a CPU after it was onlined. This
limits kexec: the second kernel won't be able to use more than one CPU.

To prevent a kexec kernel from onlining secondary CPUs invalidate the
mailbox address in the ACPI MADT wakeup structure which prevents a
kexec kernel to use it.

This is safe as the booting kernel has the mailbox address cached
already and acpi_wakeup_cpu() uses the cached value to bring up the
secondary CPUs.

Note: This is a Linux specific convention and not covered by the
      ACPI specification.

Signed-off-by: Kirill A. Shutemov <kirill.shute...@linux.intel.com>
Acked-by: Rafael J. Wysocki <rafael.j.wyso...@intel.com>
Reviewed-by: Kai Huang <kai.hu...@intel.com>
Reviewed-by: Kuppuswamy Sathyanarayanan 
<sathyanarayanan.kuppusw...@linux.intel.com>
Reviewed-by: Thomas Gleixner <t...@linutronix.de>
Tested-by: Tao Liu <l...@redhat.com>
---
 arch/x86/kernel/acpi/madt_wakeup.c | 29 ++++++++++++++++++++++++++++-
 1 file changed, 28 insertions(+), 1 deletion(-)

diff --git a/arch/x86/kernel/acpi/madt_wakeup.c 
b/arch/x86/kernel/acpi/madt_wakeup.c
index 004801b9b151..30820f9de5af 100644
--- a/arch/x86/kernel/acpi/madt_wakeup.c
+++ b/arch/x86/kernel/acpi/madt_wakeup.c
@@ -14,6 +14,11 @@ static struct acpi_madt_multiproc_wakeup_mailbox 
*acpi_mp_wake_mailbox __ro_afte
 
 static int acpi_wakeup_cpu(u32 apicid, unsigned long start_ip)
 {
+       if (!acpi_mp_wake_mailbox_paddr) {
+               pr_warn_once("No MADT mailbox: cannot bringup secondary CPUs. 
Booting with kexec?\n");
+               return -EOPNOTSUPP;
+       }
+
        /*
         * Remap mailbox memory only for the first call to acpi_wakeup_cpu().
         *
@@ -64,6 +69,28 @@ static int acpi_wakeup_cpu(u32 apicid, unsigned long 
start_ip)
        return 0;
 }
 
+static void acpi_mp_disable_offlining(struct acpi_madt_multiproc_wakeup 
*mp_wake)
+{
+       cpu_hotplug_disable_offlining();
+
+       /*
+        * ACPI MADT doesn't allow to offline a CPU after it was onlined. This
+        * limits kexec: the second kernel won't be able to use more than one 
CPU.
+        *
+        * To prevent a kexec kernel from onlining secondary CPUs invalidate the
+        * mailbox address in the ACPI MADT wakeup structure which prevents a
+        * kexec kernel to use it.
+        *
+        * This is safe as the booting kernel has the mailbox address cached
+        * already and acpi_wakeup_cpu() uses the cached value to bring up the
+        * secondary CPUs.
+        *
+        * Note: This is a Linux specific convention and not covered by the
+        *       ACPI specification.
+        */
+       mp_wake->mailbox_address = 0;
+}
+
 int __init acpi_parse_mp_wake(union acpi_subtable_headers *header,
                              const unsigned long end)
 {
@@ -77,7 +104,7 @@ int __init acpi_parse_mp_wake(union acpi_subtable_headers 
*header,
 
        acpi_mp_wake_mailbox_paddr = mp_wake->mailbox_address;
 
-       cpu_hotplug_disable_offlining();
+       acpi_mp_disable_offlining(mp_wake);
 
        apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
 
-- 
2.43.0


Reply via email to