/* * BPF Jit compiler for s390, help functions. * * Copyright IBM Corp. 2012,2015 * * Author(s): Martin Schwidefsky <schwidefsky@de.ibm.com> * Michael Holzheu <holzheu@linux.vnet.ibm.com> */ #include <linux/linkage.h> #include "bpf_jit.h" /* * Calling convention: * registers %r7-%r10, %r11,%r13, and %r15 are call saved * * Input (64 bit): * %r3 (%b2) = offset into skb data * %r6 (%b5) = return address * %r7 (%b6) = skb pointer * %r12 = skb data pointer * * Output: * %r14= %b0 = return value (read skb value) * * Work registers: %r2,%r4,%r5,%r14 * * skb_copy_bits takes 4 parameters: * %r2 = skb pointer * %r3 = offset into skb data * %r4 = pointer to temp buffer * %r5 = length to copy * Return value in %r2: 0 = ok * * bpf_internal_load_pointer_neg_helper takes 3 parameters: * %r2 = skb pointer * %r3 = offset into data * %r4 = length to copy * Return value in %r2: Pointer to data */ #define SKF_MAX_NEG_OFF -0x200000 /* SKF_LL_OFF from filter.h */ /* * Load SIZE bytes from SKB */ #define sk_load_common(NAME, SIZE, LOAD) \ ENTRY(sk_load_##NAME); \ ltgr %r3,%r3; /* Is offset negative? */ \ jl sk_load_##NAME##_slow_neg; \ ENTRY(sk_load_##NAME##_pos); \ aghi %r3,SIZE; /* Offset + SIZE */ \ clg %r3,STK_OFF_HLEN(%r15); /* Offset + SIZE > hlen? */ \ jh sk_load_##NAME##_slow; \ LOAD %r14,-SIZE(%r3,%r12); /* Get data from skb */ \ b OFF_OK(%r6); /* Return */ \ \ sk_load_##NAME##_slow:; \ lgr %r2,%r7; /* Arg1 = skb pointer */ \ aghi %r3,-SIZE; /* Arg2 = offset */ \ la %r4,STK_OFF_TMP(%r15); /* Arg3 = temp bufffer */ \ lghi %r5,SIZE; /* Arg4 = size */ \ brasl %r14,skb_copy_bits; /* Get data from skb */ \ LOAD %r14,STK_OFF_TMP(%r15); /* Load from temp bufffer */ \ ltgr %r2,%r2; /* Set cc to (%r2 != 0) */ \ br %r6; /* Return */ sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ /* * Load 1 byte from SKB (optimized version) */ /* r14 = *(u8 *) (skb->data+offset) */ ENTRY(sk_load_byte) ltgr %r3,%r3 # Is offset negative? jl sk_load_byte_slow_neg ENTRY(sk_load_byte_pos) clg %r3,STK_OFF_HLEN(%r15) # Offset >= hlen? jnl sk_load_byte_slow llgc %r14,0(%r3,%r12) # Get byte from skb b OFF_OK(%r6) # Return OK sk_load_byte_slow: lgr %r2,%r7 # Arg1 = skb pointer # Arg2 = offset la %r4,STK_OFF_TMP(%r15) # Arg3 = pointer to temp buffer lghi %r5,1 # Arg4 = size (1 byte) brasl %r14,skb_copy_bits # Get data from skb llgc %r14,STK_OFF_TMP(%r15) # Load result from temp buffer ltgr %r2,%r2 # Set cc to (%r2 != 0) br %r6 # Return cc #define sk_negative_common(NAME, SIZE, LOAD) \ sk_load_##NAME##_slow_neg:; \ cgfi %r3,SKF_MAX_NEG_OFF; \ jl bpf_error; \ lgr %r2,%r7; /* Arg1 = skb pointer */ \ /* Arg2 = offset */ \ lghi %r4,SIZE; /* Arg3 = size */ \ brasl %r14,bpf_internal_load_pointer_neg_helper; \ ltgr %r2,%r2; \ jz bpf_error; \ LOAD %r14,0(%r2); /* Get data from pointer */ \ xr %r3,%r3; /* Set cc to zero */ \ br %r6; /* Return cc */ sk_negative_common(word, 4, llgf) sk_negative_common(half, 2, llgh) sk_negative_common(byte, 1, llgc) bpf_error: # force a return 0 from jit handler ltgr %r15,%r15 # Set condition code br %r6