xref: /freebsd/contrib/netbsd-tests/lib/libbpfjit/t_extmem.c (revision fed1ca4b719c56c930f2259d80663cd34be812bb)
1 /*	$NetBSD: t_extmem.c,v 1.3 2014/07/14 19:11:15 alnsn Exp $ */
2 
3 /*-
4  * Copyright (c) 2014 Alexander Nasonov.
5  * All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  *
11  * 1. Redistributions of source code must retain the above copyright
12  *    notice, this list of conditions and the following disclaimer.
13  * 2. Redistributions in binary form must reproduce the above copyright
14  *    notice, this list of conditions and the following disclaimer in
15  *    the documentation and/or other materials provided with the
16  *    distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22  * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23  * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31 
32 #include <sys/cdefs.h>
33 __RCSID("$NetBSD: t_extmem.c,v 1.3 2014/07/14 19:11:15 alnsn Exp $");
34 
35 #include <atf-c.h>
36 #include <stdint.h>
37 #include <string.h>
38 
39 #define __BPF_PRIVATE
40 #include <net/bpf.h>
41 #include <net/bpfjit.h>
42 
43 static uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44 
45 static const bpf_copfunc_t copfuncs[] = {
46 	&retM
47 };
48 
49 static const bpf_ctx_t ctx = {
50 	.copfuncs = copfuncs,
51 	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
52 	.extwords = 4,
53 	.preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3),
54 };
55 
56 static uint32_t
57 retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
58 {
59 
60 	return args->mem[(uintptr_t)args->arg];
61 }
62 
63 
64 ATF_TC(libbpfjit_extmem_load_default);
65 ATF_TC_HEAD(libbpfjit_extmem_load_default, tc)
66 {
67 	atf_tc_set_md_var(tc, "descr", "Test that external memory "
68 	    "is zero initialized by default");
69 }
70 
71 ATF_TC_BODY(libbpfjit_extmem_load_default, tc)
72 {
73 	static struct bpf_insn insns[] = {
74 		BPF_STMT(BPF_LD+BPF_MEM, 1),
75 		BPF_STMT(BPF_RET+BPF_A, 0)
76 	};
77 
78 	bpfjit_func_t code;
79 	uint8_t pkt[1] = { 0 };
80 	uint32_t mem[ctx.extwords];
81 
82 	/* Pre-inited words. */
83 	mem[0] = 0;
84 	mem[3] = 3;
85 
86 	bpf_args_t args = {
87 		.pkt = pkt,
88 		.buflen = sizeof(pkt),
89 		.wirelen = sizeof(pkt),
90 		.mem = mem,
91 	};
92 
93 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
94 
95 	code = bpfjit_generate_code(&ctx, insns, insn_count);
96 	ATF_REQUIRE(code != NULL);
97 
98 	ATF_CHECK(code(&ctx, &args) == 0);
99 
100 	bpfjit_free_code(code);
101 }
102 
103 ATF_TC(libbpfjit_extmem_load_preinited);
104 ATF_TC_HEAD(libbpfjit_extmem_load_preinited, tc)
105 {
106 	atf_tc_set_md_var(tc, "descr", "Test a load of external "
107 	    "pre-initialized memory");
108 }
109 
110 ATF_TC_BODY(libbpfjit_extmem_load_preinited, tc)
111 {
112 	static struct bpf_insn insns[] = {
113 		BPF_STMT(BPF_LD+BPF_MEM, 3),
114 		BPF_STMT(BPF_RET+BPF_A, 0)
115 	};
116 
117 	bpfjit_func_t code;
118 	uint8_t pkt[1] = { 0 };
119 	uint32_t mem[ctx.extwords];
120 
121 	/* Pre-inited words. */
122 	mem[0] = 0;
123 	mem[3] = 3;
124 
125 	bpf_args_t args = {
126 		.pkt = pkt,
127 		.buflen = sizeof(pkt),
128 		.wirelen = sizeof(pkt),
129 		.mem = mem,
130 	};
131 
132 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
133 
134 	code = bpfjit_generate_code(&ctx, insns, insn_count);
135 	ATF_REQUIRE(code != NULL);
136 
137 	ATF_CHECK(code(&ctx, &args) == 3);
138 
139 	bpfjit_free_code(code);
140 }
141 
142 ATF_TC(libbpfjit_extmem_invalid_load);
143 ATF_TC_HEAD(libbpfjit_extmem_invalid_load, tc)
144 {
145 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range load "
146 	    "fails validation");
147 }
148 
149 ATF_TC_BODY(libbpfjit_extmem_invalid_load, tc)
150 {
151 	static struct bpf_insn insns[] = {
152 		BPF_STMT(BPF_LD+BPF_MEM, 4),
153 		BPF_STMT(BPF_RET+BPF_A, 0)
154 	};
155 
156 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
157 
158 	ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
159 }
160 
161 ATF_TC(libbpfjit_extmem_store);
162 ATF_TC_HEAD(libbpfjit_extmem_store, tc)
163 {
164 	atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
165 }
166 
167 ATF_TC_BODY(libbpfjit_extmem_store, tc)
168 {
169 	static struct bpf_insn insns[] = {
170 		BPF_STMT(BPF_LD+BPF_IMM, 1),        /* A <- 1     */
171 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
172 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
173 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
174 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
175 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
176 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
177 	};
178 
179 	bpfjit_func_t code;
180 	uint8_t pkt[1] = { 0 };
181 	uint32_t mem[ctx.extwords];
182 
183 	/* Pre-inited words. */
184 	mem[0] = 0;
185 	mem[3] = 7;
186 
187 	mem[1] = mem[2] = 0xdeadbeef;
188 
189 	bpf_args_t args = {
190 		.pkt = pkt,
191 		.buflen = sizeof(pkt),
192 		.wirelen = sizeof(pkt),
193 		.mem = mem,
194 	};
195 
196 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
197 
198 	code = bpfjit_generate_code(&ctx, insns, insn_count);
199 	ATF_REQUIRE(code != NULL);
200 
201 	ATF_CHECK(code(&ctx, &args) == 3);
202 
203 	bpfjit_free_code(code);
204 
205 	ATF_CHECK(mem[0] == 0);
206 	ATF_CHECK(mem[1] == 1);
207 	ATF_CHECK(mem[2] == 2);
208 	ATF_CHECK(mem[3] == 3);
209 }
210 
211 ATF_TC(libbpfjit_extmem_side_effect);
212 ATF_TC_HEAD(libbpfjit_extmem_side_effect, tc)
213 {
214 	atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t "
215 	    "skip stores to external memory");
216 }
217 
218 ATF_TC_BODY(libbpfjit_extmem_side_effect, tc)
219 {
220 	static struct bpf_insn insns[] = {
221 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),  /* A <- P[0]  */
222 		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
223 		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
224 		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
225 		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
226 		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
227 		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */
228 		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
229 	};
230 
231 	bpfjit_func_t code;
232 	uint8_t pkt[1] = { 1 };
233 	uint32_t mem[ctx.extwords];
234 
235 	/* Pre-inited words. */
236 	mem[0] = 0;
237 	mem[3] = 7;
238 
239 	mem[1] = mem[2] = 0xdeadbeef;
240 
241 	bpf_args_t args = {
242 		.pkt = pkt,
243 		.buflen = sizeof(pkt),
244 		.wirelen = sizeof(pkt),
245 		.mem = mem,
246 	};
247 
248 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
249 
250 	code = bpfjit_generate_code(&ctx, insns, insn_count);
251 	ATF_REQUIRE(code != NULL);
252 
253 	ATF_CHECK(code(&ctx, &args) == 0);
254 
255 	bpfjit_free_code(code);
256 
257 	ATF_CHECK(mem[0] == 0);
258 	ATF_CHECK(mem[1] == 1);
259 	ATF_CHECK(mem[2] == 2);
260 	ATF_CHECK(mem[3] == 3);
261 }
262 
263 ATF_TC(libbpfjit_extmem_invalid_store);
264 ATF_TC_HEAD(libbpfjit_extmem_invalid_store, tc)
265 {
266 	atf_tc_set_md_var(tc, "descr", "Test that out-of-range store "
267 	    "fails validation");
268 }
269 
270 ATF_TC_BODY(libbpfjit_extmem_invalid_store, tc)
271 {
272 	static struct bpf_insn insns[] = {
273 		BPF_STMT(BPF_ST, 4),
274 		BPF_STMT(BPF_RET+BPF_A, 0)
275 	};
276 
277 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
278 
279 	ATF_CHECK(bpfjit_generate_code(&ctx, insns, insn_count) == NULL);
280 }
281 
282 ATF_TC(libbpfjit_cop_ret_mem);
283 ATF_TC_HEAD(libbpfjit_cop_ret_mem, tc)
284 {
285 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
286 	    "that returns a content of external memory word");
287 }
288 
289 ATF_TC_BODY(libbpfjit_cop_ret_mem, tc)
290 {
291 	static struct bpf_insn insns[] = {
292 		BPF_STMT(BPF_LD+BPF_IMM, 13),
293 		BPF_STMT(BPF_ST, 2),
294 		BPF_STMT(BPF_LD+BPF_IMM, 137),
295 		BPF_STMT(BPF_ST, 1),
296 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
297 		BPF_STMT(BPF_RET+BPF_A, 0)
298 	};
299 
300 	bpfjit_func_t code;
301 	uint8_t pkt[1] = { 0 };
302 	uint32_t mem[ctx.extwords];
303 	void *arg = (void*)(uintptr_t)2;
304 
305 	/* Pre-inited words. */
306 	mem[0] = 0;
307 	mem[3] = 3;
308 
309 	bpf_args_t args = {
310 		.pkt = pkt,
311 		.buflen = sizeof(pkt),
312 		.wirelen = sizeof(pkt),
313 		.arg = arg,
314 		.mem = mem,
315 	};
316 
317 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
318 
319 	code = bpfjit_generate_code(&ctx, insns, insn_count);
320 	ATF_REQUIRE(code != NULL);
321 
322 	ATF_CHECK(code(&ctx, &args) == 13);
323 
324 	bpfjit_free_code(code);
325 }
326 
327 ATF_TC(libbpfjit_cop_ret_preinited_mem);
328 ATF_TC_HEAD(libbpfjit_cop_ret_preinited_mem, tc)
329 {
330 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
331 	    "returns a content of external pre-initialized memory word");
332 }
333 
334 ATF_TC_BODY(libbpfjit_cop_ret_preinited_mem, tc)
335 {
336 	static struct bpf_insn insns[] = {
337 		BPF_STMT(BPF_LD+BPF_IMM, 13),
338 		BPF_STMT(BPF_ST, 2),
339 		BPF_STMT(BPF_LD+BPF_IMM, 137),
340 		BPF_STMT(BPF_ST, 1),
341 		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
342 		BPF_STMT(BPF_RET+BPF_A, 0)
343 	};
344 
345 	bpfjit_func_t code;
346 	uint8_t pkt[1] = { 0 };
347 	uint32_t mem[ctx.extwords];
348 	void *arg = (void*)(uintptr_t)3;
349 
350 	/* Pre-inited words. */
351 	mem[0] = 0;
352 	mem[3] = 3;
353 
354 	bpf_args_t args = {
355 		.pkt = pkt,
356 		.buflen = sizeof(pkt),
357 		.wirelen = sizeof(pkt),
358 		.arg = arg,
359 		.mem = mem,
360 	};
361 
362 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
363 
364 	code = bpfjit_generate_code(&ctx, insns, insn_count);
365 	ATF_REQUIRE(code != NULL);
366 
367 	ATF_CHECK(code(&ctx, &args) == 3);
368 
369 	bpfjit_free_code(code);
370 }
371 
372 ATF_TC(libbpfjit_copx_ret_mem);
373 ATF_TC_HEAD(libbpfjit_copx_ret_mem, tc)
374 {
375 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
376 	    "that returns a content of external memory word");
377 }
378 
379 ATF_TC_BODY(libbpfjit_copx_ret_mem, tc)
380 {
381 	static struct bpf_insn insns[] = {
382 		BPF_STMT(BPF_LD+BPF_IMM, 13),
383 		BPF_STMT(BPF_ST, 2),
384 		BPF_STMT(BPF_LD+BPF_IMM, 137),
385 		BPF_STMT(BPF_ST, 1),
386 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
387 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
388 		BPF_STMT(BPF_RET+BPF_A, 0)
389 	};
390 
391 	bpfjit_func_t code;
392 	uint8_t pkt[1] = { 0 };
393 	uint32_t mem[ctx.extwords];
394 	void *arg = (void*)(uintptr_t)2;
395 
396 	/* Pre-inited words. */
397 	mem[0] = 0;
398 	mem[3] = 3;
399 
400 	bpf_args_t args = {
401 		.pkt = pkt,
402 		.buflen = sizeof(pkt),
403 		.wirelen = sizeof(pkt),
404 		.arg = arg,
405 		.mem = mem,
406 	};
407 
408 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
409 
410 	code = bpfjit_generate_code(&ctx, insns, insn_count);
411 	ATF_REQUIRE(code != NULL);
412 
413 	ATF_CHECK(code(&ctx, &args) == 13);
414 
415 	bpfjit_free_code(code);
416 }
417 
418 ATF_TC(libbpfjit_copx_ret_preinited_mem);
419 ATF_TC_HEAD(libbpfjit_copx_ret_preinited_mem, tc)
420 {
421 	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
422 	    "returns a content of external pre-initialized memory word");
423 }
424 
425 ATF_TC_BODY(libbpfjit_copx_ret_preinited_mem, tc)
426 {
427 	static struct bpf_insn insns[] = {
428 		BPF_STMT(BPF_LD+BPF_IMM, 13),
429 		BPF_STMT(BPF_ST, 2),
430 		BPF_STMT(BPF_LD+BPF_IMM, 137),
431 		BPF_STMT(BPF_ST, 1),
432 		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
433 		BPF_STMT(BPF_MISC+BPF_COPX, 0),
434 		BPF_STMT(BPF_RET+BPF_A, 0)
435 	};
436 
437 	bpfjit_func_t code;
438 	uint8_t pkt[1] = { 0 };
439 	uint32_t mem[ctx.extwords];
440 	void *arg = (void*)(uintptr_t)3;
441 
442 	/* Pre-inited words. */
443 	mem[0] = 0;
444 	mem[3] = 3;
445 
446 	bpf_args_t args = {
447 		.pkt = pkt,
448 		.buflen = sizeof(pkt),
449 		.wirelen = sizeof(pkt),
450 		.arg = arg,
451 		.mem = mem,
452 	};
453 
454 	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
455 
456 	code = bpfjit_generate_code(&ctx, insns, insn_count);
457 	ATF_REQUIRE(code != NULL);
458 
459 	ATF_CHECK(code(&ctx, &args) == 3);
460 
461 	bpfjit_free_code(code);
462 }
463 
464 ATF_TP_ADD_TCS(tp)
465 {
466 
467 	/*
468 	 * For every new test please also add a similar test
469 	 * to ../../net/bpfjit/t_extmem.c
470 	 */
471 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_load_default);
472 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_load_preinited);
473 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_invalid_load);
474 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_store);
475 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_side_effect);
476 	ATF_TP_ADD_TC(tp, libbpfjit_extmem_invalid_store);
477 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_mem);
478 	ATF_TP_ADD_TC(tp, libbpfjit_cop_ret_preinited_mem);
479 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_mem);
480 	ATF_TP_ADD_TC(tp, libbpfjit_copx_ret_preinited_mem);
481 
482 	return atf_no_error();
483 }
484