diff options
| author | Tiezhu Yang <yangtiezhu@loongson.cn> | 2026-04-22 10:45:34 +0300 |
|---|---|---|
| committer | Huacai Chen <chenhuacai@loongson.cn> | 2026-04-22 10:45:34 +0300 |
| commit | 0ef8b96051555aaded204c9e65edbd3656d9613f (patch) | |
| tree | a022be92054b90a25165b1d2edc65f0629842272 | |
| parent | 4653682c6f6559e3209586f7bb30183f36375f00 (diff) | |
| download | linux-0ef8b96051555aaded204c9e65edbd3656d9613f.tar.xz | |
LoongArch: BPF: Support small struct arguments for trampoline
In the current BPF code, the struct argument size is at most 16 bytes,
enforced by the verifier. According to the Procedure Call Standard for
LoongArch, the struct argument size below 16 bytes are provided as part
of the 8 argument registers, that is to say, the struct argument may be
passed in a pair of registers if its size is more than 8 bytes and no
more than 16 bytes.
Extend the BPF trampoline JIT to support attachment to functions that
take small structures (up to 16 bytes) as argument, save and restore a
number of "argument registers" rather than a number of arguments.
With this patch, the following related testcases passed:
sudo ./test_progs -a tracing_struct/struct_args
sudo ./test_progs -a tracing_struct/union_args
Link: https://github.com/loongson/la-abi-specs/blob/release/lapcs.adoc#structures
Acked-by: Hengqi Chen <hengqi.chen@gmail.com>
Tested-by: Hengqi Chen <hengqi.chen@gmail.com>
Signed-off-by: Tiezhu Yang <yangtiezhu@loongson.cn>
Signed-off-by: Huacai Chen <chenhuacai@loongson.cn>
| -rw-r--r-- | arch/loongarch/net/bpf_jit.c | 55 |
1 files changed, 31 insertions, 24 deletions
diff --git a/arch/loongarch/net/bpf_jit.c b/arch/loongarch/net/bpf_jit.c index 0a8dc21473f9..9fc930e89b12 100644 --- a/arch/loongarch/net/bpf_jit.c +++ b/arch/loongarch/net/bpf_jit.c @@ -1628,21 +1628,21 @@ int bpf_arch_text_invalidate(void *dst, size_t len) return ret; } -static void store_args(struct jit_ctx *ctx, int nargs, int args_off) +static void store_args(struct jit_ctx *ctx, int nregs, int args_off) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit_insn(ctx, std, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); args_off -= 8; } } -static void restore_args(struct jit_ctx *ctx, int nargs, int args_off) +static void restore_args(struct jit_ctx *ctx, int nregs, int args_off) { int i; - for (i = 0; i < nargs; i++) { + for (i = 0; i < nregs; i++) { emit_insn(ctx, ldd, LOONGARCH_GPR_A0 + i, LOONGARCH_GPR_FP, -args_off); args_off -= 8; } @@ -1763,8 +1763,8 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i void *func_addr, u32 flags) { int i, ret, save_ret; - int stack_size, nargs; - int retval_off, args_off, nargs_off, ip_off, run_ctx_off, sreg_off, tcc_ptr_off; + int stack_size, nregs = m->nr_args; + int retval_off, args_off, nregs_off, ip_off, run_ctx_off, sreg_off, tcc_ptr_off; bool is_struct_ops = flags & BPF_TRAMP_F_INDIRECT; void *orig_call = func_addr; struct bpf_tramp_links *fentry = &tlinks[BPF_TRAMP_FENTRY]; @@ -1784,11 +1784,11 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i * * FP - retval_off [ return value ] BPF_TRAMP_F_CALL_ORIG or * BPF_TRAMP_F_RET_FENTRY_RET - * [ argN ] + * [ arg regN ] * [ ... ] - * FP - args_off [ arg1 ] + * FP - args_off [ arg reg1 ] * - * FP - nargs_off [ regs count ] + * FP - nregs_off [ arg regs count ] * * FP - ip_off [ traced func ] BPF_TRAMP_F_IP_ARG * @@ -1799,15 +1799,23 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i * FP - tcc_ptr_off [ tail_call_cnt_ptr ] */ - if (m->nr_args > LOONGARCH_MAX_REG_ARGS) - return -ENOTSUPP; - - /* FIXME: No support of struct argument */ + /* Extra registers for struct arguments */ for (i = 0; i < m->nr_args; i++) { - if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) - return -ENOTSUPP; + if (m->arg_flags[i] & BTF_FMODEL_STRUCT_ARG) { + /* + * The struct argument size is at most 16 bytes, + * enforced by the verifier. The struct argument + * may be passed in a pair of registers if its + * size is more than 8 bytes and no more than 16 + * bytes. + */ + nregs += round_up(m->arg_size[i], 8) / 8 - 1; + } } + if (nregs > LOONGARCH_MAX_REG_ARGS) + return -ENOTSUPP; + if (flags & (BPF_TRAMP_F_ORIG_STACK | BPF_TRAMP_F_SHARE_IPMODIFY)) return -ENOTSUPP; @@ -1821,13 +1829,12 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i retval_off = stack_size; /* Room of trampoline frame to store args */ - nargs = m->nr_args; - stack_size += nargs * 8; + stack_size += nregs * 8; args_off = stack_size; /* Room of trampoline frame to store args number */ stack_size += 8; - nargs_off = stack_size; + nregs_off = stack_size; /* Room of trampoline frame to store ip address */ if (flags & BPF_TRAMP_F_IP_ARG) { @@ -1890,11 +1897,11 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -ip_off); } - /* store nargs number */ - move_imm(ctx, LOONGARCH_GPR_T1, nargs, false); - emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -nargs_off); + /* store arg regs count */ + move_imm(ctx, LOONGARCH_GPR_T1, nregs, false); + emit_insn(ctx, std, LOONGARCH_GPR_T1, LOONGARCH_GPR_FP, -nregs_off); - store_args(ctx, nargs, args_off); + store_args(ctx, nregs, args_off); /* To traced function */ /* Ftrace jump skips 2 NOP instructions */ @@ -1936,7 +1943,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i } if (flags & BPF_TRAMP_F_CALL_ORIG) { - restore_args(ctx, m->nr_args, args_off); + restore_args(ctx, nregs, args_off); if (flags & BPF_TRAMP_F_TAIL_CALL_CTX) emit_insn(ctx, ldd, REG_TCC, LOONGARCH_GPR_FP, -tcc_ptr_off); @@ -1972,7 +1979,7 @@ static int __arch_prepare_bpf_trampoline(struct jit_ctx *ctx, struct bpf_tramp_i } if (flags & BPF_TRAMP_F_RESTORE_REGS) - restore_args(ctx, m->nr_args, args_off); + restore_args(ctx, nregs, args_off); if (save_ret) { emit_insn(ctx, ldd, regmap[BPF_REG_0], LOONGARCH_GPR_FP, -(retval_off - 8)); |
