1156d0e29SNaveen N. Rao /* 2156d0e29SNaveen N. Rao * bpf_jit_comp64.c: eBPF JIT compiler 3156d0e29SNaveen N. Rao * 4156d0e29SNaveen N. Rao * Copyright 2016 Naveen N. Rao <naveen.n.rao@linux.vnet.ibm.com> 5156d0e29SNaveen N. Rao * IBM Corporation 6156d0e29SNaveen N. Rao * 7156d0e29SNaveen N. Rao * Based on the powerpc classic BPF JIT compiler by Matt Evans 8156d0e29SNaveen N. Rao * 9156d0e29SNaveen N. Rao * This program is free software; you can redistribute it and/or 10156d0e29SNaveen N. Rao * modify it under the terms of the GNU General Public License 11156d0e29SNaveen N. Rao * as published by the Free Software Foundation; version 2 12156d0e29SNaveen N. Rao * of the License. 13156d0e29SNaveen N. Rao */ 14156d0e29SNaveen N. Rao #include <linux/moduleloader.h> 15156d0e29SNaveen N. Rao #include <asm/cacheflush.h> 16ec0c464cSChristophe Leroy #include <asm/asm-compat.h> 17156d0e29SNaveen N. Rao #include <linux/netdevice.h> 18156d0e29SNaveen N. Rao #include <linux/filter.h> 19156d0e29SNaveen N. Rao #include <linux/if_vlan.h> 20156d0e29SNaveen N. Rao #include <asm/kprobes.h> 21ce076141SNaveen N. Rao #include <linux/bpf.h> 22156d0e29SNaveen N. Rao 23156d0e29SNaveen N. Rao #include "bpf_jit64.h" 24156d0e29SNaveen N. Rao 25156d0e29SNaveen N. Rao static void bpf_jit_fill_ill_insns(void *area, unsigned int size) 26156d0e29SNaveen N. Rao { 276acdc9a6SNaveen N. Rao memset32(area, BREAKPOINT_INSTRUCTION, size/4); 28156d0e29SNaveen N. Rao } 29156d0e29SNaveen N. Rao 30156d0e29SNaveen N. Rao static inline void bpf_flush_icache(void *start, void *end) 31156d0e29SNaveen N. Rao { 32156d0e29SNaveen N. Rao smp_wmb(); 33156d0e29SNaveen N. Rao flush_icache_range((unsigned long)start, (unsigned long)end); 34156d0e29SNaveen N. Rao } 35156d0e29SNaveen N. Rao 36156d0e29SNaveen N. Rao static inline bool bpf_is_seen_register(struct codegen_context *ctx, int i) 37156d0e29SNaveen N. Rao { 38156d0e29SNaveen N. Rao return (ctx->seen & (1 << (31 - b2p[i]))); 39156d0e29SNaveen N. Rao } 40156d0e29SNaveen N. Rao 41156d0e29SNaveen N. Rao static inline void bpf_set_seen_register(struct codegen_context *ctx, int i) 42156d0e29SNaveen N. Rao { 43156d0e29SNaveen N. Rao ctx->seen |= (1 << (31 - b2p[i])); 44156d0e29SNaveen N. Rao } 45156d0e29SNaveen N. Rao 46156d0e29SNaveen N. Rao static inline bool bpf_has_stack_frame(struct codegen_context *ctx) 47156d0e29SNaveen N. Rao { 48156d0e29SNaveen N. Rao /* 49156d0e29SNaveen N. Rao * We only need a stack frame if: 50156d0e29SNaveen N. Rao * - we call other functions (kernel helpers), or 51156d0e29SNaveen N. Rao * - the bpf program uses its stack area 52156d0e29SNaveen N. Rao * The latter condition is deduced from the usage of BPF_REG_FP 53156d0e29SNaveen N. Rao */ 54156d0e29SNaveen N. Rao return ctx->seen & SEEN_FUNC || bpf_is_seen_register(ctx, BPF_REG_FP); 55156d0e29SNaveen N. Rao } 56156d0e29SNaveen N. Rao 577b847f52SNaveen N. Rao /* 587b847f52SNaveen N. Rao * When not setting up our own stackframe, the redzone usage is: 597b847f52SNaveen N. Rao * 607b847f52SNaveen N. Rao * [ prev sp ] <------------- 617b847f52SNaveen N. Rao * [ ... ] | 627b847f52SNaveen N. Rao * sp (r1) ---> [ stack pointer ] -------------- 63dbf44dafSDaniel Borkmann * [ nv gpr save area ] 6*8 647b847f52SNaveen N. Rao * [ tail_call_cnt ] 8 657b847f52SNaveen N. Rao * [ local_tmp_var ] 8 667b847f52SNaveen N. Rao * [ unused red zone ] 208 bytes protected 677b847f52SNaveen N. Rao */ 687b847f52SNaveen N. Rao static int bpf_jit_stack_local(struct codegen_context *ctx) 697b847f52SNaveen N. Rao { 707b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) 71ac0761ebSSandipan Das return STACK_FRAME_MIN_SIZE + ctx->stack_size; 727b847f52SNaveen N. Rao else 737b847f52SNaveen N. Rao return -(BPF_PPC_STACK_SAVE + 16); 747b847f52SNaveen N. Rao } 757b847f52SNaveen N. Rao 76ce076141SNaveen N. Rao static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx) 77ce076141SNaveen N. Rao { 78ce076141SNaveen N. Rao return bpf_jit_stack_local(ctx) + 8; 79ce076141SNaveen N. Rao } 80ce076141SNaveen N. Rao 817b847f52SNaveen N. Rao static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg) 827b847f52SNaveen N. Rao { 837b847f52SNaveen N. Rao if (reg >= BPF_PPC_NVR_MIN && reg < 32) 84ac0761ebSSandipan Das return (bpf_has_stack_frame(ctx) ? 85ac0761ebSSandipan Das (BPF_PPC_STACKFRAME + ctx->stack_size) : 0) 867b847f52SNaveen N. Rao - (8 * (32 - reg)); 877b847f52SNaveen N. Rao 887b847f52SNaveen N. Rao pr_err("BPF JIT is asking about unknown registers"); 897b847f52SNaveen N. Rao BUG(); 907b847f52SNaveen N. Rao } 917b847f52SNaveen N. Rao 92156d0e29SNaveen N. Rao static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) 93156d0e29SNaveen N. Rao { 94156d0e29SNaveen N. Rao int i; 95156d0e29SNaveen N. Rao 96ce076141SNaveen N. Rao /* 97ce076141SNaveen N. Rao * Initialize tail_call_cnt if we do tail calls. 98ce076141SNaveen N. Rao * Otherwise, put in NOPs so that it can be skipped when we are 99ce076141SNaveen N. Rao * invoked through a tail call. 100ce076141SNaveen N. Rao */ 101ce076141SNaveen N. Rao if (ctx->seen & SEEN_TAILCALL) { 102ce076141SNaveen N. Rao PPC_LI(b2p[TMP_REG_1], 0); 103ce076141SNaveen N. Rao /* this goes in the redzone */ 104ce076141SNaveen N. Rao PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8)); 105ce076141SNaveen N. Rao } else { 106ce076141SNaveen N. Rao PPC_NOP(); 107ce076141SNaveen N. Rao PPC_NOP(); 108ce076141SNaveen N. Rao } 109ce076141SNaveen N. Rao 110ce076141SNaveen N. Rao #define BPF_TAILCALL_PROLOGUE_SIZE 8 111ce076141SNaveen N. Rao 1127b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) { 113156d0e29SNaveen N. Rao /* 114156d0e29SNaveen N. Rao * We need a stack frame, but we don't necessarily need to 115156d0e29SNaveen N. Rao * save/restore LR unless we call other functions 116156d0e29SNaveen N. Rao */ 117156d0e29SNaveen N. Rao if (ctx->seen & SEEN_FUNC) { 118156d0e29SNaveen N. Rao EMIT(PPC_INST_MFLR | __PPC_RT(R0)); 119156d0e29SNaveen N. Rao PPC_BPF_STL(0, 1, PPC_LR_STKOFF); 120156d0e29SNaveen N. Rao } 121156d0e29SNaveen N. Rao 122ac0761ebSSandipan Das PPC_BPF_STLU(1, 1, -(BPF_PPC_STACKFRAME + ctx->stack_size)); 123156d0e29SNaveen N. Rao } 124156d0e29SNaveen N. Rao 125156d0e29SNaveen N. Rao /* 126156d0e29SNaveen N. Rao * Back up non-volatile regs -- BPF registers 6-10 127156d0e29SNaveen N. Rao * If we haven't created our own stack frame, we save these 128156d0e29SNaveen N. Rao * in the protected zone below the previous stack frame 129156d0e29SNaveen N. Rao */ 130156d0e29SNaveen N. Rao for (i = BPF_REG_6; i <= BPF_REG_10; i++) 131156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, i)) 1327b847f52SNaveen N. Rao PPC_BPF_STL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 133156d0e29SNaveen N. Rao 134156d0e29SNaveen N. Rao /* Setup frame pointer to point to the bpf stack area */ 135156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, BPF_REG_FP)) 136156d0e29SNaveen N. Rao PPC_ADDI(b2p[BPF_REG_FP], 1, 137ac0761ebSSandipan Das STACK_FRAME_MIN_SIZE + ctx->stack_size); 138156d0e29SNaveen N. Rao } 139156d0e29SNaveen N. Rao 140ce076141SNaveen N. Rao static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx) 141156d0e29SNaveen N. Rao { 142156d0e29SNaveen N. Rao int i; 143156d0e29SNaveen N. Rao 144156d0e29SNaveen N. Rao /* Restore NVRs */ 145156d0e29SNaveen N. Rao for (i = BPF_REG_6; i <= BPF_REG_10; i++) 146156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, i)) 1477b847f52SNaveen N. Rao PPC_BPF_LL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 148156d0e29SNaveen N. Rao 149156d0e29SNaveen N. Rao /* Tear down our stack frame */ 1507b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) { 151ac0761ebSSandipan Das PPC_ADDI(1, 1, BPF_PPC_STACKFRAME + ctx->stack_size); 152156d0e29SNaveen N. Rao if (ctx->seen & SEEN_FUNC) { 153156d0e29SNaveen N. Rao PPC_BPF_LL(0, 1, PPC_LR_STKOFF); 154156d0e29SNaveen N. Rao PPC_MTLR(0); 155156d0e29SNaveen N. Rao } 156156d0e29SNaveen N. Rao } 157ce076141SNaveen N. Rao } 158ce076141SNaveen N. Rao 159ce076141SNaveen N. Rao static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) 160ce076141SNaveen N. Rao { 161ce076141SNaveen N. Rao bpf_jit_emit_common_epilogue(image, ctx); 162ce076141SNaveen N. Rao 163ce076141SNaveen N. Rao /* Move result to r3 */ 164ce076141SNaveen N. Rao PPC_MR(3, b2p[BPF_REG_0]); 165156d0e29SNaveen N. Rao 166156d0e29SNaveen N. Rao PPC_BLR(); 167156d0e29SNaveen N. Rao } 168156d0e29SNaveen N. Rao 169e2c95a61SDaniel Borkmann static void bpf_jit_emit_func_call_hlp(u32 *image, struct codegen_context *ctx, 170e2c95a61SDaniel Borkmann u64 func) 171e2c95a61SDaniel Borkmann { 172e2c95a61SDaniel Borkmann #ifdef PPC64_ELF_ABI_v1 173e2c95a61SDaniel Borkmann /* func points to the function descriptor */ 174e2c95a61SDaniel Borkmann PPC_LI64(b2p[TMP_REG_2], func); 175e2c95a61SDaniel Borkmann /* Load actual entry point from function descriptor */ 176e2c95a61SDaniel Borkmann PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); 177e2c95a61SDaniel Borkmann /* ... and move it to LR */ 178e2c95a61SDaniel Borkmann PPC_MTLR(b2p[TMP_REG_1]); 179e2c95a61SDaniel Borkmann /* 180e2c95a61SDaniel Borkmann * Load TOC from function descriptor at offset 8. 181e2c95a61SDaniel Borkmann * We can clobber r2 since we get called through a 182e2c95a61SDaniel Borkmann * function pointer (so caller will save/restore r2) 183e2c95a61SDaniel Borkmann * and since we don't use a TOC ourself. 184e2c95a61SDaniel Borkmann */ 185e2c95a61SDaniel Borkmann PPC_BPF_LL(2, b2p[TMP_REG_2], 8); 186e2c95a61SDaniel Borkmann #else 187e2c95a61SDaniel Borkmann /* We can clobber r12 */ 188e2c95a61SDaniel Borkmann PPC_FUNC_ADDR(12, func); 189e2c95a61SDaniel Borkmann PPC_MTLR(12); 190e2c95a61SDaniel Borkmann #endif 191e2c95a61SDaniel Borkmann PPC_BLRL(); 192e2c95a61SDaniel Borkmann } 193e2c95a61SDaniel Borkmann 194e2c95a61SDaniel Borkmann static void bpf_jit_emit_func_call_rel(u32 *image, struct codegen_context *ctx, 195e2c95a61SDaniel Borkmann u64 func) 196ce076141SNaveen N. Rao { 1974ea69b2fSSandipan Das unsigned int i, ctx_idx = ctx->idx; 1984ea69b2fSSandipan Das 1994ea69b2fSSandipan Das /* Load function address into r12 */ 2004ea69b2fSSandipan Das PPC_LI64(12, func); 2014ea69b2fSSandipan Das 2024ea69b2fSSandipan Das /* For bpf-to-bpf function calls, the callee's address is unknown 2034ea69b2fSSandipan Das * until the last extra pass. As seen above, we use PPC_LI64() to 2044ea69b2fSSandipan Das * load the callee's address, but this may optimize the number of 2054ea69b2fSSandipan Das * instructions required based on the nature of the address. 2064ea69b2fSSandipan Das * 2074ea69b2fSSandipan Das * Since we don't want the number of instructions emitted to change, 2084ea69b2fSSandipan Das * we pad the optimized PPC_LI64() call with NOPs to guarantee that 2094ea69b2fSSandipan Das * we always have a five-instruction sequence, which is the maximum 2104ea69b2fSSandipan Das * that PPC_LI64() can emit. 2114ea69b2fSSandipan Das */ 2124ea69b2fSSandipan Das for (i = ctx->idx - ctx_idx; i < 5; i++) 2134ea69b2fSSandipan Das PPC_NOP(); 2144ea69b2fSSandipan Das 215ce076141SNaveen N. Rao #ifdef PPC64_ELF_ABI_v1 216ce076141SNaveen N. Rao /* 217ce076141SNaveen N. Rao * Load TOC from function descriptor at offset 8. 218ce076141SNaveen N. Rao * We can clobber r2 since we get called through a 219ce076141SNaveen N. Rao * function pointer (so caller will save/restore r2) 220ce076141SNaveen N. Rao * and since we don't use a TOC ourself. 221ce076141SNaveen N. Rao */ 2224ea69b2fSSandipan Das PPC_BPF_LL(2, 12, 8); 2234ea69b2fSSandipan Das /* Load actual entry point from function descriptor */ 2244ea69b2fSSandipan Das PPC_BPF_LL(12, 12, 0); 225ce076141SNaveen N. Rao #endif 2264ea69b2fSSandipan Das 2274ea69b2fSSandipan Das PPC_MTLR(12); 228ce076141SNaveen N. Rao PPC_BLRL(); 229ce076141SNaveen N. Rao } 230ce076141SNaveen N. Rao 231ce076141SNaveen N. Rao static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) 232ce076141SNaveen N. Rao { 233ce076141SNaveen N. Rao /* 234ce076141SNaveen N. Rao * By now, the eBPF program has already setup parameters in r3, r4 and r5 235ce076141SNaveen N. Rao * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program 236ce076141SNaveen N. Rao * r4/BPF_REG_2 - pointer to bpf_array 237ce076141SNaveen N. Rao * r5/BPF_REG_3 - index in bpf_array 238ce076141SNaveen N. Rao */ 239ce076141SNaveen N. Rao int b2p_bpf_array = b2p[BPF_REG_2]; 240ce076141SNaveen N. Rao int b2p_index = b2p[BPF_REG_3]; 241ce076141SNaveen N. Rao 242ce076141SNaveen N. Rao /* 243ce076141SNaveen N. Rao * if (index >= array->map.max_entries) 244ce076141SNaveen N. Rao * goto out; 245ce076141SNaveen N. Rao */ 246ce076141SNaveen N. Rao PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); 247d269176eSDaniel Borkmann PPC_RLWINM(b2p_index, b2p_index, 0, 0, 31); 248ce076141SNaveen N. Rao PPC_CMPLW(b2p_index, b2p[TMP_REG_1]); 249ce076141SNaveen N. Rao PPC_BCC(COND_GE, out); 250ce076141SNaveen N. Rao 251ce076141SNaveen N. Rao /* 252ce076141SNaveen N. Rao * if (tail_call_cnt > MAX_TAIL_CALL_CNT) 253ce076141SNaveen N. Rao * goto out; 254ce076141SNaveen N. Rao */ 255ce076141SNaveen N. Rao PPC_LD(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); 256ce076141SNaveen N. Rao PPC_CMPLWI(b2p[TMP_REG_1], MAX_TAIL_CALL_CNT); 257ce076141SNaveen N. Rao PPC_BCC(COND_GT, out); 258ce076141SNaveen N. Rao 259ce076141SNaveen N. Rao /* 260ce076141SNaveen N. Rao * tail_call_cnt++; 261ce076141SNaveen N. Rao */ 262ce076141SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 1); 263ce076141SNaveen N. Rao PPC_BPF_STL(b2p[TMP_REG_1], 1, bpf_jit_stack_tailcallcnt(ctx)); 264ce076141SNaveen N. Rao 265ce076141SNaveen N. Rao /* prog = array->ptrs[index]; */ 266ce076141SNaveen N. Rao PPC_MULI(b2p[TMP_REG_1], b2p_index, 8); 267ce076141SNaveen N. Rao PPC_ADD(b2p[TMP_REG_1], b2p[TMP_REG_1], b2p_bpf_array); 268ce076141SNaveen N. Rao PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_array, ptrs)); 269ce076141SNaveen N. Rao 270ce076141SNaveen N. Rao /* 271ce076141SNaveen N. Rao * if (prog == NULL) 272ce076141SNaveen N. Rao * goto out; 273ce076141SNaveen N. Rao */ 274ce076141SNaveen N. Rao PPC_CMPLDI(b2p[TMP_REG_1], 0); 275ce076141SNaveen N. Rao PPC_BCC(COND_EQ, out); 276ce076141SNaveen N. Rao 277ce076141SNaveen N. Rao /* goto *(prog->bpf_func + prologue_size); */ 278ce076141SNaveen N. Rao PPC_LD(b2p[TMP_REG_1], b2p[TMP_REG_1], offsetof(struct bpf_prog, bpf_func)); 279ce076141SNaveen N. Rao #ifdef PPC64_ELF_ABI_v1 280ce076141SNaveen N. Rao /* skip past the function descriptor */ 281ce076141SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], 282ce076141SNaveen N. Rao FUNCTION_DESCR_SIZE + BPF_TAILCALL_PROLOGUE_SIZE); 283ce076141SNaveen N. Rao #else 284ce076141SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], b2p[TMP_REG_1], BPF_TAILCALL_PROLOGUE_SIZE); 285ce076141SNaveen N. Rao #endif 286ce076141SNaveen N. Rao PPC_MTCTR(b2p[TMP_REG_1]); 287ce076141SNaveen N. Rao 288ce076141SNaveen N. Rao /* tear down stack, restore NVRs, ... */ 289ce076141SNaveen N. Rao bpf_jit_emit_common_epilogue(image, ctx); 290ce076141SNaveen N. Rao 291ce076141SNaveen N. Rao PPC_BCTR(); 292ce076141SNaveen N. Rao /* out: */ 293ce076141SNaveen N. Rao } 294ce076141SNaveen N. Rao 295156d0e29SNaveen N. Rao /* Assemble the body code between the prologue & epilogue */ 296156d0e29SNaveen N. Rao static int bpf_jit_build_body(struct bpf_prog *fp, u32 *image, 297156d0e29SNaveen N. Rao struct codegen_context *ctx, 2988484ce83SSandipan Das u32 *addrs, bool extra_pass) 299156d0e29SNaveen N. Rao { 300156d0e29SNaveen N. Rao const struct bpf_insn *insn = fp->insnsi; 301156d0e29SNaveen N. Rao int flen = fp->len; 302e2c95a61SDaniel Borkmann int i, ret; 303156d0e29SNaveen N. Rao 304156d0e29SNaveen N. Rao /* Start of epilogue code - will only be valid 2nd pass onwards */ 305156d0e29SNaveen N. Rao u32 exit_addr = addrs[flen]; 306156d0e29SNaveen N. Rao 307156d0e29SNaveen N. Rao for (i = 0; i < flen; i++) { 308156d0e29SNaveen N. Rao u32 code = insn[i].code; 309156d0e29SNaveen N. Rao u32 dst_reg = b2p[insn[i].dst_reg]; 310156d0e29SNaveen N. Rao u32 src_reg = b2p[insn[i].src_reg]; 311156d0e29SNaveen N. Rao s16 off = insn[i].off; 312156d0e29SNaveen N. Rao s32 imm = insn[i].imm; 313e2c95a61SDaniel Borkmann bool func_addr_fixed; 314e2c95a61SDaniel Borkmann u64 func_addr; 315156d0e29SNaveen N. Rao u64 imm64; 316156d0e29SNaveen N. Rao u32 true_cond; 317b9c1e60eSDaniel Borkmann u32 tmp_idx; 318156d0e29SNaveen N. Rao 319156d0e29SNaveen N. Rao /* 320156d0e29SNaveen N. Rao * addrs[] maps a BPF bytecode address into a real offset from 321156d0e29SNaveen N. Rao * the start of the body code. 322156d0e29SNaveen N. Rao */ 323156d0e29SNaveen N. Rao addrs[i] = ctx->idx * 4; 324156d0e29SNaveen N. Rao 325156d0e29SNaveen N. Rao /* 326156d0e29SNaveen N. Rao * As an optimization, we note down which non-volatile registers 327156d0e29SNaveen N. Rao * are used so that we can only save/restore those in our 328156d0e29SNaveen N. Rao * prologue and epilogue. We do this here regardless of whether 329156d0e29SNaveen N. Rao * the actual BPF instruction uses src/dst registers or not 330156d0e29SNaveen N. Rao * (for instance, BPF_CALL does not use them). The expectation 331156d0e29SNaveen N. Rao * is that those instructions will have src_reg/dst_reg set to 332156d0e29SNaveen N. Rao * 0. Even otherwise, we just lose some prologue/epilogue 333156d0e29SNaveen N. Rao * optimization but everything else should work without 334156d0e29SNaveen N. Rao * any issues. 335156d0e29SNaveen N. Rao */ 3367b847f52SNaveen N. Rao if (dst_reg >= BPF_PPC_NVR_MIN && dst_reg < 32) 337156d0e29SNaveen N. Rao bpf_set_seen_register(ctx, insn[i].dst_reg); 3387b847f52SNaveen N. Rao if (src_reg >= BPF_PPC_NVR_MIN && src_reg < 32) 339156d0e29SNaveen N. Rao bpf_set_seen_register(ctx, insn[i].src_reg); 340156d0e29SNaveen N. Rao 341156d0e29SNaveen N. Rao switch (code) { 342156d0e29SNaveen N. Rao /* 343156d0e29SNaveen N. Rao * Arithmetic operations: ADD/SUB/MUL/DIV/MOD/NEG 344156d0e29SNaveen N. Rao */ 345156d0e29SNaveen N. Rao case BPF_ALU | BPF_ADD | BPF_X: /* (u32) dst += (u32) src */ 346156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ADD | BPF_X: /* dst += src */ 347156d0e29SNaveen N. Rao PPC_ADD(dst_reg, dst_reg, src_reg); 348156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 349156d0e29SNaveen N. Rao case BPF_ALU | BPF_SUB | BPF_X: /* (u32) dst -= (u32) src */ 350156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_SUB | BPF_X: /* dst -= src */ 351156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, src_reg); 352156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 353156d0e29SNaveen N. Rao case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */ 354156d0e29SNaveen N. Rao case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */ 355156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */ 356156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */ 357156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_SUB) 358156d0e29SNaveen N. Rao imm = -imm; 359156d0e29SNaveen N. Rao if (imm) { 360156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 361156d0e29SNaveen N. Rao PPC_ADDI(dst_reg, dst_reg, IMM_L(imm)); 362156d0e29SNaveen N. Rao else { 363156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 364156d0e29SNaveen N. Rao PPC_ADD(dst_reg, dst_reg, b2p[TMP_REG_1]); 365156d0e29SNaveen N. Rao } 366156d0e29SNaveen N. Rao } 367156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 368156d0e29SNaveen N. Rao case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */ 369156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MUL | BPF_X: /* dst *= src */ 370156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ALU) 371156d0e29SNaveen N. Rao PPC_MULW(dst_reg, dst_reg, src_reg); 372156d0e29SNaveen N. Rao else 373156d0e29SNaveen N. Rao PPC_MULD(dst_reg, dst_reg, src_reg); 374156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 375156d0e29SNaveen N. Rao case BPF_ALU | BPF_MUL | BPF_K: /* (u32) dst *= (u32) imm */ 376156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MUL | BPF_K: /* dst *= imm */ 377156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 378156d0e29SNaveen N. Rao PPC_MULI(dst_reg, dst_reg, IMM_L(imm)); 379156d0e29SNaveen N. Rao else { 380156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 381156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ALU) 382156d0e29SNaveen N. Rao PPC_MULW(dst_reg, dst_reg, 383156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 384156d0e29SNaveen N. Rao else 385156d0e29SNaveen N. Rao PPC_MULD(dst_reg, dst_reg, 386156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 387156d0e29SNaveen N. Rao } 388156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 389156d0e29SNaveen N. Rao case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */ 390156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */ 391156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 392156d0e29SNaveen N. Rao PPC_DIVWU(b2p[TMP_REG_1], dst_reg, src_reg); 393156d0e29SNaveen N. Rao PPC_MULW(b2p[TMP_REG_1], src_reg, 394156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 395156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]); 396156d0e29SNaveen N. Rao } else 397156d0e29SNaveen N. Rao PPC_DIVWU(dst_reg, dst_reg, src_reg); 398156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 399156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */ 400156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOD | BPF_X: /* dst %= src */ 401156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 402156d0e29SNaveen N. Rao PPC_DIVD(b2p[TMP_REG_1], dst_reg, src_reg); 403156d0e29SNaveen N. Rao PPC_MULD(b2p[TMP_REG_1], src_reg, 404156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 405156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]); 406156d0e29SNaveen N. Rao } else 407156d0e29SNaveen N. Rao PPC_DIVD(dst_reg, dst_reg, src_reg); 408156d0e29SNaveen N. Rao break; 409156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */ 410156d0e29SNaveen N. Rao case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */ 411156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOD | BPF_K: /* dst %= imm */ 412156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */ 413156d0e29SNaveen N. Rao if (imm == 0) 414156d0e29SNaveen N. Rao return -EINVAL; 415156d0e29SNaveen N. Rao else if (imm == 1) 416156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 417156d0e29SNaveen N. Rao 418156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 419156d0e29SNaveen N. Rao switch (BPF_CLASS(code)) { 420156d0e29SNaveen N. Rao case BPF_ALU: 421156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 422156d0e29SNaveen N. Rao PPC_DIVWU(b2p[TMP_REG_2], dst_reg, 423156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 424156d0e29SNaveen N. Rao PPC_MULW(b2p[TMP_REG_1], 425156d0e29SNaveen N. Rao b2p[TMP_REG_1], 426156d0e29SNaveen N. Rao b2p[TMP_REG_2]); 427156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, 428156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 429156d0e29SNaveen N. Rao } else 430156d0e29SNaveen N. Rao PPC_DIVWU(dst_reg, dst_reg, 431156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 432156d0e29SNaveen N. Rao break; 433156d0e29SNaveen N. Rao case BPF_ALU64: 434156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 435156d0e29SNaveen N. Rao PPC_DIVD(b2p[TMP_REG_2], dst_reg, 436156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 437156d0e29SNaveen N. Rao PPC_MULD(b2p[TMP_REG_1], 438156d0e29SNaveen N. Rao b2p[TMP_REG_1], 439156d0e29SNaveen N. Rao b2p[TMP_REG_2]); 440156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, 441156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 442156d0e29SNaveen N. Rao } else 443156d0e29SNaveen N. Rao PPC_DIVD(dst_reg, dst_reg, 444156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 445156d0e29SNaveen N. Rao break; 446156d0e29SNaveen N. Rao } 447156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 448156d0e29SNaveen N. Rao case BPF_ALU | BPF_NEG: /* (u32) dst = -dst */ 449156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_NEG: /* dst = -dst */ 450156d0e29SNaveen N. Rao PPC_NEG(dst_reg, dst_reg); 451156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 452156d0e29SNaveen N. Rao 453156d0e29SNaveen N. Rao /* 454156d0e29SNaveen N. Rao * Logical operations: AND/OR/XOR/[A]LSH/[A]RSH 455156d0e29SNaveen N. Rao */ 456156d0e29SNaveen N. Rao case BPF_ALU | BPF_AND | BPF_X: /* (u32) dst = dst & src */ 457156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */ 458156d0e29SNaveen N. Rao PPC_AND(dst_reg, dst_reg, src_reg); 459156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 460156d0e29SNaveen N. Rao case BPF_ALU | BPF_AND | BPF_K: /* (u32) dst = dst & imm */ 461156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */ 462156d0e29SNaveen N. Rao if (!IMM_H(imm)) 463156d0e29SNaveen N. Rao PPC_ANDI(dst_reg, dst_reg, IMM_L(imm)); 464156d0e29SNaveen N. Rao else { 465156d0e29SNaveen N. Rao /* Sign-extended */ 466156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 467156d0e29SNaveen N. Rao PPC_AND(dst_reg, dst_reg, b2p[TMP_REG_1]); 468156d0e29SNaveen N. Rao } 469156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 470156d0e29SNaveen N. Rao case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */ 471156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */ 472156d0e29SNaveen N. Rao PPC_OR(dst_reg, dst_reg, src_reg); 473156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 474156d0e29SNaveen N. Rao case BPF_ALU | BPF_OR | BPF_K:/* dst = (u32) dst | (u32) imm */ 475156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_OR | BPF_K:/* dst = dst | imm */ 476156d0e29SNaveen N. Rao if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 477156d0e29SNaveen N. Rao /* Sign-extended */ 478156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 479156d0e29SNaveen N. Rao PPC_OR(dst_reg, dst_reg, b2p[TMP_REG_1]); 480156d0e29SNaveen N. Rao } else { 481156d0e29SNaveen N. Rao if (IMM_L(imm)) 482156d0e29SNaveen N. Rao PPC_ORI(dst_reg, dst_reg, IMM_L(imm)); 483156d0e29SNaveen N. Rao if (IMM_H(imm)) 484156d0e29SNaveen N. Rao PPC_ORIS(dst_reg, dst_reg, IMM_H(imm)); 485156d0e29SNaveen N. Rao } 486156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 487156d0e29SNaveen N. Rao case BPF_ALU | BPF_XOR | BPF_X: /* (u32) dst ^= src */ 488156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_XOR | BPF_X: /* dst ^= src */ 489156d0e29SNaveen N. Rao PPC_XOR(dst_reg, dst_reg, src_reg); 490156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 491156d0e29SNaveen N. Rao case BPF_ALU | BPF_XOR | BPF_K: /* (u32) dst ^= (u32) imm */ 492156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_XOR | BPF_K: /* dst ^= imm */ 493156d0e29SNaveen N. Rao if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 494156d0e29SNaveen N. Rao /* Sign-extended */ 495156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 496156d0e29SNaveen N. Rao PPC_XOR(dst_reg, dst_reg, b2p[TMP_REG_1]); 497156d0e29SNaveen N. Rao } else { 498156d0e29SNaveen N. Rao if (IMM_L(imm)) 499156d0e29SNaveen N. Rao PPC_XORI(dst_reg, dst_reg, IMM_L(imm)); 500156d0e29SNaveen N. Rao if (IMM_H(imm)) 501156d0e29SNaveen N. Rao PPC_XORIS(dst_reg, dst_reg, IMM_H(imm)); 502156d0e29SNaveen N. Rao } 503156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 504156d0e29SNaveen N. Rao case BPF_ALU | BPF_LSH | BPF_X: /* (u32) dst <<= (u32) src */ 505156d0e29SNaveen N. Rao /* slw clears top 32 bits */ 506156d0e29SNaveen N. Rao PPC_SLW(dst_reg, dst_reg, src_reg); 507156d0e29SNaveen N. Rao break; 508156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_LSH | BPF_X: /* dst <<= src; */ 509156d0e29SNaveen N. Rao PPC_SLD(dst_reg, dst_reg, src_reg); 510156d0e29SNaveen N. Rao break; 511156d0e29SNaveen N. Rao case BPF_ALU | BPF_LSH | BPF_K: /* (u32) dst <<== (u32) imm */ 512156d0e29SNaveen N. Rao /* with imm 0, we still need to clear top 32 bits */ 513156d0e29SNaveen N. Rao PPC_SLWI(dst_reg, dst_reg, imm); 514156d0e29SNaveen N. Rao break; 515156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_LSH | BPF_K: /* dst <<== imm */ 516156d0e29SNaveen N. Rao if (imm != 0) 517156d0e29SNaveen N. Rao PPC_SLDI(dst_reg, dst_reg, imm); 518156d0e29SNaveen N. Rao break; 519156d0e29SNaveen N. Rao case BPF_ALU | BPF_RSH | BPF_X: /* (u32) dst >>= (u32) src */ 520156d0e29SNaveen N. Rao PPC_SRW(dst_reg, dst_reg, src_reg); 521156d0e29SNaveen N. Rao break; 522156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_RSH | BPF_X: /* dst >>= src */ 523156d0e29SNaveen N. Rao PPC_SRD(dst_reg, dst_reg, src_reg); 524156d0e29SNaveen N. Rao break; 525156d0e29SNaveen N. Rao case BPF_ALU | BPF_RSH | BPF_K: /* (u32) dst >>= (u32) imm */ 526156d0e29SNaveen N. Rao PPC_SRWI(dst_reg, dst_reg, imm); 527156d0e29SNaveen N. Rao break; 528156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_RSH | BPF_K: /* dst >>= imm */ 529156d0e29SNaveen N. Rao if (imm != 0) 530156d0e29SNaveen N. Rao PPC_SRDI(dst_reg, dst_reg, imm); 531156d0e29SNaveen N. Rao break; 532*44cf43c0SJiong Wang case BPF_ALU | BPF_ARSH | BPF_X: /* (s32) dst >>= src */ 533*44cf43c0SJiong Wang PPC_SRAW(dst_reg, dst_reg, src_reg); 534*44cf43c0SJiong Wang goto bpf_alu32_trunc; 535156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */ 536156d0e29SNaveen N. Rao PPC_SRAD(dst_reg, dst_reg, src_reg); 537156d0e29SNaveen N. Rao break; 538*44cf43c0SJiong Wang case BPF_ALU | BPF_ARSH | BPF_K: /* (s32) dst >>= imm */ 539*44cf43c0SJiong Wang PPC_SRAWI(dst_reg, dst_reg, imm); 540*44cf43c0SJiong Wang goto bpf_alu32_trunc; 541156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ARSH | BPF_K: /* (s64) dst >>= imm */ 542156d0e29SNaveen N. Rao if (imm != 0) 543156d0e29SNaveen N. Rao PPC_SRADI(dst_reg, dst_reg, imm); 544156d0e29SNaveen N. Rao break; 545156d0e29SNaveen N. Rao 546156d0e29SNaveen N. Rao /* 547156d0e29SNaveen N. Rao * MOV 548156d0e29SNaveen N. Rao */ 549156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOV | BPF_X: /* (u32) dst = src */ 550156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOV | BPF_X: /* dst = src */ 551156d0e29SNaveen N. Rao PPC_MR(dst_reg, src_reg); 552156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 553156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOV | BPF_K: /* (u32) dst = imm */ 554156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOV | BPF_K: /* dst = (s64) imm */ 555156d0e29SNaveen N. Rao PPC_LI32(dst_reg, imm); 556156d0e29SNaveen N. Rao if (imm < 0) 557156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 558156d0e29SNaveen N. Rao break; 559156d0e29SNaveen N. Rao 560156d0e29SNaveen N. Rao bpf_alu32_trunc: 561156d0e29SNaveen N. Rao /* Truncate to 32-bits */ 562156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ALU) 563156d0e29SNaveen N. Rao PPC_RLWINM(dst_reg, dst_reg, 0, 0, 31); 564156d0e29SNaveen N. Rao break; 565156d0e29SNaveen N. Rao 566156d0e29SNaveen N. Rao /* 567156d0e29SNaveen N. Rao * BPF_FROM_BE/LE 568156d0e29SNaveen N. Rao */ 569156d0e29SNaveen N. Rao case BPF_ALU | BPF_END | BPF_FROM_LE: 570156d0e29SNaveen N. Rao case BPF_ALU | BPF_END | BPF_FROM_BE: 571156d0e29SNaveen N. Rao #ifdef __BIG_ENDIAN__ 572156d0e29SNaveen N. Rao if (BPF_SRC(code) == BPF_FROM_BE) 573156d0e29SNaveen N. Rao goto emit_clear; 574156d0e29SNaveen N. Rao #else /* !__BIG_ENDIAN__ */ 575156d0e29SNaveen N. Rao if (BPF_SRC(code) == BPF_FROM_LE) 576156d0e29SNaveen N. Rao goto emit_clear; 577156d0e29SNaveen N. Rao #endif 578156d0e29SNaveen N. Rao switch (imm) { 579156d0e29SNaveen N. Rao case 16: 580156d0e29SNaveen N. Rao /* Rotate 8 bits left & mask with 0x0000ff00 */ 581156d0e29SNaveen N. Rao PPC_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 16, 23); 582156d0e29SNaveen N. Rao /* Rotate 8 bits right & insert LSB to reg */ 583156d0e29SNaveen N. Rao PPC_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 24, 31); 584156d0e29SNaveen N. Rao /* Move result back to dst_reg */ 585156d0e29SNaveen N. Rao PPC_MR(dst_reg, b2p[TMP_REG_1]); 586156d0e29SNaveen N. Rao break; 587156d0e29SNaveen N. Rao case 32: 588156d0e29SNaveen N. Rao /* 589156d0e29SNaveen N. Rao * Rotate word left by 8 bits: 590156d0e29SNaveen N. Rao * 2 bytes are already in their final position 591156d0e29SNaveen N. Rao * -- byte 2 and 4 (of bytes 1, 2, 3 and 4) 592156d0e29SNaveen N. Rao */ 593156d0e29SNaveen N. Rao PPC_RLWINM(b2p[TMP_REG_1], dst_reg, 8, 0, 31); 594156d0e29SNaveen N. Rao /* Rotate 24 bits and insert byte 1 */ 595156d0e29SNaveen N. Rao PPC_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 0, 7); 596156d0e29SNaveen N. Rao /* Rotate 24 bits and insert byte 3 */ 597156d0e29SNaveen N. Rao PPC_RLWIMI(b2p[TMP_REG_1], dst_reg, 24, 16, 23); 598156d0e29SNaveen N. Rao PPC_MR(dst_reg, b2p[TMP_REG_1]); 599156d0e29SNaveen N. Rao break; 600156d0e29SNaveen N. Rao case 64: 601156d0e29SNaveen N. Rao /* 602156d0e29SNaveen N. Rao * Way easier and faster(?) to store the value 603156d0e29SNaveen N. Rao * into stack and then use ldbrx 604156d0e29SNaveen N. Rao * 605156d0e29SNaveen N. Rao * ctx->seen will be reliable in pass2, but 606156d0e29SNaveen N. Rao * the instructions generated will remain the 607156d0e29SNaveen N. Rao * same across all passes 608156d0e29SNaveen N. Rao */ 6097b847f52SNaveen N. Rao PPC_STD(dst_reg, 1, bpf_jit_stack_local(ctx)); 6107b847f52SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], 1, bpf_jit_stack_local(ctx)); 611156d0e29SNaveen N. Rao PPC_LDBRX(dst_reg, 0, b2p[TMP_REG_1]); 612156d0e29SNaveen N. Rao break; 613156d0e29SNaveen N. Rao } 614156d0e29SNaveen N. Rao break; 615156d0e29SNaveen N. Rao 616156d0e29SNaveen N. Rao emit_clear: 617156d0e29SNaveen N. Rao switch (imm) { 618156d0e29SNaveen N. Rao case 16: 619156d0e29SNaveen N. Rao /* zero-extend 16 bits into 64 bits */ 620156d0e29SNaveen N. Rao PPC_RLDICL(dst_reg, dst_reg, 0, 48); 621156d0e29SNaveen N. Rao break; 622156d0e29SNaveen N. Rao case 32: 623156d0e29SNaveen N. Rao /* zero-extend 32 bits into 64 bits */ 624156d0e29SNaveen N. Rao PPC_RLDICL(dst_reg, dst_reg, 0, 32); 625156d0e29SNaveen N. Rao break; 626156d0e29SNaveen N. Rao case 64: 627156d0e29SNaveen N. Rao /* nop */ 628156d0e29SNaveen N. Rao break; 629156d0e29SNaveen N. Rao } 630156d0e29SNaveen N. Rao break; 631156d0e29SNaveen N. Rao 632156d0e29SNaveen N. Rao /* 633156d0e29SNaveen N. Rao * BPF_ST(X) 634156d0e29SNaveen N. Rao */ 635156d0e29SNaveen N. Rao case BPF_STX | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = src */ 636156d0e29SNaveen N. Rao case BPF_ST | BPF_MEM | BPF_B: /* *(u8 *)(dst + off) = imm */ 637156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ST) { 638156d0e29SNaveen N. Rao PPC_LI(b2p[TMP_REG_1], imm); 639156d0e29SNaveen N. Rao src_reg = b2p[TMP_REG_1]; 640156d0e29SNaveen N. Rao } 641156d0e29SNaveen N. Rao PPC_STB(src_reg, dst_reg, off); 642156d0e29SNaveen N. Rao break; 643156d0e29SNaveen N. Rao case BPF_STX | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = src */ 644156d0e29SNaveen N. Rao case BPF_ST | BPF_MEM | BPF_H: /* (u16 *)(dst + off) = imm */ 645156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ST) { 646156d0e29SNaveen N. Rao PPC_LI(b2p[TMP_REG_1], imm); 647156d0e29SNaveen N. Rao src_reg = b2p[TMP_REG_1]; 648156d0e29SNaveen N. Rao } 649156d0e29SNaveen N. Rao PPC_STH(src_reg, dst_reg, off); 650156d0e29SNaveen N. Rao break; 651156d0e29SNaveen N. Rao case BPF_STX | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = src */ 652156d0e29SNaveen N. Rao case BPF_ST | BPF_MEM | BPF_W: /* *(u32 *)(dst + off) = imm */ 653156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ST) { 654156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 655156d0e29SNaveen N. Rao src_reg = b2p[TMP_REG_1]; 656156d0e29SNaveen N. Rao } 657156d0e29SNaveen N. Rao PPC_STW(src_reg, dst_reg, off); 658156d0e29SNaveen N. Rao break; 659156d0e29SNaveen N. Rao case BPF_STX | BPF_MEM | BPF_DW: /* (u64 *)(dst + off) = src */ 660156d0e29SNaveen N. Rao case BPF_ST | BPF_MEM | BPF_DW: /* *(u64 *)(dst + off) = imm */ 661156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ST) { 662156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 663156d0e29SNaveen N. Rao src_reg = b2p[TMP_REG_1]; 664156d0e29SNaveen N. Rao } 665156d0e29SNaveen N. Rao PPC_STD(src_reg, dst_reg, off); 666156d0e29SNaveen N. Rao break; 667156d0e29SNaveen N. Rao 668156d0e29SNaveen N. Rao /* 669156d0e29SNaveen N. Rao * BPF_STX XADD (atomic_add) 670156d0e29SNaveen N. Rao */ 671156d0e29SNaveen N. Rao /* *(u32 *)(dst + off) += src */ 672156d0e29SNaveen N. Rao case BPF_STX | BPF_XADD | BPF_W: 673156d0e29SNaveen N. Rao /* Get EA into TMP_REG_1 */ 674156d0e29SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], dst_reg, off); 675b9c1e60eSDaniel Borkmann tmp_idx = ctx->idx * 4; 676156d0e29SNaveen N. Rao /* load value from memory into TMP_REG_2 */ 677156d0e29SNaveen N. Rao PPC_BPF_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); 678156d0e29SNaveen N. Rao /* add value from src_reg into this */ 679156d0e29SNaveen N. Rao PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); 680156d0e29SNaveen N. Rao /* store result back */ 681156d0e29SNaveen N. Rao PPC_BPF_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 682156d0e29SNaveen N. Rao /* we're done if this succeeded */ 683b9c1e60eSDaniel Borkmann PPC_BCC_SHORT(COND_NE, tmp_idx); 684156d0e29SNaveen N. Rao break; 685156d0e29SNaveen N. Rao /* *(u64 *)(dst + off) += src */ 686156d0e29SNaveen N. Rao case BPF_STX | BPF_XADD | BPF_DW: 687156d0e29SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], dst_reg, off); 688b9c1e60eSDaniel Borkmann tmp_idx = ctx->idx * 4; 689156d0e29SNaveen N. Rao PPC_BPF_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); 690156d0e29SNaveen N. Rao PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); 691156d0e29SNaveen N. Rao PPC_BPF_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 692b9c1e60eSDaniel Borkmann PPC_BCC_SHORT(COND_NE, tmp_idx); 693156d0e29SNaveen N. Rao break; 694156d0e29SNaveen N. Rao 695156d0e29SNaveen N. Rao /* 696156d0e29SNaveen N. Rao * BPF_LDX 697156d0e29SNaveen N. Rao */ 698156d0e29SNaveen N. Rao /* dst = *(u8 *)(ul) (src + off) */ 699156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_B: 700156d0e29SNaveen N. Rao PPC_LBZ(dst_reg, src_reg, off); 701156d0e29SNaveen N. Rao break; 702156d0e29SNaveen N. Rao /* dst = *(u16 *)(ul) (src + off) */ 703156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_H: 704156d0e29SNaveen N. Rao PPC_LHZ(dst_reg, src_reg, off); 705156d0e29SNaveen N. Rao break; 706156d0e29SNaveen N. Rao /* dst = *(u32 *)(ul) (src + off) */ 707156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_W: 708156d0e29SNaveen N. Rao PPC_LWZ(dst_reg, src_reg, off); 709156d0e29SNaveen N. Rao break; 710156d0e29SNaveen N. Rao /* dst = *(u64 *)(ul) (src + off) */ 711156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_DW: 712156d0e29SNaveen N. Rao PPC_LD(dst_reg, src_reg, off); 713156d0e29SNaveen N. Rao break; 714156d0e29SNaveen N. Rao 715156d0e29SNaveen N. Rao /* 716156d0e29SNaveen N. Rao * Doubleword load 717156d0e29SNaveen N. Rao * 16 byte instruction that uses two 'struct bpf_insn' 718156d0e29SNaveen N. Rao */ 719156d0e29SNaveen N. Rao case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ 720156d0e29SNaveen N. Rao imm64 = ((u64)(u32) insn[i].imm) | 721156d0e29SNaveen N. Rao (((u64)(u32) insn[i+1].imm) << 32); 722156d0e29SNaveen N. Rao /* Adjust for two bpf instructions */ 723156d0e29SNaveen N. Rao addrs[++i] = ctx->idx * 4; 724156d0e29SNaveen N. Rao PPC_LI64(dst_reg, imm64); 725156d0e29SNaveen N. Rao break; 726156d0e29SNaveen N. Rao 727156d0e29SNaveen N. Rao /* 728156d0e29SNaveen N. Rao * Return/Exit 729156d0e29SNaveen N. Rao */ 730156d0e29SNaveen N. Rao case BPF_JMP | BPF_EXIT: 731156d0e29SNaveen N. Rao /* 732156d0e29SNaveen N. Rao * If this isn't the very last instruction, branch to 733156d0e29SNaveen N. Rao * the epilogue. If we _are_ the last instruction, 734156d0e29SNaveen N. Rao * we'll just fall through to the epilogue. 735156d0e29SNaveen N. Rao */ 736156d0e29SNaveen N. Rao if (i != flen - 1) 737156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 738156d0e29SNaveen N. Rao /* else fall through to the epilogue */ 739156d0e29SNaveen N. Rao break; 740156d0e29SNaveen N. Rao 741156d0e29SNaveen N. Rao /* 7428484ce83SSandipan Das * Call kernel helper or bpf function 743156d0e29SNaveen N. Rao */ 744156d0e29SNaveen N. Rao case BPF_JMP | BPF_CALL: 745156d0e29SNaveen N. Rao ctx->seen |= SEEN_FUNC; 7468484ce83SSandipan Das 747e2c95a61SDaniel Borkmann ret = bpf_jit_get_func_addr(fp, &insn[i], extra_pass, 748e2c95a61SDaniel Borkmann &func_addr, &func_addr_fixed); 749e2c95a61SDaniel Borkmann if (ret < 0) 750e2c95a61SDaniel Borkmann return ret; 751156d0e29SNaveen N. Rao 752e2c95a61SDaniel Borkmann if (func_addr_fixed) 753e2c95a61SDaniel Borkmann bpf_jit_emit_func_call_hlp(image, ctx, func_addr); 754e2c95a61SDaniel Borkmann else 755e2c95a61SDaniel Borkmann bpf_jit_emit_func_call_rel(image, ctx, func_addr); 756156d0e29SNaveen N. Rao /* move return value from r3 to BPF_REG_0 */ 757156d0e29SNaveen N. Rao PPC_MR(b2p[BPF_REG_0], 3); 758156d0e29SNaveen N. Rao break; 759156d0e29SNaveen N. Rao 760156d0e29SNaveen N. Rao /* 761156d0e29SNaveen N. Rao * Jumps and branches 762156d0e29SNaveen N. Rao */ 763156d0e29SNaveen N. Rao case BPF_JMP | BPF_JA: 764156d0e29SNaveen N. Rao PPC_JMP(addrs[i + 1 + off]); 765156d0e29SNaveen N. Rao break; 766156d0e29SNaveen N. Rao 767156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_K: 768156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_X: 769156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_K: 770156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_X: 771156d0e29SNaveen N. Rao true_cond = COND_GT; 772156d0e29SNaveen N. Rao goto cond_branch; 77320dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLT | BPF_K: 77420dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLT | BPF_X: 77520dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLT | BPF_K: 77620dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLT | BPF_X: 77720dbf5ccSDaniel Borkmann true_cond = COND_LT; 77820dbf5ccSDaniel Borkmann goto cond_branch; 779156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_K: 780156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_X: 781156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_K: 782156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_X: 783156d0e29SNaveen N. Rao true_cond = COND_GE; 784156d0e29SNaveen N. Rao goto cond_branch; 78520dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLE | BPF_K: 78620dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLE | BPF_X: 78720dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLE | BPF_K: 78820dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLE | BPF_X: 78920dbf5ccSDaniel Borkmann true_cond = COND_LE; 79020dbf5ccSDaniel Borkmann goto cond_branch; 791156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_K: 792156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_X: 793156d0e29SNaveen N. Rao true_cond = COND_EQ; 794156d0e29SNaveen N. Rao goto cond_branch; 795156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_K: 796156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_X: 797156d0e29SNaveen N. Rao true_cond = COND_NE; 798156d0e29SNaveen N. Rao goto cond_branch; 799156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_K: 800156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_X: 801156d0e29SNaveen N. Rao true_cond = COND_NE; 802156d0e29SNaveen N. Rao /* Fall through */ 803156d0e29SNaveen N. Rao 804156d0e29SNaveen N. Rao cond_branch: 805156d0e29SNaveen N. Rao switch (code) { 806156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_X: 80720dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLT | BPF_X: 808156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_X: 80920dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLE | BPF_X: 810156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_X: 811156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_X: 812156d0e29SNaveen N. Rao /* unsigned comparison */ 813156d0e29SNaveen N. Rao PPC_CMPLD(dst_reg, src_reg); 814156d0e29SNaveen N. Rao break; 815156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_X: 81620dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLT | BPF_X: 817156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_X: 81820dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLE | BPF_X: 819156d0e29SNaveen N. Rao /* signed comparison */ 820156d0e29SNaveen N. Rao PPC_CMPD(dst_reg, src_reg); 821156d0e29SNaveen N. Rao break; 822156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_X: 823156d0e29SNaveen N. Rao PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, src_reg); 824156d0e29SNaveen N. Rao break; 825156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_K: 826156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_K: 827156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_K: 82820dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLT | BPF_K: 829156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_K: 83020dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JLE | BPF_K: 831156d0e29SNaveen N. Rao /* 832156d0e29SNaveen N. Rao * Need sign-extended load, so only positive 833156d0e29SNaveen N. Rao * values can be used as imm in cmpldi 834156d0e29SNaveen N. Rao */ 835156d0e29SNaveen N. Rao if (imm >= 0 && imm < 32768) 836156d0e29SNaveen N. Rao PPC_CMPLDI(dst_reg, imm); 837156d0e29SNaveen N. Rao else { 838156d0e29SNaveen N. Rao /* sign-extending load */ 839156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 840156d0e29SNaveen N. Rao /* ... but unsigned comparison */ 841156d0e29SNaveen N. Rao PPC_CMPLD(dst_reg, b2p[TMP_REG_1]); 842156d0e29SNaveen N. Rao } 843156d0e29SNaveen N. Rao break; 844156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_K: 84520dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLT | BPF_K: 846156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_K: 84720dbf5ccSDaniel Borkmann case BPF_JMP | BPF_JSLE | BPF_K: 848156d0e29SNaveen N. Rao /* 849156d0e29SNaveen N. Rao * signed comparison, so any 16-bit value 850156d0e29SNaveen N. Rao * can be used in cmpdi 851156d0e29SNaveen N. Rao */ 852156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 853156d0e29SNaveen N. Rao PPC_CMPDI(dst_reg, imm); 854156d0e29SNaveen N. Rao else { 855156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 856156d0e29SNaveen N. Rao PPC_CMPD(dst_reg, b2p[TMP_REG_1]); 857156d0e29SNaveen N. Rao } 858156d0e29SNaveen N. Rao break; 859156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_K: 860156d0e29SNaveen N. Rao /* andi does not sign-extend the immediate */ 861156d0e29SNaveen N. Rao if (imm >= 0 && imm < 32768) 862156d0e29SNaveen N. Rao /* PPC_ANDI is _only/always_ dot-form */ 863156d0e29SNaveen N. Rao PPC_ANDI(b2p[TMP_REG_1], dst_reg, imm); 864156d0e29SNaveen N. Rao else { 865156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 866156d0e29SNaveen N. Rao PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, 867156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 868156d0e29SNaveen N. Rao } 869156d0e29SNaveen N. Rao break; 870156d0e29SNaveen N. Rao } 871156d0e29SNaveen N. Rao PPC_BCC(true_cond, addrs[i + 1 + off]); 872156d0e29SNaveen N. Rao break; 873156d0e29SNaveen N. Rao 874156d0e29SNaveen N. Rao /* 875ce076141SNaveen N. Rao * Tail call 876156d0e29SNaveen N. Rao */ 87771189fa9SAlexei Starovoitov case BPF_JMP | BPF_TAIL_CALL: 878ce076141SNaveen N. Rao ctx->seen |= SEEN_TAILCALL; 879ce076141SNaveen N. Rao bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); 880ce076141SNaveen N. Rao break; 881156d0e29SNaveen N. Rao 882156d0e29SNaveen N. Rao default: 883156d0e29SNaveen N. Rao /* 884156d0e29SNaveen N. Rao * The filter contains something cruel & unusual. 885156d0e29SNaveen N. Rao * We don't handle it, but also there shouldn't be 886156d0e29SNaveen N. Rao * anything missing from our list. 887156d0e29SNaveen N. Rao */ 888156d0e29SNaveen N. Rao pr_err_ratelimited("eBPF filter opcode %04x (@%d) unsupported\n", 889156d0e29SNaveen N. Rao code, i); 890156d0e29SNaveen N. Rao return -ENOTSUPP; 891156d0e29SNaveen N. Rao } 892156d0e29SNaveen N. Rao } 893156d0e29SNaveen N. Rao 894156d0e29SNaveen N. Rao /* Set end-of-body-code address for exit. */ 895156d0e29SNaveen N. Rao addrs[i] = ctx->idx * 4; 896156d0e29SNaveen N. Rao 897156d0e29SNaveen N. Rao return 0; 898156d0e29SNaveen N. Rao } 899156d0e29SNaveen N. Rao 9008484ce83SSandipan Das struct powerpc64_jit_data { 9018484ce83SSandipan Das struct bpf_binary_header *header; 9028484ce83SSandipan Das u32 *addrs; 9038484ce83SSandipan Das u8 *image; 9048484ce83SSandipan Das u32 proglen; 9058484ce83SSandipan Das struct codegen_context ctx; 9068484ce83SSandipan Das }; 9078484ce83SSandipan Das 908156d0e29SNaveen N. Rao struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) 909156d0e29SNaveen N. Rao { 910156d0e29SNaveen N. Rao u32 proglen; 911156d0e29SNaveen N. Rao u32 alloclen; 912156d0e29SNaveen N. Rao u8 *image = NULL; 913156d0e29SNaveen N. Rao u32 *code_base; 914156d0e29SNaveen N. Rao u32 *addrs; 9158484ce83SSandipan Das struct powerpc64_jit_data *jit_data; 916156d0e29SNaveen N. Rao struct codegen_context cgctx; 917156d0e29SNaveen N. Rao int pass; 918156d0e29SNaveen N. Rao int flen; 919156d0e29SNaveen N. Rao struct bpf_binary_header *bpf_hdr; 920b7b7013cSNaveen N. Rao struct bpf_prog *org_fp = fp; 921b7b7013cSNaveen N. Rao struct bpf_prog *tmp_fp; 922b7b7013cSNaveen N. Rao bool bpf_blinded = false; 9238484ce83SSandipan Das bool extra_pass = false; 924156d0e29SNaveen N. Rao 92560b58afcSAlexei Starovoitov if (!fp->jit_requested) 926b7b7013cSNaveen N. Rao return org_fp; 927b7b7013cSNaveen N. Rao 928b7b7013cSNaveen N. Rao tmp_fp = bpf_jit_blind_constants(org_fp); 929b7b7013cSNaveen N. Rao if (IS_ERR(tmp_fp)) 930b7b7013cSNaveen N. Rao return org_fp; 931b7b7013cSNaveen N. Rao 932b7b7013cSNaveen N. Rao if (tmp_fp != org_fp) { 933b7b7013cSNaveen N. Rao bpf_blinded = true; 934b7b7013cSNaveen N. Rao fp = tmp_fp; 935b7b7013cSNaveen N. Rao } 936156d0e29SNaveen N. Rao 9378484ce83SSandipan Das jit_data = fp->aux->jit_data; 9388484ce83SSandipan Das if (!jit_data) { 9398484ce83SSandipan Das jit_data = kzalloc(sizeof(*jit_data), GFP_KERNEL); 9408484ce83SSandipan Das if (!jit_data) { 9418484ce83SSandipan Das fp = org_fp; 9428484ce83SSandipan Das goto out; 9438484ce83SSandipan Das } 9448484ce83SSandipan Das fp->aux->jit_data = jit_data; 9458484ce83SSandipan Das } 9468484ce83SSandipan Das 947156d0e29SNaveen N. Rao flen = fp->len; 9488484ce83SSandipan Das addrs = jit_data->addrs; 9498484ce83SSandipan Das if (addrs) { 9508484ce83SSandipan Das cgctx = jit_data->ctx; 9518484ce83SSandipan Das image = jit_data->image; 9528484ce83SSandipan Das bpf_hdr = jit_data->header; 9538484ce83SSandipan Das proglen = jit_data->proglen; 9548484ce83SSandipan Das alloclen = proglen + FUNCTION_DESCR_SIZE; 9558484ce83SSandipan Das extra_pass = true; 9568484ce83SSandipan Das goto skip_init_ctx; 9578484ce83SSandipan Das } 9588484ce83SSandipan Das 9596396bb22SKees Cook addrs = kcalloc(flen + 1, sizeof(*addrs), GFP_KERNEL); 960b7b7013cSNaveen N. Rao if (addrs == NULL) { 961b7b7013cSNaveen N. Rao fp = org_fp; 9628484ce83SSandipan Das goto out_addrs; 963b7b7013cSNaveen N. Rao } 964b7b7013cSNaveen N. Rao 965b7b7013cSNaveen N. Rao memset(&cgctx, 0, sizeof(struct codegen_context)); 966b7b7013cSNaveen N. Rao 967ac0761ebSSandipan Das /* Make sure that the stack is quadword aligned. */ 968ac0761ebSSandipan Das cgctx.stack_size = round_up(fp->aux->stack_depth, 16); 969ac0761ebSSandipan Das 970b7b7013cSNaveen N. Rao /* Scouting faux-generate pass 0 */ 9718484ce83SSandipan Das if (bpf_jit_build_body(fp, 0, &cgctx, addrs, false)) { 972b7b7013cSNaveen N. Rao /* We hit something illegal or unsupported. */ 973b7b7013cSNaveen N. Rao fp = org_fp; 9748484ce83SSandipan Das goto out_addrs; 975b7b7013cSNaveen N. Rao } 976156d0e29SNaveen N. Rao 977156d0e29SNaveen N. Rao /* 978156d0e29SNaveen N. Rao * Pretend to build prologue, given the features we've seen. This will 979156d0e29SNaveen N. Rao * update ctgtx.idx as it pretends to output instructions, then we can 980156d0e29SNaveen N. Rao * calculate total size from idx. 981156d0e29SNaveen N. Rao */ 982156d0e29SNaveen N. Rao bpf_jit_build_prologue(0, &cgctx); 983156d0e29SNaveen N. Rao bpf_jit_build_epilogue(0, &cgctx); 984156d0e29SNaveen N. Rao 985156d0e29SNaveen N. Rao proglen = cgctx.idx * 4; 986156d0e29SNaveen N. Rao alloclen = proglen + FUNCTION_DESCR_SIZE; 987156d0e29SNaveen N. Rao 988156d0e29SNaveen N. Rao bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, 989156d0e29SNaveen N. Rao bpf_jit_fill_ill_insns); 990b7b7013cSNaveen N. Rao if (!bpf_hdr) { 991b7b7013cSNaveen N. Rao fp = org_fp; 9928484ce83SSandipan Das goto out_addrs; 993b7b7013cSNaveen N. Rao } 994156d0e29SNaveen N. Rao 9958484ce83SSandipan Das skip_init_ctx: 996156d0e29SNaveen N. Rao code_base = (u32 *)(image + FUNCTION_DESCR_SIZE); 997156d0e29SNaveen N. Rao 998156d0e29SNaveen N. Rao /* Code generation passes 1-2 */ 999156d0e29SNaveen N. Rao for (pass = 1; pass < 3; pass++) { 1000156d0e29SNaveen N. Rao /* Now build the prologue, body code & epilogue for real. */ 1001156d0e29SNaveen N. Rao cgctx.idx = 0; 1002156d0e29SNaveen N. Rao bpf_jit_build_prologue(code_base, &cgctx); 10038484ce83SSandipan Das bpf_jit_build_body(fp, code_base, &cgctx, addrs, extra_pass); 1004156d0e29SNaveen N. Rao bpf_jit_build_epilogue(code_base, &cgctx); 1005156d0e29SNaveen N. Rao 1006156d0e29SNaveen N. Rao if (bpf_jit_enable > 1) 1007156d0e29SNaveen N. Rao pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass, 1008156d0e29SNaveen N. Rao proglen - (cgctx.idx * 4), cgctx.seen); 1009156d0e29SNaveen N. Rao } 1010156d0e29SNaveen N. Rao 1011156d0e29SNaveen N. Rao if (bpf_jit_enable > 1) 1012156d0e29SNaveen N. Rao /* 1013156d0e29SNaveen N. Rao * Note that we output the base address of the code_base 1014156d0e29SNaveen N. Rao * rather than image, since opcodes are in code_base. 1015156d0e29SNaveen N. Rao */ 1016156d0e29SNaveen N. Rao bpf_jit_dump(flen, proglen, pass, code_base); 1017156d0e29SNaveen N. Rao 1018156d0e29SNaveen N. Rao #ifdef PPC64_ELF_ABI_v1 1019156d0e29SNaveen N. Rao /* Function descriptor nastiness: Address + TOC */ 1020156d0e29SNaveen N. Rao ((u64 *)image)[0] = (u64)code_base; 1021156d0e29SNaveen N. Rao ((u64 *)image)[1] = local_paca->kernel_toc; 1022156d0e29SNaveen N. Rao #endif 1023052de33cSDaniel Borkmann 1024156d0e29SNaveen N. Rao fp->bpf_func = (void *)image; 1025156d0e29SNaveen N. Rao fp->jited = 1; 1026783d28ddSMartin KaFai Lau fp->jited_len = alloclen; 1027156d0e29SNaveen N. Rao 102810528b9cSNaveen N. Rao bpf_flush_icache(bpf_hdr, (u8 *)bpf_hdr + (bpf_hdr->pages * PAGE_SIZE)); 10298484ce83SSandipan Das if (!fp->is_func || extra_pass) { 10308484ce83SSandipan Das out_addrs: 10318484ce83SSandipan Das kfree(addrs); 10328484ce83SSandipan Das kfree(jit_data); 10338484ce83SSandipan Das fp->aux->jit_data = NULL; 10348484ce83SSandipan Das } else { 10358484ce83SSandipan Das jit_data->addrs = addrs; 10368484ce83SSandipan Das jit_data->ctx = cgctx; 10378484ce83SSandipan Das jit_data->proglen = proglen; 10388484ce83SSandipan Das jit_data->image = image; 10398484ce83SSandipan Das jit_data->header = bpf_hdr; 10408484ce83SSandipan Das } 1041156d0e29SNaveen N. Rao 1042156d0e29SNaveen N. Rao out: 1043b7b7013cSNaveen N. Rao if (bpf_blinded) 1044b7b7013cSNaveen N. Rao bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp); 1045b7b7013cSNaveen N. Rao 1046156d0e29SNaveen N. Rao return fp; 1047156d0e29SNaveen N. Rao } 1048156d0e29SNaveen N. Rao 104974451e66SDaniel Borkmann /* Overriding bpf_jit_free() as we don't set images read-only. */ 1050156d0e29SNaveen N. Rao void bpf_jit_free(struct bpf_prog *fp) 1051156d0e29SNaveen N. Rao { 1052156d0e29SNaveen N. Rao unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; 1053156d0e29SNaveen N. Rao struct bpf_binary_header *bpf_hdr = (void *)addr; 1054156d0e29SNaveen N. Rao 1055156d0e29SNaveen N. Rao if (fp->jited) 1056156d0e29SNaveen N. Rao bpf_jit_binary_free(bpf_hdr); 1057156d0e29SNaveen N. Rao 1058156d0e29SNaveen N. Rao bpf_prog_unlock_free(fp); 1059156d0e29SNaveen N. Rao } 1060