|
@@ -21,7 +21,6 @@
|
|
|
#include <linux/bpf.h>
|
|
|
#include <linux/filter.h>
|
|
|
#include <linux/printk.h>
|
|
|
-#include <linux/skbuff.h>
|
|
|
#include <linux/slab.h>
|
|
|
|
|
|
#include <asm/byteorder.h>
|
|
@@ -80,23 +79,66 @@ static inline void emit(const u32 insn, struct jit_ctx *ctx)
|
|
|
ctx->idx++;
|
|
|
}
|
|
|
|
|
|
+static inline void emit_a64_mov_i(const int is64, const int reg,
|
|
|
+ const s32 val, struct jit_ctx *ctx)
|
|
|
+{
|
|
|
+ u16 hi = val >> 16;
|
|
|
+ u16 lo = val & 0xffff;
|
|
|
+
|
|
|
+ if (hi & 0x8000) {
|
|
|
+ if (hi == 0xffff) {
|
|
|
+ emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
|
|
|
+ } else {
|
|
|
+ emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
|
|
|
+ if (lo != 0xffff)
|
|
|
+ emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ emit(A64_MOVZ(is64, reg, lo, 0), ctx);
|
|
|
+ if (hi)
|
|
|
+ emit(A64_MOVK(is64, reg, hi, 16), ctx);
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
+static int i64_i16_blocks(const u64 val, bool inverse)
|
|
|
+{
|
|
|
+ return (((val >> 0) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 16) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 32) & 0xffff) != (inverse ? 0xffff : 0x0000)) +
|
|
|
+ (((val >> 48) & 0xffff) != (inverse ? 0xffff : 0x0000));
|
|
|
+}
|
|
|
+
|
|
|
static inline void emit_a64_mov_i64(const int reg, const u64 val,
|
|
|
struct jit_ctx *ctx)
|
|
|
{
|
|
|
- u64 tmp = val;
|
|
|
- int shift = 0;
|
|
|
-
|
|
|
- emit(A64_MOVZ(1, reg, tmp & 0xffff, shift), ctx);
|
|
|
- tmp >>= 16;
|
|
|
- shift += 16;
|
|
|
- while (tmp) {
|
|
|
- if (tmp & 0xffff)
|
|
|
- emit(A64_MOVK(1, reg, tmp & 0xffff, shift), ctx);
|
|
|
- tmp >>= 16;
|
|
|
- shift += 16;
|
|
|
+ u64 nrm_tmp = val, rev_tmp = ~val;
|
|
|
+ bool inverse;
|
|
|
+ int shift;
|
|
|
+
|
|
|
+ if (!(nrm_tmp >> 32))
|
|
|
+ return emit_a64_mov_i(0, reg, (u32)val, ctx);
|
|
|
+
|
|
|
+ inverse = i64_i16_blocks(nrm_tmp, true) < i64_i16_blocks(nrm_tmp, false);
|
|
|
+ shift = max(round_down((inverse ? (fls64(rev_tmp) - 1) :
|
|
|
+ (fls64(nrm_tmp) - 1)), 16), 0);
|
|
|
+ if (inverse)
|
|
|
+ emit(A64_MOVN(1, reg, (rev_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ else
|
|
|
+ emit(A64_MOVZ(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ shift -= 16;
|
|
|
+ while (shift >= 0) {
|
|
|
+ if (((nrm_tmp >> shift) & 0xffff) != (inverse ? 0xffff : 0x0000))
|
|
|
+ emit(A64_MOVK(1, reg, (nrm_tmp >> shift) & 0xffff, shift), ctx);
|
|
|
+ shift -= 16;
|
|
|
}
|
|
|
}
|
|
|
|
|
|
+/*
|
|
|
+ * This is an unoptimized 64 immediate emission used for BPF to BPF call
|
|
|
+ * addresses. It will always do a full 64 bit decomposition as otherwise
|
|
|
+ * more complexity in the last extra pass is required since we previously
|
|
|
+ * reserved 4 instructions for the address.
|
|
|
+ */
|
|
|
static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
|
|
struct jit_ctx *ctx)
|
|
|
{
|
|
@@ -111,26 +153,6 @@ static inline void emit_addr_mov_i64(const int reg, const u64 val,
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static inline void emit_a64_mov_i(const int is64, const int reg,
|
|
|
- const s32 val, struct jit_ctx *ctx)
|
|
|
-{
|
|
|
- u16 hi = val >> 16;
|
|
|
- u16 lo = val & 0xffff;
|
|
|
-
|
|
|
- if (hi & 0x8000) {
|
|
|
- if (hi == 0xffff) {
|
|
|
- emit(A64_MOVN(is64, reg, (u16)~lo, 0), ctx);
|
|
|
- } else {
|
|
|
- emit(A64_MOVN(is64, reg, (u16)~hi, 16), ctx);
|
|
|
- emit(A64_MOVK(is64, reg, lo, 0), ctx);
|
|
|
- }
|
|
|
- } else {
|
|
|
- emit(A64_MOVZ(is64, reg, lo, 0), ctx);
|
|
|
- if (hi)
|
|
|
- emit(A64_MOVK(is64, reg, hi, 16), ctx);
|
|
|
- }
|
|
|
-}
|
|
|
-
|
|
|
static inline int bpf2a64_offset(int bpf_to, int bpf_from,
|
|
|
const struct jit_ctx *ctx)
|
|
|
{
|
|
@@ -163,7 +185,7 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
|
|
|
/* Tail call offset to jump into */
|
|
|
#define PROLOGUE_OFFSET 7
|
|
|
|
|
|
-static int build_prologue(struct jit_ctx *ctx)
|
|
|
+static int build_prologue(struct jit_ctx *ctx, bool ebpf_from_cbpf)
|
|
|
{
|
|
|
const struct bpf_prog *prog = ctx->prog;
|
|
|
const u8 r6 = bpf2a64[BPF_REG_6];
|
|
@@ -188,7 +210,7 @@ static int build_prologue(struct jit_ctx *ctx)
|
|
|
* | ... | BPF prog stack
|
|
|
* | |
|
|
|
* +-----+ <= (BPF_FP - prog->aux->stack_depth)
|
|
|
- * |RSVD | JIT scratchpad
|
|
|
+ * |RSVD | padding
|
|
|
* current A64_SP => +-----+ <= (BPF_FP - ctx->stack_size)
|
|
|
* | |
|
|
|
* | ... | Function call stack
|
|
@@ -210,19 +232,19 @@ static int build_prologue(struct jit_ctx *ctx)
|
|
|
/* Set up BPF prog stack base register */
|
|
|
emit(A64_MOV(1, fp, A64_SP), ctx);
|
|
|
|
|
|
- /* Initialize tail_call_cnt */
|
|
|
- emit(A64_MOVZ(1, tcc, 0, 0), ctx);
|
|
|
+ if (!ebpf_from_cbpf) {
|
|
|
+ /* Initialize tail_call_cnt */
|
|
|
+ emit(A64_MOVZ(1, tcc, 0, 0), ctx);
|
|
|
|
|
|
- cur_offset = ctx->idx - idx0;
|
|
|
- if (cur_offset != PROLOGUE_OFFSET) {
|
|
|
- pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
|
|
|
- cur_offset, PROLOGUE_OFFSET);
|
|
|
- return -1;
|
|
|
+ cur_offset = ctx->idx - idx0;
|
|
|
+ if (cur_offset != PROLOGUE_OFFSET) {
|
|
|
+ pr_err_once("PROLOGUE_OFFSET = %d, expected %d!\n",
|
|
|
+ cur_offset, PROLOGUE_OFFSET);
|
|
|
+ return -1;
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
- /* 4 byte extra for skb_copy_bits buffer */
|
|
|
- ctx->stack_size = prog->aux->stack_depth + 4;
|
|
|
- ctx->stack_size = STACK_ALIGN(ctx->stack_size);
|
|
|
+ ctx->stack_size = STACK_ALIGN(prog->aux->stack_depth);
|
|
|
|
|
|
/* Set up function call stack */
|
|
|
emit(A64_SUB_I(1, A64_SP, A64_SP, ctx->stack_size), ctx);
|
|
@@ -786,6 +808,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
|
|
struct bpf_prog *tmp, *orig_prog = prog;
|
|
|
struct bpf_binary_header *header;
|
|
|
struct arm64_jit_data *jit_data;
|
|
|
+ bool was_classic = bpf_prog_was_classic(prog);
|
|
|
bool tmp_blinded = false;
|
|
|
bool extra_pass = false;
|
|
|
struct jit_ctx ctx;
|
|
@@ -840,7 +863,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
|
|
goto out_off;
|
|
|
}
|
|
|
|
|
|
- if (build_prologue(&ctx)) {
|
|
|
+ if (build_prologue(&ctx, was_classic)) {
|
|
|
prog = orig_prog;
|
|
|
goto out_off;
|
|
|
}
|
|
@@ -863,7 +886,7 @@ struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog)
|
|
|
skip_init_ctx:
|
|
|
ctx.idx = 0;
|
|
|
|
|
|
- build_prologue(&ctx);
|
|
|
+ build_prologue(&ctx, was_classic);
|
|
|
|
|
|
if (build_body(&ctx)) {
|
|
|
bpf_jit_binary_free(header);
|