1 // SPDX-License-Identifier: GPL-2.0
3 * Copyright (C) 2020-2022 Loongson Technology Corporation Limited
5 #include <linux/sizes.h>
6 #include <linux/uaccess.h>
8 #include <asm/cacheflush.h>
11 static DEFINE_RAW_SPINLOCK(patch_lock);
13 int larch_insn_read(void *addr, u32 *insnp)
18 ret = copy_from_kernel_nofault(&val, addr, LOONGARCH_INSN_SIZE);
25 int larch_insn_write(void *addr, u32 insn)
28 unsigned long flags = 0;
30 raw_spin_lock_irqsave(&patch_lock, flags);
31 ret = copy_to_kernel_nofault(addr, &insn, LOONGARCH_INSN_SIZE);
32 raw_spin_unlock_irqrestore(&patch_lock, flags);
37 int larch_insn_patch_text(void *addr, u32 insn)
42 if ((unsigned long)tp & 3)
45 ret = larch_insn_write(tp, insn);
47 flush_icache_range((unsigned long)tp,
48 (unsigned long)tp + LOONGARCH_INSN_SIZE);
53 u32 larch_insn_gen_nop(void)
58 u32 larch_insn_gen_b(unsigned long pc, unsigned long dest)
60 long offset = dest - pc;
61 union loongarch_instruction insn;
63 if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
64 pr_warn("The generated b instruction is out of range.\n");
68 emit_b(&insn, offset >> 2);
73 u32 larch_insn_gen_bl(unsigned long pc, unsigned long dest)
75 long offset = dest - pc;
76 union loongarch_instruction insn;
78 if ((offset & 3) || offset < -SZ_128M || offset >= SZ_128M) {
79 pr_warn("The generated bl instruction is out of range.\n");
83 emit_bl(&insn, offset >> 2);
88 u32 larch_insn_gen_or(enum loongarch_gpr rd, enum loongarch_gpr rj, enum loongarch_gpr rk)
90 union loongarch_instruction insn;
92 emit_or(&insn, rd, rj, rk);
97 u32 larch_insn_gen_move(enum loongarch_gpr rd, enum loongarch_gpr rj)
99 return larch_insn_gen_or(rd, rj, 0);
102 u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm)
104 union loongarch_instruction insn;
106 emit_lu12iw(&insn, rd, imm);
111 u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm)
113 union loongarch_instruction insn;
115 emit_lu32id(&insn, rd, imm);
120 u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
122 union loongarch_instruction insn;
124 emit_lu52id(&insn, rd, rj, imm);
129 u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, unsigned long pc, unsigned long dest)
131 union loongarch_instruction insn;
133 emit_jirl(&insn, rj, rd, (dest - pc) >> 2);