bpf: Support new unconditional bswap instruction
The existing 'be' and 'le' insns will do conditional bswap depends on host endianness. This patch implements unconditional bswap insns. Acked-by: Eduard Zingerman <eddyz87@gmail.com> Signed-off-by: Yonghong Song <yonghong.song@linux.dev> Link: https://lore.kernel.org/r/20230728011213.3712808-1-yonghong.song@linux.dev Signed-off-by: Alexei Starovoitov <ast@kernel.org>
This commit is contained in:
parent
1f1e864b65
commit
0845c3db7b
3 changed files with 20 additions and 2 deletions
|
@ -1322,6 +1322,7 @@ static int do_jit(struct bpf_prog *bpf_prog, int *addrs, u8 *image, u8 *rw_image
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
case BPF_ALU | BPF_END | BPF_FROM_BE:
|
||||||
|
case BPF_ALU64 | BPF_END | BPF_FROM_LE:
|
||||||
switch (imm32) {
|
switch (imm32) {
|
||||||
case 16:
|
case 16:
|
||||||
/* Emit 'ror %ax, 8' to swap lower 2 bytes */
|
/* Emit 'ror %ax, 8' to swap lower 2 bytes */
|
||||||
|
|
|
@ -1524,6 +1524,7 @@ EXPORT_SYMBOL_GPL(__bpf_call_base);
|
||||||
INSN_3(ALU64, DIV, X), \
|
INSN_3(ALU64, DIV, X), \
|
||||||
INSN_3(ALU64, MOD, X), \
|
INSN_3(ALU64, MOD, X), \
|
||||||
INSN_2(ALU64, NEG), \
|
INSN_2(ALU64, NEG), \
|
||||||
|
INSN_3(ALU64, END, TO_LE), \
|
||||||
/* Immediate based. */ \
|
/* Immediate based. */ \
|
||||||
INSN_3(ALU64, ADD, K), \
|
INSN_3(ALU64, ADD, K), \
|
||||||
INSN_3(ALU64, SUB, K), \
|
INSN_3(ALU64, SUB, K), \
|
||||||
|
@ -1848,6 +1849,19 @@ select_insn:
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
CONT;
|
CONT;
|
||||||
|
ALU64_END_TO_LE:
|
||||||
|
switch (IMM) {
|
||||||
|
case 16:
|
||||||
|
DST = (__force u16) __swab16(DST);
|
||||||
|
break;
|
||||||
|
case 32:
|
||||||
|
DST = (__force u32) __swab32(DST);
|
||||||
|
break;
|
||||||
|
case 64:
|
||||||
|
DST = (__force u64) __swab64(DST);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
CONT;
|
||||||
|
|
||||||
/* CALL */
|
/* CALL */
|
||||||
JMP_CALL:
|
JMP_CALL:
|
||||||
|
|
|
@ -3012,8 +3012,10 @@ static bool is_reg64(struct bpf_verifier_env *env, struct bpf_insn *insn,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (class == BPF_ALU64 && op == BPF_END && (insn->imm == 16 || insn->imm == 32))
|
||||||
|
return false;
|
||||||
|
|
||||||
if (class == BPF_ALU64 || class == BPF_JMP ||
|
if (class == BPF_ALU64 || class == BPF_JMP ||
|
||||||
/* BPF_END always use BPF_ALU class. */
|
|
||||||
(class == BPF_ALU && op == BPF_END && insn->imm == 64))
|
(class == BPF_ALU && op == BPF_END && insn->imm == 64))
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
|
@ -13076,7 +13078,8 @@ static int check_alu_op(struct bpf_verifier_env *env, struct bpf_insn *insn)
|
||||||
} else {
|
} else {
|
||||||
if (insn->src_reg != BPF_REG_0 || insn->off != 0 ||
|
if (insn->src_reg != BPF_REG_0 || insn->off != 0 ||
|
||||||
(insn->imm != 16 && insn->imm != 32 && insn->imm != 64) ||
|
(insn->imm != 16 && insn->imm != 32 && insn->imm != 64) ||
|
||||||
BPF_CLASS(insn->code) == BPF_ALU64) {
|
(BPF_CLASS(insn->code) == BPF_ALU64 &&
|
||||||
|
BPF_SRC(insn->code) != BPF_TO_LE)) {
|
||||||
verbose(env, "BPF_END uses reserved fields\n");
|
verbose(env, "BPF_END uses reserved fields\n");
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue