* [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems
@ 2026-09-18 13:16 Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page Vincent Donnefort
` (3 more replies)
0 siblings, 4 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-09-18 13:16 UTC (permalink / raw)
To: catalin.marinas, will, rafael
Cc: mark.rutland, lenb, pavel, linux-arm-kernel, linux-pm,
linux-kernel, thierry.reding, rppt, Vincent Donnefort
This series is a fork of [1] which creates a new CMA pool for FF-A lent
memory which unmaps that memory from the linear map as a mitigation of
CPU speculative access to Secure memory. [1] creates a PTE-level region
to enable setting the direct map, but BBML3 systems shouldn't need it.
Currently, can_set_direct_map() only returns true if a feature forces the
linear map to be mapped at PTE granularity. This prevents systems
supporting BBML3 from enabling set_direct_map*() functions yet safe.
To enable them, this series:
1. Use the fixmap for hibernation. This removes the need for handling
atomic context in split_kernel_leaf_mapping().
2. Breaks the dependency between linear_map_requires_bbml3 and
can_set_direct_map()
3. Allow split_kernel_leaf_mapping() even when no feature requires to
set the direct map.
[1] https://lore.kernel.org/all/20260902104712.2399797-1-vdonnefort@google.com/
Vincent Donnefort (4):
PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page
arm64: hibernate: Use fixmap for hibernate_map/unmap_page
arm64: mm: Introduce linear_map_needs_set() helper
arm64: mm: Allow can_set_direct_map() on BBML3 systems
arch/arm64/include/asm/fixmap.h | 3 +++
arch/arm64/include/asm/mmu.h | 1 +
arch/arm64/kernel/hibernate.c | 12 +++++++++
arch/arm64/mm/mmu.c | 46 +++++++++++++++++++++++++--------
arch/arm64/mm/pageattr.c | 12 +--------
include/linux/suspend.h | 2 ++
kernel/power/snapshot.c | 10 ++++---
7 files changed, 60 insertions(+), 26 deletions(-)
base-commit: fd73f4a6659897191fa0d40695fe370925dd3780
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply [flat|nested] 6+ messages in thread
* [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page
2026-09-18 13:16 [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems Vincent Donnefort
@ 2026-09-18 13:16 ` Vincent Donnefort
2026-09-22 5:55 ` Mike Rapoport
2026-09-18 13:16 ` [PATCH v1 2/4] arm64: hibernate: Use fixmap " Vincent Donnefort
` (2 subsequent siblings)
3 siblings, 1 reply; 6+ messages in thread
From: Vincent Donnefort @ 2026-09-18 13:16 UTC (permalink / raw)
To: catalin.marinas, will, rafael
Cc: mark.rutland, lenb, pavel, linux-arm-kernel, linux-pm,
linux-kernel, thierry.reding, rppt, Vincent Donnefort
hibernate_map_page() is called from an atomic context. This is
problematic for Arm BBML3 systems where the linear map may contain
blocks and is allowed to split as splitting is a sleepable operation.
Add arch hook so arm64 can define its own implementation without relying
on the direct map.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
include/linux/suspend.h | 2 ++
kernel/power/snapshot.c | 10 ++++++----
2 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/include/linux/suspend.h b/include/linux/suspend.h
index b02876f1ae38..10fe2298d94e 100644
--- a/include/linux/suspend.h
+++ b/include/linux/suspend.h
@@ -401,6 +401,8 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data);
int hibernate_resume_nonboot_cpu_disable(void);
int arch_hibernation_header_save(void *addr, unsigned int max_size);
int arch_hibernation_header_restore(void *addr);
+void *hibernate_map_page(struct page *page);
+void hibernate_unmap_page(struct page *page);
#else /* CONFIG_HIBERNATION */
static inline void register_nosave_region(unsigned long b, unsigned long e) {}
diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
index b209712cb2c3..b41952f1de2a 100644
--- a/kernel/power/snapshot.c
+++ b/kernel/power/snapshot.c
@@ -85,7 +85,7 @@ static inline int hibernate_restore_unprotect_page(void *page_address) {return 0
* It is still worth to have a warning here if something changes and this
* will no longer be the case.
*/
-static inline void hibernate_map_page(struct page *page)
+void * __weak hibernate_map_page(struct page *page)
{
if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
int ret = set_direct_map_default_noflush(page);
@@ -95,9 +95,10 @@ static inline void hibernate_map_page(struct page *page)
} else {
debug_pagealloc_map_pages(page, 1);
}
+ return page_address(page);
}
-static inline void hibernate_unmap_page(struct page *page)
+void __weak hibernate_unmap_page(struct page *page)
{
if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
unsigned long addr = (unsigned long)page_address(page);
@@ -1456,8 +1457,9 @@ static bool safe_copy_page(void *dst, struct page *s_page)
if (kernel_page_present(s_page)) {
zeros_only = do_copy_page(dst, page_address(s_page));
} else {
- hibernate_map_page(s_page);
- zeros_only = do_copy_page(dst, page_address(s_page));
+ void *src = hibernate_map_page(s_page);
+
+ zeros_only = do_copy_page(dst, src);
hibernate_unmap_page(s_page);
}
return zeros_only;
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 2/4] arm64: hibernate: Use fixmap for hibernate_map/unmap_page
2026-09-18 13:16 [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page Vincent Donnefort
@ 2026-09-18 13:16 ` Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 3/4] arm64: mm: Introduce linear_map_needs_set() helper Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 4/4] arm64: mm: Allow can_set_direct_map() on BBML3 systems Vincent Donnefort
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-09-18 13:16 UTC (permalink / raw)
To: catalin.marinas, will, rafael
Cc: mark.rutland, lenb, pavel, linux-arm-kernel, linux-pm,
linux-kernel, thierry.reding, rppt, Vincent Donnefort
The default implementation for hibernate_map_page uses the direct map.
This creates an unnecessary limitation for BBML3 enabled systems which
can split linear map blocks and can enable memfd_secret users regardless
of the linear map mapping level.
Block splitting acquires a mutex (pgtable_split_lock) and as a
consequence is incompatible with hibernation. We know hibernation would
only call set_direct_map*() on a PTE-level region since it was
previously split by memfd_secret. But let's avoid special casing
hibernation in split_kernel_leaf_mapping().
On hibernation, do not modify the direct map and instead use a fixmap,
better suited for a transient mapping hibernation needs to copy the page
content. It removes the need for handling atomic context in
split_kernel_leaf_mapping() altogether.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
arch/arm64/include/asm/fixmap.h | 3 +++
arch/arm64/kernel/hibernate.c | 12 ++++++++++++
2 files changed, 15 insertions(+)
diff --git a/arch/arm64/include/asm/fixmap.h b/arch/arm64/include/asm/fixmap.h
index 170c3502d723..c8a65fd8584d 100644
--- a/arch/arm64/include/asm/fixmap.h
+++ b/arch/arm64/include/asm/fixmap.h
@@ -73,6 +73,9 @@ enum fixed_addresses {
FIX_ENTRY_TRAMP_TEXT1,
#define TRAMP_VALIAS (__fix_to_virt(FIX_ENTRY_TRAMP_TEXT1))
#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
+#ifdef CONFIG_HIBERNATION
+ FIX_HIBERNATE,
+#endif
__end_of_permanent_fixed_addresses,
/*
diff --git a/arch/arm64/kernel/hibernate.c b/arch/arm64/kernel/hibernate.c
index 7bf117427777..bbd0779081fa 100644
--- a/arch/arm64/kernel/hibernate.c
+++ b/arch/arm64/kernel/hibernate.c
@@ -21,6 +21,7 @@
#include <asm/cacheflush.h>
#include <asm/cputype.h>
#include <asm/daifflags.h>
+#include <asm/fixmap.h>
#include <asm/irqflags.h>
#include <asm/kexec.h>
#include <asm/memory.h>
@@ -213,6 +214,17 @@ static int create_safe_exec_page(void *src_start, size_t length,
return 0;
}
+void *hibernate_map_page(struct page *page)
+{
+ set_fixmap(FIX_HIBERNATE, page_to_phys(page));
+ return (void *)__fix_to_virt(FIX_HIBERNATE);
+}
+
+void hibernate_unmap_page(struct page *page)
+{
+ clear_fixmap(FIX_HIBERNATE);
+}
+
#ifdef CONFIG_ARM64_MTE
static DEFINE_XARRAY(mte_pages);
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 3/4] arm64: mm: Introduce linear_map_needs_set() helper
2026-09-18 13:16 [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 2/4] arm64: hibernate: Use fixmap " Vincent Donnefort
@ 2026-09-18 13:16 ` Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 4/4] arm64: mm: Allow can_set_direct_map() on BBML3 systems Vincent Donnefort
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-09-18 13:16 UTC (permalink / raw)
To: catalin.marinas, will, rafael
Cc: mark.rutland, lenb, pavel, linux-arm-kernel, linux-pm,
linux-kernel, thierry.reding, rppt, Vincent Donnefort
can_set_direct_map() is intended as an external query function, but is
also being called internally by map_mem() to initialise
linear_map_requires_bbml3, duplicating the feature checks already
present in force_pte_mapping().
Factor the list of features that require modifying linear map attributes
into a shared helper linear_map_needs_set().
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
arch/arm64/include/asm/mmu.h | 1 +
arch/arm64/mm/mmu.c | 22 ++++++++++++++++++++--
arch/arm64/mm/pageattr.c | 12 +-----------
3 files changed, 22 insertions(+), 13 deletions(-)
diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
index 5e1211c540ab..12ed21e2d0d7 100644
--- a/arch/arm64/include/asm/mmu.h
+++ b/arch/arm64/include/asm/mmu.h
@@ -70,6 +70,7 @@ extern void create_pgd_mapping(struct mm_struct *mm, phys_addr_t phys,
pgprot_t prot, bool page_mappings_only);
extern void *fixmap_remap_fdt(phys_addr_t dt_phys, int *size, pgprot_t prot);
extern void mark_linear_text_alias_ro(void);
+extern bool linear_map_needs_set(void);
extern int split_kernel_leaf_mapping(unsigned long start, unsigned long end);
extern void linear_map_maybe_split_to_ptes(void);
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index 79d90226fd5d..c18ed601f0a8 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -776,6 +776,24 @@ static int split_kernel_leaf_mapping_locked(unsigned long addr)
return ret;
}
+/*
+ * True if the linear map needs to be modified for one of the following
+ * features:
+ *
+ * rodata_full and DEBUG_PAGEALLOC need to protect/unprotect pages in
+ * the linear map.
+ *
+ * KFENCE pool needs to protect/unprotect pages in the linear map if
+ * initialized late.
+ *
+ * Realms need to mark pages shared/protected in the linear map.
+ */
+bool linear_map_needs_set(void)
+{
+ return rodata_full || debug_pagealloc_enabled() ||
+ arm64_kfence_can_set_direct_map() || is_realm_world();
+}
+
static inline bool force_pte_mapping(void)
{
const bool bbml3 = system_capabilities_finalized() ?
@@ -785,7 +803,7 @@ static inline bool force_pte_mapping(void)
return true;
if (bbml3)
return false;
- return rodata_full || arm64_kfence_can_set_direct_map() || is_realm_world();
+ return linear_map_needs_set();
}
static DEFINE_MUTEX(pgtable_split_lock);
@@ -1203,7 +1221,7 @@ static void __init map_mem(void)
arm64_kfence_map_pool();
- linear_map_requires_bbml3 = !force_pte_mapping() && can_set_direct_map();
+ linear_map_requires_bbml3 = !force_pte_mapping() && linear_map_needs_set();
if (force_pte_mapping())
flags |= NO_BLOCK_MAPPINGS | NO_CONT_MAPPINGS;
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index bbe98ac9ad8c..c1ba74eb602f 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -89,17 +89,7 @@ bool rodata_full __ro_after_init = true;
bool can_set_direct_map(void)
{
- /*
- * rodata_full, DEBUG_PAGEALLOC and a Realm guest all require linear
- * map to be mapped at page granularity, so that it is possible to
- * protect/unprotect single pages.
- *
- * KFENCE pool requires page-granular mapping if initialized late.
- *
- * Realms need to make pages shared/protected at page granularity.
- */
- return rodata_full || debug_pagealloc_enabled() ||
- arm64_kfence_can_set_direct_map() || is_realm_world();
+ return linear_map_needs_set();
}
static int update_range_prot(unsigned long start, unsigned long size,
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* [PATCH v1 4/4] arm64: mm: Allow can_set_direct_map() on BBML3 systems
2026-09-18 13:16 [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems Vincent Donnefort
` (2 preceding siblings ...)
2026-09-18 13:16 ` [PATCH v1 3/4] arm64: mm: Introduce linear_map_needs_set() helper Vincent Donnefort
@ 2026-09-18 13:16 ` Vincent Donnefort
3 siblings, 0 replies; 6+ messages in thread
From: Vincent Donnefort @ 2026-09-18 13:16 UTC (permalink / raw)
To: catalin.marinas, will, rafael
Cc: mark.rutland, lenb, pavel, linux-arm-kernel, linux-pm,
linux-kernel, thierry.reding, rppt, Vincent Donnefort
On BBML3 systems, block mappings in the linear map can be split
dynamically at runtime without break-before-make faults. In such
systems, allow can_set_direct_map() to enable set_direct_map_* users.
split_kernel_leaf_mapping() must now allow splitting for BBML3 systems
where no feature requires a split (i.e. !linear_map_needs_set()). As a
consequence, it can't solely rely on linear_map_requires_bbml3 anymore.
Instead, deduce force_pte_mapping() value and filter out non-lm
addresses.
Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
---
arch/arm64/mm/mmu.c | 24 +++++++++++++++---------
arch/arm64/mm/pageattr.c | 2 +-
2 files changed, 16 insertions(+), 10 deletions(-)
diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
index c18ed601f0a8..4c345065d33f 100644
--- a/arch/arm64/mm/mmu.c
+++ b/arch/arm64/mm/mmu.c
@@ -811,24 +811,30 @@ static bool linear_map_requires_bbml3;
int split_kernel_leaf_mapping(unsigned long start, unsigned long end)
{
+ bool force_pte;
int ret;
/*
* If the region is within a pte-mapped area, there is no need to try to
- * split. Additionally, CONFIG_DEBUG_PAGEALLOC and CONFIG_KFENCE may
- * change permissions from atomic context so for those cases (which are
- * always pte-mapped), we must not go any further because taking the
- * mutex below may sleep. Do not call force_pte_mapping() here because
- * it could return a confusing result if called from a secondary cpu
- * prior to finalizing caps. Instead, linear_map_requires_bbml3 gives us
- * what we need.
+ * split:
+ *
+ * Do not call force_pte_mapping() here because it could return a
+ * confusing result if called from a secondary cpu prior to finalizing
+ * caps. Instead, retrieve that value with linear_map_requires_bbml3.
+ *
+ * Additionally, CONFIG_KFENCE may change permissions from atomic
+ * context so for this case (which is always pte-mapped), we must not go
+ * any further because taking the mutex below may sleep.
+ *
+ * Finally, set_memory_* can be called on PTE-mapped vmalloc mappings.
*/
- if (!linear_map_requires_bbml3 || is_kfence_address((void *)start))
+ force_pte = !linear_map_requires_bbml3 && linear_map_needs_set();
+ if (force_pte || is_kfence_address((void *)start) || !__is_lm_address(__tag_reset(start)))
return 0;
if (!system_supports_bbml3()) {
/*
- * BBML3 systems should not be trying to change
+ * Non-BBML3 systems should not be trying to change
* permissions on anything that is not pte-mapped in the first
* place. Just return early and let the permission change code
* raise a warning if not already pte-mapped.
diff --git a/arch/arm64/mm/pageattr.c b/arch/arm64/mm/pageattr.c
index c1ba74eb602f..f952cc125705 100644
--- a/arch/arm64/mm/pageattr.c
+++ b/arch/arm64/mm/pageattr.c
@@ -89,7 +89,7 @@ bool rodata_full __ro_after_init = true;
bool can_set_direct_map(void)
{
- return linear_map_needs_set();
+ return linear_map_needs_set() || system_supports_bbml3();
}
static int update_range_prot(unsigned long start, unsigned long size,
--
2.55.0.1082.g2b9226bbc0-goog
^ permalink raw reply related [flat|nested] 6+ messages in thread
* Re: [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page
2026-09-18 13:16 ` [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page Vincent Donnefort
@ 2026-09-22 5:55 ` Mike Rapoport
0 siblings, 0 replies; 6+ messages in thread
From: Mike Rapoport @ 2026-09-22 5:55 UTC (permalink / raw)
To: Vincent Donnefort
Cc: catalin.marinas, will, rafael, mark.rutland, lenb, pavel,
linux-arm-kernel, linux-pm, linux-kernel, thierry.reding
Hi Vincent,
On Fri, Sep 18, 2026 at 02:16:53PM +0100, Vincent Donnefort wrote:
> hibernate_map_page() is called from an atomic context. This is
> problematic for Arm BBML3 systems where the linear map may contain
> blocks and is allowed to split as splitting is a sleepable operation.
>
> Add arch hook so arm64 can define its own implementation without relying
> on the direct map.
I posted patches that remove set_direct_map usage from hibernation:
https://lore.kernel.org/all/20260917-hibernation-v1-0-7f7dfae3dbe0@kernel.org
So I really hope this patch won't be needed :)
> Signed-off-by: Vincent Donnefort <vdonnefort@google.com>
> ---
> include/linux/suspend.h | 2 ++
> kernel/power/snapshot.c | 10 ++++++----
> 2 files changed, 8 insertions(+), 4 deletions(-)
>
> diff --git a/include/linux/suspend.h b/include/linux/suspend.h
> index b02876f1ae38..10fe2298d94e 100644
> --- a/include/linux/suspend.h
> +++ b/include/linux/suspend.h
> @@ -401,6 +401,8 @@ int hibernate_quiet_exec(int (*func)(void *data), void *data);
> int hibernate_resume_nonboot_cpu_disable(void);
> int arch_hibernation_header_save(void *addr, unsigned int max_size);
> int arch_hibernation_header_restore(void *addr);
> +void *hibernate_map_page(struct page *page);
> +void hibernate_unmap_page(struct page *page);
>
> #else /* CONFIG_HIBERNATION */
> static inline void register_nosave_region(unsigned long b, unsigned long e) {}
> diff --git a/kernel/power/snapshot.c b/kernel/power/snapshot.c
> index b209712cb2c3..b41952f1de2a 100644
> --- a/kernel/power/snapshot.c
> +++ b/kernel/power/snapshot.c
> @@ -85,7 +85,7 @@ static inline int hibernate_restore_unprotect_page(void *page_address) {return 0
> * It is still worth to have a warning here if something changes and this
> * will no longer be the case.
> */
> -static inline void hibernate_map_page(struct page *page)
> +void * __weak hibernate_map_page(struct page *page)
> {
> if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
> int ret = set_direct_map_default_noflush(page);
> @@ -95,9 +95,10 @@ static inline void hibernate_map_page(struct page *page)
> } else {
> debug_pagealloc_map_pages(page, 1);
> }
> + return page_address(page);
> }
>
> -static inline void hibernate_unmap_page(struct page *page)
> +void __weak hibernate_unmap_page(struct page *page)
> {
> if (IS_ENABLED(CONFIG_ARCH_HAS_SET_DIRECT_MAP)) {
> unsigned long addr = (unsigned long)page_address(page);
> @@ -1456,8 +1457,9 @@ static bool safe_copy_page(void *dst, struct page *s_page)
> if (kernel_page_present(s_page)) {
> zeros_only = do_copy_page(dst, page_address(s_page));
> } else {
> - hibernate_map_page(s_page);
> - zeros_only = do_copy_page(dst, page_address(s_page));
> + void *src = hibernate_map_page(s_page);
> +
> + zeros_only = do_copy_page(dst, src);
> hibernate_unmap_page(s_page);
> }
> return zeros_only;
> --
> 2.55.0.1082.g2b9226bbc0-goog
>
--
Sincerely yours,
Mike.
^ permalink raw reply [flat|nested] 6+ messages in thread
end of thread, other threads:[~2026-09-22 5:55 UTC | newest]
Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2026-09-18 13:16 [PATCH v1 0/4] arm64: mm: Allow set_direct_map functions on BBML3 systems Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 1/4] PM: hibernate: Add arch specific hooks for hibernate_map/unmap_page Vincent Donnefort
2026-09-22 5:55 ` Mike Rapoport
2026-09-18 13:16 ` [PATCH v1 2/4] arm64: hibernate: Use fixmap " Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 3/4] arm64: mm: Introduce linear_map_needs_set() helper Vincent Donnefort
2026-09-18 13:16 ` [PATCH v1 4/4] arm64: mm: Allow can_set_direct_map() on BBML3 systems Vincent Donnefort
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.