Re: [PATCH] efi: Allocate runtime workqueue before ACPI init

"Rafael J. Wysocki" <[email protected]> Tue, 19 May 2026 16:12:25 +0200
Newsgroups org.kernel.vger.linux-efi,org.kernel.vger.linux-acpi
Message-ID <CAJZ5v0h5NvLK3Fs9Fw+GoKCs82SXP1_oRggiG_aH3wiuMkdnJA@mail.gmail.com>
On Tue, May 19, 2026 at 10:23 AM Ard Biesheuvel <[email protected]> wrote:
>
> From: Ard Biesheuvel <[email protected]>
>
> Since commit
>
>   5894cf571e14 ("acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers")
>
> ACPI PRM calls are delegated to a workqueue which runs in a kernel
> thread, making it easier to detect and mitigate faulting memory accesses
> performed by the firmware.
>
> Rafael reports that such PRM accesses may occur before efisubsys_init()
> executes, which is where the workqueue is allocated, leading to NULL
> pointer dereferences. Since acpi_init() [which triggers the early PRM
> accesses] executes as a subsys_initcall() as well, and has its own
> dependencies that may be sensitive to initcall ordering, deferring
> acpi_init() is not an option.
>
> So instead, split off the workqueue allocation into its own postcore
> initcall, as this is the only missing piece to allow EFI runtime calls
> to be made. This ensures that EFI runtime call (including PRM calls) are
> accessible to all code running at subsys_initcall() level.
>
> Fixes: 5894cf571e14 ("acpi/prmt: Use EFI runtime sandbox to invoke PRM handlers")
> Reported-by: "Rafael J. Wysocki" <[email protected]>
> Signed-off-by: Ard Biesheuvel <[email protected]>

This should work AFAICS, so

Reviewed-by: Rafael J. Wysocki (Intel) <[email protected]>

> ---
>  drivers/firmware/efi/efi.c | 28 ++++++++++++++++------------
>  1 file changed, 16 insertions(+), 12 deletions(-)
>
> diff --git a/drivers/firmware/efi/efi.c b/drivers/firmware/efi/efi.c
> index d04be38f1750..318d1cc9a066 100644
> --- a/drivers/firmware/efi/efi.c
> +++ b/drivers/firmware/efi/efi.c
> @@ -402,21 +402,11 @@ static void __init efi_debugfs_init(void)
>  static inline void efi_debugfs_init(void) {}
>  #endif
>
> -/*
> - * We register the efi subsystem with the firmware subsystem and the
> - * efivars subsystem with the efi subsystem, if the system was booted with
> - * EFI.
> - */
> -static int __init efisubsys_init(void)
> +static int __init efipostcore_init(void)
>  {
> -       int error;
> -
>         if (!efi_enabled(EFI_RUNTIME_SERVICES))
>                 efi.runtime_supported_mask = 0;
>
> -       if (!efi_enabled(EFI_BOOT))
> -               return 0;
> -
>         if (efi.runtime_supported_mask) {
>                 /*
>                  * Since we process only one efi_runtime_service() at a time, an
> @@ -428,9 +418,23 @@ static int __init efisubsys_init(void)
>                         pr_err("Creating efi_rts_wq failed, EFI runtime services disabled.\n");
>                         clear_bit(EFI_RUNTIME_SERVICES, &efi.flags);
>                         efi.runtime_supported_mask = 0;
> -                       return 0;
>                 }
>         }
> +       return 0;
> +}
> +postcore_initcall(efipostcore_init);
> +
> +/*
> + * We register the efi subsystem with the firmware subsystem and the
> + * efivars subsystem with the efi subsystem, if the system was booted with
> + * EFI.
> + */
> +static int __init efisubsys_init(void)
> +{
> +       int error;
> +
> +       if (!efi_enabled(EFI_BOOT))
> +               return 0;
>
>         if (efi_rt_services_supported(EFI_RT_SUPPORTED_TIME_SERVICES))
>                 platform_device_register_simple("rtc-efi", 0, NULL, 0);
> --