Skip to content

Commit 4735037

Browse files
ChenMiaoistffrdhrn
authored andcommitted
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 <[email protected]> Signed-off-by: Stafford Horne <[email protected]>
1 parent 76eeb9b commit 4735037

File tree

7 files changed

+111
-2
lines changed

7 files changed

+111
-2
lines changed

arch/openrisc/include/asm/Kbuild

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,3 @@ generic-y += spinlock.h
99
generic-y += qrwlock_types.h
1010
generic-y += qrwlock.h
1111
generic-y += user.h
12-
generic-y += text-patching.h

arch/openrisc/include/asm/fixmap.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@
2828

2929
enum fixed_addresses {
3030
FIX_EARLYCON_MEM_BASE,
31+
FIX_TEXT_POKE0,
3132
__end_of_fixed_addresses
3233
};
3334

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2025 Chen Miao
4+
*/
5+
6+
#ifndef __ASM_OPENRISC_INSN_DEF_H
7+
#define __ASM_OPENRISC_INSN_DEF_H
8+
9+
/* or1k instructions are always 32 bits. */
10+
#define OPENRISC_INSN_SIZE 4
11+
12+
#endif /* __ASM_OPENRISC_INSN_DEF_H */
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
/* SPDX-License-Identifier: GPL-2.0-only */
2+
/*
3+
* Copyright (C) 2025 Chen Miao
4+
*/
5+
6+
#ifndef _ASM_OPENRISC_PATCHING_H
7+
#define _ASM_OPENRISC_PATCHING_H
8+
9+
#include <linux/types.h>
10+
11+
int patch_insn_write(void *addr, u32 insn);
12+
13+
#endif /* _ASM_OPENRISC_PATCHING_H */

arch/openrisc/kernel/Makefile

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,5 +13,6 @@ obj-$(CONFIG_SMP) += smp.o sync-timer.o
1313
obj-$(CONFIG_STACKTRACE) += stacktrace.o
1414
obj-$(CONFIG_MODULES) += module.o
1515
obj-$(CONFIG_OF) += prom.o
16+
obj-y += patching.o
1617

1718
clean:

arch/openrisc/kernel/patching.c

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
// SPDX-License-Identifier: GPL-2.0-only
2+
/* Copyright (C) 2020 SiFive
3+
* Copyright (C) 2025 Chen Miao
4+
*/
5+
6+
#include <linux/mm.h>
7+
#include <linux/kernel.h>
8+
#include <linux/spinlock.h>
9+
#include <linux/uaccess.h>
10+
11+
#include <asm/insn-def.h>
12+
#include <asm/cacheflush.h>
13+
#include <asm/page.h>
14+
#include <asm/fixmap.h>
15+
#include <asm/text-patching.h>
16+
#include <asm/sections.h>
17+
18+
static DEFINE_RAW_SPINLOCK(patch_lock);
19+
20+
static __always_inline void *patch_map(void *addr, int fixmap)
21+
{
22+
uintptr_t uaddr = (uintptr_t) addr;
23+
phys_addr_t phys;
24+
25+
if (core_kernel_text(uaddr)) {
26+
phys = __pa_symbol(addr);
27+
} else {
28+
struct page *page = vmalloc_to_page(addr);
29+
BUG_ON(!page);
30+
phys = page_to_phys(page) + offset_in_page(addr);
31+
}
32+
33+
return (void *)set_fixmap_offset(fixmap, phys);
34+
}
35+
36+
static void patch_unmap(int fixmap)
37+
{
38+
clear_fixmap(fixmap);
39+
}
40+
41+
static int __patch_insn_write(void *addr, u32 insn)
42+
{
43+
void *waddr = addr;
44+
unsigned long flags = 0;
45+
int ret;
46+
47+
raw_spin_lock_irqsave(&patch_lock, flags);
48+
49+
waddr = patch_map(addr, FIX_TEXT_POKE0);
50+
51+
ret = copy_to_kernel_nofault(waddr, &insn, OPENRISC_INSN_SIZE);
52+
local_icache_range_inv((unsigned long)waddr,
53+
(unsigned long)waddr + OPENRISC_INSN_SIZE);
54+
55+
patch_unmap(FIX_TEXT_POKE0);
56+
57+
raw_spin_unlock_irqrestore(&patch_lock, flags);
58+
59+
return ret;
60+
}
61+
62+
/*
63+
* patch_insn_write - Write a single instruction to a specified memory location
64+
* This API provides a single-instruction patching, primarily used for runtime
65+
* code modification.
66+
* By the way, the insn size must be 4 bytes.
67+
*/
68+
int patch_insn_write(void *addr, u32 insn)
69+
{
70+
u32 *tp = addr;
71+
int ret;
72+
73+
if ((uintptr_t) tp & 0x3)
74+
return -EINVAL;
75+
76+
ret = __patch_insn_write(tp, insn);
77+
78+
return ret;
79+
}

arch/openrisc/mm/init.c

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -226,7 +226,11 @@ static int __init map_page(unsigned long va, phys_addr_t pa, pgprot_t prot)
226226
return 0;
227227
}
228228

229-
void __init __set_fixmap(enum fixed_addresses idx,
229+
/*
230+
* __set_fix must now support both EARLYCON and TEXT_POKE mappings,
231+
* which are used at different stages of kernel execution.
232+
*/
233+
void __set_fixmap(enum fixed_addresses idx,
230234
phys_addr_t phys, pgprot_t prot)
231235
{
232236
unsigned long address = __fix_to_virt(idx);

0 commit comments

Comments
 (0)