Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/openrisc/kernel/patching.c
29524 views
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
}
80
81