]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
powerpc/code-patching: Avoid r/w mapping of the zero page
authorArd Biesheuvel <ardb@kernel.org>
Fri, 29 May 2026 15:02:02 +0000 (17:02 +0200)
committerWill Deacon <will@kernel.org>
Tue, 2 Jun 2026 15:29:16 +0000 (16:29 +0100)
The only remaining use of map_patch_area() is mapping the zero page, and
immediately unmapping it again so that the intermediate page table
levels are all guaranteed to be populated.

The use of the zero page here is completely arbitrary, and not harmful
per se, but currently, it creates a writable mapping, and does so in a
manner that requires that the empty_zero_page[] symbol is not
const-qualified.

Given that this is about to change, and that map_patch_area() now never
maps anything other than the zero page, let's simplify the code and
- remove the helpers and call [un]map_kernel_page() directly
- take the PA of empty_zero_page directly
- create a read-only temporary mapping.

This allows empty_zero_page[] to be repainted as const u8[] in a
subsequent patch, without making substantial changes to this code
patching logic.

Cc: Madhavan Srinivasan <maddy@linux.ibm.com>
Cc: Michael Ellerman <mpe@ellerman.id.au>
Cc: Nicholas Piggin <npiggin@gmail.com>
Cc: Christophe Leroy (CS GROUP) <chleroy@kernel.org>
Link: https://lore.kernel.org/all/20260520085423.485402-1-ardb@kernel.org/
Signed-off-by: Ard Biesheuvel <ardb@kernel.org>
Signed-off-by: Will Deacon <will@kernel.org>
arch/powerpc/lib/code-patching.c

index f84e0337cc0296ed81a6aa5bd1534de10ad8af0c..44ff9f684befa67f0034da5997988b38cc4f22f6 100644 (file)
@@ -60,9 +60,6 @@ struct patch_context {
 
 static DEFINE_PER_CPU(struct patch_context, cpu_patching_context);
 
-static int map_patch_area(void *addr, unsigned long text_poke_addr);
-static void unmap_patch_area(unsigned long addr);
-
 static bool mm_patch_enabled(void)
 {
        return IS_ENABLED(CONFIG_SMP) && radix_enabled();
@@ -117,11 +114,11 @@ static int text_area_cpu_up(unsigned int cpu)
 
        // Map/unmap the area to ensure all page tables are pre-allocated
        addr = (unsigned long)area->addr;
-       err = map_patch_area(empty_zero_page, addr);
+       err = map_kernel_page(addr, __pa_symbol(empty_zero_page), PAGE_KERNEL_RO);
        if (err)
                return err;
 
-       unmap_patch_area(addr);
+       unmap_kernel_page(addr);
 
        this_cpu_write(cpu_patching_context.area, area);
        this_cpu_write(cpu_patching_context.addr, addr);
@@ -233,51 +230,6 @@ static unsigned long get_patch_pfn(void *addr)
                return __pa_symbol(addr) >> PAGE_SHIFT;
 }
 
-/*
- * This can be called for kernel text or a module.
- */
-static int map_patch_area(void *addr, unsigned long text_poke_addr)
-{
-       unsigned long pfn = get_patch_pfn(addr);
-
-       return map_kernel_page(text_poke_addr, (pfn << PAGE_SHIFT), PAGE_KERNEL);
-}
-
-static void unmap_patch_area(unsigned long addr)
-{
-       pte_t *ptep;
-       pmd_t *pmdp;
-       pud_t *pudp;
-       p4d_t *p4dp;
-       pgd_t *pgdp;
-
-       pgdp = pgd_offset_k(addr);
-       if (WARN_ON(pgd_none(*pgdp)))
-               return;
-
-       p4dp = p4d_offset(pgdp, addr);
-       if (WARN_ON(p4d_none(*p4dp)))
-               return;
-
-       pudp = pud_offset(p4dp, addr);
-       if (WARN_ON(pud_none(*pudp)))
-               return;
-
-       pmdp = pmd_offset(pudp, addr);
-       if (WARN_ON(pmd_none(*pmdp)))
-               return;
-
-       ptep = pte_offset_kernel(pmdp, addr);
-       if (WARN_ON(pte_none(*ptep)))
-               return;
-
-       /*
-        * In hash, pte_clear flushes the tlb, in radix, we have to
-        */
-       pte_clear(&init_mm, addr, ptep);
-       flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
-}
-
 static int __do_patch_mem_mm(void *addr, unsigned long val, bool is_dword)
 {
        int err;