[PATCH v2 0/7] arm64: Make EFI calls preemptible

Ard Biesheuvel posted 7 patches 5 months ago
There is a newer version of this series
arch/arm/include/asm/efi.h              |  2 +-
arch/arm64/include/asm/efi.h            | 15 ++----
arch/arm64/kernel/efi.c                 | 57 +++++++++++++++++---
arch/arm64/kernel/fpsimd.c              |  4 +-
arch/loongarch/include/asm/efi.h        |  2 +-
arch/riscv/include/asm/efi.h            |  2 +-
arch/x86/include/asm/efi.h              |  2 +-
arch/x86/platform/efi/efi_32.c          |  3 +-
arch/x86/platform/efi/efi_64.c          |  3 +-
arch/x86/platform/uv/bios_uv.c          |  3 +-
drivers/firmware/efi/efi.c              |  3 ++
drivers/firmware/efi/riscv-runtime.c    |  3 +-
drivers/firmware/efi/runtime-wrappers.c | 20 ++++---
include/linux/efi.h                     |  8 +--
14 files changed, 89 insertions(+), 38 deletions(-)
[PATCH v2 0/7] arm64: Make EFI calls preemptible
Posted by Ard Biesheuvel 5 months ago
From: Ard Biesheuvel <ardb@kernel.org>

The arm64 port permits the use of the baseline FP/SIMD register file in
kernel mode, and no longer requires preemption to be disabled. Now that
the EFI spec is being clarified to state that EFI runtime services may
only use baseline FP/SIMD, the fact that EFI may code may use FP/SIMD
registers (while executing at the same privilege level as the kernel) is
no longer a reason to disable preemption when invoking them.

This means that the only remaining reason for disabling preemption is
the fact that the active mm is swapped out and replaced with efi_mm in a
way that is hidden from the scheduler, and so scheduling is not
supported currently. However, given that virtually all (*) EFI runtime
calls are made from the efi_rts_wq workqueue, the efi_mm can simply be
loaded into the workqueue worker kthread while the call is in progress,
and this does not require preemption to be disabled.

Note that this is only a partial solution in terms of RT guarantees,
given that the runtime services execute at the same privilege level as
the kernel, and can therefore disable interrupts (and therefore
preemption) directly. But it should prevent scheduling latency spikes
for EFI calls that simply take a long time to run to completion.

Changes since v1/RFC:
- Disable uaccess for SWPAN before updating the preserved TTBR0 value
- Document why disabling migration is needed
- Rebase onto v6.17-rc1

(*) only efi_reset_system() and EFI pstore invoke EFI runtime services
    without going through the workqueue, and the latter only when saving
    a kernel oops log to the EFI varstore

Cc: Will Deacon <will@kernel.org>
Cc: Mark Rutland <mark.rutland@arm.com>
Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
Cc: Peter Zijlstra <peterz@infradead.org>

Ard Biesheuvel (7):
  efi: Add missing static initializer for efi_mm::cpus_allowed_lock
  efi/runtime: Return success/failure from arch_efi_call_virt_setup()
  efi/runtime: Deal with arch_efi_call_virt_setup() returning failure
  arm64/fpsimd: Don't warn when EFI execution context is preemptible
  arm64/efi: Use a semaphore to protect the EFI stack and FP/SIMD state
  arm64/efi: Move uaccess en/disable out of efi_set_pgd()
  arm64/efi: Call EFI runtime services without disabling preemption

 arch/arm/include/asm/efi.h              |  2 +-
 arch/arm64/include/asm/efi.h            | 15 ++----
 arch/arm64/kernel/efi.c                 | 57 +++++++++++++++++---
 arch/arm64/kernel/fpsimd.c              |  4 +-
 arch/loongarch/include/asm/efi.h        |  2 +-
 arch/riscv/include/asm/efi.h            |  2 +-
 arch/x86/include/asm/efi.h              |  2 +-
 arch/x86/platform/efi/efi_32.c          |  3 +-
 arch/x86/platform/efi/efi_64.c          |  3 +-
 arch/x86/platform/uv/bios_uv.c          |  3 +-
 drivers/firmware/efi/efi.c              |  3 ++
 drivers/firmware/efi/riscv-runtime.c    |  3 +-
 drivers/firmware/efi/runtime-wrappers.c | 20 ++++---
 include/linux/efi.h                     |  8 +--
 14 files changed, 89 insertions(+), 38 deletions(-)


base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
-- 
2.51.0.355.g5224444f11-goog
Re: [PATCH v2 0/7] arm64: Make EFI calls preemptible
Posted by Sebastian Andrzej Siewior 4 months, 3 weeks ago
On 2025-09-05 15:30:36 [+0200], Ard Biesheuvel wrote:
> From: Ard Biesheuvel <ardb@kernel.org>
> 
…
> Note that this is only a partial solution in terms of RT guarantees,
> given that the runtime services execute at the same privilege level as
> the kernel, and can therefore disable interrupts (and therefore
> preemption) directly. But it should prevent scheduling latency spikes
> for EFI calls that simply take a long time to run to completion.

That sounds nice. There is no feature flag that could tell if a specific
EFI-call (or any) will disable interrupts, right? But if the source code
is available, you could check.

Sebastian
Re: [PATCH v2 0/7] arm64: Make EFI calls preemptible
Posted by Ard Biesheuvel 4 months, 3 weeks ago
Hi,

Thanks for taking a look.

On Mon, 15 Sept 2025 at 10:52, Sebastian Andrzej Siewior
<bigeasy@linutronix.de> wrote:
>
> On 2025-09-05 15:30:36 [+0200], Ard Biesheuvel wrote:
> > From: Ard Biesheuvel <ardb@kernel.org>
> >
> …
> > Note that this is only a partial solution in terms of RT guarantees,
> > given that the runtime services execute at the same privilege level as
> > the kernel, and can therefore disable interrupts (and therefore
> > preemption) directly. But it should prevent scheduling latency spikes
> > for EFI calls that simply take a long time to run to completion.
>
> That sounds nice. There is no feature flag that could tell if a specific
> EFI-call (or any) will disable interrupts, right?

Sadly, no. At runtime, the EFI APIs that manage this at a higher level
of abstraction are no longer available, and so the only available
option for firmware to ensure that code runs uninterrupted is to mask
interrupts at the CPU side. Everything else (timers, interrupt
controllers) is owned by the OS at this point, so runtime firmware
cannot touch it (even if it wanted to - it has no idea where memory
mapped peripherals live in the OS's memory map that it runs under)

It would be nice if we could sandbox this in a VM but that is not
straight-forward.

> But if the source code
> is available, you could check.
>

Even though much of the code is based on the public reference
implementation, the tweaks that require playing with interrupt
masking/unmasking are often part of the downstream, closed source
forks.
Re: [PATCH v2 0/7] arm64: Make EFI calls preemptible
Posted by Yeoreum Yun 5 months ago
This series looks good to me.

Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>

> From: Ard Biesheuvel <ardb@kernel.org>
>
> The arm64 port permits the use of the baseline FP/SIMD register file in
> kernel mode, and no longer requires preemption to be disabled. Now that
> the EFI spec is being clarified to state that EFI runtime services may
> only use baseline FP/SIMD, the fact that EFI may code may use FP/SIMD
> registers (while executing at the same privilege level as the kernel) is
> no longer a reason to disable preemption when invoking them.
>
> This means that the only remaining reason for disabling preemption is
> the fact that the active mm is swapped out and replaced with efi_mm in a
> way that is hidden from the scheduler, and so scheduling is not
> supported currently. However, given that virtually all (*) EFI runtime
> calls are made from the efi_rts_wq workqueue, the efi_mm can simply be
> loaded into the workqueue worker kthread while the call is in progress,
> and this does not require preemption to be disabled.
>
> Note that this is only a partial solution in terms of RT guarantees,
> given that the runtime services execute at the same privilege level as
> the kernel, and can therefore disable interrupts (and therefore
> preemption) directly. But it should prevent scheduling latency spikes
> for EFI calls that simply take a long time to run to completion.
>
> Changes since v1/RFC:
> - Disable uaccess for SWPAN before updating the preserved TTBR0 value
> - Document why disabling migration is needed
> - Rebase onto v6.17-rc1
>
> (*) only efi_reset_system() and EFI pstore invoke EFI runtime services
>     without going through the workqueue, and the latter only when saving
>     a kernel oops log to the EFI varstore
>
> Cc: Will Deacon <will@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Sebastian Andrzej Siewior <bigeasy@linutronix.de>
> Cc: Peter Zijlstra <peterz@infradead.org>
>
> Ard Biesheuvel (7):
>   efi: Add missing static initializer for efi_mm::cpus_allowed_lock
>   efi/runtime: Return success/failure from arch_efi_call_virt_setup()
>   efi/runtime: Deal with arch_efi_call_virt_setup() returning failure
>   arm64/fpsimd: Don't warn when EFI execution context is preemptible
>   arm64/efi: Use a semaphore to protect the EFI stack and FP/SIMD state
>   arm64/efi: Move uaccess en/disable out of efi_set_pgd()
>   arm64/efi: Call EFI runtime services without disabling preemption
>
>  arch/arm/include/asm/efi.h              |  2 +-
>  arch/arm64/include/asm/efi.h            | 15 ++----
>  arch/arm64/kernel/efi.c                 | 57 +++++++++++++++++---
>  arch/arm64/kernel/fpsimd.c              |  4 +-
>  arch/loongarch/include/asm/efi.h        |  2 +-
>  arch/riscv/include/asm/efi.h            |  2 +-
>  arch/x86/include/asm/efi.h              |  2 +-
>  arch/x86/platform/efi/efi_32.c          |  3 +-
>  arch/x86/platform/efi/efi_64.c          |  3 +-
>  arch/x86/platform/uv/bios_uv.c          |  3 +-
>  drivers/firmware/efi/efi.c              |  3 ++
>  drivers/firmware/efi/riscv-runtime.c    |  3 +-
>  drivers/firmware/efi/runtime-wrappers.c | 20 ++++---
>  include/linux/efi.h                     |  8 +--
>  14 files changed, 89 insertions(+), 38 deletions(-)
>
>
> base-commit: 8f5ae30d69d7543eee0d70083daf4de8fe15d585
> --
> 2.51.0.355.g5224444f11-goog
>
>

--
Sincerely,
Yeoreum Yun