Home | History | Annotate | Line # | Download | only in libbpfjit
      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