Re: [PATCH] arm64/efi: Do not call EFI runtime services preemptibly under SW PAN

Will Deacon <[email protected]>
Newsgroups org.kernel.vger.linux-efi,org.infradead.lists.linux-arm-kernel,org.kernel.vger.linux-kernel,org.kernel.vger.stable
Message-ID <anmwTDnFR2cgxkqR@willie-the-truck>
On Fri, Aug 07, 2026 at 04:56:00PM +0300, Ard Biesheuvel wrote:
> 
> 
> On Fri, 7 Aug 2026, at 15:16, Will Deacon wrote:
> > On Wed, Aug 05, 2026 at 05:01:44PM -0700, gus bourg wrote:
> >> From: Gus Bourg <[email protected]>
> >> 
> >> When PAN is emulated by switching TTBR0_EL1, arch_efi_call_virt_setup()
> >> installs the EFI mm into TTBR0_EL1 via uaccess_ttbr0_enable(), and only a
> >> return from exception ever puts it back: check_and_switch_context() skips
> >> the register write by design ("Defer TTBR0_EL1 setting for user threads to
> >> uaccess_enable() when emulating PAN"), and __switch_to() does not touch it
> >> either. switch_mm() updates only thread_info->ttbr0.
> >> 
> >> Since commit a5baf582f4c0 ("arm64/efi: Call EFI runtime services without
> >> disabling preemption") the runtime call is preemptible, so the EFI worker
> >> can now be scheduled out inside that window. An involuntary preemption is
> >> harmless, because __swpan_entry_el1()/__swpan_exit_el1() save and restore
> >> the state around the exception. A voluntary reschedule is not: it performs
> >> no return from exception, so the worker resumes with another task's
> >> TTBR0_EL1 - or reserved_pg_dir - and the next efi_mm access takes a level 0
> >> translation fault.
> >> 
> >> There is such a preemption point in arch_efi_call_virt_setup() itself,
> >> immediately after the TTBR0 install: __efi_fpsimd_begin() ->
> >> kernel_neon_begin() -> put_cpu_fpsimd_context() -> local_bh_enable() ->
> >> preempt_check_resched().
> >
> > Hmm, can we move the ttbr0 toggling until after __efi_fpsimd_begin() so
> > that this preemption point doesn't interfere?
> >
> 
> Either that, or tweak the logic so that the switch is done eagerly in
> this particular case (untested):
> 
> --- a/arch/arm64/mm/context.c
> +++ b/arch/arm64/mm/context.c
> @@ -266,7 +266,7 @@
>          * Defer TTBR0_EL1 setting for user threads to uaccess_enable() when
>          * emulating PAN.
>          */
> -       if (!system_uses_ttbr0_pan())
> +       if (!system_uses_ttbr0_pan() || mm_is_efi(mm))
>                 cpu_switch_mm(mm->pgd, mm);
>  }

I think I'd prefer to avoid special-casing this, if we can. I was just
thinking of the diff below.

Will

--->8

diff --git a/arch/arm64/kernel/efi.c b/arch/arm64/kernel/efi.c
index 30cd7f804398..0ec90fd1754e 100644
--- a/arch/arm64/kernel/efi.c
+++ b/arch/arm64/kernel/efi.c
@@ -184,6 +184,8 @@ void arch_efi_call_virt_setup(void)
                efi_virtmap_load();
        }
 
+       __efi_fpsimd_begin();
+
        /*
         * Enable access to the valid TTBR0_EL1 and invoke the errata
         * workaround directly since there is no return from exception when
@@ -191,8 +193,6 @@ void arch_efi_call_virt_setup(void)
         */
        uaccess_ttbr0_enable();
        post_ttbr_update_workaround();
-
-       __efi_fpsimd_begin();
 }
 
 void arch_efi_call_virt_teardown(void)
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.