LoongArch: BPF: Sign extend kfunc call arguments

The kfunc calls are native calls so they should follow LoongArch calling
conventions. Sign extend its arguments properly to avoid kernel panic.
This is done by adding a new emit_abi_ext() helper. The emit_abi_ext()
helper performs extension in place meaning a value already store in the
target register (Note: this is different from the existing sign_extend()
helper and thus we can't reuse it).

Cc: stable@vger.kernel.org
Fixes: 5dc615520c4d ("LoongArch: Add BPF JIT support")
Signed-off-by: Hengqi Chen <hengqi.chen@gmail.com>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
Signed-off-by: maoxiaochuan <maoxiaochuan@loongson.cn>
This commit is contained in:
Hengqi Chen
2026-02-04 16:39:57 +08:00
committed by maoxiaochuan
parent 458bfe865a
commit 43e6e72341
2 changed files with 42 additions and 0 deletions
+16
View File
@@ -950,6 +950,22 @@ static int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx, bool ext
emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_SP, tcc_ptr_off);
}
if (insn->src_reg == BPF_PSEUDO_KFUNC_CALL) {
const struct btf_func_model *m;
int i;
m = bpf_jit_find_kfunc_model(ctx->prog, insn);
if (!m)
return -EINVAL;
for (i = 0; i < m->nr_args; i++) {
u8 reg = regmap[BPF_REG_1 + i];
bool sign = m->arg_flags[i] & BTF_FMODEL_SIGNED_ARG;
emit_abi_ext(ctx, reg, m->arg_size[i], sign);
}
}
move_addr(ctx, t1, func_addr);
emit_insn(ctx, jirl, LOONGARCH_GPR_RA, t1, 0);
+26
View File
@@ -88,6 +88,32 @@ static inline void emit_sext_32(struct jit_ctx *ctx, enum loongarch_gpr reg, boo
emit_insn(ctx, addiw, reg, reg, 0);
}
/* Emit proper extension according to ABI requirements.
* Note that it requires a value of size `size` already resides in register `reg`.
*/
static inline void emit_abi_ext(struct jit_ctx *ctx, int reg, u8 size, bool sign)
{
/* ABI requires unsigned char/short to be zero-extended */
if (!sign && (size == 1 || size == 2))
return;
switch (size) {
case 1:
emit_insn(ctx, extwb, reg, reg);
break;
case 2:
emit_insn(ctx, extwh, reg, reg);
break;
case 4:
emit_insn(ctx, addiw, reg, reg, 0);
break;
case 8:
break;
default:
pr_warn("bpf_jit: invalid size %d for extension\n", size);
}
}
static inline void move_addr(struct jit_ctx *ctx, enum loongarch_gpr rd, u64 addr)
{
u64 imm_11_0, imm_31_12, imm_51_32, imm_63_52;