.. | .. |
---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
---|
1 | 2 | /* |
---|
2 | 3 | * Just-In-Time compiler for eBPF filters on 32bit ARM |
---|
3 | 4 | * |
---|
4 | 5 | * Copyright (c) 2017 Shubham Bansal <illusionist.neo@gmail.com> |
---|
5 | 6 | * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com> |
---|
6 | | - * |
---|
7 | | - * This program is free software; you can redistribute it and/or modify it |
---|
8 | | - * under the terms of the GNU General Public License as published by the |
---|
9 | | - * Free Software Foundation; version 2 of the License. |
---|
10 | 7 | */ |
---|
11 | 8 | |
---|
12 | 9 | #include <linux/bpf.h> |
---|
.. | .. |
---|
755 | 752 | |
---|
756 | 753 | /* ALU operation */ |
---|
757 | 754 | emit_alu_r(rd[1], rs, true, false, op, ctx); |
---|
758 | | - emit_a32_mov_i(rd[0], 0, ctx); |
---|
| 755 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 756 | + emit_a32_mov_i(rd[0], 0, ctx); |
---|
759 | 757 | } |
---|
760 | 758 | |
---|
761 | 759 | arm_bpf_put_reg64(dst, rd, ctx); |
---|
.. | .. |
---|
777 | 775 | struct jit_ctx *ctx) { |
---|
778 | 776 | if (!is64) { |
---|
779 | 777 | emit_a32_mov_r(dst_lo, src_lo, ctx); |
---|
780 | | - /* Zero out high 4 bytes */ |
---|
781 | | - emit_a32_mov_i(dst_hi, 0, ctx); |
---|
| 778 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 779 | + /* Zero out high 4 bytes */ |
---|
| 780 | + emit_a32_mov_i(dst_hi, 0, ctx); |
---|
782 | 781 | } else if (__LINUX_ARM_ARCH__ < 6 && |
---|
783 | 782 | ctx->cpu_architecture < CPU_ARCH_ARMv5TE) { |
---|
784 | 783 | /* complete 8 byte move */ |
---|
.. | .. |
---|
814 | 813 | break; |
---|
815 | 814 | case BPF_RSH: |
---|
816 | 815 | emit(ARM_LSR_I(rd, rd, val), ctx); |
---|
| 816 | + break; |
---|
| 817 | + case BPF_ARSH: |
---|
| 818 | + emit(ARM_ASR_I(rd, rd, val), ctx); |
---|
817 | 819 | break; |
---|
818 | 820 | case BPF_NEG: |
---|
819 | 821 | emit(ARM_RSB_I(rd, rd, val), ctx); |
---|
.. | .. |
---|
880 | 882 | emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); |
---|
881 | 883 | emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_LSR, rt), ctx); |
---|
882 | 884 | emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASL, ARM_IP), ctx); |
---|
883 | | - _emit(ARM_COND_MI, ARM_B(0), ctx); |
---|
884 | | - emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASR, tmp2[0]), ctx); |
---|
| 885 | + _emit(ARM_COND_PL, |
---|
| 886 | + ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASR, tmp2[0]), ctx); |
---|
885 | 887 | emit(ARM_MOV_SR(ARM_IP, rd[0], SRTYPE_ASR, rt), ctx); |
---|
886 | 888 | |
---|
887 | 889 | arm_bpf_put_reg32(dst_lo, ARM_LR, ctx); |
---|
.. | .. |
---|
1095 | 1097 | case BPF_B: |
---|
1096 | 1098 | /* Load a Byte */ |
---|
1097 | 1099 | emit(ARM_LDRB_I(rd[1], rm, off), ctx); |
---|
1098 | | - emit_a32_mov_i(rd[0], 0, ctx); |
---|
| 1100 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1101 | + emit_a32_mov_i(rd[0], 0, ctx); |
---|
1099 | 1102 | break; |
---|
1100 | 1103 | case BPF_H: |
---|
1101 | 1104 | /* Load a HalfWord */ |
---|
1102 | 1105 | emit(ARM_LDRH_I(rd[1], rm, off), ctx); |
---|
1103 | | - emit_a32_mov_i(rd[0], 0, ctx); |
---|
| 1106 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1107 | + emit_a32_mov_i(rd[0], 0, ctx); |
---|
1104 | 1108 | break; |
---|
1105 | 1109 | case BPF_W: |
---|
1106 | 1110 | /* Load a Word */ |
---|
1107 | 1111 | emit(ARM_LDR_I(rd[1], rm, off), ctx); |
---|
1108 | | - emit_a32_mov_i(rd[0], 0, ctx); |
---|
| 1112 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1113 | + emit_a32_mov_i(rd[0], 0, ctx); |
---|
1109 | 1114 | break; |
---|
1110 | 1115 | case BPF_DW: |
---|
1111 | 1116 | /* Load a Double Word */ |
---|
.. | .. |
---|
1118 | 1123 | |
---|
1119 | 1124 | /* Arithmatic Operation */ |
---|
1120 | 1125 | static inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm, |
---|
1121 | | - const u8 rn, struct jit_ctx *ctx, u8 op) { |
---|
| 1126 | + const u8 rn, struct jit_ctx *ctx, u8 op, |
---|
| 1127 | + bool is_jmp64) { |
---|
1122 | 1128 | switch (op) { |
---|
1123 | 1129 | case BPF_JSET: |
---|
1124 | | - emit(ARM_AND_R(ARM_IP, rt, rn), ctx); |
---|
1125 | | - emit(ARM_AND_R(ARM_LR, rd, rm), ctx); |
---|
1126 | | - emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); |
---|
| 1130 | + if (is_jmp64) { |
---|
| 1131 | + emit(ARM_AND_R(ARM_IP, rt, rn), ctx); |
---|
| 1132 | + emit(ARM_AND_R(ARM_LR, rd, rm), ctx); |
---|
| 1133 | + emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); |
---|
| 1134 | + } else { |
---|
| 1135 | + emit(ARM_ANDS_R(ARM_IP, rt, rn), ctx); |
---|
| 1136 | + } |
---|
1127 | 1137 | break; |
---|
1128 | 1138 | case BPF_JEQ: |
---|
1129 | 1139 | case BPF_JNE: |
---|
.. | .. |
---|
1131 | 1141 | case BPF_JGE: |
---|
1132 | 1142 | case BPF_JLE: |
---|
1133 | 1143 | case BPF_JLT: |
---|
1134 | | - emit(ARM_CMP_R(rd, rm), ctx); |
---|
1135 | | - _emit(ARM_COND_EQ, ARM_CMP_R(rt, rn), ctx); |
---|
| 1144 | + if (is_jmp64) { |
---|
| 1145 | + emit(ARM_CMP_R(rd, rm), ctx); |
---|
| 1146 | + /* Only compare low halve if high halve are equal. */ |
---|
| 1147 | + _emit(ARM_COND_EQ, ARM_CMP_R(rt, rn), ctx); |
---|
| 1148 | + } else { |
---|
| 1149 | + emit(ARM_CMP_R(rt, rn), ctx); |
---|
| 1150 | + } |
---|
1136 | 1151 | break; |
---|
1137 | 1152 | case BPF_JSLE: |
---|
1138 | 1153 | case BPF_JSGT: |
---|
1139 | 1154 | emit(ARM_CMP_R(rn, rt), ctx); |
---|
1140 | | - emit(ARM_SBCS_R(ARM_IP, rm, rd), ctx); |
---|
| 1155 | + if (is_jmp64) |
---|
| 1156 | + emit(ARM_SBCS_R(ARM_IP, rm, rd), ctx); |
---|
1141 | 1157 | break; |
---|
1142 | 1158 | case BPF_JSLT: |
---|
1143 | 1159 | case BPF_JSGE: |
---|
1144 | 1160 | emit(ARM_CMP_R(rt, rn), ctx); |
---|
1145 | | - emit(ARM_SBCS_R(ARM_IP, rd, rm), ctx); |
---|
| 1161 | + if (is_jmp64) |
---|
| 1162 | + emit(ARM_SBCS_R(ARM_IP, rd, rm), ctx); |
---|
1146 | 1163 | break; |
---|
1147 | 1164 | } |
---|
1148 | 1165 | } |
---|
.. | .. |
---|
1281 | 1298 | |
---|
1282 | 1299 | static void build_prologue(struct jit_ctx *ctx) |
---|
1283 | 1300 | { |
---|
1284 | | - const s8 r0 = bpf2a32[BPF_REG_0][1]; |
---|
1285 | | - const s8 r2 = bpf2a32[BPF_REG_1][1]; |
---|
1286 | | - const s8 r3 = bpf2a32[BPF_REG_1][0]; |
---|
1287 | | - const s8 r4 = bpf2a32[BPF_REG_6][1]; |
---|
1288 | | - const s8 fplo = bpf2a32[BPF_REG_FP][1]; |
---|
1289 | | - const s8 fphi = bpf2a32[BPF_REG_FP][0]; |
---|
| 1301 | + const s8 arm_r0 = bpf2a32[BPF_REG_0][1]; |
---|
| 1302 | + const s8 *bpf_r1 = bpf2a32[BPF_REG_1]; |
---|
| 1303 | + const s8 *bpf_fp = bpf2a32[BPF_REG_FP]; |
---|
1290 | 1304 | const s8 *tcc = bpf2a32[TCALL_CNT]; |
---|
1291 | 1305 | |
---|
1292 | 1306 | /* Save callee saved registers. */ |
---|
.. | .. |
---|
1299 | 1313 | emit(ARM_PUSH(CALLEE_PUSH_MASK), ctx); |
---|
1300 | 1314 | emit(ARM_MOV_R(ARM_FP, ARM_SP), ctx); |
---|
1301 | 1315 | #endif |
---|
1302 | | - /* Save frame pointer for later */ |
---|
1303 | | - emit(ARM_SUB_I(ARM_IP, ARM_SP, SCRATCH_SIZE), ctx); |
---|
| 1316 | + /* mov r3, #0 */ |
---|
| 1317 | + /* sub r2, sp, #SCRATCH_SIZE */ |
---|
| 1318 | + emit(ARM_MOV_I(bpf_r1[0], 0), ctx); |
---|
| 1319 | + emit(ARM_SUB_I(bpf_r1[1], ARM_SP, SCRATCH_SIZE), ctx); |
---|
1304 | 1320 | |
---|
1305 | 1321 | ctx->stack_size = imm8m(STACK_SIZE); |
---|
1306 | 1322 | |
---|
.. | .. |
---|
1308 | 1324 | emit(ARM_SUB_I(ARM_SP, ARM_SP, ctx->stack_size), ctx); |
---|
1309 | 1325 | |
---|
1310 | 1326 | /* Set up BPF prog stack base register */ |
---|
1311 | | - emit_a32_mov_r(fplo, ARM_IP, ctx); |
---|
1312 | | - emit_a32_mov_i(fphi, 0, ctx); |
---|
| 1327 | + emit_a32_mov_r64(true, bpf_fp, bpf_r1, ctx); |
---|
1313 | 1328 | |
---|
1314 | | - /* mov r4, 0 */ |
---|
1315 | | - emit(ARM_MOV_I(r4, 0), ctx); |
---|
| 1329 | + /* Initialize Tail Count */ |
---|
| 1330 | + emit(ARM_MOV_I(bpf_r1[1], 0), ctx); |
---|
| 1331 | + emit_a32_mov_r64(true, tcc, bpf_r1, ctx); |
---|
1316 | 1332 | |
---|
1317 | 1333 | /* Move BPF_CTX to BPF_R1 */ |
---|
1318 | | - emit(ARM_MOV_R(r3, r4), ctx); |
---|
1319 | | - emit(ARM_MOV_R(r2, r0), ctx); |
---|
1320 | | - /* Initialize Tail Count */ |
---|
1321 | | - emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[0])), ctx); |
---|
1322 | | - emit(ARM_STR_I(r4, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(tcc[1])), ctx); |
---|
| 1334 | + emit(ARM_MOV_R(bpf_r1[1], arm_r0), ctx); |
---|
| 1335 | + |
---|
1323 | 1336 | /* end of prologue */ |
---|
1324 | 1337 | } |
---|
1325 | 1338 | |
---|
.. | .. |
---|
1382 | 1395 | case BPF_ALU64 | BPF_MOV | BPF_X: |
---|
1383 | 1396 | switch (BPF_SRC(code)) { |
---|
1384 | 1397 | case BPF_X: |
---|
| 1398 | + if (imm == 1) { |
---|
| 1399 | + /* Special mov32 for zext */ |
---|
| 1400 | + emit_a32_mov_i(dst_hi, 0, ctx); |
---|
| 1401 | + break; |
---|
| 1402 | + } |
---|
1385 | 1403 | emit_a32_mov_r64(is64, dst, src, ctx); |
---|
1386 | 1404 | break; |
---|
1387 | 1405 | case BPF_K: |
---|
.. | .. |
---|
1412 | 1430 | case BPF_ALU | BPF_MUL | BPF_X: |
---|
1413 | 1431 | case BPF_ALU | BPF_LSH | BPF_X: |
---|
1414 | 1432 | case BPF_ALU | BPF_RSH | BPF_X: |
---|
1415 | | - case BPF_ALU | BPF_ARSH | BPF_K: |
---|
1416 | 1433 | case BPF_ALU | BPF_ARSH | BPF_X: |
---|
1417 | 1434 | case BPF_ALU64 | BPF_ADD | BPF_K: |
---|
1418 | 1435 | case BPF_ALU64 | BPF_ADD | BPF_X: |
---|
.. | .. |
---|
1461 | 1478 | } |
---|
1462 | 1479 | emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code)); |
---|
1463 | 1480 | arm_bpf_put_reg32(dst_lo, rd_lo, ctx); |
---|
1464 | | - emit_a32_mov_i(dst_hi, 0, ctx); |
---|
| 1481 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1482 | + emit_a32_mov_i(dst_hi, 0, ctx); |
---|
1465 | 1483 | break; |
---|
1466 | 1484 | case BPF_ALU64 | BPF_DIV | BPF_K: |
---|
1467 | 1485 | case BPF_ALU64 | BPF_DIV | BPF_X: |
---|
1468 | 1486 | case BPF_ALU64 | BPF_MOD | BPF_K: |
---|
1469 | 1487 | case BPF_ALU64 | BPF_MOD | BPF_X: |
---|
1470 | 1488 | goto notyet; |
---|
1471 | | - /* dst = dst >> imm */ |
---|
1472 | 1489 | /* dst = dst << imm */ |
---|
1473 | | - case BPF_ALU | BPF_RSH | BPF_K: |
---|
| 1490 | + /* dst = dst >> imm */ |
---|
| 1491 | + /* dst = dst >> imm (signed) */ |
---|
1474 | 1492 | case BPF_ALU | BPF_LSH | BPF_K: |
---|
| 1493 | + case BPF_ALU | BPF_RSH | BPF_K: |
---|
| 1494 | + case BPF_ALU | BPF_ARSH | BPF_K: |
---|
1475 | 1495 | if (unlikely(imm > 31)) |
---|
1476 | 1496 | return -EINVAL; |
---|
1477 | 1497 | if (imm) |
---|
1478 | 1498 | emit_a32_alu_i(dst_lo, imm, ctx, BPF_OP(code)); |
---|
1479 | | - emit_a32_mov_i(dst_hi, 0, ctx); |
---|
| 1499 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1500 | + emit_a32_mov_i(dst_hi, 0, ctx); |
---|
1480 | 1501 | break; |
---|
1481 | 1502 | /* dst = dst << imm */ |
---|
1482 | 1503 | case BPF_ALU64 | BPF_LSH | BPF_K: |
---|
.. | .. |
---|
1511 | 1532 | /* dst = ~dst */ |
---|
1512 | 1533 | case BPF_ALU | BPF_NEG: |
---|
1513 | 1534 | emit_a32_alu_i(dst_lo, 0, ctx, BPF_OP(code)); |
---|
1514 | | - emit_a32_mov_i(dst_hi, 0, ctx); |
---|
| 1535 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1536 | + emit_a32_mov_i(dst_hi, 0, ctx); |
---|
1515 | 1537 | break; |
---|
1516 | 1538 | /* dst = ~dst (64 bit) */ |
---|
1517 | 1539 | case BPF_ALU64 | BPF_NEG: |
---|
.. | .. |
---|
1567 | 1589 | #else /* ARMv6+ */ |
---|
1568 | 1590 | emit(ARM_UXTH(rd[1], rd[1]), ctx); |
---|
1569 | 1591 | #endif |
---|
1570 | | - emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); |
---|
| 1592 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1593 | + emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); |
---|
1571 | 1594 | break; |
---|
1572 | 1595 | case 32: |
---|
1573 | 1596 | /* zero-extend 32 bits into 64 bits */ |
---|
1574 | | - emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); |
---|
| 1597 | + if (!ctx->prog->aux->verifier_zext) |
---|
| 1598 | + emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); |
---|
1575 | 1599 | break; |
---|
1576 | 1600 | case 64: |
---|
1577 | 1601 | /* nop */ |
---|
.. | .. |
---|
1653 | 1677 | case BPF_JMP | BPF_JLT | BPF_X: |
---|
1654 | 1678 | case BPF_JMP | BPF_JSLT | BPF_X: |
---|
1655 | 1679 | case BPF_JMP | BPF_JSLE | BPF_X: |
---|
| 1680 | + case BPF_JMP32 | BPF_JEQ | BPF_X: |
---|
| 1681 | + case BPF_JMP32 | BPF_JGT | BPF_X: |
---|
| 1682 | + case BPF_JMP32 | BPF_JGE | BPF_X: |
---|
| 1683 | + case BPF_JMP32 | BPF_JNE | BPF_X: |
---|
| 1684 | + case BPF_JMP32 | BPF_JSGT | BPF_X: |
---|
| 1685 | + case BPF_JMP32 | BPF_JSGE | BPF_X: |
---|
| 1686 | + case BPF_JMP32 | BPF_JSET | BPF_X: |
---|
| 1687 | + case BPF_JMP32 | BPF_JLE | BPF_X: |
---|
| 1688 | + case BPF_JMP32 | BPF_JLT | BPF_X: |
---|
| 1689 | + case BPF_JMP32 | BPF_JSLT | BPF_X: |
---|
| 1690 | + case BPF_JMP32 | BPF_JSLE | BPF_X: |
---|
1656 | 1691 | /* Setup source registers */ |
---|
1657 | 1692 | rm = arm_bpf_get_reg32(src_hi, tmp2[0], ctx); |
---|
1658 | 1693 | rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); |
---|
.. | .. |
---|
1679 | 1714 | case BPF_JMP | BPF_JLE | BPF_K: |
---|
1680 | 1715 | case BPF_JMP | BPF_JSLT | BPF_K: |
---|
1681 | 1716 | case BPF_JMP | BPF_JSLE | BPF_K: |
---|
| 1717 | + case BPF_JMP32 | BPF_JEQ | BPF_K: |
---|
| 1718 | + case BPF_JMP32 | BPF_JGT | BPF_K: |
---|
| 1719 | + case BPF_JMP32 | BPF_JGE | BPF_K: |
---|
| 1720 | + case BPF_JMP32 | BPF_JNE | BPF_K: |
---|
| 1721 | + case BPF_JMP32 | BPF_JSGT | BPF_K: |
---|
| 1722 | + case BPF_JMP32 | BPF_JSGE | BPF_K: |
---|
| 1723 | + case BPF_JMP32 | BPF_JSET | BPF_K: |
---|
| 1724 | + case BPF_JMP32 | BPF_JLT | BPF_K: |
---|
| 1725 | + case BPF_JMP32 | BPF_JLE | BPF_K: |
---|
| 1726 | + case BPF_JMP32 | BPF_JSLT | BPF_K: |
---|
| 1727 | + case BPF_JMP32 | BPF_JSLE | BPF_K: |
---|
1682 | 1728 | if (off == 0) |
---|
1683 | 1729 | break; |
---|
1684 | 1730 | rm = tmp2[0]; |
---|
.. | .. |
---|
1690 | 1736 | rd = arm_bpf_get_reg64(dst, tmp, ctx); |
---|
1691 | 1737 | |
---|
1692 | 1738 | /* Check for the condition */ |
---|
1693 | | - emit_ar_r(rd[0], rd[1], rm, rn, ctx, BPF_OP(code)); |
---|
| 1739 | + emit_ar_r(rd[0], rd[1], rm, rn, ctx, BPF_OP(code), |
---|
| 1740 | + BPF_CLASS(code) == BPF_JMP); |
---|
1694 | 1741 | |
---|
1695 | 1742 | /* Setup JUMP instruction */ |
---|
1696 | 1743 | jmp_offset = bpf2a32_offset(i+off, i, ctx); |
---|
.. | .. |
---|
1841 | 1888 | /* Nothing to do here. We support Internal BPF. */ |
---|
1842 | 1889 | } |
---|
1843 | 1890 | |
---|
| 1891 | +bool bpf_jit_needs_zext(void) |
---|
| 1892 | +{ |
---|
| 1893 | + return true; |
---|
| 1894 | +} |
---|
| 1895 | + |
---|
1844 | 1896 | struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) |
---|
1845 | 1897 | { |
---|
1846 | 1898 | struct bpf_prog *tmp, *orig_prog = prog; |
---|