Re: [PATCH bpf RESEND 3/4] bpf: Add kernel function call support in 32-bit ARM

From: Yang Jihong
Date: Mon Nov 07 2022 - 04:11:08 EST


Hello,

On 2022/11/3 19:35, Russell King (Oracle) wrote:
On Thu, Nov 03, 2022 at 05:21:17PM +0800, Yang Jihong wrote:
This patch adds kernel function call support to the 32-bit ARM bpf jit.

Signed-off-by: Yang Jihong <yangjihong1@xxxxxxxxxx>
---
arch/arm/net/bpf_jit_32.c | 130 ++++++++++++++++++++++++++++++++++++++
1 file changed, 130 insertions(+)

diff --git a/arch/arm/net/bpf_jit_32.c b/arch/arm/net/bpf_jit_32.c
index 6a1c9fca5260..51428c82bec6 100644
--- a/arch/arm/net/bpf_jit_32.c
+++ b/arch/arm/net/bpf_jit_32.c
@@ -1337,6 +1337,118 @@ static void build_epilogue(struct jit_ctx *ctx)
#endif
}
+/*
+ * Input parameters of function in 32-bit ARM architecture:
+ * The first four word-sized parameters passed to a function will be
+ * transferred in registers R0-R3. Sub-word sized arguments, for example,
+ * char, will still use a whole register.
+ * Arguments larger than a word will be passed in multiple registers.
+ * If more arguments are passed, the fifth and subsequent words will be passed
+ * on the stack.
+ *
+ * The first for args of a function will be considered for
+ * putting into the 32bit register R1, R2, R3 and R4.
+ *
+ * Two 32bit registers are used to pass a 64bit arg.
+ *
+ * For example,
+ * void foo(u32 a, u32 b, u32 c, u32 d, u32 e):
+ * u32 a: R0
+ * u32 b: R1
+ * u32 c: R2
+ * u32 d: R3
+ * u32 e: stack
+ *
+ * void foo(u64 a, u32 b, u32 c, u32 d):
+ * u64 a: R0 (lo32) R1 (hi32)
+ * u32 b: R2
+ * u32 c: R3
+ * u32 d: stack
+ *
+ * void foo(u32 a, u64 b, u32 c, u32 d):
+ * u32 a: R0
+ * u64 b: R2 (lo32) R3 (hi32)
+ * u32 c: stack
+ * u32 d: stack

This code supports both EABI and OABI, but the above is EABI-only.
Either we need to decide not to support OABI, or we need to add code
for both. That can probably be done by making:

Yes, the OABI situation was not considered here before,
Because I don't have OABI ARM machine, I can't actually verify it,
only EABI is supported.
In the next version, will check whether CONFIG_AEABI is enabled.
+ for (i = 0; i < fm->nr_args; i++) {
+ if (fm->arg_size[i] > sizeof(u32)) {
+ if (arg_regs_idx + 1 < nr_arg_regs) {
+ /*
+ * AAPCS states:
+ * A double-word sized type is passed in two
+ * consecutive registers (e.g., r0 and r1, or
+ * r2 and r3). The content of the registers is
+ * as if the value had been loaded from memory
+ * representation with a single LDM instruction.
+ */
+ if (arg_regs_idx & 1)
+ arg_regs_idx++;

... this conditional on IS_ENABLED(CONFIG_AEABI).

+ emit(ARM_LDRD_I(arg_regs[arg_regs_idx], ARM_FP,
+ EBPF_SCRATCH_TO_ARM_FP(
+ bpf2a32[BPF_REG_1 + i][1])), ctx);

You probably want to re-use the internals of arm_bpf_get_reg64() to load
the register.
OK, will re-use arm_bpf_get_reg64 in next version.

+
+ arg_regs_idx += 2;
+ } else {
+ stack_off = ALIGN(stack_off, STACK_ALIGNMENT);
+
+ emit(ARM_LDRD_I(tmp[1], ARM_FP,
+ EBPF_SCRATCH_TO_ARM_FP(
+ bpf2a32[BPF_REG_1 + i][1])), ctx);

Same here.
OK, will re-use arm_bpf_get_reg64 in next version.

+ emit(ARM_STRD_I(tmp[1], ARM_SP, stack_off), ctx);

and the internals of arm_bpf_put_reg64() here. Not all Arm CPUs that
this code runs on supports ldrd and strd.

Yes, the ARM CPUs that do not support LDRD and STRD have not been considered, will fix in next version.


Thanks,
Yang