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> 16156d0e29SNaveen N. Rao #include <linux/netdevice.h> 17156d0e29SNaveen N. Rao #include <linux/filter.h> 18156d0e29SNaveen N. Rao #include <linux/if_vlan.h> 19156d0e29SNaveen N. Rao #include <asm/kprobes.h> 20ce076141SNaveen N. Rao #include <linux/bpf.h> 21156d0e29SNaveen N. Rao 22156d0e29SNaveen N. Rao #include "bpf_jit64.h" 23156d0e29SNaveen N. Rao 24156d0e29SNaveen N. Rao int bpf_jit_enable __read_mostly; 25156d0e29SNaveen N. Rao 26156d0e29SNaveen N. Rao static void bpf_jit_fill_ill_insns(void *area, unsigned int size) 27156d0e29SNaveen N. Rao { 28156d0e29SNaveen N. Rao int *p = area; 29156d0e29SNaveen N. Rao 30156d0e29SNaveen N. Rao /* Fill whole space with trap instructions */ 31156d0e29SNaveen N. Rao while (p < (int *)((char *)area + size)) 32156d0e29SNaveen N. Rao *p++ = BREAKPOINT_INSTRUCTION; 33156d0e29SNaveen N. Rao } 34156d0e29SNaveen N. Rao 35156d0e29SNaveen N. Rao static inline void bpf_flush_icache(void *start, void *end) 36156d0e29SNaveen N. Rao { 37156d0e29SNaveen N. Rao smp_wmb(); 38156d0e29SNaveen N. Rao flush_icache_range((unsigned long)start, (unsigned long)end); 39156d0e29SNaveen N. Rao } 40156d0e29SNaveen N. Rao 41156d0e29SNaveen N. Rao static inline bool bpf_is_seen_register(struct codegen_context *ctx, int i) 42156d0e29SNaveen N. Rao { 43156d0e29SNaveen N. Rao return (ctx->seen & (1 << (31 - b2p[i]))); 44156d0e29SNaveen N. Rao } 45156d0e29SNaveen N. Rao 46156d0e29SNaveen N. Rao static inline void bpf_set_seen_register(struct codegen_context *ctx, int i) 47156d0e29SNaveen N. Rao { 48156d0e29SNaveen N. Rao ctx->seen |= (1 << (31 - b2p[i])); 49156d0e29SNaveen N. Rao } 50156d0e29SNaveen N. Rao 51156d0e29SNaveen N. Rao static inline bool bpf_has_stack_frame(struct codegen_context *ctx) 52156d0e29SNaveen N. Rao { 53156d0e29SNaveen N. Rao /* 54156d0e29SNaveen N. Rao * We only need a stack frame if: 55156d0e29SNaveen N. Rao * - we call other functions (kernel helpers), or 56156d0e29SNaveen N. Rao * - the bpf program uses its stack area 57156d0e29SNaveen N. Rao * The latter condition is deduced from the usage of BPF_REG_FP 58156d0e29SNaveen N. Rao */ 59156d0e29SNaveen N. Rao return ctx->seen & SEEN_FUNC || bpf_is_seen_register(ctx, BPF_REG_FP); 60156d0e29SNaveen N. Rao } 61156d0e29SNaveen N. Rao 627b847f52SNaveen N. Rao /* 637b847f52SNaveen N. Rao * When not setting up our own stackframe, the redzone usage is: 647b847f52SNaveen N. Rao * 657b847f52SNaveen N. Rao * [ prev sp ] <------------- 667b847f52SNaveen N. Rao * [ ... ] | 677b847f52SNaveen N. Rao * sp (r1) ---> [ stack pointer ] -------------- 687b847f52SNaveen N. Rao * [ nv gpr save area ] 8*8 697b847f52SNaveen N. Rao * [ tail_call_cnt ] 8 707b847f52SNaveen N. Rao * [ local_tmp_var ] 8 717b847f52SNaveen N. Rao * [ unused red zone ] 208 bytes protected 727b847f52SNaveen N. Rao */ 737b847f52SNaveen N. Rao static int bpf_jit_stack_local(struct codegen_context *ctx) 747b847f52SNaveen N. Rao { 757b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) 767b847f52SNaveen N. Rao return STACK_FRAME_MIN_SIZE + MAX_BPF_STACK; 777b847f52SNaveen N. Rao else 787b847f52SNaveen N. Rao return -(BPF_PPC_STACK_SAVE + 16); 797b847f52SNaveen N. Rao } 807b847f52SNaveen N. Rao 81ce076141SNaveen N. Rao static int bpf_jit_stack_tailcallcnt(struct codegen_context *ctx) 82ce076141SNaveen N. Rao { 83ce076141SNaveen N. Rao return bpf_jit_stack_local(ctx) + 8; 84ce076141SNaveen N. Rao } 85ce076141SNaveen N. Rao 867b847f52SNaveen N. Rao static int bpf_jit_stack_offsetof(struct codegen_context *ctx, int reg) 877b847f52SNaveen N. Rao { 887b847f52SNaveen N. Rao if (reg >= BPF_PPC_NVR_MIN && reg < 32) 897b847f52SNaveen N. Rao return (bpf_has_stack_frame(ctx) ? BPF_PPC_STACKFRAME : 0) 907b847f52SNaveen N. Rao - (8 * (32 - reg)); 917b847f52SNaveen N. Rao 927b847f52SNaveen N. Rao pr_err("BPF JIT is asking about unknown registers"); 937b847f52SNaveen N. Rao BUG(); 947b847f52SNaveen N. Rao } 957b847f52SNaveen N. Rao 96156d0e29SNaveen N. Rao static void bpf_jit_emit_skb_loads(u32 *image, struct codegen_context *ctx) 97156d0e29SNaveen N. Rao { 98156d0e29SNaveen N. Rao /* 99156d0e29SNaveen N. Rao * Load skb->len and skb->data_len 100156d0e29SNaveen N. Rao * r3 points to skb 101156d0e29SNaveen N. Rao */ 102156d0e29SNaveen N. Rao PPC_LWZ(b2p[SKB_HLEN_REG], 3, offsetof(struct sk_buff, len)); 103156d0e29SNaveen N. Rao PPC_LWZ(b2p[TMP_REG_1], 3, offsetof(struct sk_buff, data_len)); 104156d0e29SNaveen N. Rao /* header_len = len - data_len */ 105156d0e29SNaveen N. Rao PPC_SUB(b2p[SKB_HLEN_REG], b2p[SKB_HLEN_REG], b2p[TMP_REG_1]); 106156d0e29SNaveen N. Rao 107156d0e29SNaveen N. Rao /* skb->data pointer */ 108156d0e29SNaveen N. Rao PPC_BPF_LL(b2p[SKB_DATA_REG], 3, offsetof(struct sk_buff, data)); 109156d0e29SNaveen N. Rao } 110156d0e29SNaveen N. Rao 111156d0e29SNaveen N. Rao static void bpf_jit_build_prologue(u32 *image, struct codegen_context *ctx) 112156d0e29SNaveen N. Rao { 113156d0e29SNaveen N. Rao int i; 114156d0e29SNaveen N. Rao 115ce076141SNaveen N. Rao /* 116ce076141SNaveen N. Rao * Initialize tail_call_cnt if we do tail calls. 117ce076141SNaveen N. Rao * Otherwise, put in NOPs so that it can be skipped when we are 118ce076141SNaveen N. Rao * invoked through a tail call. 119ce076141SNaveen N. Rao */ 120ce076141SNaveen N. Rao if (ctx->seen & SEEN_TAILCALL) { 121ce076141SNaveen N. Rao PPC_LI(b2p[TMP_REG_1], 0); 122ce076141SNaveen N. Rao /* this goes in the redzone */ 123ce076141SNaveen N. Rao PPC_BPF_STL(b2p[TMP_REG_1], 1, -(BPF_PPC_STACK_SAVE + 8)); 124ce076141SNaveen N. Rao } else { 125ce076141SNaveen N. Rao PPC_NOP(); 126ce076141SNaveen N. Rao PPC_NOP(); 127ce076141SNaveen N. Rao } 128ce076141SNaveen N. Rao 129ce076141SNaveen N. Rao #define BPF_TAILCALL_PROLOGUE_SIZE 8 130ce076141SNaveen N. Rao 1317b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) { 132156d0e29SNaveen N. Rao /* 133156d0e29SNaveen N. Rao * We need a stack frame, but we don't necessarily need to 134156d0e29SNaveen N. Rao * save/restore LR unless we call other functions 135156d0e29SNaveen N. Rao */ 136156d0e29SNaveen N. Rao if (ctx->seen & SEEN_FUNC) { 137156d0e29SNaveen N. Rao EMIT(PPC_INST_MFLR | __PPC_RT(R0)); 138156d0e29SNaveen N. Rao PPC_BPF_STL(0, 1, PPC_LR_STKOFF); 139156d0e29SNaveen N. Rao } 140156d0e29SNaveen N. Rao 141156d0e29SNaveen N. Rao PPC_BPF_STLU(1, 1, -BPF_PPC_STACKFRAME); 142156d0e29SNaveen N. Rao } 143156d0e29SNaveen N. Rao 144156d0e29SNaveen N. Rao /* 145156d0e29SNaveen N. Rao * Back up non-volatile regs -- BPF registers 6-10 146156d0e29SNaveen N. Rao * If we haven't created our own stack frame, we save these 147156d0e29SNaveen N. Rao * in the protected zone below the previous stack frame 148156d0e29SNaveen N. Rao */ 149156d0e29SNaveen N. Rao for (i = BPF_REG_6; i <= BPF_REG_10; i++) 150156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, i)) 1517b847f52SNaveen N. Rao PPC_BPF_STL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 152156d0e29SNaveen N. Rao 153156d0e29SNaveen N. Rao /* 154156d0e29SNaveen N. Rao * Save additional non-volatile regs if we cache skb 155156d0e29SNaveen N. Rao * Also, setup skb data 156156d0e29SNaveen N. Rao */ 157156d0e29SNaveen N. Rao if (ctx->seen & SEEN_SKB) { 158156d0e29SNaveen N. Rao PPC_BPF_STL(b2p[SKB_HLEN_REG], 1, 1597b847f52SNaveen N. Rao bpf_jit_stack_offsetof(ctx, b2p[SKB_HLEN_REG])); 160156d0e29SNaveen N. Rao PPC_BPF_STL(b2p[SKB_DATA_REG], 1, 1617b847f52SNaveen N. Rao bpf_jit_stack_offsetof(ctx, b2p[SKB_DATA_REG])); 162156d0e29SNaveen N. Rao bpf_jit_emit_skb_loads(image, ctx); 163156d0e29SNaveen N. Rao } 164156d0e29SNaveen N. Rao 165156d0e29SNaveen N. Rao /* Setup frame pointer to point to the bpf stack area */ 166156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, BPF_REG_FP)) 167156d0e29SNaveen N. Rao PPC_ADDI(b2p[BPF_REG_FP], 1, 1687b847f52SNaveen N. Rao STACK_FRAME_MIN_SIZE + MAX_BPF_STACK); 169156d0e29SNaveen N. Rao } 170156d0e29SNaveen N. Rao 171ce076141SNaveen N. Rao static void bpf_jit_emit_common_epilogue(u32 *image, struct codegen_context *ctx) 172156d0e29SNaveen N. Rao { 173156d0e29SNaveen N. Rao int i; 174156d0e29SNaveen N. Rao 175156d0e29SNaveen N. Rao /* Restore NVRs */ 176156d0e29SNaveen N. Rao for (i = BPF_REG_6; i <= BPF_REG_10; i++) 177156d0e29SNaveen N. Rao if (bpf_is_seen_register(ctx, i)) 1787b847f52SNaveen N. Rao PPC_BPF_LL(b2p[i], 1, bpf_jit_stack_offsetof(ctx, b2p[i])); 179156d0e29SNaveen N. Rao 180156d0e29SNaveen N. Rao /* Restore non-volatile registers used for skb cache */ 181156d0e29SNaveen N. Rao if (ctx->seen & SEEN_SKB) { 182156d0e29SNaveen N. Rao PPC_BPF_LL(b2p[SKB_HLEN_REG], 1, 1837b847f52SNaveen N. Rao bpf_jit_stack_offsetof(ctx, b2p[SKB_HLEN_REG])); 184156d0e29SNaveen N. Rao PPC_BPF_LL(b2p[SKB_DATA_REG], 1, 1857b847f52SNaveen N. Rao bpf_jit_stack_offsetof(ctx, b2p[SKB_DATA_REG])); 186156d0e29SNaveen N. Rao } 187156d0e29SNaveen N. Rao 188156d0e29SNaveen N. Rao /* Tear down our stack frame */ 1897b847f52SNaveen N. Rao if (bpf_has_stack_frame(ctx)) { 190156d0e29SNaveen N. Rao PPC_ADDI(1, 1, BPF_PPC_STACKFRAME); 191156d0e29SNaveen N. Rao if (ctx->seen & SEEN_FUNC) { 192156d0e29SNaveen N. Rao PPC_BPF_LL(0, 1, PPC_LR_STKOFF); 193156d0e29SNaveen N. Rao PPC_MTLR(0); 194156d0e29SNaveen N. Rao } 195156d0e29SNaveen N. Rao } 196ce076141SNaveen N. Rao } 197ce076141SNaveen N. Rao 198ce076141SNaveen N. Rao static void bpf_jit_build_epilogue(u32 *image, struct codegen_context *ctx) 199ce076141SNaveen N. Rao { 200ce076141SNaveen N. Rao bpf_jit_emit_common_epilogue(image, ctx); 201ce076141SNaveen N. Rao 202ce076141SNaveen N. Rao /* Move result to r3 */ 203ce076141SNaveen N. Rao PPC_MR(3, b2p[BPF_REG_0]); 204156d0e29SNaveen N. Rao 205156d0e29SNaveen N. Rao PPC_BLR(); 206156d0e29SNaveen N. Rao } 207156d0e29SNaveen N. Rao 208ce076141SNaveen N. Rao static void bpf_jit_emit_func_call(u32 *image, struct codegen_context *ctx, u64 func) 209ce076141SNaveen N. Rao { 210ce076141SNaveen N. Rao #ifdef PPC64_ELF_ABI_v1 211ce076141SNaveen N. Rao /* func points to the function descriptor */ 212ce076141SNaveen N. Rao PPC_LI64(b2p[TMP_REG_2], func); 213ce076141SNaveen N. Rao /* Load actual entry point from function descriptor */ 214ce076141SNaveen N. Rao PPC_BPF_LL(b2p[TMP_REG_1], b2p[TMP_REG_2], 0); 215ce076141SNaveen N. Rao /* ... and move it to LR */ 216ce076141SNaveen N. Rao PPC_MTLR(b2p[TMP_REG_1]); 217ce076141SNaveen N. Rao /* 218ce076141SNaveen N. Rao * Load TOC from function descriptor at offset 8. 219ce076141SNaveen N. Rao * We can clobber r2 since we get called through a 220ce076141SNaveen N. Rao * function pointer (so caller will save/restore r2) 221ce076141SNaveen N. Rao * and since we don't use a TOC ourself. 222ce076141SNaveen N. Rao */ 223ce076141SNaveen N. Rao PPC_BPF_LL(2, b2p[TMP_REG_2], 8); 224ce076141SNaveen N. Rao #else 225ce076141SNaveen N. Rao /* We can clobber r12 */ 226ce076141SNaveen N. Rao PPC_FUNC_ADDR(12, func); 227ce076141SNaveen N. Rao PPC_MTLR(12); 228ce076141SNaveen N. Rao #endif 229ce076141SNaveen N. Rao PPC_BLRL(); 230ce076141SNaveen N. Rao } 231ce076141SNaveen N. Rao 232ce076141SNaveen N. Rao static void bpf_jit_emit_tail_call(u32 *image, struct codegen_context *ctx, u32 out) 233ce076141SNaveen N. Rao { 234ce076141SNaveen N. Rao /* 235ce076141SNaveen N. Rao * By now, the eBPF program has already setup parameters in r3, r4 and r5 236ce076141SNaveen N. Rao * r3/BPF_REG_1 - pointer to ctx -- passed as is to the next bpf program 237ce076141SNaveen N. Rao * r4/BPF_REG_2 - pointer to bpf_array 238ce076141SNaveen N. Rao * r5/BPF_REG_3 - index in bpf_array 239ce076141SNaveen N. Rao */ 240ce076141SNaveen N. Rao int b2p_bpf_array = b2p[BPF_REG_2]; 241ce076141SNaveen N. Rao int b2p_index = b2p[BPF_REG_3]; 242ce076141SNaveen N. Rao 243ce076141SNaveen N. Rao /* 244ce076141SNaveen N. Rao * if (index >= array->map.max_entries) 245ce076141SNaveen N. Rao * goto out; 246ce076141SNaveen N. Rao */ 247ce076141SNaveen N. Rao PPC_LWZ(b2p[TMP_REG_1], b2p_bpf_array, offsetof(struct bpf_array, map.max_entries)); 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, 298156d0e29SNaveen N. Rao u32 *addrs) 299156d0e29SNaveen N. Rao { 300156d0e29SNaveen N. Rao const struct bpf_insn *insn = fp->insnsi; 301156d0e29SNaveen N. Rao int flen = fp->len; 302156d0e29SNaveen N. Rao int i; 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; 313156d0e29SNaveen N. Rao u64 imm64; 314156d0e29SNaveen N. Rao u8 *func; 315156d0e29SNaveen N. Rao u32 true_cond; 316156d0e29SNaveen N. Rao 317156d0e29SNaveen N. Rao /* 318156d0e29SNaveen N. Rao * addrs[] maps a BPF bytecode address into a real offset from 319156d0e29SNaveen N. Rao * the start of the body code. 320156d0e29SNaveen N. Rao */ 321156d0e29SNaveen N. Rao addrs[i] = ctx->idx * 4; 322156d0e29SNaveen N. Rao 323156d0e29SNaveen N. Rao /* 324156d0e29SNaveen N. Rao * As an optimization, we note down which non-volatile registers 325156d0e29SNaveen N. Rao * are used so that we can only save/restore those in our 326156d0e29SNaveen N. Rao * prologue and epilogue. We do this here regardless of whether 327156d0e29SNaveen N. Rao * the actual BPF instruction uses src/dst registers or not 328156d0e29SNaveen N. Rao * (for instance, BPF_CALL does not use them). The expectation 329156d0e29SNaveen N. Rao * is that those instructions will have src_reg/dst_reg set to 330156d0e29SNaveen N. Rao * 0. Even otherwise, we just lose some prologue/epilogue 331156d0e29SNaveen N. Rao * optimization but everything else should work without 332156d0e29SNaveen N. Rao * any issues. 333156d0e29SNaveen N. Rao */ 3347b847f52SNaveen N. Rao if (dst_reg >= BPF_PPC_NVR_MIN && dst_reg < 32) 335156d0e29SNaveen N. Rao bpf_set_seen_register(ctx, insn[i].dst_reg); 3367b847f52SNaveen N. Rao if (src_reg >= BPF_PPC_NVR_MIN && src_reg < 32) 337156d0e29SNaveen N. Rao bpf_set_seen_register(ctx, insn[i].src_reg); 338156d0e29SNaveen N. Rao 339156d0e29SNaveen N. Rao switch (code) { 340156d0e29SNaveen N. Rao /* 341156d0e29SNaveen N. Rao * Arithmetic operations: ADD/SUB/MUL/DIV/MOD/NEG 342156d0e29SNaveen N. Rao */ 343156d0e29SNaveen N. Rao case BPF_ALU | BPF_ADD | BPF_X: /* (u32) dst += (u32) src */ 344156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ADD | BPF_X: /* dst += src */ 345156d0e29SNaveen N. Rao PPC_ADD(dst_reg, dst_reg, src_reg); 346156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 347156d0e29SNaveen N. Rao case BPF_ALU | BPF_SUB | BPF_X: /* (u32) dst -= (u32) src */ 348156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_SUB | BPF_X: /* dst -= src */ 349156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, src_reg); 350156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 351156d0e29SNaveen N. Rao case BPF_ALU | BPF_ADD | BPF_K: /* (u32) dst += (u32) imm */ 352156d0e29SNaveen N. Rao case BPF_ALU | BPF_SUB | BPF_K: /* (u32) dst -= (u32) imm */ 353156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ADD | BPF_K: /* dst += imm */ 354156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_SUB | BPF_K: /* dst -= imm */ 355156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_SUB) 356156d0e29SNaveen N. Rao imm = -imm; 357156d0e29SNaveen N. Rao if (imm) { 358156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 359156d0e29SNaveen N. Rao PPC_ADDI(dst_reg, dst_reg, IMM_L(imm)); 360156d0e29SNaveen N. Rao else { 361156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 362156d0e29SNaveen N. Rao PPC_ADD(dst_reg, dst_reg, b2p[TMP_REG_1]); 363156d0e29SNaveen N. Rao } 364156d0e29SNaveen N. Rao } 365156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 366156d0e29SNaveen N. Rao case BPF_ALU | BPF_MUL | BPF_X: /* (u32) dst *= (u32) src */ 367156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MUL | BPF_X: /* dst *= src */ 368156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ALU) 369156d0e29SNaveen N. Rao PPC_MULW(dst_reg, dst_reg, src_reg); 370156d0e29SNaveen N. Rao else 371156d0e29SNaveen N. Rao PPC_MULD(dst_reg, dst_reg, src_reg); 372156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 373156d0e29SNaveen N. Rao case BPF_ALU | BPF_MUL | BPF_K: /* (u32) dst *= (u32) imm */ 374156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MUL | BPF_K: /* dst *= imm */ 375156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 376156d0e29SNaveen N. Rao PPC_MULI(dst_reg, dst_reg, IMM_L(imm)); 377156d0e29SNaveen N. Rao else { 378156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 379156d0e29SNaveen N. Rao if (BPF_CLASS(code) == BPF_ALU) 380156d0e29SNaveen N. Rao PPC_MULW(dst_reg, dst_reg, 381156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 382156d0e29SNaveen N. Rao else 383156d0e29SNaveen N. Rao PPC_MULD(dst_reg, dst_reg, 384156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 385156d0e29SNaveen N. Rao } 386156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 387156d0e29SNaveen N. Rao case BPF_ALU | BPF_DIV | BPF_X: /* (u32) dst /= (u32) src */ 388156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOD | BPF_X: /* (u32) dst %= (u32) src */ 389156d0e29SNaveen N. Rao PPC_CMPWI(src_reg, 0); 390156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_NE, (ctx->idx * 4) + 12); 391156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 392156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 393156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 394156d0e29SNaveen N. Rao PPC_DIVWU(b2p[TMP_REG_1], dst_reg, src_reg); 395156d0e29SNaveen N. Rao PPC_MULW(b2p[TMP_REG_1], src_reg, 396156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 397156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]); 398156d0e29SNaveen N. Rao } else 399156d0e29SNaveen N. Rao PPC_DIVWU(dst_reg, dst_reg, src_reg); 400156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 401156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_DIV | BPF_X: /* dst /= src */ 402156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOD | BPF_X: /* dst %= src */ 403156d0e29SNaveen N. Rao PPC_CMPDI(src_reg, 0); 404156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_NE, (ctx->idx * 4) + 12); 405156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 406156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 407156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 408156d0e29SNaveen N. Rao PPC_DIVD(b2p[TMP_REG_1], dst_reg, src_reg); 409156d0e29SNaveen N. Rao PPC_MULD(b2p[TMP_REG_1], src_reg, 410156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 411156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, b2p[TMP_REG_1]); 412156d0e29SNaveen N. Rao } else 413156d0e29SNaveen N. Rao PPC_DIVD(dst_reg, dst_reg, src_reg); 414156d0e29SNaveen N. Rao break; 415156d0e29SNaveen N. Rao case BPF_ALU | BPF_MOD | BPF_K: /* (u32) dst %= (u32) imm */ 416156d0e29SNaveen N. Rao case BPF_ALU | BPF_DIV | BPF_K: /* (u32) dst /= (u32) imm */ 417156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_MOD | BPF_K: /* dst %= imm */ 418156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_DIV | BPF_K: /* dst /= imm */ 419156d0e29SNaveen N. Rao if (imm == 0) 420156d0e29SNaveen N. Rao return -EINVAL; 421156d0e29SNaveen N. Rao else if (imm == 1) 422156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 423156d0e29SNaveen N. Rao 424156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 425156d0e29SNaveen N. Rao switch (BPF_CLASS(code)) { 426156d0e29SNaveen N. Rao case BPF_ALU: 427156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 428156d0e29SNaveen N. Rao PPC_DIVWU(b2p[TMP_REG_2], dst_reg, 429156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 430156d0e29SNaveen N. Rao PPC_MULW(b2p[TMP_REG_1], 431156d0e29SNaveen N. Rao b2p[TMP_REG_1], 432156d0e29SNaveen N. Rao b2p[TMP_REG_2]); 433156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, 434156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 435156d0e29SNaveen N. Rao } else 436156d0e29SNaveen N. Rao PPC_DIVWU(dst_reg, dst_reg, 437156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 438156d0e29SNaveen N. Rao break; 439156d0e29SNaveen N. Rao case BPF_ALU64: 440156d0e29SNaveen N. Rao if (BPF_OP(code) == BPF_MOD) { 441156d0e29SNaveen N. Rao PPC_DIVD(b2p[TMP_REG_2], dst_reg, 442156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 443156d0e29SNaveen N. Rao PPC_MULD(b2p[TMP_REG_1], 444156d0e29SNaveen N. Rao b2p[TMP_REG_1], 445156d0e29SNaveen N. Rao b2p[TMP_REG_2]); 446156d0e29SNaveen N. Rao PPC_SUB(dst_reg, dst_reg, 447156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 448156d0e29SNaveen N. Rao } else 449156d0e29SNaveen N. Rao PPC_DIVD(dst_reg, dst_reg, 450156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 451156d0e29SNaveen N. Rao break; 452156d0e29SNaveen N. Rao } 453156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 454156d0e29SNaveen N. Rao case BPF_ALU | BPF_NEG: /* (u32) dst = -dst */ 455156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_NEG: /* dst = -dst */ 456156d0e29SNaveen N. Rao PPC_NEG(dst_reg, dst_reg); 457156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 458156d0e29SNaveen N. Rao 459156d0e29SNaveen N. Rao /* 460156d0e29SNaveen N. Rao * Logical operations: AND/OR/XOR/[A]LSH/[A]RSH 461156d0e29SNaveen N. Rao */ 462156d0e29SNaveen N. Rao case BPF_ALU | BPF_AND | BPF_X: /* (u32) dst = dst & src */ 463156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_AND | BPF_X: /* dst = dst & src */ 464156d0e29SNaveen N. Rao PPC_AND(dst_reg, dst_reg, src_reg); 465156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 466156d0e29SNaveen N. Rao case BPF_ALU | BPF_AND | BPF_K: /* (u32) dst = dst & imm */ 467156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_AND | BPF_K: /* dst = dst & imm */ 468156d0e29SNaveen N. Rao if (!IMM_H(imm)) 469156d0e29SNaveen N. Rao PPC_ANDI(dst_reg, dst_reg, IMM_L(imm)); 470156d0e29SNaveen N. Rao else { 471156d0e29SNaveen N. Rao /* Sign-extended */ 472156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 473156d0e29SNaveen N. Rao PPC_AND(dst_reg, dst_reg, b2p[TMP_REG_1]); 474156d0e29SNaveen N. Rao } 475156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 476156d0e29SNaveen N. Rao case BPF_ALU | BPF_OR | BPF_X: /* dst = (u32) dst | (u32) src */ 477156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_OR | BPF_X: /* dst = dst | src */ 478156d0e29SNaveen N. Rao PPC_OR(dst_reg, dst_reg, src_reg); 479156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 480156d0e29SNaveen N. Rao case BPF_ALU | BPF_OR | BPF_K:/* dst = (u32) dst | (u32) imm */ 481156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_OR | BPF_K:/* dst = dst | imm */ 482156d0e29SNaveen N. Rao if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 483156d0e29SNaveen N. Rao /* Sign-extended */ 484156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 485156d0e29SNaveen N. Rao PPC_OR(dst_reg, dst_reg, b2p[TMP_REG_1]); 486156d0e29SNaveen N. Rao } else { 487156d0e29SNaveen N. Rao if (IMM_L(imm)) 488156d0e29SNaveen N. Rao PPC_ORI(dst_reg, dst_reg, IMM_L(imm)); 489156d0e29SNaveen N. Rao if (IMM_H(imm)) 490156d0e29SNaveen N. Rao PPC_ORIS(dst_reg, dst_reg, IMM_H(imm)); 491156d0e29SNaveen N. Rao } 492156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 493156d0e29SNaveen N. Rao case BPF_ALU | BPF_XOR | BPF_X: /* (u32) dst ^= src */ 494156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_XOR | BPF_X: /* dst ^= src */ 495156d0e29SNaveen N. Rao PPC_XOR(dst_reg, dst_reg, src_reg); 496156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 497156d0e29SNaveen N. Rao case BPF_ALU | BPF_XOR | BPF_K: /* (u32) dst ^= (u32) imm */ 498156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_XOR | BPF_K: /* dst ^= imm */ 499156d0e29SNaveen N. Rao if (imm < 0 && BPF_CLASS(code) == BPF_ALU64) { 500156d0e29SNaveen N. Rao /* Sign-extended */ 501156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 502156d0e29SNaveen N. Rao PPC_XOR(dst_reg, dst_reg, b2p[TMP_REG_1]); 503156d0e29SNaveen N. Rao } else { 504156d0e29SNaveen N. Rao if (IMM_L(imm)) 505156d0e29SNaveen N. Rao PPC_XORI(dst_reg, dst_reg, IMM_L(imm)); 506156d0e29SNaveen N. Rao if (IMM_H(imm)) 507156d0e29SNaveen N. Rao PPC_XORIS(dst_reg, dst_reg, IMM_H(imm)); 508156d0e29SNaveen N. Rao } 509156d0e29SNaveen N. Rao goto bpf_alu32_trunc; 510156d0e29SNaveen N. Rao case BPF_ALU | BPF_LSH | BPF_X: /* (u32) dst <<= (u32) src */ 511156d0e29SNaveen N. Rao /* slw clears top 32 bits */ 512156d0e29SNaveen N. Rao PPC_SLW(dst_reg, dst_reg, src_reg); 513156d0e29SNaveen N. Rao break; 514156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_LSH | BPF_X: /* dst <<= src; */ 515156d0e29SNaveen N. Rao PPC_SLD(dst_reg, dst_reg, src_reg); 516156d0e29SNaveen N. Rao break; 517156d0e29SNaveen N. Rao case BPF_ALU | BPF_LSH | BPF_K: /* (u32) dst <<== (u32) imm */ 518156d0e29SNaveen N. Rao /* with imm 0, we still need to clear top 32 bits */ 519156d0e29SNaveen N. Rao PPC_SLWI(dst_reg, dst_reg, imm); 520156d0e29SNaveen N. Rao break; 521156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_LSH | BPF_K: /* dst <<== imm */ 522156d0e29SNaveen N. Rao if (imm != 0) 523156d0e29SNaveen N. Rao PPC_SLDI(dst_reg, dst_reg, imm); 524156d0e29SNaveen N. Rao break; 525156d0e29SNaveen N. Rao case BPF_ALU | BPF_RSH | BPF_X: /* (u32) dst >>= (u32) src */ 526156d0e29SNaveen N. Rao PPC_SRW(dst_reg, dst_reg, src_reg); 527156d0e29SNaveen N. Rao break; 528156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_RSH | BPF_X: /* dst >>= src */ 529156d0e29SNaveen N. Rao PPC_SRD(dst_reg, dst_reg, src_reg); 530156d0e29SNaveen N. Rao break; 531156d0e29SNaveen N. Rao case BPF_ALU | BPF_RSH | BPF_K: /* (u32) dst >>= (u32) imm */ 532156d0e29SNaveen N. Rao PPC_SRWI(dst_reg, dst_reg, imm); 533156d0e29SNaveen N. Rao break; 534156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_RSH | BPF_K: /* dst >>= imm */ 535156d0e29SNaveen N. Rao if (imm != 0) 536156d0e29SNaveen N. Rao PPC_SRDI(dst_reg, dst_reg, imm); 537156d0e29SNaveen N. Rao break; 538156d0e29SNaveen N. Rao case BPF_ALU64 | BPF_ARSH | BPF_X: /* (s64) dst >>= src */ 539156d0e29SNaveen N. Rao PPC_SRAD(dst_reg, dst_reg, src_reg); 540156d0e29SNaveen N. Rao break; 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); 675156d0e29SNaveen N. Rao /* error if EA is not word-aligned */ 676156d0e29SNaveen N. Rao PPC_ANDI(b2p[TMP_REG_2], b2p[TMP_REG_1], 0x03); 677156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + 12); 678156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 679156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 680156d0e29SNaveen N. Rao /* load value from memory into TMP_REG_2 */ 681156d0e29SNaveen N. Rao PPC_BPF_LWARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); 682156d0e29SNaveen N. Rao /* add value from src_reg into this */ 683156d0e29SNaveen N. Rao PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); 684156d0e29SNaveen N. Rao /* store result back */ 685156d0e29SNaveen N. Rao PPC_BPF_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 686156d0e29SNaveen N. Rao /* we're done if this succeeded */ 687156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (7*4)); 688156d0e29SNaveen N. Rao /* otherwise, let's try once more */ 689156d0e29SNaveen N. Rao PPC_BPF_LWARX(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_STWCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 692156d0e29SNaveen N. Rao /* exit if the store was not successful */ 693156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 694156d0e29SNaveen N. Rao PPC_BCC(COND_NE, exit_addr); 695156d0e29SNaveen N. Rao break; 696156d0e29SNaveen N. Rao /* *(u64 *)(dst + off) += src */ 697156d0e29SNaveen N. Rao case BPF_STX | BPF_XADD | BPF_DW: 698156d0e29SNaveen N. Rao PPC_ADDI(b2p[TMP_REG_1], dst_reg, off); 699156d0e29SNaveen N. Rao /* error if EA is not doubleword-aligned */ 700156d0e29SNaveen N. Rao PPC_ANDI(b2p[TMP_REG_2], b2p[TMP_REG_1], 0x07); 701156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (3*4)); 702156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 703156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 704156d0e29SNaveen N. Rao PPC_BPF_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); 705156d0e29SNaveen N. Rao PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); 706156d0e29SNaveen N. Rao PPC_BPF_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 707156d0e29SNaveen N. Rao PPC_BCC_SHORT(COND_EQ, (ctx->idx * 4) + (7*4)); 708156d0e29SNaveen N. Rao PPC_BPF_LDARX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1], 0); 709156d0e29SNaveen N. Rao PPC_ADD(b2p[TMP_REG_2], b2p[TMP_REG_2], src_reg); 710156d0e29SNaveen N. Rao PPC_BPF_STDCX(b2p[TMP_REG_2], 0, b2p[TMP_REG_1]); 711156d0e29SNaveen N. Rao PPC_LI(b2p[BPF_REG_0], 0); 712156d0e29SNaveen N. Rao PPC_BCC(COND_NE, exit_addr); 713156d0e29SNaveen N. Rao break; 714156d0e29SNaveen N. Rao 715156d0e29SNaveen N. Rao /* 716156d0e29SNaveen N. Rao * BPF_LDX 717156d0e29SNaveen N. Rao */ 718156d0e29SNaveen N. Rao /* dst = *(u8 *)(ul) (src + off) */ 719156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_B: 720156d0e29SNaveen N. Rao PPC_LBZ(dst_reg, src_reg, off); 721156d0e29SNaveen N. Rao break; 722156d0e29SNaveen N. Rao /* dst = *(u16 *)(ul) (src + off) */ 723156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_H: 724156d0e29SNaveen N. Rao PPC_LHZ(dst_reg, src_reg, off); 725156d0e29SNaveen N. Rao break; 726156d0e29SNaveen N. Rao /* dst = *(u32 *)(ul) (src + off) */ 727156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_W: 728156d0e29SNaveen N. Rao PPC_LWZ(dst_reg, src_reg, off); 729156d0e29SNaveen N. Rao break; 730156d0e29SNaveen N. Rao /* dst = *(u64 *)(ul) (src + off) */ 731156d0e29SNaveen N. Rao case BPF_LDX | BPF_MEM | BPF_DW: 732156d0e29SNaveen N. Rao PPC_LD(dst_reg, src_reg, off); 733156d0e29SNaveen N. Rao break; 734156d0e29SNaveen N. Rao 735156d0e29SNaveen N. Rao /* 736156d0e29SNaveen N. Rao * Doubleword load 737156d0e29SNaveen N. Rao * 16 byte instruction that uses two 'struct bpf_insn' 738156d0e29SNaveen N. Rao */ 739156d0e29SNaveen N. Rao case BPF_LD | BPF_IMM | BPF_DW: /* dst = (u64) imm */ 740156d0e29SNaveen N. Rao imm64 = ((u64)(u32) insn[i].imm) | 741156d0e29SNaveen N. Rao (((u64)(u32) insn[i+1].imm) << 32); 742156d0e29SNaveen N. Rao /* Adjust for two bpf instructions */ 743156d0e29SNaveen N. Rao addrs[++i] = ctx->idx * 4; 744156d0e29SNaveen N. Rao PPC_LI64(dst_reg, imm64); 745156d0e29SNaveen N. Rao break; 746156d0e29SNaveen N. Rao 747156d0e29SNaveen N. Rao /* 748156d0e29SNaveen N. Rao * Return/Exit 749156d0e29SNaveen N. Rao */ 750156d0e29SNaveen N. Rao case BPF_JMP | BPF_EXIT: 751156d0e29SNaveen N. Rao /* 752156d0e29SNaveen N. Rao * If this isn't the very last instruction, branch to 753156d0e29SNaveen N. Rao * the epilogue. If we _are_ the last instruction, 754156d0e29SNaveen N. Rao * we'll just fall through to the epilogue. 755156d0e29SNaveen N. Rao */ 756156d0e29SNaveen N. Rao if (i != flen - 1) 757156d0e29SNaveen N. Rao PPC_JMP(exit_addr); 758156d0e29SNaveen N. Rao /* else fall through to the epilogue */ 759156d0e29SNaveen N. Rao break; 760156d0e29SNaveen N. Rao 761156d0e29SNaveen N. Rao /* 762156d0e29SNaveen N. Rao * Call kernel helper 763156d0e29SNaveen N. Rao */ 764156d0e29SNaveen N. Rao case BPF_JMP | BPF_CALL: 765156d0e29SNaveen N. Rao ctx->seen |= SEEN_FUNC; 766156d0e29SNaveen N. Rao func = (u8 *) __bpf_call_base + imm; 767156d0e29SNaveen N. Rao 768156d0e29SNaveen N. Rao /* Save skb pointer if we need to re-cache skb data */ 769156d0e29SNaveen N. Rao if (bpf_helper_changes_skb_data(func)) 7707b847f52SNaveen N. Rao PPC_BPF_STL(3, 1, bpf_jit_stack_local(ctx)); 771156d0e29SNaveen N. Rao 772156d0e29SNaveen N. Rao bpf_jit_emit_func_call(image, ctx, (u64)func); 773156d0e29SNaveen N. Rao 774156d0e29SNaveen N. Rao /* move return value from r3 to BPF_REG_0 */ 775156d0e29SNaveen N. Rao PPC_MR(b2p[BPF_REG_0], 3); 776156d0e29SNaveen N. Rao 777156d0e29SNaveen N. Rao /* refresh skb cache */ 778156d0e29SNaveen N. Rao if (bpf_helper_changes_skb_data(func)) { 779156d0e29SNaveen N. Rao /* reload skb pointer to r3 */ 7807b847f52SNaveen N. Rao PPC_BPF_LL(3, 1, bpf_jit_stack_local(ctx)); 781156d0e29SNaveen N. Rao bpf_jit_emit_skb_loads(image, ctx); 782156d0e29SNaveen N. Rao } 783156d0e29SNaveen N. Rao break; 784156d0e29SNaveen N. Rao 785156d0e29SNaveen N. Rao /* 786156d0e29SNaveen N. Rao * Jumps and branches 787156d0e29SNaveen N. Rao */ 788156d0e29SNaveen N. Rao case BPF_JMP | BPF_JA: 789156d0e29SNaveen N. Rao PPC_JMP(addrs[i + 1 + off]); 790156d0e29SNaveen N. Rao break; 791156d0e29SNaveen N. Rao 792156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_K: 793156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_X: 794156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_K: 795156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_X: 796156d0e29SNaveen N. Rao true_cond = COND_GT; 797156d0e29SNaveen N. Rao goto cond_branch; 798156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_K: 799156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_X: 800156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_K: 801156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_X: 802156d0e29SNaveen N. Rao true_cond = COND_GE; 803156d0e29SNaveen N. Rao goto cond_branch; 804156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_K: 805156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_X: 806156d0e29SNaveen N. Rao true_cond = COND_EQ; 807156d0e29SNaveen N. Rao goto cond_branch; 808156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_K: 809156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_X: 810156d0e29SNaveen N. Rao true_cond = COND_NE; 811156d0e29SNaveen N. Rao goto cond_branch; 812156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_K: 813156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_X: 814156d0e29SNaveen N. Rao true_cond = COND_NE; 815156d0e29SNaveen N. Rao /* Fall through */ 816156d0e29SNaveen N. Rao 817156d0e29SNaveen N. Rao cond_branch: 818156d0e29SNaveen N. Rao switch (code) { 819156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_X: 820156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_X: 821156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_X: 822156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_X: 823156d0e29SNaveen N. Rao /* unsigned comparison */ 824156d0e29SNaveen N. Rao PPC_CMPLD(dst_reg, src_reg); 825156d0e29SNaveen N. Rao break; 826156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_X: 827156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_X: 828156d0e29SNaveen N. Rao /* signed comparison */ 829156d0e29SNaveen N. Rao PPC_CMPD(dst_reg, src_reg); 830156d0e29SNaveen N. Rao break; 831156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_X: 832156d0e29SNaveen N. Rao PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, src_reg); 833156d0e29SNaveen N. Rao break; 834156d0e29SNaveen N. Rao case BPF_JMP | BPF_JNE | BPF_K: 835156d0e29SNaveen N. Rao case BPF_JMP | BPF_JEQ | BPF_K: 836156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGT | BPF_K: 837156d0e29SNaveen N. Rao case BPF_JMP | BPF_JGE | BPF_K: 838156d0e29SNaveen N. Rao /* 839156d0e29SNaveen N. Rao * Need sign-extended load, so only positive 840156d0e29SNaveen N. Rao * values can be used as imm in cmpldi 841156d0e29SNaveen N. Rao */ 842156d0e29SNaveen N. Rao if (imm >= 0 && imm < 32768) 843156d0e29SNaveen N. Rao PPC_CMPLDI(dst_reg, imm); 844156d0e29SNaveen N. Rao else { 845156d0e29SNaveen N. Rao /* sign-extending load */ 846156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 847156d0e29SNaveen N. Rao /* ... but unsigned comparison */ 848156d0e29SNaveen N. Rao PPC_CMPLD(dst_reg, b2p[TMP_REG_1]); 849156d0e29SNaveen N. Rao } 850156d0e29SNaveen N. Rao break; 851156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGT | BPF_K: 852156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSGE | BPF_K: 853156d0e29SNaveen N. Rao /* 854156d0e29SNaveen N. Rao * signed comparison, so any 16-bit value 855156d0e29SNaveen N. Rao * can be used in cmpdi 856156d0e29SNaveen N. Rao */ 857156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 858156d0e29SNaveen N. Rao PPC_CMPDI(dst_reg, imm); 859156d0e29SNaveen N. Rao else { 860156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 861156d0e29SNaveen N. Rao PPC_CMPD(dst_reg, b2p[TMP_REG_1]); 862156d0e29SNaveen N. Rao } 863156d0e29SNaveen N. Rao break; 864156d0e29SNaveen N. Rao case BPF_JMP | BPF_JSET | BPF_K: 865156d0e29SNaveen N. Rao /* andi does not sign-extend the immediate */ 866156d0e29SNaveen N. Rao if (imm >= 0 && imm < 32768) 867156d0e29SNaveen N. Rao /* PPC_ANDI is _only/always_ dot-form */ 868156d0e29SNaveen N. Rao PPC_ANDI(b2p[TMP_REG_1], dst_reg, imm); 869156d0e29SNaveen N. Rao else { 870156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 871156d0e29SNaveen N. Rao PPC_AND_DOT(b2p[TMP_REG_1], dst_reg, 872156d0e29SNaveen N. Rao b2p[TMP_REG_1]); 873156d0e29SNaveen N. Rao } 874156d0e29SNaveen N. Rao break; 875156d0e29SNaveen N. Rao } 876156d0e29SNaveen N. Rao PPC_BCC(true_cond, addrs[i + 1 + off]); 877156d0e29SNaveen N. Rao break; 878156d0e29SNaveen N. Rao 879156d0e29SNaveen N. Rao /* 880156d0e29SNaveen N. Rao * Loads from packet header/data 881156d0e29SNaveen N. Rao * Assume 32-bit input value in imm and X (src_reg) 882156d0e29SNaveen N. Rao */ 883156d0e29SNaveen N. Rao 884156d0e29SNaveen N. Rao /* Absolute loads */ 885156d0e29SNaveen N. Rao case BPF_LD | BPF_W | BPF_ABS: 886156d0e29SNaveen N. Rao func = (u8 *)CHOOSE_LOAD_FUNC(imm, sk_load_word); 887156d0e29SNaveen N. Rao goto common_load_abs; 888156d0e29SNaveen N. Rao case BPF_LD | BPF_H | BPF_ABS: 889156d0e29SNaveen N. Rao func = (u8 *)CHOOSE_LOAD_FUNC(imm, sk_load_half); 890156d0e29SNaveen N. Rao goto common_load_abs; 891156d0e29SNaveen N. Rao case BPF_LD | BPF_B | BPF_ABS: 892156d0e29SNaveen N. Rao func = (u8 *)CHOOSE_LOAD_FUNC(imm, sk_load_byte); 893156d0e29SNaveen N. Rao common_load_abs: 894156d0e29SNaveen N. Rao /* 895156d0e29SNaveen N. Rao * Load from [imm] 896156d0e29SNaveen N. Rao * Load into r4, which can just be passed onto 897156d0e29SNaveen N. Rao * skb load helpers as the second parameter 898156d0e29SNaveen N. Rao */ 899156d0e29SNaveen N. Rao PPC_LI32(4, imm); 900156d0e29SNaveen N. Rao goto common_load; 901156d0e29SNaveen N. Rao 902156d0e29SNaveen N. Rao /* Indirect loads */ 903156d0e29SNaveen N. Rao case BPF_LD | BPF_W | BPF_IND: 904156d0e29SNaveen N. Rao func = (u8 *)sk_load_word; 905156d0e29SNaveen N. Rao goto common_load_ind; 906156d0e29SNaveen N. Rao case BPF_LD | BPF_H | BPF_IND: 907156d0e29SNaveen N. Rao func = (u8 *)sk_load_half; 908156d0e29SNaveen N. Rao goto common_load_ind; 909156d0e29SNaveen N. Rao case BPF_LD | BPF_B | BPF_IND: 910156d0e29SNaveen N. Rao func = (u8 *)sk_load_byte; 911156d0e29SNaveen N. Rao common_load_ind: 912156d0e29SNaveen N. Rao /* 913156d0e29SNaveen N. Rao * Load from [src_reg + imm] 914156d0e29SNaveen N. Rao * Treat src_reg as a 32-bit value 915156d0e29SNaveen N. Rao */ 916156d0e29SNaveen N. Rao PPC_EXTSW(4, src_reg); 917156d0e29SNaveen N. Rao if (imm) { 918156d0e29SNaveen N. Rao if (imm >= -32768 && imm < 32768) 919156d0e29SNaveen N. Rao PPC_ADDI(4, 4, IMM_L(imm)); 920156d0e29SNaveen N. Rao else { 921156d0e29SNaveen N. Rao PPC_LI32(b2p[TMP_REG_1], imm); 922156d0e29SNaveen N. Rao PPC_ADD(4, 4, b2p[TMP_REG_1]); 923156d0e29SNaveen N. Rao } 924156d0e29SNaveen N. Rao } 925156d0e29SNaveen N. Rao 926156d0e29SNaveen N. Rao common_load: 927156d0e29SNaveen N. Rao ctx->seen |= SEEN_SKB; 928156d0e29SNaveen N. Rao ctx->seen |= SEEN_FUNC; 929156d0e29SNaveen N. Rao bpf_jit_emit_func_call(image, ctx, (u64)func); 930156d0e29SNaveen N. Rao 931156d0e29SNaveen N. Rao /* 932156d0e29SNaveen N. Rao * Helper returns 'lt' condition on error, and an 933156d0e29SNaveen N. Rao * appropriate return value in BPF_REG_0 934156d0e29SNaveen N. Rao */ 935156d0e29SNaveen N. Rao PPC_BCC(COND_LT, exit_addr); 936156d0e29SNaveen N. Rao break; 937156d0e29SNaveen N. Rao 938156d0e29SNaveen N. Rao /* 939ce076141SNaveen N. Rao * Tail call 940156d0e29SNaveen N. Rao */ 941156d0e29SNaveen N. Rao case BPF_JMP | BPF_CALL | BPF_X: 942ce076141SNaveen N. Rao ctx->seen |= SEEN_TAILCALL; 943ce076141SNaveen N. Rao bpf_jit_emit_tail_call(image, ctx, addrs[i + 1]); 944ce076141SNaveen N. Rao break; 945156d0e29SNaveen N. Rao 946156d0e29SNaveen N. Rao default: 947156d0e29SNaveen N. Rao /* 948156d0e29SNaveen N. Rao * The filter contains something cruel & unusual. 949156d0e29SNaveen N. Rao * We don't handle it, but also there shouldn't be 950156d0e29SNaveen N. Rao * anything missing from our list. 951156d0e29SNaveen N. Rao */ 952156d0e29SNaveen N. Rao pr_err_ratelimited("eBPF filter opcode %04x (@%d) unsupported\n", 953156d0e29SNaveen N. Rao code, i); 954156d0e29SNaveen N. Rao return -ENOTSUPP; 955156d0e29SNaveen N. Rao } 956156d0e29SNaveen N. Rao } 957156d0e29SNaveen N. Rao 958156d0e29SNaveen N. Rao /* Set end-of-body-code address for exit. */ 959156d0e29SNaveen N. Rao addrs[i] = ctx->idx * 4; 960156d0e29SNaveen N. Rao 961156d0e29SNaveen N. Rao return 0; 962156d0e29SNaveen N. Rao } 963156d0e29SNaveen N. Rao 964156d0e29SNaveen N. Rao void bpf_jit_compile(struct bpf_prog *fp) { } 965156d0e29SNaveen N. Rao 966156d0e29SNaveen N. Rao struct bpf_prog *bpf_int_jit_compile(struct bpf_prog *fp) 967156d0e29SNaveen N. Rao { 968156d0e29SNaveen N. Rao u32 proglen; 969156d0e29SNaveen N. Rao u32 alloclen; 970156d0e29SNaveen N. Rao u8 *image = NULL; 971156d0e29SNaveen N. Rao u32 *code_base; 972156d0e29SNaveen N. Rao u32 *addrs; 973156d0e29SNaveen N. Rao struct codegen_context cgctx; 974156d0e29SNaveen N. Rao int pass; 975156d0e29SNaveen N. Rao int flen; 976156d0e29SNaveen N. Rao struct bpf_binary_header *bpf_hdr; 977*b7b7013cSNaveen N. Rao struct bpf_prog *org_fp = fp; 978*b7b7013cSNaveen N. Rao struct bpf_prog *tmp_fp; 979*b7b7013cSNaveen N. Rao bool bpf_blinded = false; 980156d0e29SNaveen N. Rao 981156d0e29SNaveen N. Rao if (!bpf_jit_enable) 982*b7b7013cSNaveen N. Rao return org_fp; 983*b7b7013cSNaveen N. Rao 984*b7b7013cSNaveen N. Rao tmp_fp = bpf_jit_blind_constants(org_fp); 985*b7b7013cSNaveen N. Rao if (IS_ERR(tmp_fp)) 986*b7b7013cSNaveen N. Rao return org_fp; 987*b7b7013cSNaveen N. Rao 988*b7b7013cSNaveen N. Rao if (tmp_fp != org_fp) { 989*b7b7013cSNaveen N. Rao bpf_blinded = true; 990*b7b7013cSNaveen N. Rao fp = tmp_fp; 991*b7b7013cSNaveen N. Rao } 992156d0e29SNaveen N. Rao 993156d0e29SNaveen N. Rao flen = fp->len; 994156d0e29SNaveen N. Rao addrs = kzalloc((flen+1) * sizeof(*addrs), GFP_KERNEL); 995*b7b7013cSNaveen N. Rao if (addrs == NULL) { 996*b7b7013cSNaveen N. Rao fp = org_fp; 997156d0e29SNaveen N. Rao goto out; 998*b7b7013cSNaveen N. Rao } 999*b7b7013cSNaveen N. Rao 1000*b7b7013cSNaveen N. Rao memset(&cgctx, 0, sizeof(struct codegen_context)); 1001*b7b7013cSNaveen N. Rao 1002*b7b7013cSNaveen N. Rao /* Scouting faux-generate pass 0 */ 1003*b7b7013cSNaveen N. Rao if (bpf_jit_build_body(fp, 0, &cgctx, addrs)) { 1004*b7b7013cSNaveen N. Rao /* We hit something illegal or unsupported. */ 1005*b7b7013cSNaveen N. Rao fp = org_fp; 1006*b7b7013cSNaveen N. Rao goto out; 1007*b7b7013cSNaveen N. Rao } 1008156d0e29SNaveen N. Rao 1009156d0e29SNaveen N. Rao /* 1010156d0e29SNaveen N. Rao * Pretend to build prologue, given the features we've seen. This will 1011156d0e29SNaveen N. Rao * update ctgtx.idx as it pretends to output instructions, then we can 1012156d0e29SNaveen N. Rao * calculate total size from idx. 1013156d0e29SNaveen N. Rao */ 1014156d0e29SNaveen N. Rao bpf_jit_build_prologue(0, &cgctx); 1015156d0e29SNaveen N. Rao bpf_jit_build_epilogue(0, &cgctx); 1016156d0e29SNaveen N. Rao 1017156d0e29SNaveen N. Rao proglen = cgctx.idx * 4; 1018156d0e29SNaveen N. Rao alloclen = proglen + FUNCTION_DESCR_SIZE; 1019156d0e29SNaveen N. Rao 1020156d0e29SNaveen N. Rao bpf_hdr = bpf_jit_binary_alloc(alloclen, &image, 4, 1021156d0e29SNaveen N. Rao bpf_jit_fill_ill_insns); 1022*b7b7013cSNaveen N. Rao if (!bpf_hdr) { 1023*b7b7013cSNaveen N. Rao fp = org_fp; 1024156d0e29SNaveen N. Rao goto out; 1025*b7b7013cSNaveen N. Rao } 1026156d0e29SNaveen N. Rao 1027156d0e29SNaveen N. Rao code_base = (u32 *)(image + FUNCTION_DESCR_SIZE); 1028156d0e29SNaveen N. Rao 1029156d0e29SNaveen N. Rao /* Code generation passes 1-2 */ 1030156d0e29SNaveen N. Rao for (pass = 1; pass < 3; pass++) { 1031156d0e29SNaveen N. Rao /* Now build the prologue, body code & epilogue for real. */ 1032156d0e29SNaveen N. Rao cgctx.idx = 0; 1033156d0e29SNaveen N. Rao bpf_jit_build_prologue(code_base, &cgctx); 1034156d0e29SNaveen N. Rao bpf_jit_build_body(fp, code_base, &cgctx, addrs); 1035156d0e29SNaveen N. Rao bpf_jit_build_epilogue(code_base, &cgctx); 1036156d0e29SNaveen N. Rao 1037156d0e29SNaveen N. Rao if (bpf_jit_enable > 1) 1038156d0e29SNaveen N. Rao pr_info("Pass %d: shrink = %d, seen = 0x%x\n", pass, 1039156d0e29SNaveen N. Rao proglen - (cgctx.idx * 4), cgctx.seen); 1040156d0e29SNaveen N. Rao } 1041156d0e29SNaveen N. Rao 1042156d0e29SNaveen N. Rao if (bpf_jit_enable > 1) 1043156d0e29SNaveen N. Rao /* 1044156d0e29SNaveen N. Rao * Note that we output the base address of the code_base 1045156d0e29SNaveen N. Rao * rather than image, since opcodes are in code_base. 1046156d0e29SNaveen N. Rao */ 1047156d0e29SNaveen N. Rao bpf_jit_dump(flen, proglen, pass, code_base); 1048156d0e29SNaveen N. Rao 1049156d0e29SNaveen N. Rao if (image) { 1050156d0e29SNaveen N. Rao bpf_flush_icache(bpf_hdr, image + alloclen); 1051156d0e29SNaveen N. Rao #ifdef PPC64_ELF_ABI_v1 1052156d0e29SNaveen N. Rao /* Function descriptor nastiness: Address + TOC */ 1053156d0e29SNaveen N. Rao ((u64 *)image)[0] = (u64)code_base; 1054156d0e29SNaveen N. Rao ((u64 *)image)[1] = local_paca->kernel_toc; 1055156d0e29SNaveen N. Rao #endif 1056156d0e29SNaveen N. Rao fp->bpf_func = (void *)image; 1057156d0e29SNaveen N. Rao fp->jited = 1; 1058156d0e29SNaveen N. Rao } 1059156d0e29SNaveen N. Rao 1060156d0e29SNaveen N. Rao out: 1061156d0e29SNaveen N. Rao kfree(addrs); 1062*b7b7013cSNaveen N. Rao 1063*b7b7013cSNaveen N. Rao if (bpf_blinded) 1064*b7b7013cSNaveen N. Rao bpf_jit_prog_release_other(fp, fp == org_fp ? tmp_fp : org_fp); 1065*b7b7013cSNaveen N. Rao 1066156d0e29SNaveen N. Rao return fp; 1067156d0e29SNaveen N. Rao } 1068156d0e29SNaveen N. Rao 1069156d0e29SNaveen N. Rao void bpf_jit_free(struct bpf_prog *fp) 1070156d0e29SNaveen N. Rao { 1071156d0e29SNaveen N. Rao unsigned long addr = (unsigned long)fp->bpf_func & PAGE_MASK; 1072156d0e29SNaveen N. Rao struct bpf_binary_header *bpf_hdr = (void *)addr; 1073156d0e29SNaveen N. Rao 1074156d0e29SNaveen N. Rao if (fp->jited) 1075156d0e29SNaveen N. Rao bpf_jit_binary_free(bpf_hdr); 1076156d0e29SNaveen N. Rao 1077156d0e29SNaveen N. Rao bpf_prog_unlock_free(fp); 1078156d0e29SNaveen N. Rao } 1079