diff options
author | Russell King <rmk+kernel@armlinux.org.uk> | 2018-01-13 06:35:15 -0500 |
---|---|---|
committer | Russell King <rmk+kernel@armlinux.org.uk> | 2018-01-17 14:35:22 -0500 |
commit | e9062481824384f00299971f923fecf6b3668001 (patch) | |
tree | 9eb1a903130c504a325c754051c6be9c27c8088c | |
parent | 36b0cb84ee858f02c256d26f0cb4229c78e3399e (diff) |
ARM: net: bpf: avoid 'bx' instruction on non-Thumb capable CPUs
Avoid the 'bx' instruction on CPUs that have no support for Thumb and
thus do not implement this instruction by moving the generation of this
opcode to a separate function that selects between:
bx reg
and
mov pc, reg
according to the capabilities of the CPU.
Fixes: 39c13c204bb1 ("arm: eBPF JIT compiler")
Signed-off-by: Russell King <rmk+kernel@armlinux.org.uk>
-rw-r--r-- | arch/arm/net/bpf_jit_32.c | 18 |
1 files changed, 11 insertions, 7 deletions
diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c index c199990e12b6..4efb3743a89e 100644 --- a/arch/arm/net/bpf_jit_32.c +++ b/arch/arm/net/bpf_jit_32.c | |||
@@ -285,16 +285,20 @@ static inline void emit_mov_i(const u8 rd, u32 val, struct jit_ctx *ctx) | |||
285 | emit_mov_i_no8m(rd, val, ctx); | 285 | emit_mov_i_no8m(rd, val, ctx); |
286 | } | 286 | } |
287 | 287 | ||
288 | static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) | 288 | static void emit_bx_r(u8 tgt_reg, struct jit_ctx *ctx) |
289 | { | 289 | { |
290 | ctx->seen |= SEEN_CALL; | ||
291 | #if __LINUX_ARM_ARCH__ < 5 | ||
292 | emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); | ||
293 | |||
294 | if (elf_hwcap & HWCAP_THUMB) | 290 | if (elf_hwcap & HWCAP_THUMB) |
295 | emit(ARM_BX(tgt_reg), ctx); | 291 | emit(ARM_BX(tgt_reg), ctx); |
296 | else | 292 | else |
297 | emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx); | 293 | emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx); |
294 | } | ||
295 | |||
296 | static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) | ||
297 | { | ||
298 | ctx->seen |= SEEN_CALL; | ||
299 | #if __LINUX_ARM_ARCH__ < 5 | ||
300 | emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); | ||
301 | emit_bx_r(tgt_reg, ctx); | ||
298 | #else | 302 | #else |
299 | emit(ARM_BLX_R(tgt_reg), ctx); | 303 | emit(ARM_BLX_R(tgt_reg), ctx); |
300 | #endif | 304 | #endif |
@@ -997,7 +1001,7 @@ static int emit_bpf_tail_call(struct jit_ctx *ctx) | |||
997 | emit_a32_mov_i(tmp2[1], off, false, ctx); | 1001 | emit_a32_mov_i(tmp2[1], off, false, ctx); |
998 | emit(ARM_LDR_R(tmp[1], tmp[1], tmp2[1]), ctx); | 1002 | emit(ARM_LDR_R(tmp[1], tmp[1], tmp2[1]), ctx); |
999 | emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx); | 1003 | emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx); |
1000 | emit(ARM_BX(tmp[1]), ctx); | 1004 | emit_bx_r(tmp[1], ctx); |
1001 | 1005 | ||
1002 | /* out: */ | 1006 | /* out: */ |
1003 | if (out_offset == -1) | 1007 | if (out_offset == -1) |
@@ -1166,7 +1170,7 @@ static void build_epilogue(struct jit_ctx *ctx) | |||
1166 | emit(ARM_POP(reg_set), ctx); | 1170 | emit(ARM_POP(reg_set), ctx); |
1167 | /* Return back to the callee function */ | 1171 | /* Return back to the callee function */ |
1168 | if (!(ctx->seen & SEEN_CALL)) | 1172 | if (!(ctx->seen & SEEN_CALL)) |
1169 | emit(ARM_BX(ARM_LR), ctx); | 1173 | emit_bx_r(ARM_LR, ctx); |
1170 | #endif | 1174 | #endif |
1171 | } | 1175 | } |
1172 | 1176 | ||