mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
bpf, parisc: Add support for BPF_SDIV and BPF_SMOD in the parisc32 JIT
emit_alu_r32() and emit_alu_r64() call the unsigned millicode ($$divU/$$remU) and libgcc-style (hppa_div64()/hppa_div64_rem()) divide/remainder helpers for BPF_DIV and BPF_MOD regardless of the BPF instruction's signedness, so the parisc32 JIT does not implement signed BPF_SDIV and BPF_SMOD (off == 1). Signed ALU32 and ALU64 div/mod get an unsigned quotient and remainder rather than the verifier's and the interpreter's signed result for negative operands. Thread is_signed = (insn->off == 1) through emit_alu_r32()/ emit_alu_r64(), and on the signed path use the $$divI/$$remI signed millicode routines (32-bit) or the hppa_sdiv64()/hppa_sdiv64_rem() helpers added in patch 1 (64-bit) instead of their unsigned counterparts. $$divI and $$remI are extern-declared and exported next to $$divU/$$remU in arch/parisc/kernel/parisc_ksyms.c. bpf_do_misc_fixups() rewrites the zero-divisor and INT_MIN/-1 cases out of the instruction stream before the JIT runs. Signed-off-by: Nicholas Dudar <main.kalliope@gmail.com> Signed-off-by: Daniel Borkmann <daniel@iogearbox.net> Tested-by: Helge Deller <deller@gmx.de> Acked-by: Helge Deller <deller@gmx.de> Link: https://lore.kernel.org/bpf/20260915022905.1535566-3-main.kalliope@gmail.com
This commit is contained in:
parent
32a7b17bc8
commit
dbda00ac6f
|
|
@ -321,6 +321,8 @@ static void bpf_put_reg32(const s8 *reg, const s8 *src,
|
|||
extern void $$mulI(void);
|
||||
extern void $$divU(void);
|
||||
extern void $$remU(void);
|
||||
extern void $$divI(void);
|
||||
extern void $$remI(void);
|
||||
|
||||
static void emit_call_millicode(void *func, const s8 arg0,
|
||||
const s8 arg1, u8 opcode, struct hppa_jit_context *ctx)
|
||||
|
|
@ -562,12 +564,14 @@ static void emit_alu_i32(const s8 *dst, s32 imm,
|
|||
}
|
||||
|
||||
static void emit_alu_r64(const s8 *dst, const s8 *src,
|
||||
struct hppa_jit_context *ctx, const u8 op)
|
||||
struct hppa_jit_context *ctx, const u8 op,
|
||||
bool is_signed)
|
||||
{
|
||||
const s8 *tmp1 = regmap[TMP_REG_1];
|
||||
const s8 *tmp2 = regmap[TMP_REG_2];
|
||||
const s8 *rd;
|
||||
const s8 *rs = bpf_get_reg64(src, tmp2, ctx);
|
||||
void *func;
|
||||
|
||||
if (op == BPF_MOV)
|
||||
rd = bpf_get_reg64_ref(dst, tmp1, false, ctx);
|
||||
|
|
@ -604,10 +608,12 @@ static void emit_alu_r64(const s8 *dst, const s8 *src,
|
|||
emit_call_libgcc_ll(__muldi3, rd, rs, op, ctx);
|
||||
break;
|
||||
case BPF_DIV:
|
||||
emit_call_libgcc_ll(&hppa_div64, rd, rs, op, ctx);
|
||||
func = is_signed ? &hppa_sdiv64 : &hppa_div64;
|
||||
emit_call_libgcc_ll(func, rd, rs, op, ctx);
|
||||
break;
|
||||
case BPF_MOD:
|
||||
emit_call_libgcc_ll(&hppa_div64_rem, rd, rs, op, ctx);
|
||||
func = is_signed ? &hppa_sdiv64_rem : &hppa_div64_rem;
|
||||
emit_call_libgcc_ll(func, rd, rs, op, ctx);
|
||||
break;
|
||||
case BPF_LSH:
|
||||
emit_call_libgcc_ll(__ashldi3, rd, rs, op, ctx);
|
||||
|
|
@ -630,7 +636,8 @@ static void emit_alu_r64(const s8 *dst, const s8 *src,
|
|||
}
|
||||
|
||||
static void emit_alu_r32(const s8 *dst, const s8 *src,
|
||||
struct hppa_jit_context *ctx, const u8 op)
|
||||
struct hppa_jit_context *ctx, const u8 op,
|
||||
bool is_signed)
|
||||
{
|
||||
const s8 *tmp1 = regmap[TMP_REG_1];
|
||||
const s8 *tmp2 = regmap[TMP_REG_2];
|
||||
|
|
@ -666,10 +673,12 @@ static void emit_alu_r32(const s8 *dst, const s8 *src,
|
|||
emit_call_millicode($$mulI, lo(rd), lo(rs), op, ctx);
|
||||
break;
|
||||
case BPF_DIV:
|
||||
emit_call_millicode($$divU, lo(rd), lo(rs), op, ctx);
|
||||
emit_call_millicode(is_signed ? $$divI : $$divU,
|
||||
lo(rd), lo(rs), op, ctx);
|
||||
break;
|
||||
case BPF_MOD:
|
||||
emit_call_millicode($$remU, lo(rd), lo(rs), op, ctx);
|
||||
emit_call_millicode(is_signed ? $$remI : $$remU,
|
||||
lo(rd), lo(rs), op, ctx);
|
||||
break;
|
||||
case BPF_LSH:
|
||||
emit(hppa_subi(0x1f, lo(rs), HPPA_REG_T0), ctx);
|
||||
|
|
@ -1163,12 +1172,12 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
|
|||
emit_imm32(tmp2, imm, ctx);
|
||||
src = tmp2;
|
||||
}
|
||||
emit_alu_r64(dst, src, ctx, BPF_OP(code));
|
||||
emit_alu_r64(dst, src, ctx, BPF_OP(code), off == 1);
|
||||
break;
|
||||
|
||||
/* dst = -dst */
|
||||
case BPF_ALU64 | BPF_NEG:
|
||||
emit_alu_r64(dst, tmp2, ctx, BPF_OP(code));
|
||||
emit_alu_r64(dst, tmp2, ctx, BPF_OP(code), false);
|
||||
break;
|
||||
|
||||
case BPF_ALU64 | BPF_MOV | BPF_K:
|
||||
|
|
@ -1211,7 +1220,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
|
|||
emit_imm32(tmp2, imm, ctx);
|
||||
src = tmp2;
|
||||
}
|
||||
emit_alu_r32(dst, src, ctx, BPF_OP(code));
|
||||
emit_alu_r32(dst, src, ctx, BPF_OP(code), off == 1);
|
||||
break;
|
||||
|
||||
/* dst = dst OP imm */
|
||||
|
|
@ -1236,7 +1245,7 @@ int bpf_jit_emit_insn(const struct bpf_insn *insn, struct hppa_jit_context *ctx,
|
|||
* src is ignored---choose tmp2 as a dummy register since it
|
||||
* is not on the stack.
|
||||
*/
|
||||
emit_alu_r32(dst, tmp2, ctx, BPF_OP(code));
|
||||
emit_alu_r32(dst, tmp2, ctx, BPF_OP(code), false);
|
||||
break;
|
||||
|
||||
/* dst = BSWAP##imm(dst) */
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user