Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branch 'jmp32-insns'

Jiong Wang says:

====================
v3 -> v4:
- Fixed rebase issue. JMP32 checks were missing in two new functions:
+ kernel/bpf/verifier.c:insn_is_cond_jump
+ drivers/net/ethernet/netronome/nfp/bpf/main.h:is_mbpf_cond_jump
(Daniel)
- Further rebased on top of latest llvm-readelf change.

v2 -> v3:
- Added missed check on JMP32 inside bpf_jit_build_body. (Sandipan)
- Wrap ?: statements in s390 port with brace. They are used by macros
which doesn't guard the operand with brace.
- Fixed the ',' issues test_verifier change.
- Reorder two selftests patches to be near each other.
- Rebased on top of latest bpf-next.

v1 -> v2:
- Updated encoding. Use reserved insn class 0x6 instead of packing with
existing BPF_JMP. (Alexei)
- Updated code comments in s390 port. (Martin)
- Separate JIT function for jeq32_imm in NFP port. (Jakub)
- Re-implemented auto-testing support. (Jakub)
- Moved testcases to test_verifer.c, plus more unit tests. (Jakub)
- Fixed JEQ/JNE range deduction. (Jakub)
- Also supported JSET in this patch set.
- Fixed/Improved range deduction for all the other operations. All C
programs under bpf selftest passed verification now.
- Improved min/max code implementation.
- Fixed bpftool/disassembler.

Current eBPF ISA has 32-bit sub-register and has defined a set of ALU32
instructions.

However, there is no JMP32 instructions, the consequence is code-gen for
32-bit sub-registers is not efficient. For example, explicit sign-extension
from 32-bit to 64-bit is needed for signed comparison.

Adding JMP32 instruction therefore could complete eBPF ISA on 32-bit
sub-register support. This also match those JMP32 instructions in most JIT
backends, for example x64-64 and AArch64. These new eBPF JMP32 instructions
could have one-to-one map on them.

A few verifier ALU32 related bugs has been fixed recently, and JMP32
introduced by this set further improves BPF sub-register ecosystem. Once
this is landed, BPF programs using 32-bit sub-register ISA could get
reasonably good support from verifier and JIT compilers. Users then could
compare the runtime efficiency of one BPF program under both modes, and
could use the one shown better from benchmark result.

From benchmark results on some Cilium BPF programs, for 64-bit arches,
after JMP32 introduced, programs compiled with -mattr=+alu32 (meaning
enable sub-register usage) are smaller in code size and generally smaller
in verifier processed insn number.

Benchmark results
===
Text size in bytes (generated by "size")
---
LLVM code-gen option default alu32 alu32/jmp32 change Vs. change Vs.
alu32 default
bpf_lb-DLB_L3.o: 6456 6280 6160 -1.91% -4.58%
bpf_lb-DLB_L4.o: 7848 7664 7136 -6.89% -9.07%
bpf_lb-DUNKNOWN.o: 2680 2664 2568 -3.60% -4.18%
bpf_lxc.o: 104824 104744 97360 -7.05% -7.12%
bpf_netdev.o: 23456 23576 21632 -8.25% -7.78%
bpf_overlay.o: 16184 16304 14648 -10.16% -9.49%

Processed instruction number
---
LLVM code-gen option default alu32 alu32/jmp32 change Vs. change Vs.
alu32 default
bpf_lb-DLB_L3.o: 1579 1281 1295 +1.09% -17.99%
bpf_lb-DLB_L4.o: 2045 1663 1556 -6.43% -23.91%
bpf_lb-DUNKNOWN.o: 606 513 501 -2.34% -17.33%
bpf_lxc.o: 85381 103218 94435 -8.51% +10.60%
bpf_netdev.o: 5246 5809 5200 -10.48% -0.08%
bpf_overlay.o: 2443 2705 2456 -9.02% -0.53%

It is even better for 32-bit arches like x32, arm32 and nfp etc, as now
some conditional jump will become JMP32 which doesn't require code-gen for
high 32-bit comparison.

Encoding
===
The new JMP32 instructions are using new BPF_JMP32 class which is using
the reserved eBPF class number 0x6. And BPF_JA/CALL/EXIT only exist for
BPF_JMP, they are reserved opcode for BPF_JMP32.

LLVM support
===
A couple of unit tests has been added and included in this set. Also LLVM
code-gen for JMP32 has been added, so you could just compile any BPF C
program with both -mcpu=probe and -mattr=+alu32 specified. If you are
compiling on a machine with kernel patched by this set, LLVM will select
the ISA automatically based on host probe results. Otherwise specify
-mcpu=v3 and -mattr=+alu32 could also force use JMP32 ISA.

LLVM support could be found at:

https://github.com/Netronome/llvm/tree/jmp32-v2

(clang driver also taught about the new "v3" processor, will send out
merge request for both clang and llvm once kernel set landed.)

JIT backends support
===
A couple of JIT backends has been supported in this set except SPARC and
MIPS. It shouldn't be a big issue for these two ports as LLVM default won't
generate JMP32 insns, it will only generate them when host machine is
probed to be with the support.

Thanks.
====================

Acked-by: Daniel Borkmann <daniel@iogearbox.net>
Signed-off-by: Alexei Starovoitov <ast@kernel.org>

+1736 -420
+8 -7
Documentation/networking/filter.txt
··· 865 865 BPF_STX 0x03 BPF_STX 0x03 866 866 BPF_ALU 0x04 BPF_ALU 0x04 867 867 BPF_JMP 0x05 BPF_JMP 0x05 868 - BPF_RET 0x06 [ class 6 unused, for future if needed ] 868 + BPF_RET 0x06 BPF_JMP32 0x06 869 869 BPF_MISC 0x07 BPF_ALU64 0x07 870 870 871 871 When BPF_CLASS(code) == BPF_ALU or BPF_JMP, 4th bit encodes source operand ... ··· 902 902 BPF_ARSH 0xc0 /* eBPF only: sign extending shift right */ 903 903 BPF_END 0xd0 /* eBPF only: endianness conversion */ 904 904 905 - If BPF_CLASS(code) == BPF_JMP, BPF_OP(code) is one of: 905 + If BPF_CLASS(code) == BPF_JMP or BPF_JMP32 [ in eBPF ], BPF_OP(code) is one of: 906 906 907 - BPF_JA 0x00 907 + BPF_JA 0x00 /* BPF_JMP only */ 908 908 BPF_JEQ 0x10 909 909 BPF_JGT 0x20 910 910 BPF_JGE 0x30 ··· 912 912 BPF_JNE 0x50 /* eBPF only: jump != */ 913 913 BPF_JSGT 0x60 /* eBPF only: signed '>' */ 914 914 BPF_JSGE 0x70 /* eBPF only: signed '>=' */ 915 - BPF_CALL 0x80 /* eBPF only: function call */ 916 - BPF_EXIT 0x90 /* eBPF only: function return */ 915 + BPF_CALL 0x80 /* eBPF BPF_JMP only: function call */ 916 + BPF_EXIT 0x90 /* eBPF BPF_JMP only: function return */ 917 917 BPF_JLT 0xa0 /* eBPF only: unsigned '<' */ 918 918 BPF_JLE 0xb0 /* eBPF only: unsigned '<=' */ 919 919 BPF_JSLT 0xc0 /* eBPF only: signed '<' */ ··· 936 936 operation. Classic BPF_RET | BPF_K means copy imm32 into return register 937 937 and perform function exit. eBPF is modeled to match CPU, so BPF_JMP | BPF_EXIT 938 938 in eBPF means function exit only. The eBPF program needs to store return 939 - value into register R0 before doing a BPF_EXIT. Class 6 in eBPF is currently 940 - unused and reserved for future use. 939 + value into register R0 before doing a BPF_EXIT. Class 6 in eBPF is used as 940 + BPF_JMP32 to mean exactly the same operations as BPF_JMP, but with 32-bit wide 941 + operands for the comparisons instead. 941 942 942 943 For load and store instructions the 8-bit 'code' field is divided as: 943 944
+44 -9
arch/arm/net/bpf_jit_32.c
··· 1083 1083 1084 1084 /* Arithmatic Operation */ 1085 1085 static inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm, 1086 - const u8 rn, struct jit_ctx *ctx, u8 op) { 1086 + const u8 rn, struct jit_ctx *ctx, u8 op, 1087 + bool is_jmp64) { 1087 1088 switch (op) { 1088 1089 case BPF_JSET: 1089 - emit(ARM_AND_R(ARM_IP, rt, rn), ctx); 1090 - emit(ARM_AND_R(ARM_LR, rd, rm), ctx); 1091 - emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); 1090 + if (is_jmp64) { 1091 + emit(ARM_AND_R(ARM_IP, rt, rn), ctx); 1092 + emit(ARM_AND_R(ARM_LR, rd, rm), ctx); 1093 + emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); 1094 + } else { 1095 + emit(ARM_ANDS_R(ARM_IP, rt, rn), ctx); 1096 + } 1092 1097 break; 1093 1098 case BPF_JEQ: 1094 1099 case BPF_JNE: ··· 1101 1096 case BPF_JGE: 1102 1097 case BPF_JLE: 1103 1098 case BPF_JLT: 1104 - emit(ARM_CMP_R(rd, rm), ctx); 1105 - _emit(ARM_COND_EQ, ARM_CMP_R(rt, rn), ctx); 1099 + if (is_jmp64) { 1100 + emit(ARM_CMP_R(rd, rm), ctx); 1101 + /* Only compare low halve if high halve are equal. */ 1102 + _emit(ARM_COND_EQ, ARM_CMP_R(rt, rn), ctx); 1103 + } else { 1104 + emit(ARM_CMP_R(rt, rn), ctx); 1105 + } 1106 1106 break; 1107 1107 case BPF_JSLE: 1108 1108 case BPF_JSGT: 1109 1109 emit(ARM_CMP_R(rn, rt), ctx); 1110 - emit(ARM_SBCS_R(ARM_IP, rm, rd), ctx); 1110 + if (is_jmp64) 1111 + emit(ARM_SBCS_R(ARM_IP, rm, rd), ctx); 1111 1112 break; 1112 1113 case BPF_JSLT: 1113 1114 case BPF_JSGE: 1114 1115 emit(ARM_CMP_R(rt, rn), ctx); 1115 - emit(ARM_SBCS_R(ARM_IP, rd, rm), ctx); 1116 + if (is_jmp64) 1117 + emit(ARM_SBCS_R(ARM_IP, rd, rm), ctx); 1116 1118 break; 1117 1119 } 1118 1120 } ··· 1627 1615 case BPF_JMP | BPF_JLT | BPF_X: 1628 1616 case BPF_JMP | BPF_JSLT | BPF_X: 1629 1617 case BPF_JMP | BPF_JSLE | BPF_X: 1618 + case BPF_JMP32 | BPF_JEQ | BPF_X: 1619 + case BPF_JMP32 | BPF_JGT | BPF_X: 1620 + case BPF_JMP32 | BPF_JGE | BPF_X: 1621 + case BPF_JMP32 | BPF_JNE | BPF_X: 1622 + case BPF_JMP32 | BPF_JSGT | BPF_X: 1623 + case BPF_JMP32 | BPF_JSGE | BPF_X: 1624 + case BPF_JMP32 | BPF_JSET | BPF_X: 1625 + case BPF_JMP32 | BPF_JLE | BPF_X: 1626 + case BPF_JMP32 | BPF_JLT | BPF_X: 1627 + case BPF_JMP32 | BPF_JSLT | BPF_X: 1628 + case BPF_JMP32 | BPF_JSLE | BPF_X: 1630 1629 /* Setup source registers */ 1631 1630 rm = arm_bpf_get_reg32(src_hi, tmp2[0], ctx); 1632 1631 rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); ··· 1664 1641 case BPF_JMP | BPF_JLE | BPF_K: 1665 1642 case BPF_JMP | BPF_JSLT | BPF_K: 1666 1643 case BPF_JMP | BPF_JSLE | BPF_K: 1644 + case BPF_JMP32 | BPF_JEQ | BPF_K: 1645 + case BPF_JMP32 | BPF_JGT | BPF_K: 1646 + case BPF_JMP32 | BPF_JGE | BPF_K: 1647 + case BPF_JMP32 | BPF_JNE | BPF_K: 1648 + case BPF_JMP32 | BPF_JSGT | BPF_K: 1649 + case BPF_JMP32 | BPF_JSGE | BPF_K: 1650 + case BPF_JMP32 | BPF_JSET | BPF_K: 1651 + case BPF_JMP32 | BPF_JLT | BPF_K: 1652 + case BPF_JMP32 | BPF_JLE | BPF_K: 1653 + case BPF_JMP32 | BPF_JSLT | BPF_K: 1654 + case BPF_JMP32 | BPF_JSLE | BPF_K: 1667 1655 if (off == 0) 1668 1656 break; 1669 1657 rm = tmp2[0]; ··· 1686 1652 rd = arm_bpf_get_reg64(dst, tmp, ctx); 1687 1653 1688 1654 /* Check for the condition */ 1689 - emit_ar_r(rd[0], rd[1], rm, rn, ctx, BPF_OP(code)); 1655 + emit_ar_r(rd[0], rd[1], rm, rn, ctx, BPF_OP(code), 1656 + BPF_CLASS(code) == BPF_JMP); 1690 1657 1691 1658 /* Setup JUMP instruction */ 1692 1659 jmp_offset = bpf2a32_offset(i+off, i, ctx);
+2
arch/arm/net/bpf_jit_32.h
··· 62 62 #define ARM_INST_ADDS_I 0x02900000 63 63 64 64 #define ARM_INST_AND_R 0x00000000 65 + #define ARM_INST_ANDS_R 0x00100000 65 66 #define ARM_INST_AND_I 0x02000000 66 67 67 68 #define ARM_INST_BIC_R 0x01c00000 ··· 173 172 #define ARM_ADC_I(rd, rn, imm) _AL3_I(ARM_INST_ADC, rd, rn, imm) 174 173 175 174 #define ARM_AND_R(rd, rn, rm) _AL3_R(ARM_INST_AND, rd, rn, rm) 175 + #define ARM_ANDS_R(rd, rn, rm) _AL3_R(ARM_INST_ANDS, rd, rn, rm) 176 176 #define ARM_AND_I(rd, rn, imm) _AL3_I(ARM_INST_AND, rd, rn, imm) 177 177 178 178 #define ARM_BIC_R(rd, rn, rm) _AL3_R(ARM_INST_BIC, rd, rn, rm)
+30 -7
arch/arm64/net/bpf_jit_comp.c
··· 362 362 const s16 off = insn->off; 363 363 const s32 imm = insn->imm; 364 364 const int i = insn - ctx->prog->insnsi; 365 - const bool is64 = BPF_CLASS(code) == BPF_ALU64; 365 + const bool is64 = BPF_CLASS(code) == BPF_ALU64 || 366 + BPF_CLASS(code) == BPF_JMP; 366 367 const bool isdw = BPF_SIZE(code) == BPF_DW; 367 368 u8 jmp_cond; 368 369 s32 jmp_offset; ··· 560 559 case BPF_JMP | BPF_JSLT | BPF_X: 561 560 case BPF_JMP | BPF_JSGE | BPF_X: 562 561 case BPF_JMP | BPF_JSLE | BPF_X: 563 - emit(A64_CMP(1, dst, src), ctx); 562 + case BPF_JMP32 | BPF_JEQ | BPF_X: 563 + case BPF_JMP32 | BPF_JGT | BPF_X: 564 + case BPF_JMP32 | BPF_JLT | BPF_X: 565 + case BPF_JMP32 | BPF_JGE | BPF_X: 566 + case BPF_JMP32 | BPF_JLE | BPF_X: 567 + case BPF_JMP32 | BPF_JNE | BPF_X: 568 + case BPF_JMP32 | BPF_JSGT | BPF_X: 569 + case BPF_JMP32 | BPF_JSLT | BPF_X: 570 + case BPF_JMP32 | BPF_JSGE | BPF_X: 571 + case BPF_JMP32 | BPF_JSLE | BPF_X: 572 + emit(A64_CMP(is64, dst, src), ctx); 564 573 emit_cond_jmp: 565 574 jmp_offset = bpf2a64_offset(i + off, i, ctx); 566 575 check_imm19(jmp_offset); ··· 612 601 emit(A64_B_(jmp_cond, jmp_offset), ctx); 613 602 break; 614 603 case BPF_JMP | BPF_JSET | BPF_X: 615 - emit(A64_TST(1, dst, src), ctx); 604 + case BPF_JMP32 | BPF_JSET | BPF_X: 605 + emit(A64_TST(is64, dst, src), ctx); 616 606 goto emit_cond_jmp; 617 607 /* IF (dst COND imm) JUMP off */ 618 608 case BPF_JMP | BPF_JEQ | BPF_K: ··· 626 614 case BPF_JMP | BPF_JSLT | BPF_K: 627 615 case BPF_JMP | BPF_JSGE | BPF_K: 628 616 case BPF_JMP | BPF_JSLE | BPF_K: 629 - emit_a64_mov_i(1, tmp, imm, ctx); 630 - emit(A64_CMP(1, dst, tmp), ctx); 617 + case BPF_JMP32 | BPF_JEQ | BPF_K: 618 + case BPF_JMP32 | BPF_JGT | BPF_K: 619 + case BPF_JMP32 | BPF_JLT | BPF_K: 620 + case BPF_JMP32 | BPF_JGE | BPF_K: 621 + case BPF_JMP32 | BPF_JLE | BPF_K: 622 + case BPF_JMP32 | BPF_JNE | BPF_K: 623 + case BPF_JMP32 | BPF_JSGT | BPF_K: 624 + case BPF_JMP32 | BPF_JSLT | BPF_K: 625 + case BPF_JMP32 | BPF_JSGE | BPF_K: 626 + case BPF_JMP32 | BPF_JSLE | BPF_K: 627 + emit_a64_mov_i(is64, tmp, imm, ctx); 628 + emit(A64_CMP(is64, dst, tmp), ctx); 631 629 goto emit_cond_jmp; 632 630 case BPF_JMP | BPF_JSET | BPF_K: 633 - emit_a64_mov_i(1, tmp, imm, ctx); 634 - emit(A64_TST(1, dst, tmp), ctx); 631 + case BPF_JMP32 | BPF_JSET | BPF_K: 632 + emit_a64_mov_i(is64, tmp, imm, ctx); 633 + emit(A64_TST(is64, dst, tmp), ctx); 635 634 goto emit_cond_jmp; 636 635 /* function call */ 637 636 case BPF_JMP | BPF_CALL:
+1
arch/powerpc/include/asm/ppc-opcode.h
··· 337 337 #define PPC_INST_DIVWU 0x7c000396 338 338 #define PPC_INST_DIVD 0x7c0003d2 339 339 #define PPC_INST_RLWINM 0x54000000 340 + #define PPC_INST_RLWINM_DOT 0x54000001 340 341 #define PPC_INST_RLWIMI 0x50000000 341 342 #define PPC_INST_RLDICL 0x78000000 342 343 #define PPC_INST_RLDICR 0x78000004
+4
arch/powerpc/net/bpf_jit.h
··· 165 165 #define PPC_RLWINM(d, a, i, mb, me) EMIT(PPC_INST_RLWINM | ___PPC_RA(d) | \ 166 166 ___PPC_RS(a) | __PPC_SH(i) | \ 167 167 __PPC_MB(mb) | __PPC_ME(me)) 168 + #define PPC_RLWINM_DOT(d, a, i, mb, me) EMIT(PPC_INST_RLWINM_DOT | \ 169 + ___PPC_RA(d) | ___PPC_RS(a) | \ 170 + __PPC_SH(i) | __PPC_MB(mb) | \ 171 + __PPC_ME(me)) 168 172 #define PPC_RLWIMI(d, a, i, mb, me) EMIT(PPC_INST_RLWIMI | ___PPC_RA(d) | \ 169 173 ___PPC_RS(a) | __PPC_SH(i) | \ 170 174 __PPC_MB(mb) | __PPC_ME(me))
+106 -14
arch/powerpc/net/bpf_jit_comp64.c
··· 768 768 case BPF_JMP | BPF_JGT | BPF_X: 769 769 case BPF_JMP | BPF_JSGT | BPF_K: 770 770 case BPF_JMP | BPF_JSGT | BPF_X: 771 + case BPF_JMP32 | BPF_JGT | BPF_K: 772 + case BPF_JMP32 | BPF_JGT | BPF_X: 773 + case BPF_JMP32 | BPF_JSGT | BPF_K: 774 + case BPF_JMP32 | BPF_JSGT | BPF_X: 771 775 true_cond = COND_GT; 772 776 goto cond_branch; 773 777 case BPF_JMP | BPF_JLT | BPF_K: 774 778 case BPF_JMP | BPF_JLT | BPF_X: 775 779 case BPF_JMP | BPF_JSLT | BPF_K: 776 780 case BPF_JMP | BPF_JSLT | BPF_X: 781 + case BPF_JMP32 | BPF_JLT | BPF_K: 782 + case BPF_JMP32 | BPF_JLT | BPF_X: 783 + case BPF_JMP32 | BPF_JSLT | BPF_K: 784 + case BPF_JMP32 | BPF_JSLT | BPF_X: 777 785 true_cond = COND_LT; 778 786 goto cond_branch; 779 787 case BPF_JMP | BPF_JGE | BPF_K: 780 788 case BPF_JMP | BPF_JGE | BPF_X: 781 789 case BPF_JMP | BPF_JSGE | BPF_K: 782 790 case BPF_JMP | BPF_JSGE | BPF_X: 791 + case BPF_JMP32 | BPF_JGE | BPF_K: 792 + case BPF_JMP32 | BPF_JGE | BPF_X: 793 + case BPF_JMP32 | BPF_JSGE | BPF_K: 794 + case BPF_JMP32 | BPF_JSGE | BPF_X: 783 795 true_cond = COND_GE; 784 796 goto cond_branch; 785 797 case BPF_JMP | BPF_JLE | BPF_K: 786 798 case BPF_JMP | BPF_JLE | BPF_X: 787 799 case BPF_JMP | BPF_JSLE | BPF_K: 788 800 case BPF_JMP | BPF_JSLE | BPF_X: 801 + case BPF_JMP32 | BPF_JLE | BPF_K: 802 + case BPF_JMP32 | BPF_JLE | BPF_X: 803 + case BPF_JMP32 | BPF_JSLE | BPF_K: 804 + case BPF_JMP32 | BPF_JSLE | BPF_X: 789 805 true_cond = COND_LE; 790 806 goto cond_branch; 791 807 case BPF_JMP | BPF_JEQ | BPF_K: 792 808 case BPF_JMP | BPF_JEQ | BPF_X: 809 + case BPF_JMP32 | BPF_JEQ | BPF_K: 810 + case BPF_JMP32 | BPF_JEQ | BPF_X: 793 811 true_cond = COND_EQ; 794 812 goto cond_branch; 795 813 case BPF_JMP | BPF_JNE | BPF_K: 796 814 case BPF_JMP | BPF_JNE | BPF_X: 815 + case BPF_JMP32 | BPF_JNE | BPF_K: 816 + case BPF_JMP32 | BPF_JNE | BPF_X: 797 817 true_cond = COND_NE; 798 818 goto cond_branch; 799 819 case BPF_JMP | BPF_JSET | BPF_K: 800 820 case BPF_JMP | BPF_JSET | BPF_X: 821 + case BPF_JMP32 | BPF_JSET | BPF_K: 822 + case BPF_JMP32 | BPF_JSET | BPF_X: 801 823 true_cond = COND_NE; 802 824 /* Fall through */ 803 825 ··· 831 809 case BPF_JMP | BPF_JLE | BPF_X: 832 810 case BPF_JMP | BPF_JEQ | BPF_X: 833 811 case BPF_JMP | BPF_JNE | BPF_X: 812 + case BPF_JMP32 | BPF_JGT | BPF_X: 813 + case BPF_JMP32 | BPF_JLT | BPF_X: 814 + case BPF_JMP32 | BPF_JGE | BPF_X: 815 + case BPF_JMP32 | BPF_JLE | BPF_X: 816 + case BPF_JMP32 | BPF_JEQ | BPF_X: 817 + case BPF_JMP32 | BPF_JNE | BPF_X: 834 818 /* unsigned comparison */ 835 - PPC_CMPLD(dst_reg, src_reg); 819 + if (BPF_CLASS(code) == BPF_JMP32) 820 + PPC_CMPLW(dst_reg, src_reg); 821 + else 822 + PPC_CMPLD(dst_reg, src_reg); 836 823 break; 837 824 case BPF_JMP | BPF_JSGT | BPF_X: 838 825 case BPF_JMP | BPF_JSLT | BPF_X: 839 826 case BPF_JMP | BPF_JSGE | BPF_X: 840 827 case BPF_JMP | BPF_JSLE | BPF_X: 828 + case BPF_JMP32 | BPF_JSGT | BPF_X: 829 + case BPF_JMP32 | BPF_JSLT | BPF_X: 830 + case BPF_JMP32 | BPF_JSGE | BPF_X: 831 + case BPF_JMP32 | BPF_JSLE | BPF_X: 841 832 /* signed comparison */ 842 - PPC_CMPD(dst_reg, src_reg); 833 + if (BPF_CLASS(code) == BPF_JMP32) 834 + PPC_CMPW(dst_reg, src_reg); 835 + else 836 + PPC_CMPD(dst_reg, src_reg); 843 837 break; 844 838 case BPF_JMP | BPF_JSET | BPF_X: 845 - PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, src_reg); 839 + case BPF_JMP32 | BPF_JSET | BPF_X: 840 + if (BPF_CLASS(code) == BPF_JMP) { 841 + PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, 842 + src_reg); 843 + } else { 844 + int tmp_reg = b2p[TMP_REG_1]; 845 + 846 + PPC_AND(tmp_reg, dst_reg, src_reg); 847 + PPC_RLWINM_DOT(tmp_reg, tmp_reg, 0, 0, 848 + 31); 849 + } 846 850 break; 847 851 case BPF_JMP | BPF_JNE | BPF_K: 848 852 case BPF_JMP | BPF_JEQ | BPF_K: ··· 876 828 case BPF_JMP | BPF_JLT | BPF_K: 877 829 case BPF_JMP | BPF_JGE | BPF_K: 878 830 case BPF_JMP | BPF_JLE | BPF_K: 831 + case BPF_JMP32 | BPF_JNE | BPF_K: 832 + case BPF_JMP32 | BPF_JEQ | BPF_K: 833 + case BPF_JMP32 | BPF_JGT | BPF_K: 834 + case BPF_JMP32 | BPF_JLT | BPF_K: 835 + case BPF_JMP32 | BPF_JGE | BPF_K: 836 + case BPF_JMP32 | BPF_JLE | BPF_K: 837 + { 838 + bool is_jmp32 = BPF_CLASS(code) == BPF_JMP32; 839 + 879 840 /* 880 841 * Need sign-extended load, so only positive 881 842 * values can be used as imm in cmpldi 882 843 */ 883 - if (imm >= 0 && imm < 32768) 884 - PPC_CMPLDI(dst_reg, imm); 885 - else { 844 + if (imm >= 0 && imm < 32768) { 845 + if (is_jmp32) 846 + PPC_CMPLWI(dst_reg, imm); 847 + else 848 + PPC_CMPLDI(dst_reg, imm); 849 + } else { 886 850 /* sign-extending load */ 887 851 PPC_LI32(b2p[TMP_REG_1], imm); 888 852 /* ... but unsigned comparison */ 889 - PPC_CMPLD(dst_reg, b2p[TMP_REG_1]); 853 + if (is_jmp32) 854 + PPC_CMPLW(dst_reg, 855 + b2p[TMP_REG_1]); 856 + else 857 + PPC_CMPLD(dst_reg, 858 + b2p[TMP_REG_1]); 890 859 } 891 860 break; 861 + } 892 862 case BPF_JMP | BPF_JSGT | BPF_K: 893 863 case BPF_JMP | BPF_JSLT | BPF_K: 894 864 case BPF_JMP | BPF_JSGE | BPF_K: 895 865 case BPF_JMP | BPF_JSLE | BPF_K: 866 + case BPF_JMP32 | BPF_JSGT | BPF_K: 867 + case BPF_JMP32 | BPF_JSLT | BPF_K: 868 + case BPF_JMP32 | BPF_JSGE | BPF_K: 869 + case BPF_JMP32 | BPF_JSLE | BPF_K: 870 + { 871 + bool is_jmp32 = BPF_CLASS(code) == BPF_JMP32; 872 + 896 873 /* 897 874 * signed comparison, so any 16-bit value 898 875 * can be used in cmpdi 899 876 */ 900 - if (imm >= -32768 && imm < 32768) 901 - PPC_CMPDI(dst_reg, imm); 902 - else { 877 + if (imm >= -32768 && imm < 32768) { 878 + if (is_jmp32) 879 + PPC_CMPWI(dst_reg, imm); 880 + else 881 + PPC_CMPDI(dst_reg, imm); 882 + } else { 903 883 PPC_LI32(b2p[TMP_REG_1], imm); 904 - PPC_CMPD(dst_reg, b2p[TMP_REG_1]); 884 + if (is_jmp32) 885 + PPC_CMPW(dst_reg, 886 + b2p[TMP_REG_1]); 887 + else 888 + PPC_CMPD(dst_reg, 889 + b2p[TMP_REG_1]); 905 890 } 906 891 break; 892 + } 907 893 case BPF_JMP | BPF_JSET | BPF_K: 894 + case BPF_JMP32 | BPF_JSET | BPF_K: 908 895 /* andi does not sign-extend the immediate */ 909 896 if (imm >= 0 && imm < 32768) 910 897 /* PPC_ANDI is _only/always_ dot-form */ 911 898 PPC_ANDI(b2p[TMP_REG_1], dst_reg, imm); 912 899 else { 913 - PPC_LI32(b2p[TMP_REG_1], imm); 914 - PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, 915 - b2p[TMP_REG_1]); 900 + int tmp_reg = b2p[TMP_REG_1]; 901 + 902 + PPC_LI32(tmp_reg, imm); 903 + if (BPF_CLASS(code) == BPF_JMP) { 904 + PPC_AND_DOT(tmp_reg, dst_reg, 905 + tmp_reg); 906 + } else { 907 + PPC_AND(tmp_reg, dst_reg, 908 + tmp_reg); 909 + PPC_RLWINM_DOT(tmp_reg, tmp_reg, 910 + 0, 0, 31); 911 + } 916 912 } 917 913 break; 918 914 }
+52 -14
arch/s390/net/bpf_jit_comp.c
··· 1110 1110 mask = 0xf000; /* j */ 1111 1111 goto branch_oc; 1112 1112 case BPF_JMP | BPF_JSGT | BPF_K: /* ((s64) dst > (s64) imm) */ 1113 + case BPF_JMP32 | BPF_JSGT | BPF_K: /* ((s32) dst > (s32) imm) */ 1113 1114 mask = 0x2000; /* jh */ 1114 1115 goto branch_ks; 1115 1116 case BPF_JMP | BPF_JSLT | BPF_K: /* ((s64) dst < (s64) imm) */ 1117 + case BPF_JMP32 | BPF_JSLT | BPF_K: /* ((s32) dst < (s32) imm) */ 1116 1118 mask = 0x4000; /* jl */ 1117 1119 goto branch_ks; 1118 1120 case BPF_JMP | BPF_JSGE | BPF_K: /* ((s64) dst >= (s64) imm) */ 1121 + case BPF_JMP32 | BPF_JSGE | BPF_K: /* ((s32) dst >= (s32) imm) */ 1119 1122 mask = 0xa000; /* jhe */ 1120 1123 goto branch_ks; 1121 1124 case BPF_JMP | BPF_JSLE | BPF_K: /* ((s64) dst <= (s64) imm) */ 1125 + case BPF_JMP32 | BPF_JSLE | BPF_K: /* ((s32) dst <= (s32) imm) */ 1122 1126 mask = 0xc000; /* jle */ 1123 1127 goto branch_ks; 1124 1128 case BPF_JMP | BPF_JGT | BPF_K: /* (dst_reg > imm) */ 1129 + case BPF_JMP32 | BPF_JGT | BPF_K: /* ((u32) dst_reg > (u32) imm) */ 1125 1130 mask = 0x2000; /* jh */ 1126 1131 goto branch_ku; 1127 1132 case BPF_JMP | BPF_JLT | BPF_K: /* (dst_reg < imm) */ 1133 + case BPF_JMP32 | BPF_JLT | BPF_K: /* ((u32) dst_reg < (u32) imm) */ 1128 1134 mask = 0x4000; /* jl */ 1129 1135 goto branch_ku; 1130 1136 case BPF_JMP | BPF_JGE | BPF_K: /* (dst_reg >= imm) */ 1137 + case BPF_JMP32 | BPF_JGE | BPF_K: /* ((u32) dst_reg >= (u32) imm) */ 1131 1138 mask = 0xa000; /* jhe */ 1132 1139 goto branch_ku; 1133 1140 case BPF_JMP | BPF_JLE | BPF_K: /* (dst_reg <= imm) */ 1141 + case BPF_JMP32 | BPF_JLE | BPF_K: /* ((u32) dst_reg <= (u32) imm) */ 1134 1142 mask = 0xc000; /* jle */ 1135 1143 goto branch_ku; 1136 1144 case BPF_JMP | BPF_JNE | BPF_K: /* (dst_reg != imm) */ 1145 + case BPF_JMP32 | BPF_JNE | BPF_K: /* ((u32) dst_reg != (u32) imm) */ 1137 1146 mask = 0x7000; /* jne */ 1138 1147 goto branch_ku; 1139 1148 case BPF_JMP | BPF_JEQ | BPF_K: /* (dst_reg == imm) */ 1149 + case BPF_JMP32 | BPF_JEQ | BPF_K: /* ((u32) dst_reg == (u32) imm) */ 1140 1150 mask = 0x8000; /* je */ 1141 1151 goto branch_ku; 1142 1152 case BPF_JMP | BPF_JSET | BPF_K: /* (dst_reg & imm) */ 1153 + case BPF_JMP32 | BPF_JSET | BPF_K: /* ((u32) dst_reg & (u32) imm) */ 1143 1154 mask = 0x7000; /* jnz */ 1144 - /* lgfi %w1,imm (load sign extend imm) */ 1145 - EMIT6_IMM(0xc0010000, REG_W1, imm); 1146 - /* ngr %w1,%dst */ 1147 - EMIT4(0xb9800000, REG_W1, dst_reg); 1155 + if (BPF_CLASS(insn->code) == BPF_JMP32) { 1156 + /* llilf %w1,imm (load zero extend imm) */ 1157 + EMIT6_IMM(0xc0010000, REG_W1, imm); 1158 + /* nr %w1,%dst */ 1159 + EMIT2(0x1400, REG_W1, dst_reg); 1160 + } else { 1161 + /* lgfi %w1,imm (load sign extend imm) */ 1162 + EMIT6_IMM(0xc0010000, REG_W1, imm); 1163 + /* ngr %w1,%dst */ 1164 + EMIT4(0xb9800000, REG_W1, dst_reg); 1165 + } 1148 1166 goto branch_oc; 1149 1167 1150 1168 case BPF_JMP | BPF_JSGT | BPF_X: /* ((s64) dst > (s64) src) */ 1169 + case BPF_JMP32 | BPF_JSGT | BPF_X: /* ((s32) dst > (s32) src) */ 1151 1170 mask = 0x2000; /* jh */ 1152 1171 goto branch_xs; 1153 1172 case BPF_JMP | BPF_JSLT | BPF_X: /* ((s64) dst < (s64) src) */ 1173 + case BPF_JMP32 | BPF_JSLT | BPF_X: /* ((s32) dst < (s32) src) */ 1154 1174 mask = 0x4000; /* jl */ 1155 1175 goto branch_xs; 1156 1176 case BPF_JMP | BPF_JSGE | BPF_X: /* ((s64) dst >= (s64) src) */ 1177 + case BPF_JMP32 | BPF_JSGE | BPF_X: /* ((s32) dst >= (s32) src) */ 1157 1178 mask = 0xa000; /* jhe */ 1158 1179 goto branch_xs; 1159 1180 case BPF_JMP | BPF_JSLE | BPF_X: /* ((s64) dst <= (s64) src) */ 1181 + case BPF_JMP32 | BPF_JSLE | BPF_X: /* ((s32) dst <= (s32) src) */ 1160 1182 mask = 0xc000; /* jle */ 1161 1183 goto branch_xs; 1162 1184 case BPF_JMP | BPF_JGT | BPF_X: /* (dst > src) */ 1185 + case BPF_JMP32 | BPF_JGT | BPF_X: /* ((u32) dst > (u32) src) */ 1163 1186 mask = 0x2000; /* jh */ 1164 1187 goto branch_xu; 1165 1188 case BPF_JMP | BPF_JLT | BPF_X: /* (dst < src) */ 1189 + case BPF_JMP32 | BPF_JLT | BPF_X: /* ((u32) dst < (u32) src) */ 1166 1190 mask = 0x4000; /* jl */ 1167 1191 goto branch_xu; 1168 1192 case BPF_JMP | BPF_JGE | BPF_X: /* (dst >= src) */ 1193 + case BPF_JMP32 | BPF_JGE | BPF_X: /* ((u32) dst >= (u32) src) */ 1169 1194 mask = 0xa000; /* jhe */ 1170 1195 goto branch_xu; 1171 1196 case BPF_JMP | BPF_JLE | BPF_X: /* (dst <= src) */ 1197 + case BPF_JMP32 | BPF_JLE | BPF_X: /* ((u32) dst <= (u32) src) */ 1172 1198 mask = 0xc000; /* jle */ 1173 1199 goto branch_xu; 1174 1200 case BPF_JMP | BPF_JNE | BPF_X: /* (dst != src) */ 1201 + case BPF_JMP32 | BPF_JNE | BPF_X: /* ((u32) dst != (u32) src) */ 1175 1202 mask = 0x7000; /* jne */ 1176 1203 goto branch_xu; 1177 1204 case BPF_JMP | BPF_JEQ | BPF_X: /* (dst == src) */ 1205 + case BPF_JMP32 | BPF_JEQ | BPF_X: /* ((u32) dst == (u32) src) */ 1178 1206 mask = 0x8000; /* je */ 1179 1207 goto branch_xu; 1180 1208 case BPF_JMP | BPF_JSET | BPF_X: /* (dst & src) */ 1209 + case BPF_JMP32 | BPF_JSET | BPF_X: /* ((u32) dst & (u32) src) */ 1210 + { 1211 + bool is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 1212 + 1181 1213 mask = 0x7000; /* jnz */ 1182 - /* ngrk %w1,%dst,%src */ 1183 - EMIT4_RRF(0xb9e40000, REG_W1, dst_reg, src_reg); 1214 + /* nrk or ngrk %w1,%dst,%src */ 1215 + EMIT4_RRF((is_jmp32 ? 0xb9f40000 : 0xb9e40000), 1216 + REG_W1, dst_reg, src_reg); 1184 1217 goto branch_oc; 1185 1218 branch_ks: 1186 1219 /* lgfi %w1,imm (load sign extend imm) */ 1187 1220 EMIT6_IMM(0xc0010000, REG_W1, imm); 1188 - /* cgrj %dst,%w1,mask,off */ 1189 - EMIT6_PCREL(0xec000000, 0x0064, dst_reg, REG_W1, i, off, mask); 1221 + /* crj or cgrj %dst,%w1,mask,off */ 1222 + EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0076 : 0x0064), 1223 + dst_reg, REG_W1, i, off, mask); 1190 1224 break; 1191 1225 branch_ku: 1192 1226 /* lgfi %w1,imm (load sign extend imm) */ 1193 1227 EMIT6_IMM(0xc0010000, REG_W1, imm); 1194 - /* clgrj %dst,%w1,mask,off */ 1195 - EMIT6_PCREL(0xec000000, 0x0065, dst_reg, REG_W1, i, off, mask); 1228 + /* clrj or clgrj %dst,%w1,mask,off */ 1229 + EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0077 : 0x0065), 1230 + dst_reg, REG_W1, i, off, mask); 1196 1231 break; 1197 1232 branch_xs: 1198 - /* cgrj %dst,%src,mask,off */ 1199 - EMIT6_PCREL(0xec000000, 0x0064, dst_reg, src_reg, i, off, mask); 1233 + /* crj or cgrj %dst,%src,mask,off */ 1234 + EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0076 : 0x0064), 1235 + dst_reg, src_reg, i, off, mask); 1200 1236 break; 1201 1237 branch_xu: 1202 - /* clgrj %dst,%src,mask,off */ 1203 - EMIT6_PCREL(0xec000000, 0x0065, dst_reg, src_reg, i, off, mask); 1238 + /* clrj or clgrj %dst,%src,mask,off */ 1239 + EMIT6_PCREL(0xec000000, (is_jmp32 ? 0x0077 : 0x0065), 1240 + dst_reg, src_reg, i, off, mask); 1204 1241 break; 1205 1242 branch_oc: 1206 1243 /* brc mask,jmp_off (branch instruction needs 4 bytes) */ 1207 1244 jmp_off = addrs[i + off + 1] - (addrs[i + 1] - 4); 1208 1245 EMIT4_PCREL(0xa7040000 | mask << 8, jmp_off); 1209 1246 break; 1247 + } 1210 1248 default: /* too complex, give up */ 1211 1249 pr_err("Unknown opcode %02x\n", insn->code); 1212 1250 return -1;
+40 -6
arch/x86/net/bpf_jit_comp.c
··· 881 881 case BPF_JMP | BPF_JSLT | BPF_X: 882 882 case BPF_JMP | BPF_JSGE | BPF_X: 883 883 case BPF_JMP | BPF_JSLE | BPF_X: 884 + case BPF_JMP32 | BPF_JEQ | BPF_X: 885 + case BPF_JMP32 | BPF_JNE | BPF_X: 886 + case BPF_JMP32 | BPF_JGT | BPF_X: 887 + case BPF_JMP32 | BPF_JLT | BPF_X: 888 + case BPF_JMP32 | BPF_JGE | BPF_X: 889 + case BPF_JMP32 | BPF_JLE | BPF_X: 890 + case BPF_JMP32 | BPF_JSGT | BPF_X: 891 + case BPF_JMP32 | BPF_JSLT | BPF_X: 892 + case BPF_JMP32 | BPF_JSGE | BPF_X: 893 + case BPF_JMP32 | BPF_JSLE | BPF_X: 884 894 /* cmp dst_reg, src_reg */ 885 - EMIT3(add_2mod(0x48, dst_reg, src_reg), 0x39, 886 - add_2reg(0xC0, dst_reg, src_reg)); 895 + if (BPF_CLASS(insn->code) == BPF_JMP) 896 + EMIT1(add_2mod(0x48, dst_reg, src_reg)); 897 + else if (is_ereg(dst_reg) || is_ereg(src_reg)) 898 + EMIT1(add_2mod(0x40, dst_reg, src_reg)); 899 + EMIT2(0x39, add_2reg(0xC0, dst_reg, src_reg)); 887 900 goto emit_cond_jmp; 888 901 889 902 case BPF_JMP | BPF_JSET | BPF_X: 903 + case BPF_JMP32 | BPF_JSET | BPF_X: 890 904 /* test dst_reg, src_reg */ 891 - EMIT3(add_2mod(0x48, dst_reg, src_reg), 0x85, 892 - add_2reg(0xC0, dst_reg, src_reg)); 905 + if (BPF_CLASS(insn->code) == BPF_JMP) 906 + EMIT1(add_2mod(0x48, dst_reg, src_reg)); 907 + else if (is_ereg(dst_reg) || is_ereg(src_reg)) 908 + EMIT1(add_2mod(0x40, dst_reg, src_reg)); 909 + EMIT2(0x85, add_2reg(0xC0, dst_reg, src_reg)); 893 910 goto emit_cond_jmp; 894 911 895 912 case BPF_JMP | BPF_JSET | BPF_K: 913 + case BPF_JMP32 | BPF_JSET | BPF_K: 896 914 /* test dst_reg, imm32 */ 897 - EMIT1(add_1mod(0x48, dst_reg)); 915 + if (BPF_CLASS(insn->code) == BPF_JMP) 916 + EMIT1(add_1mod(0x48, dst_reg)); 917 + else if (is_ereg(dst_reg)) 918 + EMIT1(add_1mod(0x40, dst_reg)); 898 919 EMIT2_off32(0xF7, add_1reg(0xC0, dst_reg), imm32); 899 920 goto emit_cond_jmp; 900 921 ··· 929 908 case BPF_JMP | BPF_JSLT | BPF_K: 930 909 case BPF_JMP | BPF_JSGE | BPF_K: 931 910 case BPF_JMP | BPF_JSLE | BPF_K: 911 + case BPF_JMP32 | BPF_JEQ | BPF_K: 912 + case BPF_JMP32 | BPF_JNE | BPF_K: 913 + case BPF_JMP32 | BPF_JGT | BPF_K: 914 + case BPF_JMP32 | BPF_JLT | BPF_K: 915 + case BPF_JMP32 | BPF_JGE | BPF_K: 916 + case BPF_JMP32 | BPF_JLE | BPF_K: 917 + case BPF_JMP32 | BPF_JSGT | BPF_K: 918 + case BPF_JMP32 | BPF_JSLT | BPF_K: 919 + case BPF_JMP32 | BPF_JSGE | BPF_K: 920 + case BPF_JMP32 | BPF_JSLE | BPF_K: 932 921 /* cmp dst_reg, imm8/32 */ 933 - EMIT1(add_1mod(0x48, dst_reg)); 922 + if (BPF_CLASS(insn->code) == BPF_JMP) 923 + EMIT1(add_1mod(0x48, dst_reg)); 924 + else if (is_ereg(dst_reg)) 925 + EMIT1(add_1mod(0x40, dst_reg)); 934 926 935 927 if (is_imm8(imm32)) 936 928 EMIT3(0x83, add_1reg(0xF8, dst_reg), imm32);
+85 -36
arch/x86/net/bpf_jit_comp32.c
··· 2072 2072 case BPF_JMP | BPF_JSGT | BPF_X: 2073 2073 case BPF_JMP | BPF_JSLE | BPF_X: 2074 2074 case BPF_JMP | BPF_JSLT | BPF_X: 2075 - case BPF_JMP | BPF_JSGE | BPF_X: { 2075 + case BPF_JMP | BPF_JSGE | BPF_X: 2076 + case BPF_JMP32 | BPF_JEQ | BPF_X: 2077 + case BPF_JMP32 | BPF_JNE | BPF_X: 2078 + case BPF_JMP32 | BPF_JGT | BPF_X: 2079 + case BPF_JMP32 | BPF_JLT | BPF_X: 2080 + case BPF_JMP32 | BPF_JGE | BPF_X: 2081 + case BPF_JMP32 | BPF_JLE | BPF_X: 2082 + case BPF_JMP32 | BPF_JSGT | BPF_X: 2083 + case BPF_JMP32 | BPF_JSLE | BPF_X: 2084 + case BPF_JMP32 | BPF_JSLT | BPF_X: 2085 + case BPF_JMP32 | BPF_JSGE | BPF_X: { 2086 + bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; 2076 2087 u8 dreg_lo = dstk ? IA32_EAX : dst_lo; 2077 2088 u8 dreg_hi = dstk ? IA32_EDX : dst_hi; 2078 2089 u8 sreg_lo = sstk ? IA32_ECX : src_lo; ··· 2092 2081 if (dstk) { 2093 2082 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX), 2094 2083 STACK_VAR(dst_lo)); 2095 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX), 2096 - STACK_VAR(dst_hi)); 2084 + if (is_jmp64) 2085 + EMIT3(0x8B, 2086 + add_2reg(0x40, IA32_EBP, 2087 + IA32_EDX), 2088 + STACK_VAR(dst_hi)); 2097 2089 } 2098 2090 2099 2091 if (sstk) { 2100 2092 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX), 2101 2093 STACK_VAR(src_lo)); 2102 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EBX), 2103 - STACK_VAR(src_hi)); 2094 + if (is_jmp64) 2095 + EMIT3(0x8B, 2096 + add_2reg(0x40, IA32_EBP, 2097 + IA32_EBX), 2098 + STACK_VAR(src_hi)); 2104 2099 } 2105 2100 2106 - /* cmp dreg_hi,sreg_hi */ 2107 - EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi)); 2108 - EMIT2(IA32_JNE, 2); 2101 + if (is_jmp64) { 2102 + /* cmp dreg_hi,sreg_hi */ 2103 + EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi)); 2104 + EMIT2(IA32_JNE, 2); 2105 + } 2109 2106 /* cmp dreg_lo,sreg_lo */ 2110 2107 EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo)); 2111 2108 goto emit_cond_jmp; 2112 2109 } 2113 - case BPF_JMP | BPF_JSET | BPF_X: { 2110 + case BPF_JMP | BPF_JSET | BPF_X: 2111 + case BPF_JMP32 | BPF_JSET | BPF_X: { 2112 + bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; 2114 2113 u8 dreg_lo = dstk ? IA32_EAX : dst_lo; 2115 2114 u8 dreg_hi = dstk ? IA32_EDX : dst_hi; 2116 2115 u8 sreg_lo = sstk ? IA32_ECX : src_lo; ··· 2129 2108 if (dstk) { 2130 2109 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX), 2131 2110 STACK_VAR(dst_lo)); 2132 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX), 2133 - STACK_VAR(dst_hi)); 2111 + if (is_jmp64) 2112 + EMIT3(0x8B, 2113 + add_2reg(0x40, IA32_EBP, 2114 + IA32_EDX), 2115 + STACK_VAR(dst_hi)); 2134 2116 } 2135 2117 2136 2118 if (sstk) { 2137 2119 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_ECX), 2138 2120 STACK_VAR(src_lo)); 2139 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EBX), 2140 - STACK_VAR(src_hi)); 2121 + if (is_jmp64) 2122 + EMIT3(0x8B, 2123 + add_2reg(0x40, IA32_EBP, 2124 + IA32_EBX), 2125 + STACK_VAR(src_hi)); 2141 2126 } 2142 2127 /* and dreg_lo,sreg_lo */ 2143 2128 EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo)); ··· 2153 2126 EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi)); 2154 2127 goto emit_cond_jmp; 2155 2128 } 2156 - case BPF_JMP | BPF_JSET | BPF_K: { 2157 - u32 hi; 2129 + case BPF_JMP | BPF_JSET | BPF_K: 2130 + case BPF_JMP32 | BPF_JSET | BPF_K: { 2131 + bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; 2158 2132 u8 dreg_lo = dstk ? IA32_EAX : dst_lo; 2159 2133 u8 dreg_hi = dstk ? IA32_EDX : dst_hi; 2160 2134 u8 sreg_lo = IA32_ECX; 2161 2135 u8 sreg_hi = IA32_EBX; 2136 + u32 hi; 2162 2137 2163 2138 if (dstk) { 2164 2139 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX), 2165 2140 STACK_VAR(dst_lo)); 2166 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX), 2167 - STACK_VAR(dst_hi)); 2141 + if (is_jmp64) 2142 + EMIT3(0x8B, 2143 + add_2reg(0x40, IA32_EBP, 2144 + IA32_EDX), 2145 + STACK_VAR(dst_hi)); 2168 2146 } 2169 - hi = imm32 & (1<<31) ? (u32)~0 : 0; 2170 2147 2171 2148 /* mov ecx,imm32 */ 2172 - EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32); 2173 - /* mov ebx,imm32 */ 2174 - EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi); 2149 + EMIT2_off32(0xC7, add_1reg(0xC0, sreg_lo), imm32); 2175 2150 2176 2151 /* and dreg_lo,sreg_lo */ 2177 2152 EMIT2(0x23, add_2reg(0xC0, sreg_lo, dreg_lo)); 2178 - /* and dreg_hi,sreg_hi */ 2179 - EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi)); 2180 - /* or dreg_lo,dreg_hi */ 2181 - EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi)); 2153 + if (is_jmp64) { 2154 + hi = imm32 & (1 << 31) ? (u32)~0 : 0; 2155 + /* mov ebx,imm32 */ 2156 + EMIT2_off32(0xC7, add_1reg(0xC0, sreg_hi), hi); 2157 + /* and dreg_hi,sreg_hi */ 2158 + EMIT2(0x23, add_2reg(0xC0, sreg_hi, dreg_hi)); 2159 + /* or dreg_lo,dreg_hi */ 2160 + EMIT2(0x09, add_2reg(0xC0, dreg_lo, dreg_hi)); 2161 + } 2182 2162 goto emit_cond_jmp; 2183 2163 } 2184 2164 case BPF_JMP | BPF_JEQ | BPF_K: ··· 2197 2163 case BPF_JMP | BPF_JSGT | BPF_K: 2198 2164 case BPF_JMP | BPF_JSLE | BPF_K: 2199 2165 case BPF_JMP | BPF_JSLT | BPF_K: 2200 - case BPF_JMP | BPF_JSGE | BPF_K: { 2201 - u32 hi; 2166 + case BPF_JMP | BPF_JSGE | BPF_K: 2167 + case BPF_JMP32 | BPF_JEQ | BPF_K: 2168 + case BPF_JMP32 | BPF_JNE | BPF_K: 2169 + case BPF_JMP32 | BPF_JGT | BPF_K: 2170 + case BPF_JMP32 | BPF_JLT | BPF_K: 2171 + case BPF_JMP32 | BPF_JGE | BPF_K: 2172 + case BPF_JMP32 | BPF_JLE | BPF_K: 2173 + case BPF_JMP32 | BPF_JSGT | BPF_K: 2174 + case BPF_JMP32 | BPF_JSLE | BPF_K: 2175 + case BPF_JMP32 | BPF_JSLT | BPF_K: 2176 + case BPF_JMP32 | BPF_JSGE | BPF_K: { 2177 + bool is_jmp64 = BPF_CLASS(insn->code) == BPF_JMP; 2202 2178 u8 dreg_lo = dstk ? IA32_EAX : dst_lo; 2203 2179 u8 dreg_hi = dstk ? IA32_EDX : dst_hi; 2204 2180 u8 sreg_lo = IA32_ECX; 2205 2181 u8 sreg_hi = IA32_EBX; 2182 + u32 hi; 2206 2183 2207 2184 if (dstk) { 2208 2185 EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EAX), 2209 2186 STACK_VAR(dst_lo)); 2210 - EMIT3(0x8B, add_2reg(0x40, IA32_EBP, IA32_EDX), 2211 - STACK_VAR(dst_hi)); 2187 + if (is_jmp64) 2188 + EMIT3(0x8B, 2189 + add_2reg(0x40, IA32_EBP, 2190 + IA32_EDX), 2191 + STACK_VAR(dst_hi)); 2212 2192 } 2213 2193 2214 - hi = imm32 & (1<<31) ? (u32)~0 : 0; 2215 2194 /* mov ecx,imm32 */ 2216 2195 EMIT2_off32(0xC7, add_1reg(0xC0, IA32_ECX), imm32); 2217 - /* mov ebx,imm32 */ 2218 - EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi); 2219 - 2220 - /* cmp dreg_hi,sreg_hi */ 2221 - EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi)); 2222 - EMIT2(IA32_JNE, 2); 2196 + if (is_jmp64) { 2197 + hi = imm32 & (1 << 31) ? (u32)~0 : 0; 2198 + /* mov ebx,imm32 */ 2199 + EMIT2_off32(0xC7, add_1reg(0xC0, IA32_EBX), hi); 2200 + /* cmp dreg_hi,sreg_hi */ 2201 + EMIT2(0x39, add_2reg(0xC0, dreg_hi, sreg_hi)); 2202 + EMIT2(IA32_JNE, 2); 2203 + } 2223 2204 /* cmp dreg_lo,sreg_lo */ 2224 2205 EMIT2(0x39, add_2reg(0xC0, dreg_lo, sreg_lo)); 2225 2206
+73 -24
drivers/net/ethernet/netronome/nfp/bpf/jit.c
··· 1334 1334 1335 1335 wrp_test_reg_one(nfp_prog, insn->dst_reg * 2, alu_op, 1336 1336 insn->src_reg * 2, br_mask, insn->off); 1337 - wrp_test_reg_one(nfp_prog, insn->dst_reg * 2 + 1, alu_op, 1338 - insn->src_reg * 2 + 1, br_mask, insn->off); 1337 + if (is_mbpf_jmp64(meta)) 1338 + wrp_test_reg_one(nfp_prog, insn->dst_reg * 2 + 1, alu_op, 1339 + insn->src_reg * 2 + 1, br_mask, insn->off); 1339 1340 1340 1341 return 0; 1341 1342 } ··· 1391 1390 else 1392 1391 emit_alu(nfp_prog, reg_none(), tmp_reg, alu_op, reg_a(reg)); 1393 1392 1394 - tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); 1395 - if (!code->swap) 1396 - emit_alu(nfp_prog, reg_none(), 1397 - reg_a(reg + 1), carry_op, tmp_reg); 1398 - else 1399 - emit_alu(nfp_prog, reg_none(), 1400 - tmp_reg, carry_op, reg_a(reg + 1)); 1393 + if (is_mbpf_jmp64(meta)) { 1394 + tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); 1395 + if (!code->swap) 1396 + emit_alu(nfp_prog, reg_none(), 1397 + reg_a(reg + 1), carry_op, tmp_reg); 1398 + else 1399 + emit_alu(nfp_prog, reg_none(), 1400 + tmp_reg, carry_op, reg_a(reg + 1)); 1401 + } 1401 1402 1402 1403 emit_br(nfp_prog, code->br_mask, insn->off, 0); 1403 1404 ··· 1426 1423 } 1427 1424 1428 1425 emit_alu(nfp_prog, reg_none(), reg_a(areg), ALU_OP_SUB, reg_b(breg)); 1429 - emit_alu(nfp_prog, reg_none(), 1430 - reg_a(areg + 1), ALU_OP_SUB_C, reg_b(breg + 1)); 1426 + if (is_mbpf_jmp64(meta)) 1427 + emit_alu(nfp_prog, reg_none(), 1428 + reg_a(areg + 1), ALU_OP_SUB_C, reg_b(breg + 1)); 1431 1429 emit_br(nfp_prog, code->br_mask, insn->off, 0); 1432 1430 1433 1431 return 0; ··· 3052 3048 return 0; 3053 3049 } 3054 3050 3051 + static int jeq32_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) 3052 + { 3053 + const struct bpf_insn *insn = &meta->insn; 3054 + swreg tmp_reg; 3055 + 3056 + tmp_reg = ur_load_imm_any(nfp_prog, insn->imm, imm_b(nfp_prog)); 3057 + emit_alu(nfp_prog, reg_none(), 3058 + reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); 3059 + emit_br(nfp_prog, BR_BEQ, insn->off, 0); 3060 + 3061 + return 0; 3062 + } 3063 + 3055 3064 static int jset_imm(struct nfp_prog *nfp_prog, struct nfp_insn_meta *meta) 3056 3065 { 3057 3066 const struct bpf_insn *insn = &meta->insn; ··· 3078 3061 /* Upper word of the mask can only be 0 or ~0 from sign extension, 3079 3062 * so either ignore it or OR the whole thing in. 3080 3063 */ 3081 - if (imm >> 32) 3064 + if (is_mbpf_jmp64(meta) && imm >> 32) { 3082 3065 emit_alu(nfp_prog, reg_none(), 3083 3066 reg_a(dst_gpr + 1), ALU_OP_OR, imm_b(nfp_prog)); 3067 + } 3084 3068 emit_br(nfp_prog, BR_BNE, insn->off, 0); 3085 3069 3086 3070 return 0; ··· 3091 3073 { 3092 3074 const struct bpf_insn *insn = &meta->insn; 3093 3075 u64 imm = insn->imm; /* sign extend */ 3076 + bool is_jmp32 = is_mbpf_jmp32(meta); 3094 3077 swreg tmp_reg; 3095 3078 3096 3079 if (!imm) { 3097 - emit_alu(nfp_prog, reg_none(), reg_a(insn->dst_reg * 2), 3098 - ALU_OP_OR, reg_b(insn->dst_reg * 2 + 1)); 3080 + if (is_jmp32) 3081 + emit_alu(nfp_prog, reg_none(), reg_none(), ALU_OP_NONE, 3082 + reg_b(insn->dst_reg * 2)); 3083 + else 3084 + emit_alu(nfp_prog, reg_none(), reg_a(insn->dst_reg * 2), 3085 + ALU_OP_OR, reg_b(insn->dst_reg * 2 + 1)); 3099 3086 emit_br(nfp_prog, BR_BNE, insn->off, 0); 3100 3087 return 0; 3101 3088 } ··· 3109 3086 emit_alu(nfp_prog, reg_none(), 3110 3087 reg_a(insn->dst_reg * 2), ALU_OP_XOR, tmp_reg); 3111 3088 emit_br(nfp_prog, BR_BNE, insn->off, 0); 3089 + 3090 + if (is_jmp32) 3091 + return 0; 3112 3092 3113 3093 tmp_reg = ur_load_imm_any(nfp_prog, imm >> 32, imm_b(nfp_prog)); 3114 3094 emit_alu(nfp_prog, reg_none(), ··· 3127 3101 3128 3102 emit_alu(nfp_prog, imm_a(nfp_prog), reg_a(insn->dst_reg * 2), 3129 3103 ALU_OP_XOR, reg_b(insn->src_reg * 2)); 3130 - emit_alu(nfp_prog, imm_b(nfp_prog), reg_a(insn->dst_reg * 2 + 1), 3131 - ALU_OP_XOR, reg_b(insn->src_reg * 2 + 1)); 3132 - emit_alu(nfp_prog, reg_none(), 3133 - imm_a(nfp_prog), ALU_OP_OR, imm_b(nfp_prog)); 3104 + if (is_mbpf_jmp64(meta)) { 3105 + emit_alu(nfp_prog, imm_b(nfp_prog), 3106 + reg_a(insn->dst_reg * 2 + 1), ALU_OP_XOR, 3107 + reg_b(insn->src_reg * 2 + 1)); 3108 + emit_alu(nfp_prog, reg_none(), imm_a(nfp_prog), ALU_OP_OR, 3109 + imm_b(nfp_prog)); 3110 + } 3134 3111 emit_br(nfp_prog, BR_BEQ, insn->off, 0); 3135 3112 3136 3113 return 0; ··· 3398 3369 [BPF_JMP | BPF_JSLE | BPF_X] = cmp_reg, 3399 3370 [BPF_JMP | BPF_JSET | BPF_X] = jset_reg, 3400 3371 [BPF_JMP | BPF_JNE | BPF_X] = jne_reg, 3372 + [BPF_JMP32 | BPF_JEQ | BPF_K] = jeq32_imm, 3373 + [BPF_JMP32 | BPF_JGT | BPF_K] = cmp_imm, 3374 + [BPF_JMP32 | BPF_JGE | BPF_K] = cmp_imm, 3375 + [BPF_JMP32 | BPF_JLT | BPF_K] = cmp_imm, 3376 + [BPF_JMP32 | BPF_JLE | BPF_K] = cmp_imm, 3377 + [BPF_JMP32 | BPF_JSGT | BPF_K] =cmp_imm, 3378 + [BPF_JMP32 | BPF_JSGE | BPF_K] =cmp_imm, 3379 + [BPF_JMP32 | BPF_JSLT | BPF_K] =cmp_imm, 3380 + [BPF_JMP32 | BPF_JSLE | BPF_K] =cmp_imm, 3381 + [BPF_JMP32 | BPF_JSET | BPF_K] =jset_imm, 3382 + [BPF_JMP32 | BPF_JNE | BPF_K] = jne_imm, 3383 + [BPF_JMP32 | BPF_JEQ | BPF_X] = jeq_reg, 3384 + [BPF_JMP32 | BPF_JGT | BPF_X] = cmp_reg, 3385 + [BPF_JMP32 | BPF_JGE | BPF_X] = cmp_reg, 3386 + [BPF_JMP32 | BPF_JLT | BPF_X] = cmp_reg, 3387 + [BPF_JMP32 | BPF_JLE | BPF_X] = cmp_reg, 3388 + [BPF_JMP32 | BPF_JSGT | BPF_X] =cmp_reg, 3389 + [BPF_JMP32 | BPF_JSGE | BPF_X] =cmp_reg, 3390 + [BPF_JMP32 | BPF_JSLT | BPF_X] =cmp_reg, 3391 + [BPF_JMP32 | BPF_JSLE | BPF_X] =cmp_reg, 3392 + [BPF_JMP32 | BPF_JSET | BPF_X] =jset_reg, 3393 + [BPF_JMP32 | BPF_JNE | BPF_X] = jne_reg, 3401 3394 [BPF_JMP | BPF_CALL] = call, 3402 3395 [BPF_JMP | BPF_EXIT] = jmp_exit, 3403 3396 }; ··· 3448 3397 list_for_each_entry(meta, &nfp_prog->insns, l) { 3449 3398 if (meta->flags & FLAG_INSN_SKIP_MASK) 3450 3399 continue; 3451 - if (BPF_CLASS(meta->insn.code) != BPF_JMP) 3400 + if (!is_mbpf_jmp(meta)) 3452 3401 continue; 3453 3402 if (meta->insn.code == (BPF_JMP | BPF_EXIT) && 3454 3403 !nfp_is_main_function(meta)) ··· 3809 3758 if (meta->flags & FLAG_INSN_SKIP_MASK) 3810 3759 continue; 3811 3760 3812 - if (BPF_CLASS(insn.code) != BPF_ALU && 3813 - BPF_CLASS(insn.code) != BPF_ALU64 && 3814 - BPF_CLASS(insn.code) != BPF_JMP) 3761 + if (!is_mbpf_alu(meta) && !is_mbpf_jmp(meta)) 3815 3762 continue; 3816 3763 if (BPF_SRC(insn.code) != BPF_K) 3817 3764 continue; 3818 3765 if (insn.imm >= 0) 3819 3766 continue; 3820 3767 3821 - if (BPF_CLASS(insn.code) == BPF_JMP) { 3768 + if (is_mbpf_jmp(meta)) { 3822 3769 switch (BPF_OP(insn.code)) { 3823 3770 case BPF_JGE: 3824 3771 case BPF_JSGE: ··· 4387 4338 unsigned int dst_idx; 4388 4339 bool pseudo_call; 4389 4340 4390 - if (BPF_CLASS(code) != BPF_JMP) 4341 + if (!is_mbpf_jmp(meta)) 4391 4342 continue; 4392 4343 if (BPF_OP(code) == BPF_EXIT) 4393 4344 continue;
+20 -2
drivers/net/ethernet/netronome/nfp/bpf/main.h
··· 365 365 return (meta->insn.code & ~BPF_SIZE_MASK) == (BPF_LDX | BPF_MEM); 366 366 } 367 367 368 + static inline bool is_mbpf_jmp32(const struct nfp_insn_meta *meta) 369 + { 370 + return mbpf_class(meta) == BPF_JMP32; 371 + } 372 + 373 + static inline bool is_mbpf_jmp64(const struct nfp_insn_meta *meta) 374 + { 375 + return mbpf_class(meta) == BPF_JMP; 376 + } 377 + 378 + static inline bool is_mbpf_jmp(const struct nfp_insn_meta *meta) 379 + { 380 + return is_mbpf_jmp32(meta) || is_mbpf_jmp64(meta); 381 + } 382 + 368 383 static inline bool is_mbpf_store(const struct nfp_insn_meta *meta) 369 384 { 370 385 return (meta->insn.code & ~BPF_SIZE_MASK) == (BPF_STX | BPF_MEM); ··· 434 419 { 435 420 u8 op; 436 421 437 - if (BPF_CLASS(meta->insn.code) != BPF_JMP) 422 + if (is_mbpf_jmp32(meta)) 423 + return true; 424 + 425 + if (!is_mbpf_jmp64(meta)) 438 426 return false; 439 427 440 - op = BPF_OP(meta->insn.code); 428 + op = mbpf_op(meta); 441 429 return op != BPF_JA && op != BPF_EXIT && op != BPF_CALL; 442 430 } 443 431
+20
include/linux/filter.h
··· 277 277 .off = OFF, \ 278 278 .imm = IMM }) 279 279 280 + /* Like BPF_JMP_REG, but with 32-bit wide operands for comparison. */ 281 + 282 + #define BPF_JMP32_REG(OP, DST, SRC, OFF) \ 283 + ((struct bpf_insn) { \ 284 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_X, \ 285 + .dst_reg = DST, \ 286 + .src_reg = SRC, \ 287 + .off = OFF, \ 288 + .imm = 0 }) 289 + 290 + /* Like BPF_JMP_IMM, but with 32-bit wide operands for comparison. */ 291 + 292 + #define BPF_JMP32_IMM(OP, DST, IMM, OFF) \ 293 + ((struct bpf_insn) { \ 294 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \ 295 + .dst_reg = DST, \ 296 + .src_reg = 0, \ 297 + .off = OFF, \ 298 + .imm = IMM }) 299 + 280 300 /* Unconditional jumps, goto pc + off16 */ 281 301 282 302 #define BPF_JMP_A(OFF) \
+1
include/uapi/linux/bpf.h
··· 14 14 /* Extended instruction set based on top of classic BPF */ 15 15 16 16 /* instruction classes */ 17 + #define BPF_JMP32 0x06 /* jmp mode in word width */ 17 18 #define BPF_ALU64 0x07 /* alu mode in double word width */ 18 19 19 20 /* ld/ldx fields */
+86 -135
kernel/bpf/core.c
··· 362 362 insn = prog->insnsi + end_old; 363 363 } 364 364 code = insn->code; 365 - if (BPF_CLASS(code) != BPF_JMP || 365 + if ((BPF_CLASS(code) != BPF_JMP && 366 + BPF_CLASS(code) != BPF_JMP32) || 366 367 BPF_OP(code) == BPF_EXIT) 367 368 continue; 368 369 /* Adjust offset of jmps if we cross patch boundaries. */ ··· 949 948 *to++ = BPF_JMP_REG(from->code, from->dst_reg, BPF_REG_AX, off); 950 949 break; 951 950 951 + case BPF_JMP32 | BPF_JEQ | BPF_K: 952 + case BPF_JMP32 | BPF_JNE | BPF_K: 953 + case BPF_JMP32 | BPF_JGT | BPF_K: 954 + case BPF_JMP32 | BPF_JLT | BPF_K: 955 + case BPF_JMP32 | BPF_JGE | BPF_K: 956 + case BPF_JMP32 | BPF_JLE | BPF_K: 957 + case BPF_JMP32 | BPF_JSGT | BPF_K: 958 + case BPF_JMP32 | BPF_JSLT | BPF_K: 959 + case BPF_JMP32 | BPF_JSGE | BPF_K: 960 + case BPF_JMP32 | BPF_JSLE | BPF_K: 961 + case BPF_JMP32 | BPF_JSET | BPF_K: 962 + /* Accommodate for extra offset in case of a backjump. */ 963 + off = from->off; 964 + if (off < 0) 965 + off -= 2; 966 + *to++ = BPF_ALU32_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ from->imm); 967 + *to++ = BPF_ALU32_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); 968 + *to++ = BPF_JMP32_REG(from->code, from->dst_reg, BPF_REG_AX, 969 + off); 970 + break; 971 + 952 972 case BPF_LD | BPF_IMM | BPF_DW: 953 973 *to++ = BPF_ALU64_IMM(BPF_MOV, BPF_REG_AX, imm_rnd ^ aux[1].imm); 954 974 *to++ = BPF_ALU64_IMM(BPF_XOR, BPF_REG_AX, imm_rnd); ··· 1166 1144 INSN_2(JMP, CALL), \ 1167 1145 /* Exit instruction. */ \ 1168 1146 INSN_2(JMP, EXIT), \ 1147 + /* 32-bit Jump instructions. */ \ 1148 + /* Register based. */ \ 1149 + INSN_3(JMP32, JEQ, X), \ 1150 + INSN_3(JMP32, JNE, X), \ 1151 + INSN_3(JMP32, JGT, X), \ 1152 + INSN_3(JMP32, JLT, X), \ 1153 + INSN_3(JMP32, JGE, X), \ 1154 + INSN_3(JMP32, JLE, X), \ 1155 + INSN_3(JMP32, JSGT, X), \ 1156 + INSN_3(JMP32, JSLT, X), \ 1157 + INSN_3(JMP32, JSGE, X), \ 1158 + INSN_3(JMP32, JSLE, X), \ 1159 + INSN_3(JMP32, JSET, X), \ 1160 + /* Immediate based. */ \ 1161 + INSN_3(JMP32, JEQ, K), \ 1162 + INSN_3(JMP32, JNE, K), \ 1163 + INSN_3(JMP32, JGT, K), \ 1164 + INSN_3(JMP32, JLT, K), \ 1165 + INSN_3(JMP32, JGE, K), \ 1166 + INSN_3(JMP32, JLE, K), \ 1167 + INSN_3(JMP32, JSGT, K), \ 1168 + INSN_3(JMP32, JSLT, K), \ 1169 + INSN_3(JMP32, JSGE, K), \ 1170 + INSN_3(JMP32, JSLE, K), \ 1171 + INSN_3(JMP32, JSET, K), \ 1169 1172 /* Jump instructions. */ \ 1170 1173 /* Register based. */ \ 1171 1174 INSN_3(JMP, JEQ, X), \ ··· 1451 1404 out: 1452 1405 CONT; 1453 1406 } 1454 - /* JMP */ 1455 1407 JMP_JA: 1456 1408 insn += insn->off; 1457 1409 CONT; 1458 - JMP_JEQ_X: 1459 - if (DST == SRC) { 1460 - insn += insn->off; 1461 - CONT_JMP; 1462 - } 1463 - CONT; 1464 - JMP_JEQ_K: 1465 - if (DST == IMM) { 1466 - insn += insn->off; 1467 - CONT_JMP; 1468 - } 1469 - CONT; 1470 - JMP_JNE_X: 1471 - if (DST != SRC) { 1472 - insn += insn->off; 1473 - CONT_JMP; 1474 - } 1475 - CONT; 1476 - JMP_JNE_K: 1477 - if (DST != IMM) { 1478 - insn += insn->off; 1479 - CONT_JMP; 1480 - } 1481 - CONT; 1482 - JMP_JGT_X: 1483 - if (DST > SRC) { 1484 - insn += insn->off; 1485 - CONT_JMP; 1486 - } 1487 - CONT; 1488 - JMP_JGT_K: 1489 - if (DST > IMM) { 1490 - insn += insn->off; 1491 - CONT_JMP; 1492 - } 1493 - CONT; 1494 - JMP_JLT_X: 1495 - if (DST < SRC) { 1496 - insn += insn->off; 1497 - CONT_JMP; 1498 - } 1499 - CONT; 1500 - JMP_JLT_K: 1501 - if (DST < IMM) { 1502 - insn += insn->off; 1503 - CONT_JMP; 1504 - } 1505 - CONT; 1506 - JMP_JGE_X: 1507 - if (DST >= SRC) { 1508 - insn += insn->off; 1509 - CONT_JMP; 1510 - } 1511 - CONT; 1512 - JMP_JGE_K: 1513 - if (DST >= IMM) { 1514 - insn += insn->off; 1515 - CONT_JMP; 1516 - } 1517 - CONT; 1518 - JMP_JLE_X: 1519 - if (DST <= SRC) { 1520 - insn += insn->off; 1521 - CONT_JMP; 1522 - } 1523 - CONT; 1524 - JMP_JLE_K: 1525 - if (DST <= IMM) { 1526 - insn += insn->off; 1527 - CONT_JMP; 1528 - } 1529 - CONT; 1530 - JMP_JSGT_X: 1531 - if (((s64) DST) > ((s64) SRC)) { 1532 - insn += insn->off; 1533 - CONT_JMP; 1534 - } 1535 - CONT; 1536 - JMP_JSGT_K: 1537 - if (((s64) DST) > ((s64) IMM)) { 1538 - insn += insn->off; 1539 - CONT_JMP; 1540 - } 1541 - CONT; 1542 - JMP_JSLT_X: 1543 - if (((s64) DST) < ((s64) SRC)) { 1544 - insn += insn->off; 1545 - CONT_JMP; 1546 - } 1547 - CONT; 1548 - JMP_JSLT_K: 1549 - if (((s64) DST) < ((s64) IMM)) { 1550 - insn += insn->off; 1551 - CONT_JMP; 1552 - } 1553 - CONT; 1554 - JMP_JSGE_X: 1555 - if (((s64) DST) >= ((s64) SRC)) { 1556 - insn += insn->off; 1557 - CONT_JMP; 1558 - } 1559 - CONT; 1560 - JMP_JSGE_K: 1561 - if (((s64) DST) >= ((s64) IMM)) { 1562 - insn += insn->off; 1563 - CONT_JMP; 1564 - } 1565 - CONT; 1566 - JMP_JSLE_X: 1567 - if (((s64) DST) <= ((s64) SRC)) { 1568 - insn += insn->off; 1569 - CONT_JMP; 1570 - } 1571 - CONT; 1572 - JMP_JSLE_K: 1573 - if (((s64) DST) <= ((s64) IMM)) { 1574 - insn += insn->off; 1575 - CONT_JMP; 1576 - } 1577 - CONT; 1578 - JMP_JSET_X: 1579 - if (DST & SRC) { 1580 - insn += insn->off; 1581 - CONT_JMP; 1582 - } 1583 - CONT; 1584 - JMP_JSET_K: 1585 - if (DST & IMM) { 1586 - insn += insn->off; 1587 - CONT_JMP; 1588 - } 1589 - CONT; 1590 1410 JMP_EXIT: 1591 1411 return BPF_R0; 1592 - 1412 + /* JMP */ 1413 + #define COND_JMP(SIGN, OPCODE, CMP_OP) \ 1414 + JMP_##OPCODE##_X: \ 1415 + if ((SIGN##64) DST CMP_OP (SIGN##64) SRC) { \ 1416 + insn += insn->off; \ 1417 + CONT_JMP; \ 1418 + } \ 1419 + CONT; \ 1420 + JMP32_##OPCODE##_X: \ 1421 + if ((SIGN##32) DST CMP_OP (SIGN##32) SRC) { \ 1422 + insn += insn->off; \ 1423 + CONT_JMP; \ 1424 + } \ 1425 + CONT; \ 1426 + JMP_##OPCODE##_K: \ 1427 + if ((SIGN##64) DST CMP_OP (SIGN##64) IMM) { \ 1428 + insn += insn->off; \ 1429 + CONT_JMP; \ 1430 + } \ 1431 + CONT; \ 1432 + JMP32_##OPCODE##_K: \ 1433 + if ((SIGN##32) DST CMP_OP (SIGN##32) IMM) { \ 1434 + insn += insn->off; \ 1435 + CONT_JMP; \ 1436 + } \ 1437 + CONT; 1438 + COND_JMP(u, JEQ, ==) 1439 + COND_JMP(u, JNE, !=) 1440 + COND_JMP(u, JGT, >) 1441 + COND_JMP(u, JLT, <) 1442 + COND_JMP(u, JGE, >=) 1443 + COND_JMP(u, JLE, <=) 1444 + COND_JMP(u, JSET, &) 1445 + COND_JMP(s, JSGT, >) 1446 + COND_JMP(s, JSLT, <) 1447 + COND_JMP(s, JSGE, >=) 1448 + COND_JMP(s, JSLE, <=) 1449 + #undef COND_JMP 1593 1450 /* STX and ST and LDX*/ 1594 1451 #define LDST(SIZEOP, SIZE) \ 1595 1452 STX_MEM_##SIZEOP: \
+19 -15
kernel/bpf/disasm.c
··· 67 67 [BPF_STX] = "stx", 68 68 [BPF_ALU] = "alu", 69 69 [BPF_JMP] = "jmp", 70 - [BPF_RET] = "BUG", 70 + [BPF_JMP32] = "jmp32", 71 71 [BPF_ALU64] = "alu64", 72 72 }; 73 73 ··· 136 136 else 137 137 print_bpf_end_insn(verbose, cbs->private_data, insn); 138 138 } else if (BPF_OP(insn->code) == BPF_NEG) { 139 - verbose(cbs->private_data, "(%02x) r%d = %s-r%d\n", 140 - insn->code, insn->dst_reg, 141 - class == BPF_ALU ? "(u32) " : "", 139 + verbose(cbs->private_data, "(%02x) %c%d = -%c%d\n", 140 + insn->code, class == BPF_ALU ? 'w' : 'r', 141 + insn->dst_reg, class == BPF_ALU ? 'w' : 'r', 142 142 insn->dst_reg); 143 143 } else if (BPF_SRC(insn->code) == BPF_X) { 144 - verbose(cbs->private_data, "(%02x) %sr%d %s %sr%d\n", 145 - insn->code, class == BPF_ALU ? "(u32) " : "", 144 + verbose(cbs->private_data, "(%02x) %c%d %s %c%d\n", 145 + insn->code, class == BPF_ALU ? 'w' : 'r', 146 146 insn->dst_reg, 147 147 bpf_alu_string[BPF_OP(insn->code) >> 4], 148 - class == BPF_ALU ? "(u32) " : "", 148 + class == BPF_ALU ? 'w' : 'r', 149 149 insn->src_reg); 150 150 } else { 151 - verbose(cbs->private_data, "(%02x) %sr%d %s %s%d\n", 152 - insn->code, class == BPF_ALU ? "(u32) " : "", 151 + verbose(cbs->private_data, "(%02x) %c%d %s %d\n", 152 + insn->code, class == BPF_ALU ? 'w' : 'r', 153 153 insn->dst_reg, 154 154 bpf_alu_string[BPF_OP(insn->code) >> 4], 155 - class == BPF_ALU ? "(u32) " : "", 156 155 insn->imm); 157 156 } 158 157 } else if (class == BPF_STX) { ··· 219 220 verbose(cbs->private_data, "BUG_ld_%02x\n", insn->code); 220 221 return; 221 222 } 222 - } else if (class == BPF_JMP) { 223 + } else if (class == BPF_JMP32 || class == BPF_JMP) { 223 224 u8 opcode = BPF_OP(insn->code); 224 225 225 226 if (opcode == BPF_CALL) { ··· 243 244 } else if (insn->code == (BPF_JMP | BPF_EXIT)) { 244 245 verbose(cbs->private_data, "(%02x) exit\n", insn->code); 245 246 } else if (BPF_SRC(insn->code) == BPF_X) { 246 - verbose(cbs->private_data, "(%02x) if r%d %s r%d goto pc%+d\n", 247 - insn->code, insn->dst_reg, 247 + verbose(cbs->private_data, 248 + "(%02x) if %c%d %s %c%d goto pc%+d\n", 249 + insn->code, class == BPF_JMP32 ? 'w' : 'r', 250 + insn->dst_reg, 248 251 bpf_jmp_string[BPF_OP(insn->code) >> 4], 252 + class == BPF_JMP32 ? 'w' : 'r', 249 253 insn->src_reg, insn->off); 250 254 } else { 251 - verbose(cbs->private_data, "(%02x) if r%d %s 0x%x goto pc%+d\n", 252 - insn->code, insn->dst_reg, 255 + verbose(cbs->private_data, 256 + "(%02x) if %c%d %s 0x%x goto pc%+d\n", 257 + insn->code, class == BPF_JMP32 ? 'w' : 'r', 258 + insn->dst_reg, 253 259 bpf_jmp_string[BPF_OP(insn->code) >> 4], 254 260 insn->imm, insn->off); 255 261 }
+265 -100
kernel/bpf/verifier.c
··· 1095 1095 for (i = 0; i < insn_cnt; i++) { 1096 1096 u8 code = insn[i].code; 1097 1097 1098 - if (BPF_CLASS(code) != BPF_JMP) 1098 + if (BPF_CLASS(code) != BPF_JMP && BPF_CLASS(code) != BPF_JMP32) 1099 1099 goto next; 1100 1100 if (BPF_OP(code) == BPF_EXIT || BPF_OP(code) == BPF_CALL) 1101 1101 goto next; ··· 4031 4031 * 0 - branch will not be taken and fall-through to next insn 4032 4032 * -1 - unknown. Example: "if (reg < 5)" is unknown when register value range [0,10] 4033 4033 */ 4034 - static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode) 4034 + static int is_branch_taken(struct bpf_reg_state *reg, u64 val, u8 opcode, 4035 + bool is_jmp32) 4035 4036 { 4037 + struct bpf_reg_state reg_lo; 4038 + s64 sval; 4039 + 4036 4040 if (__is_pointer_value(false, reg)) 4037 4041 return -1; 4042 + 4043 + if (is_jmp32) { 4044 + reg_lo = *reg; 4045 + reg = &reg_lo; 4046 + /* For JMP32, only low 32 bits are compared, coerce_reg_to_size 4047 + * could truncate high bits and update umin/umax according to 4048 + * information of low bits. 4049 + */ 4050 + coerce_reg_to_size(reg, 4); 4051 + /* smin/smax need special handling. For example, after coerce, 4052 + * if smin_value is 0x00000000ffffffffLL, the value is -1 when 4053 + * used as operand to JMP32. It is a negative number from s32's 4054 + * point of view, while it is a positive number when seen as 4055 + * s64. The smin/smax are kept as s64, therefore, when used with 4056 + * JMP32, they need to be transformed into s32, then sign 4057 + * extended back to s64. 4058 + * 4059 + * Also, smin/smax were copied from umin/umax. If umin/umax has 4060 + * different sign bit, then min/max relationship doesn't 4061 + * maintain after casting into s32, for this case, set smin/smax 4062 + * to safest range. 4063 + */ 4064 + if ((reg->umax_value ^ reg->umin_value) & 4065 + (1ULL << 31)) { 4066 + reg->smin_value = S32_MIN; 4067 + reg->smax_value = S32_MAX; 4068 + } 4069 + reg->smin_value = (s64)(s32)reg->smin_value; 4070 + reg->smax_value = (s64)(s32)reg->smax_value; 4071 + 4072 + val = (u32)val; 4073 + sval = (s64)(s32)val; 4074 + } else { 4075 + sval = (s64)val; 4076 + } 4038 4077 4039 4078 switch (opcode) { 4040 4079 case BPF_JEQ: ··· 4097 4058 return 0; 4098 4059 break; 4099 4060 case BPF_JSGT: 4100 - if (reg->smin_value > (s64)val) 4061 + if (reg->smin_value > sval) 4101 4062 return 1; 4102 - else if (reg->smax_value < (s64)val) 4063 + else if (reg->smax_value < sval) 4103 4064 return 0; 4104 4065 break; 4105 4066 case BPF_JLT: ··· 4109 4070 return 0; 4110 4071 break; 4111 4072 case BPF_JSLT: 4112 - if (reg->smax_value < (s64)val) 4073 + if (reg->smax_value < sval) 4113 4074 return 1; 4114 - else if (reg->smin_value >= (s64)val) 4075 + else if (reg->smin_value >= sval) 4115 4076 return 0; 4116 4077 break; 4117 4078 case BPF_JGE: ··· 4121 4082 return 0; 4122 4083 break; 4123 4084 case BPF_JSGE: 4124 - if (reg->smin_value >= (s64)val) 4085 + if (reg->smin_value >= sval) 4125 4086 return 1; 4126 - else if (reg->smax_value < (s64)val) 4087 + else if (reg->smax_value < sval) 4127 4088 return 0; 4128 4089 break; 4129 4090 case BPF_JLE: ··· 4133 4094 return 0; 4134 4095 break; 4135 4096 case BPF_JSLE: 4136 - if (reg->smax_value <= (s64)val) 4097 + if (reg->smax_value <= sval) 4137 4098 return 1; 4138 - else if (reg->smin_value > (s64)val) 4099 + else if (reg->smin_value > sval) 4139 4100 return 0; 4140 4101 break; 4141 4102 } 4142 4103 4143 4104 return -1; 4105 + } 4106 + 4107 + /* Generate min value of the high 32-bit from TNUM info. */ 4108 + static u64 gen_hi_min(struct tnum var) 4109 + { 4110 + return var.value & ~0xffffffffULL; 4111 + } 4112 + 4113 + /* Generate max value of the high 32-bit from TNUM info. */ 4114 + static u64 gen_hi_max(struct tnum var) 4115 + { 4116 + return (var.value | var.mask) & ~0xffffffffULL; 4117 + } 4118 + 4119 + /* Return true if VAL is compared with a s64 sign extended from s32, and they 4120 + * are with the same signedness. 4121 + */ 4122 + static bool cmp_val_with_extended_s64(s64 sval, struct bpf_reg_state *reg) 4123 + { 4124 + return ((s32)sval >= 0 && 4125 + reg->smin_value >= 0 && reg->smax_value <= S32_MAX) || 4126 + ((s32)sval < 0 && 4127 + reg->smax_value <= 0 && reg->smin_value >= S32_MIN); 4144 4128 } 4145 4129 4146 4130 /* Adjusts the register min/max values in the case that the dst_reg is the ··· 4173 4111 */ 4174 4112 static void reg_set_min_max(struct bpf_reg_state *true_reg, 4175 4113 struct bpf_reg_state *false_reg, u64 val, 4176 - u8 opcode) 4114 + u8 opcode, bool is_jmp32) 4177 4115 { 4116 + s64 sval; 4117 + 4178 4118 /* If the dst_reg is a pointer, we can't learn anything about its 4179 4119 * variable offset from the compare (unless src_reg were a pointer into 4180 4120 * the same object, but we don't bother with that. ··· 4186 4122 if (__is_pointer_value(false, false_reg)) 4187 4123 return; 4188 4124 4125 + val = is_jmp32 ? (u32)val : val; 4126 + sval = is_jmp32 ? (s64)(s32)val : (s64)val; 4127 + 4189 4128 switch (opcode) { 4190 4129 case BPF_JEQ: 4191 - /* If this is false then we know nothing Jon Snow, but if it is 4192 - * true then we know for sure. 4193 - */ 4194 - __mark_reg_known(true_reg, val); 4195 - break; 4196 4130 case BPF_JNE: 4197 - /* If this is true we know nothing Jon Snow, but if it is false 4198 - * we know the value for sure; 4131 + { 4132 + struct bpf_reg_state *reg = 4133 + opcode == BPF_JEQ ? true_reg : false_reg; 4134 + 4135 + /* For BPF_JEQ, if this is false we know nothing Jon Snow, but 4136 + * if it is true we know the value for sure. Likewise for 4137 + * BPF_JNE. 4199 4138 */ 4200 - __mark_reg_known(false_reg, val); 4139 + if (is_jmp32) { 4140 + u64 old_v = reg->var_off.value; 4141 + u64 hi_mask = ~0xffffffffULL; 4142 + 4143 + reg->var_off.value = (old_v & hi_mask) | val; 4144 + reg->var_off.mask &= hi_mask; 4145 + } else { 4146 + __mark_reg_known(reg, val); 4147 + } 4201 4148 break; 4149 + } 4202 4150 case BPF_JSET: 4203 4151 false_reg->var_off = tnum_and(false_reg->var_off, 4204 4152 tnum_const(~val)); ··· 4218 4142 true_reg->var_off = tnum_or(true_reg->var_off, 4219 4143 tnum_const(val)); 4220 4144 break; 4221 - case BPF_JGT: 4222 - false_reg->umax_value = min(false_reg->umax_value, val); 4223 - true_reg->umin_value = max(true_reg->umin_value, val + 1); 4224 - break; 4225 - case BPF_JSGT: 4226 - false_reg->smax_value = min_t(s64, false_reg->smax_value, val); 4227 - true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1); 4228 - break; 4229 - case BPF_JLT: 4230 - false_reg->umin_value = max(false_reg->umin_value, val); 4231 - true_reg->umax_value = min(true_reg->umax_value, val - 1); 4232 - break; 4233 - case BPF_JSLT: 4234 - false_reg->smin_value = max_t(s64, false_reg->smin_value, val); 4235 - true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1); 4236 - break; 4237 4145 case BPF_JGE: 4238 - false_reg->umax_value = min(false_reg->umax_value, val - 1); 4239 - true_reg->umin_value = max(true_reg->umin_value, val); 4146 + case BPF_JGT: 4147 + { 4148 + u64 false_umax = opcode == BPF_JGT ? val : val - 1; 4149 + u64 true_umin = opcode == BPF_JGT ? val + 1 : val; 4150 + 4151 + if (is_jmp32) { 4152 + false_umax += gen_hi_max(false_reg->var_off); 4153 + true_umin += gen_hi_min(true_reg->var_off); 4154 + } 4155 + false_reg->umax_value = min(false_reg->umax_value, false_umax); 4156 + true_reg->umin_value = max(true_reg->umin_value, true_umin); 4240 4157 break; 4158 + } 4241 4159 case BPF_JSGE: 4242 - false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); 4243 - true_reg->smin_value = max_t(s64, true_reg->smin_value, val); 4160 + case BPF_JSGT: 4161 + { 4162 + s64 false_smax = opcode == BPF_JSGT ? sval : sval - 1; 4163 + s64 true_smin = opcode == BPF_JSGT ? sval + 1 : sval; 4164 + 4165 + /* If the full s64 was not sign-extended from s32 then don't 4166 + * deduct further info. 4167 + */ 4168 + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) 4169 + break; 4170 + false_reg->smax_value = min(false_reg->smax_value, false_smax); 4171 + true_reg->smin_value = max(true_reg->smin_value, true_smin); 4244 4172 break; 4173 + } 4245 4174 case BPF_JLE: 4246 - false_reg->umin_value = max(false_reg->umin_value, val + 1); 4247 - true_reg->umax_value = min(true_reg->umax_value, val); 4175 + case BPF_JLT: 4176 + { 4177 + u64 false_umin = opcode == BPF_JLT ? val : val + 1; 4178 + u64 true_umax = opcode == BPF_JLT ? val - 1 : val; 4179 + 4180 + if (is_jmp32) { 4181 + false_umin += gen_hi_min(false_reg->var_off); 4182 + true_umax += gen_hi_max(true_reg->var_off); 4183 + } 4184 + false_reg->umin_value = max(false_reg->umin_value, false_umin); 4185 + true_reg->umax_value = min(true_reg->umax_value, true_umax); 4248 4186 break; 4187 + } 4249 4188 case BPF_JSLE: 4250 - false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); 4251 - true_reg->smax_value = min_t(s64, true_reg->smax_value, val); 4189 + case BPF_JSLT: 4190 + { 4191 + s64 false_smin = opcode == BPF_JSLT ? sval : sval + 1; 4192 + s64 true_smax = opcode == BPF_JSLT ? sval - 1 : sval; 4193 + 4194 + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) 4195 + break; 4196 + false_reg->smin_value = max(false_reg->smin_value, false_smin); 4197 + true_reg->smax_value = min(true_reg->smax_value, true_smax); 4252 4198 break; 4199 + } 4253 4200 default: 4254 4201 break; 4255 4202 } ··· 4295 4196 */ 4296 4197 static void reg_set_min_max_inv(struct bpf_reg_state *true_reg, 4297 4198 struct bpf_reg_state *false_reg, u64 val, 4298 - u8 opcode) 4199 + u8 opcode, bool is_jmp32) 4299 4200 { 4201 + s64 sval; 4202 + 4300 4203 if (__is_pointer_value(false, false_reg)) 4301 4204 return; 4302 4205 4206 + val = is_jmp32 ? (u32)val : val; 4207 + sval = is_jmp32 ? (s64)(s32)val : (s64)val; 4208 + 4303 4209 switch (opcode) { 4304 4210 case BPF_JEQ: 4305 - /* If this is false then we know nothing Jon Snow, but if it is 4306 - * true then we know for sure. 4307 - */ 4308 - __mark_reg_known(true_reg, val); 4309 - break; 4310 4211 case BPF_JNE: 4311 - /* If this is true we know nothing Jon Snow, but if it is false 4312 - * we know the value for sure; 4313 - */ 4314 - __mark_reg_known(false_reg, val); 4212 + { 4213 + struct bpf_reg_state *reg = 4214 + opcode == BPF_JEQ ? true_reg : false_reg; 4215 + 4216 + if (is_jmp32) { 4217 + u64 old_v = reg->var_off.value; 4218 + u64 hi_mask = ~0xffffffffULL; 4219 + 4220 + reg->var_off.value = (old_v & hi_mask) | val; 4221 + reg->var_off.mask &= hi_mask; 4222 + } else { 4223 + __mark_reg_known(reg, val); 4224 + } 4315 4225 break; 4226 + } 4316 4227 case BPF_JSET: 4317 4228 false_reg->var_off = tnum_and(false_reg->var_off, 4318 4229 tnum_const(~val)); ··· 4330 4221 true_reg->var_off = tnum_or(true_reg->var_off, 4331 4222 tnum_const(val)); 4332 4223 break; 4333 - case BPF_JGT: 4334 - true_reg->umax_value = min(true_reg->umax_value, val - 1); 4335 - false_reg->umin_value = max(false_reg->umin_value, val); 4336 - break; 4337 - case BPF_JSGT: 4338 - true_reg->smax_value = min_t(s64, true_reg->smax_value, val - 1); 4339 - false_reg->smin_value = max_t(s64, false_reg->smin_value, val); 4340 - break; 4341 - case BPF_JLT: 4342 - true_reg->umin_value = max(true_reg->umin_value, val + 1); 4343 - false_reg->umax_value = min(false_reg->umax_value, val); 4344 - break; 4345 - case BPF_JSLT: 4346 - true_reg->smin_value = max_t(s64, true_reg->smin_value, val + 1); 4347 - false_reg->smax_value = min_t(s64, false_reg->smax_value, val); 4348 - break; 4349 4224 case BPF_JGE: 4350 - true_reg->umax_value = min(true_reg->umax_value, val); 4351 - false_reg->umin_value = max(false_reg->umin_value, val + 1); 4225 + case BPF_JGT: 4226 + { 4227 + u64 false_umin = opcode == BPF_JGT ? val : val + 1; 4228 + u64 true_umax = opcode == BPF_JGT ? val - 1 : val; 4229 + 4230 + if (is_jmp32) { 4231 + false_umin += gen_hi_min(false_reg->var_off); 4232 + true_umax += gen_hi_max(true_reg->var_off); 4233 + } 4234 + false_reg->umin_value = max(false_reg->umin_value, false_umin); 4235 + true_reg->umax_value = min(true_reg->umax_value, true_umax); 4352 4236 break; 4237 + } 4353 4238 case BPF_JSGE: 4354 - true_reg->smax_value = min_t(s64, true_reg->smax_value, val); 4355 - false_reg->smin_value = max_t(s64, false_reg->smin_value, val + 1); 4239 + case BPF_JSGT: 4240 + { 4241 + s64 false_smin = opcode == BPF_JSGT ? sval : sval + 1; 4242 + s64 true_smax = opcode == BPF_JSGT ? sval - 1 : sval; 4243 + 4244 + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) 4245 + break; 4246 + false_reg->smin_value = max(false_reg->smin_value, false_smin); 4247 + true_reg->smax_value = min(true_reg->smax_value, true_smax); 4356 4248 break; 4249 + } 4357 4250 case BPF_JLE: 4358 - true_reg->umin_value = max(true_reg->umin_value, val); 4359 - false_reg->umax_value = min(false_reg->umax_value, val - 1); 4251 + case BPF_JLT: 4252 + { 4253 + u64 false_umax = opcode == BPF_JLT ? val : val - 1; 4254 + u64 true_umin = opcode == BPF_JLT ? val + 1 : val; 4255 + 4256 + if (is_jmp32) { 4257 + false_umax += gen_hi_max(false_reg->var_off); 4258 + true_umin += gen_hi_min(true_reg->var_off); 4259 + } 4260 + false_reg->umax_value = min(false_reg->umax_value, false_umax); 4261 + true_reg->umin_value = max(true_reg->umin_value, true_umin); 4360 4262 break; 4263 + } 4361 4264 case BPF_JSLE: 4362 - true_reg->smin_value = max_t(s64, true_reg->smin_value, val); 4363 - false_reg->smax_value = min_t(s64, false_reg->smax_value, val - 1); 4265 + case BPF_JSLT: 4266 + { 4267 + s64 false_smax = opcode == BPF_JSLT ? sval : sval - 1; 4268 + s64 true_smin = opcode == BPF_JSLT ? sval + 1 : sval; 4269 + 4270 + if (is_jmp32 && !cmp_val_with_extended_s64(sval, false_reg)) 4271 + break; 4272 + false_reg->smax_value = min(false_reg->smax_value, false_smax); 4273 + true_reg->smin_value = max(true_reg->smin_value, true_smin); 4364 4274 break; 4275 + } 4365 4276 default: 4366 4277 break; 4367 4278 } ··· 4519 4390 if (BPF_SRC(insn->code) != BPF_X) 4520 4391 return false; 4521 4392 4393 + /* Pointers are always 64-bit. */ 4394 + if (BPF_CLASS(insn->code) == BPF_JMP32) 4395 + return false; 4396 + 4522 4397 switch (BPF_OP(insn->code)) { 4523 4398 case BPF_JGT: 4524 4399 if ((dst_reg->type == PTR_TO_PACKET && ··· 4615 4482 struct bpf_reg_state *regs = this_branch->frame[this_branch->curframe]->regs; 4616 4483 struct bpf_reg_state *dst_reg, *other_branch_regs; 4617 4484 u8 opcode = BPF_OP(insn->code); 4485 + bool is_jmp32; 4618 4486 int err; 4619 4487 4620 - if (opcode > BPF_JSLE) { 4621 - verbose(env, "invalid BPF_JMP opcode %x\n", opcode); 4488 + /* Only conditional jumps are expected to reach here. */ 4489 + if (opcode == BPF_JA || opcode > BPF_JSLE) { 4490 + verbose(env, "invalid BPF_JMP/JMP32 opcode %x\n", opcode); 4622 4491 return -EINVAL; 4623 4492 } 4624 4493 4625 4494 if (BPF_SRC(insn->code) == BPF_X) { 4626 4495 if (insn->imm != 0) { 4627 - verbose(env, "BPF_JMP uses reserved fields\n"); 4496 + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); 4628 4497 return -EINVAL; 4629 4498 } 4630 4499 ··· 4642 4507 } 4643 4508 } else { 4644 4509 if (insn->src_reg != BPF_REG_0) { 4645 - verbose(env, "BPF_JMP uses reserved fields\n"); 4510 + verbose(env, "BPF_JMP/JMP32 uses reserved fields\n"); 4646 4511 return -EINVAL; 4647 4512 } 4648 4513 } ··· 4653 4518 return err; 4654 4519 4655 4520 dst_reg = &regs[insn->dst_reg]; 4521 + is_jmp32 = BPF_CLASS(insn->code) == BPF_JMP32; 4656 4522 4657 4523 if (BPF_SRC(insn->code) == BPF_K) { 4658 - int pred = is_branch_taken(dst_reg, insn->imm, opcode); 4524 + int pred = is_branch_taken(dst_reg, insn->imm, opcode, 4525 + is_jmp32); 4659 4526 4660 4527 if (pred == 1) { 4661 4528 /* only follow the goto, ignore fall-through */ ··· 4685 4548 * comparable. 4686 4549 */ 4687 4550 if (BPF_SRC(insn->code) == BPF_X) { 4551 + struct bpf_reg_state *src_reg = &regs[insn->src_reg]; 4552 + struct bpf_reg_state lo_reg0 = *dst_reg; 4553 + struct bpf_reg_state lo_reg1 = *src_reg; 4554 + struct bpf_reg_state *src_lo, *dst_lo; 4555 + 4556 + dst_lo = &lo_reg0; 4557 + src_lo = &lo_reg1; 4558 + coerce_reg_to_size(dst_lo, 4); 4559 + coerce_reg_to_size(src_lo, 4); 4560 + 4688 4561 if (dst_reg->type == SCALAR_VALUE && 4689 - regs[insn->src_reg].type == SCALAR_VALUE) { 4690 - if (tnum_is_const(regs[insn->src_reg].var_off)) 4562 + src_reg->type == SCALAR_VALUE) { 4563 + if (tnum_is_const(src_reg->var_off) || 4564 + (is_jmp32 && tnum_is_const(src_lo->var_off))) 4691 4565 reg_set_min_max(&other_branch_regs[insn->dst_reg], 4692 - dst_reg, regs[insn->src_reg].var_off.value, 4693 - opcode); 4694 - else if (tnum_is_const(dst_reg->var_off)) 4566 + dst_reg, 4567 + is_jmp32 4568 + ? src_lo->var_off.value 4569 + : src_reg->var_off.value, 4570 + opcode, is_jmp32); 4571 + else if (tnum_is_const(dst_reg->var_off) || 4572 + (is_jmp32 && tnum_is_const(dst_lo->var_off))) 4695 4573 reg_set_min_max_inv(&other_branch_regs[insn->src_reg], 4696 - &regs[insn->src_reg], 4697 - dst_reg->var_off.value, opcode); 4698 - else if (opcode == BPF_JEQ || opcode == BPF_JNE) 4574 + src_reg, 4575 + is_jmp32 4576 + ? dst_lo->var_off.value 4577 + : dst_reg->var_off.value, 4578 + opcode, is_jmp32); 4579 + else if (!is_jmp32 && 4580 + (opcode == BPF_JEQ || opcode == BPF_JNE)) 4699 4581 /* Comparing for equality, we can combine knowledge */ 4700 4582 reg_combine_min_max(&other_branch_regs[insn->src_reg], 4701 4583 &other_branch_regs[insn->dst_reg], 4702 - &regs[insn->src_reg], 4703 - &regs[insn->dst_reg], opcode); 4584 + src_reg, dst_reg, opcode); 4704 4585 } 4705 4586 } else if (dst_reg->type == SCALAR_VALUE) { 4706 4587 reg_set_min_max(&other_branch_regs[insn->dst_reg], 4707 - dst_reg, insn->imm, opcode); 4588 + dst_reg, insn->imm, opcode, is_jmp32); 4708 4589 } 4709 4590 4710 - /* detect if R == 0 where R is returned from bpf_map_lookup_elem() */ 4711 - if (BPF_SRC(insn->code) == BPF_K && 4591 + /* detect if R == 0 where R is returned from bpf_map_lookup_elem(). 4592 + * NOTE: these optimizations below are related with pointer comparison 4593 + * which will never be JMP32. 4594 + */ 4595 + if (!is_jmp32 && BPF_SRC(insn->code) == BPF_K && 4712 4596 insn->imm == 0 && (opcode == BPF_JEQ || opcode == BPF_JNE) && 4713 4597 reg_type_may_be_null(dst_reg->type)) { 4714 4598 /* Mark all identical registers in each branch as either ··· 5058 4900 goto check_state; 5059 4901 t = insn_stack[cur_stack - 1]; 5060 4902 5061 - if (BPF_CLASS(insns[t].code) == BPF_JMP) { 4903 + if (BPF_CLASS(insns[t].code) == BPF_JMP || 4904 + BPF_CLASS(insns[t].code) == BPF_JMP32) { 5062 4905 u8 opcode = BPF_OP(insns[t].code); 5063 4906 5064 4907 if (opcode == BPF_EXIT) { ··· 6215 6056 if (err) 6216 6057 return err; 6217 6058 6218 - } else if (class == BPF_JMP) { 6059 + } else if (class == BPF_JMP || class == BPF_JMP32) { 6219 6060 u8 opcode = BPF_OP(insn->code); 6220 6061 6221 6062 if (opcode == BPF_CALL) { ··· 6223 6064 insn->off != 0 || 6224 6065 (insn->src_reg != BPF_REG_0 && 6225 6066 insn->src_reg != BPF_PSEUDO_CALL) || 6226 - insn->dst_reg != BPF_REG_0) { 6067 + insn->dst_reg != BPF_REG_0 || 6068 + class == BPF_JMP32) { 6227 6069 verbose(env, "BPF_CALL uses reserved fields\n"); 6228 6070 return -EINVAL; 6229 6071 } ··· 6240 6080 if (BPF_SRC(insn->code) != BPF_K || 6241 6081 insn->imm != 0 || 6242 6082 insn->src_reg != BPF_REG_0 || 6243 - insn->dst_reg != BPF_REG_0) { 6083 + insn->dst_reg != BPF_REG_0 || 6084 + class == BPF_JMP32) { 6244 6085 verbose(env, "BPF_JA uses reserved fields\n"); 6245 6086 return -EINVAL; 6246 6087 } ··· 6253 6092 if (BPF_SRC(insn->code) != BPF_K || 6254 6093 insn->imm != 0 || 6255 6094 insn->src_reg != BPF_REG_0 || 6256 - insn->dst_reg != BPF_REG_0) { 6095 + insn->dst_reg != BPF_REG_0 || 6096 + class == BPF_JMP32) { 6257 6097 verbose(env, "BPF_EXIT uses reserved fields\n"); 6258 6098 return -EINVAL; 6259 6099 } ··· 6770 6608 static bool insn_is_cond_jump(u8 code) 6771 6609 { 6772 6610 u8 op; 6611 + 6612 + if (BPF_CLASS(code) == BPF_JMP32) 6613 + return true; 6773 6614 6774 6615 if (BPF_CLASS(code) != BPF_JMP) 6775 6616 return false;
+20
samples/bpf/bpf_insn.h
··· 164 164 .off = OFF, \ 165 165 .imm = 0 }) 166 166 167 + /* Like BPF_JMP_REG, but with 32-bit wide operands for comparison. */ 168 + 169 + #define BPF_JMP32_REG(OP, DST, SRC, OFF) \ 170 + ((struct bpf_insn) { \ 171 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_X, \ 172 + .dst_reg = DST, \ 173 + .src_reg = SRC, \ 174 + .off = OFF, \ 175 + .imm = 0 }) 176 + 167 177 /* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ 168 178 169 179 #define BPF_JMP_IMM(OP, DST, IMM, OFF) \ 170 180 ((struct bpf_insn) { \ 171 181 .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ 182 + .dst_reg = DST, \ 183 + .src_reg = 0, \ 184 + .off = OFF, \ 185 + .imm = IMM }) 186 + 187 + /* Like BPF_JMP_IMM, but with 32-bit wide operands for comparison. */ 188 + 189 + #define BPF_JMP32_IMM(OP, DST, IMM, OFF) \ 190 + ((struct bpf_insn) { \ 191 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \ 172 192 .dst_reg = DST, \ 173 193 .src_reg = 0, \ 174 194 .off = OFF, \
+7 -2
tools/bpf/bpftool/cfg.c
··· 157 157 return false; 158 158 } 159 159 160 + static bool is_jmp_insn(u8 code) 161 + { 162 + return BPF_CLASS(code) == BPF_JMP || BPF_CLASS(code) == BPF_JMP32; 163 + } 164 + 160 165 static bool func_partition_bb_head(struct func_node *func) 161 166 { 162 167 struct bpf_insn *cur, *end; ··· 175 170 return true; 176 171 177 172 for (; cur <= end; cur++) { 178 - if (BPF_CLASS(cur->code) == BPF_JMP) { 173 + if (is_jmp_insn(cur->code)) { 179 174 u8 opcode = BPF_OP(cur->code); 180 175 181 176 if (opcode == BPF_EXIT || opcode == BPF_CALL) ··· 301 296 e->src = bb; 302 297 303 298 insn = bb->tail; 304 - if (BPF_CLASS(insn->code) != BPF_JMP || 299 + if (!is_jmp_insn(insn->code) || 305 300 BPF_OP(insn->code) == BPF_EXIT) { 306 301 e->dst = bb_next(bb); 307 302 e->flags |= EDGE_FLAG_FALLTHROUGH;
+20
tools/include/linux/filter.h
··· 199 199 .off = OFF, \ 200 200 .imm = 0 }) 201 201 202 + /* Like BPF_JMP_REG, but with 32-bit wide operands for comparison. */ 203 + 204 + #define BPF_JMP32_REG(OP, DST, SRC, OFF) \ 205 + ((struct bpf_insn) { \ 206 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_X, \ 207 + .dst_reg = DST, \ 208 + .src_reg = SRC, \ 209 + .off = OFF, \ 210 + .imm = 0 }) 211 + 202 212 /* Conditional jumps against immediates, if (dst_reg 'op' imm32) goto pc + off16 */ 203 213 204 214 #define BPF_JMP_IMM(OP, DST, IMM, OFF) \ 205 215 ((struct bpf_insn) { \ 206 216 .code = BPF_JMP | BPF_OP(OP) | BPF_K, \ 217 + .dst_reg = DST, \ 218 + .src_reg = 0, \ 219 + .off = OFF, \ 220 + .imm = IMM }) 221 + 222 + /* Like BPF_JMP_IMM, but with 32-bit wide operands for comparison. */ 223 + 224 + #define BPF_JMP32_IMM(OP, DST, IMM, OFF) \ 225 + ((struct bpf_insn) { \ 226 + .code = BPF_JMP32 | BPF_OP(OP) | BPF_K, \ 207 227 .dst_reg = DST, \ 208 228 .src_reg = 0, \ 209 229 .off = OFF, \
+1
tools/include/uapi/linux/bpf.h
··· 14 14 /* Extended instruction set based on top of classic BPF */ 15 15 16 16 /* instruction classes */ 17 + #define BPF_JMP32 0x06 /* jmp mode in word width */ 17 18 #define BPF_ALU64 0x07 /* alu mode in double word width */ 18 19 19 20 /* ld/ldx fields */
+70 -25
tools/testing/selftests/bpf/Makefile
··· 10 10 GENFLAGS := -DHAVE_GENHDR 11 11 endif 12 12 13 + CLANG ?= clang 14 + LLC ?= llc 15 + LLVM_OBJCOPY ?= llvm-objcopy 16 + LLVM_READELF ?= llvm-readelf 17 + BTF_PAHOLE ?= pahole 13 18 CFLAGS += -Wall -O2 -I$(APIDIR) -I$(LIBDIR) -I$(BPFDIR) -I$(GENDIR) $(GENFLAGS) -I../../../include 14 19 LDLIBS += -lcap -lelf -lrt -lpthread 15 - 16 - TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read 17 - all: $(TEST_CUSTOM_PROGS) 18 - 19 - $(TEST_CUSTOM_PROGS): $(OUTPUT)/%: %.c 20 - $(CC) -o $(TEST_CUSTOM_PROGS) -static $< -Wl,--build-id 21 20 22 21 # Order correspond to 'make run_tests' order 23 22 TEST_GEN_PROGS = test_verifier test_tag test_maps test_lru_map test_lpm_map test_progs \ ··· 25 26 test_socket_cookie test_cgroup_storage test_select_reuseport test_section_names \ 26 27 test_netcnt test_tcpnotify_user 27 28 28 - TEST_GEN_FILES = test_pkt_access.o test_xdp.o test_l4lb.o test_tcp_estats.o test_obj_id.o \ 29 - test_pkt_md_access.o test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 30 - sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o test_tracepoint.o \ 31 - test_l4lb_noinline.o test_xdp_noinline.o test_stacktrace_map.o \ 32 - test_tcpnotify_kern.o \ 33 - sample_map_ret0.o test_tcpbpf_kern.o test_stacktrace_build_id.o \ 34 - sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o test_adjust_tail.o \ 35 - test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o test_tunnel_kern.o \ 36 - test_get_stack_rawtp.o test_sockmap_kern.o test_sockhash_kern.o \ 37 - test_lwt_seg6local.o sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ 29 + BPF_OBJ_FILES = \ 30 + test_xdp_redirect.o test_xdp_meta.o sockmap_parse_prog.o \ 31 + sockmap_verdict_prog.o dev_cgroup.o sample_ret0.o \ 32 + test_tcpnotify_kern.o sample_map_ret0.o test_tcpbpf_kern.o \ 33 + sockmap_tcp_msg_prog.o connect4_prog.o connect6_prog.o \ 34 + test_btf_haskv.o test_btf_nokv.o test_sockmap_kern.o \ 35 + test_tunnel_kern.o test_sockhash_kern.o test_lwt_seg6local.o \ 36 + sendmsg4_prog.o sendmsg6_prog.o test_lirc_mode2_kern.o \ 38 37 get_cgroup_id_kern.o socket_cookie_prog.o test_select_reuseport_kern.o \ 39 - test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o \ 40 - test_sk_lookup_kern.o test_xdp_vlan.o test_queue_map.o test_stack_map.o \ 38 + test_skb_cgroup_id_kern.o bpf_flow.o netcnt_prog.o test_xdp_vlan.o \ 41 39 xdp_dummy.o test_map_in_map.o 40 + 41 + # Objects are built with default compilation flags and with sub-register 42 + # code-gen enabled. 43 + BPF_OBJ_FILES_DUAL_COMPILE = \ 44 + test_pkt_access.o test_pkt_access.o test_xdp.o test_adjust_tail.o \ 45 + test_l4lb.o test_l4lb_noinline.o test_xdp_noinline.o test_tcp_estats.o \ 46 + test_obj_id.o test_pkt_md_access.o test_tracepoint.o \ 47 + test_stacktrace_map.o test_stacktrace_map.o test_stacktrace_build_id.o \ 48 + test_stacktrace_build_id.o test_get_stack_rawtp.o \ 49 + test_get_stack_rawtp.o test_tracepoint.o test_sk_lookup_kern.o \ 50 + test_queue_map.o test_stack_map.o 51 + 52 + TEST_GEN_FILES = $(BPF_OBJ_FILES) $(BPF_OBJ_FILES_DUAL_COMPILE) 53 + 54 + # Also test sub-register code-gen if LLVM + kernel both has eBPF v3 processor 55 + # support which is the first version to contain both ALU32 and JMP32 56 + # instructions. 57 + SUBREG_CODEGEN := $(shell echo "int cal(int a) { return a > 0; }" | \ 58 + $(CLANG) -target bpf -O2 -emit-llvm -S -x c - -o - | \ 59 + $(LLC) -mattr=+alu32 -mcpu=probe 2>&1 | \ 60 + grep 'if w') 61 + ifneq ($(SUBREG_CODEGEN),) 62 + TEST_GEN_FILES += $(patsubst %.o,alu32/%.o, $(BPF_OBJ_FILES_DUAL_COMPILE)) 63 + endif 42 64 43 65 # Order correspond to 'make run_tests' order 44 66 TEST_PROGS := test_kmod.sh \ ··· 84 64 flow_dissector_load test_flow_dissector 85 65 86 66 include ../lib.mk 67 + 68 + # NOTE: $(OUTPUT) won't get default value if used before lib.mk 69 + TEST_CUSTOM_PROGS = $(OUTPUT)/urandom_read 70 + all: $(TEST_CUSTOM_PROGS) 71 + 72 + $(OUTPUT)/urandom_read: $(OUTPUT)/%: %.c 73 + $(CC) -o $@ -static $< -Wl,--build-id 87 74 88 75 BPFOBJ := $(OUTPUT)/libbpf.a 89 76 ··· 118 91 119 92 $(BPFOBJ): force 120 93 $(MAKE) -C $(BPFDIR) OUTPUT=$(OUTPUT)/ 121 - 122 - CLANG ?= clang 123 - LLC ?= llc 124 - LLVM_OBJCOPY ?= llvm-objcopy 125 - LLVM_READELF ?= llvm-readelf 126 - BTF_PAHOLE ?= pahole 127 94 128 95 PROBE := $(shell $(LLC) -march=bpf -mcpu=probe -filetype=null /dev/null 2>&1) 129 96 ··· 170 149 endif 171 150 endif 172 151 152 + ifneq ($(SUBREG_CODEGEN),) 153 + ALU32_BUILD_DIR = $(OUTPUT)/alu32 154 + TEST_CUSTOM_PROGS += $(ALU32_BUILD_DIR)/test_progs_32 155 + $(ALU32_BUILD_DIR): 156 + mkdir -p $@ 157 + 158 + $(ALU32_BUILD_DIR)/urandom_read: $(OUTPUT)/urandom_read 159 + cp $< $@ 160 + 161 + $(ALU32_BUILD_DIR)/test_progs_32: test_progs.c $(ALU32_BUILD_DIR) \ 162 + $(ALU32_BUILD_DIR)/urandom_read 163 + $(CC) $(CFLAGS) -o $(ALU32_BUILD_DIR)/test_progs_32 $< \ 164 + trace_helpers.c $(OUTPUT)/libbpf.a $(LDLIBS) 165 + 166 + $(ALU32_BUILD_DIR)/%.o: %.c $(ALU32_BUILD_DIR) $(ALU32_BUILD_DIR)/test_progs_32 167 + $(CLANG) $(CLANG_FLAGS) \ 168 + -O2 -target bpf -emit-llvm -c $< -o - | \ 169 + $(LLC) -march=bpf -mattr=+alu32 -mcpu=$(CPU) $(LLC_FLAGS) \ 170 + -filetype=obj -o $@ 171 + ifeq ($(DWARF2BTF),y) 172 + $(BTF_PAHOLE) -J $@ 173 + endif 174 + endif 175 + 173 176 # Have one program compiled without "-target bpf" to test whether libbpf loads 174 177 # it successfully 175 178 $(OUTPUT)/test_xdp.o: test_xdp.c ··· 212 167 $(BTF_PAHOLE) -J $@ 213 168 endif 214 169 215 - EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) 170 + EXTRA_CLEAN := $(TEST_CUSTOM_PROGS) $(ALU32_BUILD_DIR)
+762 -24
tools/testing/selftests/bpf/test_verifier.c
··· 211 211 BPF_MOV64_IMM(BPF_REG_5, 0), \ 212 212 BPF_EMIT_CALL(BPF_FUNC_sk_lookup_tcp) 213 213 214 + /* BPF_DIRECT_PKT_R2 contains 7 instructions, it initializes default return 215 + * value into 0 and does necessary preparation for direct packet access 216 + * through r2. The allowed access range is 8 bytes. 217 + */ 218 + #define BPF_DIRECT_PKT_R2 \ 219 + BPF_MOV64_IMM(BPF_REG_0, 0), \ 220 + BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, \ 221 + offsetof(struct __sk_buff, data)), \ 222 + BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, \ 223 + offsetof(struct __sk_buff, data_end)), \ 224 + BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), \ 225 + BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), \ 226 + BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), \ 227 + BPF_EXIT_INSN() 228 + 229 + /* BPF_RAND_UEXT_R7 contains 4 instructions, it initializes R7 into a random 230 + * positive u32, and zero-extend it into 64-bit. 231 + */ 232 + #define BPF_RAND_UEXT_R7 \ 233 + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, \ 234 + BPF_FUNC_get_prandom_u32), \ 235 + BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), \ 236 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 33), \ 237 + BPF_ALU64_IMM(BPF_RSH, BPF_REG_7, 33) 238 + 239 + /* BPF_RAND_SEXT_R7 contains 5 instructions, it initializes R7 into a random 240 + * negative u32, and sign-extend it into 64-bit. 241 + */ 242 + #define BPF_RAND_SEXT_R7 \ 243 + BPF_RAW_INSN(BPF_JMP | BPF_CALL, 0, 0, 0, \ 244 + BPF_FUNC_get_prandom_u32), \ 245 + BPF_MOV64_REG(BPF_REG_7, BPF_REG_0), \ 246 + BPF_ALU64_IMM(BPF_OR, BPF_REG_7, 0x80000000), \ 247 + BPF_ALU64_IMM(BPF_LSH, BPF_REG_7, 32), \ 248 + BPF_ALU64_IMM(BPF_ARSH, BPF_REG_7, 32) 249 + 214 250 static struct bpf_test tests[] = { 215 251 { 216 252 "add+sub+mul", ··· 15483 15447 { 15484 15448 "jset: functional", 15485 15449 .insns = { 15486 - /* r0 = 0 */ 15487 - BPF_MOV64_IMM(BPF_REG_0, 0), 15488 - /* prep for direct packet access via r2 */ 15489 - BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 15490 - offsetof(struct __sk_buff, data)), 15491 - BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 15492 - offsetof(struct __sk_buff, data_end)), 15493 - BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), 15494 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), 15495 - BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), 15496 - BPF_EXIT_INSN(), 15497 - 15450 + BPF_DIRECT_PKT_R2, 15498 15451 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15499 15452 15500 15453 /* reg, bit 63 or bit 0 set, taken */ ··· 15539 15514 { 15540 15515 "jset: sign-extend", 15541 15516 .insns = { 15542 - /* r0 = 0 */ 15543 - BPF_MOV64_IMM(BPF_REG_0, 0), 15544 - /* prep for direct packet access via r2 */ 15545 - BPF_LDX_MEM(BPF_W, BPF_REG_2, BPF_REG_1, 15546 - offsetof(struct __sk_buff, data)), 15547 - BPF_LDX_MEM(BPF_W, BPF_REG_3, BPF_REG_1, 15548 - offsetof(struct __sk_buff, data_end)), 15549 - BPF_MOV64_REG(BPF_REG_4, BPF_REG_2), 15550 - BPF_ALU64_IMM(BPF_ADD, BPF_REG_4, 8), 15551 - BPF_JMP_REG(BPF_JLE, BPF_REG_4, BPF_REG_3, 1), 15552 - BPF_EXIT_INSN(), 15553 - 15517 + BPF_DIRECT_PKT_R2, 15554 15518 BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15555 15519 15556 15520 BPF_JMP_IMM(BPF_JSET, BPF_REG_7, 0x80000000, 1), ··· 15806 15792 }, 15807 15793 .errstr_unpriv = "function calls to other bpf functions are allowed for root only", 15808 15794 .result_unpriv = REJECT, 15795 + .result = ACCEPT, 15796 + .retval = 2, 15797 + }, 15798 + { 15799 + "jset32: BPF_K", 15800 + .insns = { 15801 + BPF_DIRECT_PKT_R2, 15802 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15803 + /* reg, high bits shouldn't be tested */ 15804 + BPF_JMP32_IMM(BPF_JSET, BPF_REG_7, -2, 1), 15805 + BPF_JMP_IMM(BPF_JA, 0, 0, 1), 15806 + BPF_EXIT_INSN(), 15807 + 15808 + BPF_JMP32_IMM(BPF_JSET, BPF_REG_7, 1, 1), 15809 + BPF_EXIT_INSN(), 15810 + BPF_MOV64_IMM(BPF_REG_0, 2), 15811 + BPF_EXIT_INSN(), 15812 + }, 15813 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15814 + .result = ACCEPT, 15815 + .runs = 3, 15816 + .retvals = { 15817 + { .retval = 0, 15818 + .data64 = { 1ULL << 63, } 15819 + }, 15820 + { .retval = 2, 15821 + .data64 = { 1, } 15822 + }, 15823 + { .retval = 2, 15824 + .data64 = { 1ULL << 63 | 1, } 15825 + }, 15826 + }, 15827 + }, 15828 + { 15829 + "jset32: BPF_X", 15830 + .insns = { 15831 + BPF_DIRECT_PKT_R2, 15832 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15833 + BPF_LD_IMM64(BPF_REG_8, 0x8000000000000000), 15834 + BPF_JMP32_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1), 15835 + BPF_JMP_IMM(BPF_JA, 0, 0, 1), 15836 + BPF_EXIT_INSN(), 15837 + 15838 + BPF_LD_IMM64(BPF_REG_8, 0x8000000000000001), 15839 + BPF_JMP32_REG(BPF_JSET, BPF_REG_7, BPF_REG_8, 1), 15840 + BPF_EXIT_INSN(), 15841 + BPF_MOV64_IMM(BPF_REG_0, 2), 15842 + BPF_EXIT_INSN(), 15843 + }, 15844 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15845 + .result = ACCEPT, 15846 + .runs = 3, 15847 + .retvals = { 15848 + { .retval = 0, 15849 + .data64 = { 1ULL << 63, } 15850 + }, 15851 + { .retval = 2, 15852 + .data64 = { 1, } 15853 + }, 15854 + { .retval = 2, 15855 + .data64 = { 1ULL << 63 | 1, } 15856 + }, 15857 + }, 15858 + }, 15859 + { 15860 + "jset32: min/max deduction", 15861 + .insns = { 15862 + BPF_RAND_UEXT_R7, 15863 + BPF_MOV64_IMM(BPF_REG_0, 0), 15864 + BPF_JMP32_IMM(BPF_JSET, BPF_REG_7, 0x10, 1), 15865 + BPF_EXIT_INSN(), 15866 + BPF_JMP32_IMM(BPF_JGE, BPF_REG_7, 0x10, 1), 15867 + BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), 15868 + BPF_EXIT_INSN(), 15869 + }, 15870 + .result = ACCEPT, 15871 + }, 15872 + { 15873 + "jeq32: BPF_K", 15874 + .insns = { 15875 + BPF_DIRECT_PKT_R2, 15876 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15877 + BPF_JMP32_IMM(BPF_JEQ, BPF_REG_7, -1, 1), 15878 + BPF_EXIT_INSN(), 15879 + BPF_MOV64_IMM(BPF_REG_0, 2), 15880 + BPF_EXIT_INSN(), 15881 + }, 15882 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15883 + .result = ACCEPT, 15884 + .runs = 2, 15885 + .retvals = { 15886 + { .retval = 0, 15887 + .data64 = { -2, } 15888 + }, 15889 + { .retval = 2, 15890 + .data64 = { -1, } 15891 + }, 15892 + }, 15893 + }, 15894 + { 15895 + "jeq32: BPF_X", 15896 + .insns = { 15897 + BPF_DIRECT_PKT_R2, 15898 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15899 + BPF_LD_IMM64(BPF_REG_8, 0x7000000000000001), 15900 + BPF_JMP32_REG(BPF_JEQ, BPF_REG_7, BPF_REG_8, 1), 15901 + BPF_EXIT_INSN(), 15902 + BPF_MOV64_IMM(BPF_REG_0, 2), 15903 + BPF_EXIT_INSN(), 15904 + }, 15905 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15906 + .result = ACCEPT, 15907 + .runs = 3, 15908 + .retvals = { 15909 + { .retval = 0, 15910 + .data64 = { 2, } 15911 + }, 15912 + { .retval = 2, 15913 + .data64 = { 1, } 15914 + }, 15915 + { .retval = 2, 15916 + .data64 = { 1ULL << 63 | 1, } 15917 + }, 15918 + }, 15919 + }, 15920 + { 15921 + "jeq32: min/max deduction", 15922 + .insns = { 15923 + BPF_RAND_UEXT_R7, 15924 + BPF_MOV64_IMM(BPF_REG_0, 0), 15925 + BPF_JMP32_IMM(BPF_JEQ, BPF_REG_7, 0x10, 1), 15926 + BPF_EXIT_INSN(), 15927 + BPF_JMP32_IMM(BPF_JSGE, BPF_REG_7, 0xf, 1), 15928 + BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), 15929 + BPF_EXIT_INSN(), 15930 + }, 15931 + .result = ACCEPT, 15932 + }, 15933 + { 15934 + "jne32: BPF_K", 15935 + .insns = { 15936 + BPF_DIRECT_PKT_R2, 15937 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15938 + BPF_JMP32_IMM(BPF_JNE, BPF_REG_7, -1, 1), 15939 + BPF_EXIT_INSN(), 15940 + BPF_MOV64_IMM(BPF_REG_0, 2), 15941 + BPF_EXIT_INSN(), 15942 + }, 15943 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15944 + .result = ACCEPT, 15945 + .runs = 2, 15946 + .retvals = { 15947 + { .retval = 2, 15948 + .data64 = { 1, } 15949 + }, 15950 + { .retval = 0, 15951 + .data64 = { -1, } 15952 + }, 15953 + }, 15954 + }, 15955 + { 15956 + "jne32: BPF_X", 15957 + .insns = { 15958 + BPF_DIRECT_PKT_R2, 15959 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15960 + BPF_LD_IMM64(BPF_REG_8, 0x8000000000000001), 15961 + BPF_JMP32_REG(BPF_JNE, BPF_REG_7, BPF_REG_8, 1), 15962 + BPF_EXIT_INSN(), 15963 + BPF_MOV64_IMM(BPF_REG_0, 2), 15964 + BPF_EXIT_INSN(), 15965 + }, 15966 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 15967 + .result = ACCEPT, 15968 + .runs = 3, 15969 + .retvals = { 15970 + { .retval = 0, 15971 + .data64 = { 1, } 15972 + }, 15973 + { .retval = 2, 15974 + .data64 = { 2, } 15975 + }, 15976 + { .retval = 2, 15977 + .data64 = { 1ULL << 63 | 2, } 15978 + }, 15979 + }, 15980 + }, 15981 + { 15982 + "jne32: min/max deduction", 15983 + .insns = { 15984 + BPF_RAND_UEXT_R7, 15985 + BPF_MOV64_IMM(BPF_REG_0, 0), 15986 + BPF_JMP32_IMM(BPF_JNE, BPF_REG_7, 0x10, 1), 15987 + BPF_JMP_IMM(BPF_JNE, BPF_REG_7, 0x10, 1), 15988 + BPF_EXIT_INSN(), 15989 + BPF_LDX_MEM(BPF_B, BPF_REG_8, BPF_REG_9, 0), 15990 + BPF_EXIT_INSN(), 15991 + }, 15992 + .result = ACCEPT, 15993 + }, 15994 + { 15995 + "jge32: BPF_K", 15996 + .insns = { 15997 + BPF_DIRECT_PKT_R2, 15998 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 15999 + BPF_JMP32_IMM(BPF_JGE, BPF_REG_7, UINT_MAX - 1, 1), 16000 + BPF_EXIT_INSN(), 16001 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16002 + BPF_EXIT_INSN(), 16003 + }, 16004 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16005 + .result = ACCEPT, 16006 + .runs = 3, 16007 + .retvals = { 16008 + { .retval = 2, 16009 + .data64 = { UINT_MAX, } 16010 + }, 16011 + { .retval = 2, 16012 + .data64 = { UINT_MAX - 1, } 16013 + }, 16014 + { .retval = 0, 16015 + .data64 = { 0, } 16016 + }, 16017 + }, 16018 + }, 16019 + { 16020 + "jge32: BPF_X", 16021 + .insns = { 16022 + BPF_DIRECT_PKT_R2, 16023 + BPF_LD_IMM64(BPF_REG_8, UINT_MAX | 1ULL << 32), 16024 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16025 + BPF_JMP32_REG(BPF_JGE, BPF_REG_7, BPF_REG_8, 1), 16026 + BPF_EXIT_INSN(), 16027 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16028 + BPF_EXIT_INSN(), 16029 + }, 16030 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16031 + .result = ACCEPT, 16032 + .runs = 3, 16033 + .retvals = { 16034 + { .retval = 2, 16035 + .data64 = { UINT_MAX, } 16036 + }, 16037 + { .retval = 0, 16038 + .data64 = { INT_MAX, } 16039 + }, 16040 + { .retval = 0, 16041 + .data64 = { (UINT_MAX - 1) | 2ULL << 32, } 16042 + }, 16043 + }, 16044 + }, 16045 + { 16046 + "jge32: min/max deduction", 16047 + .insns = { 16048 + BPF_RAND_UEXT_R7, 16049 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16050 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16051 + BPF_JMP32_REG(BPF_JGE, BPF_REG_7, BPF_REG_8, 1), 16052 + BPF_EXIT_INSN(), 16053 + BPF_JMP32_IMM(BPF_JGE, BPF_REG_7, 0x7ffffff0, 1), 16054 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16055 + BPF_EXIT_INSN(), 16056 + }, 16057 + .result = ACCEPT, 16058 + .retval = 2, 16059 + }, 16060 + { 16061 + "jgt32: BPF_K", 16062 + .insns = { 16063 + BPF_DIRECT_PKT_R2, 16064 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16065 + BPF_JMP32_IMM(BPF_JGT, BPF_REG_7, UINT_MAX - 1, 1), 16066 + BPF_EXIT_INSN(), 16067 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16068 + BPF_EXIT_INSN(), 16069 + }, 16070 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16071 + .result = ACCEPT, 16072 + .runs = 3, 16073 + .retvals = { 16074 + { .retval = 2, 16075 + .data64 = { UINT_MAX, } 16076 + }, 16077 + { .retval = 0, 16078 + .data64 = { UINT_MAX - 1, } 16079 + }, 16080 + { .retval = 0, 16081 + .data64 = { 0, } 16082 + }, 16083 + }, 16084 + }, 16085 + { 16086 + "jgt32: BPF_X", 16087 + .insns = { 16088 + BPF_DIRECT_PKT_R2, 16089 + BPF_LD_IMM64(BPF_REG_8, (UINT_MAX - 1) | 1ULL << 32), 16090 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16091 + BPF_JMP32_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 1), 16092 + BPF_EXIT_INSN(), 16093 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16094 + BPF_EXIT_INSN(), 16095 + }, 16096 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16097 + .result = ACCEPT, 16098 + .runs = 3, 16099 + .retvals = { 16100 + { .retval = 2, 16101 + .data64 = { UINT_MAX, } 16102 + }, 16103 + { .retval = 0, 16104 + .data64 = { UINT_MAX - 1, } 16105 + }, 16106 + { .retval = 0, 16107 + .data64 = { (UINT_MAX - 1) | 2ULL << 32, } 16108 + }, 16109 + }, 16110 + }, 16111 + { 16112 + "jgt32: min/max deduction", 16113 + .insns = { 16114 + BPF_RAND_UEXT_R7, 16115 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16116 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16117 + BPF_JMP32_REG(BPF_JGT, BPF_REG_7, BPF_REG_8, 1), 16118 + BPF_EXIT_INSN(), 16119 + BPF_JMP_IMM(BPF_JGT, BPF_REG_7, 0x7ffffff0, 1), 16120 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16121 + BPF_EXIT_INSN(), 16122 + }, 16123 + .result = ACCEPT, 16124 + .retval = 2, 16125 + }, 16126 + { 16127 + "jle32: BPF_K", 16128 + .insns = { 16129 + BPF_DIRECT_PKT_R2, 16130 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16131 + BPF_JMP32_IMM(BPF_JLE, BPF_REG_7, INT_MAX, 1), 16132 + BPF_EXIT_INSN(), 16133 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16134 + BPF_EXIT_INSN(), 16135 + }, 16136 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16137 + .result = ACCEPT, 16138 + .runs = 3, 16139 + .retvals = { 16140 + { .retval = 2, 16141 + .data64 = { INT_MAX - 1, } 16142 + }, 16143 + { .retval = 0, 16144 + .data64 = { UINT_MAX, } 16145 + }, 16146 + { .retval = 2, 16147 + .data64 = { INT_MAX, } 16148 + }, 16149 + }, 16150 + }, 16151 + { 16152 + "jle32: BPF_X", 16153 + .insns = { 16154 + BPF_DIRECT_PKT_R2, 16155 + BPF_LD_IMM64(BPF_REG_8, (INT_MAX - 1) | 2ULL << 32), 16156 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16157 + BPF_JMP32_REG(BPF_JLE, BPF_REG_7, BPF_REG_8, 1), 16158 + BPF_EXIT_INSN(), 16159 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16160 + BPF_EXIT_INSN(), 16161 + }, 16162 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16163 + .result = ACCEPT, 16164 + .runs = 3, 16165 + .retvals = { 16166 + { .retval = 0, 16167 + .data64 = { INT_MAX | 1ULL << 32, } 16168 + }, 16169 + { .retval = 2, 16170 + .data64 = { INT_MAX - 2, } 16171 + }, 16172 + { .retval = 0, 16173 + .data64 = { UINT_MAX, } 16174 + }, 16175 + }, 16176 + }, 16177 + { 16178 + "jle32: min/max deduction", 16179 + .insns = { 16180 + BPF_RAND_UEXT_R7, 16181 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16182 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16183 + BPF_JMP32_REG(BPF_JLE, BPF_REG_7, BPF_REG_8, 1), 16184 + BPF_EXIT_INSN(), 16185 + BPF_JMP32_IMM(BPF_JLE, BPF_REG_7, 0x7ffffff0, 1), 16186 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16187 + BPF_EXIT_INSN(), 16188 + }, 16189 + .result = ACCEPT, 16190 + .retval = 2, 16191 + }, 16192 + { 16193 + "jlt32: BPF_K", 16194 + .insns = { 16195 + BPF_DIRECT_PKT_R2, 16196 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16197 + BPF_JMP32_IMM(BPF_JLT, BPF_REG_7, INT_MAX, 1), 16198 + BPF_EXIT_INSN(), 16199 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16200 + BPF_EXIT_INSN(), 16201 + }, 16202 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16203 + .result = ACCEPT, 16204 + .runs = 3, 16205 + .retvals = { 16206 + { .retval = 0, 16207 + .data64 = { INT_MAX, } 16208 + }, 16209 + { .retval = 0, 16210 + .data64 = { UINT_MAX, } 16211 + }, 16212 + { .retval = 2, 16213 + .data64 = { INT_MAX - 1, } 16214 + }, 16215 + }, 16216 + }, 16217 + { 16218 + "jlt32: BPF_X", 16219 + .insns = { 16220 + BPF_DIRECT_PKT_R2, 16221 + BPF_LD_IMM64(BPF_REG_8, INT_MAX | 2ULL << 32), 16222 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16223 + BPF_JMP32_REG(BPF_JLT, BPF_REG_7, BPF_REG_8, 1), 16224 + BPF_EXIT_INSN(), 16225 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16226 + BPF_EXIT_INSN(), 16227 + }, 16228 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16229 + .result = ACCEPT, 16230 + .runs = 3, 16231 + .retvals = { 16232 + { .retval = 0, 16233 + .data64 = { INT_MAX | 1ULL << 32, } 16234 + }, 16235 + { .retval = 0, 16236 + .data64 = { UINT_MAX, } 16237 + }, 16238 + { .retval = 2, 16239 + .data64 = { (INT_MAX - 1) | 3ULL << 32, } 16240 + }, 16241 + }, 16242 + }, 16243 + { 16244 + "jlt32: min/max deduction", 16245 + .insns = { 16246 + BPF_RAND_UEXT_R7, 16247 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16248 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16249 + BPF_JMP32_REG(BPF_JLT, BPF_REG_7, BPF_REG_8, 1), 16250 + BPF_EXIT_INSN(), 16251 + BPF_JMP_IMM(BPF_JSLT, BPF_REG_7, 0x7ffffff0, 1), 16252 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16253 + BPF_EXIT_INSN(), 16254 + }, 16255 + .result = ACCEPT, 16256 + .retval = 2, 16257 + }, 16258 + { 16259 + "jsge32: BPF_K", 16260 + .insns = { 16261 + BPF_DIRECT_PKT_R2, 16262 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16263 + BPF_JMP32_IMM(BPF_JSGE, BPF_REG_7, -1, 1), 16264 + BPF_EXIT_INSN(), 16265 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16266 + BPF_EXIT_INSN(), 16267 + }, 16268 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16269 + .result = ACCEPT, 16270 + .runs = 3, 16271 + .retvals = { 16272 + { .retval = 2, 16273 + .data64 = { 0, } 16274 + }, 16275 + { .retval = 2, 16276 + .data64 = { -1, } 16277 + }, 16278 + { .retval = 0, 16279 + .data64 = { -2, } 16280 + }, 16281 + }, 16282 + }, 16283 + { 16284 + "jsge32: BPF_X", 16285 + .insns = { 16286 + BPF_DIRECT_PKT_R2, 16287 + BPF_LD_IMM64(BPF_REG_8, (__u32)-1 | 2ULL << 32), 16288 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16289 + BPF_JMP32_REG(BPF_JSGE, BPF_REG_7, BPF_REG_8, 1), 16290 + BPF_EXIT_INSN(), 16291 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16292 + BPF_EXIT_INSN(), 16293 + }, 16294 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16295 + .result = ACCEPT, 16296 + .runs = 3, 16297 + .retvals = { 16298 + { .retval = 2, 16299 + .data64 = { -1, } 16300 + }, 16301 + { .retval = 2, 16302 + .data64 = { 0x7fffffff | 1ULL << 32, } 16303 + }, 16304 + { .retval = 0, 16305 + .data64 = { -2, } 16306 + }, 16307 + }, 16308 + }, 16309 + { 16310 + "jsge32: min/max deduction", 16311 + .insns = { 16312 + BPF_RAND_UEXT_R7, 16313 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16314 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16315 + BPF_JMP32_REG(BPF_JSGE, BPF_REG_7, BPF_REG_8, 1), 16316 + BPF_EXIT_INSN(), 16317 + BPF_JMP_IMM(BPF_JSGE, BPF_REG_7, 0x7ffffff0, 1), 16318 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16319 + BPF_EXIT_INSN(), 16320 + }, 16321 + .result = ACCEPT, 16322 + .retval = 2, 16323 + }, 16324 + { 16325 + "jsgt32: BPF_K", 16326 + .insns = { 16327 + BPF_DIRECT_PKT_R2, 16328 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16329 + BPF_JMP32_IMM(BPF_JSGT, BPF_REG_7, -1, 1), 16330 + BPF_EXIT_INSN(), 16331 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16332 + BPF_EXIT_INSN(), 16333 + }, 16334 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16335 + .result = ACCEPT, 16336 + .runs = 3, 16337 + .retvals = { 16338 + { .retval = 0, 16339 + .data64 = { (__u32)-2, } 16340 + }, 16341 + { .retval = 0, 16342 + .data64 = { -1, } 16343 + }, 16344 + { .retval = 2, 16345 + .data64 = { 1, } 16346 + }, 16347 + }, 16348 + }, 16349 + { 16350 + "jsgt32: BPF_X", 16351 + .insns = { 16352 + BPF_DIRECT_PKT_R2, 16353 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffffe | 1ULL << 32), 16354 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16355 + BPF_JMP32_REG(BPF_JSGT, BPF_REG_7, BPF_REG_8, 1), 16356 + BPF_EXIT_INSN(), 16357 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16358 + BPF_EXIT_INSN(), 16359 + }, 16360 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16361 + .result = ACCEPT, 16362 + .runs = 3, 16363 + .retvals = { 16364 + { .retval = 0, 16365 + .data64 = { 0x7ffffffe, } 16366 + }, 16367 + { .retval = 0, 16368 + .data64 = { 0x1ffffffffULL, } 16369 + }, 16370 + { .retval = 2, 16371 + .data64 = { 0x7fffffff, } 16372 + }, 16373 + }, 16374 + }, 16375 + { 16376 + "jsgt32: min/max deduction", 16377 + .insns = { 16378 + BPF_RAND_SEXT_R7, 16379 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16380 + BPF_LD_IMM64(BPF_REG_8, (__u32)(-2) | 1ULL << 32), 16381 + BPF_JMP32_REG(BPF_JSGT, BPF_REG_7, BPF_REG_8, 1), 16382 + BPF_EXIT_INSN(), 16383 + BPF_JMP_IMM(BPF_JSGT, BPF_REG_7, -2, 1), 16384 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16385 + BPF_EXIT_INSN(), 16386 + }, 16387 + .result = ACCEPT, 16388 + .retval = 2, 16389 + }, 16390 + { 16391 + "jsle32: BPF_K", 16392 + .insns = { 16393 + BPF_DIRECT_PKT_R2, 16394 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16395 + BPF_JMP32_IMM(BPF_JSLE, BPF_REG_7, -1, 1), 16396 + BPF_EXIT_INSN(), 16397 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16398 + BPF_EXIT_INSN(), 16399 + }, 16400 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16401 + .result = ACCEPT, 16402 + .runs = 3, 16403 + .retvals = { 16404 + { .retval = 2, 16405 + .data64 = { (__u32)-2, } 16406 + }, 16407 + { .retval = 2, 16408 + .data64 = { -1, } 16409 + }, 16410 + { .retval = 0, 16411 + .data64 = { 1, } 16412 + }, 16413 + }, 16414 + }, 16415 + { 16416 + "jsle32: BPF_X", 16417 + .insns = { 16418 + BPF_DIRECT_PKT_R2, 16419 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffffe | 1ULL << 32), 16420 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16421 + BPF_JMP32_REG(BPF_JSLE, BPF_REG_7, BPF_REG_8, 1), 16422 + BPF_EXIT_INSN(), 16423 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16424 + BPF_EXIT_INSN(), 16425 + }, 16426 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16427 + .result = ACCEPT, 16428 + .runs = 3, 16429 + .retvals = { 16430 + { .retval = 2, 16431 + .data64 = { 0x7ffffffe, } 16432 + }, 16433 + { .retval = 2, 16434 + .data64 = { (__u32)-1, } 16435 + }, 16436 + { .retval = 0, 16437 + .data64 = { 0x7fffffff | 2ULL << 32, } 16438 + }, 16439 + }, 16440 + }, 16441 + { 16442 + "jsle32: min/max deduction", 16443 + .insns = { 16444 + BPF_RAND_UEXT_R7, 16445 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16446 + BPF_LD_IMM64(BPF_REG_8, 0x7ffffff0 | 1ULL << 32), 16447 + BPF_JMP32_REG(BPF_JSLE, BPF_REG_7, BPF_REG_8, 1), 16448 + BPF_EXIT_INSN(), 16449 + BPF_JMP_IMM(BPF_JSLE, BPF_REG_7, 0x7ffffff0, 1), 16450 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16451 + BPF_EXIT_INSN(), 16452 + }, 16453 + .result = ACCEPT, 16454 + .retval = 2, 16455 + }, 16456 + { 16457 + "jslt32: BPF_K", 16458 + .insns = { 16459 + BPF_DIRECT_PKT_R2, 16460 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16461 + BPF_JMP32_IMM(BPF_JSLT, BPF_REG_7, -1, 1), 16462 + BPF_EXIT_INSN(), 16463 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16464 + BPF_EXIT_INSN(), 16465 + }, 16466 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16467 + .result = ACCEPT, 16468 + .runs = 3, 16469 + .retvals = { 16470 + { .retval = 2, 16471 + .data64 = { (__u32)-2, } 16472 + }, 16473 + { .retval = 0, 16474 + .data64 = { -1, } 16475 + }, 16476 + { .retval = 0, 16477 + .data64 = { 1, } 16478 + }, 16479 + }, 16480 + }, 16481 + { 16482 + "jslt32: BPF_X", 16483 + .insns = { 16484 + BPF_DIRECT_PKT_R2, 16485 + BPF_LD_IMM64(BPF_REG_8, 0x7fffffff | 1ULL << 32), 16486 + BPF_LDX_MEM(BPF_DW, BPF_REG_7, BPF_REG_2, 0), 16487 + BPF_JMP32_REG(BPF_JSLT, BPF_REG_7, BPF_REG_8, 1), 16488 + BPF_EXIT_INSN(), 16489 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16490 + BPF_EXIT_INSN(), 16491 + }, 16492 + .prog_type = BPF_PROG_TYPE_SCHED_CLS, 16493 + .result = ACCEPT, 16494 + .runs = 3, 16495 + .retvals = { 16496 + { .retval = 2, 16497 + .data64 = { 0x7ffffffe, } 16498 + }, 16499 + { .retval = 2, 16500 + .data64 = { 0xffffffff, } 16501 + }, 16502 + { .retval = 0, 16503 + .data64 = { 0x7fffffff | 2ULL << 32, } 16504 + }, 16505 + }, 16506 + }, 16507 + { 16508 + "jslt32: min/max deduction", 16509 + .insns = { 16510 + BPF_RAND_SEXT_R7, 16511 + BPF_ALU32_IMM(BPF_MOV, BPF_REG_0, 2), 16512 + BPF_LD_IMM64(BPF_REG_8, (__u32)(-1) | 1ULL << 32), 16513 + BPF_JMP32_REG(BPF_JSLT, BPF_REG_7, BPF_REG_8, 1), 16514 + BPF_EXIT_INSN(), 16515 + BPF_JMP32_IMM(BPF_JSLT, BPF_REG_7, -1, 1), 16516 + BPF_LDX_MEM(BPF_DW, BPF_REG_0, BPF_REG_0, 0), 16517 + BPF_EXIT_INSN(), 16518 + }, 15809 16519 .result = ACCEPT, 15810 16520 .retval = 2, 15811 16521 },