• Johan Almbladh's avatar
    mips, bpf: Add eBPF JIT for 32-bit MIPS · eb63cfcd
    Johan Almbladh authored
    This is an implementation of an eBPF JIT for 32-bit MIPS I-V and MIPS32.
    The implementation supports all 32-bit and 64-bit ALU and JMP operations,
    including the recently-added atomics. 64-bit div/mod and 64-bit atomics
    are implemented using function calls to math64 and atomic64 functions,
    respectively. All 32-bit operations are implemented natively by the JIT,
    except if the CPU lacks ll/sc instructions.
    
    Register mapping
    ================
    All 64-bit eBPF registers are mapped to native 32-bit MIPS register pairs,
    and does not use any stack scratch space for register swapping. This means
    that all eBPF register data is kept in CPU registers all the time, and
    this simplifies the register management a lot. It also reduces the JIT's
    pressure on temporary registers since we do not have to move data around.
    
    Native register pairs are ordered according to CPU endiannes, following
    the O32 calling convention for passing 64-bit arguments and return values.
    The eBPF return value, arguments and callee-saved registers are mapped to
    their native MIPS equivalents.
    
    Since the 32 highest bits in the eBPF FP (frame pointer) register are
    always zero, only one general-purpose register is actually needed for the
    mapping. The MIPS fp register is used for this purpose. The high bits are
    mapped to MIPS register r0. This saves us one CPU register, which is much
    needed for temporaries, while still allowing us to treat the R10 (FP)
    register just like any other eBPF register in the JIT.
    
    The MIPS gp (global pointer) and at (assembler temporary) registers are
    used as internal temporary registers for constant blinding. CPU registers
    t6-t9 are used internally by the JIT when constructing more complex 64-bit
    operations. This is precisely what is needed - two registers to store an
    operand value, and two more as scratch registers when performing the
    operation.
    
    The register mapping is shown below.
    
        R0 - $v1, $v0   return value
        R1 - $a1, $a0   argument 1, passed in registers
        R2 - $a3, $a2   argument 2, passed in registers
        R3 - $t1, $t0   argument 3, passed on stack
        R4 - $t3, $t2   argument 4, passed on stack
        R5 - $t4, $t3   argument 5, passed on stack
        R6 - $s1, $s0   callee-saved
        R7 - $s3, $s2   callee-saved
        R8 - $s5, $s4   callee-saved
        R9 - $s7, $s6   callee-saved
        FP - $r0, $fp   32-bit frame pointer
        AX - $gp, $at   constant-blinding
             $t6 - $t9  unallocated, JIT temporaries
    
    Jump offsets
    ============
    The JIT tries to map all conditional JMP operations to MIPS conditional
    PC-relative branches. The MIPS branch offset field is 18 bits, in bytes,
    which is equivalent to the eBPF 16-bit instruction offset. However, since
    the JIT may emit more than one CPU instruction per eBPF instruction, the
    field width may overflow. If that happens, the JIT converts the long
    conditional jump to a short PC-relative branch with the condition
    inverted, jumping over a long unconditional absolute jmp (j).
    
    This conversion will change the instruction offset mapping used for jumps,
    and may in turn result in more branch offset overflows. The JIT therefore
    dry-runs the translation until no more branches are converted and the
    offsets do not change anymore. There is an upper bound on this of course,
    and if the JIT hits that limit, the last two iterations are run with all
    branches being converted.
    
    Tail call count
    ===============
    The current tail call count is stored in the 16-byte area of the caller's
    stack frame that is reserved for the callee in the o32 ABI. The value is
    initialized in the prologue, and propagated to the tail-callee by skipping
    the initialization instructions when emitting the tail call.
    Signed-off-by: default avatarJohan Almbladh <johan.almbladh@anyfinetworks.com>
    Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
    Signed-off-by: default avatarAndrii Nakryiko <andrii@kernel.org>
    Link: https://lore.kernel.org/bpf/20211005165408.2305108-4-johan.almbladh@anyfinetworks.com
    eb63cfcd
bpf_jit_comp32.c 53.4 KB