[RFC 12/15] riscv: bpf: big endian fixes, updated BPF_ALU ops

Ben Dooks
2024-12-20T15:58:20Z

If running big endian then the instruction stream needs to
be written le16/le323 and the BPF BSWAP instrictions need
to correctly set the endian.

Signed-off-by: Ben Dooks <ben.dooks@codethink.co.uk>
---
arch/riscv/net/bpf_jit.h | 14 +++++++++-----
arch/riscv/net/bpf_jit_comp64.c | 29 +++++++++++++++++------------
2 files changed, 26 insertions(+), 17 deletions(-)

diff --git a/arch/riscv/net/bpf_jit.h b/arch/riscv/net/bpf_jit.h
index 1d1c78d4cff1..eb2908cc42fd 100644
--- a/arch/riscv/net/bpf_jit.h
+++ b/arch/riscv/net/bpf_jit.h
@@ -28,6 +28,12 @@ static inline bool rvzbb_enabled(void)
return IS_ENABLED(CONFIG_RISCV_ISA_ZBB) && riscv_has_extension_likely(RISCV_ISA_EXT_ZBB);
}

+static inline bool alu_end_should_swap(u32 code)
+{
+ u32 endian = IS_ENABLED(CONFIG_CPU_BIG_ENDIAN) ? BPF_FROM_BE : BPF_FROM_LE;
+ return (code & BPF_FROM_BE) != endian;
+}
+
enum {
RV_REG_ZERO = 0, /* The constant value 0 */
RV_REG_RA = 1, /* Return address */
@@ -117,10 +123,8 @@ static inline void bpf_flush_icache(void *start, void *end)
/* Emit a 4-byte riscv instruction. */
static inline void emit(const u32 insn, struct rv_jit_context *ctx)
{
- if (ctx->insns) {
- ctx->insns[ctx->ninsns] = insn;
- ctx->insns[ctx->ninsns + 1] = (insn >> 16);
- }
+ if (ctx->insns)
+ put_unaligned_le32(insn, ctx->insns+ctx->ninsns);

ctx->ninsns += 2;
}
@@ -131,7 +135,7 @@ static inline void emitc(const u16 insn, struct rv_jit_context *ctx)
BUILD_BUG_ON(!rvc_enabled());

if (ctx->insns)
- ctx->insns[ctx->ninsns] = insn;
+ ctx->insns[ctx->ninsns] = cpu_to_le16(insn);

ctx->ninsns++;
}
diff --git a/arch/riscv/net/bpf_jit_comp64.c b/arch/riscv/net/bpf_jit_comp64.c
index 4cc631fa7039..05f5b1a88423 100644
--- a/arch/riscv/net/bpf_jit_comp64.c
+++ b/arch/riscv/net/bpf_jit_comp64.c
@@ -1273,20 +1273,25 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct rv_jit_context *ctx,

/* dst = BSWAP##imm(dst) */
case BPF_ALU | BPF_END | BPF_FROM_LE:
- switch (imm) {
- case 16:
- emit_zexth(rd, rd, ctx);
- break;
- case 32:
- if (!aux->verifier_zext)
- emit_zextw(rd, rd, ctx);
- break;
- case 64:
- /* Do nothing */
- break;
+ case BPF_ALU | BPF_END | BPF_FROM_BE:
+ if (alu_end_should_swap(code)) {
+ emit_bswap(rd, imm, ctx);
+ } else {
+ switch (imm) {
+ case 16:
+ emit_zexth(rd, rd, ctx);
+ break;
+ case 32:
+ if (!aux->verifier_zext)
+ emit_zextw(rd, rd, ctx);
+ break;
+ case 64:
+ /* Do nothing */
+ break;
+ }
}
break;
- case BPF_ALU | BPF_END | BPF_FROM_BE:
+
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
emit_bswap(rd, imm, ctx);
break;