Linux 4.8-rc8
[linux/fpc-iii.git] / arch / s390 / net / bpf_jit.S
bloba1c917d881ec41056f8e80cac7c9736f66ffa9a2
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  */
10 #include <linux/linkage.h>
11 #include "bpf_jit.h"
14  * Calling convention:
15  * registers %r7-%r10, %r11,%r13, and %r15 are call saved
16  *
17  * Input (64 bit):
18  *   %r3 (%b2) = offset into skb data
19  *   %r6 (%b5) = return address
20  *   %r7 (%b6) = skb pointer
21  *   %r12      = skb data pointer
22  *
23  * Output:
24  *   %r14= %b0 = return value (read skb value)
25  *
26  * Work registers: %r2,%r4,%r5,%r14
27  *
28  * skb_copy_bits takes 4 parameters:
29  *   %r2 = skb pointer
30  *   %r3 = offset into skb data
31  *   %r4 = pointer to temp buffer
32  *   %r5 = length to copy
33  *   Return value in %r2: 0 = ok
34  *
35  * bpf_internal_load_pointer_neg_helper takes 3 parameters:
36  *   %r2 = skb pointer
37  *   %r3 = offset into data
38  *   %r4 = length to copy
39  *   Return value in %r2: Pointer to data
40  */
42 #define SKF_MAX_NEG_OFF -0x200000       /* SKF_LL_OFF from filter.h */
45  * Load SIZE bytes from SKB
46  */
47 #define sk_load_common(NAME, SIZE, LOAD)                                \
48 ENTRY(sk_load_##NAME);                                                  \
49         ltgr    %r3,%r3;                /* Is offset negative? */       \
50         jl      sk_load_##NAME##_slow_neg;                              \
51 ENTRY(sk_load_##NAME##_pos);                                            \
52         aghi    %r3,SIZE;               /* Offset + SIZE */             \
53         clg     %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */     \
54         jh      sk_load_##NAME##_slow;                                  \
55         LOAD    %r14,-SIZE(%r3,%r12);   /* Get data from skb */         \
56         b       OFF_OK(%r6);            /* Return */                    \
57                                                                         \
58 sk_load_##NAME##_slow:;                                                 \
59         lgr     %r2,%r7;                /* Arg1 = skb pointer */        \
60         aghi    %r3,-SIZE;              /* Arg2 = offset */             \
61         la      %r4,STK_OFF_TMP(%r15);  /* Arg3 = temp bufffer */       \
62         lghi    %r5,SIZE;               /* Arg4 = size */               \
63         brasl   %r14,skb_copy_bits;     /* Get data from skb */         \
64         LOAD    %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */    \
65         ltgr    %r2,%r2;                /* Set cc to (%r2 != 0) */      \
66         br      %r6;                    /* Return */
68 sk_load_common(word, 4, llgf)   /* r14 = *(u32 *) (skb->data+offset) */
69 sk_load_common(half, 2, llgh)   /* r14 = *(u16 *) (skb->data+offset) */
72  * Load 1 byte from SKB (optimized version)
73  */
74         /* r14 = *(u8 *) (skb->data+offset) */
75 ENTRY(sk_load_byte)
76         ltgr    %r3,%r3                 # Is offset negative?
77         jl      sk_load_byte_slow_neg
78 ENTRY(sk_load_byte_pos)
79         clg     %r3,STK_OFF_HLEN(%r15)  # Offset >= hlen?
80         jnl     sk_load_byte_slow
81         llgc    %r14,0(%r3,%r12)        # Get byte from skb
82         b       OFF_OK(%r6)             # Return OK
84 sk_load_byte_slow:
85         lgr     %r2,%r7                 # Arg1 = skb pointer
86                                         # Arg2 = offset
87         la      %r4,STK_OFF_TMP(%r15)   # Arg3 = pointer to temp buffer
88         lghi    %r5,1                   # Arg4 = size (1 byte)
89         brasl   %r14,skb_copy_bits      # Get data from skb
90         llgc    %r14,STK_OFF_TMP(%r15)  # Load result from temp buffer
91         ltgr    %r2,%r2                 # Set cc to (%r2 != 0)
92         br      %r6                     # Return cc
94 #define sk_negative_common(NAME, SIZE, LOAD)                            \
95 sk_load_##NAME##_slow_neg:;                                             \
96         cgfi    %r3,SKF_MAX_NEG_OFF;                                    \
97         jl      bpf_error;                                              \
98         lgr     %r2,%r7;                /* Arg1 = skb pointer */        \
99                                         /* Arg2 = offset */             \
100         lghi    %r4,SIZE;               /* Arg3 = size */               \
101         brasl   %r14,bpf_internal_load_pointer_neg_helper;              \
102         ltgr    %r2,%r2;                                                \
103         jz      bpf_error;                                              \
104         LOAD    %r14,0(%r2);            /* Get data from pointer */     \
105         xr      %r3,%r3;                /* Set cc to zero */            \
106         br      %r6;                    /* Return cc */
108 sk_negative_common(word, 4, llgf)
109 sk_negative_common(half, 2, llgh)
110 sk_negative_common(byte, 1, llgc)
112 bpf_error:
113 # force a return 0 from jit handler
114         ltgr    %r15,%r15       # Set condition code
115         br      %r6