Eduard Zingerman <eddyz87@xxxxxxxxx> writes: > On Wed, 2024-07-03 at 11:27 +0000, Puranjay Mohan wrote: > > [...] > >> > > > > @@ -16030,7 +16030,14 @@ static u8 get_helper_reg_mask(const struct bpf_func_proto *fn) >> > > > > */ >> > > > > static bool verifier_inlines_helper_call(struct bpf_verifier_env *env, s32 imm) >> > > > > { >> > > > > - return false; >> > > > > + switch (imm) { >> > > > > +#ifdef CONFIG_X86_64 >> > > > > + case BPF_FUNC_get_smp_processor_id: >> > > > > + return env->prog->jit_requested && bpf_jit_supports_percpu_insn(); >> > > > > +#endif >> > > > >> > > > please see bpf_jit_inlines_helper_call(), arm64 and risc-v inline it >> > > > in JIT, so we need to validate they don't assume any of R1-R5 register >> > > > to be a scratch register >> >> They don't assume any register to be scratch (except R0) so we can >> enable this on arm64 and riscv. > > Puranjay, just out of curiosity and tangential to this patch-set, > I see that get_smp_processor_id is implemented as follows in riscv jit: > > emit_ld(bpf_to_rv_reg(BPF_REG_0, ctx), offsetof(struct thread_info, cpu), > RV_REG_TP, ctx); > > Where bpf_to_rv_reg() refers to regmap, which in turn has the following line: > > static const int regmap[] = { > [BPF_REG_0] = RV_REG_A5, > ... > } > > At the same time, [1] says: > >> 18.2 RVG Calling Convention >> ... >> Values are returned from functions in integer registers a0 and a1 and >> floating-point registers fa0 and fa1. > > [1] https://riscv.org/wp-content/uploads/2015/01/riscv-calling.pdf > > So, I would expect r0 to be mapped to a0, do you happen to know why is it a5? I had the same question when I started working with the JITs. This is seen on both risc-v and arm64, where as you said on risc-v R0 should be mapped to A0 but is mapped to A5. Similarly, on ARM64, BPF_R0 should be mapped to ARM64_R0 but is mapped to ARM64_R7. Here is my understanding of this: The reason for this quirk is the usage of BPF register R0 as defined by BPF Registers and calling convention [1] [1] says: ``` * R0: return value from function calls, and exit value for BPF programs * R1 - R5: arguments for function calls ``` On arm64 and risc-v the first argument and the return value are passed/returned in the same register, A0 on risc-v and R0 on arm64. In BPF, the first argument to a function is passed in R1 and not in R0. So when we map these registers to riscv or arm64 calling convention, we have to map BPF_R1 to A0 on risc-v and to R0 on ARM64. This is to make argument passing easy. Therefore BPF_R0 is mapped to A5 on risc-v and ARM64_R7 on arm64. And when we JIT the 'BPF_JMP | BPF_CALL' we add a mov instruction at the end to move A0 to A5 on risc-v and R0 to R7 on arm64. But when inlining the call we can directly put the result in A5 or R7. Thanks, Puranjay [1] https://kernel.googlesource.com/pub/scm/linux/kernel/git/bpf/bpf-next/+/refs/heads/master/Documentation/bpf/standardization/abi.rst
Attachment:
signature.asc
Description: PGP signature