diff --git a/arch/loongarch/include/asm/inst.h b/arch/loongarch/include/asm/inst.h index 277d2140676b6..20f4fc745bea6 100644 --- a/arch/loongarch/include/asm/inst.h +++ b/arch/loongarch/include/asm/inst.h @@ -92,6 +92,8 @@ enum reg2i6_op { }; enum reg2i12_op { + slti_op = 0x08, + sltui_op = 0x09, addiw_op = 0x0a, addid_op = 0x0b, lu52id_op = 0x0c, @@ -148,6 +150,8 @@ enum reg3_op { addd_op = 0x21, subw_op = 0x22, subd_op = 0x23, + slt_op = 0x24, + sltu_op = 0x25, nor_op = 0x28, and_op = 0x29, or_op = 0x2a, @@ -629,6 +633,8 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \ insn->reg2i12_format.rj = rj; \ } +DEF_EMIT_REG2I12_FORMAT(slti, slti_op) +DEF_EMIT_REG2I12_FORMAT(sltui, sltui_op) DEF_EMIT_REG2I12_FORMAT(addiw, addiw_op) DEF_EMIT_REG2I12_FORMAT(addid, addid_op) DEF_EMIT_REG2I12_FORMAT(lu52id, lu52id_op) @@ -729,6 +735,8 @@ static inline void emit_##NAME(union loongarch_instruction *insn, \ DEF_EMIT_REG3_FORMAT(addw, addw_op) DEF_EMIT_REG3_FORMAT(addd, addd_op) DEF_EMIT_REG3_FORMAT(subd, subd_op) +DEF_EMIT_REG3_FORMAT(slt, slt_op) +DEF_EMIT_REG3_FORMAT(sltu, sltu_op) DEF_EMIT_REG3_FORMAT(muld, muld_op) DEF_EMIT_REG3_FORMAT(divd, divd_op) DEF_EMIT_REG3_FORMAT(modd, modd_op) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index abfdb6bb5c382..50067be79c4f7 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -229,8 +229,21 @@ static void __build_epilogue(struct jit_ctx *ctx, bool is_tail_call) emit_insn(ctx, addid, LOONGARCH_GPR_SP, LOONGARCH_GPR_SP, stack_adjust); if (!is_tail_call) { - /* Set return value */ - emit_insn(ctx, addiw, LOONGARCH_GPR_A0, regmap[BPF_REG_0], 0); + /* + * Set return value + * Check if the 64th bit in regmap[BPF_REG_0] is 1. If it is, + * the value in regmap[BPF_REG_0] is a kernel-space address. + + * long long val = regmap[BPF_REG_0]; + * int shift = 0 < val ? 32 : 0; + * return (val << shift) >> shift; + */ + move_reg(ctx, LOONGARCH_GPR_A0, regmap[BPF_REG_0]); + emit_insn(ctx, slt, LOONGARCH_GPR_T0, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_A0); + emit_insn(ctx, sllid, LOONGARCH_GPR_T0, LOONGARCH_GPR_T0, 5); + emit_insn(ctx, slld, LOONGARCH_GPR_A0, LOONGARCH_GPR_A0, LOONGARCH_GPR_T0); + emit_insn(ctx, srad, LOONGARCH_GPR_A0, LOONGARCH_GPR_A0, LOONGARCH_GPR_T0); + /* Return to the caller */ emit_insn(ctx, jirl, LOONGARCH_GPR_ZERO, LOONGARCH_GPR_RA, 0); } else {