Merge tag 'for_linus' of git://git.kernel.org/pub/scm/linux/kernel/git/mst/vhost
[cris-mirror.git] / arch / s390 / net / bpf_jit.S
blob25bb4643c4f46cc3bcbf904e9fc257a3145f4221
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  */
11 #include <linux/linkage.h>
12 #include "bpf_jit.h"
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  */
43 #define SKF_MAX_NEG_OFF -0x200000       /* SKF_LL_OFF from filter.h */
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       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      %r6;                    /* Return */
69 sk_load_common(word, 4, llgf)   /* r14 = *(u32 *) (skb->data+offset) */
70 sk_load_common(half, 2, llgh)   /* r14 = *(u16 *) (skb->data+offset) */
73  * Load 1 byte from SKB (optimized version)
74  */
75         /* r14 = *(u8 *) (skb->data+offset) */
76 ENTRY(sk_load_byte)
77         ltgr    %r3,%r3                 # Is offset negative?
78         jl      sk_load_byte_slow_neg
79 ENTRY(sk_load_byte_pos)
80         clg     %r3,STK_OFF_HLEN(%r15)  # Offset >= hlen?
81         jnl     sk_load_byte_slow
82         llgc    %r14,0(%r3,%r12)        # Get byte from skb
83         b       OFF_OK(%r6)             # Return OK
85 sk_load_byte_slow:
86         lgr     %r2,%r7                 # Arg1 = skb pointer
87                                         # Arg2 = offset
88         la      %r4,STK_OFF_TMP(%r15)   # Arg3 = pointer to temp buffer
89         lghi    %r5,1                   # Arg4 = size (1 byte)
90         brasl   %r14,skb_copy_bits      # Get data from skb
91         llgc    %r14,STK_OFF_TMP(%r15)  # Load result from temp buffer
92         ltgr    %r2,%r2                 # Set cc to (%r2 != 0)
93         br      %r6                     # Return cc
95 #define sk_negative_common(NAME, SIZE, LOAD)                            \
96 sk_load_##NAME##_slow_neg:;                                             \
97         cgfi    %r3,SKF_MAX_NEG_OFF;                                    \
98         jl      bpf_error;                                              \
99         lgr     %r2,%r7;                /* Arg1 = skb pointer */        \
100                                         /* Arg2 = offset */             \
101         lghi    %r4,SIZE;               /* Arg3 = size */               \
102         brasl   %r14,bpf_internal_load_pointer_neg_helper;              \
103         ltgr    %r2,%r2;                                                \
104         jz      bpf_error;                                              \
105         LOAD    %r14,0(%r2);            /* Get data from pointer */     \
106         xr      %r3,%r3;                /* Set cc to zero */            \
107         br      %r6;                    /* Return cc */
109 sk_negative_common(word, 4, llgf)
110 sk_negative_common(half, 2, llgh)
111 sk_negative_common(byte, 1, llgc)
113 bpf_error:
114 # force a return 0 from jit handler
115         ltgr    %r15,%r15       # Set condition code
116         br      %r6