blob: 25bb4643c4f46cc3bcbf904e9fc257a3145f4221 [file] [log] [blame]
Greg Kroah-Hartmanb2441312017-11-01 15:07:57 +01001/* SPDX-License-Identifier: GPL-2.0 */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +02002/*
3 * BPF Jit compiler for s390, help functions.
4 *
Michael Holzheu05462312015-04-01 16:08:32 +02005 * Copyright IBM Corp. 2012,2015
Martin Schwidefskyc10302e2012-07-31 16:23:59 +02006 *
7 * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com>
Michael Holzheu05462312015-04-01 16:08:32 +02008 * Michael Holzheu <holzheu@linux.vnet.ibm.com>
Martin Schwidefskyc10302e2012-07-31 16:23:59 +02009 */
Michael Holzheu05462312015-04-01 16:08:32 +020010
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020011#include <linux/linkage.h>
Michael Holzheu05462312015-04-01 16:08:32 +020012#include "bpf_jit.h"
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020013
14/*
15 * Calling convention:
Michael Holzheu05462312015-04-01 16:08:32 +020016 * 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
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020028 *
29 * skb_copy_bits takes 4 parameters:
30 * %r2 = skb pointer
31 * %r3 = offset into skb data
Michael Holzheudb9aa8f2015-01-15 10:20:28 +010032 * %r4 = pointer to temp buffer
33 * %r5 = length to copy
Michael Holzheu05462312015-04-01 16:08:32 +020034 * 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
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020041 */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020042
Michael Holzheu05462312015-04-01 16:08:32 +020043#define SKF_MAX_NEG_OFF -0x200000 /* SKF_LL_OFF from filter.h */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020044
Michael Holzheu05462312015-04-01 16:08:32 +020045/*
46 * Load SIZE bytes from SKB
47 */
48#define sk_load_common(NAME, SIZE, LOAD) \
49ENTRY(sk_load_##NAME); \
50 ltgr %r3,%r3; /* Is offset negative? */ \
51 jl sk_load_##NAME##_slow_neg; \
52ENTRY(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 \
59sk_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 */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020068
Michael Holzheu05462312015-04-01 16:08:32 +020069sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */
70sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020071
Michael Holzheu05462312015-04-01 16:08:32 +020072/*
73 * Load 1 byte from SKB (optimized version)
74 */
75 /* r14 = *(u8 *) (skb->data+offset) */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020076ENTRY(sk_load_byte)
Michael Holzheu05462312015-04-01 16:08:32 +020077 ltgr %r3,%r3 # Is offset negative?
78 jl sk_load_byte_slow_neg
79ENTRY(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
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020084
85sk_load_byte_slow:
Michael Holzheu05462312015-04-01 16:08:32 +020086 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
Martin Schwidefskyc10302e2012-07-31 16:23:59 +020094
Michael Holzheu05462312015-04-01 16:08:32 +020095#define sk_negative_common(NAME, SIZE, LOAD) \
96sk_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 */
Martin Schwidefskyc10302e2012-07-31 16:23:59 +0200108
Michael Holzheu05462312015-04-01 16:08:32 +0200109sk_negative_common(word, 4, llgf)
110sk_negative_common(half, 2, llgh)
111sk_negative_common(byte, 1, llgc)
112
113bpf_error:
114# force a return 0 from jit handler
115 ltgr %r15,%r15 # Set condition code
116 br %r6