From: Yeoreum Yun <yeoreum.yun@arm.com>
To: Kevin Brodsky <kevin.brodsky@arm.com>
Cc: linux-arm-kernel@lists.infradead.org,
linux-kernel@vger.kernel.org, Ryan Roberts <ryan.roberts@arm.com>,
Ard Biesheuvel <ardb@kernel.org>,
Anshuman Khandual <anshuman.khandual@arm.com>,
Catalin Marinas <catalin.marinas@arm.com>,
Kees Cook <kees@kernel.org>, Mark Rutland <mark.rutland@arm.com>,
Suzuki K Poulose <suzuki.poulose@arm.com>,
Will Deacon <will@kernel.org>
Subject: Re: [PATCH v2] arm64: mm: Move KPTI helpers to mmu.c
Date: Fri, 12 Sep 2025 09:03:02 +0100 [thread overview]
Message-ID: <aMPTtrP07Li9uS2Q@e129823.arm.com> (raw)
In-Reply-To: <20250912073908.404924-1-kevin.brodsky@arm.com>
LGTM.
Reviewed-by: Yeoreum Yun <yeoreum.yun@arm.com>
> create_kpti_ng_temp_pgd() is currently defined (as an alias) in
> mmu.c without matching declaration in a header; instead cpufeature.c
> makes its own declaration. This is clearly not pretty, and as commit
> ceca927c86e6 ("arm64: mm: Fix CFI failure due to kpti_ng_pgd_alloc
> function signature") showed, it also makes it very easy for the
> prototypes to go out of sync.
>
> All this would be much simpler if kpti_install_ng_mappings() and
> associated functions lived in mmu.c, where they logically belong.
> This is what this patch does:
> - Move kpti_install_ng_mappings() and associated functions from
> cpufeature.c to mmu.c, add a declaration to <asm/mmu.h>
> - Remove create_kpti_ng_temp_pgd() and just call
> __create_pgd_mapping_locked() directly instead
> - Mark all these functions __init
> - Move __initdata after kpti_ng_temp_alloc (as suggested by
> checkpatch)
>
> Reviewed-by: Ryan Roberts <ryan.roberts@arm.com>
> Reviewed-by: Ard Biesheuvel <ardb@kernel.org>
> Reviewed-by: Anshuman Khandual <anshuman.khandual@arm.com>
> Signed-off-by: Kevin Brodsky <kevin.brodsky@arm.com>
> ---
> v1..v2:
> * Removed create_kpti_ng_temp_pgd() instead of making it a wrapper
> [Ryan's suggestion]
> * Added Reviewed-by's.
> ---
> Cc: Anshuman Khandual <anshuman.khandual@arm.com>
> Cc: Ard Biesheuvel <ardb@kernel.org>
> Cc: Catalin Marinas <catalin.marinas@arm.com>
> Cc: Kees Cook <kees@kernel.org>
> Cc: Mark Rutland <mark.rutland@arm.com>
> Cc: Ryan Roberts <ryan.roberts@arm.com>
> Cc: Suzuki K Poulose <suzuki.poulose@arm.com>
> Cc: Will Deacon <will@kernel.org>
> Cc: Yeoreum Yun <yeoreum.yun@arm.com>
> ---
> arch/arm64/include/asm/mmu.h | 6 +++
> arch/arm64/kernel/cpufeature.c | 97 ----------------------------------
> arch/arm64/mm/mmu.c | 96 +++++++++++++++++++++++++++++----
> 3 files changed, 93 insertions(+), 106 deletions(-)
>
> diff --git a/arch/arm64/include/asm/mmu.h b/arch/arm64/include/asm/mmu.h
> index 49f1a810df16..624edd6c4964 100644
> --- a/arch/arm64/include/asm/mmu.h
> +++ b/arch/arm64/include/asm/mmu.h
> @@ -104,5 +104,11 @@ static inline bool kaslr_requires_kpti(void)
> return true;
> }
>
> +#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> +void kpti_install_ng_mappings(void);
> +#else
> +static inline void kpti_install_ng_mappings(void) {}
> +#endif
> +
> #endif /* !__ASSEMBLY__ */
> #endif
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index ef269a5a37e1..b99eaad48c14 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1940,103 +1940,6 @@ static bool has_pmuv3(const struct arm64_cpu_capabilities *entry, int scope)
> }
> #endif
>
> -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> -#define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT))
> -
> -extern
> -void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
> - phys_addr_t size, pgprot_t prot,
> - phys_addr_t (*pgtable_alloc)(enum pgtable_type), int flags);
> -
> -static phys_addr_t __initdata kpti_ng_temp_alloc;
> -
> -static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
> -{
> - kpti_ng_temp_alloc -= PAGE_SIZE;
> - return kpti_ng_temp_alloc;
> -}
> -
> -static int __init __kpti_install_ng_mappings(void *__unused)
> -{
> - typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
> - extern kpti_remap_fn idmap_kpti_install_ng_mappings;
> - kpti_remap_fn *remap_fn;
> -
> - int cpu = smp_processor_id();
> - int levels = CONFIG_PGTABLE_LEVELS;
> - int order = order_base_2(levels);
> - u64 kpti_ng_temp_pgd_pa = 0;
> - pgd_t *kpti_ng_temp_pgd;
> - u64 alloc = 0;
> -
> - if (levels == 5 && !pgtable_l5_enabled())
> - levels = 4;
> - else if (levels == 4 && !pgtable_l4_enabled())
> - levels = 3;
> -
> - remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
> -
> - if (!cpu) {
> - alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> - kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
> - kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
> -
> - //
> - // Create a minimal page table hierarchy that permits us to map
> - // the swapper page tables temporarily as we traverse them.
> - //
> - // The physical pages are laid out as follows:
> - //
> - // +--------+-/-------+-/------ +-/------ +-\\\--------+
> - // : PTE[] : | PMD[] : | PUD[] : | P4D[] : ||| PGD[] :
> - // +--------+-\-------+-\------ +-\------ +-///--------+
> - // ^
> - // The first page is mapped into this hierarchy at a PMD_SHIFT
> - // aligned virtual address, so that we can manipulate the PTE
> - // level entries while the mapping is active. The first entry
> - // covers the PTE[] page itself, the remaining entries are free
> - // to be used as a ad-hoc fixmap.
> - //
> - create_kpti_ng_temp_pgd(kpti_ng_temp_pgd, __pa(alloc),
> - KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL,
> - kpti_ng_pgd_alloc, 0);
> - }
> -
> - cpu_install_idmap();
> - remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
> - cpu_uninstall_idmap();
> -
> - if (!cpu) {
> - free_pages(alloc, order);
> - arm64_use_ng_mappings = true;
> - }
> -
> - return 0;
> -}
> -
> -static void __init kpti_install_ng_mappings(void)
> -{
> - /* Check whether KPTI is going to be used */
> - if (!arm64_kernel_unmapped_at_el0())
> - return;
> -
> - /*
> - * We don't need to rewrite the page-tables if either we've done
> - * it already or we have KASLR enabled and therefore have not
> - * created any global mappings at all.
> - */
> - if (arm64_use_ng_mappings)
> - return;
> -
> - stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
> -}
> -
> -#else
> -static inline void kpti_install_ng_mappings(void)
> -{
> -}
> -#endif /* CONFIG_UNMAP_KERNEL_AT_EL0 */
> -
> static void cpu_enable_kpti(struct arm64_cpu_capabilities const *cap)
> {
> if (__this_cpu_read(this_cpu_vector) == vectors) {
> diff --git a/arch/arm64/mm/mmu.c b/arch/arm64/mm/mmu.c
> index 183801520740..6a8e831b2b63 100644
> --- a/arch/arm64/mm/mmu.c
> +++ b/arch/arm64/mm/mmu.c
> @@ -27,6 +27,7 @@
> #include <linux/kfence.h>
> #include <linux/pkeys.h>
> #include <linux/mm_inline.h>
> +#include <linux/stop_machine.h>
>
> #include <asm/barrier.h>
> #include <asm/cputype.h>
> @@ -466,14 +467,6 @@ static void __create_pgd_mapping(pgd_t *pgdir, phys_addr_t phys,
> mutex_unlock(&fixmap_lock);
> }
>
> -#ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> -extern __alias(__create_pgd_mapping_locked)
> -void create_kpti_ng_temp_pgd(pgd_t *pgdir, phys_addr_t phys, unsigned long virt,
> - phys_addr_t size, pgprot_t prot,
> - phys_addr_t (*pgtable_alloc)(enum pgtable_type),
> - int flags);
> -#endif
> -
> static phys_addr_t __pgd_pgtable_alloc(struct mm_struct *mm,
> enum pgtable_type pgtable_type)
> {
> @@ -735,7 +728,92 @@ static void __init declare_vma(struct vm_struct *vma,
> }
>
> #ifdef CONFIG_UNMAP_KERNEL_AT_EL0
> -static pgprot_t kernel_exec_prot(void)
> +#define KPTI_NG_TEMP_VA (-(1UL << PMD_SHIFT))
> +
> +static phys_addr_t kpti_ng_temp_alloc __initdata;
> +
> +static phys_addr_t __init kpti_ng_pgd_alloc(enum pgtable_type type)
> +{
> + kpti_ng_temp_alloc -= PAGE_SIZE;
> + return kpti_ng_temp_alloc;
> +}
> +
> +static int __init __kpti_install_ng_mappings(void *__unused)
> +{
> + typedef void (kpti_remap_fn)(int, int, phys_addr_t, unsigned long);
> + extern kpti_remap_fn idmap_kpti_install_ng_mappings;
> + kpti_remap_fn *remap_fn;
> +
> + int cpu = smp_processor_id();
> + int levels = CONFIG_PGTABLE_LEVELS;
> + int order = order_base_2(levels);
> + u64 kpti_ng_temp_pgd_pa = 0;
> + pgd_t *kpti_ng_temp_pgd;
> + u64 alloc = 0;
> +
> + if (levels == 5 && !pgtable_l5_enabled())
> + levels = 4;
> + else if (levels == 4 && !pgtable_l4_enabled())
> + levels = 3;
> +
> + remap_fn = (void *)__pa_symbol(idmap_kpti_install_ng_mappings);
> +
> + if (!cpu) {
> + alloc = __get_free_pages(GFP_ATOMIC | __GFP_ZERO, order);
> + kpti_ng_temp_pgd = (pgd_t *)(alloc + (levels - 1) * PAGE_SIZE);
> + kpti_ng_temp_alloc = kpti_ng_temp_pgd_pa = __pa(kpti_ng_temp_pgd);
> +
> + //
> + // Create a minimal page table hierarchy that permits us to map
> + // the swapper page tables temporarily as we traverse them.
> + //
> + // The physical pages are laid out as follows:
> + //
> + // +--------+-/-------+-/------ +-/------ +-\\\--------+
> + // : PTE[] : | PMD[] : | PUD[] : | P4D[] : ||| PGD[] :
> + // +--------+-\-------+-\------ +-\------ +-///--------+
> + // ^
> + // The first page is mapped into this hierarchy at a PMD_SHIFT
> + // aligned virtual address, so that we can manipulate the PTE
> + // level entries while the mapping is active. The first entry
> + // covers the PTE[] page itself, the remaining entries are free
> + // to be used as a ad-hoc fixmap.
> + //
> + __create_pgd_mapping_locked(kpti_ng_temp_pgd, __pa(alloc),
> + KPTI_NG_TEMP_VA, PAGE_SIZE, PAGE_KERNEL,
> + kpti_ng_pgd_alloc, 0);
> + }
> +
> + cpu_install_idmap();
> + remap_fn(cpu, num_online_cpus(), kpti_ng_temp_pgd_pa, KPTI_NG_TEMP_VA);
> + cpu_uninstall_idmap();
> +
> + if (!cpu) {
> + free_pages(alloc, order);
> + arm64_use_ng_mappings = true;
> + }
> +
> + return 0;
> +}
> +
> +void __init kpti_install_ng_mappings(void)
> +{
> + /* Check whether KPTI is going to be used */
> + if (!arm64_kernel_unmapped_at_el0())
> + return;
> +
> + /*
> + * We don't need to rewrite the page-tables if either we've done
> + * it already or we have KASLR enabled and therefore have not
> + * created any global mappings at all.
> + */
> + if (arm64_use_ng_mappings)
> + return;
> +
> + stop_machine(__kpti_install_ng_mappings, NULL, cpu_online_mask);
> +}
> +
> +static pgprot_t __init kernel_exec_prot(void)
> {
> return rodata_enabled ? PAGE_KERNEL_ROX : PAGE_KERNEL_EXEC;
> }
>
> base-commit: 76eeb9b8de9880ca38696b2fb56ac45ac0a25c6c
> --
> 2.47.0
>
--
Sincerely,
Yeoreum Yun
next prev parent reply other threads:[~2025-09-12 8:04 UTC|newest]
Thread overview: 6+ messages / expand[flat|nested] mbox.gz Atom feed top
2025-09-12 7:39 [PATCH v2] arm64: mm: Move KPTI helpers to mmu.c Kevin Brodsky
2025-09-12 8:03 ` Yeoreum Yun [this message]
2025-09-17 15:35 ` Will Deacon
2025-09-18 7:24 ` Kevin Brodsky
2025-09-25 15:32 ` Will Deacon
2025-09-30 14:24 ` Kevin Brodsky
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=aMPTtrP07Li9uS2Q@e129823.arm.com \
--to=yeoreum.yun@arm.com \
--cc=anshuman.khandual@arm.com \
--cc=ardb@kernel.org \
--cc=catalin.marinas@arm.com \
--cc=kees@kernel.org \
--cc=kevin.brodsky@arm.com \
--cc=linux-arm-kernel@lists.infradead.org \
--cc=linux-kernel@vger.kernel.org \
--cc=mark.rutland@arm.com \
--cc=ryan.roberts@arm.com \
--cc=suzuki.poulose@arm.com \
--cc=will@kernel.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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.