[PATCH v2] arm: bpf_jit: support MOD operation

Vladimir Murzin murzin.v at gmail.com
Sat Sep 21 03:32:37 EDT 2013


commit b6069a9570 (filter: add MOD operation) added generic
support for modulus operation in BPF.

This patch brings JIT support for ARM.

Signed-off-by: Vladimir Murzin <murzin.v at gmail.com>
---
v1->v2
    - wrapper for udiv_mod is added
    - MUL and SUB are squashed into MLS instruction
    
For BPF program

(000) ldh      [12]
(001) jeq      #0x800           jt 2	jf 10
(002) ldh      [16]
(003) sub      #20
(004) mod      #5
(005) jeq      #0x0             jt 10	jf 6
(006) ldb      [20]
(007) and      #0x20
(008) jeq      #0x20            jt 9	jf 10
(009) ret      #65535
(010) ret      #0

Following code is generated

256 bytes emitted from JIT compiler (pass:2, flen:11)
bf008000 + <x>:
   0:	push	{r4, r6, r7, r8, lr}
   4:	mov	r6, r0
   8:	ldr	r7, [r6, #168]	; 0xa8
   c:	ldr	r8, [r6, #80]	; 0x50
  10:	ldr	r0, [r6, #84]	; 0x54
  14:	sub	r8, r8, r0
  18:	mov	r1, #12
  1c:	sub	r0, r8, #2
  20:	cmp	r0, r1
  24:	addcs	r0, r1, r7
  28:	ldrhcs	r4, [r0]
  2c:	rev16cs	r4, r4
  30:	bcs	0x00000054
  34:	movw	r3, #7012	; 0x1b64
  38:	movt	r3, #49154	; 0xc002
  3c:	mov	r0, r6
  40:	blx	r3
  44:	cmp	r1, #0
  48:	bne	0x000000f8
  4c:	nop			; (mov r0, r0)
  50:	mov	r4, r0
  54:	cmp	r4, #2048	; 0x800
  58:	bne	0x000000f8
  5c:	mov	r1, #16
  60:	sub	r0, r8, #2
  64:	cmp	r0, r1
  68:	addcs	r0, r1, r7
  6c:	ldrhcs	r4, [r0]
  70:	rev16cs	r4, r4
  74:	bcs	0x00000098
  78:	movw	r3, #7012	; 0x1b64
  7c:	movt	r3, #49154	; 0xc002
  80:	mov	r0, r6
  84:	blx	r3
  88:	cmp	r1, #0
  8c:	bne	0x000000f8
  90:	nop			; (mov r0, r0)
  94:	mov	r4, r0
  98:	sub	r4, r4, #20
  9c:	mov	r0, #5
  a0:	udiv	r3, r4, r0
  a4:	mls	r4, r3, r0, r4
  a8:	cmp	r4, #0
  ac:	beq	0x000000f8
  b0:	mov	r1, #20
  b4:	cmp	r8, r1
  b8:	addhi	r0, r1, r7
  bc:	ldrbhi	r4, [r0]
  c0:	bhi	0x000000e4
  c4:	movw	r3, #7068	; 0x1b9c
  c8:	movt	r3, #49154	; 0xc002
  cc:	mov	r0, r6
  d0:	blx	r3
  d4:	cmp	r1, #0
  d8:	bne	0x000000f8
  dc:	nop			; (mov r0, r0)
  e0:	mov	r4, r0
  e4:	and	r4, r4, #32
  e8:	cmp	r4, #32
  ec:	bne	0x000000f8
  f0:	movw	r0, #65535	; 0xffff
  f4:	b	0x000000fc
  f8:	mov	r0, #0
  fc:	pop	{r4, r6, r7, r8, pc}

Raw opcodes are

flen=11 proglen=256 pass=2 image=bf008000
JIT code: 00000000: d0 41 2d e9 00 60 a0 e1 a8 70 96 e5 50 80 96 e5
JIT code: 00000010: 54 00 96 e5 00 80 48 e0 0c 10 a0 e3 02 00 48 e2
JIT code: 00000020: 01 00 50 e1 07 00 81 20 b0 40 d0 21 b4 4f bf 26
JIT code: 00000030: 07 00 00 2a 64 3b 01 e3 02 30 4c e3 06 00 a0 e1
JIT code: 00000040: 33 ff 2f e1 00 00 51 e3 2a 00 00 1a 00 00 a0 e1
JIT code: 00000050: 00 40 a0 e1 02 0b 54 e3 26 00 00 1a 10 10 a0 e3
JIT code: 00000060: 02 00 48 e2 01 00 50 e1 07 00 81 20 b0 40 d0 21
JIT code: 00000070: b4 4f bf 26 07 00 00 2a 64 3b 01 e3 02 30 4c e3
JIT code: 00000080: 06 00 a0 e1 33 ff 2f e1 00 00 51 e3 19 00 00 1a
JIT code: 00000090: 00 00 a0 e1 00 40 a0 e1 14 40 44 e2 05 00 a0 e3
JIT code: 000000a0: 14 f0 33 e7 93 40 64 e0 00 00 54 e3 11 00 00 0a
JIT code: 000000b0: 14 10 a0 e3 01 00 58 e1 07 00 81 80 00 40 d0 85
JIT code: 000000c0: 07 00 00 8a 9c 3b 01 e3 02 30 4c e3 06 00 a0 e1
JIT code: 000000d0: 33 ff 2f e1 00 00 51 e3 06 00 00 1a 00 00 a0 e1
JIT code: 000000e0: 00 40 a0 e1 20 40 04 e2 20 00 54 e3 01 00 00 1a
JIT code: 000000f0: ff 0f 0f e3 00 00 00 ea 00 00 a0 e3 d0 81 bd e8

 arch/arm/net/bpf_jit_32.c |   38 ++++++++++++++++++++++++++++++++++++++
 arch/arm/net/bpf_jit_32.h |    3 +++
 2 files changed, 41 insertions(+)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index f50d223..faec4d3 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -111,6 +111,11 @@ static u32 jit_udiv(u32 dividend, u32 divisor)
 	return dividend / divisor;
 }
 
+static u32 jit_udiv_mod(u32 dividend, u32 divisor)
+{
+	return dividend % divisor;
+}
+
 static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
 {
 	if (ctx->target != NULL)
@@ -458,6 +463,29 @@ static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
 		emit(ARM_MOV_R(rd, ARM_R0), ctx);
 }
 
+static inline void emit_udiv_mod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx)
+{
+#if __LINUX_ARM_ARCH__ == 7
+	if (elf_hwcap & HWCAP_IDIVA) {
+		emit(ARM_UDIV(ARM_R3, rm, rn), ctx);
+		emit(ARM_MLS(rd, ARM_R3, rn, rm), ctx);
+		return;
+	}
+#endif
+	if (rm != ARM_R0)
+		emit(ARM_MOV_R(ARM_R0, rm), ctx);
+	if (rn != ARM_R1)
+		emit(ARM_MOV_R(ARM_R1, rn), ctx);
+
+	ctx->seen |= SEEN_CALL;
+	emit_mov_i(ARM_R3, (u32)jit_udiv_mod, ctx);
+	emit_blx_r(ARM_R3, ctx);
+
+	if (rd != ARM_R0)
+		emit(ARM_MOV_R(rd, ARM_R0), ctx);
+}
+
+
 static inline void update_on_xread(struct jit_ctx *ctx)
 {
 	if (!(ctx->seen & SEEN_X))
@@ -636,6 +664,16 @@ load_ind:
 			update_on_xread(ctx);
 			emit(ARM_MUL(r_A, r_A, r_X), ctx);
 			break;
+		case BPF_S_ALU_MOD_X: /* A %= X; */
+			update_on_xread(ctx);
+			emit(ARM_CMP_I(r_X, 0), ctx);
+			emit_err_ret(ARM_COND_EQ, ctx);
+			emit_udiv_mod(r_A, r_A, r_X, ctx);
+			break;
+		case BPF_S_ALU_MOD_K: /* A %= K; */
+			emit_mov_i(r_scratch, k, ctx);
+			emit_udiv_mod(r_A, r_A, r_scratch, ctx);
+			break;
 		case BPF_S_ALU_DIV_K:
 			/* current k == reciprocal_value(userspace k) */
 			emit_mov_i(r_scratch, k, ctx);
diff --git a/arch/arm/net/bpf_jit_32.h b/arch/arm/net/bpf_jit_32.h
index afb8462..640a8fd 100644
--- a/arch/arm/net/bpf_jit_32.h
+++ b/arch/arm/net/bpf_jit_32.h
@@ -90,6 +90,7 @@
 #define ARM_INST_MOVT		0x03400000
 
 #define ARM_INST_MUL		0x00000090
+#define ARM_INST_MLS		0x00600090
 
 #define ARM_INST_POP		0x08bd0000
 #define ARM_INST_PUSH		0x092d0000
@@ -192,5 +193,7 @@
 
 #define ARM_UMULL(rd_lo, rd_hi, rn, rm)	(ARM_INST_UMULL | (rd_hi) << 16 \
 					 | (rd_lo) << 12 | (rm) << 8 | rn)
+#define ARM_MLS(rd, rn, rm, ra)	(ARM_INST_MLS | (rd) << 16 \
+					 | (ra) << 12 | (rm) << 8 | rn)
 
 #endif /* PFILTER_OPCODES_ARM_H */
-- 
1.7.10.4




More information about the linux-arm-kernel mailing list