162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Just-In-Time compiler for eBPF filters on 32bit ARM 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2017 Shubham Bansal <illusionist.neo@gmail.com> 662306a36Sopenharmony_ci * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com> 762306a36Sopenharmony_ci */ 862306a36Sopenharmony_ci 962306a36Sopenharmony_ci#include <linux/bpf.h> 1062306a36Sopenharmony_ci#include <linux/bitops.h> 1162306a36Sopenharmony_ci#include <linux/compiler.h> 1262306a36Sopenharmony_ci#include <linux/errno.h> 1362306a36Sopenharmony_ci#include <linux/filter.h> 1462306a36Sopenharmony_ci#include <linux/netdevice.h> 1562306a36Sopenharmony_ci#include <linux/string.h> 1662306a36Sopenharmony_ci#include <linux/slab.h> 1762306a36Sopenharmony_ci#include <linux/if_vlan.h> 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci#include <asm/cacheflush.h> 2062306a36Sopenharmony_ci#include <asm/hwcap.h> 2162306a36Sopenharmony_ci#include <asm/opcodes.h> 2262306a36Sopenharmony_ci#include <asm/system_info.h> 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci#include "bpf_jit_32.h" 2562306a36Sopenharmony_ci 2662306a36Sopenharmony_ci/* 2762306a36Sopenharmony_ci * eBPF prog stack layout: 2862306a36Sopenharmony_ci * 2962306a36Sopenharmony_ci * high 3062306a36Sopenharmony_ci * original ARM_SP => +-----+ 3162306a36Sopenharmony_ci * | | callee saved registers 3262306a36Sopenharmony_ci * +-----+ <= (BPF_FP + SCRATCH_SIZE) 3362306a36Sopenharmony_ci * | ... | eBPF JIT scratch space 3462306a36Sopenharmony_ci * eBPF fp register => +-----+ 3562306a36Sopenharmony_ci * (BPF_FP) | ... | eBPF prog stack 3662306a36Sopenharmony_ci * +-----+ 3762306a36Sopenharmony_ci * |RSVD | JIT scratchpad 3862306a36Sopenharmony_ci * current ARM_SP => +-----+ <= (BPF_FP - STACK_SIZE + SCRATCH_SIZE) 3962306a36Sopenharmony_ci * | ... | caller-saved registers 4062306a36Sopenharmony_ci * +-----+ 4162306a36Sopenharmony_ci * | ... | arguments passed on stack 4262306a36Sopenharmony_ci * ARM_SP during call => +-----| 4362306a36Sopenharmony_ci * | | 4462306a36Sopenharmony_ci * | ... | Function call stack 4562306a36Sopenharmony_ci * | | 4662306a36Sopenharmony_ci * +-----+ 4762306a36Sopenharmony_ci * low 4862306a36Sopenharmony_ci * 4962306a36Sopenharmony_ci * The callee saved registers depends on whether frame pointers are enabled. 5062306a36Sopenharmony_ci * With frame pointers (to be compliant with the ABI): 5162306a36Sopenharmony_ci * 5262306a36Sopenharmony_ci * high 5362306a36Sopenharmony_ci * original ARM_SP => +--------------+ \ 5462306a36Sopenharmony_ci * | pc | | 5562306a36Sopenharmony_ci * current ARM_FP => +--------------+ } callee saved registers 5662306a36Sopenharmony_ci * |r4-r9,fp,ip,lr| | 5762306a36Sopenharmony_ci * +--------------+ / 5862306a36Sopenharmony_ci * low 5962306a36Sopenharmony_ci * 6062306a36Sopenharmony_ci * Without frame pointers: 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * high 6362306a36Sopenharmony_ci * original ARM_SP => +--------------+ 6462306a36Sopenharmony_ci * | r4-r9,fp,lr | callee saved registers 6562306a36Sopenharmony_ci * current ARM_FP => +--------------+ 6662306a36Sopenharmony_ci * low 6762306a36Sopenharmony_ci * 6862306a36Sopenharmony_ci * When popping registers off the stack at the end of a BPF function, we 6962306a36Sopenharmony_ci * reference them via the current ARM_FP register. 7062306a36Sopenharmony_ci * 7162306a36Sopenharmony_ci * Some eBPF operations are implemented via a call to a helper function. 7262306a36Sopenharmony_ci * Such calls are "invisible" in the eBPF code, so it is up to the calling 7362306a36Sopenharmony_ci * program to preserve any caller-saved ARM registers during the call. The 7462306a36Sopenharmony_ci * JIT emits code to push and pop those registers onto the stack, immediately 7562306a36Sopenharmony_ci * above the callee stack frame. 7662306a36Sopenharmony_ci */ 7762306a36Sopenharmony_ci#define CALLEE_MASK (1 << ARM_R4 | 1 << ARM_R5 | 1 << ARM_R6 | \ 7862306a36Sopenharmony_ci 1 << ARM_R7 | 1 << ARM_R8 | 1 << ARM_R9 | \ 7962306a36Sopenharmony_ci 1 << ARM_FP) 8062306a36Sopenharmony_ci#define CALLEE_PUSH_MASK (CALLEE_MASK | 1 << ARM_LR) 8162306a36Sopenharmony_ci#define CALLEE_POP_MASK (CALLEE_MASK | 1 << ARM_PC) 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci#define CALLER_MASK (1 << ARM_R0 | 1 << ARM_R1 | 1 << ARM_R2 | 1 << ARM_R3) 8462306a36Sopenharmony_ci 8562306a36Sopenharmony_cienum { 8662306a36Sopenharmony_ci /* Stack layout - these are offsets from (top of stack - 4) */ 8762306a36Sopenharmony_ci BPF_R2_HI, 8862306a36Sopenharmony_ci BPF_R2_LO, 8962306a36Sopenharmony_ci BPF_R3_HI, 9062306a36Sopenharmony_ci BPF_R3_LO, 9162306a36Sopenharmony_ci BPF_R4_HI, 9262306a36Sopenharmony_ci BPF_R4_LO, 9362306a36Sopenharmony_ci BPF_R5_HI, 9462306a36Sopenharmony_ci BPF_R5_LO, 9562306a36Sopenharmony_ci BPF_R7_HI, 9662306a36Sopenharmony_ci BPF_R7_LO, 9762306a36Sopenharmony_ci BPF_R8_HI, 9862306a36Sopenharmony_ci BPF_R8_LO, 9962306a36Sopenharmony_ci BPF_R9_HI, 10062306a36Sopenharmony_ci BPF_R9_LO, 10162306a36Sopenharmony_ci BPF_FP_HI, 10262306a36Sopenharmony_ci BPF_FP_LO, 10362306a36Sopenharmony_ci BPF_TC_HI, 10462306a36Sopenharmony_ci BPF_TC_LO, 10562306a36Sopenharmony_ci BPF_AX_HI, 10662306a36Sopenharmony_ci BPF_AX_LO, 10762306a36Sopenharmony_ci /* Stack space for BPF_REG_2, BPF_REG_3, BPF_REG_4, 10862306a36Sopenharmony_ci * BPF_REG_5, BPF_REG_7, BPF_REG_8, BPF_REG_9, 10962306a36Sopenharmony_ci * BPF_REG_FP and Tail call counts. 11062306a36Sopenharmony_ci */ 11162306a36Sopenharmony_ci BPF_JIT_SCRATCH_REGS, 11262306a36Sopenharmony_ci}; 11362306a36Sopenharmony_ci 11462306a36Sopenharmony_ci/* 11562306a36Sopenharmony_ci * Negative "register" values indicate the register is stored on the stack 11662306a36Sopenharmony_ci * and are the offset from the top of the eBPF JIT scratch space. 11762306a36Sopenharmony_ci */ 11862306a36Sopenharmony_ci#define STACK_OFFSET(k) (-4 - (k) * 4) 11962306a36Sopenharmony_ci#define SCRATCH_SIZE (BPF_JIT_SCRATCH_REGS * 4) 12062306a36Sopenharmony_ci 12162306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 12262306a36Sopenharmony_ci#define EBPF_SCRATCH_TO_ARM_FP(x) ((x) - 4 * hweight16(CALLEE_PUSH_MASK) - 4) 12362306a36Sopenharmony_ci#else 12462306a36Sopenharmony_ci#define EBPF_SCRATCH_TO_ARM_FP(x) (x) 12562306a36Sopenharmony_ci#endif 12662306a36Sopenharmony_ci 12762306a36Sopenharmony_ci#define TMP_REG_1 (MAX_BPF_JIT_REG + 0) /* TEMP Register 1 */ 12862306a36Sopenharmony_ci#define TMP_REG_2 (MAX_BPF_JIT_REG + 1) /* TEMP Register 2 */ 12962306a36Sopenharmony_ci#define TCALL_CNT (MAX_BPF_JIT_REG + 2) /* Tail Call Count */ 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci#define FLAG_IMM_OVERFLOW (1 << 0) 13262306a36Sopenharmony_ci 13362306a36Sopenharmony_ci/* 13462306a36Sopenharmony_ci * Map eBPF registers to ARM 32bit registers or stack scratch space. 13562306a36Sopenharmony_ci * 13662306a36Sopenharmony_ci * 1. First argument is passed using the arm 32bit registers and rest of the 13762306a36Sopenharmony_ci * arguments are passed on stack scratch space. 13862306a36Sopenharmony_ci * 2. First callee-saved argument is mapped to arm 32 bit registers and rest 13962306a36Sopenharmony_ci * arguments are mapped to scratch space on stack. 14062306a36Sopenharmony_ci * 3. We need two 64 bit temp registers to do complex operations on eBPF 14162306a36Sopenharmony_ci * registers. 14262306a36Sopenharmony_ci * 14362306a36Sopenharmony_ci * As the eBPF registers are all 64 bit registers and arm has only 32 bit 14462306a36Sopenharmony_ci * registers, we have to map each eBPF registers with two arm 32 bit regs or 14562306a36Sopenharmony_ci * scratch memory space and we have to build eBPF 64 bit register from those. 14662306a36Sopenharmony_ci * 14762306a36Sopenharmony_ci */ 14862306a36Sopenharmony_cistatic const s8 bpf2a32[][2] = { 14962306a36Sopenharmony_ci /* return value from in-kernel function, and exit value from eBPF */ 15062306a36Sopenharmony_ci [BPF_REG_0] = {ARM_R1, ARM_R0}, 15162306a36Sopenharmony_ci /* arguments from eBPF program to in-kernel function */ 15262306a36Sopenharmony_ci [BPF_REG_1] = {ARM_R3, ARM_R2}, 15362306a36Sopenharmony_ci /* Stored on stack scratch space */ 15462306a36Sopenharmony_ci [BPF_REG_2] = {STACK_OFFSET(BPF_R2_HI), STACK_OFFSET(BPF_R2_LO)}, 15562306a36Sopenharmony_ci [BPF_REG_3] = {STACK_OFFSET(BPF_R3_HI), STACK_OFFSET(BPF_R3_LO)}, 15662306a36Sopenharmony_ci [BPF_REG_4] = {STACK_OFFSET(BPF_R4_HI), STACK_OFFSET(BPF_R4_LO)}, 15762306a36Sopenharmony_ci [BPF_REG_5] = {STACK_OFFSET(BPF_R5_HI), STACK_OFFSET(BPF_R5_LO)}, 15862306a36Sopenharmony_ci /* callee saved registers that in-kernel function will preserve */ 15962306a36Sopenharmony_ci [BPF_REG_6] = {ARM_R5, ARM_R4}, 16062306a36Sopenharmony_ci /* Stored on stack scratch space */ 16162306a36Sopenharmony_ci [BPF_REG_7] = {STACK_OFFSET(BPF_R7_HI), STACK_OFFSET(BPF_R7_LO)}, 16262306a36Sopenharmony_ci [BPF_REG_8] = {STACK_OFFSET(BPF_R8_HI), STACK_OFFSET(BPF_R8_LO)}, 16362306a36Sopenharmony_ci [BPF_REG_9] = {STACK_OFFSET(BPF_R9_HI), STACK_OFFSET(BPF_R9_LO)}, 16462306a36Sopenharmony_ci /* Read only Frame Pointer to access Stack */ 16562306a36Sopenharmony_ci [BPF_REG_FP] = {STACK_OFFSET(BPF_FP_HI), STACK_OFFSET(BPF_FP_LO)}, 16662306a36Sopenharmony_ci /* Temporary Register for BPF JIT, can be used 16762306a36Sopenharmony_ci * for constant blindings and others. 16862306a36Sopenharmony_ci */ 16962306a36Sopenharmony_ci [TMP_REG_1] = {ARM_R7, ARM_R6}, 17062306a36Sopenharmony_ci [TMP_REG_2] = {ARM_R9, ARM_R8}, 17162306a36Sopenharmony_ci /* Tail call count. Stored on stack scratch space. */ 17262306a36Sopenharmony_ci [TCALL_CNT] = {STACK_OFFSET(BPF_TC_HI), STACK_OFFSET(BPF_TC_LO)}, 17362306a36Sopenharmony_ci /* temporary register for blinding constants. 17462306a36Sopenharmony_ci * Stored on stack scratch space. 17562306a36Sopenharmony_ci */ 17662306a36Sopenharmony_ci [BPF_REG_AX] = {STACK_OFFSET(BPF_AX_HI), STACK_OFFSET(BPF_AX_LO)}, 17762306a36Sopenharmony_ci}; 17862306a36Sopenharmony_ci 17962306a36Sopenharmony_ci#define dst_lo dst[1] 18062306a36Sopenharmony_ci#define dst_hi dst[0] 18162306a36Sopenharmony_ci#define src_lo src[1] 18262306a36Sopenharmony_ci#define src_hi src[0] 18362306a36Sopenharmony_ci 18462306a36Sopenharmony_ci/* 18562306a36Sopenharmony_ci * JIT Context: 18662306a36Sopenharmony_ci * 18762306a36Sopenharmony_ci * prog : bpf_prog 18862306a36Sopenharmony_ci * idx : index of current last JITed instruction. 18962306a36Sopenharmony_ci * prologue_bytes : bytes used in prologue. 19062306a36Sopenharmony_ci * epilogue_offset : offset of epilogue starting. 19162306a36Sopenharmony_ci * offsets : array of eBPF instruction offsets in 19262306a36Sopenharmony_ci * JITed code. 19362306a36Sopenharmony_ci * target : final JITed code. 19462306a36Sopenharmony_ci * epilogue_bytes : no of bytes used in epilogue. 19562306a36Sopenharmony_ci * imm_count : no of immediate counts used for global 19662306a36Sopenharmony_ci * variables. 19762306a36Sopenharmony_ci * imms : array of global variable addresses. 19862306a36Sopenharmony_ci */ 19962306a36Sopenharmony_ci 20062306a36Sopenharmony_cistruct jit_ctx { 20162306a36Sopenharmony_ci const struct bpf_prog *prog; 20262306a36Sopenharmony_ci unsigned int idx; 20362306a36Sopenharmony_ci unsigned int prologue_bytes; 20462306a36Sopenharmony_ci unsigned int epilogue_offset; 20562306a36Sopenharmony_ci unsigned int cpu_architecture; 20662306a36Sopenharmony_ci u32 flags; 20762306a36Sopenharmony_ci u32 *offsets; 20862306a36Sopenharmony_ci u32 *target; 20962306a36Sopenharmony_ci u32 stack_size; 21062306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7 21162306a36Sopenharmony_ci u16 epilogue_bytes; 21262306a36Sopenharmony_ci u16 imm_count; 21362306a36Sopenharmony_ci u32 *imms; 21462306a36Sopenharmony_ci#endif 21562306a36Sopenharmony_ci}; 21662306a36Sopenharmony_ci 21762306a36Sopenharmony_ci/* 21862306a36Sopenharmony_ci * Wrappers which handle both OABI and EABI and assures Thumb2 interworking 21962306a36Sopenharmony_ci * (where the assembly routines like __aeabi_uidiv could cause problems). 22062306a36Sopenharmony_ci */ 22162306a36Sopenharmony_cistatic u32 jit_udiv32(u32 dividend, u32 divisor) 22262306a36Sopenharmony_ci{ 22362306a36Sopenharmony_ci return dividend / divisor; 22462306a36Sopenharmony_ci} 22562306a36Sopenharmony_ci 22662306a36Sopenharmony_cistatic u32 jit_mod32(u32 dividend, u32 divisor) 22762306a36Sopenharmony_ci{ 22862306a36Sopenharmony_ci return dividend % divisor; 22962306a36Sopenharmony_ci} 23062306a36Sopenharmony_ci 23162306a36Sopenharmony_cistatic inline void _emit(int cond, u32 inst, struct jit_ctx *ctx) 23262306a36Sopenharmony_ci{ 23362306a36Sopenharmony_ci inst |= (cond << 28); 23462306a36Sopenharmony_ci inst = __opcode_to_mem_arm(inst); 23562306a36Sopenharmony_ci 23662306a36Sopenharmony_ci if (ctx->target != NULL) 23762306a36Sopenharmony_ci ctx->target[ctx->idx] = inst; 23862306a36Sopenharmony_ci 23962306a36Sopenharmony_ci ctx->idx++; 24062306a36Sopenharmony_ci} 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci/* 24362306a36Sopenharmony_ci * Emit an instruction that will be executed unconditionally. 24462306a36Sopenharmony_ci */ 24562306a36Sopenharmony_cistatic inline void emit(u32 inst, struct jit_ctx *ctx) 24662306a36Sopenharmony_ci{ 24762306a36Sopenharmony_ci _emit(ARM_COND_AL, inst, ctx); 24862306a36Sopenharmony_ci} 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci/* 25162306a36Sopenharmony_ci * This is rather horrid, but necessary to convert an integer constant 25262306a36Sopenharmony_ci * to an immediate operand for the opcodes, and be able to detect at 25362306a36Sopenharmony_ci * build time whether the constant can't be converted (iow, usable in 25462306a36Sopenharmony_ci * BUILD_BUG_ON()). 25562306a36Sopenharmony_ci */ 25662306a36Sopenharmony_ci#define imm12val(v, s) (rol32(v, (s)) | (s) << 7) 25762306a36Sopenharmony_ci#define const_imm8m(x) \ 25862306a36Sopenharmony_ci ({ int r; \ 25962306a36Sopenharmony_ci u32 v = (x); \ 26062306a36Sopenharmony_ci if (!(v & ~0x000000ff)) \ 26162306a36Sopenharmony_ci r = imm12val(v, 0); \ 26262306a36Sopenharmony_ci else if (!(v & ~0xc000003f)) \ 26362306a36Sopenharmony_ci r = imm12val(v, 2); \ 26462306a36Sopenharmony_ci else if (!(v & ~0xf000000f)) \ 26562306a36Sopenharmony_ci r = imm12val(v, 4); \ 26662306a36Sopenharmony_ci else if (!(v & ~0xfc000003)) \ 26762306a36Sopenharmony_ci r = imm12val(v, 6); \ 26862306a36Sopenharmony_ci else if (!(v & ~0xff000000)) \ 26962306a36Sopenharmony_ci r = imm12val(v, 8); \ 27062306a36Sopenharmony_ci else if (!(v & ~0x3fc00000)) \ 27162306a36Sopenharmony_ci r = imm12val(v, 10); \ 27262306a36Sopenharmony_ci else if (!(v & ~0x0ff00000)) \ 27362306a36Sopenharmony_ci r = imm12val(v, 12); \ 27462306a36Sopenharmony_ci else if (!(v & ~0x03fc0000)) \ 27562306a36Sopenharmony_ci r = imm12val(v, 14); \ 27662306a36Sopenharmony_ci else if (!(v & ~0x00ff0000)) \ 27762306a36Sopenharmony_ci r = imm12val(v, 16); \ 27862306a36Sopenharmony_ci else if (!(v & ~0x003fc000)) \ 27962306a36Sopenharmony_ci r = imm12val(v, 18); \ 28062306a36Sopenharmony_ci else if (!(v & ~0x000ff000)) \ 28162306a36Sopenharmony_ci r = imm12val(v, 20); \ 28262306a36Sopenharmony_ci else if (!(v & ~0x0003fc00)) \ 28362306a36Sopenharmony_ci r = imm12val(v, 22); \ 28462306a36Sopenharmony_ci else if (!(v & ~0x0000ff00)) \ 28562306a36Sopenharmony_ci r = imm12val(v, 24); \ 28662306a36Sopenharmony_ci else if (!(v & ~0x00003fc0)) \ 28762306a36Sopenharmony_ci r = imm12val(v, 26); \ 28862306a36Sopenharmony_ci else if (!(v & ~0x00000ff0)) \ 28962306a36Sopenharmony_ci r = imm12val(v, 28); \ 29062306a36Sopenharmony_ci else if (!(v & ~0x000003fc)) \ 29162306a36Sopenharmony_ci r = imm12val(v, 30); \ 29262306a36Sopenharmony_ci else \ 29362306a36Sopenharmony_ci r = -1; \ 29462306a36Sopenharmony_ci r; }) 29562306a36Sopenharmony_ci 29662306a36Sopenharmony_ci/* 29762306a36Sopenharmony_ci * Checks if immediate value can be converted to imm12(12 bits) value. 29862306a36Sopenharmony_ci */ 29962306a36Sopenharmony_cistatic int imm8m(u32 x) 30062306a36Sopenharmony_ci{ 30162306a36Sopenharmony_ci u32 rot; 30262306a36Sopenharmony_ci 30362306a36Sopenharmony_ci for (rot = 0; rot < 16; rot++) 30462306a36Sopenharmony_ci if ((x & ~ror32(0xff, 2 * rot)) == 0) 30562306a36Sopenharmony_ci return rol32(x, 2 * rot) | (rot << 8); 30662306a36Sopenharmony_ci return -1; 30762306a36Sopenharmony_ci} 30862306a36Sopenharmony_ci 30962306a36Sopenharmony_ci#define imm8m(x) (__builtin_constant_p(x) ? const_imm8m(x) : imm8m(x)) 31062306a36Sopenharmony_ci 31162306a36Sopenharmony_cistatic u32 arm_bpf_ldst_imm12(u32 op, u8 rt, u8 rn, s16 imm12) 31262306a36Sopenharmony_ci{ 31362306a36Sopenharmony_ci op |= rt << 12 | rn << 16; 31462306a36Sopenharmony_ci if (imm12 >= 0) 31562306a36Sopenharmony_ci op |= ARM_INST_LDST__U; 31662306a36Sopenharmony_ci else 31762306a36Sopenharmony_ci imm12 = -imm12; 31862306a36Sopenharmony_ci return op | (imm12 & ARM_INST_LDST__IMM12); 31962306a36Sopenharmony_ci} 32062306a36Sopenharmony_ci 32162306a36Sopenharmony_cistatic u32 arm_bpf_ldst_imm8(u32 op, u8 rt, u8 rn, s16 imm8) 32262306a36Sopenharmony_ci{ 32362306a36Sopenharmony_ci op |= rt << 12 | rn << 16; 32462306a36Sopenharmony_ci if (imm8 >= 0) 32562306a36Sopenharmony_ci op |= ARM_INST_LDST__U; 32662306a36Sopenharmony_ci else 32762306a36Sopenharmony_ci imm8 = -imm8; 32862306a36Sopenharmony_ci return op | (imm8 & 0xf0) << 4 | (imm8 & 0x0f); 32962306a36Sopenharmony_ci} 33062306a36Sopenharmony_ci 33162306a36Sopenharmony_ci#define ARM_LDR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDR_I, rt, rn, off) 33262306a36Sopenharmony_ci#define ARM_LDRB_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_LDRB_I, rt, rn, off) 33362306a36Sopenharmony_ci#define ARM_LDRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRD_I, rt, rn, off) 33462306a36Sopenharmony_ci#define ARM_LDRH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_LDRH_I, rt, rn, off) 33562306a36Sopenharmony_ci 33662306a36Sopenharmony_ci#define ARM_STR_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STR_I, rt, rn, off) 33762306a36Sopenharmony_ci#define ARM_STRB_I(rt, rn, off) arm_bpf_ldst_imm12(ARM_INST_STRB_I, rt, rn, off) 33862306a36Sopenharmony_ci#define ARM_STRD_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_STRD_I, rt, rn, off) 33962306a36Sopenharmony_ci#define ARM_STRH_I(rt, rn, off) arm_bpf_ldst_imm8(ARM_INST_STRH_I, rt, rn, off) 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_ci/* 34262306a36Sopenharmony_ci * Initializes the JIT space with undefined instructions. 34362306a36Sopenharmony_ci */ 34462306a36Sopenharmony_cistatic void jit_fill_hole(void *area, unsigned int size) 34562306a36Sopenharmony_ci{ 34662306a36Sopenharmony_ci u32 *ptr; 34762306a36Sopenharmony_ci /* We are guaranteed to have aligned memory. */ 34862306a36Sopenharmony_ci for (ptr = area; size >= sizeof(u32); size -= sizeof(u32)) 34962306a36Sopenharmony_ci *ptr++ = __opcode_to_mem_arm(ARM_INST_UDF); 35062306a36Sopenharmony_ci} 35162306a36Sopenharmony_ci 35262306a36Sopenharmony_ci#if defined(CONFIG_AEABI) && (__LINUX_ARM_ARCH__ >= 5) 35362306a36Sopenharmony_ci/* EABI requires the stack to be aligned to 64-bit boundaries */ 35462306a36Sopenharmony_ci#define STACK_ALIGNMENT 8 35562306a36Sopenharmony_ci#else 35662306a36Sopenharmony_ci/* Stack must be aligned to 32-bit boundaries */ 35762306a36Sopenharmony_ci#define STACK_ALIGNMENT 4 35862306a36Sopenharmony_ci#endif 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* total stack size used in JITed code */ 36162306a36Sopenharmony_ci#define _STACK_SIZE (ctx->prog->aux->stack_depth + SCRATCH_SIZE) 36262306a36Sopenharmony_ci#define STACK_SIZE ALIGN(_STACK_SIZE, STACK_ALIGNMENT) 36362306a36Sopenharmony_ci 36462306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_cistatic u16 imm_offset(u32 k, struct jit_ctx *ctx) 36762306a36Sopenharmony_ci{ 36862306a36Sopenharmony_ci unsigned int i = 0, offset; 36962306a36Sopenharmony_ci u16 imm; 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_ci /* on the "fake" run we just count them (duplicates included) */ 37262306a36Sopenharmony_ci if (ctx->target == NULL) { 37362306a36Sopenharmony_ci ctx->imm_count++; 37462306a36Sopenharmony_ci return 0; 37562306a36Sopenharmony_ci } 37662306a36Sopenharmony_ci 37762306a36Sopenharmony_ci while ((i < ctx->imm_count) && ctx->imms[i]) { 37862306a36Sopenharmony_ci if (ctx->imms[i] == k) 37962306a36Sopenharmony_ci break; 38062306a36Sopenharmony_ci i++; 38162306a36Sopenharmony_ci } 38262306a36Sopenharmony_ci 38362306a36Sopenharmony_ci if (ctx->imms[i] == 0) 38462306a36Sopenharmony_ci ctx->imms[i] = k; 38562306a36Sopenharmony_ci 38662306a36Sopenharmony_ci /* constants go just after the epilogue */ 38762306a36Sopenharmony_ci offset = ctx->offsets[ctx->prog->len - 1] * 4; 38862306a36Sopenharmony_ci offset += ctx->prologue_bytes; 38962306a36Sopenharmony_ci offset += ctx->epilogue_bytes; 39062306a36Sopenharmony_ci offset += i * 4; 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_ci ctx->target[offset / 4] = k; 39362306a36Sopenharmony_ci 39462306a36Sopenharmony_ci /* PC in ARM mode == address of the instruction + 8 */ 39562306a36Sopenharmony_ci imm = offset - (8 + ctx->idx * 4); 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci if (imm & ~0xfff) { 39862306a36Sopenharmony_ci /* 39962306a36Sopenharmony_ci * literal pool is too far, signal it into flags. we 40062306a36Sopenharmony_ci * can only detect it on the second pass unfortunately. 40162306a36Sopenharmony_ci */ 40262306a36Sopenharmony_ci ctx->flags |= FLAG_IMM_OVERFLOW; 40362306a36Sopenharmony_ci return 0; 40462306a36Sopenharmony_ci } 40562306a36Sopenharmony_ci 40662306a36Sopenharmony_ci return imm; 40762306a36Sopenharmony_ci} 40862306a36Sopenharmony_ci 40962306a36Sopenharmony_ci#endif /* __LINUX_ARM_ARCH__ */ 41062306a36Sopenharmony_ci 41162306a36Sopenharmony_cistatic inline int bpf2a32_offset(int bpf_to, int bpf_from, 41262306a36Sopenharmony_ci const struct jit_ctx *ctx) { 41362306a36Sopenharmony_ci int to, from; 41462306a36Sopenharmony_ci 41562306a36Sopenharmony_ci if (ctx->target == NULL) 41662306a36Sopenharmony_ci return 0; 41762306a36Sopenharmony_ci to = ctx->offsets[bpf_to]; 41862306a36Sopenharmony_ci from = ctx->offsets[bpf_from]; 41962306a36Sopenharmony_ci 42062306a36Sopenharmony_ci return to - from - 1; 42162306a36Sopenharmony_ci} 42262306a36Sopenharmony_ci 42362306a36Sopenharmony_ci/* 42462306a36Sopenharmony_ci * Move an immediate that's not an imm8m to a core register. 42562306a36Sopenharmony_ci */ 42662306a36Sopenharmony_cistatic inline void emit_mov_i_no8m(const u8 rd, u32 val, struct jit_ctx *ctx) 42762306a36Sopenharmony_ci{ 42862306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7 42962306a36Sopenharmony_ci emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx); 43062306a36Sopenharmony_ci#else 43162306a36Sopenharmony_ci emit(ARM_MOVW(rd, val & 0xffff), ctx); 43262306a36Sopenharmony_ci if (val > 0xffff) 43362306a36Sopenharmony_ci emit(ARM_MOVT(rd, val >> 16), ctx); 43462306a36Sopenharmony_ci#endif 43562306a36Sopenharmony_ci} 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_cistatic inline void emit_mov_i(const u8 rd, u32 val, struct jit_ctx *ctx) 43862306a36Sopenharmony_ci{ 43962306a36Sopenharmony_ci int imm12 = imm8m(val); 44062306a36Sopenharmony_ci 44162306a36Sopenharmony_ci if (imm12 >= 0) 44262306a36Sopenharmony_ci emit(ARM_MOV_I(rd, imm12), ctx); 44362306a36Sopenharmony_ci else 44462306a36Sopenharmony_ci emit_mov_i_no8m(rd, val, ctx); 44562306a36Sopenharmony_ci} 44662306a36Sopenharmony_ci 44762306a36Sopenharmony_cistatic void emit_bx_r(u8 tgt_reg, struct jit_ctx *ctx) 44862306a36Sopenharmony_ci{ 44962306a36Sopenharmony_ci if (elf_hwcap & HWCAP_THUMB) 45062306a36Sopenharmony_ci emit(ARM_BX(tgt_reg), ctx); 45162306a36Sopenharmony_ci else 45262306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx); 45362306a36Sopenharmony_ci} 45462306a36Sopenharmony_ci 45562306a36Sopenharmony_cistatic inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) 45662306a36Sopenharmony_ci{ 45762306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 5 45862306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); 45962306a36Sopenharmony_ci emit_bx_r(tgt_reg, ctx); 46062306a36Sopenharmony_ci#else 46162306a36Sopenharmony_ci emit(ARM_BLX_R(tgt_reg), ctx); 46262306a36Sopenharmony_ci#endif 46362306a36Sopenharmony_ci} 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_cistatic inline int epilogue_offset(const struct jit_ctx *ctx) 46662306a36Sopenharmony_ci{ 46762306a36Sopenharmony_ci int to, from; 46862306a36Sopenharmony_ci /* No need for 1st dummy run */ 46962306a36Sopenharmony_ci if (ctx->target == NULL) 47062306a36Sopenharmony_ci return 0; 47162306a36Sopenharmony_ci to = ctx->epilogue_offset; 47262306a36Sopenharmony_ci from = ctx->idx; 47362306a36Sopenharmony_ci 47462306a36Sopenharmony_ci return to - from - 2; 47562306a36Sopenharmony_ci} 47662306a36Sopenharmony_ci 47762306a36Sopenharmony_cistatic inline void emit_udivmod(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx, u8 op) 47862306a36Sopenharmony_ci{ 47962306a36Sopenharmony_ci const int exclude_mask = BIT(ARM_R0) | BIT(ARM_R1); 48062306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 48162306a36Sopenharmony_ci 48262306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ == 7 48362306a36Sopenharmony_ci if (elf_hwcap & HWCAP_IDIVA) { 48462306a36Sopenharmony_ci if (op == BPF_DIV) 48562306a36Sopenharmony_ci emit(ARM_UDIV(rd, rm, rn), ctx); 48662306a36Sopenharmony_ci else { 48762306a36Sopenharmony_ci emit(ARM_UDIV(ARM_IP, rm, rn), ctx); 48862306a36Sopenharmony_ci emit(ARM_MLS(rd, rn, ARM_IP, rm), ctx); 48962306a36Sopenharmony_ci } 49062306a36Sopenharmony_ci return; 49162306a36Sopenharmony_ci } 49262306a36Sopenharmony_ci#endif 49362306a36Sopenharmony_ci 49462306a36Sopenharmony_ci /* 49562306a36Sopenharmony_ci * For BPF_ALU | BPF_DIV | BPF_K instructions 49662306a36Sopenharmony_ci * As ARM_R1 and ARM_R0 contains 1st argument of bpf 49762306a36Sopenharmony_ci * function, we need to save it on caller side to save 49862306a36Sopenharmony_ci * it from getting destroyed within callee. 49962306a36Sopenharmony_ci * After the return from the callee, we restore ARM_R0 50062306a36Sopenharmony_ci * ARM_R1. 50162306a36Sopenharmony_ci */ 50262306a36Sopenharmony_ci if (rn != ARM_R1) { 50362306a36Sopenharmony_ci emit(ARM_MOV_R(tmp[0], ARM_R1), ctx); 50462306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_R1, rn), ctx); 50562306a36Sopenharmony_ci } 50662306a36Sopenharmony_ci if (rm != ARM_R0) { 50762306a36Sopenharmony_ci emit(ARM_MOV_R(tmp[1], ARM_R0), ctx); 50862306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_R0, rm), ctx); 50962306a36Sopenharmony_ci } 51062306a36Sopenharmony_ci 51162306a36Sopenharmony_ci /* Push caller-saved registers on stack */ 51262306a36Sopenharmony_ci emit(ARM_PUSH(CALLER_MASK & ~exclude_mask), ctx); 51362306a36Sopenharmony_ci 51462306a36Sopenharmony_ci /* Call appropriate function */ 51562306a36Sopenharmony_ci emit_mov_i(ARM_IP, op == BPF_DIV ? 51662306a36Sopenharmony_ci (u32)jit_udiv32 : (u32)jit_mod32, ctx); 51762306a36Sopenharmony_ci emit_blx_r(ARM_IP, ctx); 51862306a36Sopenharmony_ci 51962306a36Sopenharmony_ci /* Restore caller-saved registers from stack */ 52062306a36Sopenharmony_ci emit(ARM_POP(CALLER_MASK & ~exclude_mask), ctx); 52162306a36Sopenharmony_ci 52262306a36Sopenharmony_ci /* Save return value */ 52362306a36Sopenharmony_ci if (rd != ARM_R0) 52462306a36Sopenharmony_ci emit(ARM_MOV_R(rd, ARM_R0), ctx); 52562306a36Sopenharmony_ci 52662306a36Sopenharmony_ci /* Restore ARM_R0 and ARM_R1 */ 52762306a36Sopenharmony_ci if (rn != ARM_R1) 52862306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_R1, tmp[0]), ctx); 52962306a36Sopenharmony_ci if (rm != ARM_R0) 53062306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_R0, tmp[1]), ctx); 53162306a36Sopenharmony_ci} 53262306a36Sopenharmony_ci 53362306a36Sopenharmony_ci/* Is the translated BPF register on stack? */ 53462306a36Sopenharmony_cistatic bool is_stacked(s8 reg) 53562306a36Sopenharmony_ci{ 53662306a36Sopenharmony_ci return reg < 0; 53762306a36Sopenharmony_ci} 53862306a36Sopenharmony_ci 53962306a36Sopenharmony_ci/* If a BPF register is on the stack (stk is true), load it to the 54062306a36Sopenharmony_ci * supplied temporary register and return the temporary register 54162306a36Sopenharmony_ci * for subsequent operations, otherwise just use the CPU register. 54262306a36Sopenharmony_ci */ 54362306a36Sopenharmony_cistatic s8 arm_bpf_get_reg32(s8 reg, s8 tmp, struct jit_ctx *ctx) 54462306a36Sopenharmony_ci{ 54562306a36Sopenharmony_ci if (is_stacked(reg)) { 54662306a36Sopenharmony_ci emit(ARM_LDR_I(tmp, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx); 54762306a36Sopenharmony_ci reg = tmp; 54862306a36Sopenharmony_ci } 54962306a36Sopenharmony_ci return reg; 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_cistatic const s8 *arm_bpf_get_reg64(const s8 *reg, const s8 *tmp, 55362306a36Sopenharmony_ci struct jit_ctx *ctx) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci if (is_stacked(reg[1])) { 55662306a36Sopenharmony_ci if (__LINUX_ARM_ARCH__ >= 6 || 55762306a36Sopenharmony_ci ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) { 55862306a36Sopenharmony_ci emit(ARM_LDRD_I(tmp[1], ARM_FP, 55962306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx); 56062306a36Sopenharmony_ci } else { 56162306a36Sopenharmony_ci emit(ARM_LDR_I(tmp[1], ARM_FP, 56262306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx); 56362306a36Sopenharmony_ci emit(ARM_LDR_I(tmp[0], ARM_FP, 56462306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx); 56562306a36Sopenharmony_ci } 56662306a36Sopenharmony_ci reg = tmp; 56762306a36Sopenharmony_ci } 56862306a36Sopenharmony_ci return reg; 56962306a36Sopenharmony_ci} 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci/* If a BPF register is on the stack (stk is true), save the register 57262306a36Sopenharmony_ci * back to the stack. If the source register is not the same, then 57362306a36Sopenharmony_ci * move it into the correct register. 57462306a36Sopenharmony_ci */ 57562306a36Sopenharmony_cistatic void arm_bpf_put_reg32(s8 reg, s8 src, struct jit_ctx *ctx) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci if (is_stacked(reg)) 57862306a36Sopenharmony_ci emit(ARM_STR_I(src, ARM_FP, EBPF_SCRATCH_TO_ARM_FP(reg)), ctx); 57962306a36Sopenharmony_ci else if (reg != src) 58062306a36Sopenharmony_ci emit(ARM_MOV_R(reg, src), ctx); 58162306a36Sopenharmony_ci} 58262306a36Sopenharmony_ci 58362306a36Sopenharmony_cistatic void arm_bpf_put_reg64(const s8 *reg, const s8 *src, 58462306a36Sopenharmony_ci struct jit_ctx *ctx) 58562306a36Sopenharmony_ci{ 58662306a36Sopenharmony_ci if (is_stacked(reg[1])) { 58762306a36Sopenharmony_ci if (__LINUX_ARM_ARCH__ >= 6 || 58862306a36Sopenharmony_ci ctx->cpu_architecture >= CPU_ARCH_ARMv5TE) { 58962306a36Sopenharmony_ci emit(ARM_STRD_I(src[1], ARM_FP, 59062306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx); 59162306a36Sopenharmony_ci } else { 59262306a36Sopenharmony_ci emit(ARM_STR_I(src[1], ARM_FP, 59362306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[1])), ctx); 59462306a36Sopenharmony_ci emit(ARM_STR_I(src[0], ARM_FP, 59562306a36Sopenharmony_ci EBPF_SCRATCH_TO_ARM_FP(reg[0])), ctx); 59662306a36Sopenharmony_ci } 59762306a36Sopenharmony_ci } else { 59862306a36Sopenharmony_ci if (reg[1] != src[1]) 59962306a36Sopenharmony_ci emit(ARM_MOV_R(reg[1], src[1]), ctx); 60062306a36Sopenharmony_ci if (reg[0] != src[0]) 60162306a36Sopenharmony_ci emit(ARM_MOV_R(reg[0], src[0]), ctx); 60262306a36Sopenharmony_ci } 60362306a36Sopenharmony_ci} 60462306a36Sopenharmony_ci 60562306a36Sopenharmony_cistatic inline void emit_a32_mov_i(const s8 dst, const u32 val, 60662306a36Sopenharmony_ci struct jit_ctx *ctx) 60762306a36Sopenharmony_ci{ 60862306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 60962306a36Sopenharmony_ci 61062306a36Sopenharmony_ci if (is_stacked(dst)) { 61162306a36Sopenharmony_ci emit_mov_i(tmp[1], val, ctx); 61262306a36Sopenharmony_ci arm_bpf_put_reg32(dst, tmp[1], ctx); 61362306a36Sopenharmony_ci } else { 61462306a36Sopenharmony_ci emit_mov_i(dst, val, ctx); 61562306a36Sopenharmony_ci } 61662306a36Sopenharmony_ci} 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_cistatic void emit_a32_mov_i64(const s8 dst[], u64 val, struct jit_ctx *ctx) 61962306a36Sopenharmony_ci{ 62062306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 62162306a36Sopenharmony_ci const s8 *rd = is_stacked(dst_lo) ? tmp : dst; 62262306a36Sopenharmony_ci 62362306a36Sopenharmony_ci emit_mov_i(rd[1], (u32)val, ctx); 62462306a36Sopenharmony_ci emit_mov_i(rd[0], val >> 32, ctx); 62562306a36Sopenharmony_ci 62662306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 62762306a36Sopenharmony_ci} 62862306a36Sopenharmony_ci 62962306a36Sopenharmony_ci/* Sign extended move */ 63062306a36Sopenharmony_cistatic inline void emit_a32_mov_se_i64(const bool is64, const s8 dst[], 63162306a36Sopenharmony_ci const u32 val, struct jit_ctx *ctx) { 63262306a36Sopenharmony_ci u64 val64 = val; 63362306a36Sopenharmony_ci 63462306a36Sopenharmony_ci if (is64 && (val & (1<<31))) 63562306a36Sopenharmony_ci val64 |= 0xffffffff00000000ULL; 63662306a36Sopenharmony_ci emit_a32_mov_i64(dst, val64, ctx); 63762306a36Sopenharmony_ci} 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_cistatic inline void emit_a32_add_r(const u8 dst, const u8 src, 64062306a36Sopenharmony_ci const bool is64, const bool hi, 64162306a36Sopenharmony_ci struct jit_ctx *ctx) { 64262306a36Sopenharmony_ci /* 64 bit : 64362306a36Sopenharmony_ci * adds dst_lo, dst_lo, src_lo 64462306a36Sopenharmony_ci * adc dst_hi, dst_hi, src_hi 64562306a36Sopenharmony_ci * 32 bit : 64662306a36Sopenharmony_ci * add dst_lo, dst_lo, src_lo 64762306a36Sopenharmony_ci */ 64862306a36Sopenharmony_ci if (!hi && is64) 64962306a36Sopenharmony_ci emit(ARM_ADDS_R(dst, dst, src), ctx); 65062306a36Sopenharmony_ci else if (hi && is64) 65162306a36Sopenharmony_ci emit(ARM_ADC_R(dst, dst, src), ctx); 65262306a36Sopenharmony_ci else 65362306a36Sopenharmony_ci emit(ARM_ADD_R(dst, dst, src), ctx); 65462306a36Sopenharmony_ci} 65562306a36Sopenharmony_ci 65662306a36Sopenharmony_cistatic inline void emit_a32_sub_r(const u8 dst, const u8 src, 65762306a36Sopenharmony_ci const bool is64, const bool hi, 65862306a36Sopenharmony_ci struct jit_ctx *ctx) { 65962306a36Sopenharmony_ci /* 64 bit : 66062306a36Sopenharmony_ci * subs dst_lo, dst_lo, src_lo 66162306a36Sopenharmony_ci * sbc dst_hi, dst_hi, src_hi 66262306a36Sopenharmony_ci * 32 bit : 66362306a36Sopenharmony_ci * sub dst_lo, dst_lo, src_lo 66462306a36Sopenharmony_ci */ 66562306a36Sopenharmony_ci if (!hi && is64) 66662306a36Sopenharmony_ci emit(ARM_SUBS_R(dst, dst, src), ctx); 66762306a36Sopenharmony_ci else if (hi && is64) 66862306a36Sopenharmony_ci emit(ARM_SBC_R(dst, dst, src), ctx); 66962306a36Sopenharmony_ci else 67062306a36Sopenharmony_ci emit(ARM_SUB_R(dst, dst, src), ctx); 67162306a36Sopenharmony_ci} 67262306a36Sopenharmony_ci 67362306a36Sopenharmony_cistatic inline void emit_alu_r(const u8 dst, const u8 src, const bool is64, 67462306a36Sopenharmony_ci const bool hi, const u8 op, struct jit_ctx *ctx){ 67562306a36Sopenharmony_ci switch (BPF_OP(op)) { 67662306a36Sopenharmony_ci /* dst = dst + src */ 67762306a36Sopenharmony_ci case BPF_ADD: 67862306a36Sopenharmony_ci emit_a32_add_r(dst, src, is64, hi, ctx); 67962306a36Sopenharmony_ci break; 68062306a36Sopenharmony_ci /* dst = dst - src */ 68162306a36Sopenharmony_ci case BPF_SUB: 68262306a36Sopenharmony_ci emit_a32_sub_r(dst, src, is64, hi, ctx); 68362306a36Sopenharmony_ci break; 68462306a36Sopenharmony_ci /* dst = dst | src */ 68562306a36Sopenharmony_ci case BPF_OR: 68662306a36Sopenharmony_ci emit(ARM_ORR_R(dst, dst, src), ctx); 68762306a36Sopenharmony_ci break; 68862306a36Sopenharmony_ci /* dst = dst & src */ 68962306a36Sopenharmony_ci case BPF_AND: 69062306a36Sopenharmony_ci emit(ARM_AND_R(dst, dst, src), ctx); 69162306a36Sopenharmony_ci break; 69262306a36Sopenharmony_ci /* dst = dst ^ src */ 69362306a36Sopenharmony_ci case BPF_XOR: 69462306a36Sopenharmony_ci emit(ARM_EOR_R(dst, dst, src), ctx); 69562306a36Sopenharmony_ci break; 69662306a36Sopenharmony_ci /* dst = dst * src */ 69762306a36Sopenharmony_ci case BPF_MUL: 69862306a36Sopenharmony_ci emit(ARM_MUL(dst, dst, src), ctx); 69962306a36Sopenharmony_ci break; 70062306a36Sopenharmony_ci /* dst = dst << src */ 70162306a36Sopenharmony_ci case BPF_LSH: 70262306a36Sopenharmony_ci emit(ARM_LSL_R(dst, dst, src), ctx); 70362306a36Sopenharmony_ci break; 70462306a36Sopenharmony_ci /* dst = dst >> src */ 70562306a36Sopenharmony_ci case BPF_RSH: 70662306a36Sopenharmony_ci emit(ARM_LSR_R(dst, dst, src), ctx); 70762306a36Sopenharmony_ci break; 70862306a36Sopenharmony_ci /* dst = dst >> src (signed)*/ 70962306a36Sopenharmony_ci case BPF_ARSH: 71062306a36Sopenharmony_ci emit(ARM_MOV_SR(dst, dst, SRTYPE_ASR, src), ctx); 71162306a36Sopenharmony_ci break; 71262306a36Sopenharmony_ci } 71362306a36Sopenharmony_ci} 71462306a36Sopenharmony_ci 71562306a36Sopenharmony_ci/* ALU operation (64 bit) */ 71662306a36Sopenharmony_cistatic inline void emit_a32_alu_r64(const bool is64, const s8 dst[], 71762306a36Sopenharmony_ci const s8 src[], struct jit_ctx *ctx, 71862306a36Sopenharmony_ci const u8 op) { 71962306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 72062306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 72162306a36Sopenharmony_ci const s8 *rd; 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 72462306a36Sopenharmony_ci if (is64) { 72562306a36Sopenharmony_ci const s8 *rs; 72662306a36Sopenharmony_ci 72762306a36Sopenharmony_ci rs = arm_bpf_get_reg64(src, tmp2, ctx); 72862306a36Sopenharmony_ci 72962306a36Sopenharmony_ci /* ALU operation */ 73062306a36Sopenharmony_ci emit_alu_r(rd[1], rs[1], true, false, op, ctx); 73162306a36Sopenharmony_ci emit_alu_r(rd[0], rs[0], true, true, op, ctx); 73262306a36Sopenharmony_ci } else { 73362306a36Sopenharmony_ci s8 rs; 73462306a36Sopenharmony_ci 73562306a36Sopenharmony_ci rs = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 73662306a36Sopenharmony_ci 73762306a36Sopenharmony_ci /* ALU operation */ 73862306a36Sopenharmony_ci emit_alu_r(rd[1], rs, true, false, op, ctx); 73962306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 74062306a36Sopenharmony_ci emit_a32_mov_i(rd[0], 0, ctx); 74162306a36Sopenharmony_ci } 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 74462306a36Sopenharmony_ci} 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci/* dst = src (4 bytes)*/ 74762306a36Sopenharmony_cistatic inline void emit_a32_mov_r(const s8 dst, const s8 src, 74862306a36Sopenharmony_ci struct jit_ctx *ctx) { 74962306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 75062306a36Sopenharmony_ci s8 rt; 75162306a36Sopenharmony_ci 75262306a36Sopenharmony_ci rt = arm_bpf_get_reg32(src, tmp[0], ctx); 75362306a36Sopenharmony_ci arm_bpf_put_reg32(dst, rt, ctx); 75462306a36Sopenharmony_ci} 75562306a36Sopenharmony_ci 75662306a36Sopenharmony_ci/* dst = src */ 75762306a36Sopenharmony_cistatic inline void emit_a32_mov_r64(const bool is64, const s8 dst[], 75862306a36Sopenharmony_ci const s8 src[], 75962306a36Sopenharmony_ci struct jit_ctx *ctx) { 76062306a36Sopenharmony_ci if (!is64) { 76162306a36Sopenharmony_ci emit_a32_mov_r(dst_lo, src_lo, ctx); 76262306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 76362306a36Sopenharmony_ci /* Zero out high 4 bytes */ 76462306a36Sopenharmony_ci emit_a32_mov_i(dst_hi, 0, ctx); 76562306a36Sopenharmony_ci } else if (__LINUX_ARM_ARCH__ < 6 && 76662306a36Sopenharmony_ci ctx->cpu_architecture < CPU_ARCH_ARMv5TE) { 76762306a36Sopenharmony_ci /* complete 8 byte move */ 76862306a36Sopenharmony_ci emit_a32_mov_r(dst_lo, src_lo, ctx); 76962306a36Sopenharmony_ci emit_a32_mov_r(dst_hi, src_hi, ctx); 77062306a36Sopenharmony_ci } else if (is_stacked(src_lo) && is_stacked(dst_lo)) { 77162306a36Sopenharmony_ci const u8 *tmp = bpf2a32[TMP_REG_1]; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci emit(ARM_LDRD_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx); 77462306a36Sopenharmony_ci emit(ARM_STRD_I(tmp[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(dst_lo)), ctx); 77562306a36Sopenharmony_ci } else if (is_stacked(src_lo)) { 77662306a36Sopenharmony_ci emit(ARM_LDRD_I(dst[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(src_lo)), ctx); 77762306a36Sopenharmony_ci } else if (is_stacked(dst_lo)) { 77862306a36Sopenharmony_ci emit(ARM_STRD_I(src[1], ARM_FP, EBPF_SCRATCH_TO_ARM_FP(dst_lo)), ctx); 77962306a36Sopenharmony_ci } else { 78062306a36Sopenharmony_ci emit(ARM_MOV_R(dst[0], src[0]), ctx); 78162306a36Sopenharmony_ci emit(ARM_MOV_R(dst[1], src[1]), ctx); 78262306a36Sopenharmony_ci } 78362306a36Sopenharmony_ci} 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci/* Shift operations */ 78662306a36Sopenharmony_cistatic inline void emit_a32_alu_i(const s8 dst, const u32 val, 78762306a36Sopenharmony_ci struct jit_ctx *ctx, const u8 op) { 78862306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 78962306a36Sopenharmony_ci s8 rd; 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_ci rd = arm_bpf_get_reg32(dst, tmp[0], ctx); 79262306a36Sopenharmony_ci 79362306a36Sopenharmony_ci /* Do shift operation */ 79462306a36Sopenharmony_ci switch (op) { 79562306a36Sopenharmony_ci case BPF_LSH: 79662306a36Sopenharmony_ci emit(ARM_LSL_I(rd, rd, val), ctx); 79762306a36Sopenharmony_ci break; 79862306a36Sopenharmony_ci case BPF_RSH: 79962306a36Sopenharmony_ci emit(ARM_LSR_I(rd, rd, val), ctx); 80062306a36Sopenharmony_ci break; 80162306a36Sopenharmony_ci case BPF_ARSH: 80262306a36Sopenharmony_ci emit(ARM_ASR_I(rd, rd, val), ctx); 80362306a36Sopenharmony_ci break; 80462306a36Sopenharmony_ci case BPF_NEG: 80562306a36Sopenharmony_ci emit(ARM_RSB_I(rd, rd, val), ctx); 80662306a36Sopenharmony_ci break; 80762306a36Sopenharmony_ci } 80862306a36Sopenharmony_ci 80962306a36Sopenharmony_ci arm_bpf_put_reg32(dst, rd, ctx); 81062306a36Sopenharmony_ci} 81162306a36Sopenharmony_ci 81262306a36Sopenharmony_ci/* dst = ~dst (64 bit) */ 81362306a36Sopenharmony_cistatic inline void emit_a32_neg64(const s8 dst[], 81462306a36Sopenharmony_ci struct jit_ctx *ctx){ 81562306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 81662306a36Sopenharmony_ci const s8 *rd; 81762306a36Sopenharmony_ci 81862306a36Sopenharmony_ci /* Setup Operand */ 81962306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 82062306a36Sopenharmony_ci 82162306a36Sopenharmony_ci /* Do Negate Operation */ 82262306a36Sopenharmony_ci emit(ARM_RSBS_I(rd[1], rd[1], 0), ctx); 82362306a36Sopenharmony_ci emit(ARM_RSC_I(rd[0], rd[0], 0), ctx); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 82662306a36Sopenharmony_ci} 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci/* dst = dst << src */ 82962306a36Sopenharmony_cistatic inline void emit_a32_lsh_r64(const s8 dst[], const s8 src[], 83062306a36Sopenharmony_ci struct jit_ctx *ctx) { 83162306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 83262306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 83362306a36Sopenharmony_ci const s8 *rd; 83462306a36Sopenharmony_ci s8 rt; 83562306a36Sopenharmony_ci 83662306a36Sopenharmony_ci /* Setup Operands */ 83762306a36Sopenharmony_ci rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 83862306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 83962306a36Sopenharmony_ci 84062306a36Sopenharmony_ci /* Do LSH operation */ 84162306a36Sopenharmony_ci emit(ARM_SUB_I(ARM_IP, rt, 32), ctx); 84262306a36Sopenharmony_ci emit(ARM_RSB_I(tmp2[0], rt, 32), ctx); 84362306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_LR, rd[0], SRTYPE_ASL, rt), ctx); 84462306a36Sopenharmony_ci emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[1], SRTYPE_ASL, ARM_IP), ctx); 84562306a36Sopenharmony_ci emit(ARM_ORR_SR(ARM_IP, ARM_LR, rd[1], SRTYPE_LSR, tmp2[0]), ctx); 84662306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_ASL, rt), ctx); 84762306a36Sopenharmony_ci 84862306a36Sopenharmony_ci arm_bpf_put_reg32(dst_lo, ARM_LR, ctx); 84962306a36Sopenharmony_ci arm_bpf_put_reg32(dst_hi, ARM_IP, ctx); 85062306a36Sopenharmony_ci} 85162306a36Sopenharmony_ci 85262306a36Sopenharmony_ci/* dst = dst >> src (signed)*/ 85362306a36Sopenharmony_cistatic inline void emit_a32_arsh_r64(const s8 dst[], const s8 src[], 85462306a36Sopenharmony_ci struct jit_ctx *ctx) { 85562306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 85662306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 85762306a36Sopenharmony_ci const s8 *rd; 85862306a36Sopenharmony_ci s8 rt; 85962306a36Sopenharmony_ci 86062306a36Sopenharmony_ci /* Setup Operands */ 86162306a36Sopenharmony_ci rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 86262306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 86362306a36Sopenharmony_ci 86462306a36Sopenharmony_ci /* Do the ARSH operation */ 86562306a36Sopenharmony_ci emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); 86662306a36Sopenharmony_ci emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); 86762306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_LSR, rt), ctx); 86862306a36Sopenharmony_ci emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASL, ARM_IP), ctx); 86962306a36Sopenharmony_ci _emit(ARM_COND_PL, 87062306a36Sopenharmony_ci ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASR, tmp2[0]), ctx); 87162306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_IP, rd[0], SRTYPE_ASR, rt), ctx); 87262306a36Sopenharmony_ci 87362306a36Sopenharmony_ci arm_bpf_put_reg32(dst_lo, ARM_LR, ctx); 87462306a36Sopenharmony_ci arm_bpf_put_reg32(dst_hi, ARM_IP, ctx); 87562306a36Sopenharmony_ci} 87662306a36Sopenharmony_ci 87762306a36Sopenharmony_ci/* dst = dst >> src */ 87862306a36Sopenharmony_cistatic inline void emit_a32_rsh_r64(const s8 dst[], const s8 src[], 87962306a36Sopenharmony_ci struct jit_ctx *ctx) { 88062306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 88162306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 88262306a36Sopenharmony_ci const s8 *rd; 88362306a36Sopenharmony_ci s8 rt; 88462306a36Sopenharmony_ci 88562306a36Sopenharmony_ci /* Setup Operands */ 88662306a36Sopenharmony_ci rt = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 88762306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 88862306a36Sopenharmony_ci 88962306a36Sopenharmony_ci /* Do RSH operation */ 89062306a36Sopenharmony_ci emit(ARM_RSB_I(ARM_IP, rt, 32), ctx); 89162306a36Sopenharmony_ci emit(ARM_SUBS_I(tmp2[0], rt, 32), ctx); 89262306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_LR, rd[1], SRTYPE_LSR, rt), ctx); 89362306a36Sopenharmony_ci emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_ASL, ARM_IP), ctx); 89462306a36Sopenharmony_ci emit(ARM_ORR_SR(ARM_LR, ARM_LR, rd[0], SRTYPE_LSR, tmp2[0]), ctx); 89562306a36Sopenharmony_ci emit(ARM_MOV_SR(ARM_IP, rd[0], SRTYPE_LSR, rt), ctx); 89662306a36Sopenharmony_ci 89762306a36Sopenharmony_ci arm_bpf_put_reg32(dst_lo, ARM_LR, ctx); 89862306a36Sopenharmony_ci arm_bpf_put_reg32(dst_hi, ARM_IP, ctx); 89962306a36Sopenharmony_ci} 90062306a36Sopenharmony_ci 90162306a36Sopenharmony_ci/* dst = dst << val */ 90262306a36Sopenharmony_cistatic inline void emit_a32_lsh_i64(const s8 dst[], 90362306a36Sopenharmony_ci const u32 val, struct jit_ctx *ctx){ 90462306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 90562306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 90662306a36Sopenharmony_ci const s8 *rd; 90762306a36Sopenharmony_ci 90862306a36Sopenharmony_ci /* Setup operands */ 90962306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 91062306a36Sopenharmony_ci 91162306a36Sopenharmony_ci /* Do LSH operation */ 91262306a36Sopenharmony_ci if (val < 32) { 91362306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[0], rd[0], SRTYPE_ASL, val), ctx); 91462306a36Sopenharmony_ci emit(ARM_ORR_SI(rd[0], tmp2[0], rd[1], SRTYPE_LSR, 32 - val), ctx); 91562306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[1], rd[1], SRTYPE_ASL, val), ctx); 91662306a36Sopenharmony_ci } else { 91762306a36Sopenharmony_ci if (val == 32) 91862306a36Sopenharmony_ci emit(ARM_MOV_R(rd[0], rd[1]), ctx); 91962306a36Sopenharmony_ci else 92062306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[0], rd[1], SRTYPE_ASL, val - 32), ctx); 92162306a36Sopenharmony_ci emit(ARM_EOR_R(rd[1], rd[1], rd[1]), ctx); 92262306a36Sopenharmony_ci } 92362306a36Sopenharmony_ci 92462306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 92562306a36Sopenharmony_ci} 92662306a36Sopenharmony_ci 92762306a36Sopenharmony_ci/* dst = dst >> val */ 92862306a36Sopenharmony_cistatic inline void emit_a32_rsh_i64(const s8 dst[], 92962306a36Sopenharmony_ci const u32 val, struct jit_ctx *ctx) { 93062306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 93162306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 93262306a36Sopenharmony_ci const s8 *rd; 93362306a36Sopenharmony_ci 93462306a36Sopenharmony_ci /* Setup operands */ 93562306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 93662306a36Sopenharmony_ci 93762306a36Sopenharmony_ci /* Do LSR operation */ 93862306a36Sopenharmony_ci if (val == 0) { 93962306a36Sopenharmony_ci /* An immediate value of 0 encodes a shift amount of 32 94062306a36Sopenharmony_ci * for LSR. To shift by 0, don't do anything. 94162306a36Sopenharmony_ci */ 94262306a36Sopenharmony_ci } else if (val < 32) { 94362306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx); 94462306a36Sopenharmony_ci emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx); 94562306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_LSR, val), ctx); 94662306a36Sopenharmony_ci } else if (val == 32) { 94762306a36Sopenharmony_ci emit(ARM_MOV_R(rd[1], rd[0]), ctx); 94862306a36Sopenharmony_ci emit(ARM_MOV_I(rd[0], 0), ctx); 94962306a36Sopenharmony_ci } else { 95062306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[1], rd[0], SRTYPE_LSR, val - 32), ctx); 95162306a36Sopenharmony_ci emit(ARM_MOV_I(rd[0], 0), ctx); 95262306a36Sopenharmony_ci } 95362306a36Sopenharmony_ci 95462306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 95562306a36Sopenharmony_ci} 95662306a36Sopenharmony_ci 95762306a36Sopenharmony_ci/* dst = dst >> val (signed) */ 95862306a36Sopenharmony_cistatic inline void emit_a32_arsh_i64(const s8 dst[], 95962306a36Sopenharmony_ci const u32 val, struct jit_ctx *ctx){ 96062306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 96162306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 96262306a36Sopenharmony_ci const s8 *rd; 96362306a36Sopenharmony_ci 96462306a36Sopenharmony_ci /* Setup operands */ 96562306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 96662306a36Sopenharmony_ci 96762306a36Sopenharmony_ci /* Do ARSH operation */ 96862306a36Sopenharmony_ci if (val == 0) { 96962306a36Sopenharmony_ci /* An immediate value of 0 encodes a shift amount of 32 97062306a36Sopenharmony_ci * for ASR. To shift by 0, don't do anything. 97162306a36Sopenharmony_ci */ 97262306a36Sopenharmony_ci } else if (val < 32) { 97362306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[1], rd[1], SRTYPE_LSR, val), ctx); 97462306a36Sopenharmony_ci emit(ARM_ORR_SI(rd[1], tmp2[1], rd[0], SRTYPE_ASL, 32 - val), ctx); 97562306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, val), ctx); 97662306a36Sopenharmony_ci } else if (val == 32) { 97762306a36Sopenharmony_ci emit(ARM_MOV_R(rd[1], rd[0]), ctx); 97862306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, 31), ctx); 97962306a36Sopenharmony_ci } else { 98062306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[1], rd[0], SRTYPE_ASR, val - 32), ctx); 98162306a36Sopenharmony_ci emit(ARM_MOV_SI(rd[0], rd[0], SRTYPE_ASR, 31), ctx); 98262306a36Sopenharmony_ci } 98362306a36Sopenharmony_ci 98462306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 98562306a36Sopenharmony_ci} 98662306a36Sopenharmony_ci 98762306a36Sopenharmony_cistatic inline void emit_a32_mul_r64(const s8 dst[], const s8 src[], 98862306a36Sopenharmony_ci struct jit_ctx *ctx) { 98962306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 99062306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 99162306a36Sopenharmony_ci const s8 *rd, *rt; 99262306a36Sopenharmony_ci 99362306a36Sopenharmony_ci /* Setup operands for multiplication */ 99462306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 99562306a36Sopenharmony_ci rt = arm_bpf_get_reg64(src, tmp2, ctx); 99662306a36Sopenharmony_ci 99762306a36Sopenharmony_ci /* Do Multiplication */ 99862306a36Sopenharmony_ci emit(ARM_MUL(ARM_IP, rd[1], rt[0]), ctx); 99962306a36Sopenharmony_ci emit(ARM_MUL(ARM_LR, rd[0], rt[1]), ctx); 100062306a36Sopenharmony_ci emit(ARM_ADD_R(ARM_LR, ARM_IP, ARM_LR), ctx); 100162306a36Sopenharmony_ci 100262306a36Sopenharmony_ci emit(ARM_UMULL(ARM_IP, rd[0], rd[1], rt[1]), ctx); 100362306a36Sopenharmony_ci emit(ARM_ADD_R(rd[0], ARM_LR, rd[0]), ctx); 100462306a36Sopenharmony_ci 100562306a36Sopenharmony_ci arm_bpf_put_reg32(dst_lo, ARM_IP, ctx); 100662306a36Sopenharmony_ci arm_bpf_put_reg32(dst_hi, rd[0], ctx); 100762306a36Sopenharmony_ci} 100862306a36Sopenharmony_ci 100962306a36Sopenharmony_cistatic bool is_ldst_imm(s16 off, const u8 size) 101062306a36Sopenharmony_ci{ 101162306a36Sopenharmony_ci s16 off_max = 0; 101262306a36Sopenharmony_ci 101362306a36Sopenharmony_ci switch (size) { 101462306a36Sopenharmony_ci case BPF_B: 101562306a36Sopenharmony_ci case BPF_W: 101662306a36Sopenharmony_ci off_max = 0xfff; 101762306a36Sopenharmony_ci break; 101862306a36Sopenharmony_ci case BPF_H: 101962306a36Sopenharmony_ci off_max = 0xff; 102062306a36Sopenharmony_ci break; 102162306a36Sopenharmony_ci case BPF_DW: 102262306a36Sopenharmony_ci /* Need to make sure off+4 does not overflow. */ 102362306a36Sopenharmony_ci off_max = 0xfff - 4; 102462306a36Sopenharmony_ci break; 102562306a36Sopenharmony_ci } 102662306a36Sopenharmony_ci return -off_max <= off && off <= off_max; 102762306a36Sopenharmony_ci} 102862306a36Sopenharmony_ci 102962306a36Sopenharmony_ci/* *(size *)(dst + off) = src */ 103062306a36Sopenharmony_cistatic inline void emit_str_r(const s8 dst, const s8 src[], 103162306a36Sopenharmony_ci s16 off, struct jit_ctx *ctx, const u8 sz){ 103262306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 103362306a36Sopenharmony_ci s8 rd; 103462306a36Sopenharmony_ci 103562306a36Sopenharmony_ci rd = arm_bpf_get_reg32(dst, tmp[1], ctx); 103662306a36Sopenharmony_ci 103762306a36Sopenharmony_ci if (!is_ldst_imm(off, sz)) { 103862306a36Sopenharmony_ci emit_a32_mov_i(tmp[0], off, ctx); 103962306a36Sopenharmony_ci emit(ARM_ADD_R(tmp[0], tmp[0], rd), ctx); 104062306a36Sopenharmony_ci rd = tmp[0]; 104162306a36Sopenharmony_ci off = 0; 104262306a36Sopenharmony_ci } 104362306a36Sopenharmony_ci switch (sz) { 104462306a36Sopenharmony_ci case BPF_B: 104562306a36Sopenharmony_ci /* Store a Byte */ 104662306a36Sopenharmony_ci emit(ARM_STRB_I(src_lo, rd, off), ctx); 104762306a36Sopenharmony_ci break; 104862306a36Sopenharmony_ci case BPF_H: 104962306a36Sopenharmony_ci /* Store a HalfWord */ 105062306a36Sopenharmony_ci emit(ARM_STRH_I(src_lo, rd, off), ctx); 105162306a36Sopenharmony_ci break; 105262306a36Sopenharmony_ci case BPF_W: 105362306a36Sopenharmony_ci /* Store a Word */ 105462306a36Sopenharmony_ci emit(ARM_STR_I(src_lo, rd, off), ctx); 105562306a36Sopenharmony_ci break; 105662306a36Sopenharmony_ci case BPF_DW: 105762306a36Sopenharmony_ci /* Store a Double Word */ 105862306a36Sopenharmony_ci emit(ARM_STR_I(src_lo, rd, off), ctx); 105962306a36Sopenharmony_ci emit(ARM_STR_I(src_hi, rd, off + 4), ctx); 106062306a36Sopenharmony_ci break; 106162306a36Sopenharmony_ci } 106262306a36Sopenharmony_ci} 106362306a36Sopenharmony_ci 106462306a36Sopenharmony_ci/* dst = *(size*)(src + off) */ 106562306a36Sopenharmony_cistatic inline void emit_ldx_r(const s8 dst[], const s8 src, 106662306a36Sopenharmony_ci s16 off, struct jit_ctx *ctx, const u8 sz){ 106762306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 106862306a36Sopenharmony_ci const s8 *rd = is_stacked(dst_lo) ? tmp : dst; 106962306a36Sopenharmony_ci s8 rm = src; 107062306a36Sopenharmony_ci 107162306a36Sopenharmony_ci if (!is_ldst_imm(off, sz)) { 107262306a36Sopenharmony_ci emit_a32_mov_i(tmp[0], off, ctx); 107362306a36Sopenharmony_ci emit(ARM_ADD_R(tmp[0], tmp[0], src), ctx); 107462306a36Sopenharmony_ci rm = tmp[0]; 107562306a36Sopenharmony_ci off = 0; 107662306a36Sopenharmony_ci } else if (rd[1] == rm) { 107762306a36Sopenharmony_ci emit(ARM_MOV_R(tmp[0], rm), ctx); 107862306a36Sopenharmony_ci rm = tmp[0]; 107962306a36Sopenharmony_ci } 108062306a36Sopenharmony_ci switch (sz) { 108162306a36Sopenharmony_ci case BPF_B: 108262306a36Sopenharmony_ci /* Load a Byte */ 108362306a36Sopenharmony_ci emit(ARM_LDRB_I(rd[1], rm, off), ctx); 108462306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 108562306a36Sopenharmony_ci emit_a32_mov_i(rd[0], 0, ctx); 108662306a36Sopenharmony_ci break; 108762306a36Sopenharmony_ci case BPF_H: 108862306a36Sopenharmony_ci /* Load a HalfWord */ 108962306a36Sopenharmony_ci emit(ARM_LDRH_I(rd[1], rm, off), ctx); 109062306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 109162306a36Sopenharmony_ci emit_a32_mov_i(rd[0], 0, ctx); 109262306a36Sopenharmony_ci break; 109362306a36Sopenharmony_ci case BPF_W: 109462306a36Sopenharmony_ci /* Load a Word */ 109562306a36Sopenharmony_ci emit(ARM_LDR_I(rd[1], rm, off), ctx); 109662306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 109762306a36Sopenharmony_ci emit_a32_mov_i(rd[0], 0, ctx); 109862306a36Sopenharmony_ci break; 109962306a36Sopenharmony_ci case BPF_DW: 110062306a36Sopenharmony_ci /* Load a Double Word */ 110162306a36Sopenharmony_ci emit(ARM_LDR_I(rd[1], rm, off), ctx); 110262306a36Sopenharmony_ci emit(ARM_LDR_I(rd[0], rm, off + 4), ctx); 110362306a36Sopenharmony_ci break; 110462306a36Sopenharmony_ci } 110562306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 110662306a36Sopenharmony_ci} 110762306a36Sopenharmony_ci 110862306a36Sopenharmony_ci/* Arithmatic Operation */ 110962306a36Sopenharmony_cistatic inline void emit_ar_r(const u8 rd, const u8 rt, const u8 rm, 111062306a36Sopenharmony_ci const u8 rn, struct jit_ctx *ctx, u8 op, 111162306a36Sopenharmony_ci bool is_jmp64) { 111262306a36Sopenharmony_ci switch (op) { 111362306a36Sopenharmony_ci case BPF_JSET: 111462306a36Sopenharmony_ci if (is_jmp64) { 111562306a36Sopenharmony_ci emit(ARM_AND_R(ARM_IP, rt, rn), ctx); 111662306a36Sopenharmony_ci emit(ARM_AND_R(ARM_LR, rd, rm), ctx); 111762306a36Sopenharmony_ci emit(ARM_ORRS_R(ARM_IP, ARM_LR, ARM_IP), ctx); 111862306a36Sopenharmony_ci } else { 111962306a36Sopenharmony_ci emit(ARM_ANDS_R(ARM_IP, rt, rn), ctx); 112062306a36Sopenharmony_ci } 112162306a36Sopenharmony_ci break; 112262306a36Sopenharmony_ci case BPF_JEQ: 112362306a36Sopenharmony_ci case BPF_JNE: 112462306a36Sopenharmony_ci case BPF_JGT: 112562306a36Sopenharmony_ci case BPF_JGE: 112662306a36Sopenharmony_ci case BPF_JLE: 112762306a36Sopenharmony_ci case BPF_JLT: 112862306a36Sopenharmony_ci if (is_jmp64) { 112962306a36Sopenharmony_ci emit(ARM_CMP_R(rd, rm), ctx); 113062306a36Sopenharmony_ci /* Only compare low halve if high halve are equal. */ 113162306a36Sopenharmony_ci _emit(ARM_COND_EQ, ARM_CMP_R(rt, rn), ctx); 113262306a36Sopenharmony_ci } else { 113362306a36Sopenharmony_ci emit(ARM_CMP_R(rt, rn), ctx); 113462306a36Sopenharmony_ci } 113562306a36Sopenharmony_ci break; 113662306a36Sopenharmony_ci case BPF_JSLE: 113762306a36Sopenharmony_ci case BPF_JSGT: 113862306a36Sopenharmony_ci emit(ARM_CMP_R(rn, rt), ctx); 113962306a36Sopenharmony_ci if (is_jmp64) 114062306a36Sopenharmony_ci emit(ARM_SBCS_R(ARM_IP, rm, rd), ctx); 114162306a36Sopenharmony_ci break; 114262306a36Sopenharmony_ci case BPF_JSLT: 114362306a36Sopenharmony_ci case BPF_JSGE: 114462306a36Sopenharmony_ci emit(ARM_CMP_R(rt, rn), ctx); 114562306a36Sopenharmony_ci if (is_jmp64) 114662306a36Sopenharmony_ci emit(ARM_SBCS_R(ARM_IP, rd, rm), ctx); 114762306a36Sopenharmony_ci break; 114862306a36Sopenharmony_ci } 114962306a36Sopenharmony_ci} 115062306a36Sopenharmony_ci 115162306a36Sopenharmony_cistatic int out_offset = -1; /* initialized on the first pass of build_body() */ 115262306a36Sopenharmony_cistatic int emit_bpf_tail_call(struct jit_ctx *ctx) 115362306a36Sopenharmony_ci{ 115462306a36Sopenharmony_ci 115562306a36Sopenharmony_ci /* bpf_tail_call(void *prog_ctx, struct bpf_array *array, u64 index) */ 115662306a36Sopenharmony_ci const s8 *r2 = bpf2a32[BPF_REG_2]; 115762306a36Sopenharmony_ci const s8 *r3 = bpf2a32[BPF_REG_3]; 115862306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 115962306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 116062306a36Sopenharmony_ci const s8 *tcc = bpf2a32[TCALL_CNT]; 116162306a36Sopenharmony_ci const s8 *tc; 116262306a36Sopenharmony_ci const int idx0 = ctx->idx; 116362306a36Sopenharmony_ci#define cur_offset (ctx->idx - idx0) 116462306a36Sopenharmony_ci#define jmp_offset (out_offset - (cur_offset) - 2) 116562306a36Sopenharmony_ci u32 lo, hi; 116662306a36Sopenharmony_ci s8 r_array, r_index; 116762306a36Sopenharmony_ci int off; 116862306a36Sopenharmony_ci 116962306a36Sopenharmony_ci /* if (index >= array->map.max_entries) 117062306a36Sopenharmony_ci * goto out; 117162306a36Sopenharmony_ci */ 117262306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct bpf_array, map.max_entries) > 117362306a36Sopenharmony_ci ARM_INST_LDST__IMM12); 117462306a36Sopenharmony_ci off = offsetof(struct bpf_array, map.max_entries); 117562306a36Sopenharmony_ci r_array = arm_bpf_get_reg32(r2[1], tmp2[0], ctx); 117662306a36Sopenharmony_ci /* index is 32-bit for arrays */ 117762306a36Sopenharmony_ci r_index = arm_bpf_get_reg32(r3[1], tmp2[1], ctx); 117862306a36Sopenharmony_ci /* array->map.max_entries */ 117962306a36Sopenharmony_ci emit(ARM_LDR_I(tmp[1], r_array, off), ctx); 118062306a36Sopenharmony_ci /* index >= array->map.max_entries */ 118162306a36Sopenharmony_ci emit(ARM_CMP_R(r_index, tmp[1]), ctx); 118262306a36Sopenharmony_ci _emit(ARM_COND_CS, ARM_B(jmp_offset), ctx); 118362306a36Sopenharmony_ci 118462306a36Sopenharmony_ci /* tmp2[0] = array, tmp2[1] = index */ 118562306a36Sopenharmony_ci 118662306a36Sopenharmony_ci /* 118762306a36Sopenharmony_ci * if (tail_call_cnt >= MAX_TAIL_CALL_CNT) 118862306a36Sopenharmony_ci * goto out; 118962306a36Sopenharmony_ci * tail_call_cnt++; 119062306a36Sopenharmony_ci */ 119162306a36Sopenharmony_ci lo = (u32)MAX_TAIL_CALL_CNT; 119262306a36Sopenharmony_ci hi = (u32)((u64)MAX_TAIL_CALL_CNT >> 32); 119362306a36Sopenharmony_ci tc = arm_bpf_get_reg64(tcc, tmp, ctx); 119462306a36Sopenharmony_ci emit(ARM_CMP_I(tc[0], hi), ctx); 119562306a36Sopenharmony_ci _emit(ARM_COND_EQ, ARM_CMP_I(tc[1], lo), ctx); 119662306a36Sopenharmony_ci _emit(ARM_COND_CS, ARM_B(jmp_offset), ctx); 119762306a36Sopenharmony_ci emit(ARM_ADDS_I(tc[1], tc[1], 1), ctx); 119862306a36Sopenharmony_ci emit(ARM_ADC_I(tc[0], tc[0], 0), ctx); 119962306a36Sopenharmony_ci arm_bpf_put_reg64(tcc, tmp, ctx); 120062306a36Sopenharmony_ci 120162306a36Sopenharmony_ci /* prog = array->ptrs[index] 120262306a36Sopenharmony_ci * if (prog == NULL) 120362306a36Sopenharmony_ci * goto out; 120462306a36Sopenharmony_ci */ 120562306a36Sopenharmony_ci BUILD_BUG_ON(imm8m(offsetof(struct bpf_array, ptrs)) < 0); 120662306a36Sopenharmony_ci off = imm8m(offsetof(struct bpf_array, ptrs)); 120762306a36Sopenharmony_ci emit(ARM_ADD_I(tmp[1], r_array, off), ctx); 120862306a36Sopenharmony_ci emit(ARM_LDR_R_SI(tmp[1], tmp[1], r_index, SRTYPE_ASL, 2), ctx); 120962306a36Sopenharmony_ci emit(ARM_CMP_I(tmp[1], 0), ctx); 121062306a36Sopenharmony_ci _emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx); 121162306a36Sopenharmony_ci 121262306a36Sopenharmony_ci /* goto *(prog->bpf_func + prologue_size); */ 121362306a36Sopenharmony_ci BUILD_BUG_ON(offsetof(struct bpf_prog, bpf_func) > 121462306a36Sopenharmony_ci ARM_INST_LDST__IMM12); 121562306a36Sopenharmony_ci off = offsetof(struct bpf_prog, bpf_func); 121662306a36Sopenharmony_ci emit(ARM_LDR_I(tmp[1], tmp[1], off), ctx); 121762306a36Sopenharmony_ci emit(ARM_ADD_I(tmp[1], tmp[1], ctx->prologue_bytes), ctx); 121862306a36Sopenharmony_ci emit_bx_r(tmp[1], ctx); 121962306a36Sopenharmony_ci 122062306a36Sopenharmony_ci /* out: */ 122162306a36Sopenharmony_ci if (out_offset == -1) 122262306a36Sopenharmony_ci out_offset = cur_offset; 122362306a36Sopenharmony_ci if (cur_offset != out_offset) { 122462306a36Sopenharmony_ci pr_err_once("tail_call out_offset = %d, expected %d!\n", 122562306a36Sopenharmony_ci cur_offset, out_offset); 122662306a36Sopenharmony_ci return -1; 122762306a36Sopenharmony_ci } 122862306a36Sopenharmony_ci return 0; 122962306a36Sopenharmony_ci#undef cur_offset 123062306a36Sopenharmony_ci#undef jmp_offset 123162306a36Sopenharmony_ci} 123262306a36Sopenharmony_ci 123362306a36Sopenharmony_ci/* 0xabcd => 0xcdab */ 123462306a36Sopenharmony_cistatic inline void emit_rev16(const u8 rd, const u8 rn, struct jit_ctx *ctx) 123562306a36Sopenharmony_ci{ 123662306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 123762306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 123862306a36Sopenharmony_ci 123962306a36Sopenharmony_ci emit(ARM_AND_I(tmp2[1], rn, 0xff), ctx); 124062306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[0], rn, SRTYPE_LSR, 8), ctx); 124162306a36Sopenharmony_ci emit(ARM_AND_I(tmp2[0], tmp2[0], 0xff), ctx); 124262306a36Sopenharmony_ci emit(ARM_ORR_SI(rd, tmp2[0], tmp2[1], SRTYPE_LSL, 8), ctx); 124362306a36Sopenharmony_ci#else /* ARMv6+ */ 124462306a36Sopenharmony_ci emit(ARM_REV16(rd, rn), ctx); 124562306a36Sopenharmony_ci#endif 124662306a36Sopenharmony_ci} 124762306a36Sopenharmony_ci 124862306a36Sopenharmony_ci/* 0xabcdefgh => 0xghefcdab */ 124962306a36Sopenharmony_cistatic inline void emit_rev32(const u8 rd, const u8 rn, struct jit_ctx *ctx) 125062306a36Sopenharmony_ci{ 125162306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 125262306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 125362306a36Sopenharmony_ci 125462306a36Sopenharmony_ci emit(ARM_AND_I(tmp2[1], rn, 0xff), ctx); 125562306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[0], rn, SRTYPE_LSR, 24), ctx); 125662306a36Sopenharmony_ci emit(ARM_ORR_SI(ARM_IP, tmp2[0], tmp2[1], SRTYPE_LSL, 24), ctx); 125762306a36Sopenharmony_ci 125862306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[1], rn, SRTYPE_LSR, 8), ctx); 125962306a36Sopenharmony_ci emit(ARM_AND_I(tmp2[1], tmp2[1], 0xff), ctx); 126062306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[0], rn, SRTYPE_LSR, 16), ctx); 126162306a36Sopenharmony_ci emit(ARM_AND_I(tmp2[0], tmp2[0], 0xff), ctx); 126262306a36Sopenharmony_ci emit(ARM_MOV_SI(tmp2[0], tmp2[0], SRTYPE_LSL, 8), ctx); 126362306a36Sopenharmony_ci emit(ARM_ORR_SI(tmp2[0], tmp2[0], tmp2[1], SRTYPE_LSL, 16), ctx); 126462306a36Sopenharmony_ci emit(ARM_ORR_R(rd, ARM_IP, tmp2[0]), ctx); 126562306a36Sopenharmony_ci 126662306a36Sopenharmony_ci#else /* ARMv6+ */ 126762306a36Sopenharmony_ci emit(ARM_REV(rd, rn), ctx); 126862306a36Sopenharmony_ci#endif 126962306a36Sopenharmony_ci} 127062306a36Sopenharmony_ci 127162306a36Sopenharmony_ci// push the scratch stack register on top of the stack 127262306a36Sopenharmony_cistatic inline void emit_push_r64(const s8 src[], struct jit_ctx *ctx) 127362306a36Sopenharmony_ci{ 127462306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 127562306a36Sopenharmony_ci const s8 *rt; 127662306a36Sopenharmony_ci u16 reg_set = 0; 127762306a36Sopenharmony_ci 127862306a36Sopenharmony_ci rt = arm_bpf_get_reg64(src, tmp2, ctx); 127962306a36Sopenharmony_ci 128062306a36Sopenharmony_ci reg_set = (1 << rt[1]) | (1 << rt[0]); 128162306a36Sopenharmony_ci emit(ARM_PUSH(reg_set), ctx); 128262306a36Sopenharmony_ci} 128362306a36Sopenharmony_ci 128462306a36Sopenharmony_cistatic void build_prologue(struct jit_ctx *ctx) 128562306a36Sopenharmony_ci{ 128662306a36Sopenharmony_ci const s8 arm_r0 = bpf2a32[BPF_REG_0][1]; 128762306a36Sopenharmony_ci const s8 *bpf_r1 = bpf2a32[BPF_REG_1]; 128862306a36Sopenharmony_ci const s8 *bpf_fp = bpf2a32[BPF_REG_FP]; 128962306a36Sopenharmony_ci const s8 *tcc = bpf2a32[TCALL_CNT]; 129062306a36Sopenharmony_ci 129162306a36Sopenharmony_ci /* Save callee saved registers. */ 129262306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 129362306a36Sopenharmony_ci u16 reg_set = CALLEE_PUSH_MASK | 1 << ARM_IP | 1 << ARM_PC; 129462306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx); 129562306a36Sopenharmony_ci emit(ARM_PUSH(reg_set), ctx); 129662306a36Sopenharmony_ci emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx); 129762306a36Sopenharmony_ci#else 129862306a36Sopenharmony_ci emit(ARM_PUSH(CALLEE_PUSH_MASK), ctx); 129962306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_FP, ARM_SP), ctx); 130062306a36Sopenharmony_ci#endif 130162306a36Sopenharmony_ci /* mov r3, #0 */ 130262306a36Sopenharmony_ci /* sub r2, sp, #SCRATCH_SIZE */ 130362306a36Sopenharmony_ci emit(ARM_MOV_I(bpf_r1[0], 0), ctx); 130462306a36Sopenharmony_ci emit(ARM_SUB_I(bpf_r1[1], ARM_SP, SCRATCH_SIZE), ctx); 130562306a36Sopenharmony_ci 130662306a36Sopenharmony_ci ctx->stack_size = imm8m(STACK_SIZE); 130762306a36Sopenharmony_ci 130862306a36Sopenharmony_ci /* Set up function call stack */ 130962306a36Sopenharmony_ci emit(ARM_SUB_I(ARM_SP, ARM_SP, ctx->stack_size), ctx); 131062306a36Sopenharmony_ci 131162306a36Sopenharmony_ci /* Set up BPF prog stack base register */ 131262306a36Sopenharmony_ci emit_a32_mov_r64(true, bpf_fp, bpf_r1, ctx); 131362306a36Sopenharmony_ci 131462306a36Sopenharmony_ci /* Initialize Tail Count */ 131562306a36Sopenharmony_ci emit(ARM_MOV_I(bpf_r1[1], 0), ctx); 131662306a36Sopenharmony_ci emit_a32_mov_r64(true, tcc, bpf_r1, ctx); 131762306a36Sopenharmony_ci 131862306a36Sopenharmony_ci /* Move BPF_CTX to BPF_R1 */ 131962306a36Sopenharmony_ci emit(ARM_MOV_R(bpf_r1[1], arm_r0), ctx); 132062306a36Sopenharmony_ci 132162306a36Sopenharmony_ci /* end of prologue */ 132262306a36Sopenharmony_ci} 132362306a36Sopenharmony_ci 132462306a36Sopenharmony_ci/* restore callee saved registers. */ 132562306a36Sopenharmony_cistatic void build_epilogue(struct jit_ctx *ctx) 132662306a36Sopenharmony_ci{ 132762306a36Sopenharmony_ci#ifdef CONFIG_FRAME_POINTER 132862306a36Sopenharmony_ci /* When using frame pointers, some additional registers need to 132962306a36Sopenharmony_ci * be loaded. */ 133062306a36Sopenharmony_ci u16 reg_set = CALLEE_POP_MASK | 1 << ARM_SP; 133162306a36Sopenharmony_ci emit(ARM_SUB_I(ARM_SP, ARM_FP, hweight16(reg_set) * 4), ctx); 133262306a36Sopenharmony_ci emit(ARM_LDM(ARM_SP, reg_set), ctx); 133362306a36Sopenharmony_ci#else 133462306a36Sopenharmony_ci /* Restore callee saved registers. */ 133562306a36Sopenharmony_ci emit(ARM_MOV_R(ARM_SP, ARM_FP), ctx); 133662306a36Sopenharmony_ci emit(ARM_POP(CALLEE_POP_MASK), ctx); 133762306a36Sopenharmony_ci#endif 133862306a36Sopenharmony_ci} 133962306a36Sopenharmony_ci 134062306a36Sopenharmony_ci/* 134162306a36Sopenharmony_ci * Convert an eBPF instruction to native instruction, i.e 134262306a36Sopenharmony_ci * JITs an eBPF instruction. 134362306a36Sopenharmony_ci * Returns : 134462306a36Sopenharmony_ci * 0 - Successfully JITed an 8-byte eBPF instruction 134562306a36Sopenharmony_ci * >0 - Successfully JITed a 16-byte eBPF instruction 134662306a36Sopenharmony_ci * <0 - Failed to JIT. 134762306a36Sopenharmony_ci */ 134862306a36Sopenharmony_cistatic int build_insn(const struct bpf_insn *insn, struct jit_ctx *ctx) 134962306a36Sopenharmony_ci{ 135062306a36Sopenharmony_ci const u8 code = insn->code; 135162306a36Sopenharmony_ci const s8 *dst = bpf2a32[insn->dst_reg]; 135262306a36Sopenharmony_ci const s8 *src = bpf2a32[insn->src_reg]; 135362306a36Sopenharmony_ci const s8 *tmp = bpf2a32[TMP_REG_1]; 135462306a36Sopenharmony_ci const s8 *tmp2 = bpf2a32[TMP_REG_2]; 135562306a36Sopenharmony_ci const s16 off = insn->off; 135662306a36Sopenharmony_ci const s32 imm = insn->imm; 135762306a36Sopenharmony_ci const int i = insn - ctx->prog->insnsi; 135862306a36Sopenharmony_ci const bool is64 = BPF_CLASS(code) == BPF_ALU64; 135962306a36Sopenharmony_ci const s8 *rd, *rs; 136062306a36Sopenharmony_ci s8 rd_lo, rt, rm, rn; 136162306a36Sopenharmony_ci s32 jmp_offset; 136262306a36Sopenharmony_ci 136362306a36Sopenharmony_ci#define check_imm(bits, imm) do { \ 136462306a36Sopenharmony_ci if ((imm) >= (1 << ((bits) - 1)) || \ 136562306a36Sopenharmony_ci (imm) < -(1 << ((bits) - 1))) { \ 136662306a36Sopenharmony_ci pr_info("[%2d] imm=%d(0x%x) out of range\n", \ 136762306a36Sopenharmony_ci i, imm, imm); \ 136862306a36Sopenharmony_ci return -EINVAL; \ 136962306a36Sopenharmony_ci } \ 137062306a36Sopenharmony_ci} while (0) 137162306a36Sopenharmony_ci#define check_imm24(imm) check_imm(24, imm) 137262306a36Sopenharmony_ci 137362306a36Sopenharmony_ci switch (code) { 137462306a36Sopenharmony_ci /* ALU operations */ 137562306a36Sopenharmony_ci 137662306a36Sopenharmony_ci /* dst = src */ 137762306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: 137862306a36Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: 137962306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: 138062306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: 138162306a36Sopenharmony_ci switch (BPF_SRC(code)) { 138262306a36Sopenharmony_ci case BPF_X: 138362306a36Sopenharmony_ci if (imm == 1) { 138462306a36Sopenharmony_ci /* Special mov32 for zext */ 138562306a36Sopenharmony_ci emit_a32_mov_i(dst_hi, 0, ctx); 138662306a36Sopenharmony_ci break; 138762306a36Sopenharmony_ci } 138862306a36Sopenharmony_ci emit_a32_mov_r64(is64, dst, src, ctx); 138962306a36Sopenharmony_ci break; 139062306a36Sopenharmony_ci case BPF_K: 139162306a36Sopenharmony_ci /* Sign-extend immediate value to destination reg */ 139262306a36Sopenharmony_ci emit_a32_mov_se_i64(is64, dst, imm, ctx); 139362306a36Sopenharmony_ci break; 139462306a36Sopenharmony_ci } 139562306a36Sopenharmony_ci break; 139662306a36Sopenharmony_ci /* dst = dst + src/imm */ 139762306a36Sopenharmony_ci /* dst = dst - src/imm */ 139862306a36Sopenharmony_ci /* dst = dst | src/imm */ 139962306a36Sopenharmony_ci /* dst = dst & src/imm */ 140062306a36Sopenharmony_ci /* dst = dst ^ src/imm */ 140162306a36Sopenharmony_ci /* dst = dst * src/imm */ 140262306a36Sopenharmony_ci /* dst = dst << src */ 140362306a36Sopenharmony_ci /* dst = dst >> src */ 140462306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: 140562306a36Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: 140662306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: 140762306a36Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: 140862306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K: 140962306a36Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: 141062306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: 141162306a36Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: 141262306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: 141362306a36Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: 141462306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: 141562306a36Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: 141662306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: 141762306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: 141862306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: 141962306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: 142062306a36Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: 142162306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: 142262306a36Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: 142362306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K: 142462306a36Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: 142562306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: 142662306a36Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: 142762306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: 142862306a36Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: 142962306a36Sopenharmony_ci switch (BPF_SRC(code)) { 143062306a36Sopenharmony_ci case BPF_X: 143162306a36Sopenharmony_ci emit_a32_alu_r64(is64, dst, src, ctx, BPF_OP(code)); 143262306a36Sopenharmony_ci break; 143362306a36Sopenharmony_ci case BPF_K: 143462306a36Sopenharmony_ci /* Move immediate value to the temporary register 143562306a36Sopenharmony_ci * and then do the ALU operation on the temporary 143662306a36Sopenharmony_ci * register as this will sign-extend the immediate 143762306a36Sopenharmony_ci * value into temporary reg and then it would be 143862306a36Sopenharmony_ci * safe to do the operation on it. 143962306a36Sopenharmony_ci */ 144062306a36Sopenharmony_ci emit_a32_mov_se_i64(is64, tmp2, imm, ctx); 144162306a36Sopenharmony_ci emit_a32_alu_r64(is64, dst, tmp2, ctx, BPF_OP(code)); 144262306a36Sopenharmony_ci break; 144362306a36Sopenharmony_ci } 144462306a36Sopenharmony_ci break; 144562306a36Sopenharmony_ci /* dst = dst / src(imm) */ 144662306a36Sopenharmony_ci /* dst = dst % src(imm) */ 144762306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: 144862306a36Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: 144962306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: 145062306a36Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: 145162306a36Sopenharmony_ci rd_lo = arm_bpf_get_reg32(dst_lo, tmp2[1], ctx); 145262306a36Sopenharmony_ci switch (BPF_SRC(code)) { 145362306a36Sopenharmony_ci case BPF_X: 145462306a36Sopenharmony_ci rt = arm_bpf_get_reg32(src_lo, tmp2[0], ctx); 145562306a36Sopenharmony_ci break; 145662306a36Sopenharmony_ci case BPF_K: 145762306a36Sopenharmony_ci rt = tmp2[0]; 145862306a36Sopenharmony_ci emit_a32_mov_i(rt, imm, ctx); 145962306a36Sopenharmony_ci break; 146062306a36Sopenharmony_ci default: 146162306a36Sopenharmony_ci rt = src_lo; 146262306a36Sopenharmony_ci break; 146362306a36Sopenharmony_ci } 146462306a36Sopenharmony_ci emit_udivmod(rd_lo, rd_lo, rt, ctx, BPF_OP(code)); 146562306a36Sopenharmony_ci arm_bpf_put_reg32(dst_lo, rd_lo, ctx); 146662306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 146762306a36Sopenharmony_ci emit_a32_mov_i(dst_hi, 0, ctx); 146862306a36Sopenharmony_ci break; 146962306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: 147062306a36Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: 147162306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: 147262306a36Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: 147362306a36Sopenharmony_ci goto notyet; 147462306a36Sopenharmony_ci /* dst = dst << imm */ 147562306a36Sopenharmony_ci /* dst = dst >> imm */ 147662306a36Sopenharmony_ci /* dst = dst >> imm (signed) */ 147762306a36Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: 147862306a36Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: 147962306a36Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: 148062306a36Sopenharmony_ci if (unlikely(imm > 31)) 148162306a36Sopenharmony_ci return -EINVAL; 148262306a36Sopenharmony_ci if (imm) 148362306a36Sopenharmony_ci emit_a32_alu_i(dst_lo, imm, ctx, BPF_OP(code)); 148462306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 148562306a36Sopenharmony_ci emit_a32_mov_i(dst_hi, 0, ctx); 148662306a36Sopenharmony_ci break; 148762306a36Sopenharmony_ci /* dst = dst << imm */ 148862306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: 148962306a36Sopenharmony_ci if (unlikely(imm > 63)) 149062306a36Sopenharmony_ci return -EINVAL; 149162306a36Sopenharmony_ci emit_a32_lsh_i64(dst, imm, ctx); 149262306a36Sopenharmony_ci break; 149362306a36Sopenharmony_ci /* dst = dst >> imm */ 149462306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: 149562306a36Sopenharmony_ci if (unlikely(imm > 63)) 149662306a36Sopenharmony_ci return -EINVAL; 149762306a36Sopenharmony_ci emit_a32_rsh_i64(dst, imm, ctx); 149862306a36Sopenharmony_ci break; 149962306a36Sopenharmony_ci /* dst = dst << src */ 150062306a36Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: 150162306a36Sopenharmony_ci emit_a32_lsh_r64(dst, src, ctx); 150262306a36Sopenharmony_ci break; 150362306a36Sopenharmony_ci /* dst = dst >> src */ 150462306a36Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: 150562306a36Sopenharmony_ci emit_a32_rsh_r64(dst, src, ctx); 150662306a36Sopenharmony_ci break; 150762306a36Sopenharmony_ci /* dst = dst >> src (signed) */ 150862306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: 150962306a36Sopenharmony_ci emit_a32_arsh_r64(dst, src, ctx); 151062306a36Sopenharmony_ci break; 151162306a36Sopenharmony_ci /* dst = dst >> imm (signed) */ 151262306a36Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: 151362306a36Sopenharmony_ci if (unlikely(imm > 63)) 151462306a36Sopenharmony_ci return -EINVAL; 151562306a36Sopenharmony_ci emit_a32_arsh_i64(dst, imm, ctx); 151662306a36Sopenharmony_ci break; 151762306a36Sopenharmony_ci /* dst = ~dst */ 151862306a36Sopenharmony_ci case BPF_ALU | BPF_NEG: 151962306a36Sopenharmony_ci emit_a32_alu_i(dst_lo, 0, ctx, BPF_OP(code)); 152062306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 152162306a36Sopenharmony_ci emit_a32_mov_i(dst_hi, 0, ctx); 152262306a36Sopenharmony_ci break; 152362306a36Sopenharmony_ci /* dst = ~dst (64 bit) */ 152462306a36Sopenharmony_ci case BPF_ALU64 | BPF_NEG: 152562306a36Sopenharmony_ci emit_a32_neg64(dst, ctx); 152662306a36Sopenharmony_ci break; 152762306a36Sopenharmony_ci /* dst = dst * src/imm */ 152862306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: 152962306a36Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: 153062306a36Sopenharmony_ci switch (BPF_SRC(code)) { 153162306a36Sopenharmony_ci case BPF_X: 153262306a36Sopenharmony_ci emit_a32_mul_r64(dst, src, ctx); 153362306a36Sopenharmony_ci break; 153462306a36Sopenharmony_ci case BPF_K: 153562306a36Sopenharmony_ci /* Move immediate value to the temporary register 153662306a36Sopenharmony_ci * and then do the multiplication on it as this 153762306a36Sopenharmony_ci * will sign-extend the immediate value into temp 153862306a36Sopenharmony_ci * reg then it would be safe to do the operation 153962306a36Sopenharmony_ci * on it. 154062306a36Sopenharmony_ci */ 154162306a36Sopenharmony_ci emit_a32_mov_se_i64(is64, tmp2, imm, ctx); 154262306a36Sopenharmony_ci emit_a32_mul_r64(dst, tmp2, ctx); 154362306a36Sopenharmony_ci break; 154462306a36Sopenharmony_ci } 154562306a36Sopenharmony_ci break; 154662306a36Sopenharmony_ci /* dst = htole(dst) */ 154762306a36Sopenharmony_ci /* dst = htobe(dst) */ 154862306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 154962306a36Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 155062306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 155162306a36Sopenharmony_ci if (BPF_SRC(code) == BPF_FROM_LE) 155262306a36Sopenharmony_ci goto emit_bswap_uxt; 155362306a36Sopenharmony_ci switch (imm) { 155462306a36Sopenharmony_ci case 16: 155562306a36Sopenharmony_ci emit_rev16(rd[1], rd[1], ctx); 155662306a36Sopenharmony_ci goto emit_bswap_uxt; 155762306a36Sopenharmony_ci case 32: 155862306a36Sopenharmony_ci emit_rev32(rd[1], rd[1], ctx); 155962306a36Sopenharmony_ci goto emit_bswap_uxt; 156062306a36Sopenharmony_ci case 64: 156162306a36Sopenharmony_ci emit_rev32(ARM_LR, rd[1], ctx); 156262306a36Sopenharmony_ci emit_rev32(rd[1], rd[0], ctx); 156362306a36Sopenharmony_ci emit(ARM_MOV_R(rd[0], ARM_LR), ctx); 156462306a36Sopenharmony_ci break; 156562306a36Sopenharmony_ci } 156662306a36Sopenharmony_ci goto exit; 156762306a36Sopenharmony_ciemit_bswap_uxt: 156862306a36Sopenharmony_ci switch (imm) { 156962306a36Sopenharmony_ci case 16: 157062306a36Sopenharmony_ci /* zero-extend 16 bits into 64 bits */ 157162306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 6 157262306a36Sopenharmony_ci emit_a32_mov_i(tmp2[1], 0xffff, ctx); 157362306a36Sopenharmony_ci emit(ARM_AND_R(rd[1], rd[1], tmp2[1]), ctx); 157462306a36Sopenharmony_ci#else /* ARMv6+ */ 157562306a36Sopenharmony_ci emit(ARM_UXTH(rd[1], rd[1]), ctx); 157662306a36Sopenharmony_ci#endif 157762306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 157862306a36Sopenharmony_ci emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); 157962306a36Sopenharmony_ci break; 158062306a36Sopenharmony_ci case 32: 158162306a36Sopenharmony_ci /* zero-extend 32 bits into 64 bits */ 158262306a36Sopenharmony_ci if (!ctx->prog->aux->verifier_zext) 158362306a36Sopenharmony_ci emit(ARM_EOR_R(rd[0], rd[0], rd[0]), ctx); 158462306a36Sopenharmony_ci break; 158562306a36Sopenharmony_ci case 64: 158662306a36Sopenharmony_ci /* nop */ 158762306a36Sopenharmony_ci break; 158862306a36Sopenharmony_ci } 158962306a36Sopenharmony_ciexit: 159062306a36Sopenharmony_ci arm_bpf_put_reg64(dst, rd, ctx); 159162306a36Sopenharmony_ci break; 159262306a36Sopenharmony_ci /* dst = imm64 */ 159362306a36Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: 159462306a36Sopenharmony_ci { 159562306a36Sopenharmony_ci u64 val = (u32)imm | (u64)insn[1].imm << 32; 159662306a36Sopenharmony_ci 159762306a36Sopenharmony_ci emit_a32_mov_i64(dst, val, ctx); 159862306a36Sopenharmony_ci 159962306a36Sopenharmony_ci return 1; 160062306a36Sopenharmony_ci } 160162306a36Sopenharmony_ci /* LDX: dst = *(size *)(src + off) */ 160262306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: 160362306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: 160462306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: 160562306a36Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: 160662306a36Sopenharmony_ci rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 160762306a36Sopenharmony_ci emit_ldx_r(dst, rn, off, ctx, BPF_SIZE(code)); 160862306a36Sopenharmony_ci break; 160962306a36Sopenharmony_ci /* speculation barrier */ 161062306a36Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 161162306a36Sopenharmony_ci break; 161262306a36Sopenharmony_ci /* ST: *(size *)(dst + off) = imm */ 161362306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: 161462306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: 161562306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: 161662306a36Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: 161762306a36Sopenharmony_ci switch (BPF_SIZE(code)) { 161862306a36Sopenharmony_ci case BPF_DW: 161962306a36Sopenharmony_ci /* Sign-extend immediate value into temp reg */ 162062306a36Sopenharmony_ci emit_a32_mov_se_i64(true, tmp2, imm, ctx); 162162306a36Sopenharmony_ci break; 162262306a36Sopenharmony_ci case BPF_W: 162362306a36Sopenharmony_ci case BPF_H: 162462306a36Sopenharmony_ci case BPF_B: 162562306a36Sopenharmony_ci emit_a32_mov_i(tmp2[1], imm, ctx); 162662306a36Sopenharmony_ci break; 162762306a36Sopenharmony_ci } 162862306a36Sopenharmony_ci emit_str_r(dst_lo, tmp2, off, ctx, BPF_SIZE(code)); 162962306a36Sopenharmony_ci break; 163062306a36Sopenharmony_ci /* Atomic ops */ 163162306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_W: 163262306a36Sopenharmony_ci case BPF_STX | BPF_ATOMIC | BPF_DW: 163362306a36Sopenharmony_ci goto notyet; 163462306a36Sopenharmony_ci /* STX: *(size *)(dst + off) = src */ 163562306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: 163662306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: 163762306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: 163862306a36Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: 163962306a36Sopenharmony_ci rs = arm_bpf_get_reg64(src, tmp2, ctx); 164062306a36Sopenharmony_ci emit_str_r(dst_lo, rs, off, ctx, BPF_SIZE(code)); 164162306a36Sopenharmony_ci break; 164262306a36Sopenharmony_ci /* PC += off if dst == src */ 164362306a36Sopenharmony_ci /* PC += off if dst > src */ 164462306a36Sopenharmony_ci /* PC += off if dst >= src */ 164562306a36Sopenharmony_ci /* PC += off if dst < src */ 164662306a36Sopenharmony_ci /* PC += off if dst <= src */ 164762306a36Sopenharmony_ci /* PC += off if dst != src */ 164862306a36Sopenharmony_ci /* PC += off if dst > src (signed) */ 164962306a36Sopenharmony_ci /* PC += off if dst >= src (signed) */ 165062306a36Sopenharmony_ci /* PC += off if dst < src (signed) */ 165162306a36Sopenharmony_ci /* PC += off if dst <= src (signed) */ 165262306a36Sopenharmony_ci /* PC += off if dst & src */ 165362306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 165462306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 165562306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 165662306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 165762306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 165862306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 165962306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 166062306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 166162306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 166262306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 166362306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 166462306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 166562306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 166662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 166762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 166862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 166962306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 167062306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 167162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 167262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 167362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 167462306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 167562306a36Sopenharmony_ci /* Setup source registers */ 167662306a36Sopenharmony_ci rm = arm_bpf_get_reg32(src_hi, tmp2[0], ctx); 167762306a36Sopenharmony_ci rn = arm_bpf_get_reg32(src_lo, tmp2[1], ctx); 167862306a36Sopenharmony_ci goto go_jmp; 167962306a36Sopenharmony_ci /* PC += off if dst == imm */ 168062306a36Sopenharmony_ci /* PC += off if dst > imm */ 168162306a36Sopenharmony_ci /* PC += off if dst >= imm */ 168262306a36Sopenharmony_ci /* PC += off if dst < imm */ 168362306a36Sopenharmony_ci /* PC += off if dst <= imm */ 168462306a36Sopenharmony_ci /* PC += off if dst != imm */ 168562306a36Sopenharmony_ci /* PC += off if dst > imm (signed) */ 168662306a36Sopenharmony_ci /* PC += off if dst >= imm (signed) */ 168762306a36Sopenharmony_ci /* PC += off if dst < imm (signed) */ 168862306a36Sopenharmony_ci /* PC += off if dst <= imm (signed) */ 168962306a36Sopenharmony_ci /* PC += off if dst & imm */ 169062306a36Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 169162306a36Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 169262306a36Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 169362306a36Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 169462306a36Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 169562306a36Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 169662306a36Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 169762306a36Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 169862306a36Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 169962306a36Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 170062306a36Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 170162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 170262306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 170362306a36Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 170462306a36Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 170562306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 170662306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 170762306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 170862306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 170962306a36Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 171062306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 171162306a36Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 171262306a36Sopenharmony_ci if (off == 0) 171362306a36Sopenharmony_ci break; 171462306a36Sopenharmony_ci rm = tmp2[0]; 171562306a36Sopenharmony_ci rn = tmp2[1]; 171662306a36Sopenharmony_ci /* Sign-extend immediate value */ 171762306a36Sopenharmony_ci emit_a32_mov_se_i64(true, tmp2, imm, ctx); 171862306a36Sopenharmony_cigo_jmp: 171962306a36Sopenharmony_ci /* Setup destination register */ 172062306a36Sopenharmony_ci rd = arm_bpf_get_reg64(dst, tmp, ctx); 172162306a36Sopenharmony_ci 172262306a36Sopenharmony_ci /* Check for the condition */ 172362306a36Sopenharmony_ci emit_ar_r(rd[0], rd[1], rm, rn, ctx, BPF_OP(code), 172462306a36Sopenharmony_ci BPF_CLASS(code) == BPF_JMP); 172562306a36Sopenharmony_ci 172662306a36Sopenharmony_ci /* Setup JUMP instruction */ 172762306a36Sopenharmony_ci jmp_offset = bpf2a32_offset(i+off, i, ctx); 172862306a36Sopenharmony_ci switch (BPF_OP(code)) { 172962306a36Sopenharmony_ci case BPF_JNE: 173062306a36Sopenharmony_ci case BPF_JSET: 173162306a36Sopenharmony_ci _emit(ARM_COND_NE, ARM_B(jmp_offset), ctx); 173262306a36Sopenharmony_ci break; 173362306a36Sopenharmony_ci case BPF_JEQ: 173462306a36Sopenharmony_ci _emit(ARM_COND_EQ, ARM_B(jmp_offset), ctx); 173562306a36Sopenharmony_ci break; 173662306a36Sopenharmony_ci case BPF_JGT: 173762306a36Sopenharmony_ci _emit(ARM_COND_HI, ARM_B(jmp_offset), ctx); 173862306a36Sopenharmony_ci break; 173962306a36Sopenharmony_ci case BPF_JGE: 174062306a36Sopenharmony_ci _emit(ARM_COND_CS, ARM_B(jmp_offset), ctx); 174162306a36Sopenharmony_ci break; 174262306a36Sopenharmony_ci case BPF_JSGT: 174362306a36Sopenharmony_ci _emit(ARM_COND_LT, ARM_B(jmp_offset), ctx); 174462306a36Sopenharmony_ci break; 174562306a36Sopenharmony_ci case BPF_JSGE: 174662306a36Sopenharmony_ci _emit(ARM_COND_GE, ARM_B(jmp_offset), ctx); 174762306a36Sopenharmony_ci break; 174862306a36Sopenharmony_ci case BPF_JLE: 174962306a36Sopenharmony_ci _emit(ARM_COND_LS, ARM_B(jmp_offset), ctx); 175062306a36Sopenharmony_ci break; 175162306a36Sopenharmony_ci case BPF_JLT: 175262306a36Sopenharmony_ci _emit(ARM_COND_CC, ARM_B(jmp_offset), ctx); 175362306a36Sopenharmony_ci break; 175462306a36Sopenharmony_ci case BPF_JSLT: 175562306a36Sopenharmony_ci _emit(ARM_COND_LT, ARM_B(jmp_offset), ctx); 175662306a36Sopenharmony_ci break; 175762306a36Sopenharmony_ci case BPF_JSLE: 175862306a36Sopenharmony_ci _emit(ARM_COND_GE, ARM_B(jmp_offset), ctx); 175962306a36Sopenharmony_ci break; 176062306a36Sopenharmony_ci } 176162306a36Sopenharmony_ci break; 176262306a36Sopenharmony_ci /* JMP OFF */ 176362306a36Sopenharmony_ci case BPF_JMP | BPF_JA: 176462306a36Sopenharmony_ci { 176562306a36Sopenharmony_ci if (off == 0) 176662306a36Sopenharmony_ci break; 176762306a36Sopenharmony_ci jmp_offset = bpf2a32_offset(i+off, i, ctx); 176862306a36Sopenharmony_ci check_imm24(jmp_offset); 176962306a36Sopenharmony_ci emit(ARM_B(jmp_offset), ctx); 177062306a36Sopenharmony_ci break; 177162306a36Sopenharmony_ci } 177262306a36Sopenharmony_ci /* tail call */ 177362306a36Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 177462306a36Sopenharmony_ci if (emit_bpf_tail_call(ctx)) 177562306a36Sopenharmony_ci return -EFAULT; 177662306a36Sopenharmony_ci break; 177762306a36Sopenharmony_ci /* function call */ 177862306a36Sopenharmony_ci case BPF_JMP | BPF_CALL: 177962306a36Sopenharmony_ci { 178062306a36Sopenharmony_ci const s8 *r0 = bpf2a32[BPF_REG_0]; 178162306a36Sopenharmony_ci const s8 *r1 = bpf2a32[BPF_REG_1]; 178262306a36Sopenharmony_ci const s8 *r2 = bpf2a32[BPF_REG_2]; 178362306a36Sopenharmony_ci const s8 *r3 = bpf2a32[BPF_REG_3]; 178462306a36Sopenharmony_ci const s8 *r4 = bpf2a32[BPF_REG_4]; 178562306a36Sopenharmony_ci const s8 *r5 = bpf2a32[BPF_REG_5]; 178662306a36Sopenharmony_ci const u32 func = (u32)__bpf_call_base + (u32)imm; 178762306a36Sopenharmony_ci 178862306a36Sopenharmony_ci emit_a32_mov_r64(true, r0, r1, ctx); 178962306a36Sopenharmony_ci emit_a32_mov_r64(true, r1, r2, ctx); 179062306a36Sopenharmony_ci emit_push_r64(r5, ctx); 179162306a36Sopenharmony_ci emit_push_r64(r4, ctx); 179262306a36Sopenharmony_ci emit_push_r64(r3, ctx); 179362306a36Sopenharmony_ci 179462306a36Sopenharmony_ci emit_a32_mov_i(tmp[1], func, ctx); 179562306a36Sopenharmony_ci emit_blx_r(tmp[1], ctx); 179662306a36Sopenharmony_ci 179762306a36Sopenharmony_ci emit(ARM_ADD_I(ARM_SP, ARM_SP, imm8m(24)), ctx); // callee clean 179862306a36Sopenharmony_ci break; 179962306a36Sopenharmony_ci } 180062306a36Sopenharmony_ci /* function return */ 180162306a36Sopenharmony_ci case BPF_JMP | BPF_EXIT: 180262306a36Sopenharmony_ci /* Optimization: when last instruction is EXIT 180362306a36Sopenharmony_ci * simply fallthrough to epilogue. 180462306a36Sopenharmony_ci */ 180562306a36Sopenharmony_ci if (i == ctx->prog->len - 1) 180662306a36Sopenharmony_ci break; 180762306a36Sopenharmony_ci jmp_offset = epilogue_offset(ctx); 180862306a36Sopenharmony_ci check_imm24(jmp_offset); 180962306a36Sopenharmony_ci emit(ARM_B(jmp_offset), ctx); 181062306a36Sopenharmony_ci break; 181162306a36Sopenharmony_cinotyet: 181262306a36Sopenharmony_ci pr_info_once("*** NOT YET: opcode %02x ***\n", code); 181362306a36Sopenharmony_ci return -EFAULT; 181462306a36Sopenharmony_ci default: 181562306a36Sopenharmony_ci pr_err_once("unknown opcode %02x\n", code); 181662306a36Sopenharmony_ci return -EINVAL; 181762306a36Sopenharmony_ci } 181862306a36Sopenharmony_ci 181962306a36Sopenharmony_ci if (ctx->flags & FLAG_IMM_OVERFLOW) 182062306a36Sopenharmony_ci /* 182162306a36Sopenharmony_ci * this instruction generated an overflow when 182262306a36Sopenharmony_ci * trying to access the literal pool, so 182362306a36Sopenharmony_ci * delegate this filter to the kernel interpreter. 182462306a36Sopenharmony_ci */ 182562306a36Sopenharmony_ci return -1; 182662306a36Sopenharmony_ci return 0; 182762306a36Sopenharmony_ci} 182862306a36Sopenharmony_ci 182962306a36Sopenharmony_cistatic int build_body(struct jit_ctx *ctx) 183062306a36Sopenharmony_ci{ 183162306a36Sopenharmony_ci const struct bpf_prog *prog = ctx->prog; 183262306a36Sopenharmony_ci unsigned int i; 183362306a36Sopenharmony_ci 183462306a36Sopenharmony_ci for (i = 0; i < prog->len; i++) { 183562306a36Sopenharmony_ci const struct bpf_insn *insn = &(prog->insnsi[i]); 183662306a36Sopenharmony_ci int ret; 183762306a36Sopenharmony_ci 183862306a36Sopenharmony_ci ret = build_insn(insn, ctx); 183962306a36Sopenharmony_ci 184062306a36Sopenharmony_ci /* It's used with loading the 64 bit immediate value. */ 184162306a36Sopenharmony_ci if (ret > 0) { 184262306a36Sopenharmony_ci i++; 184362306a36Sopenharmony_ci if (ctx->target == NULL) 184462306a36Sopenharmony_ci ctx->offsets[i] = ctx->idx; 184562306a36Sopenharmony_ci continue; 184662306a36Sopenharmony_ci } 184762306a36Sopenharmony_ci 184862306a36Sopenharmony_ci if (ctx->target == NULL) 184962306a36Sopenharmony_ci ctx->offsets[i] = ctx->idx; 185062306a36Sopenharmony_ci 185162306a36Sopenharmony_ci /* If unsuccesful, return with error code */ 185262306a36Sopenharmony_ci if (ret) 185362306a36Sopenharmony_ci return ret; 185462306a36Sopenharmony_ci } 185562306a36Sopenharmony_ci return 0; 185662306a36Sopenharmony_ci} 185762306a36Sopenharmony_ci 185862306a36Sopenharmony_cistatic int validate_code(struct jit_ctx *ctx) 185962306a36Sopenharmony_ci{ 186062306a36Sopenharmony_ci int i; 186162306a36Sopenharmony_ci 186262306a36Sopenharmony_ci for (i = 0; i < ctx->idx; i++) { 186362306a36Sopenharmony_ci if (ctx->target[i] == __opcode_to_mem_arm(ARM_INST_UDF)) 186462306a36Sopenharmony_ci return -1; 186562306a36Sopenharmony_ci } 186662306a36Sopenharmony_ci 186762306a36Sopenharmony_ci return 0; 186862306a36Sopenharmony_ci} 186962306a36Sopenharmony_ci 187062306a36Sopenharmony_cibool bpf_jit_needs_zext(void) 187162306a36Sopenharmony_ci{ 187262306a36Sopenharmony_ci return true; 187362306a36Sopenharmony_ci} 187462306a36Sopenharmony_ci 187562306a36Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *prog) 187662306a36Sopenharmony_ci{ 187762306a36Sopenharmony_ci struct bpf_prog *tmp, *orig_prog = prog; 187862306a36Sopenharmony_ci struct bpf_binary_header *header; 187962306a36Sopenharmony_ci bool tmp_blinded = false; 188062306a36Sopenharmony_ci struct jit_ctx ctx; 188162306a36Sopenharmony_ci unsigned int tmp_idx; 188262306a36Sopenharmony_ci unsigned int image_size; 188362306a36Sopenharmony_ci u8 *image_ptr; 188462306a36Sopenharmony_ci 188562306a36Sopenharmony_ci /* If BPF JIT was not enabled then we must fall back to 188662306a36Sopenharmony_ci * the interpreter. 188762306a36Sopenharmony_ci */ 188862306a36Sopenharmony_ci if (!prog->jit_requested) 188962306a36Sopenharmony_ci return orig_prog; 189062306a36Sopenharmony_ci 189162306a36Sopenharmony_ci /* If constant blinding was enabled and we failed during blinding 189262306a36Sopenharmony_ci * then we must fall back to the interpreter. Otherwise, we save 189362306a36Sopenharmony_ci * the new JITed code. 189462306a36Sopenharmony_ci */ 189562306a36Sopenharmony_ci tmp = bpf_jit_blind_constants(prog); 189662306a36Sopenharmony_ci 189762306a36Sopenharmony_ci if (IS_ERR(tmp)) 189862306a36Sopenharmony_ci return orig_prog; 189962306a36Sopenharmony_ci if (tmp != prog) { 190062306a36Sopenharmony_ci tmp_blinded = true; 190162306a36Sopenharmony_ci prog = tmp; 190262306a36Sopenharmony_ci } 190362306a36Sopenharmony_ci 190462306a36Sopenharmony_ci memset(&ctx, 0, sizeof(ctx)); 190562306a36Sopenharmony_ci ctx.prog = prog; 190662306a36Sopenharmony_ci ctx.cpu_architecture = cpu_architecture(); 190762306a36Sopenharmony_ci 190862306a36Sopenharmony_ci /* Not able to allocate memory for offsets[] , then 190962306a36Sopenharmony_ci * we must fall back to the interpreter 191062306a36Sopenharmony_ci */ 191162306a36Sopenharmony_ci ctx.offsets = kcalloc(prog->len, sizeof(int), GFP_KERNEL); 191262306a36Sopenharmony_ci if (ctx.offsets == NULL) { 191362306a36Sopenharmony_ci prog = orig_prog; 191462306a36Sopenharmony_ci goto out; 191562306a36Sopenharmony_ci } 191662306a36Sopenharmony_ci 191762306a36Sopenharmony_ci /* 1) fake pass to find in the length of the JITed code, 191862306a36Sopenharmony_ci * to compute ctx->offsets and other context variables 191962306a36Sopenharmony_ci * needed to compute final JITed code. 192062306a36Sopenharmony_ci * Also, calculate random starting pointer/start of JITed code 192162306a36Sopenharmony_ci * which is prefixed by random number of fault instructions. 192262306a36Sopenharmony_ci * 192362306a36Sopenharmony_ci * If the first pass fails then there is no chance of it 192462306a36Sopenharmony_ci * being successful in the second pass, so just fall back 192562306a36Sopenharmony_ci * to the interpreter. 192662306a36Sopenharmony_ci */ 192762306a36Sopenharmony_ci if (build_body(&ctx)) { 192862306a36Sopenharmony_ci prog = orig_prog; 192962306a36Sopenharmony_ci goto out_off; 193062306a36Sopenharmony_ci } 193162306a36Sopenharmony_ci 193262306a36Sopenharmony_ci tmp_idx = ctx.idx; 193362306a36Sopenharmony_ci build_prologue(&ctx); 193462306a36Sopenharmony_ci ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4; 193562306a36Sopenharmony_ci 193662306a36Sopenharmony_ci ctx.epilogue_offset = ctx.idx; 193762306a36Sopenharmony_ci 193862306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7 193962306a36Sopenharmony_ci tmp_idx = ctx.idx; 194062306a36Sopenharmony_ci build_epilogue(&ctx); 194162306a36Sopenharmony_ci ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4; 194262306a36Sopenharmony_ci 194362306a36Sopenharmony_ci ctx.idx += ctx.imm_count; 194462306a36Sopenharmony_ci if (ctx.imm_count) { 194562306a36Sopenharmony_ci ctx.imms = kcalloc(ctx.imm_count, sizeof(u32), GFP_KERNEL); 194662306a36Sopenharmony_ci if (ctx.imms == NULL) { 194762306a36Sopenharmony_ci prog = orig_prog; 194862306a36Sopenharmony_ci goto out_off; 194962306a36Sopenharmony_ci } 195062306a36Sopenharmony_ci } 195162306a36Sopenharmony_ci#else 195262306a36Sopenharmony_ci /* there's nothing about the epilogue on ARMv7 */ 195362306a36Sopenharmony_ci build_epilogue(&ctx); 195462306a36Sopenharmony_ci#endif 195562306a36Sopenharmony_ci /* Now we can get the actual image size of the JITed arm code. 195662306a36Sopenharmony_ci * Currently, we are not considering the THUMB-2 instructions 195762306a36Sopenharmony_ci * for jit, although it can decrease the size of the image. 195862306a36Sopenharmony_ci * 195962306a36Sopenharmony_ci * As each arm instruction is of length 32bit, we are translating 196062306a36Sopenharmony_ci * number of JITed instructions into the size required to store these 196162306a36Sopenharmony_ci * JITed code. 196262306a36Sopenharmony_ci */ 196362306a36Sopenharmony_ci image_size = sizeof(u32) * ctx.idx; 196462306a36Sopenharmony_ci 196562306a36Sopenharmony_ci /* Now we know the size of the structure to make */ 196662306a36Sopenharmony_ci header = bpf_jit_binary_alloc(image_size, &image_ptr, 196762306a36Sopenharmony_ci sizeof(u32), jit_fill_hole); 196862306a36Sopenharmony_ci /* Not able to allocate memory for the structure then 196962306a36Sopenharmony_ci * we must fall back to the interpretation 197062306a36Sopenharmony_ci */ 197162306a36Sopenharmony_ci if (header == NULL) { 197262306a36Sopenharmony_ci prog = orig_prog; 197362306a36Sopenharmony_ci goto out_imms; 197462306a36Sopenharmony_ci } 197562306a36Sopenharmony_ci 197662306a36Sopenharmony_ci /* 2.) Actual pass to generate final JIT code */ 197762306a36Sopenharmony_ci ctx.target = (u32 *) image_ptr; 197862306a36Sopenharmony_ci ctx.idx = 0; 197962306a36Sopenharmony_ci 198062306a36Sopenharmony_ci build_prologue(&ctx); 198162306a36Sopenharmony_ci 198262306a36Sopenharmony_ci /* If building the body of the JITed code fails somehow, 198362306a36Sopenharmony_ci * we fall back to the interpretation. 198462306a36Sopenharmony_ci */ 198562306a36Sopenharmony_ci if (build_body(&ctx) < 0) { 198662306a36Sopenharmony_ci image_ptr = NULL; 198762306a36Sopenharmony_ci bpf_jit_binary_free(header); 198862306a36Sopenharmony_ci prog = orig_prog; 198962306a36Sopenharmony_ci goto out_imms; 199062306a36Sopenharmony_ci } 199162306a36Sopenharmony_ci build_epilogue(&ctx); 199262306a36Sopenharmony_ci 199362306a36Sopenharmony_ci /* 3.) Extra pass to validate JITed Code */ 199462306a36Sopenharmony_ci if (validate_code(&ctx)) { 199562306a36Sopenharmony_ci image_ptr = NULL; 199662306a36Sopenharmony_ci bpf_jit_binary_free(header); 199762306a36Sopenharmony_ci prog = orig_prog; 199862306a36Sopenharmony_ci goto out_imms; 199962306a36Sopenharmony_ci } 200062306a36Sopenharmony_ci flush_icache_range((u32)header, (u32)(ctx.target + ctx.idx)); 200162306a36Sopenharmony_ci 200262306a36Sopenharmony_ci if (bpf_jit_enable > 1) 200362306a36Sopenharmony_ci /* there are 2 passes here */ 200462306a36Sopenharmony_ci bpf_jit_dump(prog->len, image_size, 2, ctx.target); 200562306a36Sopenharmony_ci 200662306a36Sopenharmony_ci bpf_jit_binary_lock_ro(header); 200762306a36Sopenharmony_ci prog->bpf_func = (void *)ctx.target; 200862306a36Sopenharmony_ci prog->jited = 1; 200962306a36Sopenharmony_ci prog->jited_len = image_size; 201062306a36Sopenharmony_ci 201162306a36Sopenharmony_ciout_imms: 201262306a36Sopenharmony_ci#if __LINUX_ARM_ARCH__ < 7 201362306a36Sopenharmony_ci if (ctx.imm_count) 201462306a36Sopenharmony_ci kfree(ctx.imms); 201562306a36Sopenharmony_ci#endif 201662306a36Sopenharmony_ciout_off: 201762306a36Sopenharmony_ci kfree(ctx.offsets); 201862306a36Sopenharmony_ciout: 201962306a36Sopenharmony_ci if (tmp_blinded) 202062306a36Sopenharmony_ci bpf_jit_prog_release_other(prog, prog == orig_prog ? 202162306a36Sopenharmony_ci tmp : orig_prog); 202262306a36Sopenharmony_ci return prog; 202362306a36Sopenharmony_ci} 202462306a36Sopenharmony_ci 2025