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 */ 9 10#include <linux/linkage.h> 11#include "bpf_jit.h" 12 13/* 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 */ 41 42#define SKF_MAX_NEG_OFF -0x200000 /* SKF_LL_OFF from filter.h */ 43 44/* 45 * Load SIZE bytes from SKB 46 */ 47#define sk_load_common(NAME, SIZE, LOAD) \ 48ENTRY(sk_load_##NAME); \ 49 ltgr %r3,%r3; /* Is offset negative? */ \ 50 jl sk_load_##NAME##_slow_neg; \ 51ENTRY(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 \ 58sk_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 */ 67 68sk_load_common(word, 4, llgf) /* r14 = *(u32 *) (skb->data+offset) */ 69sk_load_common(half, 2, llgh) /* r14 = *(u16 *) (skb->data+offset) */ 70 71/* 72 * Load 1 byte from SKB (optimized version) 73 */ 74 /* r14 = *(u8 *) (skb->data+offset) */ 75ENTRY(sk_load_byte) 76 ltgr %r3,%r3 # Is offset negative? 77 jl sk_load_byte_slow_neg 78ENTRY(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 83 84sk_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 93 94#define sk_negative_common(NAME, SIZE, LOAD) \ 95sk_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 */ 107 108sk_negative_common(word, 4, llgf) 109sk_negative_common(half, 2, llgh) 110sk_negative_common(byte, 1, llgc) 111 112bpf_error: 113# force a return 0 from jit handler 114 ltgr %r15,%r15 # Set condition code 115 br %r6 116