Skip to content

Commit a4b1d3c

Browse files
Jiong WangAlexei Starovoitov
authored andcommitted
bpf: verifier: insert zero extension according to analysis result
After previous patches, verifier will mark a insn if it really needs zero extension on dst_reg. It is then for back-ends to decide how to use such information to eliminate unnecessary zero extension code-gen during JIT compilation. One approach is verifier insert explicit zero extension for those insns that need zero extension in a generic way, JIT back-ends then do not generate zero extension for sub-register write at default. However, only those back-ends which do not have hardware zero extension want this optimization. Back-ends like x86_64 and AArch64 have hardware zero extension support that the insertion should be disabled. This patch introduces new target hook "bpf_jit_needs_zext" which returns false at default, meaning verifier zero extension insertion is disabled at default. A back-end could override this hook to return true if it doesn't have hardware support and want verifier insert zero extension explicitly. Offload targets do not use this native target hook, instead, they could get the optimization results using bpf_prog_offload_ops.finalize. NOTE: arches could have diversified features, it is possible for one arch to have hardware zero extension support for some sub-register write insns but not for all. For example, PowerPC, SPARC have zero extended loads, but not for alu32. So when verifier zero extension insertion enabled, these JIT back-ends need to peephole insns to remove those zero extension inserted for insn that actually has hardware zero extension support. The peephole could be as simple as looking the next insn, if it is a special zero extension insn then it is safe to eliminate it if the current insn has hardware zero extension support. Reviewed-by: Jakub Kicinski <jakub.kicinski@netronome.com> Signed-off-by: Jiong Wang <jiong.wang@netronome.com> Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 7d13404 commit a4b1d3c

File tree

4 files changed

+52
-0
lines changed

4 files changed

+52
-0
lines changed

include/linux/bpf.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,6 +370,7 @@ struct bpf_prog_aux {
370370
u32 id;
371371
u32 func_cnt; /* used by non-func prog as the number of func progs */
372372
u32 func_idx; /* 0 for non-func prog, the index in func array for func prog */
373+
bool verifier_zext; /* Zero extensions has been inserted by verifier. */
373374
bool offload_requested;
374375
struct bpf_prog **func;
375376
void *jit_data; /* JIT specific data. arch dependent */

include/linux/filter.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -825,6 +825,7 @@ u64 __bpf_call_base(u64 r1, u64 r2, u64 r3, u64 r4, u64 r5);
825825

826826
struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog);
827827
void bpf_jit_compile(struct bpf_prog *prog);
828+
bool bpf_jit_needs_zext(void);
828829
bool bpf_helper_changes_pkt_data(void *func);
829830

830831
static inline bool bpf_dump_raw_ok(void)

kernel/bpf/core.c

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2090,6 +2090,15 @@ bool __weak bpf_helper_changes_pkt_data(void *func)
20902090
return false;
20912091
}
20922092

2093+
/* Return TRUE if the JIT backend wants verifier to enable sub-register usage
2094+
* analysis code and wants explicit zero extension inserted by verifier.
2095+
* Otherwise, return FALSE.
2096+
*/
2097+
bool __weak bpf_jit_needs_zext(void)
2098+
{
2099+
return false;
2100+
}
2101+
20932102
/* To execute LD_ABS/LD_IND instructions __bpf_prog_run() may call
20942103
* skb_copy_bits(), so provide a weak definition of it for NET-less config.
20952104
*/

kernel/bpf/verifier.c

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7640,6 +7640,38 @@ static int opt_remove_nops(struct bpf_verifier_env *env)
76407640
return 0;
76417641
}
76427642

7643+
static int opt_subreg_zext_lo32(struct bpf_verifier_env *env)
7644+
{
7645+
struct bpf_insn_aux_data *aux = env->insn_aux_data;
7646+
struct bpf_insn *insns = env->prog->insnsi;
7647+
int i, delta = 0, len = env->prog->len;
7648+
struct bpf_insn zext_patch[2];
7649+
struct bpf_prog *new_prog;
7650+
7651+
zext_patch[1] = BPF_ZEXT_REG(0);
7652+
for (i = 0; i < len; i++) {
7653+
int adj_idx = i + delta;
7654+
struct bpf_insn insn;
7655+
7656+
if (!aux[adj_idx].zext_dst)
7657+
continue;
7658+
7659+
insn = insns[adj_idx];
7660+
zext_patch[0] = insn;
7661+
zext_patch[1].dst_reg = insn.dst_reg;
7662+
zext_patch[1].src_reg = insn.dst_reg;
7663+
new_prog = bpf_patch_insn_data(env, adj_idx, zext_patch, 2);
7664+
if (!new_prog)
7665+
return -ENOMEM;
7666+
env->prog = new_prog;
7667+
insns = new_prog->insnsi;
7668+
aux = env->insn_aux_data;
7669+
delta += 2;
7670+
}
7671+
7672+
return 0;
7673+
}
7674+
76437675
/* convert load instructions that access fields of a context type into a
76447676
* sequence of instructions that access fields of the underlying structure:
76457677
* struct __sk_buff -> struct sk_buff
@@ -8490,6 +8522,15 @@ int bpf_check(struct bpf_prog **prog, union bpf_attr *attr,
84908522
if (ret == 0)
84918523
ret = fixup_bpf_calls(env);
84928524

8525+
/* do 32-bit optimization after insn patching has done so those patched
8526+
* insns could be handled correctly.
8527+
*/
8528+
if (ret == 0 && bpf_jit_needs_zext() &&
8529+
!bpf_prog_is_dev_bound(env->prog->aux)) {
8530+
ret = opt_subreg_zext_lo32(env);
8531+
env->prog->aux->verifier_zext = !ret;
8532+
}
8533+
84938534
if (ret == 0)
84948535
ret = fixup_call_args(env);
84958536

0 commit comments

Comments
 (0)