1314817Sngie/*	$NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $ */
2272343Sngie
3272343Sngie/*-
4272343Sngie * Copyright (c) 2014 Alexander Nasonov.
5272343Sngie * All rights reserved.
6272343Sngie *
7272343Sngie * Redistribution and use in source and binary forms, with or without
8272343Sngie * modification, are permitted provided that the following conditions
9272343Sngie * are met:
10272343Sngie *
11272343Sngie * 1. Redistributions of source code must retain the above copyright
12272343Sngie *    notice, this list of conditions and the following disclaimer.
13272343Sngie * 2. Redistributions in binary form must reproduce the above copyright
14272343Sngie *    notice, this list of conditions and the following disclaimer in
15272343Sngie *    the documentation and/or other materials provided with the
16272343Sngie *    distribution.
17272343Sngie *
18272343Sngie * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19272343Sngie * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20272343Sngie * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
21272343Sngie * FOR A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE
22272343Sngie * COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
23272343Sngie * INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
24272343Sngie * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
25272343Sngie * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
26272343Sngie * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
27272343Sngie * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
28272343Sngie * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29272343Sngie * SUCH DAMAGE.
30272343Sngie */
31272343Sngie
32272343Sngie#include <sys/cdefs.h>
33314817Sngie__RCSID("$NetBSD: t_extmem.c,v 1.2 2017/01/13 21:30:42 christos Exp $");
34272343Sngie
35272343Sngie#include <stdint.h>
36272343Sngie#include <string.h>
37272343Sngie
38272343Sngie#define __BPF_PRIVATE
39272343Sngie#include <net/bpf.h>
40272343Sngie#include <net/bpfjit.h>
41272343Sngie
42272343Sngie#include "../../net/bpf/h_bpf.h"
43272343Sngie
44272343Sngie/* XXX: atf-c.h has collisions with mbuf */
45272343Sngie#undef m_type
46272343Sngie#undef m_data
47272343Sngie#include <atf-c.h>
48272343Sngie
49314817Sngie#include "h_macros.h"
50272343Sngie
51272343Sngiestatic uint32_t retM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A);
52272343Sngie
53272343Sngiestatic const bpf_copfunc_t copfuncs[] = {
54272343Sngie	&retM
55272343Sngie};
56272343Sngie
57272343Sngiestatic const bpf_ctx_t ctx = {
58272343Sngie	.copfuncs = copfuncs,
59272343Sngie	.nfuncs = sizeof(copfuncs) / sizeof(copfuncs[0]),
60272343Sngie	.extwords = 4,
61272343Sngie	.preinited = BPF_MEMWORD_INIT(0) | BPF_MEMWORD_INIT(3),
62272343Sngie};
63272343Sngie
64272343Sngiestatic uint32_t
65272343SngieretM(const bpf_ctx_t *bc, bpf_args_t *args, uint32_t A)
66272343Sngie{
67272343Sngie
68272343Sngie	return args->mem[(uintptr_t)args->arg];
69272343Sngie}
70272343Sngie
71272343Sngie
72272343SngieATF_TC(bpfjit_extmem_load_preinited);
73272343SngieATF_TC_HEAD(bpfjit_extmem_load_preinited, tc)
74272343Sngie{
75272343Sngie	atf_tc_set_md_var(tc, "descr", "Test a load of external "
76272343Sngie	    "pre-initialized memory");
77272343Sngie}
78272343Sngie
79272343SngieATF_TC_BODY(bpfjit_extmem_load_preinited, tc)
80272343Sngie{
81272343Sngie	static struct bpf_insn insns[] = {
82272343Sngie		BPF_STMT(BPF_LD+BPF_MEM, 3),
83272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
84272343Sngie	};
85272343Sngie
86272343Sngie	bpfjit_func_t code;
87272343Sngie	uint8_t pkt[1] = { 0 };
88272343Sngie	uint32_t mem[ctx.extwords];
89272343Sngie
90272343Sngie	/* Pre-inited words. */
91272343Sngie	mem[0] = 0;
92272343Sngie	mem[3] = 3;
93272343Sngie
94272343Sngie	bpf_args_t args = {
95272343Sngie		.pkt = pkt,
96272343Sngie		.buflen = sizeof(pkt),
97272343Sngie		.wirelen = sizeof(pkt),
98272343Sngie		.mem = mem,
99272343Sngie	};
100272343Sngie
101272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
102272343Sngie
103272343Sngie	RZ(rump_init());
104272343Sngie
105272343Sngie	rump_schedule();
106272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
107272343Sngie	rump_unschedule();
108272343Sngie	ATF_REQUIRE(code != NULL);
109272343Sngie
110272343Sngie	ATF_CHECK(code(&ctx, &args) == 3);
111272343Sngie
112272343Sngie	rump_schedule();
113272343Sngie	rumpns_bpfjit_free_code(code);
114272343Sngie	rump_unschedule();
115272343Sngie}
116272343Sngie
117272343SngieATF_TC(bpfjit_extmem_invalid_load);
118272343SngieATF_TC_HEAD(bpfjit_extmem_invalid_load, tc)
119272343Sngie{
120272343Sngie	atf_tc_set_md_var(tc, "descr", "Test that out-of-range load "
121272343Sngie	    "fails validation");
122272343Sngie}
123272343Sngie
124272343SngieATF_TC_BODY(bpfjit_extmem_invalid_load, tc)
125272343Sngie{
126272343Sngie	static struct bpf_insn insns[] = {
127272343Sngie		BPF_STMT(BPF_LD+BPF_MEM, 4),
128272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
129272343Sngie	};
130272343Sngie
131272343Sngie	bpfjit_func_t code;
132272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
133272343Sngie
134272343Sngie	RZ(rump_init());
135272343Sngie
136272343Sngie	rump_schedule();
137272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
138272343Sngie	rump_unschedule();
139272343Sngie	ATF_CHECK(code == NULL);
140272343Sngie}
141272343Sngie
142272343SngieATF_TC(bpfjit_extmem_store);
143272343SngieATF_TC_HEAD(bpfjit_extmem_store, tc)
144272343Sngie{
145272343Sngie	atf_tc_set_md_var(tc, "descr", "Test stores to external memory");
146272343Sngie}
147272343Sngie
148272343SngieATF_TC_BODY(bpfjit_extmem_store, tc)
149272343Sngie{
150272343Sngie	static struct bpf_insn insns[] = {
151272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 1),        /* A <- 1     */
152272343Sngie		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
153272343Sngie		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
154272343Sngie		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
155272343Sngie		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
156272343Sngie		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
157272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
158272343Sngie	};
159272343Sngie
160272343Sngie	bpfjit_func_t code;
161272343Sngie	uint8_t pkt[1] = { 0 };
162272343Sngie	uint32_t mem[ctx.extwords];
163272343Sngie
164272343Sngie	/* Pre-inited words. */
165272343Sngie	mem[0] = 0;
166272343Sngie	mem[3] = 7;
167272343Sngie
168272343Sngie	mem[1] = mem[2] = 0xdeadbeef;
169272343Sngie
170272343Sngie	bpf_args_t args = {
171272343Sngie		.pkt = pkt,
172272343Sngie		.buflen = sizeof(pkt),
173272343Sngie		.wirelen = sizeof(pkt),
174272343Sngie		.mem = mem,
175272343Sngie	};
176272343Sngie
177272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
178272343Sngie
179272343Sngie	RZ(rump_init());
180272343Sngie
181272343Sngie	rump_schedule();
182272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
183272343Sngie	rump_unschedule();
184272343Sngie	ATF_REQUIRE(code != NULL);
185272343Sngie
186272343Sngie	ATF_CHECK(code(&ctx, &args) == 3);
187272343Sngie
188272343Sngie	rump_schedule();
189272343Sngie	rumpns_bpfjit_free_code(code);
190272343Sngie	rump_unschedule();
191272343Sngie
192272343Sngie	ATF_CHECK(mem[0] == 0);
193272343Sngie	ATF_CHECK(mem[1] == 1);
194272343Sngie	ATF_CHECK(mem[2] == 2);
195272343Sngie	ATF_CHECK(mem[3] == 3);
196272343Sngie}
197272343Sngie
198272343SngieATF_TC(bpfjit_extmem_side_effect);
199272343SngieATF_TC_HEAD(bpfjit_extmem_side_effect, tc)
200272343Sngie{
201272343Sngie	atf_tc_set_md_var(tc, "descr", "Test that ABC optimization doesn\'t "
202272343Sngie	    "skip stores to external memory");
203272343Sngie}
204272343Sngie
205272343SngieATF_TC_BODY(bpfjit_extmem_side_effect, tc)
206272343Sngie{
207272343Sngie	static struct bpf_insn insns[] = {
208272343Sngie		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 0),  /* A <- P[0]  */
209272343Sngie		BPF_STMT(BPF_LDX+BPF_W+BPF_IMM, 2), /* X <- 2     */
210272343Sngie		BPF_STMT(BPF_ST, 1),                /* M[1] <- A  */
211272343Sngie		BPF_STMT(BPF_ALU+BPF_ADD+BPF_X, 0), /* A <- A + X */
212272343Sngie		BPF_STMT(BPF_STX, 2),               /* M[2] <- X  */
213272343Sngie		BPF_STMT(BPF_ST, 3),                /* M[3] <- A  */
214272343Sngie		BPF_STMT(BPF_LD+BPF_B+BPF_ABS, 99), /* A <- P[99] */
215272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)          /* ret A      */
216272343Sngie	};
217272343Sngie
218272343Sngie	bpfjit_func_t code;
219272343Sngie	uint8_t pkt[1] = { 1 };
220272343Sngie	uint32_t mem[ctx.extwords];
221272343Sngie
222272343Sngie	/* Pre-inited words. */
223272343Sngie	mem[0] = 0;
224272343Sngie	mem[3] = 7;
225272343Sngie
226272343Sngie	mem[1] = mem[2] = 0xdeadbeef;
227272343Sngie
228272343Sngie	bpf_args_t args = {
229272343Sngie		.pkt = pkt,
230272343Sngie		.buflen = sizeof(pkt),
231272343Sngie		.wirelen = sizeof(pkt),
232272343Sngie		.mem = mem,
233272343Sngie	};
234272343Sngie
235272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
236272343Sngie
237272343Sngie	RZ(rump_init());
238272343Sngie
239272343Sngie	rump_schedule();
240272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
241272343Sngie	rump_unschedule();
242272343Sngie	ATF_REQUIRE(code != NULL);
243272343Sngie
244272343Sngie	ATF_CHECK(code(&ctx, &args) == 0);
245272343Sngie
246272343Sngie	rump_schedule();
247272343Sngie	rumpns_bpfjit_free_code(code);
248272343Sngie	rump_unschedule();
249272343Sngie
250272343Sngie	ATF_CHECK(mem[0] == 0);
251272343Sngie	ATF_CHECK(mem[1] == 1);
252272343Sngie	ATF_CHECK(mem[2] == 2);
253272343Sngie	ATF_CHECK(mem[3] == 3);
254272343Sngie}
255272343Sngie
256272343SngieATF_TC(bpfjit_extmem_invalid_store);
257272343SngieATF_TC_HEAD(bpfjit_extmem_invalid_store, tc)
258272343Sngie{
259272343Sngie	atf_tc_set_md_var(tc, "descr", "Test that out-of-range store "
260272343Sngie	    "fails validation");
261272343Sngie}
262272343Sngie
263272343SngieATF_TC_BODY(bpfjit_extmem_invalid_store, tc)
264272343Sngie{
265272343Sngie	static struct bpf_insn insns[] = {
266272343Sngie		BPF_STMT(BPF_ST, 4),
267272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
268272343Sngie	};
269272343Sngie
270272343Sngie	bpfjit_func_t code;
271272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
272272343Sngie
273272343Sngie	RZ(rump_init());
274272343Sngie
275272343Sngie	rump_schedule();
276272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
277272343Sngie	rump_unschedule();
278272343Sngie	ATF_CHECK(code == NULL);
279272343Sngie}
280272343Sngie
281272343SngieATF_TC(bpfjit_cop_ret_mem);
282272343SngieATF_TC_HEAD(bpfjit_cop_ret_mem, tc)
283272343Sngie{
284272343Sngie	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
285272343Sngie	    "that returns a content of external memory word");
286272343Sngie}
287272343Sngie
288272343SngieATF_TC_BODY(bpfjit_cop_ret_mem, tc)
289272343Sngie{
290272343Sngie	static struct bpf_insn insns[] = {
291272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 13),
292272343Sngie		BPF_STMT(BPF_ST, 2),
293272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 137),
294272343Sngie		BPF_STMT(BPF_ST, 1),
295272343Sngie		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
296272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
297272343Sngie	};
298272343Sngie
299272343Sngie	bpfjit_func_t code;
300272343Sngie	uint8_t pkt[1] = { 0 };
301272343Sngie	uint32_t mem[ctx.extwords];
302272343Sngie	void *arg = (void*)(uintptr_t)2;
303272343Sngie
304272343Sngie	/* Pre-inited words. */
305272343Sngie	mem[0] = 0;
306272343Sngie	mem[3] = 3;
307272343Sngie
308272343Sngie	bpf_args_t args = {
309272343Sngie		.pkt = pkt,
310272343Sngie		.buflen = sizeof(pkt),
311272343Sngie		.wirelen = sizeof(pkt),
312272343Sngie		.arg = arg,
313272343Sngie		.mem = mem,
314272343Sngie	};
315272343Sngie
316272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
317272343Sngie
318272343Sngie	RZ(rump_init());
319272343Sngie
320272343Sngie	rump_schedule();
321272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
322272343Sngie	rump_unschedule();
323272343Sngie	ATF_REQUIRE(code != NULL);
324272343Sngie
325272343Sngie	ATF_CHECK(code(&ctx, &args) == 13);
326272343Sngie
327272343Sngie	rump_schedule();
328272343Sngie	rumpns_bpfjit_free_code(code);
329272343Sngie	rump_unschedule();
330272343Sngie}
331272343Sngie
332272343SngieATF_TC(bpfjit_cop_ret_preinited_mem);
333272343SngieATF_TC_HEAD(bpfjit_cop_ret_preinited_mem, tc)
334272343Sngie{
335272343Sngie	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
336272343Sngie	    "returns a content of external pre-initialized memory word");
337272343Sngie}
338272343Sngie
339272343SngieATF_TC_BODY(bpfjit_cop_ret_preinited_mem, tc)
340272343Sngie{
341272343Sngie	static struct bpf_insn insns[] = {
342272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 13),
343272343Sngie		BPF_STMT(BPF_ST, 2),
344272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 137),
345272343Sngie		BPF_STMT(BPF_ST, 1),
346272343Sngie		BPF_STMT(BPF_MISC+BPF_COP, 0), // retM
347272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
348272343Sngie	};
349272343Sngie
350272343Sngie	bpfjit_func_t code;
351272343Sngie	uint8_t pkt[1] = { 0 };
352272343Sngie	uint32_t mem[ctx.extwords];
353272343Sngie	void *arg = (void*)(uintptr_t)3;
354272343Sngie
355272343Sngie	/* Pre-inited words. */
356272343Sngie	mem[0] = 0;
357272343Sngie	mem[3] = 3;
358272343Sngie
359272343Sngie	bpf_args_t args = {
360272343Sngie		.pkt = pkt,
361272343Sngie		.buflen = sizeof(pkt),
362272343Sngie		.wirelen = sizeof(pkt),
363272343Sngie		.arg = arg,
364272343Sngie		.mem = mem,
365272343Sngie	};
366272343Sngie
367272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
368272343Sngie
369272343Sngie	RZ(rump_init());
370272343Sngie
371272343Sngie	rump_schedule();
372272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
373272343Sngie	rump_unschedule();
374272343Sngie	ATF_REQUIRE(code != NULL);
375272343Sngie
376272343Sngie	ATF_CHECK(code(&ctx, &args) == 3);
377272343Sngie
378272343Sngie	rump_schedule();
379272343Sngie	rumpns_bpfjit_free_code(code);
380272343Sngie	rump_unschedule();
381272343Sngie}
382272343Sngie
383272343SngieATF_TC(bpfjit_copx_ret_mem);
384272343SngieATF_TC_HEAD(bpfjit_copx_ret_mem, tc)
385272343Sngie{
386272343Sngie	atf_tc_set_md_var(tc, "descr", "Test coprocessor function "
387272343Sngie	    "that returns a content of external memory word");
388272343Sngie}
389272343Sngie
390272343SngieATF_TC_BODY(bpfjit_copx_ret_mem, tc)
391272343Sngie{
392272343Sngie	static struct bpf_insn insns[] = {
393272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 13),
394272343Sngie		BPF_STMT(BPF_ST, 2),
395272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 137),
396272343Sngie		BPF_STMT(BPF_ST, 1),
397272343Sngie		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
398272343Sngie		BPF_STMT(BPF_MISC+BPF_COPX, 0),
399272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
400272343Sngie	};
401272343Sngie
402272343Sngie	bpfjit_func_t code;
403272343Sngie	uint8_t pkt[1] = { 0 };
404272343Sngie	uint32_t mem[ctx.extwords];
405272343Sngie	void *arg = (void*)(uintptr_t)2;
406272343Sngie
407272343Sngie	/* Pre-inited words. */
408272343Sngie	mem[0] = 0;
409272343Sngie	mem[3] = 3;
410272343Sngie
411272343Sngie	bpf_args_t args = {
412272343Sngie		.pkt = pkt,
413272343Sngie		.buflen = sizeof(pkt),
414272343Sngie		.wirelen = sizeof(pkt),
415272343Sngie		.arg = arg,
416272343Sngie		.mem = mem,
417272343Sngie	};
418272343Sngie
419272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
420272343Sngie
421272343Sngie	RZ(rump_init());
422272343Sngie
423272343Sngie	rump_schedule();
424272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
425272343Sngie	rump_unschedule();
426272343Sngie	ATF_REQUIRE(code != NULL);
427272343Sngie
428272343Sngie	ATF_CHECK(code(&ctx, &args) == 13);
429272343Sngie
430272343Sngie	rump_schedule();
431272343Sngie	rumpns_bpfjit_free_code(code);
432272343Sngie	rump_unschedule();
433272343Sngie}
434272343Sngie
435272343SngieATF_TC(bpfjit_copx_ret_preinited_mem);
436272343SngieATF_TC_HEAD(bpfjit_copx_ret_preinited_mem, tc)
437272343Sngie{
438272343Sngie	atf_tc_set_md_var(tc, "descr", "Test coprocessor function that "
439272343Sngie	    "returns a content of external pre-initialized memory word");
440272343Sngie}
441272343Sngie
442272343SngieATF_TC_BODY(bpfjit_copx_ret_preinited_mem, tc)
443272343Sngie{
444272343Sngie	static struct bpf_insn insns[] = {
445272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 13),
446272343Sngie		BPF_STMT(BPF_ST, 2),
447272343Sngie		BPF_STMT(BPF_LD+BPF_IMM, 137),
448272343Sngie		BPF_STMT(BPF_ST, 1),
449272343Sngie		BPF_STMT(BPF_LDX+BPF_IMM, 0), // retM
450272343Sngie		BPF_STMT(BPF_MISC+BPF_COPX, 0),
451272343Sngie		BPF_STMT(BPF_RET+BPF_A, 0)
452272343Sngie	};
453272343Sngie
454272343Sngie	bpfjit_func_t code;
455272343Sngie	uint8_t pkt[1] = { 0 };
456272343Sngie	uint32_t mem[ctx.extwords];
457272343Sngie	void *arg = (void*)(uintptr_t)3;
458272343Sngie
459272343Sngie	/* Pre-inited words. */
460272343Sngie	mem[0] = 0;
461272343Sngie	mem[3] = 3;
462272343Sngie
463272343Sngie	bpf_args_t args = {
464272343Sngie		.pkt = pkt,
465272343Sngie		.buflen = sizeof(pkt),
466272343Sngie		.wirelen = sizeof(pkt),
467272343Sngie		.arg = arg,
468272343Sngie		.mem = mem,
469272343Sngie	};
470272343Sngie
471272343Sngie	size_t insn_count = sizeof(insns) / sizeof(insns[0]);
472272343Sngie
473272343Sngie	RZ(rump_init());
474272343Sngie
475272343Sngie	rump_schedule();
476272343Sngie	code = rumpns_bpfjit_generate_code(&ctx, insns, insn_count);
477272343Sngie	rump_unschedule();
478272343Sngie	ATF_REQUIRE(code != NULL);
479272343Sngie
480272343Sngie	ATF_CHECK(code(&ctx, &args) == 3);
481272343Sngie
482272343Sngie	rump_schedule();
483272343Sngie	rumpns_bpfjit_free_code(code);
484272343Sngie	rump_unschedule();
485272343Sngie}
486272343Sngie
487272343SngieATF_TP_ADD_TCS(tp)
488272343Sngie{
489272343Sngie
490272343Sngie	/*
491272343Sngie	 * For every new test please also add a similar test
492272343Sngie	 * to ../../lib/libbpfjit/t_extmem.c
493272343Sngie	 */
494272343Sngie	//ATF_TP_ADD_TC(tp, bpfjit_extmem_load_default);
495272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_extmem_load_preinited);
496272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_load);
497272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_extmem_store);
498272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_extmem_side_effect);
499272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_extmem_invalid_store);
500272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_mem);
501272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_cop_ret_preinited_mem);
502272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_mem);
503272343Sngie	ATF_TP_ADD_TC(tp, bpfjit_copx_ret_preinited_mem);
504272343Sngie
505272343Sngie	return atf_no_error();
506272343Sngie}
507