Skip to content

Commit c069315

Browse files
ardbiesheuvelwilldeacon
authored andcommitted
powerpc/code-patching: Avoid r/w mapping of the zero page
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>
1 parent d672a4b commit c069315

1 file changed

Lines changed: 2 additions & 50 deletions

File tree

arch/powerpc/lib/code-patching.c

Lines changed: 2 additions & 50 deletions
Original file line numberDiff line numberDiff line change
@@ -60,9 +60,6 @@ struct patch_context {
6060

6161
static DEFINE_PER_CPU(struct patch_context, cpu_patching_context);
6262

63-
static int map_patch_area(void *addr, unsigned long text_poke_addr);
64-
static void unmap_patch_area(unsigned long addr);
65-
6663
static bool mm_patch_enabled(void)
6764
{
6865
return IS_ENABLED(CONFIG_SMP) && radix_enabled();
@@ -117,11 +114,11 @@ static int text_area_cpu_up(unsigned int cpu)
117114

118115
// Map/unmap the area to ensure all page tables are pre-allocated
119116
addr = (unsigned long)area->addr;
120-
err = map_patch_area(empty_zero_page, addr);
117+
err = map_kernel_page(addr, __pa_symbol(empty_zero_page), PAGE_KERNEL_RO);
121118
if (err)
122119
return err;
123120

124-
unmap_patch_area(addr);
121+
unmap_kernel_page(addr);
125122

126123
this_cpu_write(cpu_patching_context.area, area);
127124
this_cpu_write(cpu_patching_context.addr, addr);
@@ -233,51 +230,6 @@ static unsigned long get_patch_pfn(void *addr)
233230
return __pa_symbol(addr) >> PAGE_SHIFT;
234231
}
235232

236-
/*
237-
* This can be called for kernel text or a module.
238-
*/
239-
static int map_patch_area(void *addr, unsigned long text_poke_addr)
240-
{
241-
unsigned long pfn = get_patch_pfn(addr);
242-
243-
return map_kernel_page(text_poke_addr, (pfn << PAGE_SHIFT), PAGE_KERNEL);
244-
}
245-
246-
static void unmap_patch_area(unsigned long addr)
247-
{
248-
pte_t *ptep;
249-
pmd_t *pmdp;
250-
pud_t *pudp;
251-
p4d_t *p4dp;
252-
pgd_t *pgdp;
253-
254-
pgdp = pgd_offset_k(addr);
255-
if (WARN_ON(pgd_none(*pgdp)))
256-
return;
257-
258-
p4dp = p4d_offset(pgdp, addr);
259-
if (WARN_ON(p4d_none(*p4dp)))
260-
return;
261-
262-
pudp = pud_offset(p4dp, addr);
263-
if (WARN_ON(pud_none(*pudp)))
264-
return;
265-
266-
pmdp = pmd_offset(pudp, addr);
267-
if (WARN_ON(pmd_none(*pmdp)))
268-
return;
269-
270-
ptep = pte_offset_kernel(pmdp, addr);
271-
if (WARN_ON(pte_none(*ptep)))
272-
return;
273-
274-
/*
275-
* In hash, pte_clear flushes the tlb, in radix, we have to
276-
*/
277-
pte_clear(&init_mm, addr, ptep);
278-
flush_tlb_kernel_range(addr, addr + PAGE_SIZE);
279-
}
280-
281233
static int __do_patch_mem_mm(void *addr, unsigned long val, bool is_dword)
282234
{
283235
int err;

0 commit comments

Comments
 (0)