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