GNU Linux-libre 4.4.292-gnu1
[releases.git] / arch / s390 / net / bpf_jit.S
1 /*
2  * BPF Jit compiler for s390, help functions.
3  *
4  * Copyright IBM Corp. 2012,2015
5  *
6  * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
7  *            Michael Holzheu <holzheu@linux.vnet.ibm.com>
8  */
9
10 #include <linux/linkage.h>
11 #include <asm/nospec-insn.h>
12 #include "bpf_jit.h"
13
14 /*
15  * Calling convention:
16  * registers %r7-%r10, %r11,%r13, and %r15 are call saved
17  *
18  * Input (64 bit):
19  *   %r3 (%b2) = offset into skb data
20  *   %r6 (%b5) = return address
21  *   %r7 (%b6) = skb pointer
22  *   %r12      = skb data pointer
23  *
24  * Output:
25  *   %r14= %b0 = return value (read skb value)
26  *
27  * Work registers: %r2,%r4,%r5,%r14
28  *
29  * skb_copy_bits takes 4 parameters:
30  *   %r2 = skb pointer
31  *   %r3 = offset into skb data
32  *   %r4 = pointer to temp buffer
33  *   %r5 = length to copy
34  *   Return value in %r2: 0 = ok
35  *
36  * bpf_internal_load_pointer_neg_helper takes 3 parameters:
37  *   %r2 = skb pointer
38  *   %r3 = offset into data
39  *   %r4 = length to copy
40  *   Return value in %r2: Pointer to data
41  */
42
43 #define SKF_MAX_NEG_OFF -0x200000       /* SKF_LL_OFF from filter.h */
44
45 /*
46  * Load SIZE bytes from SKB
47  */
48 #define sk_load_common(NAME, SIZE, LOAD)                                \
49 ENTRY(sk_load_##NAME);                                                  \
50         ltgr    %r3,%r3;                /* Is offset negative? */       \
51         jl      sk_load_##NAME##_slow_neg;                              \
52 ENTRY(sk_load_##NAME##_pos);                                            \
53         aghi    %r3,SIZE;               /* Offset + SIZE */             \
54         clg     %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */     \
55         jh      sk_load_##NAME##_slow;                                  \
56         LOAD    %r14,-SIZE(%r3,%r12);   /* Get data from skb */         \
57         B_EX    OFF_OK,%r6;             /* Return */                    \
58                                                                         \
59 sk_load_##NAME##_slow:;                                                 \
60         lgr     %r2,%r7;                /* Arg1 = skb pointer */        \
61         aghi    %r3,-SIZE;              /* Arg2 = offset */             \
62         la      %r4,STK_OFF_TMP(%r15);  /* Arg3 = temp bufffer */       \
63         lghi    %r5,SIZE;               /* Arg4 = size */               \
64         brasl   %r14,skb_copy_bits;     /* Get data from skb */         \
65         LOAD    %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */    \
66         ltgr    %r2,%r2;                /* Set cc to (%r2 != 0) */      \
67         BR_EX   %r6;                    /* Return */
68
69 sk_load_common(word, 4, llgf)   /* r14 = *(u32 *) (skb->data+offset) */
70 sk_load_common(half, 2, llgh)   /* r14 = *(u16 *) (skb->data+offset) */
71
72         GEN_BR_THUNK %r6
73         GEN_B_THUNK OFF_OK,%r6
74
75 /*
76  * Load 1 byte from SKB (optimized version)
77  */
78         /* r14 = *(u8 *) (skb->data+offset) */
79 ENTRY(sk_load_byte)
80         ltgr    %r3,%r3                 # Is offset negative?
81         jl      sk_load_byte_slow_neg
82 ENTRY(sk_load_byte_pos)
83         clg     %r3,STK_OFF_HLEN(%r15)  # Offset >= hlen?
84         jnl     sk_load_byte_slow
85         llgc    %r14,0(%r3,%r12)        # Get byte from skb
86         B_EX    OFF_OK,%r6              # Return OK
87
88 sk_load_byte_slow:
89         lgr     %r2,%r7                 # Arg1 = skb pointer
90                                         # Arg2 = offset
91         la      %r4,STK_OFF_TMP(%r15)   # Arg3 = pointer to temp buffer
92         lghi    %r5,1                   # Arg4 = size (1 byte)
93         brasl   %r14,skb_copy_bits      # Get data from skb
94         llgc    %r14,STK_OFF_TMP(%r15)  # Load result from temp buffer
95         ltgr    %r2,%r2                 # Set cc to (%r2 != 0)
96         BR_EX   %r6                     # Return cc
97
98 #define sk_negative_common(NAME, SIZE, LOAD)                            \
99 sk_load_##NAME##_slow_neg:;                                             \
100         cgfi    %r3,SKF_MAX_NEG_OFF;                                    \
101         jl      bpf_error;                                              \
102         lgr     %r2,%r7;                /* Arg1 = skb pointer */        \
103                                         /* Arg2 = offset */             \
104         lghi    %r4,SIZE;               /* Arg3 = size */               \
105         brasl   %r14,bpf_internal_load_pointer_neg_helper;              \
106         ltgr    %r2,%r2;                                                \
107         jz      bpf_error;                                              \
108         LOAD    %r14,0(%r2);            /* Get data from pointer */     \
109         xr      %r3,%r3;                /* Set cc to zero */            \
110         BR_EX   %r6;                    /* Return cc */
111
112 sk_negative_common(word, 4, llgf)
113 sk_negative_common(half, 2, llgh)
114 sk_negative_common(byte, 1, llgc)
115
116 bpf_error:
117 # force a return 0 from jit handler
118         ltgr    %r15,%r15       # Set condition code
119         BR_EX   %r6