18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * bpf_jit_comp64.c: eBPF JIT compiler 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2016 Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> 68c2ecf20Sopenharmony_ci * IBM Corporation 78c2ecf20Sopenharmony_ci * 88c2ecf20Sopenharmony_ci * Based on the powerpc classic BPF JIT compiler by Matt Evans 98c2ecf20Sopenharmony_ci */ 108c2ecf20Sopenharmony_ci#include <linux/moduleloader.h> 118c2ecf20Sopenharmony_ci#include <asm/cacheflush.h> 128c2ecf20Sopenharmony_ci#include <asm/asm-compat.h> 138c2ecf20Sopenharmony_ci#include <linux/netdevice.h> 148c2ecf20Sopenharmony_ci#include <linux/filter.h> 158c2ecf20Sopenharmony_ci#include <linux/if_vlan.h> 168c2ecf20Sopenharmony_ci#include <asm/kprobes.h> 178c2ecf20Sopenharmony_ci#include <linux/bpf.h> 188c2ecf20Sopenharmony_ci#include <asm/security_features.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_ci#include "bpf_jit64.h" 218c2ecf20Sopenharmony_ci 228c2ecf20Sopenharmony_cistatic void bpf_jit_fill_ill_insns(void *area, unsigned int size) 238c2ecf20Sopenharmony_ci{ 248c2ecf20Sopenharmony_ci memset32(area, BREAKPOINT_INSTRUCTION, size/4); 258c2ecf20Sopenharmony_ci} 268c2ecf20Sopenharmony_ci 278c2ecf20Sopenharmony_cistatic inline void bpf_flush_icache(void *start, void *end) 288c2ecf20Sopenharmony_ci{ 298c2ecf20Sopenharmony_ci smp_wmb(); 308c2ecf20Sopenharmony_ci flush_icache_range((unsigned long)start, (unsigned long)end); 318c2ecf20Sopenharmony_ci} 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistatic inline bool bpf_is_seen_register(struct codegen_context *ctx, int i) 348c2ecf20Sopenharmony_ci{ 358c2ecf20Sopenharmony_ci return (ctx->seen & (1 << (31 - b2p[i]))); 368c2ecf20Sopenharmony_ci} 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistatic inline void bpf_set_seen_register(struct codegen_context *ctx, int i) 398c2ecf20Sopenharmony_ci{ 408c2ecf20Sopenharmony_ci ctx->seen |= (1 << (31 - b2p[i])); 418c2ecf20Sopenharmony_ci} 428c2ecf20Sopenharmony_ci 438c2ecf20Sopenharmony_cistatic inline bool bpf_has_stack_frame(struct codegen_context *ctx) 448c2ecf20Sopenharmony_ci{ 458c2ecf20Sopenharmony_ci /* 468c2ecf20Sopenharmony_ci * We only need a stack frame if: 478c2ecf20Sopenharmony_ci * - we call other functions (kernel helpers), or 488c2ecf20Sopenharmony_ci * - the bpf program uses its stack area 498c2ecf20Sopenharmony_ci * The latter condition is deduced from the usage of BPF_REG_FP 508c2ecf20Sopenharmony_ci */ 518c2ecf20Sopenharmony_ci return ctx->seen & SEEN_FUNC || bpf_is_seen_register(ctx, BPF_REG_FP); 528c2ecf20Sopenharmony_ci} 538c2ecf20Sopenharmony_ci 548c2ecf20Sopenharmony_ci/* 558c2ecf20Sopenharmony_ci * When not setting up our own stackframe, the redzone usage is: 568c2ecf20Sopenharmony_ci * 578c2ecf20Sopenharmony_ci * [ prev sp ] <------------- 588c2ecf20Sopenharmony_ci * [ ... ] | 598c2ecf20Sopenharmony_ci * sp (r1) ---> [ stack pointer ] -------------- 608c2ecf20Sopenharmony_ci * [ nv gpr save area ] 5*8 618c2ecf20Sopenharmony_ci * [ tail_call_cnt ] 8 628c2ecf20Sopenharmony_ci * [ local_tmp_var ] 16 638c2ecf20Sopenharmony_ci * [ unused red zone ] 208 bytes protected 648c2ecf20Sopenharmony_ci */ 658c2ecf20Sopenharmony_cistatic int bpf_jit_stack_local(struct codegen_context *ctx) 668c2ecf20Sopenharmony_ci{ 678c2ecf20Sopenharmony_ci if (bpf_has_stack_frame(ctx)) 688c2ecf20Sopenharmony_ci return STACK_FRAME_MIN_SIZE + ctx->stack_size; 698c2ecf20Sopenharmony_ci else 708c2ecf20Sopenharmony_ci return -(BPF_PPC_STACK_SAVE + 24); 718c2ecf20Sopenharmony_ci} 728c2ecf20Sopenharmony_ci 738c2ecf20Sopenharmony_cistatic int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx) 748c2ecf20Sopenharmony_ci{ 758c2ecf20Sopenharmony_ci return bpf_jit_stack_local(ctx) + 16; 768c2ecf20Sopenharmony_ci} 778c2ecf20Sopenharmony_ci 788c2ecf20Sopenharmony_cistatic int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg) 798c2ecf20Sopenharmony_ci{ 808c2ecf20Sopenharmony_ci if (reg >= BPF_PPC_NVR_MIN && reg < 32) 818c2ecf20Sopenharmony_ci return (bpf_has_stack_frame(ctx) ? 828c2ecf20Sopenharmony_ci (BPF_PPC_STACKFRAME + ctx->stack_size) : 0) 838c2ecf20Sopenharmony_ci - (8 * (32 - reg)); 848c2ecf20Sopenharmony_ci 858c2ecf20Sopenharmony_ci pr_err("BPF JIT is asking about unknown registers"); 868c2ecf20Sopenharmony_ci BUG(); 878c2ecf20Sopenharmony_ci} 888c2ecf20Sopenharmony_ci 898c2ecf20Sopenharmony_cistatic void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) 908c2ecf20Sopenharmony_ci{ 918c2ecf20Sopenharmony_ci int i; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci /* 948c2ecf20Sopenharmony_ci * Initialize tail_call_cnt if we do tail calls. 958c2ecf20Sopenharmony_ci * Otherwise, put in NOPs so that it can be skipped when we are 968c2ecf20Sopenharmony_ci * invoked through a tail call. 978c2ecf20Sopenharmony_ci */ 988c2ecf20Sopenharmony_ci if (ctx->seen & SEEN_TAILCALL) { 998c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LI(b2p[TMP_REG_1], 0)); 1008c2ecf20Sopenharmony_ci /* this goes in the redzone */ 1018c2ecf20Sopenharmony_ci PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8)); 1028c2ecf20Sopenharmony_ci } else { 1038c2ecf20Sopenharmony_ci EMIT(PPC_RAW_NOP()); 1048c2ecf20Sopenharmony_ci EMIT(PPC_RAW_NOP()); 1058c2ecf20Sopenharmony_ci } 1068c2ecf20Sopenharmony_ci 1078c2ecf20Sopenharmony_ci#define BPF_TAILCALL_PROLOGUE_SIZE 8 1088c2ecf20Sopenharmony_ci 1098c2ecf20Sopenharmony_ci if (bpf_has_stack_frame(ctx)) { 1108c2ecf20Sopenharmony_ci /* 1118c2ecf20Sopenharmony_ci * We need a stack frame, but we don't necessarily need to 1128c2ecf20Sopenharmony_ci * save/restore LR unless we call other functions 1138c2ecf20Sopenharmony_ci */ 1148c2ecf20Sopenharmony_ci if (ctx->seen & SEEN_FUNC) { 1158c2ecf20Sopenharmony_ci EMIT(PPC_INST_MFLR | __PPC_RT(R0)); 1168c2ecf20Sopenharmony_ci PPC_BPF_STL(0, 1, PPC_LR_STKOFF); 1178c2ecf20Sopenharmony_ci } 1188c2ecf20Sopenharmony_ci 1198c2ecf20Sopenharmony_ci PPC_BPF_STLU(1, 1, -(BPF_PPC_STACKFRAME + ctx->stack_size)); 1208c2ecf20Sopenharmony_ci } 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci /* 1238c2ecf20Sopenharmony_ci * Back up non-volatile regs -- BPF registers 6-10 1248c2ecf20Sopenharmony_ci * If we haven't created our own stack frame, we save these 1258c2ecf20Sopenharmony_ci * in the protected zone below the previous stack frame 1268c2ecf20Sopenharmony_ci */ 1278c2ecf20Sopenharmony_ci for (i = BPF_REG_6; i <= BPF_REG_10; i++) 1288c2ecf20Sopenharmony_ci if (bpf_is_seen_register(ctx, i)) 1298c2ecf20Sopenharmony_ci PPC_BPF_STL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 1308c2ecf20Sopenharmony_ci 1318c2ecf20Sopenharmony_ci /* Setup frame pointer to point to the bpf stack area */ 1328c2ecf20Sopenharmony_ci if (bpf_is_seen_register(ctx, BPF_REG_FP)) 1338c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[BPF_REG_FP], 1, 1348c2ecf20Sopenharmony_ci STACK_FRAME_MIN_SIZE + ctx->stack_size)); 1358c2ecf20Sopenharmony_ci} 1368c2ecf20Sopenharmony_ci 1378c2ecf20Sopenharmony_cistatic void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx) 1388c2ecf20Sopenharmony_ci{ 1398c2ecf20Sopenharmony_ci int i; 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci /* Restore NVRs */ 1428c2ecf20Sopenharmony_ci for (i = BPF_REG_6; i <= BPF_REG_10; i++) 1438c2ecf20Sopenharmony_ci if (bpf_is_seen_register(ctx, i)) 1448c2ecf20Sopenharmony_ci PPC_BPF_LL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 1458c2ecf20Sopenharmony_ci 1468c2ecf20Sopenharmony_ci /* Tear down our stack frame */ 1478c2ecf20Sopenharmony_ci if (bpf_has_stack_frame(ctx)) { 1488c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(1, 1, BPF_PPC_STACKFRAME + ctx->stack_size)); 1498c2ecf20Sopenharmony_ci if (ctx->seen & SEEN_FUNC) { 1508c2ecf20Sopenharmony_ci PPC_BPF_LL(0, 1, PPC_LR_STKOFF); 1518c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTLR(0)); 1528c2ecf20Sopenharmony_ci } 1538c2ecf20Sopenharmony_ci } 1548c2ecf20Sopenharmony_ci} 1558c2ecf20Sopenharmony_ci 1568c2ecf20Sopenharmony_cistatic void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci bpf_jit_emit_common_epilogue(image, ctx); 1598c2ecf20Sopenharmony_ci 1608c2ecf20Sopenharmony_ci /* Move result to r3 */ 1618c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MR(3, b2p[BPF_REG_0])); 1628c2ecf20Sopenharmony_ci 1638c2ecf20Sopenharmony_ci EMIT(PPC_RAW_BLR()); 1648c2ecf20Sopenharmony_ci} 1658c2ecf20Sopenharmony_ci 1668c2ecf20Sopenharmony_cistatic void bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, 1678c2ecf20Sopenharmony_ci u64 func) 1688c2ecf20Sopenharmony_ci{ 1698c2ecf20Sopenharmony_ci#ifdef PPC64_ELF_ABI_v1 1708c2ecf20Sopenharmony_ci /* func points to the function descriptor */ 1718c2ecf20Sopenharmony_ci PPC_LI64(b2p[TMP_REG_2], func); 1728c2ecf20Sopenharmony_ci /* Load actual entry point from function descriptor */ 1738c2ecf20Sopenharmony_ci PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); 1748c2ecf20Sopenharmony_ci /* ... and move it to LR */ 1758c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTLR(b2p[TMP_REG_1])); 1768c2ecf20Sopenharmony_ci /* 1778c2ecf20Sopenharmony_ci * Load TOC from function descriptor at offset 8. 1788c2ecf20Sopenharmony_ci * We can clobber r2 since we get called through a 1798c2ecf20Sopenharmony_ci * function pointer (so caller will save/restore r2) 1808c2ecf20Sopenharmony_ci * and since we don't use a TOC ourself. 1818c2ecf20Sopenharmony_ci */ 1828c2ecf20Sopenharmony_ci PPC_BPF_LL(2, b2p[TMP_REG_2], 8); 1838c2ecf20Sopenharmony_ci#else 1848c2ecf20Sopenharmony_ci /* We can clobber r12 */ 1858c2ecf20Sopenharmony_ci PPC_FUNC_ADDR(12, func); 1868c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTLR(12)); 1878c2ecf20Sopenharmony_ci#endif 1888c2ecf20Sopenharmony_ci EMIT(PPC_RAW_BLRL()); 1898c2ecf20Sopenharmony_ci} 1908c2ecf20Sopenharmony_ci 1918c2ecf20Sopenharmony_cistatic void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, 1928c2ecf20Sopenharmony_ci u64 func) 1938c2ecf20Sopenharmony_ci{ 1948c2ecf20Sopenharmony_ci unsigned int i, ctx_idx = ctx->idx; 1958c2ecf20Sopenharmony_ci 1968c2ecf20Sopenharmony_ci /* Load function address into r12 */ 1978c2ecf20Sopenharmony_ci PPC_LI64(12, func); 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci /* For bpf-to-bpf function calls, the callee's address is unknown 2008c2ecf20Sopenharmony_ci * until the last extra pass. As seen above, we use PPC_LI64() to 2018c2ecf20Sopenharmony_ci * load the callee's address, but this may optimize the number of 2028c2ecf20Sopenharmony_ci * instructions required based on the nature of the address. 2038c2ecf20Sopenharmony_ci * 2048c2ecf20Sopenharmony_ci * Since we don't want the number of instructions emitted to change, 2058c2ecf20Sopenharmony_ci * we pad the optimized PPC_LI64() call with NOPs to guarantee that 2068c2ecf20Sopenharmony_ci * we always have a five-instruction sequence, which is the maximum 2078c2ecf20Sopenharmony_ci * that PPC_LI64() can emit. 2088c2ecf20Sopenharmony_ci */ 2098c2ecf20Sopenharmony_ci for (i = ctx->idx - ctx_idx; i < 5; i++) 2108c2ecf20Sopenharmony_ci EMIT(PPC_RAW_NOP()); 2118c2ecf20Sopenharmony_ci 2128c2ecf20Sopenharmony_ci#ifdef PPC64_ELF_ABI_v1 2138c2ecf20Sopenharmony_ci /* 2148c2ecf20Sopenharmony_ci * Load TOC from function descriptor at offset 8. 2158c2ecf20Sopenharmony_ci * We can clobber r2 since we get called through a 2168c2ecf20Sopenharmony_ci * function pointer (so caller will save/restore r2) 2178c2ecf20Sopenharmony_ci * and since we don't use a TOC ourself. 2188c2ecf20Sopenharmony_ci */ 2198c2ecf20Sopenharmony_ci PPC_BPF_LL(2, 12, 8); 2208c2ecf20Sopenharmony_ci /* Load actual entry point from function descriptor */ 2218c2ecf20Sopenharmony_ci PPC_BPF_LL(12, 12, 0); 2228c2ecf20Sopenharmony_ci#endif 2238c2ecf20Sopenharmony_ci 2248c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTLR(12)); 2258c2ecf20Sopenharmony_ci EMIT(PPC_RAW_BLRL()); 2268c2ecf20Sopenharmony_ci} 2278c2ecf20Sopenharmony_ci 2288c2ecf20Sopenharmony_cistatic int bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) 2298c2ecf20Sopenharmony_ci{ 2308c2ecf20Sopenharmony_ci /* 2318c2ecf20Sopenharmony_ci * By now, the eBPF program has already setup parameters in r3, r4 and r5 2328c2ecf20Sopenharmony_ci * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program 2338c2ecf20Sopenharmony_ci * r4/BPF_REG_2 - pointer to bpf_array 2348c2ecf20Sopenharmony_ci * r5/BPF_REG_3 - index in bpf_array 2358c2ecf20Sopenharmony_ci */ 2368c2ecf20Sopenharmony_ci int b2p_bpf_array = b2p[BPF_REG_2]; 2378c2ecf20Sopenharmony_ci int b2p_index = b2p[BPF_REG_3]; 2388c2ecf20Sopenharmony_ci 2398c2ecf20Sopenharmony_ci /* 2408c2ecf20Sopenharmony_ci * if (index >= array->map.max_entries) 2418c2ecf20Sopenharmony_ci * goto out; 2428c2ecf20Sopenharmony_ci */ 2438c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries))); 2448c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM(b2p_index, b2p_index, 0, 0, 31)); 2458c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLW(b2p_index, b2p[TMP_REG_1])); 2468c2ecf20Sopenharmony_ci PPC_BCC(COND_GE, out); 2478c2ecf20Sopenharmony_ci 2488c2ecf20Sopenharmony_ci /* 2498c2ecf20Sopenharmony_ci * if (tail_call_cnt > MAX_TAIL_CALL_CNT) 2508c2ecf20Sopenharmony_ci * goto out; 2518c2ecf20Sopenharmony_ci */ 2528c2ecf20Sopenharmony_ci PPC_BPF_LL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); 2538c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLWI(b2p[TMP_REG_1], MAX_TAIL_CALL_CNT)); 2548c2ecf20Sopenharmony_ci PPC_BCC(COND_GT, out); 2558c2ecf20Sopenharmony_ci 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * tail_call_cnt++; 2588c2ecf20Sopenharmony_ci */ 2598c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1)); 2608c2ecf20Sopenharmony_ci PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); 2618c2ecf20Sopenharmony_ci 2628c2ecf20Sopenharmony_ci /* prog = array->ptrs[index]; */ 2638c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULI(b2p[TMP_REG_1], b2p_index, 8)); 2648c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array)); 2658c2ecf20Sopenharmony_ci PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs)); 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci /* 2688c2ecf20Sopenharmony_ci * if (prog == NULL) 2698c2ecf20Sopenharmony_ci * goto out; 2708c2ecf20Sopenharmony_ci */ 2718c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLDI(b2p[TMP_REG_1], 0)); 2728c2ecf20Sopenharmony_ci PPC_BCC(COND_EQ, out); 2738c2ecf20Sopenharmony_ci 2748c2ecf20Sopenharmony_ci /* goto *(prog->bpf_func + prologue_size); */ 2758c2ecf20Sopenharmony_ci PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func)); 2768c2ecf20Sopenharmony_ci#ifdef PPC64_ELF_ABI_v1 2778c2ecf20Sopenharmony_ci /* skip past the function descriptor */ 2788c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 2798c2ecf20Sopenharmony_ci FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE)); 2808c2ecf20Sopenharmony_ci#else 2818c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE)); 2828c2ecf20Sopenharmony_ci#endif 2838c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTCTR(b2p[TMP_REG_1])); 2848c2ecf20Sopenharmony_ci 2858c2ecf20Sopenharmony_ci /* tear down stack, restore NVRs, ... */ 2868c2ecf20Sopenharmony_ci bpf_jit_emit_common_epilogue(image, ctx); 2878c2ecf20Sopenharmony_ci 2888c2ecf20Sopenharmony_ci EMIT(PPC_RAW_BCTR()); 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci /* out: */ 2918c2ecf20Sopenharmony_ci return 0; 2928c2ecf20Sopenharmony_ci} 2938c2ecf20Sopenharmony_ci 2948c2ecf20Sopenharmony_ci/* 2958c2ecf20Sopenharmony_ci * We spill into the redzone always, even if the bpf program has its own stackframe. 2968c2ecf20Sopenharmony_ci * Offsets hardcoded based on BPF_PPC_STACK_SAVE -- see bpf_jit_stack_local() 2978c2ecf20Sopenharmony_ci */ 2988c2ecf20Sopenharmony_civoid bpf_stf_barrier(void); 2998c2ecf20Sopenharmony_ci 3008c2ecf20Sopenharmony_ciasm ( 3018c2ecf20Sopenharmony_ci" .global bpf_stf_barrier ;" 3028c2ecf20Sopenharmony_ci" bpf_stf_barrier: ;" 3038c2ecf20Sopenharmony_ci" std 21,-64(1) ;" 3048c2ecf20Sopenharmony_ci" std 22,-56(1) ;" 3058c2ecf20Sopenharmony_ci" sync ;" 3068c2ecf20Sopenharmony_ci" ld 21,-64(1) ;" 3078c2ecf20Sopenharmony_ci" ld 22,-56(1) ;" 3088c2ecf20Sopenharmony_ci" ori 31,31,0 ;" 3098c2ecf20Sopenharmony_ci" .rept 14 ;" 3108c2ecf20Sopenharmony_ci" b 1f ;" 3118c2ecf20Sopenharmony_ci" 1: ;" 3128c2ecf20Sopenharmony_ci" .endr ;" 3138c2ecf20Sopenharmony_ci" blr ;" 3148c2ecf20Sopenharmony_ci); 3158c2ecf20Sopenharmony_ci 3168c2ecf20Sopenharmony_ci/* Assemble the body code between the prologue & epilogue */ 3178c2ecf20Sopenharmony_cistatic int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, 3188c2ecf20Sopenharmony_ci struct codegen_context *ctx, 3198c2ecf20Sopenharmony_ci u32 *addrs, bool extra_pass) 3208c2ecf20Sopenharmony_ci{ 3218c2ecf20Sopenharmony_ci enum stf_barrier_type stf_barrier = stf_barrier_type_get(); 3228c2ecf20Sopenharmony_ci const struct bpf_insn *insn = fp->insnsi; 3238c2ecf20Sopenharmony_ci int flen = fp->len; 3248c2ecf20Sopenharmony_ci int i, ret; 3258c2ecf20Sopenharmony_ci 3268c2ecf20Sopenharmony_ci /* Start of epilogue code - will only be valid 2nd pass onwards */ 3278c2ecf20Sopenharmony_ci u32 exit_addr = addrs[flen]; 3288c2ecf20Sopenharmony_ci 3298c2ecf20Sopenharmony_ci for (i = 0; i < flen; i++) { 3308c2ecf20Sopenharmony_ci u32 code = insn[i].code; 3318c2ecf20Sopenharmony_ci u32 dst_reg = b2p[insn[i].dst_reg]; 3328c2ecf20Sopenharmony_ci u32 src_reg = b2p[insn[i].src_reg]; 3338c2ecf20Sopenharmony_ci s16 off = insn[i].off; 3348c2ecf20Sopenharmony_ci s32 imm = insn[i].imm; 3358c2ecf20Sopenharmony_ci bool func_addr_fixed; 3368c2ecf20Sopenharmony_ci u64 func_addr; 3378c2ecf20Sopenharmony_ci u64 imm64; 3388c2ecf20Sopenharmony_ci u32 true_cond; 3398c2ecf20Sopenharmony_ci u32 tmp_idx; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci /* 3428c2ecf20Sopenharmony_ci * addrs[] maps a BPF bytecode address into a real offset from 3438c2ecf20Sopenharmony_ci * the start of the body code. 3448c2ecf20Sopenharmony_ci */ 3458c2ecf20Sopenharmony_ci addrs[i] = ctx->idx * 4; 3468c2ecf20Sopenharmony_ci 3478c2ecf20Sopenharmony_ci /* 3488c2ecf20Sopenharmony_ci * As an optimization, we note down which non-volatile registers 3498c2ecf20Sopenharmony_ci * are used so that we can only save/restore those in our 3508c2ecf20Sopenharmony_ci * prologue and epilogue. We do this here regardless of whether 3518c2ecf20Sopenharmony_ci * the actual BPF instruction uses src/dst registers or not 3528c2ecf20Sopenharmony_ci * (for instance, BPF_CALL does not use them). The expectation 3538c2ecf20Sopenharmony_ci * is that those instructions will have src_reg/dst_reg set to 3548c2ecf20Sopenharmony_ci * 0. Even otherwise, we just lose some prologue/epilogue 3558c2ecf20Sopenharmony_ci * optimization but everything else should work without 3568c2ecf20Sopenharmony_ci * any issues. 3578c2ecf20Sopenharmony_ci */ 3588c2ecf20Sopenharmony_ci if (dst_reg >= BPF_PPC_NVR_MIN && dst_reg < 32) 3598c2ecf20Sopenharmony_ci bpf_set_seen_register(ctx, insn[i].dst_reg); 3608c2ecf20Sopenharmony_ci if (src_reg >= BPF_PPC_NVR_MIN && src_reg < 32) 3618c2ecf20Sopenharmony_ci bpf_set_seen_register(ctx, insn[i].src_reg); 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci switch (code) { 3648c2ecf20Sopenharmony_ci /* 3658c2ecf20Sopenharmony_ci * Arithmetic operations: ADD/SUB/MUL/DIV/MOD/NEG 3668c2ecf20Sopenharmony_ci */ 3678c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_X: /* (u32) dst += (u32) src */ 3688c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_X: /* dst += src */ 3698c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADD(dst_reg, dst_reg, src_reg)); 3708c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3718c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_X: /* (u32) dst -= (u32) src */ 3728c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_X: /* dst -= src */ 3738c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, src_reg)); 3748c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3758c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */ 3768c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */ 3778c2ecf20Sopenharmony_ci if (!imm) { 3788c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3798c2ecf20Sopenharmony_ci } else if (imm >= -32768 && imm < 32768) { 3808c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(dst_reg, dst_reg, IMM_L(imm))); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 3838c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADD(dst_reg, dst_reg, b2p[TMP_REG_1])); 3848c2ecf20Sopenharmony_ci } 3858c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3868c2ecf20Sopenharmony_ci case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */ 3878c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */ 3888c2ecf20Sopenharmony_ci if (!imm) { 3898c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3908c2ecf20Sopenharmony_ci } else if (imm > -32768 && imm <= 32768) { 3918c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(dst_reg, dst_reg, IMM_L(-imm))); 3928c2ecf20Sopenharmony_ci } else { 3938c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 3948c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1])); 3958c2ecf20Sopenharmony_ci } 3968c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 3978c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */ 3988c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_X: /* dst *= src */ 3998c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ALU) 4008c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULW(dst_reg, dst_reg, src_reg)); 4018c2ecf20Sopenharmony_ci else 4028c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULD(dst_reg, dst_reg, src_reg)); 4038c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4048c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MUL | BPF_K: /* (u32) dst *= (u32) imm */ 4058c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MUL | BPF_K: /* dst *= imm */ 4068c2ecf20Sopenharmony_ci if (imm >= -32768 && imm < 32768) 4078c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULI(dst_reg, dst_reg, IMM_L(imm))); 4088c2ecf20Sopenharmony_ci else { 4098c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 4108c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ALU) 4118c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULW(dst_reg, dst_reg, 4128c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4138c2ecf20Sopenharmony_ci else 4148c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULD(dst_reg, dst_reg, 4158c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4168c2ecf20Sopenharmony_ci } 4178c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4188c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */ 4198c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */ 4208c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_MOD) { 4218c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVWU(b2p[TMP_REG_1], dst_reg, src_reg)); 4228c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULW(b2p[TMP_REG_1], src_reg, 4238c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4248c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1])); 4258c2ecf20Sopenharmony_ci } else 4268c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, src_reg)); 4278c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4288c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */ 4298c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_X: /* dst %= src */ 4308c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_MOD) { 4318c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVDU(b2p[TMP_REG_1], dst_reg, src_reg)); 4328c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULD(b2p[TMP_REG_1], src_reg, 4338c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4348c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, b2p[TMP_REG_1])); 4358c2ecf20Sopenharmony_ci } else 4368c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, src_reg)); 4378c2ecf20Sopenharmony_ci break; 4388c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */ 4398c2ecf20Sopenharmony_ci case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */ 4408c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOD | BPF_K: /* dst %= imm */ 4418c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */ 4428c2ecf20Sopenharmony_ci if (imm == 0) 4438c2ecf20Sopenharmony_ci return -EINVAL; 4448c2ecf20Sopenharmony_ci if (imm == 1) { 4458c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_DIV) { 4468c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4478c2ecf20Sopenharmony_ci } else { 4488c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LI(dst_reg, 0)); 4498c2ecf20Sopenharmony_ci break; 4508c2ecf20Sopenharmony_ci } 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 4548c2ecf20Sopenharmony_ci switch (BPF_CLASS(code)) { 4558c2ecf20Sopenharmony_ci case BPF_ALU: 4568c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_MOD) { 4578c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVWU(b2p[TMP_REG_2], 4588c2ecf20Sopenharmony_ci dst_reg, 4598c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4608c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULW(b2p[TMP_REG_1], 4618c2ecf20Sopenharmony_ci b2p[TMP_REG_1], 4628c2ecf20Sopenharmony_ci b2p[TMP_REG_2])); 4638c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, 4648c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4658c2ecf20Sopenharmony_ci } else 4668c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVWU(dst_reg, dst_reg, 4678c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4688c2ecf20Sopenharmony_ci break; 4698c2ecf20Sopenharmony_ci case BPF_ALU64: 4708c2ecf20Sopenharmony_ci if (BPF_OP(code) == BPF_MOD) { 4718c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVDU(b2p[TMP_REG_2], 4728c2ecf20Sopenharmony_ci dst_reg, 4738c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4748c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MULD(b2p[TMP_REG_1], 4758c2ecf20Sopenharmony_ci b2p[TMP_REG_1], 4768c2ecf20Sopenharmony_ci b2p[TMP_REG_2])); 4778c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SUB(dst_reg, dst_reg, 4788c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4798c2ecf20Sopenharmony_ci } else 4808c2ecf20Sopenharmony_ci EMIT(PPC_RAW_DIVDU(dst_reg, dst_reg, 4818c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 4828c2ecf20Sopenharmony_ci break; 4838c2ecf20Sopenharmony_ci } 4848c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4858c2ecf20Sopenharmony_ci case BPF_ALU | BPF_NEG: /* (u32) dst = -dst */ 4868c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_NEG: /* dst = -dst */ 4878c2ecf20Sopenharmony_ci EMIT(PPC_RAW_NEG(dst_reg, dst_reg)); 4888c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4898c2ecf20Sopenharmony_ci 4908c2ecf20Sopenharmony_ci /* 4918c2ecf20Sopenharmony_ci * Logical operations: AND/OR/XOR/[A]LSH/[A]RSH 4928c2ecf20Sopenharmony_ci */ 4938c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_X: /* (u32) dst = dst & src */ 4948c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */ 4958c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND(dst_reg, dst_reg, src_reg)); 4968c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 4978c2ecf20Sopenharmony_ci case BPF_ALU | BPF_AND | BPF_K: /* (u32) dst = dst & imm */ 4988c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */ 4998c2ecf20Sopenharmony_ci if (!IMM_H(imm)) 5008c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ANDI(dst_reg, dst_reg, IMM_L(imm))); 5018c2ecf20Sopenharmony_ci else { 5028c2ecf20Sopenharmony_ci /* Sign-extended */ 5038c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 5048c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND(dst_reg, dst_reg, b2p[TMP_REG_1])); 5058c2ecf20Sopenharmony_ci } 5068c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5078c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */ 5088c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */ 5098c2ecf20Sopenharmony_ci EMIT(PPC_RAW_OR(dst_reg, dst_reg, src_reg)); 5108c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5118c2ecf20Sopenharmony_ci case BPF_ALU | BPF_OR | BPF_K:/* dst = (u32) dst | (u32) imm */ 5128c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_OR | BPF_K:/* dst = dst | imm */ 5138c2ecf20Sopenharmony_ci if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 5148c2ecf20Sopenharmony_ci /* Sign-extended */ 5158c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 5168c2ecf20Sopenharmony_ci EMIT(PPC_RAW_OR(dst_reg, dst_reg, b2p[TMP_REG_1])); 5178c2ecf20Sopenharmony_ci } else { 5188c2ecf20Sopenharmony_ci if (IMM_L(imm)) 5198c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ORI(dst_reg, dst_reg, IMM_L(imm))); 5208c2ecf20Sopenharmony_ci if (IMM_H(imm)) 5218c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ORIS(dst_reg, dst_reg, IMM_H(imm))); 5228c2ecf20Sopenharmony_ci } 5238c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5248c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_X: /* (u32) dst ^= src */ 5258c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_X: /* dst ^= src */ 5268c2ecf20Sopenharmony_ci EMIT(PPC_RAW_XOR(dst_reg, dst_reg, src_reg)); 5278c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5288c2ecf20Sopenharmony_ci case BPF_ALU | BPF_XOR | BPF_K: /* (u32) dst ^= (u32) imm */ 5298c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_XOR | BPF_K: /* dst ^= imm */ 5308c2ecf20Sopenharmony_ci if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 5318c2ecf20Sopenharmony_ci /* Sign-extended */ 5328c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 5338c2ecf20Sopenharmony_ci EMIT(PPC_RAW_XOR(dst_reg, dst_reg, b2p[TMP_REG_1])); 5348c2ecf20Sopenharmony_ci } else { 5358c2ecf20Sopenharmony_ci if (IMM_L(imm)) 5368c2ecf20Sopenharmony_ci EMIT(PPC_RAW_XORI(dst_reg, dst_reg, IMM_L(imm))); 5378c2ecf20Sopenharmony_ci if (IMM_H(imm)) 5388c2ecf20Sopenharmony_ci EMIT(PPC_RAW_XORIS(dst_reg, dst_reg, IMM_H(imm))); 5398c2ecf20Sopenharmony_ci } 5408c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5418c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_X: /* (u32) dst <<= (u32) src */ 5428c2ecf20Sopenharmony_ci /* slw clears top 32 bits */ 5438c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLW(dst_reg, dst_reg, src_reg)); 5448c2ecf20Sopenharmony_ci /* skip zero extension move, but set address map. */ 5458c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 5468c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 5478c2ecf20Sopenharmony_ci break; 5488c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_X: /* dst <<= src; */ 5498c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLD(dst_reg, dst_reg, src_reg)); 5508c2ecf20Sopenharmony_ci break; 5518c2ecf20Sopenharmony_ci case BPF_ALU | BPF_LSH | BPF_K: /* (u32) dst <<== (u32) imm */ 5528c2ecf20Sopenharmony_ci /* with imm 0, we still need to clear top 32 bits */ 5538c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLWI(dst_reg, dst_reg, imm)); 5548c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 5558c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 5568c2ecf20Sopenharmony_ci break; 5578c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_LSH | BPF_K: /* dst <<== imm */ 5588c2ecf20Sopenharmony_ci if (imm != 0) 5598c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLDI(dst_reg, dst_reg, imm)); 5608c2ecf20Sopenharmony_ci break; 5618c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_X: /* (u32) dst >>= (u32) src */ 5628c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRW(dst_reg, dst_reg, src_reg)); 5638c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 5648c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 5658c2ecf20Sopenharmony_ci break; 5668c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_X: /* dst >>= src */ 5678c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRD(dst_reg, dst_reg, src_reg)); 5688c2ecf20Sopenharmony_ci break; 5698c2ecf20Sopenharmony_ci case BPF_ALU | BPF_RSH | BPF_K: /* (u32) dst >>= (u32) imm */ 5708c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRWI(dst_reg, dst_reg, imm)); 5718c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 5728c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 5738c2ecf20Sopenharmony_ci break; 5748c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_RSH | BPF_K: /* dst >>= imm */ 5758c2ecf20Sopenharmony_ci if (imm != 0) 5768c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRDI(dst_reg, dst_reg, imm)); 5778c2ecf20Sopenharmony_ci break; 5788c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_X: /* (s32) dst >>= src */ 5798c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRAW(dst_reg, dst_reg, src_reg)); 5808c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5818c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */ 5828c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRAD(dst_reg, dst_reg, src_reg)); 5838c2ecf20Sopenharmony_ci break; 5848c2ecf20Sopenharmony_ci case BPF_ALU | BPF_ARSH | BPF_K: /* (s32) dst >>= imm */ 5858c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRAWI(dst_reg, dst_reg, imm)); 5868c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 5878c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */ 5888c2ecf20Sopenharmony_ci if (imm != 0) 5898c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SRADI(dst_reg, dst_reg, imm)); 5908c2ecf20Sopenharmony_ci break; 5918c2ecf20Sopenharmony_ci 5928c2ecf20Sopenharmony_ci /* 5938c2ecf20Sopenharmony_ci * MOV 5948c2ecf20Sopenharmony_ci */ 5958c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_X: /* (u32) dst = src */ 5968c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */ 5978c2ecf20Sopenharmony_ci if (imm == 1) { 5988c2ecf20Sopenharmony_ci /* special mov32 for zext */ 5998c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 0, 31)); 6008c2ecf20Sopenharmony_ci break; 6018c2ecf20Sopenharmony_ci } 6028c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MR(dst_reg, src_reg)); 6038c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 6048c2ecf20Sopenharmony_ci case BPF_ALU | BPF_MOV | BPF_K: /* (u32) dst = imm */ 6058c2ecf20Sopenharmony_ci case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = (s64) imm */ 6068c2ecf20Sopenharmony_ci PPC_LI32(dst_reg, imm); 6078c2ecf20Sopenharmony_ci if (imm < 0) 6088c2ecf20Sopenharmony_ci goto bpf_alu32_trunc; 6098c2ecf20Sopenharmony_ci else if (insn_is_zext(&insn[i + 1])) 6108c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 6118c2ecf20Sopenharmony_ci break; 6128c2ecf20Sopenharmony_ci 6138c2ecf20Sopenharmony_cibpf_alu32_trunc: 6148c2ecf20Sopenharmony_ci /* Truncate to 32-bits */ 6158c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ALU && !fp->aux->verifier_zext) 6168c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM(dst_reg, dst_reg, 0, 0, 31)); 6178c2ecf20Sopenharmony_ci break; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci /* 6208c2ecf20Sopenharmony_ci * BPF_FROM_BE/LE 6218c2ecf20Sopenharmony_ci */ 6228c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_LE: 6238c2ecf20Sopenharmony_ci case BPF_ALU | BPF_END | BPF_FROM_BE: 6248c2ecf20Sopenharmony_ci#ifdef __BIG_ENDIAN__ 6258c2ecf20Sopenharmony_ci if (BPF_SRC(code) == BPF_FROM_BE) 6268c2ecf20Sopenharmony_ci goto emit_clear; 6278c2ecf20Sopenharmony_ci#else /* !__BIG_ENDIAN__ */ 6288c2ecf20Sopenharmony_ci if (BPF_SRC(code) == BPF_FROM_LE) 6298c2ecf20Sopenharmony_ci goto emit_clear; 6308c2ecf20Sopenharmony_ci#endif 6318c2ecf20Sopenharmony_ci switch (imm) { 6328c2ecf20Sopenharmony_ci case 16: 6338c2ecf20Sopenharmony_ci /* Rotate 8 bits left & mask with 0x0000ff00 */ 6348c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 16, 23)); 6358c2ecf20Sopenharmony_ci /* Rotate 8 bits right & insert LSB to reg */ 6368c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 24, 31)); 6378c2ecf20Sopenharmony_ci /* Move result back to dst_reg */ 6388c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1])); 6398c2ecf20Sopenharmony_ci break; 6408c2ecf20Sopenharmony_ci case 32: 6418c2ecf20Sopenharmony_ci /* 6428c2ecf20Sopenharmony_ci * Rotate word left by 8 bits: 6438c2ecf20Sopenharmony_ci * 2 bytes are already in their final position 6448c2ecf20Sopenharmony_ci * -- byte 2 and 4 (of bytes 1, 2, 3 and 4) 6458c2ecf20Sopenharmony_ci */ 6468c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 0, 31)); 6478c2ecf20Sopenharmony_ci /* Rotate 24 bits and insert byte 1 */ 6488c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 0, 7)); 6498c2ecf20Sopenharmony_ci /* Rotate 24 bits and insert byte 3 */ 6508c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 16, 23)); 6518c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MR(dst_reg, b2p[TMP_REG_1])); 6528c2ecf20Sopenharmony_ci break; 6538c2ecf20Sopenharmony_ci case 64: 6548c2ecf20Sopenharmony_ci /* Store the value to stack and then use byte-reverse loads */ 6558c2ecf20Sopenharmony_ci PPC_BPF_STL(dst_reg, 1, bpf_jit_stack_local(ctx)); 6568c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx))); 6578c2ecf20Sopenharmony_ci if (cpu_has_feature(CPU_FTR_ARCH_206)) { 6588c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LDBRX(dst_reg, 0, b2p[TMP_REG_1])); 6598c2ecf20Sopenharmony_ci } else { 6608c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LWBRX(dst_reg, 0, b2p[TMP_REG_1])); 6618c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_CPU_LITTLE_ENDIAN)) 6628c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLDI(dst_reg, dst_reg, 32)); 6638c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LI(b2p[TMP_REG_2], 4)); 6648c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LWBRX(b2p[TMP_REG_2], b2p[TMP_REG_2], b2p[TMP_REG_1])); 6658c2ecf20Sopenharmony_ci if (IS_ENABLED(CONFIG_CPU_BIG_ENDIAN)) 6668c2ecf20Sopenharmony_ci EMIT(PPC_RAW_SLDI(b2p[TMP_REG_2], b2p[TMP_REG_2], 32)); 6678c2ecf20Sopenharmony_ci EMIT(PPC_RAW_OR(dst_reg, dst_reg, b2p[TMP_REG_2])); 6688c2ecf20Sopenharmony_ci } 6698c2ecf20Sopenharmony_ci break; 6708c2ecf20Sopenharmony_ci } 6718c2ecf20Sopenharmony_ci break; 6728c2ecf20Sopenharmony_ci 6738c2ecf20Sopenharmony_ciemit_clear: 6748c2ecf20Sopenharmony_ci switch (imm) { 6758c2ecf20Sopenharmony_ci case 16: 6768c2ecf20Sopenharmony_ci /* zero-extend 16 bits into 64 bits */ 6778c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLDICL(dst_reg, dst_reg, 0, 48)); 6788c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 6798c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 6808c2ecf20Sopenharmony_ci break; 6818c2ecf20Sopenharmony_ci case 32: 6828c2ecf20Sopenharmony_ci if (!fp->aux->verifier_zext) 6838c2ecf20Sopenharmony_ci /* zero-extend 32 bits into 64 bits */ 6848c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLDICL(dst_reg, dst_reg, 0, 32)); 6858c2ecf20Sopenharmony_ci break; 6868c2ecf20Sopenharmony_ci case 64: 6878c2ecf20Sopenharmony_ci /* nop */ 6888c2ecf20Sopenharmony_ci break; 6898c2ecf20Sopenharmony_ci } 6908c2ecf20Sopenharmony_ci break; 6918c2ecf20Sopenharmony_ci 6928c2ecf20Sopenharmony_ci /* 6938c2ecf20Sopenharmony_ci * BPF_ST NOSPEC (speculation barrier) 6948c2ecf20Sopenharmony_ci */ 6958c2ecf20Sopenharmony_ci case BPF_ST | BPF_NOSPEC: 6968c2ecf20Sopenharmony_ci if (!security_ftr_enabled(SEC_FTR_FAVOUR_SECURITY) || 6978c2ecf20Sopenharmony_ci (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_PR) && 6988c2ecf20Sopenharmony_ci (!security_ftr_enabled(SEC_FTR_L1D_FLUSH_HV) || !cpu_has_feature(CPU_FTR_HVMODE)))) 6998c2ecf20Sopenharmony_ci break; 7008c2ecf20Sopenharmony_ci 7018c2ecf20Sopenharmony_ci switch (stf_barrier) { 7028c2ecf20Sopenharmony_ci case STF_BARRIER_EIEIO: 7038c2ecf20Sopenharmony_ci EMIT(0x7c0006ac | 0x02000000); 7048c2ecf20Sopenharmony_ci break; 7058c2ecf20Sopenharmony_ci case STF_BARRIER_SYNC_ORI: 7068c2ecf20Sopenharmony_ci EMIT(PPC_INST_SYNC); 7078c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LD(b2p[TMP_REG_1], 13, 0)); 7088c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ORI(31, 31, 0)); 7098c2ecf20Sopenharmony_ci break; 7108c2ecf20Sopenharmony_ci case STF_BARRIER_FALLBACK: 7118c2ecf20Sopenharmony_ci EMIT(PPC_INST_MFLR | ___PPC_RT(b2p[TMP_REG_1])); 7128c2ecf20Sopenharmony_ci PPC_LI64(12, dereference_kernel_function_descriptor(bpf_stf_barrier)); 7138c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTCTR(12)); 7148c2ecf20Sopenharmony_ci EMIT(PPC_INST_BCTR | 0x1); 7158c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MTLR(b2p[TMP_REG_1])); 7168c2ecf20Sopenharmony_ci break; 7178c2ecf20Sopenharmony_ci case STF_BARRIER_NONE: 7188c2ecf20Sopenharmony_ci break; 7198c2ecf20Sopenharmony_ci } 7208c2ecf20Sopenharmony_ci break; 7218c2ecf20Sopenharmony_ci 7228c2ecf20Sopenharmony_ci /* 7238c2ecf20Sopenharmony_ci * BPF_ST(X) 7248c2ecf20Sopenharmony_ci */ 7258c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */ 7268c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */ 7278c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 7288c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LI(b2p[TMP_REG_1], imm)); 7298c2ecf20Sopenharmony_ci src_reg = b2p[TMP_REG_1]; 7308c2ecf20Sopenharmony_ci } 7318c2ecf20Sopenharmony_ci EMIT(PPC_RAW_STB(src_reg, dst_reg, off)); 7328c2ecf20Sopenharmony_ci break; 7338c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */ 7348c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */ 7358c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 7368c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LI(b2p[TMP_REG_1], imm)); 7378c2ecf20Sopenharmony_ci src_reg = b2p[TMP_REG_1]; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci EMIT(PPC_RAW_STH(src_reg, dst_reg, off)); 7408c2ecf20Sopenharmony_ci break; 7418c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */ 7428c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */ 7438c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 7448c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 7458c2ecf20Sopenharmony_ci src_reg = b2p[TMP_REG_1]; 7468c2ecf20Sopenharmony_ci } 7478c2ecf20Sopenharmony_ci EMIT(PPC_RAW_STW(src_reg, dst_reg, off)); 7488c2ecf20Sopenharmony_ci break; 7498c2ecf20Sopenharmony_ci case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */ 7508c2ecf20Sopenharmony_ci case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */ 7518c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_ST) { 7528c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 7538c2ecf20Sopenharmony_ci src_reg = b2p[TMP_REG_1]; 7548c2ecf20Sopenharmony_ci } 7558c2ecf20Sopenharmony_ci PPC_BPF_STL(src_reg, dst_reg, off); 7568c2ecf20Sopenharmony_ci break; 7578c2ecf20Sopenharmony_ci 7588c2ecf20Sopenharmony_ci /* 7598c2ecf20Sopenharmony_ci * BPF_STX XADD (atomic_add) 7608c2ecf20Sopenharmony_ci */ 7618c2ecf20Sopenharmony_ci /* *(u32 *)(dst + off) += src */ 7628c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_W: 7638c2ecf20Sopenharmony_ci /* Get EA into TMP_REG_1 */ 7648c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], dst_reg, off)); 7658c2ecf20Sopenharmony_ci tmp_idx = ctx->idx * 4; 7668c2ecf20Sopenharmony_ci /* load value from memory into TMP_REG_2 */ 7678c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0)); 7688c2ecf20Sopenharmony_ci /* add value from src_reg into this */ 7698c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg)); 7708c2ecf20Sopenharmony_ci /* store result back */ 7718c2ecf20Sopenharmony_ci EMIT(PPC_RAW_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1])); 7728c2ecf20Sopenharmony_ci /* we're done if this succeeded */ 7738c2ecf20Sopenharmony_ci PPC_BCC_SHORT(COND_NE, tmp_idx); 7748c2ecf20Sopenharmony_ci break; 7758c2ecf20Sopenharmony_ci /* *(u64 *)(dst + off) += src */ 7768c2ecf20Sopenharmony_ci case BPF_STX | BPF_XADD | BPF_DW: 7778c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADDI(b2p[TMP_REG_1], dst_reg, off)); 7788c2ecf20Sopenharmony_ci tmp_idx = ctx->idx * 4; 7798c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0)); 7808c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg)); 7818c2ecf20Sopenharmony_ci EMIT(PPC_RAW_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1])); 7828c2ecf20Sopenharmony_ci PPC_BCC_SHORT(COND_NE, tmp_idx); 7838c2ecf20Sopenharmony_ci break; 7848c2ecf20Sopenharmony_ci 7858c2ecf20Sopenharmony_ci /* 7868c2ecf20Sopenharmony_ci * BPF_LDX 7878c2ecf20Sopenharmony_ci */ 7888c2ecf20Sopenharmony_ci /* dst = *(u8 *)(ul) (src + off) */ 7898c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_B: 7908c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LBZ(dst_reg, src_reg, off)); 7918c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 7928c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 7938c2ecf20Sopenharmony_ci break; 7948c2ecf20Sopenharmony_ci /* dst = *(u16 *)(ul) (src + off) */ 7958c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_H: 7968c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LHZ(dst_reg, src_reg, off)); 7978c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 7988c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 7998c2ecf20Sopenharmony_ci break; 8008c2ecf20Sopenharmony_ci /* dst = *(u32 *)(ul) (src + off) */ 8018c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_W: 8028c2ecf20Sopenharmony_ci EMIT(PPC_RAW_LWZ(dst_reg, src_reg, off)); 8038c2ecf20Sopenharmony_ci if (insn_is_zext(&insn[i + 1])) 8048c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 8058c2ecf20Sopenharmony_ci break; 8068c2ecf20Sopenharmony_ci /* dst = *(u64 *)(ul) (src + off) */ 8078c2ecf20Sopenharmony_ci case BPF_LDX | BPF_MEM | BPF_DW: 8088c2ecf20Sopenharmony_ci PPC_BPF_LL(dst_reg, src_reg, off); 8098c2ecf20Sopenharmony_ci break; 8108c2ecf20Sopenharmony_ci 8118c2ecf20Sopenharmony_ci /* 8128c2ecf20Sopenharmony_ci * Doubleword load 8138c2ecf20Sopenharmony_ci * 16 byte instruction that uses two 'struct bpf_insn' 8148c2ecf20Sopenharmony_ci */ 8158c2ecf20Sopenharmony_ci case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ 8168c2ecf20Sopenharmony_ci imm64 = ((u64)(u32) insn[i].imm) | 8178c2ecf20Sopenharmony_ci (((u64)(u32) insn[i+1].imm) << 32); 8188c2ecf20Sopenharmony_ci /* Adjust for two bpf instructions */ 8198c2ecf20Sopenharmony_ci addrs[++i] = ctx->idx * 4; 8208c2ecf20Sopenharmony_ci PPC_LI64(dst_reg, imm64); 8218c2ecf20Sopenharmony_ci break; 8228c2ecf20Sopenharmony_ci 8238c2ecf20Sopenharmony_ci /* 8248c2ecf20Sopenharmony_ci * Return/Exit 8258c2ecf20Sopenharmony_ci */ 8268c2ecf20Sopenharmony_ci case BPF_JMP | BPF_EXIT: 8278c2ecf20Sopenharmony_ci /* 8288c2ecf20Sopenharmony_ci * If this isn't the very last instruction, branch to 8298c2ecf20Sopenharmony_ci * the epilogue. If we _are_ the last instruction, 8308c2ecf20Sopenharmony_ci * we'll just fall through to the epilogue. 8318c2ecf20Sopenharmony_ci */ 8328c2ecf20Sopenharmony_ci if (i != flen - 1) 8338c2ecf20Sopenharmony_ci PPC_JMP(exit_addr); 8348c2ecf20Sopenharmony_ci /* else fall through to the epilogue */ 8358c2ecf20Sopenharmony_ci break; 8368c2ecf20Sopenharmony_ci 8378c2ecf20Sopenharmony_ci /* 8388c2ecf20Sopenharmony_ci * Call kernel helper or bpf function 8398c2ecf20Sopenharmony_ci */ 8408c2ecf20Sopenharmony_ci case BPF_JMP | BPF_CALL: 8418c2ecf20Sopenharmony_ci ctx->seen |= SEEN_FUNC; 8428c2ecf20Sopenharmony_ci 8438c2ecf20Sopenharmony_ci ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass, 8448c2ecf20Sopenharmony_ci &func_addr, &func_addr_fixed); 8458c2ecf20Sopenharmony_ci if (ret < 0) 8468c2ecf20Sopenharmony_ci return ret; 8478c2ecf20Sopenharmony_ci 8488c2ecf20Sopenharmony_ci if (func_addr_fixed) 8498c2ecf20Sopenharmony_ci bpf_jit_emit_func_call_hlp(image, ctx, func_addr); 8508c2ecf20Sopenharmony_ci else 8518c2ecf20Sopenharmony_ci bpf_jit_emit_func_call_rel(image, ctx, func_addr); 8528c2ecf20Sopenharmony_ci /* move return value from r3 to BPF_REG_0 */ 8538c2ecf20Sopenharmony_ci EMIT(PPC_RAW_MR(b2p[BPF_REG_0], 3)); 8548c2ecf20Sopenharmony_ci break; 8558c2ecf20Sopenharmony_ci 8568c2ecf20Sopenharmony_ci /* 8578c2ecf20Sopenharmony_ci * Jumps and branches 8588c2ecf20Sopenharmony_ci */ 8598c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JA: 8608c2ecf20Sopenharmony_ci PPC_JMP(addrs[i + 1 + off]); 8618c2ecf20Sopenharmony_ci break; 8628c2ecf20Sopenharmony_ci 8638c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 8648c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 8658c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 8668c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 8678c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 8688c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 8698c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 8708c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 8718c2ecf20Sopenharmony_ci true_cond = COND_GT; 8728c2ecf20Sopenharmony_ci goto cond_branch; 8738c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 8748c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 8758c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 8768c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 8778c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 8788c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 8798c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 8808c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 8818c2ecf20Sopenharmony_ci true_cond = COND_LT; 8828c2ecf20Sopenharmony_ci goto cond_branch; 8838c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 8848c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 8858c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 8868c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 8878c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 8888c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 8898c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 8908c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 8918c2ecf20Sopenharmony_ci true_cond = COND_GE; 8928c2ecf20Sopenharmony_ci goto cond_branch; 8938c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 8948c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 8958c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 8968c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 8978c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 8988c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 8998c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 9008c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 9018c2ecf20Sopenharmony_ci true_cond = COND_LE; 9028c2ecf20Sopenharmony_ci goto cond_branch; 9038c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 9048c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 9058c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 9068c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 9078c2ecf20Sopenharmony_ci true_cond = COND_EQ; 9088c2ecf20Sopenharmony_ci goto cond_branch; 9098c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 9108c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 9118c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 9128c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 9138c2ecf20Sopenharmony_ci true_cond = COND_NE; 9148c2ecf20Sopenharmony_ci goto cond_branch; 9158c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 9168c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 9178c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 9188c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 9198c2ecf20Sopenharmony_ci true_cond = COND_NE; 9208c2ecf20Sopenharmony_ci /* Fall through */ 9218c2ecf20Sopenharmony_ci 9228c2ecf20Sopenharmony_cicond_branch: 9238c2ecf20Sopenharmony_ci switch (code) { 9248c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_X: 9258c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_X: 9268c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_X: 9278c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_X: 9288c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_X: 9298c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_X: 9308c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_X: 9318c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_X: 9328c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_X: 9338c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_X: 9348c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_X: 9358c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_X: 9368c2ecf20Sopenharmony_ci /* unsigned comparison */ 9378c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_JMP32) 9388c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLW(dst_reg, src_reg)); 9398c2ecf20Sopenharmony_ci else 9408c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLD(dst_reg, src_reg)); 9418c2ecf20Sopenharmony_ci break; 9428c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_X: 9438c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_X: 9448c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_X: 9458c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_X: 9468c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_X: 9478c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_X: 9488c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_X: 9498c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_X: 9508c2ecf20Sopenharmony_ci /* signed comparison */ 9518c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_JMP32) 9528c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPW(dst_reg, src_reg)); 9538c2ecf20Sopenharmony_ci else 9548c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPD(dst_reg, src_reg)); 9558c2ecf20Sopenharmony_ci break; 9568c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_X: 9578c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_X: 9588c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_JMP) { 9598c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND_DOT(b2p[TMP_REG_1], dst_reg, 9608c2ecf20Sopenharmony_ci src_reg)); 9618c2ecf20Sopenharmony_ci } else { 9628c2ecf20Sopenharmony_ci int tmp_reg = b2p[TMP_REG_1]; 9638c2ecf20Sopenharmony_ci 9648c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND(tmp_reg, dst_reg, src_reg)); 9658c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM_DOT(tmp_reg, tmp_reg, 0, 0, 9668c2ecf20Sopenharmony_ci 31)); 9678c2ecf20Sopenharmony_ci } 9688c2ecf20Sopenharmony_ci break; 9698c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JNE | BPF_K: 9708c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JEQ | BPF_K: 9718c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGT | BPF_K: 9728c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLT | BPF_K: 9738c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JGE | BPF_K: 9748c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JLE | BPF_K: 9758c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JNE | BPF_K: 9768c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JEQ | BPF_K: 9778c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGT | BPF_K: 9788c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLT | BPF_K: 9798c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JGE | BPF_K: 9808c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JLE | BPF_K: 9818c2ecf20Sopenharmony_ci { 9828c2ecf20Sopenharmony_ci bool is_jmp32 = BPF_CLASS(code) == BPF_JMP32; 9838c2ecf20Sopenharmony_ci 9848c2ecf20Sopenharmony_ci /* 9858c2ecf20Sopenharmony_ci * Need sign-extended load, so only positive 9868c2ecf20Sopenharmony_ci * values can be used as imm in cmpldi 9878c2ecf20Sopenharmony_ci */ 9888c2ecf20Sopenharmony_ci if (imm >= 0 && imm < 32768) { 9898c2ecf20Sopenharmony_ci if (is_jmp32) 9908c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLWI(dst_reg, imm)); 9918c2ecf20Sopenharmony_ci else 9928c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLDI(dst_reg, imm)); 9938c2ecf20Sopenharmony_ci } else { 9948c2ecf20Sopenharmony_ci /* sign-extending load */ 9958c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 9968c2ecf20Sopenharmony_ci /* ... but unsigned comparison */ 9978c2ecf20Sopenharmony_ci if (is_jmp32) 9988c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLW(dst_reg, 9998c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 10008c2ecf20Sopenharmony_ci else 10018c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPLD(dst_reg, 10028c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 10038c2ecf20Sopenharmony_ci } 10048c2ecf20Sopenharmony_ci break; 10058c2ecf20Sopenharmony_ci } 10068c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGT | BPF_K: 10078c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLT | BPF_K: 10088c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSGE | BPF_K: 10098c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSLE | BPF_K: 10108c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGT | BPF_K: 10118c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLT | BPF_K: 10128c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSGE | BPF_K: 10138c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSLE | BPF_K: 10148c2ecf20Sopenharmony_ci { 10158c2ecf20Sopenharmony_ci bool is_jmp32 = BPF_CLASS(code) == BPF_JMP32; 10168c2ecf20Sopenharmony_ci 10178c2ecf20Sopenharmony_ci /* 10188c2ecf20Sopenharmony_ci * signed comparison, so any 16-bit value 10198c2ecf20Sopenharmony_ci * can be used in cmpdi 10208c2ecf20Sopenharmony_ci */ 10218c2ecf20Sopenharmony_ci if (imm >= -32768 && imm < 32768) { 10228c2ecf20Sopenharmony_ci if (is_jmp32) 10238c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPWI(dst_reg, imm)); 10248c2ecf20Sopenharmony_ci else 10258c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPDI(dst_reg, imm)); 10268c2ecf20Sopenharmony_ci } else { 10278c2ecf20Sopenharmony_ci PPC_LI32(b2p[TMP_REG_1], imm); 10288c2ecf20Sopenharmony_ci if (is_jmp32) 10298c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPW(dst_reg, 10308c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 10318c2ecf20Sopenharmony_ci else 10328c2ecf20Sopenharmony_ci EMIT(PPC_RAW_CMPD(dst_reg, 10338c2ecf20Sopenharmony_ci b2p[TMP_REG_1])); 10348c2ecf20Sopenharmony_ci } 10358c2ecf20Sopenharmony_ci break; 10368c2ecf20Sopenharmony_ci } 10378c2ecf20Sopenharmony_ci case BPF_JMP | BPF_JSET | BPF_K: 10388c2ecf20Sopenharmony_ci case BPF_JMP32 | BPF_JSET | BPF_K: 10398c2ecf20Sopenharmony_ci /* andi does not sign-extend the immediate */ 10408c2ecf20Sopenharmony_ci if (imm >= 0 && imm < 32768) 10418c2ecf20Sopenharmony_ci /* PPC_ANDI is _only/always_ dot-form */ 10428c2ecf20Sopenharmony_ci EMIT(PPC_RAW_ANDI(b2p[TMP_REG_1], dst_reg, imm)); 10438c2ecf20Sopenharmony_ci else { 10448c2ecf20Sopenharmony_ci int tmp_reg = b2p[TMP_REG_1]; 10458c2ecf20Sopenharmony_ci 10468c2ecf20Sopenharmony_ci PPC_LI32(tmp_reg, imm); 10478c2ecf20Sopenharmony_ci if (BPF_CLASS(code) == BPF_JMP) { 10488c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND_DOT(tmp_reg, dst_reg, 10498c2ecf20Sopenharmony_ci tmp_reg)); 10508c2ecf20Sopenharmony_ci } else { 10518c2ecf20Sopenharmony_ci EMIT(PPC_RAW_AND(tmp_reg, dst_reg, 10528c2ecf20Sopenharmony_ci tmp_reg)); 10538c2ecf20Sopenharmony_ci EMIT(PPC_RAW_RLWINM_DOT(tmp_reg, tmp_reg, 10548c2ecf20Sopenharmony_ci 0, 0, 31)); 10558c2ecf20Sopenharmony_ci } 10568c2ecf20Sopenharmony_ci } 10578c2ecf20Sopenharmony_ci break; 10588c2ecf20Sopenharmony_ci } 10598c2ecf20Sopenharmony_ci PPC_BCC(true_cond, addrs[i + 1 + off]); 10608c2ecf20Sopenharmony_ci break; 10618c2ecf20Sopenharmony_ci 10628c2ecf20Sopenharmony_ci /* 10638c2ecf20Sopenharmony_ci * Tail call 10648c2ecf20Sopenharmony_ci */ 10658c2ecf20Sopenharmony_ci case BPF_JMP | BPF_TAIL_CALL: 10668c2ecf20Sopenharmony_ci ctx->seen |= SEEN_TAILCALL; 10678c2ecf20Sopenharmony_ci ret = bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); 10688c2ecf20Sopenharmony_ci if (ret < 0) 10698c2ecf20Sopenharmony_ci return ret; 10708c2ecf20Sopenharmony_ci break; 10718c2ecf20Sopenharmony_ci 10728c2ecf20Sopenharmony_ci default: 10738c2ecf20Sopenharmony_ci /* 10748c2ecf20Sopenharmony_ci * The filter contains something cruel & unusual. 10758c2ecf20Sopenharmony_ci * We don't handle it, but also there shouldn't be 10768c2ecf20Sopenharmony_ci * anything missing from our list. 10778c2ecf20Sopenharmony_ci */ 10788c2ecf20Sopenharmony_ci pr_err_ratelimited("eBPF filter opcode %04x (@%d) unsupported\n", 10798c2ecf20Sopenharmony_ci code, i); 10808c2ecf20Sopenharmony_ci return -ENOTSUPP; 10818c2ecf20Sopenharmony_ci } 10828c2ecf20Sopenharmony_ci } 10838c2ecf20Sopenharmony_ci 10848c2ecf20Sopenharmony_ci /* Set end-of-body-code address for exit. */ 10858c2ecf20Sopenharmony_ci addrs[i] = ctx->idx * 4; 10868c2ecf20Sopenharmony_ci 10878c2ecf20Sopenharmony_ci return 0; 10888c2ecf20Sopenharmony_ci} 10898c2ecf20Sopenharmony_ci 10908c2ecf20Sopenharmony_ci/* Fix the branch target addresses for subprog calls */ 10918c2ecf20Sopenharmony_cistatic int bpf_jit_fixup_subprog_calls(struct bpf_prog *fp, u32 *image, 10928c2ecf20Sopenharmony_ci struct codegen_context *ctx, u32 *addrs) 10938c2ecf20Sopenharmony_ci{ 10948c2ecf20Sopenharmony_ci const struct bpf_insn *insn = fp->insnsi; 10958c2ecf20Sopenharmony_ci bool func_addr_fixed; 10968c2ecf20Sopenharmony_ci u64 func_addr; 10978c2ecf20Sopenharmony_ci u32 tmp_idx; 10988c2ecf20Sopenharmony_ci int i, ret; 10998c2ecf20Sopenharmony_ci 11008c2ecf20Sopenharmony_ci for (i = 0; i < fp->len; i++) { 11018c2ecf20Sopenharmony_ci /* 11028c2ecf20Sopenharmony_ci * During the extra pass, only the branch target addresses for 11038c2ecf20Sopenharmony_ci * the subprog calls need to be fixed. All other instructions 11048c2ecf20Sopenharmony_ci * can left untouched. 11058c2ecf20Sopenharmony_ci * 11068c2ecf20Sopenharmony_ci * The JITed image length does not change because we already 11078c2ecf20Sopenharmony_ci * ensure that the JITed instruction sequence for these calls 11088c2ecf20Sopenharmony_ci * are of fixed length by padding them with NOPs. 11098c2ecf20Sopenharmony_ci */ 11108c2ecf20Sopenharmony_ci if (insn[i].code == (BPF_JMP | BPF_CALL) && 11118c2ecf20Sopenharmony_ci insn[i].src_reg == BPF_PSEUDO_CALL) { 11128c2ecf20Sopenharmony_ci ret = bpf_jit_get_func_addr(fp, &insn[i], true, 11138c2ecf20Sopenharmony_ci &func_addr, 11148c2ecf20Sopenharmony_ci &func_addr_fixed); 11158c2ecf20Sopenharmony_ci if (ret < 0) 11168c2ecf20Sopenharmony_ci return ret; 11178c2ecf20Sopenharmony_ci 11188c2ecf20Sopenharmony_ci /* 11198c2ecf20Sopenharmony_ci * Save ctx->idx as this would currently point to the 11208c2ecf20Sopenharmony_ci * end of the JITed image and set it to the offset of 11218c2ecf20Sopenharmony_ci * the instruction sequence corresponding to the 11228c2ecf20Sopenharmony_ci * subprog call temporarily. 11238c2ecf20Sopenharmony_ci */ 11248c2ecf20Sopenharmony_ci tmp_idx = ctx->idx; 11258c2ecf20Sopenharmony_ci ctx->idx = addrs[i] / 4; 11268c2ecf20Sopenharmony_ci bpf_jit_emit_func_call_rel(image, ctx, func_addr); 11278c2ecf20Sopenharmony_ci 11288c2ecf20Sopenharmony_ci /* 11298c2ecf20Sopenharmony_ci * Restore ctx->idx here. This is safe as the length 11308c2ecf20Sopenharmony_ci * of the JITed sequence remains unchanged. 11318c2ecf20Sopenharmony_ci */ 11328c2ecf20Sopenharmony_ci ctx->idx = tmp_idx; 11338c2ecf20Sopenharmony_ci } 11348c2ecf20Sopenharmony_ci } 11358c2ecf20Sopenharmony_ci 11368c2ecf20Sopenharmony_ci return 0; 11378c2ecf20Sopenharmony_ci} 11388c2ecf20Sopenharmony_ci 11398c2ecf20Sopenharmony_cistruct powerpc64_jit_data { 11408c2ecf20Sopenharmony_ci struct bpf_binary_header *header; 11418c2ecf20Sopenharmony_ci u32 *addrs; 11428c2ecf20Sopenharmony_ci u8 *image; 11438c2ecf20Sopenharmony_ci u32 proglen; 11448c2ecf20Sopenharmony_ci struct codegen_context ctx; 11458c2ecf20Sopenharmony_ci}; 11468c2ecf20Sopenharmony_ci 11478c2ecf20Sopenharmony_cibool bpf_jit_needs_zext(void) 11488c2ecf20Sopenharmony_ci{ 11498c2ecf20Sopenharmony_ci return true; 11508c2ecf20Sopenharmony_ci} 11518c2ecf20Sopenharmony_ci 11528c2ecf20Sopenharmony_cistruct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) 11538c2ecf20Sopenharmony_ci{ 11548c2ecf20Sopenharmony_ci u32 proglen; 11558c2ecf20Sopenharmony_ci u32 alloclen; 11568c2ecf20Sopenharmony_ci u8 *image = NULL; 11578c2ecf20Sopenharmony_ci u32 *code_base; 11588c2ecf20Sopenharmony_ci u32 *addrs; 11598c2ecf20Sopenharmony_ci struct powerpc64_jit_data *jit_data; 11608c2ecf20Sopenharmony_ci struct codegen_context cgctx; 11618c2ecf20Sopenharmony_ci int pass; 11628c2ecf20Sopenharmony_ci int flen; 11638c2ecf20Sopenharmony_ci struct bpf_binary_header *bpf_hdr; 11648c2ecf20Sopenharmony_ci struct bpf_prog *org_fp = fp; 11658c2ecf20Sopenharmony_ci struct bpf_prog *tmp_fp; 11668c2ecf20Sopenharmony_ci bool bpf_blinded = false; 11678c2ecf20Sopenharmony_ci bool extra_pass = false; 11688c2ecf20Sopenharmony_ci 11698c2ecf20Sopenharmony_ci if (!fp->jit_requested) 11708c2ecf20Sopenharmony_ci return org_fp; 11718c2ecf20Sopenharmony_ci 11728c2ecf20Sopenharmony_ci tmp_fp = bpf_jit_blind_constants(org_fp); 11738c2ecf20Sopenharmony_ci if (IS_ERR(tmp_fp)) 11748c2ecf20Sopenharmony_ci return org_fp; 11758c2ecf20Sopenharmony_ci 11768c2ecf20Sopenharmony_ci if (tmp_fp != org_fp) { 11778c2ecf20Sopenharmony_ci bpf_blinded = true; 11788c2ecf20Sopenharmony_ci fp = tmp_fp; 11798c2ecf20Sopenharmony_ci } 11808c2ecf20Sopenharmony_ci 11818c2ecf20Sopenharmony_ci jit_data = fp->aux->jit_data; 11828c2ecf20Sopenharmony_ci if (!jit_data) { 11838c2ecf20Sopenharmony_ci jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL); 11848c2ecf20Sopenharmony_ci if (!jit_data) { 11858c2ecf20Sopenharmony_ci fp = org_fp; 11868c2ecf20Sopenharmony_ci goto out; 11878c2ecf20Sopenharmony_ci } 11888c2ecf20Sopenharmony_ci fp->aux->jit_data = jit_data; 11898c2ecf20Sopenharmony_ci } 11908c2ecf20Sopenharmony_ci 11918c2ecf20Sopenharmony_ci flen = fp->len; 11928c2ecf20Sopenharmony_ci addrs = jit_data->addrs; 11938c2ecf20Sopenharmony_ci if (addrs) { 11948c2ecf20Sopenharmony_ci cgctx = jit_data->ctx; 11958c2ecf20Sopenharmony_ci image = jit_data->image; 11968c2ecf20Sopenharmony_ci bpf_hdr = jit_data->header; 11978c2ecf20Sopenharmony_ci proglen = jit_data->proglen; 11988c2ecf20Sopenharmony_ci alloclen = proglen + FUNCTION_DESCR_SIZE; 11998c2ecf20Sopenharmony_ci extra_pass = true; 12008c2ecf20Sopenharmony_ci goto skip_init_ctx; 12018c2ecf20Sopenharmony_ci } 12028c2ecf20Sopenharmony_ci 12038c2ecf20Sopenharmony_ci addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL); 12048c2ecf20Sopenharmony_ci if (addrs == NULL) { 12058c2ecf20Sopenharmony_ci fp = org_fp; 12068c2ecf20Sopenharmony_ci goto out_addrs; 12078c2ecf20Sopenharmony_ci } 12088c2ecf20Sopenharmony_ci 12098c2ecf20Sopenharmony_ci memset(&cgctx, 0, sizeof(struct codegen_context)); 12108c2ecf20Sopenharmony_ci 12118c2ecf20Sopenharmony_ci /* Make sure that the stack is quadword aligned. */ 12128c2ecf20Sopenharmony_ci cgctx.stack_size = round_up(fp->aux->stack_depth, 16); 12138c2ecf20Sopenharmony_ci 12148c2ecf20Sopenharmony_ci /* Scouting faux-generate pass 0 */ 12158c2ecf20Sopenharmony_ci if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) { 12168c2ecf20Sopenharmony_ci /* We hit something illegal or unsupported. */ 12178c2ecf20Sopenharmony_ci fp = org_fp; 12188c2ecf20Sopenharmony_ci goto out_addrs; 12198c2ecf20Sopenharmony_ci } 12208c2ecf20Sopenharmony_ci 12218c2ecf20Sopenharmony_ci /* 12228c2ecf20Sopenharmony_ci * If we have seen a tail call, we need a second pass. 12238c2ecf20Sopenharmony_ci * This is because bpf_jit_emit_common_epilogue() is called 12248c2ecf20Sopenharmony_ci * from bpf_jit_emit_tail_call() with a not yet stable ctx->seen. 12258c2ecf20Sopenharmony_ci */ 12268c2ecf20Sopenharmony_ci if (cgctx.seen & SEEN_TAILCALL) { 12278c2ecf20Sopenharmony_ci cgctx.idx = 0; 12288c2ecf20Sopenharmony_ci if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) { 12298c2ecf20Sopenharmony_ci fp = org_fp; 12308c2ecf20Sopenharmony_ci goto out_addrs; 12318c2ecf20Sopenharmony_ci } 12328c2ecf20Sopenharmony_ci } 12338c2ecf20Sopenharmony_ci 12348c2ecf20Sopenharmony_ci /* 12358c2ecf20Sopenharmony_ci * Pretend to build prologue, given the features we've seen. This will 12368c2ecf20Sopenharmony_ci * update ctgtx.idx as it pretends to output instructions, then we can 12378c2ecf20Sopenharmony_ci * calculate total size from idx. 12388c2ecf20Sopenharmony_ci */ 12398c2ecf20Sopenharmony_ci bpf_jit_build_prologue(0, &cgctx); 12408c2ecf20Sopenharmony_ci bpf_jit_build_epilogue(0, &cgctx); 12418c2ecf20Sopenharmony_ci 12428c2ecf20Sopenharmony_ci proglen = cgctx.idx * 4; 12438c2ecf20Sopenharmony_ci alloclen = proglen + FUNCTION_DESCR_SIZE; 12448c2ecf20Sopenharmony_ci 12458c2ecf20Sopenharmony_ci bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, 12468c2ecf20Sopenharmony_ci bpf_jit_fill_ill_insns); 12478c2ecf20Sopenharmony_ci if (!bpf_hdr) { 12488c2ecf20Sopenharmony_ci fp = org_fp; 12498c2ecf20Sopenharmony_ci goto out_addrs; 12508c2ecf20Sopenharmony_ci } 12518c2ecf20Sopenharmony_ci 12528c2ecf20Sopenharmony_ciskip_init_ctx: 12538c2ecf20Sopenharmony_ci code_base = (u32 *)(image + FUNCTION_DESCR_SIZE); 12548c2ecf20Sopenharmony_ci 12558c2ecf20Sopenharmony_ci if (extra_pass) { 12568c2ecf20Sopenharmony_ci /* 12578c2ecf20Sopenharmony_ci * Do not touch the prologue and epilogue as they will remain 12588c2ecf20Sopenharmony_ci * unchanged. Only fix the branch target address for subprog 12598c2ecf20Sopenharmony_ci * calls in the body. 12608c2ecf20Sopenharmony_ci * 12618c2ecf20Sopenharmony_ci * This does not change the offsets and lengths of the subprog 12628c2ecf20Sopenharmony_ci * call instruction sequences and hence, the size of the JITed 12638c2ecf20Sopenharmony_ci * image as well. 12648c2ecf20Sopenharmony_ci */ 12658c2ecf20Sopenharmony_ci bpf_jit_fixup_subprog_calls(fp, code_base, &cgctx, addrs); 12668c2ecf20Sopenharmony_ci 12678c2ecf20Sopenharmony_ci /* There is no need to perform the usual passes. */ 12688c2ecf20Sopenharmony_ci goto skip_codegen_passes; 12698c2ecf20Sopenharmony_ci } 12708c2ecf20Sopenharmony_ci 12718c2ecf20Sopenharmony_ci /* Code generation passes 1-2 */ 12728c2ecf20Sopenharmony_ci for (pass = 1; pass < 3; pass++) { 12738c2ecf20Sopenharmony_ci /* Now build the prologue, body code & epilogue for real. */ 12748c2ecf20Sopenharmony_ci cgctx.idx = 0; 12758c2ecf20Sopenharmony_ci bpf_jit_build_prologue(code_base, &cgctx); 12768c2ecf20Sopenharmony_ci bpf_jit_build_body(fp, code_base, &cgctx, addrs, extra_pass); 12778c2ecf20Sopenharmony_ci bpf_jit_build_epilogue(code_base, &cgctx); 12788c2ecf20Sopenharmony_ci 12798c2ecf20Sopenharmony_ci if (bpf_jit_enable > 1) 12808c2ecf20Sopenharmony_ci pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass, 12818c2ecf20Sopenharmony_ci proglen - (cgctx.idx * 4), cgctx.seen); 12828c2ecf20Sopenharmony_ci } 12838c2ecf20Sopenharmony_ci 12848c2ecf20Sopenharmony_ciskip_codegen_passes: 12858c2ecf20Sopenharmony_ci if (bpf_jit_enable > 1) 12868c2ecf20Sopenharmony_ci /* 12878c2ecf20Sopenharmony_ci * Note that we output the base address of the code_base 12888c2ecf20Sopenharmony_ci * rather than image, since opcodes are in code_base. 12898c2ecf20Sopenharmony_ci */ 12908c2ecf20Sopenharmony_ci bpf_jit_dump(flen, proglen, pass, code_base); 12918c2ecf20Sopenharmony_ci 12928c2ecf20Sopenharmony_ci#ifdef PPC64_ELF_ABI_v1 12938c2ecf20Sopenharmony_ci /* Function descriptor nastiness: Address + TOC */ 12948c2ecf20Sopenharmony_ci ((u64 *)image)[0] = (u64)code_base; 12958c2ecf20Sopenharmony_ci ((u64 *)image)[1] = local_paca->kernel_toc; 12968c2ecf20Sopenharmony_ci#endif 12978c2ecf20Sopenharmony_ci 12988c2ecf20Sopenharmony_ci fp->bpf_func = (void *)image; 12998c2ecf20Sopenharmony_ci fp->jited = 1; 13008c2ecf20Sopenharmony_ci fp->jited_len = alloclen; 13018c2ecf20Sopenharmony_ci 13028c2ecf20Sopenharmony_ci bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE)); 13038c2ecf20Sopenharmony_ci if (!fp->is_func || extra_pass) { 13048c2ecf20Sopenharmony_ci bpf_prog_fill_jited_linfo(fp, addrs); 13058c2ecf20Sopenharmony_ciout_addrs: 13068c2ecf20Sopenharmony_ci kfree(addrs); 13078c2ecf20Sopenharmony_ci kfree(jit_data); 13088c2ecf20Sopenharmony_ci fp->aux->jit_data = NULL; 13098c2ecf20Sopenharmony_ci } else { 13108c2ecf20Sopenharmony_ci jit_data->addrs = addrs; 13118c2ecf20Sopenharmony_ci jit_data->ctx = cgctx; 13128c2ecf20Sopenharmony_ci jit_data->proglen = proglen; 13138c2ecf20Sopenharmony_ci jit_data->image = image; 13148c2ecf20Sopenharmony_ci jit_data->header = bpf_hdr; 13158c2ecf20Sopenharmony_ci } 13168c2ecf20Sopenharmony_ci 13178c2ecf20Sopenharmony_ciout: 13188c2ecf20Sopenharmony_ci if (bpf_blinded) 13198c2ecf20Sopenharmony_ci bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp); 13208c2ecf20Sopenharmony_ci 13218c2ecf20Sopenharmony_ci return fp; 13228c2ecf20Sopenharmony_ci} 13238c2ecf20Sopenharmony_ci 13248c2ecf20Sopenharmony_ci/* Overriding bpf_jit_free() as we don't set images read-only. */ 13258c2ecf20Sopenharmony_civoid bpf_jit_free(struct bpf_prog *fp) 13268c2ecf20Sopenharmony_ci{ 13278c2ecf20Sopenharmony_ci unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; 13288c2ecf20Sopenharmony_ci struct bpf_binary_header *bpf_hdr = (void *)addr; 13298c2ecf20Sopenharmony_ci 13308c2ecf20Sopenharmony_ci if (fp->jited) 13318c2ecf20Sopenharmony_ci bpf_jit_binary_free(bpf_hdr); 13328c2ecf20Sopenharmony_ci 13338c2ecf20Sopenharmony_ci bpf_prog_unlock_free(fp); 13348c2ecf20Sopenharmony_ci} 1335