/* Verify that no instruction will be emitted when there is no buffer. */ staticinlineint jit_buffer_check(conststruct jit_context *ctx)
{ if (ctx->emit) { if (!ctx->jit.buf) {
pr_err("bpf-jit: inconsistence state; no " "buffer to emit instructions.\n"); return -EINVAL;
} elseif (ctx->jit.index > ctx->jit.len) {
pr_err("bpf-jit: estimated JIT length is less " "than the emitted instructions.\n"); return -EFAULT;
}
} return0;
}
/* On a dry-run (emit=false), "jit.len" is growing gradually. */ staticinlinevoid jit_buffer_update(struct jit_context *ctx, u32 n)
{ if (!ctx->emit)
ctx->jit.len += n; else
ctx->jit.index += n;
}
/* Based on "emit", determine the address where instructions are emitted. */ staticinline u8 *effective_jit_buf(conststruct jit_context *ctx)
{ return ctx->emit ? (ctx->jit.buf + ctx->jit.index) : NULL;
}
/* Prologue based on context variables set by "analyze_reg_usage()". */ staticint handle_prologue(struct jit_context *ctx)
{ int ret;
u8 *buf = effective_jit_buf(ctx);
u32 len = 0;
CHECK_RET(jit_buffer_check(ctx));
len = arc_prologue(buf, ctx->arc_regs_clobbered, ctx->frame_size);
jit_buffer_update(ctx, len);
return0;
}
/* The counter part for "handle_prologue()". */ staticint handle_epilogue(struct jit_context *ctx)
{ int ret;
u8 *buf = effective_jit_buf(ctx);
u32 len = 0;
CHECK_RET(jit_buffer_check(ctx));
len = arc_epilogue(buf, ctx->arc_regs_clobbered, ctx->frame_size);
jit_buffer_update(ctx, len);
return0;
}
/* Tell which number of the BPF instruction we are dealing with. */ staticinline s32 get_index_for_insn(conststruct jit_context *ctx, conststruct bpf_insn *insn)
{ return (insn - ctx->prog->insnsi);
}
/* Is there an immediate operand encoded in the "insn"? */ staticinlinebool has_imm(conststruct bpf_insn *insn)
{ return BPF_SRC(insn->code) == BPF_K;
}
/* Is the last BPF instruction? */ staticinlinebool is_last_insn(conststruct bpf_prog *prog, u32 idx)
{ return idx == (prog->len - 1);
}
/* Must be a jmp(32) instruction that is not a "call/exit". */ if ((class != BPF_JMP && class != BPF_JMP32) ||
(op == BPF_CALL || op == BPF_EXIT)) {
pr_err("bpf-jit: not a jump instruction.\n"); return -EINVAL;
}
if (!check_insn_idx_valid(ctx, get_index_for_insn(ctx, insn))) {
pr_err("bpf-jit: the bpf jump insn is not in prog.\n"); return -EINVAL;
}
if (!check_insn_idx_valid(ctx, get_target_index_for_insn(ctx, insn))) {
pr_err("bpf-jit: bpf jump label is out of range.\n"); return -EINVAL;
}
/* If the offsets are known, check if the branch can occur. */ if (offsets_available(ctx)) {
curr_off = get_curr_jit_off(ctx, insn) + *len;
targ_off = get_targ_jit_off(ctx, insn);
/* Sanity check on the back-end side. */
CHECK_RET(feasible_jit_jump(curr_off, targ_off, cond, j32));
}
/* Check the offset only if the data is available. */ if (offsets_available(ctx)) {
curr_off = get_curr_jit_off(ctx, insn);
epi_off = ctx->epilogue_offset;
if (!check_jmp_64(curr_off, epi_off, ARC_CC_AL)) {
pr_err("bpf-jit: epilogue offset is not valid.\n"); return -EINVAL;
}
}
/* Jump to "epilogue offset" (rd and rs don't matter). */
*len = gen_jmp_64(buf, 0, 0, ARC_CC_AL, curr_off, epi_off);
return0;
}
/* Try to get the resolved address and generate the instructions. */ staticint handle_call(struct jit_context *ctx, conststruct bpf_insn *insn,
u8 *len)
{ int ret; bool in_kernel_func, fixed = false;
u64 addr = 0;
u8 *buf = effective_jit_buf(ctx);
ret = bpf_jit_get_func_addr(ctx->prog, insn, ctx->is_extra_pass,
&addr, &fixed); if (ret < 0) {
pr_err("bpf-jit: can't get the address for call.\n"); return ret;
}
in_kernel_func = (fixed ? true : false);
/* No valuable address retrieved (yet). */ if (!fixed && !addr)
set_need_for_extra_pass(ctx);
/* We're about to consume 2 VM instructions. */ if (is_last_insn(ctx->prog, idx)) {
pr_err("bpf-jit: need more data for 64-bit immediate.\n"); return -EINVAL;
}
switch (code) { /* dst += src (32-bit) */ case BPF_ALU | BPF_ADD | BPF_X:
len = add_r32(buf, dst, src); break; /* dst += imm (32-bit) */ case BPF_ALU | BPF_ADD | BPF_K:
len = add_r32_i32(buf, dst, imm); break; /* dst -= src (32-bit) */ case BPF_ALU | BPF_SUB | BPF_X:
len = sub_r32(buf, dst, src); break; /* dst -= imm (32-bit) */ case BPF_ALU | BPF_SUB | BPF_K:
len = sub_r32_i32(buf, dst, imm); break; /* dst = -dst (32-bit) */ case BPF_ALU | BPF_NEG:
len = neg_r32(buf, dst); break; /* dst *= src (32-bit) */ case BPF_ALU | BPF_MUL | BPF_X:
len = mul_r32(buf, dst, src); break; /* dst *= imm (32-bit) */ case BPF_ALU | BPF_MUL | BPF_K:
len = mul_r32_i32(buf, dst, imm); break; /* dst /= src (32-bit) */ case BPF_ALU | BPF_DIV | BPF_X:
len = div_r32(buf, dst, src, off == 1); break; /* dst /= imm (32-bit) */ case BPF_ALU | BPF_DIV | BPF_K:
len = div_r32_i32(buf, dst, imm, off == 1); break; /* dst %= src (32-bit) */ case BPF_ALU | BPF_MOD | BPF_X:
len = mod_r32(buf, dst, src, off == 1); break; /* dst %= imm (32-bit) */ case BPF_ALU | BPF_MOD | BPF_K:
len = mod_r32_i32(buf, dst, imm, off == 1); break; /* dst &= src (32-bit) */ case BPF_ALU | BPF_AND | BPF_X:
len = and_r32(buf, dst, src); break; /* dst &= imm (32-bit) */ case BPF_ALU | BPF_AND | BPF_K:
len = and_r32_i32(buf, dst, imm); break; /* dst |= src (32-bit) */ case BPF_ALU | BPF_OR | BPF_X:
len = or_r32(buf, dst, src); break; /* dst |= imm (32-bit) */ case BPF_ALU | BPF_OR | BPF_K:
len = or_r32_i32(buf, dst, imm); break; /* dst ^= src (32-bit) */ case BPF_ALU | BPF_XOR | BPF_X:
len = xor_r32(buf, dst, src); break; /* dst ^= imm (32-bit) */ case BPF_ALU | BPF_XOR | BPF_K:
len = xor_r32_i32(buf, dst, imm); break; /* dst <<= src (32-bit) */ case BPF_ALU | BPF_LSH | BPF_X:
len = lsh_r32(buf, dst, src); break; /* dst <<= imm (32-bit) */ case BPF_ALU | BPF_LSH | BPF_K:
len = lsh_r32_i32(buf, dst, imm); break; /* dst >>= src (32-bit) [unsigned] */ case BPF_ALU | BPF_RSH | BPF_X:
len = rsh_r32(buf, dst, src); break; /* dst >>= imm (32-bit) [unsigned] */ case BPF_ALU | BPF_RSH | BPF_K:
len = rsh_r32_i32(buf, dst, imm); break; /* dst >>= src (32-bit) [signed] */ case BPF_ALU | BPF_ARSH | BPF_X:
len = arsh_r32(buf, dst, src); break; /* dst >>= imm (32-bit) [signed] */ case BPF_ALU | BPF_ARSH | BPF_K:
len = arsh_r32_i32(buf, dst, imm); break; /* dst = src (32-bit) */ case BPF_ALU | BPF_MOV | BPF_X:
len = mov_r32(buf, dst, src, (u8)off); break; /* dst = imm32 (32-bit) */ case BPF_ALU | BPF_MOV | BPF_K:
len = mov_r32_i32(buf, dst, imm); break; /* dst = swap(dst) */ case BPF_ALU | BPF_END | BPF_FROM_LE: case BPF_ALU | BPF_END | BPF_FROM_BE: case BPF_ALU64 | BPF_END | BPF_FROM_LE: {
CHECK_RET(handle_swap(buf, dst, imm, BPF_SRC(code),
BPF_CLASS(code) == BPF_ALU64,
ctx->do_zext, &len)); break;
} /* dst += src (64-bit) */ case BPF_ALU64 | BPF_ADD | BPF_X:
len = add_r64(buf, dst, src); break; /* dst += imm32 (64-bit) */ case BPF_ALU64 | BPF_ADD | BPF_K:
len = add_r64_i32(buf, dst, imm); break; /* dst -= src (64-bit) */ case BPF_ALU64 | BPF_SUB | BPF_X:
len = sub_r64(buf, dst, src); break; /* dst -= imm32 (64-bit) */ case BPF_ALU64 | BPF_SUB | BPF_K:
len = sub_r64_i32(buf, dst, imm); break; /* dst = -dst (64-bit) */ case BPF_ALU64 | BPF_NEG:
len = neg_r64(buf, dst); break; /* dst *= src (64-bit) */ case BPF_ALU64 | BPF_MUL | BPF_X:
len = mul_r64(buf, dst, src); break; /* dst *= imm32 (64-bit) */ case BPF_ALU64 | BPF_MUL | BPF_K:
len = mul_r64_i32(buf, dst, imm); break; /* dst &= src (64-bit) */ case BPF_ALU64 | BPF_AND | BPF_X:
len = and_r64(buf, dst, src); break; /* dst &= imm32 (64-bit) */ case BPF_ALU64 | BPF_AND | BPF_K:
len = and_r64_i32(buf, dst, imm); break; /* dst |= src (64-bit) */ case BPF_ALU64 | BPF_OR | BPF_X:
len = or_r64(buf, dst, src); break; /* dst |= imm32 (64-bit) */ case BPF_ALU64 | BPF_OR | BPF_K:
len = or_r64_i32(buf, dst, imm); break; /* dst ^= src (64-bit) */ case BPF_ALU64 | BPF_XOR | BPF_X:
len = xor_r64(buf, dst, src); break; /* dst ^= imm32 (64-bit) */ case BPF_ALU64 | BPF_XOR | BPF_K:
len = xor_r64_i32(buf, dst, imm); break; /* dst <<= src (64-bit) */ case BPF_ALU64 | BPF_LSH | BPF_X:
len = lsh_r64(buf, dst, src); break; /* dst <<= imm32 (64-bit) */ case BPF_ALU64 | BPF_LSH | BPF_K:
len = lsh_r64_i32(buf, dst, imm); break; /* dst >>= src (64-bit) [unsigned] */ case BPF_ALU64 | BPF_RSH | BPF_X:
len = rsh_r64(buf, dst, src); break; /* dst >>= imm32 (64-bit) [unsigned] */ case BPF_ALU64 | BPF_RSH | BPF_K:
len = rsh_r64_i32(buf, dst, imm); break; /* dst >>= src (64-bit) [signed] */ case BPF_ALU64 | BPF_ARSH | BPF_X:
len = arsh_r64(buf, dst, src); break; /* dst >>= imm32 (64-bit) [signed] */ case BPF_ALU64 | BPF_ARSH | BPF_K:
len = arsh_r64_i32(buf, dst, imm); break; /* dst = src (64-bit) */ case BPF_ALU64 | BPF_MOV | BPF_X:
len = mov_r64(buf, dst, src, (u8)off); break; /* dst = imm32 (sign extend to 64-bit) */ case BPF_ALU64 | BPF_MOV | BPF_K:
len = mov_r64_i32(buf, dst, imm); break; /* dst = imm64 */ case BPF_LD | BPF_DW | BPF_IMM:
CHECK_RET(handle_ld_imm64(ctx, insn, &len)); /* Tell the loop to skip the next instruction. */
ret = 1; break; /* dst = *(size *)(src + off) */ case BPF_LDX | BPF_MEM | BPF_W: case BPF_LDX | BPF_MEM | BPF_H: case BPF_LDX | BPF_MEM | BPF_B: case BPF_LDX | BPF_MEM | BPF_DW:
len = load_r(buf, dst, src, off, BPF_SIZE(code), false); break; case BPF_LDX | BPF_MEMSX | BPF_W: case BPF_LDX | BPF_MEMSX | BPF_H: case BPF_LDX | BPF_MEMSX | BPF_B:
len = load_r(buf, dst, src, off, BPF_SIZE(code), true); break; /* *(size *)(dst + off) = src */ case BPF_STX | BPF_MEM | BPF_W: case BPF_STX | BPF_MEM | BPF_H: case BPF_STX | BPF_MEM | BPF_B: case BPF_STX | BPF_MEM | BPF_DW:
len = store_r(buf, src, dst, off, BPF_SIZE(code)); break; case BPF_ST | BPF_MEM | BPF_W: case BPF_ST | BPF_MEM | BPF_H: case BPF_ST | BPF_MEM | BPF_B: case BPF_ST | BPF_MEM | BPF_DW:
len = store_i(buf, imm, dst, off, BPF_SIZE(code)); break; case BPF_JMP | BPF_JA: case BPF_JMP | BPF_JEQ | BPF_X: case BPF_JMP | BPF_JEQ | BPF_K: case BPF_JMP | BPF_JNE | BPF_X: case BPF_JMP | BPF_JNE | BPF_K: case BPF_JMP | BPF_JSET | BPF_X: case BPF_JMP | BPF_JSET | BPF_K: case BPF_JMP | BPF_JGT | BPF_X: case BPF_JMP | BPF_JGT | BPF_K: case BPF_JMP | BPF_JGE | BPF_X: case BPF_JMP | BPF_JGE | BPF_K: case BPF_JMP | BPF_JSGT | BPF_X: case BPF_JMP | BPF_JSGT | BPF_K: case BPF_JMP | BPF_JSGE | BPF_X: case BPF_JMP | BPF_JSGE | BPF_K: case BPF_JMP | BPF_JLT | BPF_X: case BPF_JMP | BPF_JLT | BPF_K: case BPF_JMP | BPF_JLE | BPF_X: case BPF_JMP | BPF_JLE | BPF_K: case BPF_JMP | BPF_JSLT | BPF_X: case BPF_JMP | BPF_JSLT | BPF_K: case BPF_JMP | BPF_JSLE | BPF_X: case BPF_JMP | BPF_JSLE | BPF_K: case BPF_JMP32 | BPF_JA: case BPF_JMP32 | BPF_JEQ | BPF_X: case BPF_JMP32 | BPF_JEQ | BPF_K: case BPF_JMP32 | BPF_JNE | BPF_X: case BPF_JMP32 | BPF_JNE | BPF_K: case BPF_JMP32 | BPF_JSET | BPF_X: case BPF_JMP32 | BPF_JSET | BPF_K: case BPF_JMP32 | BPF_JGT | BPF_X: case BPF_JMP32 | BPF_JGT | BPF_K: case BPF_JMP32 | BPF_JGE | BPF_X: case BPF_JMP32 | BPF_JGE | BPF_K: case BPF_JMP32 | BPF_JSGT | BPF_X: case BPF_JMP32 | BPF_JSGT | BPF_K: case BPF_JMP32 | BPF_JSGE | BPF_X: case BPF_JMP32 | BPF_JSGE | BPF_K: case BPF_JMP32 | BPF_JLT | BPF_X: case BPF_JMP32 | BPF_JLT | BPF_K: case BPF_JMP32 | BPF_JLE | BPF_X: case BPF_JMP32 | BPF_JLE | BPF_K: case BPF_JMP32 | BPF_JSLT | BPF_X: case BPF_JMP32 | BPF_JSLT | BPF_K: case BPF_JMP32 | BPF_JSLE | BPF_X: case BPF_JMP32 | BPF_JSLE | BPF_K:
CHECK_RET(handle_jumps(ctx, insn, &len)); break; case BPF_JMP | BPF_CALL:
CHECK_RET(handle_call(ctx, insn, &len)); break;
case BPF_JMP | BPF_EXIT: /* If this is the last instruction, epilogue will follow. */ if (is_last_insn(ctx->prog, idx)) break;
CHECK_RET(handle_jmp_epilogue(ctx, insn, &len)); break; default:
pr_err("bpf-jit: can't handle instruction code 0x%02X\n", code); return -EOPNOTSUPP;
}
if (BPF_CLASS(code) == BPF_ALU) { /* *Skipthe"swap"instructions.Even64-bitswapsareoftype *BPF_ALU(andnotBPF_ALU64).Therefore,fortheswaps,one *hastolookatthe"size"oftheoperationsratherthanthe *ALUtype."gen_swap()"specificallytakescareofthat.
*/ if (BPF_OP(code) != BPF_END && ctx->do_zext)
len += zext(BUF(buf, len), dst);
}
/* *Recordthemappingfortheinstructionsduringthedry-run. *Doingitthiswayallowsustohavethemappingreadyfor *thejumpinstructionsduringtherealcompilationphase.
*/ if (!ctx->emit)
populate_bpf2insn = true;
for (u32 i = 0; i < prog->len; i++) { /* During the dry-run, jit.len grows gradually per BPF insn. */ if (populate_bpf2insn)
ctx->bpf2insn[i] = ctx->jit.len;
CHECK_RET(handle_insn(ctx, i)); if (ret > 0) { /* "ret" is 1 if two (64-bit) chunks were consumed. */
ctx->bpf2insn[i + 1] = ctx->bpf2insn[i];
i++;
}
}
/* If bpf2insn had to be populated, then it is done at this point. */ if (populate_bpf2insn)
ctx->bpf2insn_valid = true;
/* Piece of memory that can be allocated at the beginning of jit_prepare(). */ staticint jit_prepare_early_mem_alloc(struct jit_context *ctx)
{
ctx->bpf2insn = kcalloc(ctx->prog->len, sizeof(ctx->jit.len),
GFP_KERNEL);
if (!ctx->bpf2insn) {
pr_err("bpf-jit: could not allocate memory for " "mapping of the instructions.\n"); return -ENOMEM;
}
ctx->bpf_header = bpf_jit_binary_alloc(ctx->jit.len, &ctx->jit.buf,
alignment, fill_ill_insn); if (!ctx->bpf_header) {
pr_err("bpf-jit: could not allocate memory for translation.\n"); return -ENOMEM;
}
if (ctx->need_extra_pass) {
ctx->jit_data = kzalloc(sizeof(*ctx->jit_data), GFP_KERNEL); if (!ctx->jit_data) return -ENOMEM;
}
if (ctx->jit.index != ctx->jit.len) {
pr_err("bpf-jit: divergence between the phases; " "%u vs. %u (bytes).\n",
ctx->jit.len, ctx->jit.index); return -EFAULT;
}
/* We're going to need this information for the "do_extra_pass()". */ if (ctx->need_extra_pass) {
ctx->jit_data->bpf_header = ctx->bpf_header;
ctx->jit_data->bpf2insn = ctx->bpf2insn;
prog->aux->jit_data = (void *)ctx->jit_data;
} else { /* *Ifthingsseemfinalised,thenmarktheJITedmemory *asR-Xandflushit.
*/ if (bpf_jit_binary_lock_ro(ctx->bpf_header)) {
pr_err("bpf-jit: Could not lock the JIT memory.\n"); return -EFAULT;
}
flush_icache_range((unsignedlong)ctx->bpf_header,
(unsignedlong)
BUF(ctx->jit.buf, ctx->jit.len));
prog->aux->jit_data = NULL;
bpf_prog_fill_jited_linfo(prog, ctx->bpf2insn);
}
/* *AlenientverificationfortheexistenceofJITcontextin"prog". *ApparentlytheJITinternals,namelyjit_subprogs()inbpf/verifier.c, *mayrequestforasecondcompilationalthoughnothingneedstobedone.
*/ staticinlineint check_jit_context(conststruct bpf_prog *prog)
{ if (!prog->aux->jit_data) {
pr_notice("bpf-jit: no jit data for the extra pass.\n"); return1;
} else { return0;
}
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.