2 * bpf_jib_asm.S: Packet/header access helper functions for MIPS/MIPS64 BPF
5 * Copyright (C) 2015 Imagination Technologies Ltd.
6 * Author: Markos Chandras <markos.chandras@imgtec.com>
8 * This program is free software; you can redistribute it and/or modify it
9 * under the terms of the GNU General Public License as published by the
10 * Free Software Foundation; version 2 of the License.
14 #include <asm/isa-rev.h>
15 #include <asm/regdef.h>
20 * r_skb_hl skb header length
22 * r_off(a1) offset register
28 * r_s0 Scratch register 0
29 * r_s1 Scratch register 1
33 * a1: offset (imm or imm + X)
35 * All non-BPF-ABI registers are free for use. On return, we only
36 * care about r_ret. The BPF-ABI registers are assumed to remain
37 * unmodified during the entire filter operation.
42 #define SKF_LL_OFF (-0x200000) /* Can't include linux/filter.h in assembly */
44 /* We know better :) so prevent assembler reordering etc */
47 #define is_offset_negative(TYPE) \
48 /* If offset is negative we have more work to do */ \
50 bgtz t0, bpf_slow_path_##TYPE##_neg; \
51 /* Be careful what follows in DS. */
53 #define is_offset_in_header(SIZE, TYPE) \
54 /* Reading from header? */ \
55 addiu $r_s0, $r_skb_hl, -SIZE; \
56 slt t0, $r_s0, offset; \
57 bgtz t0, bpf_slow_path_##TYPE; \
60 is_offset_negative(word)
61 FEXPORT(sk_load_word_positive)
62 is_offset_in_header(4, word)
63 /* Offset within header boundaries */
64 PTR_ADDU t1, $r_skb_data, offset
68 #ifdef CONFIG_CPU_LITTLE_ENDIAN
69 # if MIPS_ISA_REV >= 2
89 is_offset_negative(half)
90 FEXPORT(sk_load_half_positive)
91 is_offset_in_header(2, half)
92 /* Offset within header boundaries */
93 PTR_ADDU t1, $r_skb_data, offset
95 #ifdef CONFIG_CPU_LITTLE_ENDIAN
96 # if MIPS_ISA_REV >= 2
110 is_offset_negative(byte)
111 FEXPORT(sk_load_byte_positive)
112 is_offset_in_header(1, byte)
113 /* Offset within header boundaries */
114 PTR_ADDU t1, $r_skb_data, offset
121 * call skb_copy_bits:
122 * (prototype in linux/skbuff.h)
124 * int skb_copy_bits(sk_buff *skb, int offset, void *to, int len)
126 * o32 mandates we leave 4 spaces for argument registers in case
127 * the callee needs to use them. Even though we don't care about
128 * the argument registers ourselves, we need to allocate that space
129 * to remain ABI compliant since the callee may want to use that space.
130 * We also allocate 2 more spaces for $r_ra and our return register (*to).
132 * n64 is a bit different. The *caller* will allocate the space to preserve
133 * the arguments. So in 64-bit kernels, we allocate the 4-arg space for no
134 * good reason but it does not matter that much really.
136 * (void *to) is returned in r_s0
139 #ifdef CONFIG_CPU_LITTLE_ENDIAN
140 #define DS_OFFSET(SIZE) (4 * SZREG)
142 #define DS_OFFSET(SIZE) ((4 * SZREG) + (4 - SIZE))
144 #define bpf_slow_path_common(SIZE) \
145 /* Quick check. Are we within reasonable boundaries? */ \
146 LONG_ADDIU $r_s1, $r_skb_len, -SIZE; \
147 sltu $r_s0, offset, $r_s1; \
149 /* Load 4th argument in DS */ \
150 LONG_ADDIU a3, zero, SIZE; \
151 PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
152 PTR_LA t0, skb_copy_bits; \
153 PTR_S $r_ra, (5 * SZREG)($r_sp); \
154 /* Assign low slot to a2 */ \
155 PTR_ADDIU a2, $r_sp, DS_OFFSET(SIZE); \
157 /* Reset our destination slot (DS but it's ok) */ \
158 INT_S zero, (4 * SZREG)($r_sp); \
160 * skb_copy_bits returns 0 on success and -EFAULT \
161 * on error. Our data live in a2. Do not bother with \
162 * our data if an error has been returned. \
164 /* Restore our frame */ \
165 PTR_L $r_ra, (5 * SZREG)($r_sp); \
166 INT_L $r_s0, (4 * SZREG)($r_sp); \
168 PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
171 NESTED(bpf_slow_path_word, (6 * SZREG), $r_sp)
172 bpf_slow_path_common(4)
173 #ifdef CONFIG_CPU_LITTLE_ENDIAN
174 # if MIPS_ISA_REV >= 2
184 andi t1, $r_s0, 0xff00
195 END(bpf_slow_path_word)
197 NESTED(bpf_slow_path_half, (6 * SZREG), $r_sp)
198 bpf_slow_path_common(2)
199 #ifdef CONFIG_CPU_LITTLE_ENDIAN
200 # if MIPS_ISA_REV >= 2
205 andi t1, $r_s0, 0xff00
216 END(bpf_slow_path_half)
218 NESTED(bpf_slow_path_byte, (6 * SZREG), $r_sp)
219 bpf_slow_path_common(1)
223 END(bpf_slow_path_byte)
226 * Negative entry points
228 .macro bpf_is_end_of_data
230 /* Reading link layer data? */
233 /* Be careful what follows in DS. */
236 * call skb_copy_bits:
237 * (prototype in linux/filter.h)
239 * void *bpf_internal_load_pointer_neg_helper(const struct sk_buff *skb,
240 * int k, unsigned int size)
242 * see above (bpf_slow_path_common) for ABI restrictions
244 #define bpf_negative_common(SIZE) \
245 PTR_ADDIU $r_sp, $r_sp, -(6 * SZREG); \
246 PTR_LA t0, bpf_internal_load_pointer_neg_helper; \
247 PTR_S $r_ra, (5 * SZREG)($r_sp); \
250 PTR_L $r_ra, (5 * SZREG)($r_sp); \
251 /* Check return pointer */ \
253 PTR_ADDIU $r_sp, $r_sp, 6 * SZREG; \
254 /* Preserve our pointer */ \
256 /* Set return value */ \
259 bpf_slow_path_word_neg:
261 NESTED(sk_load_word_negative, (6 * SZREG), $r_sp)
262 bpf_negative_common(4)
265 END(sk_load_word_negative)
267 bpf_slow_path_half_neg:
269 NESTED(sk_load_half_negative, (6 * SZREG), $r_sp)
270 bpf_negative_common(2)
273 END(sk_load_half_negative)
275 bpf_slow_path_byte_neg:
277 NESTED(sk_load_byte_negative, (6 * SZREG), $r_sp)
278 bpf_negative_common(1)
281 END(sk_load_byte_negative)
285 addiu $r_ret, zero, 1