File Index
Files and directories
Sign in
FILE

patching.c

File preview with syntax highlighting.

linux-6.19.14/arch/openrisc/kernel/patching.c C
 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
18static DEFINE_RAW_SPINLOCK(patch_lock);
19
20static __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
36static void patch_unmap(int fixmap)
37{
38	clear_fixmap(fixmap);
39}
40
41static 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 */
68int 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}
~/ Read-only file preview.