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
retM(const bpf_ctx_t * bc,bpf_args_t * args,uint32_t A)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);
ATF_TC_HEAD(libbpfjit_extmem_load_default,tc)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
ATF_TC_BODY(libbpfjit_extmem_load_default,tc)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);
ATF_TC_HEAD(libbpfjit_extmem_load_preinited,tc)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
ATF_TC_BODY(libbpfjit_extmem_load_preinited,tc)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);
ATF_TC_HEAD(libbpfjit_extmem_invalid_load,tc)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
ATF_TC_BODY(libbpfjit_extmem_invalid_load,tc)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);
ATF_TC_HEAD(libbpfjit_extmem_store,tc)162 ATF_TC_HEAD(libbpfjit_extmem_store, tc)
163 {
164 atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
165 }
166
ATF_TC_BODY(libbpfjit_extmem_store,tc)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);
ATF_TC_HEAD(libbpfjit_extmem_side_effect,tc)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
ATF_TC_BODY(libbpfjit_extmem_side_effect,tc)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);
ATF_TC_HEAD(libbpfjit_extmem_invalid_store,tc)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
ATF_TC_BODY(libbpfjit_extmem_invalid_store,tc)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);
ATF_TC_HEAD(libbpfjit_cop_ret_mem,tc)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
ATF_TC_BODY(libbpfjit_cop_ret_mem,tc)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);
ATF_TC_HEAD(libbpfjit_cop_ret_preinited_mem,tc)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
ATF_TC_BODY(libbpfjit_cop_ret_preinited_mem,tc)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);
ATF_TC_HEAD(libbpfjit_copx_ret_mem,tc)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
ATF_TC_BODY(libbpfjit_copx_ret_mem,tc)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);
ATF_TC_HEAD(libbpfjit_copx_ret_preinited_mem,tc)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
ATF_TC_BODY(libbpfjit_copx_ret_preinited_mem,tc)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
ATF_TP_ADD_TCS(tp)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