/* Compute the 28-bit jump target address from a BPF program location */ int get_target(struct jit_context *ctx, u32 loc)
{
u32 index = INDEX(ctx->descriptors[loc]); unsignedlong pc = (unsignedlong)&ctx->target[ctx->jit_index]; unsignedlong addr = (unsignedlong)&ctx->target[index];
if (!ctx->target) return0;
if ((addr ^ pc) & ~MIPS_JMP_MASK) return -1;
return addr & MIPS_JMP_MASK;
}
/* Compute the PC-relative offset to relative BPF program offset */ int get_offset(conststruct jit_context *ctx, int off)
{ return (INDEX(ctx->descriptors[ctx->bpf_index + off]) -
ctx->jit_index - 1) * sizeof(u32);
}
/* Validate ALU immediate range */ bool valid_alu_i(u8 op, s32 imm)
{ switch (BPF_OP(op)) { case BPF_NEG: case BPF_LSH: case BPF_RSH: case BPF_ARSH: /* All legal eBPF values are valid */ returntrue; case BPF_ADD: if (IS_ENABLED(CONFIG_CPU_DADDI_WORKAROUNDS)) returnfalse; /* imm must be 16 bits */ return imm >= -0x8000 && imm <= 0x7fff; case BPF_SUB: if (IS_ENABLED(CONFIG_CPU_DADDI_WORKAROUNDS)) returnfalse; /* -imm must be 16 bits */ return imm >= -0x7fff && imm <= 0x8000; case BPF_AND: case BPF_OR: case BPF_XOR: /* imm must be 16 bits unsigned */ return imm >= 0 && imm <= 0xffff; case BPF_MUL: /* imm must be zero or a positive power of two */ return imm == 0 || (imm > 0 && is_power_of_2(imm)); case BPF_DIV: case BPF_MOD: /* imm must be an 17-bit power of two */ return (u32)imm <= 0x10000 && is_power_of_2((u32)imm);
} returnfalse;
}
/* Validate jump immediate range */ bool valid_jmp_i(u8 op, s32 imm)
{ switch (op) { case JIT_JNOP: /* Immediate value not used */ returntrue; case BPF_JEQ: case BPF_JNE: /* No immediate operation */ returnfalse; case BPF_JSET: case JIT_JNSET: /* imm must be 16 bits unsigned */ return imm >= 0 && imm <= 0xffff; case BPF_JGE: case BPF_JLT: case BPF_JSGE: case BPF_JSLT: /* imm must be 16 bits */ return imm >= -0x8000 && imm <= 0x7fff; case BPF_JGT: case BPF_JLE: case BPF_JSGT: case BPF_JSLE: /* imm + 1 must be 16 bits */ return imm >= -0x8001 && imm <= 0x7ffe;
} returnfalse;
}
/* Invert a conditional jump operation */ static u8 invert_jmp(u8 op)
{ switch (op) { case BPF_JA: return JIT_JNOP; case BPF_JEQ: return BPF_JNE; case BPF_JNE: return BPF_JEQ; case BPF_JSET: return JIT_JNSET; case BPF_JGT: return BPF_JLE; case BPF_JGE: return BPF_JLT; case BPF_JLT: return BPF_JGE; case BPF_JLE: return BPF_JGT; case BPF_JSGT: return BPF_JSLE; case BPF_JSGE: return BPF_JSLT; case BPF_JSLT: return BPF_JSGE; case BPF_JSLE: return BPF_JSGT;
} return0;
}
/* Prepare a PC-relative jump operation */ staticvoid setup_jmp(struct jit_context *ctx, u8 bpf_op,
s16 bpf_off, u8 *jit_op, s32 *jit_off)
{
u32 *descp = &ctx->descriptors[ctx->bpf_index]; int op = bpf_op; int offset = 0;
/* Do not compute offsets on the first pass */ if (INDEX(*descp) == 0) goto done;
/* Skip jumps never taken */ if (bpf_op == JIT_JNOP) goto done;
/* Convert jumps always taken */ if (bpf_op == BPF_JA)
*descp |= JIT_DESC_CONVERT;
/* *Currentctx->jit_indexpointstothestartofthebranchpreamble. *Sincethepreamblediffersamongdifferentbranchconditionals, *thecurrentindexcannotbeusedtocomputethebranchoffset. *Instead,weusetheoffsettablevalueforthenextinstruction, *whichgivestheindeximmediatelyafterthebranchdelayslot.
*/ if (!CONVERTED(*descp)) { int target = ctx->bpf_index + bpf_off + 1; int origin = ctx->bpf_index + 1;
switch (bpf_op) { case BPF_JEQ: case BPF_JNE: break; case BPF_JSET: case BPF_JLT:
never = imm == 0; break; case BPF_JGE:
always = imm == 0; break; case BPF_JGT:
never = (u32)imm == U32_MAX; break; case BPF_JLE:
always = (u32)imm == U32_MAX; break; case BPF_JSGT:
never = imm == S32_MAX && width == 32; break; case BPF_JSGE:
always = imm == S32_MIN && width == 32; break; case BPF_JSLT:
never = imm == S32_MIN && width == 32; break; case BPF_JSLE:
always = imm == S32_MAX && width == 32; break;
}
if (never)
bpf_op = JIT_JNOP; if (always)
bpf_op = BPF_JA;
setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off);
}
/* Prepare a PC-relative jump operation with register conditional */ void setup_jmp_r(struct jit_context *ctx, bool same_reg,
u8 bpf_op, s16 bpf_off, u8 *jit_op, s32 *jit_off)
{ switch (bpf_op) { case BPF_JSET: break; case BPF_JEQ: case BPF_JGE: case BPF_JLE: case BPF_JSGE: case BPF_JSLE: if (same_reg)
bpf_op = BPF_JA; break; case BPF_JNE: case BPF_JLT: case BPF_JGT: case BPF_JSGT: case BPF_JSLT: if (same_reg)
bpf_op = JIT_JNOP; break;
}
setup_jmp(ctx, bpf_op, bpf_off, jit_op, jit_off);
}
/* Finish a PC-relative jump operation */ int finish_jmp(struct jit_context *ctx, u8 jit_op, s16 bpf_off)
{ /* Emit conditional branch delay slot */ if (jit_op != JIT_JNOP)
emit(ctx, nop); /* *Emitanabsolutelongjumpwithdelayslot, *ifthePC-relativebranchwasconverted.
*/ if (CONVERTED(ctx->descriptors[ctx->bpf_index])) { int target = get_target(ctx, ctx->bpf_index + bpf_off + 1);
/* We are guaranteed to have aligned memory. */ for (p = area; size >= sizeof(u32); size -= sizeof(u32))
uasm_i_break(&p, BRK_BUG); /* Increments p */
}
/* First pass discovers used resources */ if (build_body(&ctx) < 0) goto out_err; /* *Secondpasscomputesinstructionoffsets. *IfanyPC-relativebranchesareoutofrange,asequenceof *aPC-relativebranch+ajumpisgenerated,andwehaveto *tryagainfromthebeginningtogeneratethenewoffsets. *Thisisdoneuntilnoadditionalconversionsarenecessary. *Thelasttwoiterationsaredonewithallbranchesbeing *converted,toguaranteeoffsettableconvergencewithina *fixednumberofiterations.
*/
ctx.jit_index = 0;
build_prologue(&ctx);
tmp_idx = ctx.jit_index;
tries = JIT_MAX_ITERATIONS; do {
ctx.jit_index = tmp_idx;
ctx.changes = 0; if (tries == 2)
set_convert_flag(&ctx, true); if (build_body(&ctx) < 0) goto out_err;
} while (ctx.changes > 0 && --tries > 0);
if (WARN_ONCE(ctx.changes > 0, "JIT offsets failed to converge")) goto out_err;
build_epilogue(&ctx, MIPS_R_RA);
/* Now we know the size of the structure to make */
image_size = sizeof(u32) * ctx.jit_index;
header = bpf_jit_binary_alloc(image_size, &image_ptr, sizeof(u32), jit_fill_hole); /* *Notabletoallocatememoryforthestructurethen *wemustfallbacktotheinterpretation
*/ if (header == NULL) goto out_err;
/* Actual pass to generate final JIT code */
ctx.target = (u32 *)image_ptr;
ctx.jit_index = 0;
/* Populate line info meta data */
set_convert_flag(&ctx, false);
bpf_prog_fill_jited_linfo(prog, &ctx.descriptors[1]);
/* Set as read-only exec and flush instruction cache */ if (bpf_jit_binary_lock_ro(header)) goto out_err;
flush_icache_range((unsignedlong)header,
(unsignedlong)&ctx.target[ctx.jit_index]);
if (bpf_jit_enable > 1)
bpf_jit_dump(prog->len, image_size, 2, ctx.target);
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.