Skip to content

Support trampoline for LoongArch #5483

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 4 commits into
base: bpf-next_base
Choose a base branch
from
Open
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
57 changes: 57 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,34 @@ int larch_insn_patch_text(void *addr, u32 insn)
return ret;
}

int larch_insn_text_copy(void *dst, void *src, size_t len)
{
unsigned long flags;
size_t wlen = 0;
size_t size;
void *ptr;
int ret = 0;

set_memory_rw((unsigned long)dst, round_up(len, PAGE_SIZE) / PAGE_SIZE);
raw_spin_lock_irqsave(&patch_lock, flags);
while (wlen < len) {
ptr = dst + wlen;
size = min_t(size_t, PAGE_SIZE - offset_in_page(ptr),
len - wlen);

ret = copy_to_kernel_nofault(ptr, src + wlen, size);
if (ret) {
pr_err("%s: operation failed\n", __func__);
break;
}
wlen += size;
}
raw_spin_unlock_irqrestore(&patch_lock, flags);
set_memory_rox((unsigned long)dst, round_up(len, PAGE_SIZE) / PAGE_SIZE);

return ret;
}

u32 larch_insn_gen_nop(void)
{
return INSN_NOP;
Expand Down Expand Up @@ -336,3 +365,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, rd, rj, 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