* [PATCH] ARM: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN
@ 2026-05-23 0:08 Florian Fainelli
2026-05-25 13:35 ` Linus Walleij
0 siblings, 1 reply; 3+ messages in thread
From: Florian Fainelli @ 2026-05-23 0:08 UTC (permalink / raw)
To: linux-arm-kernel
Cc: bcm-kernel-feedback-list, Florian Fainelli, Catalin Marinas,
Linus Walleij, Russell King, Linus Walleij, Russell King (Oracle),
Kees Cook, open list
Commit 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0
page table walks disablement") implemented PAN for LPAE kernels by
setting TTBCR.EPD0 on every kernel entry, disabling TTBR0 page-table
walks while running in kernel mode. The commit correctly updated
cpu_suspend() in arch/arm/kernel/suspend.c, but missed two other code
paths that switch the CPU to the identity mapping before jumping to
low-PA (TTBR0-range) physical addresses:
1. setup_mm_for_reboot() in arch/arm/mm/idmap.c, used by the kexec
reboot path. With TTBCR.EPD0 still set, the subsequent branch to
the identity-mapped cpu_v7_reset causes a PrefetchAbort because the
TTBR0 page-table walk needed to resolve the identity-mapped address
is disabled. This manifests as a hard hang or "bad PC value" panic
on LPAE kernels booted on CPUs that strictly enforce EPD0 for
instruction fetch (e.g. Cortex-A53 in AArch32 mode) while the same
image may accidentally work on Cortex-A15 due to microarchitectural
differences in EPD0 enforcement.
2. arch_restore_image() in arch/arm/kernel/hibernate.c, which calls
cpu_switch_mm(idmap_pgd, &init_mm) directly without going through
setup_mm_for_reboot(), leaving TTBCR.EPD0 set while the identity
mapping is active.
Fix both sites by calling uaccess_save_and_enable() before switching
to the identity mapping, mirroring what the original commit did for
cpu_suspend().
Fixes: 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0 page table walks disablement")
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Linus Walleij <linus.walleij@linaro.org>
Assisted-by: Cursor:claude-sonnet-4.6
Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
---
arch/arm/kernel/hibernate.c | 10 ++++++++++
arch/arm/mm/idmap.c | 12 ++++++++++++
2 files changed, 22 insertions(+)
diff --git a/arch/arm/kernel/hibernate.c b/arch/arm/kernel/hibernate.c
index 38a90a3d12b2..231a76af09a0 100644
--- a/arch/arm/kernel/hibernate.c
+++ b/arch/arm/kernel/hibernate.c
@@ -21,6 +21,7 @@
#include <asm/suspend.h>
#include <asm/page.h>
#include <asm/sections.h>
+#include <asm/uaccess.h>
#include "reboot.h"
int pfn_is_nosave(unsigned long pfn)
@@ -82,6 +83,15 @@ static void notrace arch_restore_image(void *unused)
{
struct pbe *pbe;
+ /*
+ * With CONFIG_CPU_TTBR0_PAN enabled, TTBCR.EPD0 is set to block
+ * TTBR0 page-table walks. The identity mapping used here lives at
+ * low (user-space) virtual addresses and is only reachable via
+ * TTBR0, so re-enable those walks before switching page tables.
+ * On non-PAN kernels this is a no-op.
+ */
+ if (IS_ENABLED(CONFIG_CPU_TTBR0_PAN))
+ uaccess_save_and_enable();
cpu_switch_mm(idmap_pgd, &init_mm);
for (pbe = restore_pblist; pbe; pbe = pbe->next)
copy_page(pbe->orig_address, pbe->address);
diff --git a/arch/arm/mm/idmap.c b/arch/arm/mm/idmap.c
index 4a833e89782a..70403e968d2a 100644
--- a/arch/arm/mm/idmap.c
+++ b/arch/arm/mm/idmap.c
@@ -11,6 +11,7 @@
#include <asm/pgalloc.h>
#include <asm/sections.h>
#include <asm/system_info.h>
+#include <asm/uaccess.h>
/*
* Note: accesses outside of the kernel image and the identity map area
@@ -133,6 +134,17 @@ early_initcall(init_static_idmap);
*/
void setup_mm_for_reboot(void)
{
+ /*
+ * With CONFIG_CPU_TTBR0_PAN enabled, TTBCR.EPD0 is set whenever
+ * user-space access is disabled in order to block TTBR0 page-table
+ * walks. The identity mapping lives at low (user-space) virtual
+ * addresses and can only be reached via TTBR0, so we must re-enable
+ * those walks before switching page tables. On non-PAN kernels this
+ * is a no-op.
+ */
+ if (IS_ENABLED(CONFIG_CPU_TTBR0_PAN))
+ uaccess_save_and_enable();
+
/* Switch to the identity mapping. */
cpu_switch_mm(idmap_pgd, &init_mm);
local_flush_bp_all();
--
2.34.1
^ permalink raw reply related [flat|nested] 3+ messages in thread* Re: [PATCH] ARM: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN
2026-05-23 0:08 [PATCH] ARM: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN Florian Fainelli
@ 2026-05-25 13:35 ` Linus Walleij
2026-05-25 18:15 ` Florian Fainelli
0 siblings, 1 reply; 3+ messages in thread
From: Linus Walleij @ 2026-05-25 13:35 UTC (permalink / raw)
To: Florian Fainelli
Cc: linux-arm-kernel, bcm-kernel-feedback-list, Catalin Marinas,
Linus Walleij, Russell King, Russell King (Oracle), Kees Cook,
open list
Hi Florian,
thanks for digging in and finding this!
On Sat, May 23, 2026 at 2:08 AM Florian Fainelli
<florian.fainelli@broadcom.com> wrote:
> Commit 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0
> page table walks disablement") implemented PAN for LPAE kernels by
> setting TTBCR.EPD0 on every kernel entry, disabling TTBR0 page-table
> walks while running in kernel mode. The commit correctly updated
> cpu_suspend() in arch/arm/kernel/suspend.c, but missed two other code
> paths that switch the CPU to the identity mapping before jumping to
> low-PA (TTBR0-range) physical addresses:
>
> 1. setup_mm_for_reboot() in arch/arm/mm/idmap.c, used by the kexec
> reboot path. With TTBCR.EPD0 still set, the subsequent branch to
> the identity-mapped cpu_v7_reset causes a PrefetchAbort because the
> TTBR0 page-table walk needed to resolve the identity-mapped address
> is disabled. This manifests as a hard hang or "bad PC value" panic
> on LPAE kernels booted on CPUs that strictly enforce EPD0 for
> instruction fetch (e.g. Cortex-A53 in AArch32 mode) while the same
> image may accidentally work on Cortex-A15 due to microarchitectural
> differences in EPD0 enforcement.
>
> 2. arch_restore_image() in arch/arm/kernel/hibernate.c, which calls
> cpu_switch_mm(idmap_pgd, &init_mm) directly without going through
> setup_mm_for_reboot(), leaving TTBCR.EPD0 set while the identity
> mapping is active.
>
> Fix both sites by calling uaccess_save_and_enable() before switching
> to the identity mapping, mirroring what the original commit did for
> cpu_suspend().
>
> Fixes: 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0 page table walks disablement")
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Linus Walleij <linus.walleij@linaro.org>
> Assisted-by: Cursor:claude-sonnet-4.6
> Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
Reviewed-by: Linus Walleij <linusw@kernel.org>
Please put this patch into Russell's patch tracker.
Yours,
Linus Walleij
^ permalink raw reply [flat|nested] 3+ messages in thread* Re: [PATCH] ARM: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN
2026-05-25 13:35 ` Linus Walleij
@ 2026-05-25 18:15 ` Florian Fainelli
0 siblings, 0 replies; 3+ messages in thread
From: Florian Fainelli @ 2026-05-25 18:15 UTC (permalink / raw)
To: Linus Walleij
Cc: linux-arm-kernel, bcm-kernel-feedback-list, Catalin Marinas,
Linus Walleij, Russell King, Russell King (Oracle), Kees Cook,
open list
On 5/25/2026 6:35 AM, Linus Walleij wrote:
> Hi Florian,
>
> thanks for digging in and finding this!
>
> On Sat, May 23, 2026 at 2:08 AM Florian Fainelli
> <florian.fainelli@broadcom.com> wrote:
>
>> Commit 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0
>> page table walks disablement") implemented PAN for LPAE kernels by
>> setting TTBCR.EPD0 on every kernel entry, disabling TTBR0 page-table
>> walks while running in kernel mode. The commit correctly updated
>> cpu_suspend() in arch/arm/kernel/suspend.c, but missed two other code
>> paths that switch the CPU to the identity mapping before jumping to
>> low-PA (TTBR0-range) physical addresses:
>>
>> 1. setup_mm_for_reboot() in arch/arm/mm/idmap.c, used by the kexec
>> reboot path. With TTBCR.EPD0 still set, the subsequent branch to
>> the identity-mapped cpu_v7_reset causes a PrefetchAbort because the
>> TTBR0 page-table walk needed to resolve the identity-mapped address
>> is disabled. This manifests as a hard hang or "bad PC value" panic
>> on LPAE kernels booted on CPUs that strictly enforce EPD0 for
>> instruction fetch (e.g. Cortex-A53 in AArch32 mode) while the same
>> image may accidentally work on Cortex-A15 due to microarchitectural
>> differences in EPD0 enforcement.
>>
>> 2. arch_restore_image() in arch/arm/kernel/hibernate.c, which calls
>> cpu_switch_mm(idmap_pgd, &init_mm) directly without going through
>> setup_mm_for_reboot(), leaving TTBCR.EPD0 set while the identity
>> mapping is active.
>>
>> Fix both sites by calling uaccess_save_and_enable() before switching
>> to the identity mapping, mirroring what the original commit did for
>> cpu_suspend().
>>
>> Fixes: 7af5b901e847 ("ARM: 9358/2: Implement PAN for LPAE by TTBR0 page table walks disablement")
>> Cc: Catalin Marinas <catalin.marinas@arm.com>
>> Cc: Linus Walleij <linus.walleij@linaro.org>
>> Assisted-by: Cursor:claude-sonnet-4.6
>> Signed-off-by: Florian Fainelli <florian.fainelli@broadcom.com>
>
> Reviewed-by: Linus Walleij <linusw@kernel.org>
>
> Please put this patch into Russell's patch tracker.
Thank you, now done:
https://www.armlinux.org.uk/developer/patches/viewpatch.php?id=9476/1
--
Florian
^ permalink raw reply [flat|nested] 3+ messages in thread
end of thread, other threads:[~2026-05-25 18:15 UTC | newest]
Thread overview: 3+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-05-23 0:08 [PATCH] ARM: mm: fix kexec and hibernation with CONFIG_CPU_TTBR0_PAN Florian Fainelli
2026-05-25 13:35 ` Linus Walleij
2026-05-25 18:15 ` Florian Fainelli
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox