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
43static uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
44
45static const bpf_copfunc_t copfuncs[] = {
46	&retM
47};
48
49static 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
56static uint32_t
57retM(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
64ATF_TC(libbpfjit_extmem_load_default);
65ATF_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
71ATF_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
103ATF_TC(libbpfjit_extmem_load_preinited);
104ATF_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
110ATF_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
142ATF_TC(libbpfjit_extmem_invalid_load);
143ATF_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
149ATF_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
161ATF_TC(libbpfjit_extmem_store);
162ATF_TC_HEAD(libbpfjit_extmem_store, tc)
163{
164	atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
165}
166
167ATF_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
211ATF_TC(libbpfjit_extmem_side_effect);
212ATF_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
218ATF_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
263ATF_TC(libbpfjit_extmem_invalid_store);
264ATF_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
270ATF_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
282ATF_TC(libbpfjit_cop_ret_mem);
283ATF_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
289ATF_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
327ATF_TC(libbpfjit_cop_ret_preinited_mem);
328ATF_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
334ATF_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
372ATF_TC(libbpfjit_copx_ret_mem);
373ATF_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
379ATF_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
418ATF_TC(libbpfjit_copx_ret_preinited_mem);
419ATF_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
425ATF_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
464ATF_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