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