The 8-bit and 16-bit read-modify-write instructions amadd.{b/h} and amswap.{b/h} were newly added in the new LoongArch Reference Manual, handle them to avoid the error of unknown opcode if possible. Signed-off-by: Tiezhu Yang --- arch/loongarch/net/bpf_jit.c | 83 ++++++++++++++++++++++++++++++++---- 1 file changed, 74 insertions(+), 9 deletions(-) diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index fefda4050a20..c9a32f124f5e 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -363,10 +363,30 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) switch (imm) { /* lock *(size *)(dst + off) = src */ case BPF_ADD: - if (isdw) - emit_insn(ctx, amaddd, t2, t1, src); - else + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (cpu_has_lam_bh) { + emit_insn(ctx, amaddb, t2, t1, src); + } else { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_H: + if (cpu_has_lam_bh) { + emit_insn(ctx, amaddh, t2, t1, src); + } else { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_W: emit_insn(ctx, amaddw, t2, t1, src); + break; + case BPF_DW: + emit_insn(ctx, amaddd, t2, t1, src); + break; + } break; case BPF_AND: if (isdw) @@ -388,11 +408,32 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_fetch_(dst + off, src) */ case BPF_ADD | BPF_FETCH: - if (isdw) { - emit_insn(ctx, amaddd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (cpu_has_lam_bh) { + emit_insn(ctx, amaddb, src, t1, t3); + emit_zext_32(ctx, src, true); + } else { + pr_err_once("bpf-jit: amadd.b instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_H: + if (cpu_has_lam_bh) { + emit_insn(ctx, amaddh, src, t1, t3); + emit_zext_32(ctx, src, true); + } else { + pr_err_once("bpf-jit: amadd.h instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_W: emit_insn(ctx, amaddw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amaddd, src, t1, t3); + break; } break; case BPF_AND | BPF_FETCH: @@ -421,11 +462,32 @@ static int emit_atomic_rmw(const struct bpf_insn *insn, struct jit_ctx *ctx) break; /* src = atomic_xchg(dst + off, src); */ case BPF_XCHG: - if (isdw) { - emit_insn(ctx, amswapd, src, t1, t3); - } else { + switch (BPF_SIZE(insn->code)) { + case BPF_B: + if (cpu_has_lam_bh) { + emit_insn(ctx, amswapb, src, t1, t3); + emit_zext_32(ctx, src, true); + } else { + pr_err_once("bpf-jit: amswap.b instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_H: + if (cpu_has_lam_bh) { + emit_insn(ctx, amswaph, src, t1, t3); + emit_zext_32(ctx, src, true); + } else { + pr_err_once("bpf-jit: amswap.h instruction is not supported\n"); + return -EINVAL; + } + break; + case BPF_W: emit_insn(ctx, amswapw, src, t1, t3); emit_zext_32(ctx, src, true); + break; + case BPF_DW: + emit_insn(ctx, amswapd, src, t1, t3); + break; } break; /* r0 = atomic_cmpxchg(dst + off, r0, src); */ @@ -1259,6 +1321,9 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext return ret; break; + /* Atomics */ + case BPF_STX | BPF_ATOMIC | BPF_B: + case BPF_STX | BPF_ATOMIC | BPF_H: case BPF_STX | BPF_ATOMIC | BPF_W: case BPF_STX | BPF_ATOMIC | BPF_DW: ret = emit_atomic_rmw(insn, ctx); -- 2.42.0