| .. | .. |
|---|
| 1 | +// SPDX-License-Identifier: GPL-2.0-only |
|---|
| 1 | 2 | /* |
|---|
| 2 | 3 | * Just-In-Time compiler for eBPF filters on MIPS |
|---|
| 3 | 4 | * |
|---|
| .. | .. |
|---|
| 7 | 8 | * |
|---|
| 8 | 9 | * Copyright (c) 2014 Imagination Technologies Ltd. |
|---|
| 9 | 10 | * Author: Markos Chandras <markos.chandras@imgtec.com> |
|---|
| 10 | | - * |
|---|
| 11 | | - * This program is free software; you can redistribute it and/or modify it |
|---|
| 12 | | - * under the terms of the GNU General Public License as published by the |
|---|
| 13 | | - * Free Software Foundation; version 2 of the License. |
|---|
| 14 | 11 | */ |
|---|
| 15 | 12 | |
|---|
| 16 | 13 | #include <linux/bitops.h> |
|---|
| .. | .. |
|---|
| 22 | 19 | #include <asm/byteorder.h> |
|---|
| 23 | 20 | #include <asm/cacheflush.h> |
|---|
| 24 | 21 | #include <asm/cpu-features.h> |
|---|
| 22 | +#include <asm/isa-rev.h> |
|---|
| 25 | 23 | #include <asm/uasm.h> |
|---|
| 26 | 24 | |
|---|
| 27 | 25 | /* Registers used by JIT */ |
|---|
| .. | .. |
|---|
| 79 | 77 | REG_64BIT_32BIT, |
|---|
| 80 | 78 | /* 32-bit compatible, need truncation for 64-bit ops. */ |
|---|
| 81 | 79 | REG_32BIT, |
|---|
| 82 | | - /* 32-bit zero extended. */ |
|---|
| 83 | | - REG_32BIT_ZERO_EX, |
|---|
| 84 | 80 | /* 32-bit no sign/zero extension needed. */ |
|---|
| 85 | 81 | REG_32BIT_POS |
|---|
| 86 | 82 | }; |
|---|
| .. | .. |
|---|
| 127 | 123 | } |
|---|
| 128 | 124 | |
|---|
| 129 | 125 | /* Simply emit the instruction if the JIT memory space has been allocated */ |
|---|
| 130 | | -#define emit_instr(ctx, func, ...) \ |
|---|
| 131 | | -do { \ |
|---|
| 132 | | - if ((ctx)->target != NULL) { \ |
|---|
| 133 | | - u32 *p = &(ctx)->target[ctx->idx]; \ |
|---|
| 134 | | - uasm_i_##func(&p, ##__VA_ARGS__); \ |
|---|
| 135 | | - } \ |
|---|
| 136 | | - (ctx)->idx++; \ |
|---|
| 126 | +#define emit_instr_long(ctx, func64, func32, ...) \ |
|---|
| 127 | +do { \ |
|---|
| 128 | + if ((ctx)->target != NULL) { \ |
|---|
| 129 | + u32 *p = &(ctx)->target[ctx->idx]; \ |
|---|
| 130 | + if (IS_ENABLED(CONFIG_64BIT)) \ |
|---|
| 131 | + uasm_i_##func64(&p, ##__VA_ARGS__); \ |
|---|
| 132 | + else \ |
|---|
| 133 | + uasm_i_##func32(&p, ##__VA_ARGS__); \ |
|---|
| 134 | + } \ |
|---|
| 135 | + (ctx)->idx++; \ |
|---|
| 137 | 136 | } while (0) |
|---|
| 137 | + |
|---|
| 138 | +#define emit_instr(ctx, func, ...) \ |
|---|
| 139 | + emit_instr_long(ctx, func, func, ##__VA_ARGS__) |
|---|
| 138 | 140 | |
|---|
| 139 | 141 | static unsigned int j_target(struct jit_ctx *ctx, int target_idx) |
|---|
| 140 | 142 | { |
|---|
| .. | .. |
|---|
| 188 | 190 | * separate frame pointer, so BPF_REG_10 relative accesses are |
|---|
| 189 | 191 | * adjusted to be $sp relative. |
|---|
| 190 | 192 | */ |
|---|
| 191 | | -int ebpf_to_mips_reg(struct jit_ctx *ctx, const struct bpf_insn *insn, |
|---|
| 192 | | - enum which_ebpf_reg w) |
|---|
| 193 | +static int ebpf_to_mips_reg(struct jit_ctx *ctx, |
|---|
| 194 | + const struct bpf_insn *insn, |
|---|
| 195 | + enum which_ebpf_reg w) |
|---|
| 193 | 196 | { |
|---|
| 194 | 197 | int ebpf_reg = (w == src_reg || w == src_reg_no_fp) ? |
|---|
| 195 | 198 | insn->src_reg : insn->dst_reg; |
|---|
| .. | .. |
|---|
| 275 | 278 | * If RA we are doing a function call and may need |
|---|
| 276 | 279 | * extra 8-byte tmp area. |
|---|
| 277 | 280 | */ |
|---|
| 278 | | - stack_adjust += 16; |
|---|
| 281 | + stack_adjust += 2 * sizeof(long); |
|---|
| 279 | 282 | if (ctx->flags & EBPF_SAVE_S0) |
|---|
| 280 | | - stack_adjust += 8; |
|---|
| 283 | + stack_adjust += sizeof(long); |
|---|
| 281 | 284 | if (ctx->flags & EBPF_SAVE_S1) |
|---|
| 282 | | - stack_adjust += 8; |
|---|
| 285 | + stack_adjust += sizeof(long); |
|---|
| 283 | 286 | if (ctx->flags & EBPF_SAVE_S2) |
|---|
| 284 | | - stack_adjust += 8; |
|---|
| 287 | + stack_adjust += sizeof(long); |
|---|
| 285 | 288 | if (ctx->flags & EBPF_SAVE_S3) |
|---|
| 286 | | - stack_adjust += 8; |
|---|
| 289 | + stack_adjust += sizeof(long); |
|---|
| 287 | 290 | if (ctx->flags & EBPF_SAVE_S4) |
|---|
| 288 | | - stack_adjust += 8; |
|---|
| 291 | + stack_adjust += sizeof(long); |
|---|
| 289 | 292 | |
|---|
| 290 | 293 | BUILD_BUG_ON(MAX_BPF_STACK & 7); |
|---|
| 291 | 294 | locals_size = (ctx->flags & EBPF_SEEN_FP) ? MAX_BPF_STACK : 0; |
|---|
| .. | .. |
|---|
| 299 | 302 | * On tail call we skip this instruction, and the TCC is |
|---|
| 300 | 303 | * passed in $v1 from the caller. |
|---|
| 301 | 304 | */ |
|---|
| 302 | | - emit_instr(ctx, daddiu, MIPS_R_V1, MIPS_R_ZERO, MAX_TAIL_CALL_CNT); |
|---|
| 305 | + emit_instr(ctx, addiu, MIPS_R_V1, MIPS_R_ZERO, MAX_TAIL_CALL_CNT); |
|---|
| 303 | 306 | if (stack_adjust) |
|---|
| 304 | | - emit_instr(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, -stack_adjust); |
|---|
| 307 | + emit_instr_long(ctx, daddiu, addiu, |
|---|
| 308 | + MIPS_R_SP, MIPS_R_SP, -stack_adjust); |
|---|
| 305 | 309 | else |
|---|
| 306 | 310 | return 0; |
|---|
| 307 | 311 | |
|---|
| 308 | | - store_offset = stack_adjust - 8; |
|---|
| 312 | + store_offset = stack_adjust - sizeof(long); |
|---|
| 309 | 313 | |
|---|
| 310 | 314 | if (ctx->flags & EBPF_SAVE_RA) { |
|---|
| 311 | | - emit_instr(ctx, sd, MIPS_R_RA, store_offset, MIPS_R_SP); |
|---|
| 312 | | - store_offset -= 8; |
|---|
| 315 | + emit_instr_long(ctx, sd, sw, |
|---|
| 316 | + MIPS_R_RA, store_offset, MIPS_R_SP); |
|---|
| 317 | + store_offset -= sizeof(long); |
|---|
| 313 | 318 | } |
|---|
| 314 | 319 | if (ctx->flags & EBPF_SAVE_S0) { |
|---|
| 315 | | - emit_instr(ctx, sd, MIPS_R_S0, store_offset, MIPS_R_SP); |
|---|
| 316 | | - store_offset -= 8; |
|---|
| 320 | + emit_instr_long(ctx, sd, sw, |
|---|
| 321 | + MIPS_R_S0, store_offset, MIPS_R_SP); |
|---|
| 322 | + store_offset -= sizeof(long); |
|---|
| 317 | 323 | } |
|---|
| 318 | 324 | if (ctx->flags & EBPF_SAVE_S1) { |
|---|
| 319 | | - emit_instr(ctx, sd, MIPS_R_S1, store_offset, MIPS_R_SP); |
|---|
| 320 | | - store_offset -= 8; |
|---|
| 325 | + emit_instr_long(ctx, sd, sw, |
|---|
| 326 | + MIPS_R_S1, store_offset, MIPS_R_SP); |
|---|
| 327 | + store_offset -= sizeof(long); |
|---|
| 321 | 328 | } |
|---|
| 322 | 329 | if (ctx->flags & EBPF_SAVE_S2) { |
|---|
| 323 | | - emit_instr(ctx, sd, MIPS_R_S2, store_offset, MIPS_R_SP); |
|---|
| 324 | | - store_offset -= 8; |
|---|
| 330 | + emit_instr_long(ctx, sd, sw, |
|---|
| 331 | + MIPS_R_S2, store_offset, MIPS_R_SP); |
|---|
| 332 | + store_offset -= sizeof(long); |
|---|
| 325 | 333 | } |
|---|
| 326 | 334 | if (ctx->flags & EBPF_SAVE_S3) { |
|---|
| 327 | | - emit_instr(ctx, sd, MIPS_R_S3, store_offset, MIPS_R_SP); |
|---|
| 328 | | - store_offset -= 8; |
|---|
| 335 | + emit_instr_long(ctx, sd, sw, |
|---|
| 336 | + MIPS_R_S3, store_offset, MIPS_R_SP); |
|---|
| 337 | + store_offset -= sizeof(long); |
|---|
| 329 | 338 | } |
|---|
| 330 | 339 | if (ctx->flags & EBPF_SAVE_S4) { |
|---|
| 331 | | - emit_instr(ctx, sd, MIPS_R_S4, store_offset, MIPS_R_SP); |
|---|
| 332 | | - store_offset -= 8; |
|---|
| 340 | + emit_instr_long(ctx, sd, sw, |
|---|
| 341 | + MIPS_R_S4, store_offset, MIPS_R_SP); |
|---|
| 342 | + store_offset -= sizeof(long); |
|---|
| 333 | 343 | } |
|---|
| 334 | 344 | |
|---|
| 335 | 345 | if ((ctx->flags & EBPF_SEEN_TC) && !(ctx->flags & EBPF_TCC_IN_V1)) |
|---|
| 336 | | - emit_instr(ctx, daddu, MIPS_R_S4, MIPS_R_V1, MIPS_R_ZERO); |
|---|
| 346 | + emit_instr_long(ctx, daddu, addu, |
|---|
| 347 | + MIPS_R_S4, MIPS_R_V1, MIPS_R_ZERO); |
|---|
| 337 | 348 | |
|---|
| 338 | 349 | return 0; |
|---|
| 339 | 350 | } |
|---|
| .. | .. |
|---|
| 342 | 353 | { |
|---|
| 343 | 354 | const struct bpf_prog *prog = ctx->skf; |
|---|
| 344 | 355 | int stack_adjust = ctx->stack_size; |
|---|
| 345 | | - int store_offset = stack_adjust - 8; |
|---|
| 356 | + int store_offset = stack_adjust - sizeof(long); |
|---|
| 346 | 357 | enum reg_val_type td; |
|---|
| 347 | 358 | int r0 = MIPS_R_V0; |
|---|
| 348 | 359 | |
|---|
| 349 | 360 | if (dest_reg == MIPS_R_RA) { |
|---|
| 350 | 361 | /* Don't let zero extended value escape. */ |
|---|
| 351 | 362 | td = get_reg_val_type(ctx, prog->len, BPF_REG_0); |
|---|
| 352 | | - if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) |
|---|
| 363 | + if (td == REG_64BIT) |
|---|
| 353 | 364 | emit_instr(ctx, sll, r0, r0, 0); |
|---|
| 354 | 365 | } |
|---|
| 355 | 366 | |
|---|
| 356 | 367 | if (ctx->flags & EBPF_SAVE_RA) { |
|---|
| 357 | | - emit_instr(ctx, ld, MIPS_R_RA, store_offset, MIPS_R_SP); |
|---|
| 358 | | - store_offset -= 8; |
|---|
| 368 | + emit_instr_long(ctx, ld, lw, |
|---|
| 369 | + MIPS_R_RA, store_offset, MIPS_R_SP); |
|---|
| 370 | + store_offset -= sizeof(long); |
|---|
| 359 | 371 | } |
|---|
| 360 | 372 | if (ctx->flags & EBPF_SAVE_S0) { |
|---|
| 361 | | - emit_instr(ctx, ld, MIPS_R_S0, store_offset, MIPS_R_SP); |
|---|
| 362 | | - store_offset -= 8; |
|---|
| 373 | + emit_instr_long(ctx, ld, lw, |
|---|
| 374 | + MIPS_R_S0, store_offset, MIPS_R_SP); |
|---|
| 375 | + store_offset -= sizeof(long); |
|---|
| 363 | 376 | } |
|---|
| 364 | 377 | if (ctx->flags & EBPF_SAVE_S1) { |
|---|
| 365 | | - emit_instr(ctx, ld, MIPS_R_S1, store_offset, MIPS_R_SP); |
|---|
| 366 | | - store_offset -= 8; |
|---|
| 378 | + emit_instr_long(ctx, ld, lw, |
|---|
| 379 | + MIPS_R_S1, store_offset, MIPS_R_SP); |
|---|
| 380 | + store_offset -= sizeof(long); |
|---|
| 367 | 381 | } |
|---|
| 368 | 382 | if (ctx->flags & EBPF_SAVE_S2) { |
|---|
| 369 | | - emit_instr(ctx, ld, MIPS_R_S2, store_offset, MIPS_R_SP); |
|---|
| 370 | | - store_offset -= 8; |
|---|
| 383 | + emit_instr_long(ctx, ld, lw, |
|---|
| 384 | + MIPS_R_S2, store_offset, MIPS_R_SP); |
|---|
| 385 | + store_offset -= sizeof(long); |
|---|
| 371 | 386 | } |
|---|
| 372 | 387 | if (ctx->flags & EBPF_SAVE_S3) { |
|---|
| 373 | | - emit_instr(ctx, ld, MIPS_R_S3, store_offset, MIPS_R_SP); |
|---|
| 374 | | - store_offset -= 8; |
|---|
| 388 | + emit_instr_long(ctx, ld, lw, |
|---|
| 389 | + MIPS_R_S3, store_offset, MIPS_R_SP); |
|---|
| 390 | + store_offset -= sizeof(long); |
|---|
| 375 | 391 | } |
|---|
| 376 | 392 | if (ctx->flags & EBPF_SAVE_S4) { |
|---|
| 377 | | - emit_instr(ctx, ld, MIPS_R_S4, store_offset, MIPS_R_SP); |
|---|
| 378 | | - store_offset -= 8; |
|---|
| 393 | + emit_instr_long(ctx, ld, lw, |
|---|
| 394 | + MIPS_R_S4, store_offset, MIPS_R_SP); |
|---|
| 395 | + store_offset -= sizeof(long); |
|---|
| 379 | 396 | } |
|---|
| 380 | 397 | emit_instr(ctx, jr, dest_reg); |
|---|
| 381 | 398 | |
|---|
| 382 | 399 | if (stack_adjust) |
|---|
| 383 | | - emit_instr(ctx, daddiu, MIPS_R_SP, MIPS_R_SP, stack_adjust); |
|---|
| 400 | + emit_instr_long(ctx, daddiu, addiu, |
|---|
| 401 | + MIPS_R_SP, MIPS_R_SP, stack_adjust); |
|---|
| 384 | 402 | else |
|---|
| 385 | 403 | emit_instr(ctx, nop); |
|---|
| 386 | 404 | |
|---|
| .. | .. |
|---|
| 648 | 666 | s64 t64s; |
|---|
| 649 | 667 | int bpf_op = BPF_OP(insn->code); |
|---|
| 650 | 668 | |
|---|
| 669 | + if (IS_ENABLED(CONFIG_32BIT) && ((BPF_CLASS(insn->code) == BPF_ALU64) |
|---|
| 670 | + || (bpf_op == BPF_DW))) |
|---|
| 671 | + return -EINVAL; |
|---|
| 672 | + |
|---|
| 651 | 673 | switch (insn->code) { |
|---|
| 652 | 674 | case BPF_ALU64 | BPF_ADD | BPF_K: /* ALU64_IMM */ |
|---|
| 653 | 675 | case BPF_ALU64 | BPF_SUB | BPF_K: /* ALU64_IMM */ |
|---|
| .. | .. |
|---|
| 680 | 702 | if (insn->imm == 1) /* Mult by 1 is a nop */ |
|---|
| 681 | 703 | break; |
|---|
| 682 | 704 | gen_imm_to_reg(insn, MIPS_R_AT, ctx); |
|---|
| 683 | | - emit_instr(ctx, dmultu, MIPS_R_AT, dst); |
|---|
| 684 | | - emit_instr(ctx, mflo, dst); |
|---|
| 705 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 706 | + emit_instr(ctx, dmulu, dst, dst, MIPS_R_AT); |
|---|
| 707 | + } else { |
|---|
| 708 | + emit_instr(ctx, dmultu, MIPS_R_AT, dst); |
|---|
| 709 | + emit_instr(ctx, mflo, dst); |
|---|
| 710 | + } |
|---|
| 685 | 711 | break; |
|---|
| 686 | 712 | case BPF_ALU64 | BPF_NEG | BPF_K: /* ALU64_IMM */ |
|---|
| 687 | 713 | dst = ebpf_to_mips_reg(ctx, insn, dst_reg); |
|---|
| .. | .. |
|---|
| 696 | 722 | if (dst < 0) |
|---|
| 697 | 723 | return dst; |
|---|
| 698 | 724 | td = get_reg_val_type(ctx, this_idx, insn->dst_reg); |
|---|
| 699 | | - if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) { |
|---|
| 725 | + if (td == REG_64BIT) { |
|---|
| 700 | 726 | /* sign extend */ |
|---|
| 701 | 727 | emit_instr(ctx, sll, dst, dst, 0); |
|---|
| 702 | 728 | } |
|---|
| 703 | 729 | if (insn->imm == 1) /* Mult by 1 is a nop */ |
|---|
| 704 | 730 | break; |
|---|
| 705 | 731 | gen_imm_to_reg(insn, MIPS_R_AT, ctx); |
|---|
| 706 | | - emit_instr(ctx, multu, dst, MIPS_R_AT); |
|---|
| 707 | | - emit_instr(ctx, mflo, dst); |
|---|
| 732 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 733 | + emit_instr(ctx, mulu, dst, dst, MIPS_R_AT); |
|---|
| 734 | + } else { |
|---|
| 735 | + emit_instr(ctx, multu, dst, MIPS_R_AT); |
|---|
| 736 | + emit_instr(ctx, mflo, dst); |
|---|
| 737 | + } |
|---|
| 708 | 738 | break; |
|---|
| 709 | 739 | case BPF_ALU | BPF_NEG | BPF_K: /* ALU_IMM */ |
|---|
| 710 | 740 | dst = ebpf_to_mips_reg(ctx, insn, dst_reg); |
|---|
| 711 | 741 | if (dst < 0) |
|---|
| 712 | 742 | return dst; |
|---|
| 713 | 743 | td = get_reg_val_type(ctx, this_idx, insn->dst_reg); |
|---|
| 714 | | - if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) { |
|---|
| 744 | + if (td == REG_64BIT) { |
|---|
| 715 | 745 | /* sign extend */ |
|---|
| 716 | 746 | emit_instr(ctx, sll, dst, dst, 0); |
|---|
| 717 | 747 | } |
|---|
| .. | .. |
|---|
| 725 | 755 | if (dst < 0) |
|---|
| 726 | 756 | return dst; |
|---|
| 727 | 757 | td = get_reg_val_type(ctx, this_idx, insn->dst_reg); |
|---|
| 728 | | - if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) |
|---|
| 758 | + if (td == REG_64BIT) |
|---|
| 729 | 759 | /* sign extend */ |
|---|
| 730 | 760 | emit_instr(ctx, sll, dst, dst, 0); |
|---|
| 731 | 761 | if (insn->imm == 1) { |
|---|
| .. | .. |
|---|
| 735 | 765 | break; |
|---|
| 736 | 766 | } |
|---|
| 737 | 767 | gen_imm_to_reg(insn, MIPS_R_AT, ctx); |
|---|
| 768 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 769 | + if (bpf_op == BPF_DIV) |
|---|
| 770 | + emit_instr(ctx, divu_r6, dst, dst, MIPS_R_AT); |
|---|
| 771 | + else |
|---|
| 772 | + emit_instr(ctx, modu, dst, dst, MIPS_R_AT); |
|---|
| 773 | + break; |
|---|
| 774 | + } |
|---|
| 738 | 775 | emit_instr(ctx, divu, dst, MIPS_R_AT); |
|---|
| 739 | 776 | if (bpf_op == BPF_DIV) |
|---|
| 740 | 777 | emit_instr(ctx, mflo, dst); |
|---|
| .. | .. |
|---|
| 757 | 794 | break; |
|---|
| 758 | 795 | } |
|---|
| 759 | 796 | gen_imm_to_reg(insn, MIPS_R_AT, ctx); |
|---|
| 797 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 798 | + if (bpf_op == BPF_DIV) |
|---|
| 799 | + emit_instr(ctx, ddivu_r6, dst, dst, MIPS_R_AT); |
|---|
| 800 | + else |
|---|
| 801 | + emit_instr(ctx, modu, dst, dst, MIPS_R_AT); |
|---|
| 802 | + break; |
|---|
| 803 | + } |
|---|
| 760 | 804 | emit_instr(ctx, ddivu, dst, MIPS_R_AT); |
|---|
| 761 | 805 | if (bpf_op == BPF_DIV) |
|---|
| 762 | 806 | emit_instr(ctx, mflo, dst); |
|---|
| .. | .. |
|---|
| 822 | 866 | emit_instr(ctx, and, dst, dst, src); |
|---|
| 823 | 867 | break; |
|---|
| 824 | 868 | case BPF_MUL: |
|---|
| 825 | | - emit_instr(ctx, dmultu, dst, src); |
|---|
| 826 | | - emit_instr(ctx, mflo, dst); |
|---|
| 869 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 870 | + emit_instr(ctx, dmulu, dst, dst, src); |
|---|
| 871 | + } else { |
|---|
| 872 | + emit_instr(ctx, dmultu, dst, src); |
|---|
| 873 | + emit_instr(ctx, mflo, dst); |
|---|
| 874 | + } |
|---|
| 827 | 875 | break; |
|---|
| 828 | 876 | case BPF_DIV: |
|---|
| 829 | 877 | case BPF_MOD: |
|---|
| 878 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 879 | + if (bpf_op == BPF_DIV) |
|---|
| 880 | + emit_instr(ctx, ddivu_r6, |
|---|
| 881 | + dst, dst, src); |
|---|
| 882 | + else |
|---|
| 883 | + emit_instr(ctx, modu, dst, dst, src); |
|---|
| 884 | + break; |
|---|
| 885 | + } |
|---|
| 830 | 886 | emit_instr(ctx, ddivu, dst, src); |
|---|
| 831 | 887 | if (bpf_op == BPF_DIV) |
|---|
| 832 | 888 | emit_instr(ctx, mflo, dst); |
|---|
| .. | .. |
|---|
| 858 | 914 | case BPF_ALU | BPF_MOD | BPF_X: /* ALU_REG */ |
|---|
| 859 | 915 | case BPF_ALU | BPF_LSH | BPF_X: /* ALU_REG */ |
|---|
| 860 | 916 | case BPF_ALU | BPF_RSH | BPF_X: /* ALU_REG */ |
|---|
| 917 | + case BPF_ALU | BPF_ARSH | BPF_X: /* ALU_REG */ |
|---|
| 861 | 918 | src = ebpf_to_mips_reg(ctx, insn, src_reg_no_fp); |
|---|
| 862 | 919 | dst = ebpf_to_mips_reg(ctx, insn, dst_reg); |
|---|
| 863 | 920 | if (src < 0 || dst < 0) |
|---|
| 864 | 921 | return -EINVAL; |
|---|
| 865 | 922 | td = get_reg_val_type(ctx, this_idx, insn->dst_reg); |
|---|
| 866 | | - if (td == REG_64BIT || td == REG_32BIT_ZERO_EX) { |
|---|
| 923 | + if (td == REG_64BIT) { |
|---|
| 867 | 924 | /* sign extend */ |
|---|
| 868 | 925 | emit_instr(ctx, sll, dst, dst, 0); |
|---|
| 869 | 926 | } |
|---|
| 870 | 927 | did_move = false; |
|---|
| 871 | 928 | ts = get_reg_val_type(ctx, this_idx, insn->src_reg); |
|---|
| 872 | | - if (ts == REG_64BIT || ts == REG_32BIT_ZERO_EX) { |
|---|
| 929 | + if (ts == REG_64BIT) { |
|---|
| 873 | 930 | int tmp_reg = MIPS_R_AT; |
|---|
| 874 | 931 | |
|---|
| 875 | 932 | if (bpf_op == BPF_MOV) { |
|---|
| .. | .. |
|---|
| 905 | 962 | break; |
|---|
| 906 | 963 | case BPF_DIV: |
|---|
| 907 | 964 | case BPF_MOD: |
|---|
| 965 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 966 | + if (bpf_op == BPF_DIV) |
|---|
| 967 | + emit_instr(ctx, divu_r6, dst, dst, src); |
|---|
| 968 | + else |
|---|
| 969 | + emit_instr(ctx, modu, dst, dst, src); |
|---|
| 970 | + break; |
|---|
| 971 | + } |
|---|
| 908 | 972 | emit_instr(ctx, divu, dst, src); |
|---|
| 909 | 973 | if (bpf_op == BPF_DIV) |
|---|
| 910 | 974 | emit_instr(ctx, mflo, dst); |
|---|
| .. | .. |
|---|
| 916 | 980 | break; |
|---|
| 917 | 981 | case BPF_RSH: |
|---|
| 918 | 982 | emit_instr(ctx, srlv, dst, dst, src); |
|---|
| 983 | + break; |
|---|
| 984 | + case BPF_ARSH: |
|---|
| 985 | + emit_instr(ctx, srav, dst, dst, src); |
|---|
| 919 | 986 | break; |
|---|
| 920 | 987 | default: |
|---|
| 921 | 988 | pr_err("ALU_REG NOT HANDLED\n"); |
|---|
| .. | .. |
|---|
| 1005 | 1072 | emit_instr(ctx, dsubu, MIPS_R_T8, dst, src); |
|---|
| 1006 | 1073 | emit_instr(ctx, sltu, MIPS_R_AT, dst, src); |
|---|
| 1007 | 1074 | /* SP known to be non-zero, movz becomes boolean not */ |
|---|
| 1008 | | - emit_instr(ctx, movz, MIPS_R_T9, MIPS_R_SP, MIPS_R_T8); |
|---|
| 1009 | | - emit_instr(ctx, movn, MIPS_R_T9, MIPS_R_ZERO, MIPS_R_T8); |
|---|
| 1075 | + if (MIPS_ISA_REV >= 6) { |
|---|
| 1076 | + emit_instr(ctx, seleqz, MIPS_R_T9, |
|---|
| 1077 | + MIPS_R_SP, MIPS_R_T8); |
|---|
| 1078 | + } else { |
|---|
| 1079 | + emit_instr(ctx, movz, MIPS_R_T9, |
|---|
| 1080 | + MIPS_R_SP, MIPS_R_T8); |
|---|
| 1081 | + emit_instr(ctx, movn, MIPS_R_T9, |
|---|
| 1082 | + MIPS_R_ZERO, MIPS_R_T8); |
|---|
| 1083 | + } |
|---|
| 1010 | 1084 | emit_instr(ctx, or, MIPS_R_AT, MIPS_R_T9, MIPS_R_AT); |
|---|
| 1011 | 1085 | cmp_eq = bpf_op == BPF_JGT; |
|---|
| 1012 | 1086 | dst = MIPS_R_AT; |
|---|
| .. | .. |
|---|
| 1233 | 1307 | |
|---|
| 1234 | 1308 | case BPF_JMP | BPF_CALL: |
|---|
| 1235 | 1309 | ctx->flags |= EBPF_SAVE_RA; |
|---|
| 1236 | | - t64s = (s64)insn->imm + (s64)__bpf_call_base; |
|---|
| 1310 | + t64s = (s64)insn->imm + (long)__bpf_call_base; |
|---|
| 1237 | 1311 | emit_const_to_reg(ctx, MIPS_R_T9, (u64)t64s); |
|---|
| 1238 | 1312 | emit_instr(ctx, jalr, MIPS_R_RA, MIPS_R_T9); |
|---|
| 1239 | 1313 | /* delay slot */ |
|---|
| .. | .. |
|---|
| 1254 | 1328 | if (insn->imm == 64 && td == REG_32BIT) |
|---|
| 1255 | 1329 | emit_instr(ctx, dinsu, dst, MIPS_R_ZERO, 32, 32); |
|---|
| 1256 | 1330 | |
|---|
| 1257 | | - if (insn->imm != 64 && |
|---|
| 1258 | | - (td == REG_64BIT || td == REG_32BIT_ZERO_EX)) { |
|---|
| 1331 | + if (insn->imm != 64 && td == REG_64BIT) { |
|---|
| 1259 | 1332 | /* sign extend */ |
|---|
| 1260 | 1333 | emit_instr(ctx, sll, dst, dst, 0); |
|---|
| 1261 | 1334 | } |
|---|
| .. | .. |
|---|
| 1369 | 1442 | if (src < 0) |
|---|
| 1370 | 1443 | return src; |
|---|
| 1371 | 1444 | if (BPF_MODE(insn->code) == BPF_XADD) { |
|---|
| 1445 | + /* |
|---|
| 1446 | + * If mem_off does not fit within the 9 bit ll/sc |
|---|
| 1447 | + * instruction immediate field, use a temp reg. |
|---|
| 1448 | + */ |
|---|
| 1449 | + if (MIPS_ISA_REV >= 6 && |
|---|
| 1450 | + (mem_off >= BIT(8) || mem_off < -BIT(8))) { |
|---|
| 1451 | + emit_instr(ctx, daddiu, MIPS_R_T6, |
|---|
| 1452 | + dst, mem_off); |
|---|
| 1453 | + mem_off = 0; |
|---|
| 1454 | + dst = MIPS_R_T6; |
|---|
| 1455 | + } |
|---|
| 1372 | 1456 | switch (BPF_SIZE(insn->code)) { |
|---|
| 1373 | 1457 | case BPF_W: |
|---|
| 1374 | 1458 | if (get_reg_val_type(ctx, this_idx, insn->src_reg) == REG_32BIT) { |
|---|
| .. | .. |
|---|
| 1723 | 1807 | unsigned int image_size; |
|---|
| 1724 | 1808 | u8 *image_ptr; |
|---|
| 1725 | 1809 | |
|---|
| 1726 | | - if (!prog->jit_requested || !cpu_has_mips64r2) |
|---|
| 1810 | + if (!prog->jit_requested) |
|---|
| 1727 | 1811 | return prog; |
|---|
| 1728 | 1812 | |
|---|
| 1729 | 1813 | tmp = bpf_jit_blind_constants(prog); |
|---|