On Sat, May 3, 2025 at 9:10 PM Ricardo Neri
<ricardo.neri-calde...@linux.intel.com> wrote:
>
> The bootstrap processor uses acpi_wakeup_cpu() to indicate to firmware that
> it wants to boot a secondary CPU using a mailbox as described in the
> Multiprocessor Wakeup Structure of the ACPI specification.
>
> The wakeup mailbox does not strictly require support from ACPI.

Well, except that it is defined by the ACPI specification.

> The platform firmware can implement a mailbox compatible in structure and
> operation and enumerate it using other mechanisms such a DeviceTree graph.

So is there a specification defining this mechanism?

It is generally not sufficient to put the code and DT bindings
unilaterally into the OS and expect the firmware to follow suit.

> Move the code used to setup and use the mailbox out of the ACPI
> directory to use it when support for ACPI is not available or needed.

I think that the code implementing interfaces defined by the ACPI
specification is not generic and so it should not be built when the
kernel is configured without ACPI support.

> No functional changes are intended.
>
> Originally-by: Yunhong Jiang <yunhong.ji...@linux.intel.com>
> Signed-off-by: Ricardo Neri <ricardo.neri-calde...@linux.intel.com>
> ---
> Changes since v2:
>  - Only move to smpboot.c the portions of the code that configure and
>    use the mailbox. This also resolved the compile warnings about unused
>    functions that Michael Kelley reported.
>  - Edited the commit message for clarity.
>
> Changes since v1:
>  - None.
> ---
>  arch/x86/kernel/acpi/madt_wakeup.c | 75 ----------------------------
>  arch/x86/kernel/smpboot.c          | 78 ++++++++++++++++++++++++++++++
>  2 files changed, 78 insertions(+), 75 deletions(-)
>
> diff --git a/arch/x86/kernel/acpi/madt_wakeup.c 
> b/arch/x86/kernel/acpi/madt_wakeup.c
> index 6b9e41a24574..15627f63f9f5 100644
> --- a/arch/x86/kernel/acpi/madt_wakeup.c
> +++ b/arch/x86/kernel/acpi/madt_wakeup.c
> @@ -2,7 +2,6 @@
>  #include <linux/acpi.h>
>  #include <linux/cpu.h>
>  #include <linux/delay.h>
> -#include <linux/io.h>
>  #include <linux/kexec.h>
>  #include <linux/memblock.h>
>  #include <linux/pgtable.h>
> @@ -15,12 +14,6 @@
>  #include <asm/processor.h>
>  #include <asm/reboot.h>
>
> -/* Physical address of the Multiprocessor Wakeup Structure mailbox */
> -static u64 acpi_mp_wake_mailbox_paddr __ro_after_init;
> -
> -/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
> -static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
> -
>  static u64 acpi_mp_pgd __ro_after_init;
>  static u64 acpi_mp_reset_vector_paddr __ro_after_init;
>
> @@ -127,63 +120,6 @@ static int __init acpi_mp_setup_reset(u64 reset_vector)
>         return 0;
>  }
>
> -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().
> -        *
> -        * Wakeup of secondary CPUs is fully serialized in the core code.
> -        * No need to protect acpi_mp_wake_mailbox from concurrent accesses.
> -        */
> -       if (!acpi_mp_wake_mailbox) {
> -               acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
> -                                               sizeof(*acpi_mp_wake_mailbox),
> -                                               MEMREMAP_WB);
> -       }
> -
> -       /*
> -        * Mailbox memory is shared between the firmware and OS. Firmware will
> -        * listen on mailbox command address, and once it receives the wakeup
> -        * command, the CPU associated with the given apicid will be booted.
> -        *
> -        * The value of 'apic_id' and 'wakeup_vector' must be visible to the
> -        * firmware before the wakeup command is visible.  smp_store_release()
> -        * ensures ordering and visibility.
> -        */
> -       acpi_mp_wake_mailbox->apic_id       = apicid;
> -       acpi_mp_wake_mailbox->wakeup_vector = start_ip;
> -       smp_store_release(&acpi_mp_wake_mailbox->command,
> -                         ACPI_MP_WAKE_COMMAND_WAKEUP);
> -
> -       /*
> -        * Wait for the CPU to wake up.
> -        *
> -        * The CPU being woken up is essentially in a spin loop waiting to be
> -        * woken up. It should not take long for it wake up and acknowledge by
> -        * zeroing out ->command.
> -        *
> -        * ACPI specification doesn't provide any guidance on how long kernel
> -        * has to wait for a wake up acknowledgment. It also doesn't provide
> -        * a way to cancel a wake up request if it takes too long.
> -        *
> -        * In TDX environment, the VMM has control over how long it takes to
> -        * wake up secondary. It can postpone scheduling secondary vCPU
> -        * indefinitely. Giving up on wake up request and reporting error 
> opens
> -        * possible attack vector for VMM: it can wake up a secondary CPU when
> -        * kernel doesn't expect it. Wait until positive result of the wake up
> -        * request.
> -        */
> -       while (READ_ONCE(acpi_mp_wake_mailbox->command))
> -               cpu_relax();
> -
> -       return 0;
> -}
> -
>  static void acpi_mp_disable_offlining(struct acpi_madt_multiproc_wakeup 
> *mp_wake)
>  {
>         cpu_hotplug_disable_offlining();
> @@ -246,14 +182,3 @@ int __init acpi_parse_mp_wake(union 
> acpi_subtable_headers *header,
>
>         return 0;
>  }
> -
> -void __init setup_mp_wakeup_mailbox(u64 mailbox_paddr)
> -{
> -       acpi_mp_wake_mailbox_paddr = mailbox_paddr;
> -       apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
> -}
> -
> -struct acpi_madt_multiproc_wakeup_mailbox *get_mp_wakeup_mailbox(void)
> -{
> -       return acpi_mp_wake_mailbox;
> -}
> diff --git a/arch/x86/kernel/smpboot.c b/arch/x86/kernel/smpboot.c
> index d6cf1e23c2a3..6f39ebe4d192 100644
> --- a/arch/x86/kernel/smpboot.c
> +++ b/arch/x86/kernel/smpboot.c
> @@ -61,7 +61,9 @@
>  #include <linux/cpuhotplug.h>
>  #include <linux/mc146818rtc.h>
>  #include <linux/acpi.h>
> +#include <linux/io.h>
>
> +#include <asm/barrier.h>
>  #include <asm/acpi.h>
>  #include <asm/cacheinfo.h>
>  #include <asm/cpuid.h>
> @@ -1354,3 +1356,79 @@ void native_play_dead(void)
>  }
>
>  #endif
> +
> +#ifdef CONFIG_X86_64
> +/* Physical address of the Multiprocessor Wakeup Structure mailbox */
> +static u64 acpi_mp_wake_mailbox_paddr __ro_after_init;
> +
> +/* Virtual address of the Multiprocessor Wakeup Structure mailbox */
> +static struct acpi_madt_multiproc_wakeup_mailbox *acpi_mp_wake_mailbox;
> +
> +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().
> +        *
> +        * Wakeup of secondary CPUs is fully serialized in the core code.
> +        * No need to protect acpi_mp_wake_mailbox from concurrent accesses.
> +        */
> +       if (!acpi_mp_wake_mailbox) {
> +               acpi_mp_wake_mailbox = memremap(acpi_mp_wake_mailbox_paddr,
> +                                               sizeof(*acpi_mp_wake_mailbox),
> +                                               MEMREMAP_WB);
> +       }
> +
> +       /*
> +        * Mailbox memory is shared between the firmware and OS. Firmware will
> +        * listen on mailbox command address, and once it receives the wakeup
> +        * command, the CPU associated with the given apicid will be booted.
> +        *
> +        * The value of 'apic_id' and 'wakeup_vector' must be visible to the
> +        * firmware before the wakeup command is visible.  smp_store_release()
> +        * ensures ordering and visibility.
> +        */
> +       acpi_mp_wake_mailbox->apic_id       = apicid;
> +       acpi_mp_wake_mailbox->wakeup_vector = start_ip;
> +       smp_store_release(&acpi_mp_wake_mailbox->command,
> +                         ACPI_MP_WAKE_COMMAND_WAKEUP);
> +
> +       /*
> +        * Wait for the CPU to wake up.
> +        *
> +        * The CPU being woken up is essentially in a spin loop waiting to be
> +        * woken up. It should not take long for it wake up and acknowledge by
> +        * zeroing out ->command.
> +        *
> +        * ACPI specification doesn't provide any guidance on how long kernel
> +        * has to wait for a wake up acknowledgment. It also doesn't provide
> +        * a way to cancel a wake up request if it takes too long.
> +        *
> +        * In TDX environment, the VMM has control over how long it takes to
> +        * wake up secondary. It can postpone scheduling secondary vCPU
> +        * indefinitely. Giving up on wake up request and reporting error 
> opens
> +        * possible attack vector for VMM: it can wake up a secondary CPU when
> +        * kernel doesn't expect it. Wait until positive result of the wake up
> +        * request.
> +        */
> +       while (READ_ONCE(acpi_mp_wake_mailbox->command))
> +               cpu_relax();
> +
> +       return 0;
> +}
> +
> +void __init setup_mp_wakeup_mailbox(u64 mailbox_paddr)
> +{
> +       acpi_mp_wake_mailbox_paddr = mailbox_paddr;
> +       apic_update_callback(wakeup_secondary_cpu_64, acpi_wakeup_cpu);
> +}
> +
> +struct acpi_madt_multiproc_wakeup_mailbox *get_mp_wakeup_mailbox(void)
> +{
> +       return acpi_mp_wake_mailbox;
> +}
> +#endif
> --
> 2.43.0
>
>

Reply via email to