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