LoongArch, bpf: Use 4 instructions for function address in JIT
authorHengqi Chen <hengqi.chen@gmail.com>
Tue, 14 Feb 2023 15:26:33 +0000 (15:26 +0000)
committerDaniel Borkmann <daniel@iogearbox.net>
Fri, 17 Feb 2023 16:43:07 +0000 (17:43 +0100)
This patch fixes the following issue of function calls in JIT, like:

  [   29.346981] multi-func JIT bug 105 != 103

The issus can be reproduced by running the "inline simple bpf_loop call"
verifier test.

This is because we are emiting 2-4 instructions for 64-bit immediate moves.
During the first pass of JIT, the placeholder address is zero, emiting two
instructions for it. In the extra pass, the function address is in XKVRANGE,
emiting four instructions for it. This change the instruction index in
JIT context. Let's always use 4 instructions for function address in JIT.
So that the instruction sequences don't change between the first pass and
the extra pass for function calls.

Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support")
Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com>
Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>
Tested-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Link: https://lore.kernel.org/bpf/20230214152633.2265699-1-hengqi.chen@gmail.com
arch/loongarch/net/bpf_jit.c
arch/loongarch/net/bpf_jit.h

index c4b1947ebf768fb222e23fdd9a93796c83690dad..288003a9f0cae478a058102a6413e15a07585b29 100644 (file)
@@ -841,7 +841,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
                if (ret < 0)
                        return ret;
 
-               move_imm(ctx, t1, func_addr, is32);
+               move_addr(ctx, t1, func_addr);
                emit_insn(ctx, jirl, t1, LOONGARCH_GPR_RA, 0);
                move_reg(ctx, regmap[BPF_REG_0], LOONGARCH_GPR_A0);
                break;
index ca708024fdd3e61f6859b76c125d2bda64989d21..c335dc4eed370e6b8cedfc995bd96c6e323fd505 100644 (file)
@@ -82,6 +82,27 @@ static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, boo
        emit_insn(ctx, addiw, reg, reg, 0);
 }
 
+static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 addr)
+{
+       u64 imm_11_0, imm_31_12, imm_51_32, imm_63_52;
+
+       /* lu12iw rd, imm_31_12 */
+       imm_31_12 = (addr >> 12) & 0xfffff;
+       emit_insn(ctx, lu12iw, rd, imm_31_12);
+
+       /* ori rd, rd, imm_11_0 */
+       imm_11_0 = addr & 0xfff;
+       emit_insn(ctx, ori, rd, rd, imm_11_0);
+
+       /* lu32id rd, imm_51_32 */
+       imm_51_32 = (addr >> 32) & 0xfffff;
+       emit_insn(ctx, lu32id, rd, imm_51_32);
+
+       /* lu52id rd, rd, imm_63_52 */
+       imm_63_52 = (addr >> 52) & 0xfff;
+       emit_insn(ctx, lu52id, rd, rd, imm_63_52);
+}
+
 static inline void move_imm(struct jit_ctx *ctx, enum loongarch_gpr rd, long imm, bool is32)
 {
        long imm_11_0, imm_31_12, imm_51_32, imm_63_52, imm_51_0, imm_51_31;