FILE
patching.c
File preview with syntax highlighting.
linux-6.19.14/arch/openrisc/kernel/patching.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.