1*ddecdfceSMircea Gherzan /* 2*ddecdfceSMircea Gherzan * Just-In-Time compiler for BPF filters on 32bit ARM 3*ddecdfceSMircea Gherzan * 4*ddecdfceSMircea Gherzan * Copyright (c) 2011 Mircea Gherzan <mgherzan@gmail.com> 5*ddecdfceSMircea Gherzan * 6*ddecdfceSMircea Gherzan * This program is free software; you can redistribute it and/or modify it 7*ddecdfceSMircea Gherzan * under the terms of the GNU General Public License as published by the 8*ddecdfceSMircea Gherzan * Free Software Foundation; version 2 of the License. 9*ddecdfceSMircea Gherzan */ 10*ddecdfceSMircea Gherzan 11*ddecdfceSMircea Gherzan #include <linux/bitops.h> 12*ddecdfceSMircea Gherzan #include <linux/compiler.h> 13*ddecdfceSMircea Gherzan #include <linux/errno.h> 14*ddecdfceSMircea Gherzan #include <linux/filter.h> 15*ddecdfceSMircea Gherzan #include <linux/moduleloader.h> 16*ddecdfceSMircea Gherzan #include <linux/netdevice.h> 17*ddecdfceSMircea Gherzan #include <linux/string.h> 18*ddecdfceSMircea Gherzan #include <linux/slab.h> 19*ddecdfceSMircea Gherzan #include <asm/cacheflush.h> 20*ddecdfceSMircea Gherzan #include <asm/hwcap.h> 21*ddecdfceSMircea Gherzan 22*ddecdfceSMircea Gherzan #include "bpf_jit_32.h" 23*ddecdfceSMircea Gherzan 24*ddecdfceSMircea Gherzan /* 25*ddecdfceSMircea Gherzan * ABI: 26*ddecdfceSMircea Gherzan * 27*ddecdfceSMircea Gherzan * r0 scratch register 28*ddecdfceSMircea Gherzan * r4 BPF register A 29*ddecdfceSMircea Gherzan * r5 BPF register X 30*ddecdfceSMircea Gherzan * r6 pointer to the skb 31*ddecdfceSMircea Gherzan * r7 skb->data 32*ddecdfceSMircea Gherzan * r8 skb_headlen(skb) 33*ddecdfceSMircea Gherzan */ 34*ddecdfceSMircea Gherzan 35*ddecdfceSMircea Gherzan #define r_scratch ARM_R0 36*ddecdfceSMircea Gherzan /* r1-r3 are (also) used for the unaligned loads on the non-ARMv7 slowpath */ 37*ddecdfceSMircea Gherzan #define r_off ARM_R1 38*ddecdfceSMircea Gherzan #define r_A ARM_R4 39*ddecdfceSMircea Gherzan #define r_X ARM_R5 40*ddecdfceSMircea Gherzan #define r_skb ARM_R6 41*ddecdfceSMircea Gherzan #define r_skb_data ARM_R7 42*ddecdfceSMircea Gherzan #define r_skb_hl ARM_R8 43*ddecdfceSMircea Gherzan 44*ddecdfceSMircea Gherzan #define SCRATCH_SP_OFFSET 0 45*ddecdfceSMircea Gherzan #define SCRATCH_OFF(k) (SCRATCH_SP_OFFSET + (k)) 46*ddecdfceSMircea Gherzan 47*ddecdfceSMircea Gherzan #define SEEN_MEM ((1 << BPF_MEMWORDS) - 1) 48*ddecdfceSMircea Gherzan #define SEEN_MEM_WORD(k) (1 << (k)) 49*ddecdfceSMircea Gherzan #define SEEN_X (1 << BPF_MEMWORDS) 50*ddecdfceSMircea Gherzan #define SEEN_CALL (1 << (BPF_MEMWORDS + 1)) 51*ddecdfceSMircea Gherzan #define SEEN_SKB (1 << (BPF_MEMWORDS + 2)) 52*ddecdfceSMircea Gherzan #define SEEN_DATA (1 << (BPF_MEMWORDS + 3)) 53*ddecdfceSMircea Gherzan 54*ddecdfceSMircea Gherzan #define FLAG_NEED_X_RESET (1 << 0) 55*ddecdfceSMircea Gherzan 56*ddecdfceSMircea Gherzan struct jit_ctx { 57*ddecdfceSMircea Gherzan const struct sk_filter *skf; 58*ddecdfceSMircea Gherzan unsigned idx; 59*ddecdfceSMircea Gherzan unsigned prologue_bytes; 60*ddecdfceSMircea Gherzan int ret0_fp_idx; 61*ddecdfceSMircea Gherzan u32 seen; 62*ddecdfceSMircea Gherzan u32 flags; 63*ddecdfceSMircea Gherzan u32 *offsets; 64*ddecdfceSMircea Gherzan u32 *target; 65*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 7 66*ddecdfceSMircea Gherzan u16 epilogue_bytes; 67*ddecdfceSMircea Gherzan u16 imm_count; 68*ddecdfceSMircea Gherzan u32 *imms; 69*ddecdfceSMircea Gherzan #endif 70*ddecdfceSMircea Gherzan }; 71*ddecdfceSMircea Gherzan 72*ddecdfceSMircea Gherzan int bpf_jit_enable __read_mostly; 73*ddecdfceSMircea Gherzan 74*ddecdfceSMircea Gherzan static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset) 75*ddecdfceSMircea Gherzan { 76*ddecdfceSMircea Gherzan u8 ret; 77*ddecdfceSMircea Gherzan int err; 78*ddecdfceSMircea Gherzan 79*ddecdfceSMircea Gherzan err = skb_copy_bits(skb, offset, &ret, 1); 80*ddecdfceSMircea Gherzan 81*ddecdfceSMircea Gherzan return (u64)err << 32 | ret; 82*ddecdfceSMircea Gherzan } 83*ddecdfceSMircea Gherzan 84*ddecdfceSMircea Gherzan static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset) 85*ddecdfceSMircea Gherzan { 86*ddecdfceSMircea Gherzan u16 ret; 87*ddecdfceSMircea Gherzan int err; 88*ddecdfceSMircea Gherzan 89*ddecdfceSMircea Gherzan err = skb_copy_bits(skb, offset, &ret, 2); 90*ddecdfceSMircea Gherzan 91*ddecdfceSMircea Gherzan return (u64)err << 32 | ntohs(ret); 92*ddecdfceSMircea Gherzan } 93*ddecdfceSMircea Gherzan 94*ddecdfceSMircea Gherzan static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset) 95*ddecdfceSMircea Gherzan { 96*ddecdfceSMircea Gherzan u32 ret; 97*ddecdfceSMircea Gherzan int err; 98*ddecdfceSMircea Gherzan 99*ddecdfceSMircea Gherzan err = skb_copy_bits(skb, offset, &ret, 4); 100*ddecdfceSMircea Gherzan 101*ddecdfceSMircea Gherzan return (u64)err << 32 | ntohl(ret); 102*ddecdfceSMircea Gherzan } 103*ddecdfceSMircea Gherzan 104*ddecdfceSMircea Gherzan /* 105*ddecdfceSMircea Gherzan * Wrapper that handles both OABI and EABI and assures Thumb2 interworking 106*ddecdfceSMircea Gherzan * (where the assembly routines like __aeabi_uidiv could cause problems). 107*ddecdfceSMircea Gherzan */ 108*ddecdfceSMircea Gherzan static u32 jit_udiv(u32 dividend, u32 divisor) 109*ddecdfceSMircea Gherzan { 110*ddecdfceSMircea Gherzan return dividend / divisor; 111*ddecdfceSMircea Gherzan } 112*ddecdfceSMircea Gherzan 113*ddecdfceSMircea Gherzan static inline void _emit(int cond, u32 inst, struct jit_ctx *ctx) 114*ddecdfceSMircea Gherzan { 115*ddecdfceSMircea Gherzan if (ctx->target != NULL) 116*ddecdfceSMircea Gherzan ctx->target[ctx->idx] = inst | (cond << 28); 117*ddecdfceSMircea Gherzan 118*ddecdfceSMircea Gherzan ctx->idx++; 119*ddecdfceSMircea Gherzan } 120*ddecdfceSMircea Gherzan 121*ddecdfceSMircea Gherzan /* 122*ddecdfceSMircea Gherzan * Emit an instruction that will be executed unconditionally. 123*ddecdfceSMircea Gherzan */ 124*ddecdfceSMircea Gherzan static inline void emit(u32 inst, struct jit_ctx *ctx) 125*ddecdfceSMircea Gherzan { 126*ddecdfceSMircea Gherzan _emit(ARM_COND_AL, inst, ctx); 127*ddecdfceSMircea Gherzan } 128*ddecdfceSMircea Gherzan 129*ddecdfceSMircea Gherzan static u16 saved_regs(struct jit_ctx *ctx) 130*ddecdfceSMircea Gherzan { 131*ddecdfceSMircea Gherzan u16 ret = 0; 132*ddecdfceSMircea Gherzan 133*ddecdfceSMircea Gherzan if ((ctx->skf->len > 1) || 134*ddecdfceSMircea Gherzan (ctx->skf->insns[0].code == BPF_S_RET_A)) 135*ddecdfceSMircea Gherzan ret |= 1 << r_A; 136*ddecdfceSMircea Gherzan 137*ddecdfceSMircea Gherzan #ifdef CONFIG_FRAME_POINTER 138*ddecdfceSMircea Gherzan ret |= (1 << ARM_FP) | (1 << ARM_IP) | (1 << ARM_LR) | (1 << ARM_PC); 139*ddecdfceSMircea Gherzan #else 140*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_CALL) 141*ddecdfceSMircea Gherzan ret |= 1 << ARM_LR; 142*ddecdfceSMircea Gherzan #endif 143*ddecdfceSMircea Gherzan if (ctx->seen & (SEEN_DATA | SEEN_SKB)) 144*ddecdfceSMircea Gherzan ret |= 1 << r_skb; 145*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_DATA) 146*ddecdfceSMircea Gherzan ret |= (1 << r_skb_data) | (1 << r_skb_hl); 147*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_X) 148*ddecdfceSMircea Gherzan ret |= 1 << r_X; 149*ddecdfceSMircea Gherzan 150*ddecdfceSMircea Gherzan return ret; 151*ddecdfceSMircea Gherzan } 152*ddecdfceSMircea Gherzan 153*ddecdfceSMircea Gherzan static inline int mem_words_used(struct jit_ctx *ctx) 154*ddecdfceSMircea Gherzan { 155*ddecdfceSMircea Gherzan /* yes, we do waste some stack space IF there are "holes" in the set" */ 156*ddecdfceSMircea Gherzan return fls(ctx->seen & SEEN_MEM); 157*ddecdfceSMircea Gherzan } 158*ddecdfceSMircea Gherzan 159*ddecdfceSMircea Gherzan static inline bool is_load_to_a(u16 inst) 160*ddecdfceSMircea Gherzan { 161*ddecdfceSMircea Gherzan switch (inst) { 162*ddecdfceSMircea Gherzan case BPF_S_LD_W_LEN: 163*ddecdfceSMircea Gherzan case BPF_S_LD_W_ABS: 164*ddecdfceSMircea Gherzan case BPF_S_LD_H_ABS: 165*ddecdfceSMircea Gherzan case BPF_S_LD_B_ABS: 166*ddecdfceSMircea Gherzan case BPF_S_ANC_CPU: 167*ddecdfceSMircea Gherzan case BPF_S_ANC_IFINDEX: 168*ddecdfceSMircea Gherzan case BPF_S_ANC_MARK: 169*ddecdfceSMircea Gherzan case BPF_S_ANC_PROTOCOL: 170*ddecdfceSMircea Gherzan case BPF_S_ANC_RXHASH: 171*ddecdfceSMircea Gherzan case BPF_S_ANC_QUEUE: 172*ddecdfceSMircea Gherzan return true; 173*ddecdfceSMircea Gherzan default: 174*ddecdfceSMircea Gherzan return false; 175*ddecdfceSMircea Gherzan } 176*ddecdfceSMircea Gherzan } 177*ddecdfceSMircea Gherzan 178*ddecdfceSMircea Gherzan static void build_prologue(struct jit_ctx *ctx) 179*ddecdfceSMircea Gherzan { 180*ddecdfceSMircea Gherzan u16 reg_set = saved_regs(ctx); 181*ddecdfceSMircea Gherzan u16 first_inst = ctx->skf->insns[0].code; 182*ddecdfceSMircea Gherzan u16 off; 183*ddecdfceSMircea Gherzan 184*ddecdfceSMircea Gherzan #ifdef CONFIG_FRAME_POINTER 185*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_IP, ARM_SP), ctx); 186*ddecdfceSMircea Gherzan emit(ARM_PUSH(reg_set), ctx); 187*ddecdfceSMircea Gherzan emit(ARM_SUB_I(ARM_FP, ARM_IP, 4), ctx); 188*ddecdfceSMircea Gherzan #else 189*ddecdfceSMircea Gherzan if (reg_set) 190*ddecdfceSMircea Gherzan emit(ARM_PUSH(reg_set), ctx); 191*ddecdfceSMircea Gherzan #endif 192*ddecdfceSMircea Gherzan 193*ddecdfceSMircea Gherzan if (ctx->seen & (SEEN_DATA | SEEN_SKB)) 194*ddecdfceSMircea Gherzan emit(ARM_MOV_R(r_skb, ARM_R0), ctx); 195*ddecdfceSMircea Gherzan 196*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_DATA) { 197*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, data); 198*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_skb_data, r_skb, off), ctx); 199*ddecdfceSMircea Gherzan /* headlen = len - data_len */ 200*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, len); 201*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_skb_hl, r_skb, off), ctx); 202*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, data_len); 203*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_scratch, r_skb, off), ctx); 204*ddecdfceSMircea Gherzan emit(ARM_SUB_R(r_skb_hl, r_skb_hl, r_scratch), ctx); 205*ddecdfceSMircea Gherzan } 206*ddecdfceSMircea Gherzan 207*ddecdfceSMircea Gherzan if (ctx->flags & FLAG_NEED_X_RESET) 208*ddecdfceSMircea Gherzan emit(ARM_MOV_I(r_X, 0), ctx); 209*ddecdfceSMircea Gherzan 210*ddecdfceSMircea Gherzan /* do not leak kernel data to userspace */ 211*ddecdfceSMircea Gherzan if ((first_inst != BPF_S_RET_K) && !(is_load_to_a(first_inst))) 212*ddecdfceSMircea Gherzan emit(ARM_MOV_I(r_A, 0), ctx); 213*ddecdfceSMircea Gherzan 214*ddecdfceSMircea Gherzan /* stack space for the BPF_MEM words */ 215*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_MEM) 216*ddecdfceSMircea Gherzan emit(ARM_SUB_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx); 217*ddecdfceSMircea Gherzan } 218*ddecdfceSMircea Gherzan 219*ddecdfceSMircea Gherzan static void build_epilogue(struct jit_ctx *ctx) 220*ddecdfceSMircea Gherzan { 221*ddecdfceSMircea Gherzan u16 reg_set = saved_regs(ctx); 222*ddecdfceSMircea Gherzan 223*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_MEM) 224*ddecdfceSMircea Gherzan emit(ARM_ADD_I(ARM_SP, ARM_SP, mem_words_used(ctx) * 4), ctx); 225*ddecdfceSMircea Gherzan 226*ddecdfceSMircea Gherzan reg_set &= ~(1 << ARM_LR); 227*ddecdfceSMircea Gherzan 228*ddecdfceSMircea Gherzan #ifdef CONFIG_FRAME_POINTER 229*ddecdfceSMircea Gherzan /* the first instruction of the prologue was: mov ip, sp */ 230*ddecdfceSMircea Gherzan reg_set &= ~(1 << ARM_IP); 231*ddecdfceSMircea Gherzan reg_set |= (1 << ARM_SP); 232*ddecdfceSMircea Gherzan emit(ARM_LDM(ARM_SP, reg_set), ctx); 233*ddecdfceSMircea Gherzan #else 234*ddecdfceSMircea Gherzan if (reg_set) { 235*ddecdfceSMircea Gherzan if (ctx->seen & SEEN_CALL) 236*ddecdfceSMircea Gherzan reg_set |= 1 << ARM_PC; 237*ddecdfceSMircea Gherzan emit(ARM_POP(reg_set), ctx); 238*ddecdfceSMircea Gherzan } 239*ddecdfceSMircea Gherzan 240*ddecdfceSMircea Gherzan if (!(ctx->seen & SEEN_CALL)) 241*ddecdfceSMircea Gherzan emit(ARM_BX(ARM_LR), ctx); 242*ddecdfceSMircea Gherzan #endif 243*ddecdfceSMircea Gherzan } 244*ddecdfceSMircea Gherzan 245*ddecdfceSMircea Gherzan static int16_t imm8m(u32 x) 246*ddecdfceSMircea Gherzan { 247*ddecdfceSMircea Gherzan u32 rot; 248*ddecdfceSMircea Gherzan 249*ddecdfceSMircea Gherzan for (rot = 0; rot < 16; rot++) 250*ddecdfceSMircea Gherzan if ((x & ~ror32(0xff, 2 * rot)) == 0) 251*ddecdfceSMircea Gherzan return rol32(x, 2 * rot) | (rot << 8); 252*ddecdfceSMircea Gherzan 253*ddecdfceSMircea Gherzan return -1; 254*ddecdfceSMircea Gherzan } 255*ddecdfceSMircea Gherzan 256*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 7 257*ddecdfceSMircea Gherzan 258*ddecdfceSMircea Gherzan static u16 imm_offset(u32 k, struct jit_ctx *ctx) 259*ddecdfceSMircea Gherzan { 260*ddecdfceSMircea Gherzan unsigned i = 0, offset; 261*ddecdfceSMircea Gherzan u16 imm; 262*ddecdfceSMircea Gherzan 263*ddecdfceSMircea Gherzan /* on the "fake" run we just count them (duplicates included) */ 264*ddecdfceSMircea Gherzan if (ctx->target == NULL) { 265*ddecdfceSMircea Gherzan ctx->imm_count++; 266*ddecdfceSMircea Gherzan return 0; 267*ddecdfceSMircea Gherzan } 268*ddecdfceSMircea Gherzan 269*ddecdfceSMircea Gherzan while ((i < ctx->imm_count) && ctx->imms[i]) { 270*ddecdfceSMircea Gherzan if (ctx->imms[i] == k) 271*ddecdfceSMircea Gherzan break; 272*ddecdfceSMircea Gherzan i++; 273*ddecdfceSMircea Gherzan } 274*ddecdfceSMircea Gherzan 275*ddecdfceSMircea Gherzan if (ctx->imms[i] == 0) 276*ddecdfceSMircea Gherzan ctx->imms[i] = k; 277*ddecdfceSMircea Gherzan 278*ddecdfceSMircea Gherzan /* constants go just after the epilogue */ 279*ddecdfceSMircea Gherzan offset = ctx->offsets[ctx->skf->len]; 280*ddecdfceSMircea Gherzan offset += ctx->prologue_bytes; 281*ddecdfceSMircea Gherzan offset += ctx->epilogue_bytes; 282*ddecdfceSMircea Gherzan offset += i * 4; 283*ddecdfceSMircea Gherzan 284*ddecdfceSMircea Gherzan ctx->target[offset / 4] = k; 285*ddecdfceSMircea Gherzan 286*ddecdfceSMircea Gherzan /* PC in ARM mode == address of the instruction + 8 */ 287*ddecdfceSMircea Gherzan imm = offset - (8 + ctx->idx * 4); 288*ddecdfceSMircea Gherzan 289*ddecdfceSMircea Gherzan return imm; 290*ddecdfceSMircea Gherzan } 291*ddecdfceSMircea Gherzan 292*ddecdfceSMircea Gherzan #endif /* __LINUX_ARM_ARCH__ */ 293*ddecdfceSMircea Gherzan 294*ddecdfceSMircea Gherzan /* 295*ddecdfceSMircea Gherzan * Move an immediate that's not an imm8m to a core register. 296*ddecdfceSMircea Gherzan */ 297*ddecdfceSMircea Gherzan static inline void emit_mov_i_no8m(int rd, u32 val, struct jit_ctx *ctx) 298*ddecdfceSMircea Gherzan { 299*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 7 300*ddecdfceSMircea Gherzan emit(ARM_LDR_I(rd, ARM_PC, imm_offset(val, ctx)), ctx); 301*ddecdfceSMircea Gherzan #else 302*ddecdfceSMircea Gherzan emit(ARM_MOVW(rd, val & 0xffff), ctx); 303*ddecdfceSMircea Gherzan if (val > 0xffff) 304*ddecdfceSMircea Gherzan emit(ARM_MOVT(rd, val >> 16), ctx); 305*ddecdfceSMircea Gherzan #endif 306*ddecdfceSMircea Gherzan } 307*ddecdfceSMircea Gherzan 308*ddecdfceSMircea Gherzan static inline void emit_mov_i(int rd, u32 val, struct jit_ctx *ctx) 309*ddecdfceSMircea Gherzan { 310*ddecdfceSMircea Gherzan int imm12 = imm8m(val); 311*ddecdfceSMircea Gherzan 312*ddecdfceSMircea Gherzan if (imm12 >= 0) 313*ddecdfceSMircea Gherzan emit(ARM_MOV_I(rd, imm12), ctx); 314*ddecdfceSMircea Gherzan else 315*ddecdfceSMircea Gherzan emit_mov_i_no8m(rd, val, ctx); 316*ddecdfceSMircea Gherzan } 317*ddecdfceSMircea Gherzan 318*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 6 319*ddecdfceSMircea Gherzan 320*ddecdfceSMircea Gherzan static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx) 321*ddecdfceSMircea Gherzan { 322*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R3, r_addr, 1), ctx); 323*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx); 324*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 3), ctx); 325*ddecdfceSMircea Gherzan _emit(cond, ARM_LSL_I(ARM_R3, ARM_R3, 16), ctx); 326*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R0, r_addr, 2), ctx); 327*ddecdfceSMircea Gherzan _emit(cond, ARM_ORR_S(ARM_R3, ARM_R3, ARM_R1, SRTYPE_LSL, 24), ctx); 328*ddecdfceSMircea Gherzan _emit(cond, ARM_ORR_R(ARM_R3, ARM_R3, ARM_R2), ctx); 329*ddecdfceSMircea Gherzan _emit(cond, ARM_ORR_S(r_res, ARM_R3, ARM_R0, SRTYPE_LSL, 8), ctx); 330*ddecdfceSMircea Gherzan } 331*ddecdfceSMircea Gherzan 332*ddecdfceSMircea Gherzan static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx) 333*ddecdfceSMircea Gherzan { 334*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R1, r_addr, 0), ctx); 335*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRB_I(ARM_R2, r_addr, 1), ctx); 336*ddecdfceSMircea Gherzan _emit(cond, ARM_ORR_S(r_res, ARM_R2, ARM_R1, SRTYPE_LSL, 8), ctx); 337*ddecdfceSMircea Gherzan } 338*ddecdfceSMircea Gherzan 339*ddecdfceSMircea Gherzan static inline void emit_swap16(u8 r_dst, u8 r_src, struct jit_ctx *ctx) 340*ddecdfceSMircea Gherzan { 341*ddecdfceSMircea Gherzan emit(ARM_LSL_R(ARM_R1, r_src, 8), ctx); 342*ddecdfceSMircea Gherzan emit(ARM_ORR_S(r_dst, ARM_R1, r_src, SRTYPE_LSL, 8), ctx); 343*ddecdfceSMircea Gherzan emit(ARM_LSL_I(r_dst, r_dst, 8), ctx); 344*ddecdfceSMircea Gherzan emit(ARM_LSL_R(r_dst, r_dst, 8), ctx); 345*ddecdfceSMircea Gherzan } 346*ddecdfceSMircea Gherzan 347*ddecdfceSMircea Gherzan #else /* ARMv6+ */ 348*ddecdfceSMircea Gherzan 349*ddecdfceSMircea Gherzan static void emit_load_be32(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx) 350*ddecdfceSMircea Gherzan { 351*ddecdfceSMircea Gherzan _emit(cond, ARM_LDR_I(r_res, r_addr, 0), ctx); 352*ddecdfceSMircea Gherzan #ifdef __LITTLE_ENDIAN 353*ddecdfceSMircea Gherzan _emit(cond, ARM_REV(r_res, r_res), ctx); 354*ddecdfceSMircea Gherzan #endif 355*ddecdfceSMircea Gherzan } 356*ddecdfceSMircea Gherzan 357*ddecdfceSMircea Gherzan static void emit_load_be16(u8 cond, u8 r_res, u8 r_addr, struct jit_ctx *ctx) 358*ddecdfceSMircea Gherzan { 359*ddecdfceSMircea Gherzan _emit(cond, ARM_LDRH_I(r_res, r_addr, 0), ctx); 360*ddecdfceSMircea Gherzan #ifdef __LITTLE_ENDIAN 361*ddecdfceSMircea Gherzan _emit(cond, ARM_REV16(r_res, r_res), ctx); 362*ddecdfceSMircea Gherzan #endif 363*ddecdfceSMircea Gherzan } 364*ddecdfceSMircea Gherzan 365*ddecdfceSMircea Gherzan static inline void emit_swap16(u8 r_dst __maybe_unused, 366*ddecdfceSMircea Gherzan u8 r_src __maybe_unused, 367*ddecdfceSMircea Gherzan struct jit_ctx *ctx __maybe_unused) 368*ddecdfceSMircea Gherzan { 369*ddecdfceSMircea Gherzan #ifdef __LITTLE_ENDIAN 370*ddecdfceSMircea Gherzan emit(ARM_REV16(r_dst, r_src), ctx); 371*ddecdfceSMircea Gherzan #endif 372*ddecdfceSMircea Gherzan } 373*ddecdfceSMircea Gherzan 374*ddecdfceSMircea Gherzan #endif /* __LINUX_ARM_ARCH__ < 6 */ 375*ddecdfceSMircea Gherzan 376*ddecdfceSMircea Gherzan 377*ddecdfceSMircea Gherzan /* Compute the immediate value for a PC-relative branch. */ 378*ddecdfceSMircea Gherzan static inline u32 b_imm(unsigned tgt, struct jit_ctx *ctx) 379*ddecdfceSMircea Gherzan { 380*ddecdfceSMircea Gherzan u32 imm; 381*ddecdfceSMircea Gherzan 382*ddecdfceSMircea Gherzan if (ctx->target == NULL) 383*ddecdfceSMircea Gherzan return 0; 384*ddecdfceSMircea Gherzan /* 385*ddecdfceSMircea Gherzan * BPF allows only forward jumps and the offset of the target is 386*ddecdfceSMircea Gherzan * still the one computed during the first pass. 387*ddecdfceSMircea Gherzan */ 388*ddecdfceSMircea Gherzan imm = ctx->offsets[tgt] + ctx->prologue_bytes - (ctx->idx * 4 + 8); 389*ddecdfceSMircea Gherzan 390*ddecdfceSMircea Gherzan return imm >> 2; 391*ddecdfceSMircea Gherzan } 392*ddecdfceSMircea Gherzan 393*ddecdfceSMircea Gherzan #define OP_IMM3(op, r1, r2, imm_val, ctx) \ 394*ddecdfceSMircea Gherzan do { \ 395*ddecdfceSMircea Gherzan imm12 = imm8m(imm_val); \ 396*ddecdfceSMircea Gherzan if (imm12 < 0) { \ 397*ddecdfceSMircea Gherzan emit_mov_i_no8m(r_scratch, imm_val, ctx); \ 398*ddecdfceSMircea Gherzan emit(op ## _R((r1), (r2), r_scratch), ctx); \ 399*ddecdfceSMircea Gherzan } else { \ 400*ddecdfceSMircea Gherzan emit(op ## _I((r1), (r2), imm12), ctx); \ 401*ddecdfceSMircea Gherzan } \ 402*ddecdfceSMircea Gherzan } while (0) 403*ddecdfceSMircea Gherzan 404*ddecdfceSMircea Gherzan static inline void emit_err_ret(u8 cond, struct jit_ctx *ctx) 405*ddecdfceSMircea Gherzan { 406*ddecdfceSMircea Gherzan if (ctx->ret0_fp_idx >= 0) { 407*ddecdfceSMircea Gherzan _emit(cond, ARM_B(b_imm(ctx->ret0_fp_idx, ctx)), ctx); 408*ddecdfceSMircea Gherzan /* NOP to keep the size constant between passes */ 409*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R0, ARM_R0), ctx); 410*ddecdfceSMircea Gherzan } else { 411*ddecdfceSMircea Gherzan _emit(cond, ARM_MOV_I(ARM_R0, 0), ctx); 412*ddecdfceSMircea Gherzan _emit(cond, ARM_B(b_imm(ctx->skf->len, ctx)), ctx); 413*ddecdfceSMircea Gherzan } 414*ddecdfceSMircea Gherzan } 415*ddecdfceSMircea Gherzan 416*ddecdfceSMircea Gherzan static inline void emit_blx_r(u8 tgt_reg, struct jit_ctx *ctx) 417*ddecdfceSMircea Gherzan { 418*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 5 419*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_LR, ARM_PC), ctx); 420*ddecdfceSMircea Gherzan 421*ddecdfceSMircea Gherzan if (elf_hwcap & HWCAP_THUMB) 422*ddecdfceSMircea Gherzan emit(ARM_BX(tgt_reg), ctx); 423*ddecdfceSMircea Gherzan else 424*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_PC, tgt_reg), ctx); 425*ddecdfceSMircea Gherzan #else 426*ddecdfceSMircea Gherzan emit(ARM_BLX_R(tgt_reg), ctx); 427*ddecdfceSMircea Gherzan #endif 428*ddecdfceSMircea Gherzan } 429*ddecdfceSMircea Gherzan 430*ddecdfceSMircea Gherzan static inline void emit_udiv(u8 rd, u8 rm, u8 rn, struct jit_ctx *ctx) 431*ddecdfceSMircea Gherzan { 432*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ == 7 433*ddecdfceSMircea Gherzan if (elf_hwcap & HWCAP_IDIVA) { 434*ddecdfceSMircea Gherzan emit(ARM_UDIV(rd, rm, rn), ctx); 435*ddecdfceSMircea Gherzan return; 436*ddecdfceSMircea Gherzan } 437*ddecdfceSMircea Gherzan #endif 438*ddecdfceSMircea Gherzan if (rm != ARM_R0) 439*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R0, rm), ctx); 440*ddecdfceSMircea Gherzan if (rn != ARM_R1) 441*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R1, rn), ctx); 442*ddecdfceSMircea Gherzan 443*ddecdfceSMircea Gherzan ctx->seen |= SEEN_CALL; 444*ddecdfceSMircea Gherzan emit_mov_i(ARM_R3, (u32)jit_udiv, ctx); 445*ddecdfceSMircea Gherzan emit_blx_r(ARM_R3, ctx); 446*ddecdfceSMircea Gherzan 447*ddecdfceSMircea Gherzan if (rd != ARM_R0) 448*ddecdfceSMircea Gherzan emit(ARM_MOV_R(rd, ARM_R0), ctx); 449*ddecdfceSMircea Gherzan } 450*ddecdfceSMircea Gherzan 451*ddecdfceSMircea Gherzan static inline void update_on_xread(struct jit_ctx *ctx) 452*ddecdfceSMircea Gherzan { 453*ddecdfceSMircea Gherzan if (!(ctx->seen & SEEN_X)) 454*ddecdfceSMircea Gherzan ctx->flags |= FLAG_NEED_X_RESET; 455*ddecdfceSMircea Gherzan 456*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X; 457*ddecdfceSMircea Gherzan } 458*ddecdfceSMircea Gherzan 459*ddecdfceSMircea Gherzan static int build_body(struct jit_ctx *ctx) 460*ddecdfceSMircea Gherzan { 461*ddecdfceSMircea Gherzan void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w}; 462*ddecdfceSMircea Gherzan const struct sk_filter *prog = ctx->skf; 463*ddecdfceSMircea Gherzan const struct sock_filter *inst; 464*ddecdfceSMircea Gherzan unsigned i, load_order, off, condt; 465*ddecdfceSMircea Gherzan int imm12; 466*ddecdfceSMircea Gherzan u32 k; 467*ddecdfceSMircea Gherzan 468*ddecdfceSMircea Gherzan for (i = 0; i < prog->len; i++) { 469*ddecdfceSMircea Gherzan inst = &(prog->insns[i]); 470*ddecdfceSMircea Gherzan /* K as an immediate value operand */ 471*ddecdfceSMircea Gherzan k = inst->k; 472*ddecdfceSMircea Gherzan 473*ddecdfceSMircea Gherzan /* compute offsets only in the fake pass */ 474*ddecdfceSMircea Gherzan if (ctx->target == NULL) 475*ddecdfceSMircea Gherzan ctx->offsets[i] = ctx->idx * 4; 476*ddecdfceSMircea Gherzan 477*ddecdfceSMircea Gherzan switch (inst->code) { 478*ddecdfceSMircea Gherzan case BPF_S_LD_IMM: 479*ddecdfceSMircea Gherzan emit_mov_i(r_A, k, ctx); 480*ddecdfceSMircea Gherzan break; 481*ddecdfceSMircea Gherzan case BPF_S_LD_W_LEN: 482*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 483*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, len) != 4); 484*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, r_skb, 485*ddecdfceSMircea Gherzan offsetof(struct sk_buff, len)), ctx); 486*ddecdfceSMircea Gherzan break; 487*ddecdfceSMircea Gherzan case BPF_S_LD_MEM: 488*ddecdfceSMircea Gherzan /* A = scratch[k] */ 489*ddecdfceSMircea Gherzan ctx->seen |= SEEN_MEM_WORD(k); 490*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx); 491*ddecdfceSMircea Gherzan break; 492*ddecdfceSMircea Gherzan case BPF_S_LD_W_ABS: 493*ddecdfceSMircea Gherzan load_order = 2; 494*ddecdfceSMircea Gherzan goto load; 495*ddecdfceSMircea Gherzan case BPF_S_LD_H_ABS: 496*ddecdfceSMircea Gherzan load_order = 1; 497*ddecdfceSMircea Gherzan goto load; 498*ddecdfceSMircea Gherzan case BPF_S_LD_B_ABS: 499*ddecdfceSMircea Gherzan load_order = 0; 500*ddecdfceSMircea Gherzan load: 501*ddecdfceSMircea Gherzan /* the interpreter will deal with the negative K */ 502*ddecdfceSMircea Gherzan if ((int)k < 0) 503*ddecdfceSMircea Gherzan return -ENOTSUPP; 504*ddecdfceSMircea Gherzan emit_mov_i(r_off, k, ctx); 505*ddecdfceSMircea Gherzan load_common: 506*ddecdfceSMircea Gherzan ctx->seen |= SEEN_DATA | SEEN_CALL; 507*ddecdfceSMircea Gherzan 508*ddecdfceSMircea Gherzan if (load_order > 0) { 509*ddecdfceSMircea Gherzan emit(ARM_SUB_I(r_scratch, r_skb_hl, 510*ddecdfceSMircea Gherzan 1 << load_order), ctx); 511*ddecdfceSMircea Gherzan emit(ARM_CMP_R(r_scratch, r_off), ctx); 512*ddecdfceSMircea Gherzan condt = ARM_COND_HS; 513*ddecdfceSMircea Gherzan } else { 514*ddecdfceSMircea Gherzan emit(ARM_CMP_R(r_skb_hl, r_off), ctx); 515*ddecdfceSMircea Gherzan condt = ARM_COND_HI; 516*ddecdfceSMircea Gherzan } 517*ddecdfceSMircea Gherzan 518*ddecdfceSMircea Gherzan _emit(condt, ARM_ADD_R(r_scratch, r_off, r_skb_data), 519*ddecdfceSMircea Gherzan ctx); 520*ddecdfceSMircea Gherzan 521*ddecdfceSMircea Gherzan if (load_order == 0) 522*ddecdfceSMircea Gherzan _emit(condt, ARM_LDRB_I(r_A, r_scratch, 0), 523*ddecdfceSMircea Gherzan ctx); 524*ddecdfceSMircea Gherzan else if (load_order == 1) 525*ddecdfceSMircea Gherzan emit_load_be16(condt, r_A, r_scratch, ctx); 526*ddecdfceSMircea Gherzan else if (load_order == 2) 527*ddecdfceSMircea Gherzan emit_load_be32(condt, r_A, r_scratch, ctx); 528*ddecdfceSMircea Gherzan 529*ddecdfceSMircea Gherzan _emit(condt, ARM_B(b_imm(i + 1, ctx)), ctx); 530*ddecdfceSMircea Gherzan 531*ddecdfceSMircea Gherzan /* the slowpath */ 532*ddecdfceSMircea Gherzan emit_mov_i(ARM_R3, (u32)load_func[load_order], ctx); 533*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R0, r_skb), ctx); 534*ddecdfceSMircea Gherzan /* the offset is already in R1 */ 535*ddecdfceSMircea Gherzan emit_blx_r(ARM_R3, ctx); 536*ddecdfceSMircea Gherzan /* check the result of skb_copy_bits */ 537*ddecdfceSMircea Gherzan emit(ARM_CMP_I(ARM_R1, 0), ctx); 538*ddecdfceSMircea Gherzan emit_err_ret(ARM_COND_NE, ctx); 539*ddecdfceSMircea Gherzan emit(ARM_MOV_R(r_A, ARM_R0), ctx); 540*ddecdfceSMircea Gherzan break; 541*ddecdfceSMircea Gherzan case BPF_S_LD_W_IND: 542*ddecdfceSMircea Gherzan load_order = 2; 543*ddecdfceSMircea Gherzan goto load_ind; 544*ddecdfceSMircea Gherzan case BPF_S_LD_H_IND: 545*ddecdfceSMircea Gherzan load_order = 1; 546*ddecdfceSMircea Gherzan goto load_ind; 547*ddecdfceSMircea Gherzan case BPF_S_LD_B_IND: 548*ddecdfceSMircea Gherzan load_order = 0; 549*ddecdfceSMircea Gherzan load_ind: 550*ddecdfceSMircea Gherzan OP_IMM3(ARM_ADD, r_off, r_X, k, ctx); 551*ddecdfceSMircea Gherzan goto load_common; 552*ddecdfceSMircea Gherzan case BPF_S_LDX_IMM: 553*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X; 554*ddecdfceSMircea Gherzan emit_mov_i(r_X, k, ctx); 555*ddecdfceSMircea Gherzan break; 556*ddecdfceSMircea Gherzan case BPF_S_LDX_W_LEN: 557*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X | SEEN_SKB; 558*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_X, r_skb, 559*ddecdfceSMircea Gherzan offsetof(struct sk_buff, len)), ctx); 560*ddecdfceSMircea Gherzan break; 561*ddecdfceSMircea Gherzan case BPF_S_LDX_MEM: 562*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X | SEEN_MEM_WORD(k); 563*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx); 564*ddecdfceSMircea Gherzan break; 565*ddecdfceSMircea Gherzan case BPF_S_LDX_B_MSH: 566*ddecdfceSMircea Gherzan /* x = ((*(frame + k)) & 0xf) << 2; */ 567*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X | SEEN_DATA | SEEN_CALL; 568*ddecdfceSMircea Gherzan /* the interpreter should deal with the negative K */ 569*ddecdfceSMircea Gherzan if (k < 0) 570*ddecdfceSMircea Gherzan return -1; 571*ddecdfceSMircea Gherzan /* offset in r1: we might have to take the slow path */ 572*ddecdfceSMircea Gherzan emit_mov_i(r_off, k, ctx); 573*ddecdfceSMircea Gherzan emit(ARM_CMP_R(r_skb_hl, r_off), ctx); 574*ddecdfceSMircea Gherzan 575*ddecdfceSMircea Gherzan /* load in r0: common with the slowpath */ 576*ddecdfceSMircea Gherzan _emit(ARM_COND_HI, ARM_LDRB_R(ARM_R0, r_skb_data, 577*ddecdfceSMircea Gherzan ARM_R1), ctx); 578*ddecdfceSMircea Gherzan /* 579*ddecdfceSMircea Gherzan * emit_mov_i() might generate one or two instructions, 580*ddecdfceSMircea Gherzan * the same holds for emit_blx_r() 581*ddecdfceSMircea Gherzan */ 582*ddecdfceSMircea Gherzan _emit(ARM_COND_HI, ARM_B(b_imm(i + 1, ctx) - 2), ctx); 583*ddecdfceSMircea Gherzan 584*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R0, r_skb), ctx); 585*ddecdfceSMircea Gherzan /* r_off is r1 */ 586*ddecdfceSMircea Gherzan emit_mov_i(ARM_R3, (u32)jit_get_skb_b, ctx); 587*ddecdfceSMircea Gherzan emit_blx_r(ARM_R3, ctx); 588*ddecdfceSMircea Gherzan /* check the return value of skb_copy_bits */ 589*ddecdfceSMircea Gherzan emit(ARM_CMP_I(ARM_R1, 0), ctx); 590*ddecdfceSMircea Gherzan emit_err_ret(ARM_COND_NE, ctx); 591*ddecdfceSMircea Gherzan 592*ddecdfceSMircea Gherzan emit(ARM_AND_I(r_X, ARM_R0, 0x00f), ctx); 593*ddecdfceSMircea Gherzan emit(ARM_LSL_I(r_X, r_X, 2), ctx); 594*ddecdfceSMircea Gherzan break; 595*ddecdfceSMircea Gherzan case BPF_S_ST: 596*ddecdfceSMircea Gherzan ctx->seen |= SEEN_MEM_WORD(k); 597*ddecdfceSMircea Gherzan emit(ARM_STR_I(r_A, ARM_SP, SCRATCH_OFF(k)), ctx); 598*ddecdfceSMircea Gherzan break; 599*ddecdfceSMircea Gherzan case BPF_S_STX: 600*ddecdfceSMircea Gherzan update_on_xread(ctx); 601*ddecdfceSMircea Gherzan ctx->seen |= SEEN_MEM_WORD(k); 602*ddecdfceSMircea Gherzan emit(ARM_STR_I(r_X, ARM_SP, SCRATCH_OFF(k)), ctx); 603*ddecdfceSMircea Gherzan break; 604*ddecdfceSMircea Gherzan case BPF_S_ALU_ADD_K: 605*ddecdfceSMircea Gherzan /* A += K */ 606*ddecdfceSMircea Gherzan OP_IMM3(ARM_ADD, r_A, r_A, k, ctx); 607*ddecdfceSMircea Gherzan break; 608*ddecdfceSMircea Gherzan case BPF_S_ALU_ADD_X: 609*ddecdfceSMircea Gherzan update_on_xread(ctx); 610*ddecdfceSMircea Gherzan emit(ARM_ADD_R(r_A, r_A, r_X), ctx); 611*ddecdfceSMircea Gherzan break; 612*ddecdfceSMircea Gherzan case BPF_S_ALU_SUB_K: 613*ddecdfceSMircea Gherzan /* A -= K */ 614*ddecdfceSMircea Gherzan OP_IMM3(ARM_SUB, r_A, r_A, k, ctx); 615*ddecdfceSMircea Gherzan break; 616*ddecdfceSMircea Gherzan case BPF_S_ALU_SUB_X: 617*ddecdfceSMircea Gherzan update_on_xread(ctx); 618*ddecdfceSMircea Gherzan emit(ARM_SUB_R(r_A, r_A, r_X), ctx); 619*ddecdfceSMircea Gherzan break; 620*ddecdfceSMircea Gherzan case BPF_S_ALU_MUL_K: 621*ddecdfceSMircea Gherzan /* A *= K */ 622*ddecdfceSMircea Gherzan emit_mov_i(r_scratch, k, ctx); 623*ddecdfceSMircea Gherzan emit(ARM_MUL(r_A, r_A, r_scratch), ctx); 624*ddecdfceSMircea Gherzan break; 625*ddecdfceSMircea Gherzan case BPF_S_ALU_MUL_X: 626*ddecdfceSMircea Gherzan update_on_xread(ctx); 627*ddecdfceSMircea Gherzan emit(ARM_MUL(r_A, r_A, r_X), ctx); 628*ddecdfceSMircea Gherzan break; 629*ddecdfceSMircea Gherzan case BPF_S_ALU_DIV_K: 630*ddecdfceSMircea Gherzan /* current k == reciprocal_value(userspace k) */ 631*ddecdfceSMircea Gherzan emit_mov_i(r_scratch, k, ctx); 632*ddecdfceSMircea Gherzan /* A = top 32 bits of the product */ 633*ddecdfceSMircea Gherzan emit(ARM_UMULL(r_scratch, r_A, r_A, r_scratch), ctx); 634*ddecdfceSMircea Gherzan break; 635*ddecdfceSMircea Gherzan case BPF_S_ALU_DIV_X: 636*ddecdfceSMircea Gherzan update_on_xread(ctx); 637*ddecdfceSMircea Gherzan emit(ARM_CMP_I(r_X, 0), ctx); 638*ddecdfceSMircea Gherzan emit_err_ret(ARM_COND_EQ, ctx); 639*ddecdfceSMircea Gherzan emit_udiv(r_A, r_A, r_X, ctx); 640*ddecdfceSMircea Gherzan break; 641*ddecdfceSMircea Gherzan case BPF_S_ALU_OR_K: 642*ddecdfceSMircea Gherzan /* A |= K */ 643*ddecdfceSMircea Gherzan OP_IMM3(ARM_ORR, r_A, r_A, k, ctx); 644*ddecdfceSMircea Gherzan break; 645*ddecdfceSMircea Gherzan case BPF_S_ALU_OR_X: 646*ddecdfceSMircea Gherzan update_on_xread(ctx); 647*ddecdfceSMircea Gherzan emit(ARM_ORR_R(r_A, r_A, r_X), ctx); 648*ddecdfceSMircea Gherzan break; 649*ddecdfceSMircea Gherzan case BPF_S_ALU_AND_K: 650*ddecdfceSMircea Gherzan /* A &= K */ 651*ddecdfceSMircea Gherzan OP_IMM3(ARM_AND, r_A, r_A, k, ctx); 652*ddecdfceSMircea Gherzan break; 653*ddecdfceSMircea Gherzan case BPF_S_ALU_AND_X: 654*ddecdfceSMircea Gherzan update_on_xread(ctx); 655*ddecdfceSMircea Gherzan emit(ARM_AND_R(r_A, r_A, r_X), ctx); 656*ddecdfceSMircea Gherzan break; 657*ddecdfceSMircea Gherzan case BPF_S_ALU_LSH_K: 658*ddecdfceSMircea Gherzan if (unlikely(k > 31)) 659*ddecdfceSMircea Gherzan return -1; 660*ddecdfceSMircea Gherzan emit(ARM_LSL_I(r_A, r_A, k), ctx); 661*ddecdfceSMircea Gherzan break; 662*ddecdfceSMircea Gherzan case BPF_S_ALU_LSH_X: 663*ddecdfceSMircea Gherzan update_on_xread(ctx); 664*ddecdfceSMircea Gherzan emit(ARM_LSL_R(r_A, r_A, r_X), ctx); 665*ddecdfceSMircea Gherzan break; 666*ddecdfceSMircea Gherzan case BPF_S_ALU_RSH_K: 667*ddecdfceSMircea Gherzan if (unlikely(k > 31)) 668*ddecdfceSMircea Gherzan return -1; 669*ddecdfceSMircea Gherzan emit(ARM_LSR_I(r_A, r_A, k), ctx); 670*ddecdfceSMircea Gherzan break; 671*ddecdfceSMircea Gherzan case BPF_S_ALU_RSH_X: 672*ddecdfceSMircea Gherzan update_on_xread(ctx); 673*ddecdfceSMircea Gherzan emit(ARM_LSR_R(r_A, r_A, r_X), ctx); 674*ddecdfceSMircea Gherzan break; 675*ddecdfceSMircea Gherzan case BPF_S_ALU_NEG: 676*ddecdfceSMircea Gherzan /* A = -A */ 677*ddecdfceSMircea Gherzan emit(ARM_RSB_I(r_A, r_A, 0), ctx); 678*ddecdfceSMircea Gherzan break; 679*ddecdfceSMircea Gherzan case BPF_S_JMP_JA: 680*ddecdfceSMircea Gherzan /* pc += K */ 681*ddecdfceSMircea Gherzan emit(ARM_B(b_imm(i + k + 1, ctx)), ctx); 682*ddecdfceSMircea Gherzan break; 683*ddecdfceSMircea Gherzan case BPF_S_JMP_JEQ_K: 684*ddecdfceSMircea Gherzan /* pc += (A == K) ? pc->jt : pc->jf */ 685*ddecdfceSMircea Gherzan condt = ARM_COND_EQ; 686*ddecdfceSMircea Gherzan goto cmp_imm; 687*ddecdfceSMircea Gherzan case BPF_S_JMP_JGT_K: 688*ddecdfceSMircea Gherzan /* pc += (A > K) ? pc->jt : pc->jf */ 689*ddecdfceSMircea Gherzan condt = ARM_COND_HI; 690*ddecdfceSMircea Gherzan goto cmp_imm; 691*ddecdfceSMircea Gherzan case BPF_S_JMP_JGE_K: 692*ddecdfceSMircea Gherzan /* pc += (A >= K) ? pc->jt : pc->jf */ 693*ddecdfceSMircea Gherzan condt = ARM_COND_HS; 694*ddecdfceSMircea Gherzan cmp_imm: 695*ddecdfceSMircea Gherzan imm12 = imm8m(k); 696*ddecdfceSMircea Gherzan if (imm12 < 0) { 697*ddecdfceSMircea Gherzan emit_mov_i_no8m(r_scratch, k, ctx); 698*ddecdfceSMircea Gherzan emit(ARM_CMP_R(r_A, r_scratch), ctx); 699*ddecdfceSMircea Gherzan } else { 700*ddecdfceSMircea Gherzan emit(ARM_CMP_I(r_A, imm12), ctx); 701*ddecdfceSMircea Gherzan } 702*ddecdfceSMircea Gherzan cond_jump: 703*ddecdfceSMircea Gherzan if (inst->jt) 704*ddecdfceSMircea Gherzan _emit(condt, ARM_B(b_imm(i + inst->jt + 1, 705*ddecdfceSMircea Gherzan ctx)), ctx); 706*ddecdfceSMircea Gherzan if (inst->jf) 707*ddecdfceSMircea Gherzan _emit(condt ^ 1, ARM_B(b_imm(i + inst->jf + 1, 708*ddecdfceSMircea Gherzan ctx)), ctx); 709*ddecdfceSMircea Gherzan break; 710*ddecdfceSMircea Gherzan case BPF_S_JMP_JEQ_X: 711*ddecdfceSMircea Gherzan /* pc += (A == X) ? pc->jt : pc->jf */ 712*ddecdfceSMircea Gherzan condt = ARM_COND_EQ; 713*ddecdfceSMircea Gherzan goto cmp_x; 714*ddecdfceSMircea Gherzan case BPF_S_JMP_JGT_X: 715*ddecdfceSMircea Gherzan /* pc += (A > X) ? pc->jt : pc->jf */ 716*ddecdfceSMircea Gherzan condt = ARM_COND_HI; 717*ddecdfceSMircea Gherzan goto cmp_x; 718*ddecdfceSMircea Gherzan case BPF_S_JMP_JGE_X: 719*ddecdfceSMircea Gherzan /* pc += (A >= X) ? pc->jt : pc->jf */ 720*ddecdfceSMircea Gherzan condt = ARM_COND_CS; 721*ddecdfceSMircea Gherzan cmp_x: 722*ddecdfceSMircea Gherzan update_on_xread(ctx); 723*ddecdfceSMircea Gherzan emit(ARM_CMP_R(r_A, r_X), ctx); 724*ddecdfceSMircea Gherzan goto cond_jump; 725*ddecdfceSMircea Gherzan case BPF_S_JMP_JSET_K: 726*ddecdfceSMircea Gherzan /* pc += (A & K) ? pc->jt : pc->jf */ 727*ddecdfceSMircea Gherzan condt = ARM_COND_NE; 728*ddecdfceSMircea Gherzan /* not set iff all zeroes iff Z==1 iff EQ */ 729*ddecdfceSMircea Gherzan 730*ddecdfceSMircea Gherzan imm12 = imm8m(k); 731*ddecdfceSMircea Gherzan if (imm12 < 0) { 732*ddecdfceSMircea Gherzan emit_mov_i_no8m(r_scratch, k, ctx); 733*ddecdfceSMircea Gherzan emit(ARM_TST_R(r_A, r_scratch), ctx); 734*ddecdfceSMircea Gherzan } else { 735*ddecdfceSMircea Gherzan emit(ARM_TST_I(r_A, imm12), ctx); 736*ddecdfceSMircea Gherzan } 737*ddecdfceSMircea Gherzan goto cond_jump; 738*ddecdfceSMircea Gherzan case BPF_S_JMP_JSET_X: 739*ddecdfceSMircea Gherzan /* pc += (A & X) ? pc->jt : pc->jf */ 740*ddecdfceSMircea Gherzan update_on_xread(ctx); 741*ddecdfceSMircea Gherzan condt = ARM_COND_NE; 742*ddecdfceSMircea Gherzan emit(ARM_TST_R(r_A, r_X), ctx); 743*ddecdfceSMircea Gherzan goto cond_jump; 744*ddecdfceSMircea Gherzan case BPF_S_RET_A: 745*ddecdfceSMircea Gherzan emit(ARM_MOV_R(ARM_R0, r_A), ctx); 746*ddecdfceSMircea Gherzan goto b_epilogue; 747*ddecdfceSMircea Gherzan case BPF_S_RET_K: 748*ddecdfceSMircea Gherzan if ((k == 0) && (ctx->ret0_fp_idx < 0)) 749*ddecdfceSMircea Gherzan ctx->ret0_fp_idx = i; 750*ddecdfceSMircea Gherzan emit_mov_i(ARM_R0, k, ctx); 751*ddecdfceSMircea Gherzan b_epilogue: 752*ddecdfceSMircea Gherzan if (i != ctx->skf->len - 1) 753*ddecdfceSMircea Gherzan emit(ARM_B(b_imm(prog->len, ctx)), ctx); 754*ddecdfceSMircea Gherzan break; 755*ddecdfceSMircea Gherzan case BPF_S_MISC_TAX: 756*ddecdfceSMircea Gherzan /* X = A */ 757*ddecdfceSMircea Gherzan ctx->seen |= SEEN_X; 758*ddecdfceSMircea Gherzan emit(ARM_MOV_R(r_X, r_A), ctx); 759*ddecdfceSMircea Gherzan break; 760*ddecdfceSMircea Gherzan case BPF_S_MISC_TXA: 761*ddecdfceSMircea Gherzan /* A = X */ 762*ddecdfceSMircea Gherzan update_on_xread(ctx); 763*ddecdfceSMircea Gherzan emit(ARM_MOV_R(r_A, r_X), ctx); 764*ddecdfceSMircea Gherzan break; 765*ddecdfceSMircea Gherzan case BPF_S_ANC_PROTOCOL: 766*ddecdfceSMircea Gherzan /* A = ntohs(skb->protocol) */ 767*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 768*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, 769*ddecdfceSMircea Gherzan protocol) != 2); 770*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, protocol); 771*ddecdfceSMircea Gherzan emit(ARM_LDRH_I(r_scratch, r_skb, off), ctx); 772*ddecdfceSMircea Gherzan emit_swap16(r_A, r_scratch, ctx); 773*ddecdfceSMircea Gherzan break; 774*ddecdfceSMircea Gherzan case BPF_S_ANC_CPU: 775*ddecdfceSMircea Gherzan /* r_scratch = current_thread_info() */ 776*ddecdfceSMircea Gherzan OP_IMM3(ARM_BIC, r_scratch, ARM_SP, THREAD_SIZE - 1, ctx); 777*ddecdfceSMircea Gherzan /* A = current_thread_info()->cpu */ 778*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct thread_info, cpu) != 4); 779*ddecdfceSMircea Gherzan off = offsetof(struct thread_info, cpu); 780*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, r_scratch, off), ctx); 781*ddecdfceSMircea Gherzan break; 782*ddecdfceSMircea Gherzan case BPF_S_ANC_IFINDEX: 783*ddecdfceSMircea Gherzan /* A = skb->dev->ifindex */ 784*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 785*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, dev); 786*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_scratch, r_skb, off), ctx); 787*ddecdfceSMircea Gherzan 788*ddecdfceSMircea Gherzan emit(ARM_CMP_I(r_scratch, 0), ctx); 789*ddecdfceSMircea Gherzan emit_err_ret(ARM_COND_EQ, ctx); 790*ddecdfceSMircea Gherzan 791*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct net_device, 792*ddecdfceSMircea Gherzan ifindex) != 4); 793*ddecdfceSMircea Gherzan off = offsetof(struct net_device, ifindex); 794*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, r_scratch, off), ctx); 795*ddecdfceSMircea Gherzan break; 796*ddecdfceSMircea Gherzan case BPF_S_ANC_MARK: 797*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 798*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, mark) != 4); 799*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, mark); 800*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, r_skb, off), ctx); 801*ddecdfceSMircea Gherzan break; 802*ddecdfceSMircea Gherzan case BPF_S_ANC_RXHASH: 803*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 804*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, rxhash) != 4); 805*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, rxhash); 806*ddecdfceSMircea Gherzan emit(ARM_LDR_I(r_A, r_skb, off), ctx); 807*ddecdfceSMircea Gherzan break; 808*ddecdfceSMircea Gherzan case BPF_S_ANC_QUEUE: 809*ddecdfceSMircea Gherzan ctx->seen |= SEEN_SKB; 810*ddecdfceSMircea Gherzan BUILD_BUG_ON(FIELD_SIZEOF(struct sk_buff, 811*ddecdfceSMircea Gherzan queue_mapping) != 2); 812*ddecdfceSMircea Gherzan BUILD_BUG_ON(offsetof(struct sk_buff, 813*ddecdfceSMircea Gherzan queue_mapping) > 0xff); 814*ddecdfceSMircea Gherzan off = offsetof(struct sk_buff, queue_mapping); 815*ddecdfceSMircea Gherzan emit(ARM_LDRH_I(r_A, r_skb, off), ctx); 816*ddecdfceSMircea Gherzan break; 817*ddecdfceSMircea Gherzan default: 818*ddecdfceSMircea Gherzan return -1; 819*ddecdfceSMircea Gherzan } 820*ddecdfceSMircea Gherzan } 821*ddecdfceSMircea Gherzan 822*ddecdfceSMircea Gherzan /* compute offsets only during the first pass */ 823*ddecdfceSMircea Gherzan if (ctx->target == NULL) 824*ddecdfceSMircea Gherzan ctx->offsets[i] = ctx->idx * 4; 825*ddecdfceSMircea Gherzan 826*ddecdfceSMircea Gherzan return 0; 827*ddecdfceSMircea Gherzan } 828*ddecdfceSMircea Gherzan 829*ddecdfceSMircea Gherzan 830*ddecdfceSMircea Gherzan void bpf_jit_compile(struct sk_filter *fp) 831*ddecdfceSMircea Gherzan { 832*ddecdfceSMircea Gherzan struct jit_ctx ctx; 833*ddecdfceSMircea Gherzan unsigned tmp_idx; 834*ddecdfceSMircea Gherzan unsigned alloc_size; 835*ddecdfceSMircea Gherzan 836*ddecdfceSMircea Gherzan if (!bpf_jit_enable) 837*ddecdfceSMircea Gherzan return; 838*ddecdfceSMircea Gherzan 839*ddecdfceSMircea Gherzan memset(&ctx, 0, sizeof(ctx)); 840*ddecdfceSMircea Gherzan ctx.skf = fp; 841*ddecdfceSMircea Gherzan ctx.ret0_fp_idx = -1; 842*ddecdfceSMircea Gherzan 843*ddecdfceSMircea Gherzan ctx.offsets = kzalloc(GFP_KERNEL, 4 * (ctx.skf->len + 1)); 844*ddecdfceSMircea Gherzan if (ctx.offsets == NULL) 845*ddecdfceSMircea Gherzan return; 846*ddecdfceSMircea Gherzan 847*ddecdfceSMircea Gherzan /* fake pass to fill in the ctx->seen */ 848*ddecdfceSMircea Gherzan if (unlikely(build_body(&ctx))) 849*ddecdfceSMircea Gherzan goto out; 850*ddecdfceSMircea Gherzan 851*ddecdfceSMircea Gherzan tmp_idx = ctx.idx; 852*ddecdfceSMircea Gherzan build_prologue(&ctx); 853*ddecdfceSMircea Gherzan ctx.prologue_bytes = (ctx.idx - tmp_idx) * 4; 854*ddecdfceSMircea Gherzan 855*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 7 856*ddecdfceSMircea Gherzan tmp_idx = ctx.idx; 857*ddecdfceSMircea Gherzan build_epilogue(&ctx); 858*ddecdfceSMircea Gherzan ctx.epilogue_bytes = (ctx.idx - tmp_idx) * 4; 859*ddecdfceSMircea Gherzan 860*ddecdfceSMircea Gherzan ctx.idx += ctx.imm_count; 861*ddecdfceSMircea Gherzan if (ctx.imm_count) { 862*ddecdfceSMircea Gherzan ctx.imms = kzalloc(GFP_KERNEL, 4 * ctx.imm_count); 863*ddecdfceSMircea Gherzan if (ctx.imms == NULL) 864*ddecdfceSMircea Gherzan goto out; 865*ddecdfceSMircea Gherzan } 866*ddecdfceSMircea Gherzan #else 867*ddecdfceSMircea Gherzan /* there's nothing after the epilogue on ARMv7 */ 868*ddecdfceSMircea Gherzan build_epilogue(&ctx); 869*ddecdfceSMircea Gherzan #endif 870*ddecdfceSMircea Gherzan 871*ddecdfceSMircea Gherzan alloc_size = 4 * ctx.idx; 872*ddecdfceSMircea Gherzan ctx.target = module_alloc(max(sizeof(struct work_struct), 873*ddecdfceSMircea Gherzan alloc_size)); 874*ddecdfceSMircea Gherzan if (unlikely(ctx.target == NULL)) 875*ddecdfceSMircea Gherzan goto out; 876*ddecdfceSMircea Gherzan 877*ddecdfceSMircea Gherzan ctx.idx = 0; 878*ddecdfceSMircea Gherzan build_prologue(&ctx); 879*ddecdfceSMircea Gherzan build_body(&ctx); 880*ddecdfceSMircea Gherzan build_epilogue(&ctx); 881*ddecdfceSMircea Gherzan 882*ddecdfceSMircea Gherzan flush_icache_range((u32)ctx.target, (u32)(ctx.target + ctx.idx)); 883*ddecdfceSMircea Gherzan 884*ddecdfceSMircea Gherzan #if __LINUX_ARM_ARCH__ < 7 885*ddecdfceSMircea Gherzan if (ctx.imm_count) 886*ddecdfceSMircea Gherzan kfree(ctx.imms); 887*ddecdfceSMircea Gherzan #endif 888*ddecdfceSMircea Gherzan 889*ddecdfceSMircea Gherzan if (bpf_jit_enable > 1) 890*ddecdfceSMircea Gherzan print_hex_dump(KERN_INFO, "BPF JIT code: ", 891*ddecdfceSMircea Gherzan DUMP_PREFIX_ADDRESS, 16, 4, ctx.target, 892*ddecdfceSMircea Gherzan alloc_size, false); 893*ddecdfceSMircea Gherzan 894*ddecdfceSMircea Gherzan fp->bpf_func = (void *)ctx.target; 895*ddecdfceSMircea Gherzan out: 896*ddecdfceSMircea Gherzan kfree(ctx.offsets); 897*ddecdfceSMircea Gherzan return; 898*ddecdfceSMircea Gherzan } 899*ddecdfceSMircea Gherzan 900*ddecdfceSMircea Gherzan static void bpf_jit_free_worker(struct work_struct *work) 901*ddecdfceSMircea Gherzan { 902*ddecdfceSMircea Gherzan module_free(NULL, work); 903*ddecdfceSMircea Gherzan } 904*ddecdfceSMircea Gherzan 905*ddecdfceSMircea Gherzan void bpf_jit_free(struct sk_filter *fp) 906*ddecdfceSMircea Gherzan { 907*ddecdfceSMircea Gherzan struct work_struct *work; 908*ddecdfceSMircea Gherzan 909*ddecdfceSMircea Gherzan if (fp->bpf_func != sk_run_filter) { 910*ddecdfceSMircea Gherzan work = (struct work_struct *)fp->bpf_func; 911*ddecdfceSMircea Gherzan 912*ddecdfceSMircea Gherzan INIT_WORK(work, bpf_jit_free_worker); 913*ddecdfceSMircea Gherzan schedule_work(work); 914*ddecdfceSMircea Gherzan } 915*ddecdfceSMircea Gherzan } 916