mirror of
https://github.com/torvalds/linux.git
synced 2026-07-27 17:47:41 +02:00
openrisc: Add text patching API support
Add text patching api's to use in subsequent jump_label implementation. We use a new fixmap FIX_TEXT_POKE0 entry to temporarily override MMU mappings to allow read only text pages to be written to. Previously, __set_fix was marked with __init as it was only used during the EARLYCON stage. Now that TEXT_POKE mappings require post-init usage (e.g., FIX_TEXT_POKE0), keeping __init would cause runtime bugs whenset_fixmap accesses invalid memory. Thus, we remove the __init flag to ensure __set_fix remains valid beyond initialization. A new function patch_insn_write is exposed to allow single instruction patching. Link: https://lore.kernel.org/openrisc/aJIC8o1WmVHol9RY@antec/T/#t Signed-off-by: chenmiao <chenmiao.ku@gmail.com> Signed-off-by: Stafford Horne <shorne@gmail.com>
This commit is contained in:
parent
76eeb9b8de
commit
4735037b5d
|
|
@ -9,4 +9,3 @@ generic-y += spinlock.h
|
|||
generic-y += qrwlock_types.h
|
||||
generic-y += qrwlock.h
|
||||
generic-y += user.h
|
||||
generic-y += text-patching.h
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
|
||||
enum fixed_addresses {
|
||||
FIX_EARLYCON_MEM_BASE,
|
||||
FIX_TEXT_POKE0,
|
||||
__end_of_fixed_addresses
|
||||
};
|
||||
|
||||
|
|
|
|||
12
arch/openrisc/include/asm/insn-def.h
Normal file
12
arch/openrisc/include/asm/insn-def.h
Normal file
|
|
@ -0,0 +1,12 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2025 Chen Miao
|
||||
*/
|
||||
|
||||
#ifndef __ASM_OPENRISC_INSN_DEF_H
|
||||
#define __ASM_OPENRISC_INSN_DEF_H
|
||||
|
||||
/* or1k instructions are always 32 bits. */
|
||||
#define OPENRISC_INSN_SIZE 4
|
||||
|
||||
#endif /* __ASM_OPENRISC_INSN_DEF_H */
|
||||
13
arch/openrisc/include/asm/text-patching.h
Normal file
13
arch/openrisc/include/asm/text-patching.h
Normal file
|
|
@ -0,0 +1,13 @@
|
|||
/* SPDX-License-Identifier: GPL-2.0-only */
|
||||
/*
|
||||
* Copyright (C) 2025 Chen Miao
|
||||
*/
|
||||
|
||||
#ifndef _ASM_OPENRISC_PATCHING_H
|
||||
#define _ASM_OPENRISC_PATCHING_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
int patch_insn_write(void *addr, u32 insn);
|
||||
|
||||
#endif /* _ASM_OPENRISC_PATCHING_H */
|
||||
|
|
@ -13,5 +13,6 @@ obj-$(CONFIG_SMP) += smp.o sync-timer.o
|
|||
obj-$(CONFIG_STACKTRACE) += stacktrace.o
|
||||
obj-$(CONFIG_MODULES) += module.o
|
||||
obj-$(CONFIG_OF) += prom.o
|
||||
obj-y += patching.o
|
||||
|
||||
clean:
|
||||
|
|
|
|||
79
arch/openrisc/kernel/patching.c
Normal file
79
arch/openrisc/kernel/patching.c
Normal file
|
|
@ -0,0 +1,79 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/* Copyright (C) 2020 SiFive
|
||||
* Copyright (C) 2025 Chen Miao
|
||||
*/
|
||||
|
||||
#include <linux/mm.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/spinlock.h>
|
||||
#include <linux/uaccess.h>
|
||||
|
||||
#include <asm/insn-def.h>
|
||||
#include <asm/cacheflush.h>
|
||||
#include <asm/page.h>
|
||||
#include <asm/fixmap.h>
|
||||
#include <asm/text-patching.h>
|
||||
#include <asm/sections.h>
|
||||
|
||||
static DEFINE_RAW_SPINLOCK(patch_lock);
|
||||
|
||||
static __always_inline void *patch_map(void *addr, int fixmap)
|
||||
{
|
||||
uintptr_t uaddr = (uintptr_t) addr;
|
||||
phys_addr_t phys;
|
||||
|
||||
if (core_kernel_text(uaddr)) {
|
||||
phys = __pa_symbol(addr);
|
||||
} else {
|
||||
struct page *page = vmalloc_to_page(addr);
|
||||
BUG_ON(!page);
|
||||
phys = page_to_phys(page) + offset_in_page(addr);
|
||||
}
|
||||
|
||||
return (void *)set_fixmap_offset(fixmap, phys);
|
||||
}
|
||||
|
||||
static void patch_unmap(int fixmap)
|
||||
{
|
||||
clear_fixmap(fixmap);
|
||||
}
|
||||
|
||||
static int __patch_insn_write(void *addr, u32 insn)
|
||||
{
|
||||
void *waddr = addr;
|
||||
unsigned long flags = 0;
|
||||
int ret;
|
||||
|
||||
raw_spin_lock_irqsave(&patch_lock, flags);
|
||||
|
||||
waddr = patch_map(addr, FIX_TEXT_POKE0);
|
||||
|
||||
ret = copy_to_kernel_nofault(waddr, &insn, OPENRISC_INSN_SIZE);
|
||||
local_icache_range_inv((unsigned long)waddr,
|
||||
(unsigned long)waddr + OPENRISC_INSN_SIZE);
|
||||
|
||||
patch_unmap(FIX_TEXT_POKE0);
|
||||
|
||||
raw_spin_unlock_irqrestore(&patch_lock, flags);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
* patch_insn_write - Write a single instruction to a specified memory location
|
||||
* This API provides a single-instruction patching, primarily used for runtime
|
||||
* code modification.
|
||||
* By the way, the insn size must be 4 bytes.
|
||||
*/
|
||||
int patch_insn_write(void *addr, u32 insn)
|
||||
{
|
||||
u32 *tp = addr;
|
||||
int ret;
|
||||
|
||||
if ((uintptr_t) tp & 0x3)
|
||||
return -EINVAL;
|
||||
|
||||
ret = __patch_insn_write(tp, insn);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
|
@ -226,7 +226,11 @@ static int __init map_page(unsigned long va, phys_addr_t pa, pgprot_t prot)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __init __set_fixmap(enum fixed_addresses idx,
|
||||
/*
|
||||
* __set_fix must now support both EARLYCON and TEXT_POKE mappings,
|
||||
* which are used at different stages of kernel execution.
|
||||
*/
|
||||
void __set_fixmap(enum fixed_addresses idx,
|
||||
phys_addr_t phys, pgprot_t prot)
|
||||
{
|
||||
unsigned long address = __fix_to_virt(idx);
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user