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

Merge branch 'bpf-rv64-jit'

Luke Nelson says:

====================
This patch series introduces a set of optimizations to the BPF JIT
on RV64. The optimizations are related to the verifier zero-extension
optimization and BPF_JMP BPF_K.

We tested the optimizations on a QEMU riscv64 virt machine, using
lib/test_bpf and test_verifier, and formally verified their correctness
using Serval.
====================

Signed-off-by: Daniel Borkmann <daniel@iogearbox.net>

+44 -20
+44 -20
arch/riscv/net/bpf_jit_comp64.c
··· 515 515 case BPF_ALU | BPF_LSH | BPF_X: 516 516 case BPF_ALU64 | BPF_LSH | BPF_X: 517 517 emit(is64 ? rv_sll(rd, rd, rs) : rv_sllw(rd, rd, rs), ctx); 518 - if (!is64) 518 + if (!is64 && !aux->verifier_zext) 519 519 emit_zext_32(rd, ctx); 520 520 break; 521 521 case BPF_ALU | BPF_RSH | BPF_X: ··· 542 542 543 543 /* dst = BSWAP##imm(dst) */ 544 544 case BPF_ALU | BPF_END | BPF_FROM_LE: 545 - { 546 - int shift = 64 - imm; 547 - 548 - emit(rv_slli(rd, rd, shift), ctx); 549 - emit(rv_srli(rd, rd, shift), ctx); 545 + switch (imm) { 546 + case 16: 547 + emit(rv_slli(rd, rd, 48), ctx); 548 + emit(rv_srli(rd, rd, 48), ctx); 549 + break; 550 + case 32: 551 + if (!aux->verifier_zext) 552 + emit_zext_32(rd, ctx); 553 + break; 554 + case 64: 555 + /* Do nothing */ 556 + break; 557 + } 550 558 break; 551 - } 559 + 552 560 case BPF_ALU | BPF_END | BPF_FROM_BE: 553 561 emit(rv_addi(RV_REG_T2, RV_REG_ZERO, 0), ctx); 554 562 ··· 700 692 case BPF_ALU | BPF_LSH | BPF_K: 701 693 case BPF_ALU64 | BPF_LSH | BPF_K: 702 694 emit(is64 ? rv_slli(rd, rd, imm) : rv_slliw(rd, rd, imm), ctx); 703 - if (!is64) 695 + if (!is64 && !aux->verifier_zext) 704 696 emit_zext_32(rd, ctx); 705 697 break; 706 698 case BPF_ALU | BPF_RSH | BPF_K: 707 699 case BPF_ALU64 | BPF_RSH | BPF_K: 708 700 emit(is64 ? rv_srli(rd, rd, imm) : rv_srliw(rd, rd, imm), ctx); 709 - if (!is64) 701 + if (!is64 && !aux->verifier_zext) 710 702 emit_zext_32(rd, ctx); 711 703 break; 712 704 case BPF_ALU | BPF_ARSH | BPF_K: 713 705 case BPF_ALU64 | BPF_ARSH | BPF_K: 714 706 emit(is64 ? rv_srai(rd, rd, imm) : rv_sraiw(rd, rd, imm), ctx); 715 - if (!is64) 707 + if (!is64 && !aux->verifier_zext) 716 708 emit_zext_32(rd, ctx); 717 709 break; 718 710 ··· 792 784 case BPF_JMP32 | BPF_JSGE | BPF_K: 793 785 case BPF_JMP | BPF_JSLE | BPF_K: 794 786 case BPF_JMP32 | BPF_JSLE | BPF_K: 795 - case BPF_JMP | BPF_JSET | BPF_K: 796 - case BPF_JMP32 | BPF_JSET | BPF_K: 797 787 rvoff = rv_offset(i, off, ctx); 798 788 s = ctx->ninsns; 799 - emit_imm(RV_REG_T1, imm, ctx); 789 + if (imm) { 790 + emit_imm(RV_REG_T1, imm, ctx); 791 + rs = RV_REG_T1; 792 + } else { 793 + /* If imm is 0, simply use zero register. */ 794 + rs = RV_REG_ZERO; 795 + } 800 796 if (!is64) { 801 797 if (is_signed_bpf_cond(BPF_OP(code))) 802 798 emit_sext_32_rd(&rd, ctx); ··· 811 799 812 800 /* Adjust for extra insns */ 813 801 rvoff -= (e - s) << 2; 802 + emit_branch(BPF_OP(code), rd, rs, rvoff, ctx); 803 + break; 814 804 815 - if (BPF_OP(code) == BPF_JSET) { 816 - /* Adjust for and */ 817 - rvoff -= 4; 818 - emit(rv_and(RV_REG_T1, rd, RV_REG_T1), ctx); 819 - emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, 820 - ctx); 805 + case BPF_JMP | BPF_JSET | BPF_K: 806 + case BPF_JMP32 | BPF_JSET | BPF_K: 807 + rvoff = rv_offset(i, off, ctx); 808 + s = ctx->ninsns; 809 + if (is_12b_int(imm)) { 810 + emit(rv_andi(RV_REG_T1, rd, imm), ctx); 821 811 } else { 822 - emit_branch(BPF_OP(code), rd, RV_REG_T1, rvoff, ctx); 812 + emit_imm(RV_REG_T1, imm, ctx); 813 + emit(rv_and(RV_REG_T1, rd, RV_REG_T1), ctx); 823 814 } 815 + /* For jset32, we should clear the upper 32 bits of t1, but 816 + * sign-extension is sufficient here and saves one instruction, 817 + * as t1 is used only in comparison against zero. 818 + */ 819 + if (!is64 && imm < 0) 820 + emit(rv_addiw(RV_REG_T1, RV_REG_T1, 0), ctx); 821 + e = ctx->ninsns; 822 + rvoff -= (e - s) << 2; 823 + emit_branch(BPF_JNE, RV_REG_T1, RV_REG_ZERO, rvoff, ctx); 824 824 break; 825 825 826 826 /* function call */