Skip to content

Commit 5097faa

Browse files
puranjaymohanAlexei Starovoitov
authored andcommitted
arm32, bpf: add support for 32-bit signed division
The cpuv4 added a new BPF_SDIV instruction that does signed division. The encoding is similar to BPF_DIV but BPF_SDIV sets offset=1. ARM32 already supports 32-bit BPF_DIV which can be easily extended to support BPF_SDIV as ARM32 has the SDIV instruction. When the CPU is not ARM-v7, we implement that SDIV/SMOD with the function call similar to the implementation of DIV/MOD. Signed-off-by: Puranjay Mohan <puranjay12@gmail.com> Reviewed-by: Russell King (Oracle) <rmk+kernel@armlinux.org.uk> Link: https://lore.kernel.org/r/20230907230550.1417590-6-puranjay12@gmail.com Signed-off-by: Alexei Starovoitov <ast@kernel.org>
1 parent 1cfb7ea commit 5097faa

File tree

2 files changed

+32
-8
lines changed

2 files changed

+32
-8
lines changed

arch/arm/net/bpf_jit_32.c

Lines changed: 30 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -228,6 +228,16 @@ static u32 jit_mod32(u32 dividend, u32 divisor)
228228
return dividend % divisor;
229229
}
230230

231+
static s32 jit_sdiv32(s32 dividend, s32 divisor)
232+
{
233+
return dividend / divisor;
234+
}
235+
236+
static s32 jit_smod32(s32 dividend, s32 divisor)
237+
{
238+
return dividend % divisor;
239+
}
240+
231241
static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx)
232242
{
233243
inst |= (cond << 28);
@@ -477,17 +487,18 @@ static inline int epilogue_offset(const struct jit_ctx *ctx)
477487
return to - from - 2;
478488
}
479489

480-
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
490+
static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op, u8 sign)
481491
{
482492
const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1);
483493
const s8 *tmp = bpf2a32[TMP_REG_1];
494+
u32 dst;
484495

485496
#if __LINUX_ARM_ARCH__ == 7
486497
if (elf_hwcap & HWCAP_IDIVA) {
487-
if (op == BPF_DIV)
488-
emit(ARM_UDIV(rd, rm, rn), ctx);
489-
else {
490-
emit(ARM_UDIV(ARM_IP, rm, rn), ctx);
498+
if (op == BPF_DIV) {
499+
emit(sign ? ARM_SDIV(rd, rm, rn) : ARM_UDIV(rd, rm, rn), ctx);
500+
} else {
501+
emit(sign ? ARM_SDIV(ARM_IP, rm, rn) : ARM_UDIV(ARM_IP, rm, rn), ctx);
491502
emit(ARM_MLS(rd, rn, ARM_IP, rm), ctx);
492503
}
493504
return;
@@ -515,8 +526,19 @@ static inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op)
515526
emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx);
516527

517528
/* Call appropriate function */
518-
emit_mov_i(ARM_IP, op == BPF_DIV ?
519-
(u32)jit_udiv32 : (u32)jit_mod32, ctx);
529+
if (sign) {
530+
if (op == BPF_DIV)
531+
dst = (u32)jit_sdiv32;
532+
else
533+
dst = (u32)jit_smod32;
534+
} else {
535+
if (op == BPF_DIV)
536+
dst = (u32)jit_udiv32;
537+
else
538+
dst = (u32)jit_mod32;
539+
}
540+
541+
emit_mov_i(ARM_IP, dst, ctx);
520542
emit_blx_r(ARM_IP, ctx);
521543

522544
/* Restore caller-saved registers from stack */
@@ -1551,7 +1573,7 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx)
15511573
rt = src_lo;
15521574
break;
15531575
}
1554-
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code));
1576+
emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code), off);
15551577
arm_bpf_put_reg32(dst_lo, rd_lo, ctx);
15561578
if (!ctx->prog->aux->verifier_zext)
15571579
emit_a32_mov_i(dst_hi, 0, ctx);

arch/arm/net/bpf_jit_32.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -139,6 +139,7 @@
139139
#define ARM_INST_TST_I 0x03100000
140140

141141
#define ARM_INST_UDIV 0x0730f010
142+
#define ARM_INST_SDIV 0x0710f010
142143

143144
#define ARM_INST_UMULL 0x00800090
144145

@@ -267,6 +268,7 @@
267268
#define ARM_TST_I(rn, imm) _AL3_I(ARM_INST_TST, 0, rn, imm)
268269

269270
#define ARM_UDIV(rd, rn, rm) (ARM_INST_UDIV | (rd) << 16 | (rn) | (rm) << 8)
271+
#define ARM_SDIV(rd, rn, rm) (ARM_INST_SDIV | (rd) << 16 | (rn) | (rm) << 8)
270272

271273
#define ARM_UMULL(rd_lo, rd_hi, rn, rm) (ARM_INST_UMULL | (rd_hi) << 16 \
272274
| (rd_lo) << 12 | (rm) << 8 | rn)

0 commit comments

Comments
 (0)