Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions arch/loongarch/include/asm/inst.h
Original file line number Diff line number Diff line change
Expand Up @@ -497,6 +497,7 @@ void arch_simulate_insn(union loongarch_instruction insn, struct pt_regs *regs);
int larch_insn_read(void *addr, u32 *insnp);
int larch_insn_write(void *addr, u32 insn);
int larch_insn_patch_text(void *addr, u32 insn);
int larch_insn_text_copy(void *dst, void *src, size_t len);

u32 larch_insn_gen_nop(void);
u32 larch_insn_gen_b(unsigned long pc, unsigned long dest);
Expand All @@ -511,6 +512,8 @@ u32 larch_insn_gen_lu12iw(enum loongarch_gpr rd, int imm);
u32 larch_insn_gen_lu32id(enum loongarch_gpr rd, int imm);
u32 larch_insn_gen_lu52id(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
u32 larch_insn_gen_beq(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);
u32 larch_insn_gen_bne(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm);

static inline bool signed_imm_check(long val, unsigned int bit)
{
Expand Down
55 changes: 55 additions & 0 deletions arch/loongarch/kernel/inst.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
*/
#include <linux/sizes.h>
#include <linux/uaccess.h>
#include <linux/set_memory.h>

#include <asm/cacheflush.h>
#include <asm/inst.h>
Expand Down Expand Up @@ -218,6 +219,32 @@ int larch_insn_patch_text(void *addr, u32 insn)
return ret;
}

int larch_insn_text_copy(void *dst, void *src, size_t len)
{
int ret;
unsigned long flags;
unsigned long dst_start, dst_end, dst_len;

dst_start = round_down((unsigned long)dst, PAGE_SIZE);
dst_end = round_up((unsigned long)dst + len, PAGE_SIZE);
dst_len = dst_end - dst_start;

set_memory_rw(dst_start, dst_len / PAGE_SIZE);
raw_spin_lock_irqsave(&patch_lock, flags);

ret = copy_to_kernel_nofault(dst, src, len);
if (ret)
pr_err("%s: operation failed\n", __func__);

raw_spin_unlock_irqrestore(&patch_lock, flags);
set_memory_rox(dst_start, dst_len / PAGE_SIZE);

if (!ret)
flush_icache_range((unsigned long)dst, (unsigned long)dst + len);

return ret;
}

u32 larch_insn_gen_nop(void)
{
return INSN_NOP;
Expand Down Expand Up @@ -336,3 +363,31 @@ u32 larch_insn_gen_jirl(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)

return insn.word;
}

u32 larch_insn_gen_beq(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
{
union loongarch_instruction insn;

if ((imm & 3) || imm < -SZ_128K || imm >= SZ_128K) {
pr_warn("The generated beq instruction is out of range.\n");
return INSN_BREAK;
}

emit_beq(&insn, rj, rd, imm >> 2);

return insn.word;
}

u32 larch_insn_gen_bne(enum loongarch_gpr rd, enum loongarch_gpr rj, int imm)
{
union loongarch_instruction insn;

if ((imm & 3) || imm < -SZ_128K || imm >= SZ_128K) {
pr_warn("The generated bne instruction is out of range.\n");
return INSN_BREAK;
}

emit_bne(&insn, rj, rd, imm >> 2);

return insn.word;
}
Loading
Loading