aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm/net/bpf_jit_32.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/net/bpf_jit_32.c')
-rw-r--r--arch/arm/net/bpf_jit_32.c42
1 files changed, 39 insertions, 3 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index b5f470ddab6d..4550d247e308 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -54,6 +54,7 @@
54#define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) 54#define SEEN_DATA (1 << (BPF_MEMWORDS + 3))
55 55
56#define FLAG_NEED_X_RESET (1 << 0) 56#define FLAG_NEED_X_RESET (1 << 0)
57#define FLAG_IMM_OVERFLOW (1 << 1)
57 58
58struct jit_ctx { 59struct jit_ctx {
59 const struct bpf_prog *skf; 60 const struct bpf_prog *skf;
@@ -293,6 +294,15 @@ static u16 imm_offset(u32 k, struct jit_ctx *ctx)
293 /* PC in ARM mode == address of the instruction + 8 */ 294 /* PC in ARM mode == address of the instruction + 8 */
294 imm = offset - (8 + ctx->idx * 4); 295 imm = offset - (8 + ctx->idx * 4);
295 296
297 if (imm & ~0xfff) {
298 /*
299 * literal pool is too far, signal it into flags. we
300 * can only detect it on the second pass unfortunately.
301 */
302 ctx->flags |= FLAG_IMM_OVERFLOW;
303 return 0;
304 }
305
296 return imm; 306 return imm;
297} 307}
298 308
@@ -449,10 +459,21 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
449 return; 459 return;
450 } 460 }
451#endif 461#endif
452 if (rm != ARM_R0) 462
453 emit(ARM_MOV_R(ARM_R0, rm), ctx); 463 /*
464 * For BPF_ALU | BPF_DIV | BPF_K instructions, rm is ARM_R4
465 * (r_A) and rn is ARM_R0 (r_scratch) so load rn first into
466 * ARM_R1 to avoid accidentally overwriting ARM_R0 with rm
467 * before using it as a source for ARM_R1.
468 *
469 * For BPF_ALU | BPF_DIV | BPF_X rm is ARM_R4 (r_A) and rn is
470 * ARM_R5 (r_X) so there is no particular register overlap
471 * issues.
472 */
454 if (rn != ARM_R1) 473 if (rn != ARM_R1)
455 emit(ARM_MOV_R(ARM_R1, rn), ctx); 474 emit(ARM_MOV_R(ARM_R1, rn), ctx);
475 if (rm != ARM_R0)
476 emit(ARM_MOV_R(ARM_R0, rm), ctx);
456 477
457 ctx->seen |= SEEN_CALL; 478 ctx->seen |= SEEN_CALL;
458 emit_mov_i(ARM_R3, (u32)jit_udiv, ctx); 479 emit_mov_i(ARM_R3, (u32)jit_udiv, ctx);
@@ -865,6 +886,14 @@ b_epilogue:
865 default: 886 default:
866 return -1; 887 return -1;
867 } 888 }
889
890 if (ctx->flags & FLAG_IMM_OVERFLOW)
891 /*
892 * this instruction generated an overflow when
893 * trying to access the literal pool, so
894 * delegate this filter to the kernel interpreter.
895 */
896 return -1;
868 } 897 }
869 898
870 /* compute offsets only during the first pass */ 899 /* compute offsets only during the first pass */
@@ -927,7 +956,14 @@ void bpf_jit_compile(struct bpf_prog *fp)
927 ctx.idx = 0; 956 ctx.idx = 0;
928 957
929 build_prologue(&ctx); 958 build_prologue(&ctx);
930 build_body(&ctx); 959 if (build_body(&ctx) < 0) {
960#if __LINUX_ARM_ARCH__ < 7
961 if (ctx.imm_count)
962 kfree(ctx.imms);
963#endif
964 bpf_jit_binary_free(header);
965 goto out;
966 }
931 build_epilogue(&ctx); 967 build_epilogue(&ctx);
932 968
933 flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); 969 flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx));