MIPS: BPF: Introduce BPF ASM helpers
[deliverable/linux.git] / arch / mips / net / bpf_jit.c
index f0db4f8310b28c6ccb98fc83f8b17502e2fe5a7b..0c4a133f6216012c303e2b4105214c422a327976 100644 (file)
 #include "bpf_jit.h"
 
 /* ABI
- *
+ * r_skb_hl    SKB header length
+ * r_data      SKB data pointer
+ * r_off       Offset
  * r_A         BPF register A
  * r_X         BPF register X
  * r_skb       *skb
  * r_M         *scratch memory
+ * r_skb_len   SKB length
  *
  * On entry (*bpf_func)(*skb, *filter)
  * a0 = MIPS_R_A0 = skb;
@@ -75,6 +78,8 @@
 #define SEEN_X                 SEEN_SREG(4)
 #define SEEN_SKB               SEEN_SREG(5)
 #define SEEN_MEM               SEEN_SREG(6)
+/* SEEN_SK_DATA also implies skb_hl an skb_len */
+#define SEEN_SKB_DATA          (SEEN_SREG(7) | SEEN_SREG(1) | SEEN_SREG(0))
 
 /* Arguments used by JIT */
 #define ARGS_USED_BY_JIT       2 /* only applicable to 64-bit */
@@ -537,20 +542,6 @@ static void save_bpf_jit_regs(struct jit_ctx *ctx, unsigned offset)
        /* Adjust the stack pointer */
        emit_stack_offset(-align_sp(offset), ctx);
 
-       if (ctx->flags & SEEN_CALL) {
-               /* Argument save area */
-               if (config_enabled(CONFIG_64BIT))
-                       /* Bottom of current frame */
-                       real_off = align_sp(offset) - SZREG;
-               else
-                       /* Top of previous frame */
-                       real_off = align_sp(offset) + SZREG;
-               emit_store_stack_reg(MIPS_R_A0, r_sp, real_off, ctx);
-               emit_store_stack_reg(MIPS_R_A1, r_sp, real_off + SZREG, ctx);
-
-               real_off = 0;
-       }
-
        tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
        /* sflags is essentially a bitmap */
        while (tmp_flags) {
@@ -583,19 +574,6 @@ static void restore_bpf_jit_regs(struct jit_ctx *ctx,
        int i, real_off = 0;
        u32 sflags, tmp_flags;
 
-       if (ctx->flags & SEEN_CALL) {
-               if (config_enabled(CONFIG_64BIT))
-                       /* Bottom of current frame */
-                       real_off = align_sp(offset) - SZREG;
-               else
-                       /* Top of previous frame */
-                       real_off = align_sp(offset) + SZREG;
-               emit_load_stack_reg(MIPS_R_A0, r_sp, real_off, ctx);
-               emit_load_stack_reg(MIPS_R_A1, r_sp, real_off + SZREG, ctx);
-
-               real_off = 0;
-       }
-
        tmp_flags = sflags = ctx->flags >> SEEN_SREG_SFT;
        /* sflags is a bitmap */
        i = 0;
@@ -629,17 +607,7 @@ static unsigned int get_stack_depth(struct jit_ctx *ctx)
                sp_off += 4 * BPF_MEMWORDS; /* BPF_MEMWORDS are 32-bit */
 
        if (ctx->flags & SEEN_CALL)
-               /*
-                * The JIT code make calls to external functions using 2
-                * arguments. Therefore, for o32 we don't need to allocate
-                * space because we don't care if the argumetns are lost
-                * across calls. We do need however to preserve incoming
-                * arguments but the space is already allocated for us by
-                * the caller. On the other hand, for n64, we need to allocate
-                * this space ourselves. We need to preserve $ra as well.
-                */
-               sp_off += config_enabled(CONFIG_64BIT) ?
-                       (ARGS_USED_BY_JIT + 1) * SZREG : SZREG;
+               sp_off += SZREG; /* Space for our ra register */
 
        return sp_off;
 }
@@ -656,6 +624,19 @@ static void build_prologue(struct jit_ctx *ctx)
        if (ctx->flags & SEEN_SKB)
                emit_reg_move(r_skb, MIPS_R_A0, ctx);
 
+       if (ctx->flags & SEEN_SKB_DATA) {
+               /* Load packet length */
+               emit_load(r_skb_len, r_skb, offsetof(struct sk_buff, len),
+                         ctx);
+               emit_load(r_tmp, r_skb, offsetof(struct sk_buff, data_len),
+                         ctx);
+               /* Load the data pointer */
+               emit_load_ptr(r_skb_data, r_skb,
+                             offsetof(struct sk_buff, data), ctx);
+               /* Load the header length */
+               emit_subu(r_skb_hl, r_skb_len, r_tmp, ctx);
+       }
+
        if (ctx->flags & SEEN_X)
                emit_jit_reg_move(r_X, r_zero, ctx);
 
@@ -678,43 +659,17 @@ static void build_epilogue(struct jit_ctx *ctx)
        emit_nop(ctx);
 }
 
-static u64 jit_get_skb_b(struct sk_buff *skb, unsigned offset)
-{
-       u8 ret;
-       int err;
-
-       err = skb_copy_bits(skb, offset, &ret, 1);
-
-       return (u64)err << 32 | ret;
-}
-
-static u64 jit_get_skb_h(struct sk_buff *skb, unsigned offset)
-{
-       u16 ret;
-       int err;
-
-       err = skb_copy_bits(skb, offset, &ret, 2);
-
-       return (u64)err << 32 | ntohs(ret);
-}
-
-static u64 jit_get_skb_w(struct sk_buff *skb, unsigned offset)
-{
-       u32 ret;
-       int err;
-
-       err = skb_copy_bits(skb, offset, &ret, 4);
-
-       return (u64)err << 32 | ntohl(ret);
-}
+#define CHOOSE_LOAD_FUNC(K, func) \
+       ((int)K < 0 ? ((int)K >= SKF_LL_OFF ? func##_negative : func) : \
+        func##_positive)
 
 static int build_body(struct jit_ctx *ctx)
 {
-       void *load_func[] = {jit_get_skb_b, jit_get_skb_h, jit_get_skb_w};
        const struct bpf_prog *prog = ctx->skf;
        const struct sock_filter *inst;
-       unsigned int i, off, load_order, condt;
+       unsigned int i, off, condt;
        u32 k, b_off __maybe_unused;
+       u8 (*sk_load_func)(unsigned long *skb, int offset);
 
        for (i = 0; i < prog->len; i++) {
                u16 code;
@@ -748,71 +703,46 @@ static int build_body(struct jit_ctx *ctx)
                        break;
                case BPF_LD | BPF_W | BPF_ABS:
                        /* A <- P[k:4] */
-                       load_order = 2;
+                       sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_word);
                        goto load;
                case BPF_LD | BPF_H | BPF_ABS:
                        /* A <- P[k:2] */
-                       load_order = 1;
+                       sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_half);
                        goto load;
                case BPF_LD | BPF_B | BPF_ABS:
                        /* A <- P[k:1] */
-                       load_order = 0;
+                       sk_load_func = CHOOSE_LOAD_FUNC(k, sk_load_byte);
 load:
-                       /* the interpreter will deal with the negative K */
-                       if ((int)k < 0)
-                               return -ENOTSUPP;
-
                        emit_load_imm(r_off, k, ctx);
 load_common:
-                       /*
-                        * We may got here from the indirect loads so
-                        * return if offset is negative.
-                        */
-                       emit_slt(r_s0, r_off, r_zero, ctx);
-                       emit_bcond(MIPS_COND_NE, r_s0, r_zero,
-                                  b_imm(prog->len, ctx), ctx);
-                       emit_reg_move(r_ret, r_zero, ctx);
-
                        ctx->flags |= SEEN_CALL | SEEN_OFF |
-                               SEEN_SKB | SEEN_A;
+                               SEEN_SKB | SEEN_A | SEEN_SKB_DATA;
 
-                       emit_load_func(r_s0, (ptr)load_func[load_order],
-                                     ctx);
+                       emit_load_func(r_s0, (ptr)sk_load_func, ctx);
                        emit_reg_move(MIPS_R_A0, r_skb, ctx);
                        emit_jalr(MIPS_R_RA, r_s0, ctx);
                        /* Load second argument to delay slot */
                        emit_reg_move(MIPS_R_A1, r_off, ctx);
                        /* Check the error value */
-                       if (config_enabled(CONFIG_64BIT)) {
-                               /* Get error code from the top 32-bits */
-                               emit_dsrl32(r_s0, r_val, 0, ctx);
-                               /* Branch to 3 instructions ahead */
-                               emit_bcond(MIPS_COND_NE, r_s0, r_zero, 3 << 2,
-                                          ctx);
-                       } else {
-                               /* Branch to 3 instructions ahead */
-                               emit_bcond(MIPS_COND_NE, r_err, r_zero, 3 << 2,
-                                          ctx);
-                       }
-                       emit_nop(ctx);
-                       /* We are good */
-                       emit_b(b_imm(i + 1, ctx), ctx);
-                       emit_jit_reg_move(r_A, r_val, ctx);
+                       emit_bcond(MIPS_COND_EQ, r_ret, 0, b_imm(i + 1, ctx),
+                                  ctx);
+                       /* Load return register on DS for failures */
+                       emit_reg_move(r_ret, r_zero, ctx);
                        /* Return with error */
                        emit_b(b_imm(prog->len, ctx), ctx);
-                       emit_reg_move(r_ret, r_zero, ctx);
+                       emit_nop(ctx);
                        break;
                case BPF_LD | BPF_W | BPF_IND:
                        /* A <- P[X + k:4] */
-                       load_order = 2;
+                       sk_load_func = sk_load_word;
                        goto load_ind;
                case BPF_LD | BPF_H | BPF_IND:
                        /* A <- P[X + k:2] */
-                       load_order = 1;
+                       sk_load_func = sk_load_half;
                        goto load_ind;
                case BPF_LD | BPF_B | BPF_IND:
                        /* A <- P[X + k:1] */
-                       load_order = 0;
+                       sk_load_func = sk_load_byte;
 load_ind:
                        ctx->flags |= SEEN_OFF | SEEN_X;
                        emit_addiu(r_off, r_X, k, ctx);
@@ -834,14 +764,10 @@ load_ind:
                        emit_load(r_X, r_skb, off, ctx);
                        break;
                case BPF_LDX | BPF_B | BPF_MSH:
-                       /* the interpreter will deal with the negative K */
-                       if ((int)k < 0)
-                               return -ENOTSUPP;
-
                        /* X <- 4 * (P[k:1] & 0xf) */
                        ctx->flags |= SEEN_X | SEEN_CALL | SEEN_SKB;
                        /* Load offset to a1 */
-                       emit_load_func(r_s0, (ptr)jit_get_skb_b, ctx);
+                       emit_load_func(r_s0, (ptr)sk_load_byte, ctx);
                        /*
                         * This may emit two instructions so it may not fit
                         * in the delay slot. So use a0 in the delay slot.
@@ -850,25 +776,15 @@ load_ind:
                        emit_jalr(MIPS_R_RA, r_s0, ctx);
                        emit_reg_move(MIPS_R_A0, r_skb, ctx); /* delay slot */
                        /* Check the error value */
-                       if (config_enabled(CONFIG_64BIT)) {
-                               /* Top 32-bits of $v0 on 64-bit */
-                               emit_dsrl32(r_s0, r_val, 0, ctx);
-                               emit_bcond(MIPS_COND_NE, r_s0, r_zero,
-                                          3 << 2, ctx);
-                       } else {
-                               emit_bcond(MIPS_COND_NE, r_err, r_zero,
-                                          3 << 2, ctx);
-                       }
-                       /* No need for delay slot */
+                       emit_bcond(MIPS_COND_NE, r_ret, 0,
+                                  b_imm(prog->len, ctx), ctx);
+                       emit_reg_move(r_ret, r_zero, ctx);
                        /* We are good */
                        /* X <- P[1:K] & 0xf */
-                       emit_andi(r_X, r_val, 0xf, ctx);
+                       emit_andi(r_X, r_A, 0xf, ctx);
                        /* X << 2 */
                        emit_b(b_imm(i + 1, ctx), ctx);
                        emit_sll(r_X, r_X, 2, ctx); /* delay slot */
-                       /* Return with error */
-                       emit_b(b_imm(prog->len, ctx), ctx);
-                       emit_load_imm(r_ret, 0, ctx); /* delay slot */
                        break;
                case BPF_ST:
                        /* M[k] <- A */
@@ -942,7 +858,7 @@ load_ind:
                        /* Check if r_X is zero */
                        emit_bcond(MIPS_COND_EQ, r_X, r_zero,
                                   b_imm(prog->len, ctx), ctx);
-                       emit_load_imm(r_val, 0, ctx); /* delay slot */
+                       emit_load_imm(r_ret, 0, ctx); /* delay slot */
                        emit_div(r_A, r_X, ctx);
                        break;
                case BPF_ALU | BPF_MOD | BPF_X:
@@ -951,7 +867,7 @@ load_ind:
                        /* Check if r_X is zero */
                        emit_bcond(MIPS_COND_EQ, r_X, r_zero,
                                   b_imm(prog->len, ctx), ctx);
-                       emit_load_imm(r_val, 0, ctx); /* delay slot */
+                       emit_load_imm(r_ret, 0, ctx); /* delay slot */
                        emit_mod(r_A, r_X, ctx);
                        break;
                case BPF_ALU | BPF_OR | BPF_K:
This page took 0.027901 seconds and 5 git commands to generate.