1 /* SPDX-License-Identifier: Apache-2.0 OR GPL-2.0-or-later */ 2 3 #ifdef HAVE_CONFIG_H 4 #include "config.h" 5 #endif 6 7 #define ASTLPC_VER_CUR 2 8 #include "astlpc.c" 9 10 #ifdef pr_fmt 11 #undef pr_fmt 12 #define pr_fmt(x) "test: " x 13 #endif 14 15 #include "libmctp-astlpc.h" 16 #include "libmctp-log.h" 17 #include "container_of.h" 18 19 #ifdef NDEBUG 20 #undef NDEBUG 21 #endif 22 23 #include <assert.h> 24 #include <limits.h> 25 #include <stdint.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 30 #ifndef ARRAY_SIZE 31 #define ARRAY_SIZE(a) (sizeof(a) / sizeof(a[0])) 32 #endif 33 34 struct mctp_binding_astlpc_mmio { 35 struct mctp_binding_astlpc astlpc; 36 bool bmc; 37 38 uint8_t (*kcs)[2]; 39 40 size_t lpc_size; 41 uint8_t *lpc; 42 }; 43 44 struct astlpc_endpoint { 45 struct mctp_binding_astlpc_mmio mmio; 46 struct mctp_binding_astlpc *astlpc; 47 struct mctp *mctp; 48 }; 49 50 struct astlpc_test { 51 struct astlpc_endpoint bmc; 52 struct astlpc_endpoint host; 53 uint8_t kcs[2]; 54 uint8_t *lpc_mem; 55 56 void *msg; 57 uint8_t count; 58 }; 59 60 #define binding_to_mmio(b) \ 61 container_of(b, struct mctp_binding_astlpc_mmio, astlpc) 62 63 static int mctp_astlpc_mmio_kcs_read(void *data, 64 enum mctp_binding_astlpc_kcs_reg reg, 65 uint8_t *val) 66 { 67 struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data); 68 69 *val = (*mmio->kcs)[reg]; 70 71 mctp_prdebug("%s: 0x%hhx from %s", __func__, *val, 72 reg ? "status" : "data"); 73 74 if (reg == MCTP_ASTLPC_KCS_REG_DATA) { 75 uint8_t flag = mmio->bmc ? KCS_STATUS_IBF : KCS_STATUS_OBF; 76 (*mmio->kcs)[MCTP_ASTLPC_KCS_REG_STATUS] &= ~flag; 77 } 78 79 return 0; 80 } 81 82 static int mctp_astlpc_mmio_kcs_write(void *data, 83 enum mctp_binding_astlpc_kcs_reg reg, 84 uint8_t val) 85 { 86 struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data); 87 uint8_t *regp; 88 89 assert(reg == MCTP_ASTLPC_KCS_REG_DATA || 90 reg == MCTP_ASTLPC_KCS_REG_STATUS); 91 92 if (reg == MCTP_ASTLPC_KCS_REG_DATA) { 93 uint8_t flag = mmio->bmc ? KCS_STATUS_OBF : KCS_STATUS_IBF; 94 (*mmio->kcs)[MCTP_ASTLPC_KCS_REG_STATUS] |= flag; 95 } 96 97 regp = &(*mmio->kcs)[reg]; 98 if (reg == MCTP_ASTLPC_KCS_REG_STATUS) 99 *regp = (val & ~0xbU) | (val & *regp & 1); 100 else 101 *regp = val; 102 103 mctp_prdebug("%s: 0x%hhx to %s", __func__, val, 104 reg ? "status" : "data"); 105 106 return 0; 107 } 108 109 static const struct mctp_binding_astlpc_ops astlpc_direct_mmio_ops = { 110 .kcs_read = mctp_astlpc_mmio_kcs_read, 111 .kcs_write = mctp_astlpc_mmio_kcs_write, 112 }; 113 114 int mctp_astlpc_mmio_lpc_read(void *data, void *buf, long offset, size_t len) 115 { 116 struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data); 117 118 mctp_prdebug("%s: %zu bytes from 0x%lx", __func__, len, offset); 119 120 assert(offset >= 0L); 121 assert(offset + len < mmio->lpc_size); 122 123 memcpy(buf, mmio->lpc + offset, len); 124 125 return 0; 126 } 127 128 int mctp_astlpc_mmio_lpc_write(void *data, const void *buf, long offset, 129 size_t len) 130 { 131 struct mctp_binding_astlpc_mmio *mmio = binding_to_mmio(data); 132 133 mctp_prdebug("%s: %zu bytes to 0x%lx", __func__, len, offset); 134 135 assert(offset >= 0L); 136 assert(offset + len < mmio->lpc_size); 137 138 memcpy(mmio->lpc + offset, buf, len); 139 140 return 0; 141 } 142 143 static const struct mctp_binding_astlpc_ops astlpc_indirect_mmio_ops = { 144 .kcs_read = mctp_astlpc_mmio_kcs_read, 145 .kcs_write = mctp_astlpc_mmio_kcs_write, 146 .lpc_read = mctp_astlpc_mmio_lpc_read, 147 .lpc_write = mctp_astlpc_mmio_lpc_write, 148 }; 149 150 #define __unused __attribute__((unused)) 151 152 static void rx_message(uint8_t eid __unused, void *data __unused, void *msg, 153 size_t len) 154 { 155 struct astlpc_test *test = data; 156 157 mctp_prdebug("MCTP message received: msg: %p, len %zd", msg, len); 158 159 assert(len > 0); 160 assert(msg); 161 assert(test); 162 assert(test->msg); 163 assert(!memcmp(test->msg, msg, len)); 164 165 test->count++; 166 } 167 168 static int endpoint_init(struct astlpc_endpoint *ep, mctp_eid_t eid, 169 uint8_t mode, uint32_t mtu, uint8_t (*kcs)[2], 170 void *lpc_mem) 171 { 172 /* 173 * Configure the direction of the KCS interface so we know whether to 174 * set or clear IBF or OBF on writes or reads. 175 */ 176 ep->mmio.bmc = (mode == MCTP_BINDING_ASTLPC_MODE_BMC); 177 178 ep->mctp = mctp_init(); 179 assert(ep->mctp); 180 181 /* Inject KCS registers */ 182 ep->mmio.kcs = kcs; 183 184 /* Initialise the binding */ 185 ep->astlpc = mctp_astlpc_init(mode, mtu, lpc_mem, 186 &astlpc_direct_mmio_ops, &ep->mmio); 187 assert(ep->astlpc); 188 189 return mctp_register_bus(ep->mctp, &ep->astlpc->binding, eid); 190 } 191 192 static void endpoint_destroy(struct astlpc_endpoint *ep) 193 { 194 mctp_astlpc_destroy(ep->astlpc); 195 mctp_destroy(ep->mctp); 196 } 197 198 static void network_init(struct astlpc_test *ctx) 199 { 200 int rc; 201 202 ctx->lpc_mem = calloc(1, 1 * 1024 * 1024); 203 assert(ctx->lpc_mem); 204 205 /* BMC initialisation */ 206 rc = endpoint_init(&ctx->bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 207 &ctx->kcs, ctx->lpc_mem); 208 assert(!rc); 209 assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_BMC_READY); 210 211 /* Host initialisation */ 212 rc = endpoint_init(&ctx->host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, 213 MCTP_BTU, &ctx->kcs, ctx->lpc_mem); 214 assert(!rc); 215 216 /* BMC processes host channel init request, alerts host */ 217 mctp_astlpc_poll(ctx->bmc.astlpc); 218 assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_STATUS] & 219 KCS_STATUS_CHANNEL_ACTIVE); 220 assert(ctx->kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0xff); 221 222 /* Host dequeues channel init result */ 223 mctp_astlpc_poll(ctx->host.astlpc); 224 } 225 226 static void network_destroy(struct astlpc_test *ctx) 227 { 228 endpoint_destroy(&ctx->bmc); 229 endpoint_destroy(&ctx->host); 230 free(ctx->lpc_mem); 231 } 232 233 static void astlpc_assert_tx_packet(struct astlpc_endpoint *src, 234 const void *expected, size_t len) 235 { 236 const size_t tx_body = src->astlpc->layout.tx.offset + 4 + 4; 237 const void *test = ((char *)src->astlpc->lpc_map) + tx_body; 238 assert(!memcmp(test, expected, len)); 239 } 240 241 static void astlpc_test_packetised_message_bmc_to_host(void) 242 { 243 struct astlpc_test ctx = { 0 }; 244 uint8_t msg[2 * MCTP_BTU]; 245 int rc; 246 247 /* Test harness initialisation */ 248 249 network_init(&ctx); 250 251 memset(&msg[0], 0x5a, MCTP_BTU); 252 memset(&msg[MCTP_BTU], 0xa5, MCTP_BTU); 253 254 ctx.msg = &msg[0]; 255 ctx.count = 0; 256 mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx); 257 258 /* BMC sends a message */ 259 rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg)); 260 assert(rc == 0); 261 262 /* Host receives the first packet */ 263 mctp_astlpc_poll(ctx.host.astlpc); 264 265 /* BMC dequeues ownership hand-over and sends the queued packet */ 266 rc = mctp_astlpc_poll(ctx.bmc.astlpc); 267 assert(rc == 0); 268 269 /* Host receives the next packet */ 270 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF); 271 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01); 272 273 astlpc_assert_tx_packet(&ctx.bmc, &msg[MCTP_BTU], MCTP_BTU); 274 275 /* Host receives final packet */ 276 mctp_astlpc_poll(ctx.host.astlpc); 277 assert(ctx.count == 1); 278 279 network_destroy(&ctx); 280 } 281 282 static void astlpc_test_simple_message_host_to_bmc(void) 283 { 284 struct astlpc_test ctx = { 0 }; 285 uint8_t msg[MCTP_BTU]; 286 int rc; 287 288 /* Test harness initialisation */ 289 290 network_init(&ctx); 291 292 memset(&msg[0], 0xa5, MCTP_BTU); 293 294 ctx.msg = &msg[0]; 295 ctx.count = 0; 296 mctp_set_rx_all(ctx.bmc.mctp, rx_message, &ctx); 297 298 /* Host sends the single-packet message */ 299 rc = mctp_message_tx(ctx.host.mctp, 8, msg, sizeof(msg)); 300 assert(rc == 0); 301 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF); 302 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01); 303 304 astlpc_assert_tx_packet(&ctx.host, &msg[0], MCTP_BTU); 305 306 /* BMC receives the single-packet message */ 307 mctp_astlpc_poll(ctx.bmc.astlpc); 308 assert(ctx.count == 1); 309 310 /* BMC returns Tx area ownership to Host */ 311 assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF)); 312 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02); 313 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF); 314 315 /* Host dequeues ownership hand-over and sends the queued packet */ 316 rc = mctp_astlpc_poll(ctx.host.astlpc); 317 assert(rc == 0); 318 319 network_destroy(&ctx); 320 } 321 322 static void astlpc_test_simple_message_bmc_to_host(void) 323 { 324 struct astlpc_test ctx = { 0 }; 325 uint8_t msg[MCTP_BTU]; 326 int rc; 327 328 /* Test harness initialisation */ 329 330 network_init(&ctx); 331 332 memset(&msg[0], 0x5a, MCTP_BTU); 333 334 ctx.msg = &msg[0]; 335 ctx.count = 0; 336 mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx); 337 338 /* BMC sends the single-packet message */ 339 rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg)); 340 assert(rc == 0); 341 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF); 342 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x01); 343 344 astlpc_assert_tx_packet(&ctx.bmc, &msg[0], MCTP_BTU); 345 346 /* Host receives the single-packet message */ 347 mctp_astlpc_poll(ctx.host.astlpc); 348 assert(ctx.count == 1); 349 350 /* Host returns Rx area ownership to BMC */ 351 assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF)); 352 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x02); 353 assert(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF); 354 355 /* BMC dequeues ownership hand-over and sends the queued packet */ 356 rc = mctp_astlpc_poll(ctx.bmc.astlpc); 357 assert(rc == 0); 358 359 network_destroy(&ctx); 360 } 361 362 static void astlpc_test_host_before_bmc(void) 363 { 364 struct mctp_binding_astlpc_mmio mmio = { 0 }; 365 struct mctp_binding_astlpc *astlpc; 366 uint8_t kcs[2] = { 0 }; 367 struct mctp *mctp; 368 int rc; 369 370 mctp = mctp_init(); 371 assert(mctp); 372 373 /* Inject KCS registers */ 374 mmio.kcs = &kcs; 375 376 /* Initialise the binding */ 377 astlpc = mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, NULL, 378 &astlpc_direct_mmio_ops, &mmio); 379 380 /* Register the binding to trigger the start-up sequence */ 381 rc = mctp_register_bus(mctp, &astlpc->binding, 8); 382 383 /* Start-up should fail as we haven't initialised the BMC */ 384 assert(rc < 0); 385 386 mctp_astlpc_destroy(astlpc); 387 mctp_destroy(mctp); 388 } 389 390 static void astlpc_test_bad_version(void) 391 { 392 assert(0 == 393 mctp_astlpc_negotiate_version(ASTLPC_VER_BAD, ASTLPC_VER_CUR, 394 ASTLPC_VER_MIN, ASTLPC_VER_CUR)); 395 assert(0 == 396 mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_BAD, 397 ASTLPC_VER_MIN, ASTLPC_VER_CUR)); 398 assert(0 == 399 mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR, 400 ASTLPC_VER_BAD, ASTLPC_VER_CUR)); 401 assert(0 == 402 mctp_astlpc_negotiate_version(ASTLPC_VER_MIN, ASTLPC_VER_CUR, 403 ASTLPC_VER_MIN, ASTLPC_VER_BAD)); 404 assert(0 == mctp_astlpc_negotiate_version( 405 ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR, ASTLPC_VER_MIN, 406 ASTLPC_VER_CUR + 1)); 407 assert(0 == mctp_astlpc_negotiate_version( 408 ASTLPC_VER_MIN, ASTLPC_VER_CUR + 1, 409 ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR)); 410 } 411 412 static void astlpc_test_incompatible_versions(void) 413 { 414 assert(0 == mctp_astlpc_negotiate_version( 415 ASTLPC_VER_CUR, ASTLPC_VER_CUR, ASTLPC_VER_CUR + 1, 416 ASTLPC_VER_CUR + 1)); 417 assert(0 == mctp_astlpc_negotiate_version( 418 ASTLPC_VER_CUR + 1, ASTLPC_VER_CUR + 1, 419 ASTLPC_VER_CUR, ASTLPC_VER_CUR)); 420 } 421 422 static void astlpc_test_choose_bmc_ver_cur(void) 423 { 424 assert(2 == mctp_astlpc_negotiate_version(1, 2, 2, 3)); 425 } 426 427 static void astlpc_test_choose_host_ver_cur(void) 428 { 429 assert(2 == mctp_astlpc_negotiate_version(2, 3, 1, 2)); 430 } 431 432 static void astlpc_test_version_host_fails_negotiation(void) 433 { 434 struct astlpc_endpoint bmc, host; 435 struct mctp_lpcmap_hdr *hdr; 436 uint8_t kcs[2] = { 0 }; 437 void *lpc_mem; 438 int rc; 439 440 /* Test harness initialisation */ 441 lpc_mem = calloc(1, 1 * 1024 * 1024); 442 assert(lpc_mem); 443 444 /* BMC initialisation */ 445 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 446 &kcs, lpc_mem); 447 assert(!rc); 448 449 /* Now the BMC is initialised, break its version announcement */ 450 hdr = lpc_mem; 451 hdr->bmc_ver_cur = ASTLPC_VER_BAD; 452 453 /* Host initialisation */ 454 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 455 &kcs, lpc_mem); 456 assert(rc < 0); 457 458 endpoint_destroy(&bmc); 459 endpoint_destroy(&host); 460 free(lpc_mem); 461 } 462 463 static void astlpc_test_version_bmc_fails_negotiation(void) 464 { 465 struct astlpc_endpoint bmc, host; 466 struct mctp_lpcmap_hdr *hdr; 467 uint8_t kcs[2] = { 0 }; 468 void *lpc_mem; 469 int rc; 470 471 /* Test harness initialisation */ 472 lpc_mem = calloc(1, 1 * 1024 * 1024); 473 assert(lpc_mem); 474 475 /* BMC initialisation */ 476 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 477 &kcs, lpc_mem); 478 assert(!rc); 479 480 /* Host initialisation */ 481 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 482 &kcs, lpc_mem); 483 assert(!rc); 484 485 /* Now the host is initialised, break its version announcement */ 486 hdr = lpc_mem; 487 hdr->host_ver_cur = ASTLPC_VER_BAD; 488 489 /* Poll the BMC to detect the broken host version */ 490 mctp_astlpc_poll(bmc.astlpc); 491 assert(!(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE)); 492 493 /* Poll the host so it detects failed negotiation */ 494 rc = mctp_astlpc_poll(host.astlpc); 495 assert(rc < 0); 496 497 endpoint_destroy(&bmc); 498 endpoint_destroy(&host); 499 free(lpc_mem); 500 } 501 502 static void astlpc_test_simple_init(void) 503 { 504 struct astlpc_endpoint bmc, host; 505 uint8_t kcs[2] = { 0 }; 506 void *lpc_mem; 507 int rc; 508 509 /* Test harness initialisation */ 510 lpc_mem = calloc(1, 1 * 1024 * 1024); 511 assert(lpc_mem); 512 513 /* BMC initialisation */ 514 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 515 &kcs, lpc_mem); 516 assert(!rc); 517 518 /* Verify the BMC binding was initialised */ 519 assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_BMC_READY); 520 521 /* Host initialisation */ 522 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 523 &kcs, lpc_mem); 524 assert(!rc); 525 526 /* Host sends channel init command */ 527 assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_IBF); 528 assert(kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0x00); 529 530 /* BMC receives host channel init request */ 531 mctp_astlpc_poll(bmc.astlpc); 532 533 /* BMC sends init response */ 534 assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF); 535 assert(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE); 536 assert(kcs[MCTP_ASTLPC_KCS_REG_DATA] == 0xff); 537 538 /* Host dequeues data */ 539 mctp_astlpc_poll(host.astlpc); 540 541 endpoint_destroy(&bmc); 542 endpoint_destroy(&host); 543 free(lpc_mem); 544 } 545 546 static void astlpc_test_simple_indirect_message_bmc_to_host(void) 547 { 548 struct astlpc_test ctx = { 0 }; 549 uint8_t kcs[2] = { 0 }; 550 uint8_t msg[MCTP_BTU]; 551 int rc; 552 553 ctx.lpc_mem = calloc(1, LPC_WIN_SIZE); 554 assert(ctx.lpc_mem); 555 556 /* Test message data */ 557 memset(&msg[0], 0x5a, MCTP_BTU); 558 559 /* Manually set up the network so we can inject the indirect ops */ 560 561 /* BMC initialisation */ 562 ctx.bmc.mmio.bmc = true; 563 ctx.bmc.mctp = mctp_init(); 564 assert(ctx.bmc.mctp); 565 ctx.bmc.mmio.kcs = &kcs; 566 ctx.bmc.mmio.lpc = ctx.lpc_mem; 567 ctx.bmc.mmio.lpc_size = LPC_WIN_SIZE; 568 ctx.bmc.astlpc = 569 mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, NULL, 570 &astlpc_indirect_mmio_ops, &ctx.bmc.mmio); 571 mctp_register_bus(ctx.bmc.mctp, &ctx.bmc.astlpc->binding, 8); 572 573 /* Host initialisation */ 574 ctx.host.mmio.bmc = false; 575 ctx.host.mctp = mctp_init(); 576 assert(ctx.host.mctp); 577 ctx.host.mmio.kcs = &kcs; 578 ctx.host.mmio.lpc = ctx.lpc_mem; 579 ctx.host.mmio.lpc_size = LPC_WIN_SIZE; 580 ctx.host.astlpc = 581 mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, NULL, 582 &astlpc_indirect_mmio_ops, &ctx.host.mmio); 583 mctp_register_bus(ctx.host.mctp, &ctx.host.astlpc->binding, 9); 584 585 /* BMC processes host channel init request, alerts host */ 586 mctp_astlpc_poll(ctx.bmc.astlpc); 587 588 /* Host dequeues channel init result */ 589 mctp_astlpc_poll(ctx.host.astlpc); 590 591 ctx.msg = &msg[0]; 592 ctx.count = 0; 593 mctp_set_rx_all(ctx.host.mctp, rx_message, &ctx); 594 595 /* BMC sends the single-packet message */ 596 rc = mctp_message_tx(ctx.bmc.mctp, 9, msg, sizeof(msg)); 597 assert(rc == 0); 598 599 /* Host receives the single-packet message */ 600 rc = mctp_astlpc_poll(ctx.host.astlpc); 601 assert(rc == 0); 602 assert(ctx.count == 1); 603 604 /* BMC dequeues ownership hand-over and sends the queued packet */ 605 rc = mctp_astlpc_poll(ctx.bmc.astlpc); 606 assert(rc == 0); 607 608 /* Can still tear-down the network in the normal fashion */ 609 network_destroy(&ctx); 610 } 611 612 static void astlpc_test_host_tx_bmc_gone(void) 613 { 614 struct astlpc_test ctx = { 0 }; 615 uint8_t unwritten[MCTP_BTU]; 616 uint8_t msg[MCTP_BTU]; 617 int rc; 618 619 /* Test harness initialisation */ 620 621 network_init(&ctx); 622 623 memset(&msg[0], 0x5a, sizeof(msg)); 624 memset(&unwritten[0], 0, sizeof(unwritten)); 625 626 ctx.msg = &msg[0]; 627 ctx.count = 0; 628 629 /* Clear bmc-ready */ 630 endpoint_destroy(&ctx.bmc); 631 632 /* Host detects that the BMC is disabled */ 633 mctp_astlpc_poll(ctx.host.astlpc); 634 635 /* Host attempts to send the single-packet message, but is prevented */ 636 rc = mctp_message_tx(ctx.host.mctp, 8, msg, sizeof(msg)); 637 assert(rc == 0); 638 assert(!(ctx.kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_OBF)); 639 astlpc_assert_tx_packet(&ctx.host, &unwritten[0], MCTP_BTU); 640 641 /* BMC comes back */ 642 rc = endpoint_init(&ctx.bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 643 &ctx.kcs, ctx.lpc_mem); 644 assert(!rc); 645 mctp_set_rx_all(ctx.bmc.mctp, rx_message, &ctx); 646 647 /* Host triggers channel init */ 648 mctp_astlpc_poll(ctx.host.astlpc); 649 650 /* BMC handles channel init */ 651 mctp_astlpc_poll(ctx.bmc.astlpc); 652 653 /* Host completes channel init, flushing the Tx queue */ 654 mctp_astlpc_poll(ctx.host.astlpc); 655 656 /* BMC receives the single-packet message */ 657 mctp_astlpc_poll(ctx.bmc.astlpc); 658 assert(ctx.count == 1); 659 660 network_destroy(&ctx); 661 } 662 663 static void astlpc_test_poll_not_ready(void) 664 { 665 struct astlpc_endpoint bmc; 666 uint8_t kcs[2] = { 0 }; 667 void *lpc_mem; 668 int rc; 669 670 /* Test harness initialisation */ 671 lpc_mem = calloc(1, 1 * 1024 * 1024); 672 assert(lpc_mem); 673 674 /* BMC initialisation */ 675 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 676 &kcs, lpc_mem); 677 assert(!rc); 678 679 /* Check for a command despite none present */ 680 rc = mctp_astlpc_poll(bmc.astlpc); 681 682 /* Make sure it doesn't fail */ 683 assert(rc == 0); 684 685 endpoint_destroy(&bmc); 686 free(lpc_mem); 687 } 688 689 static void astlpc_test_undefined_command(void) 690 { 691 struct astlpc_endpoint bmc; 692 uint8_t kcs[2] = { 0 }; 693 void *lpc_mem; 694 int rc; 695 696 /* Test harness initialisation */ 697 lpc_mem = calloc(1, 1 * 1024 * 1024); 698 assert(lpc_mem); 699 700 /* BMC initialisation */ 701 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 702 &kcs, lpc_mem); 703 assert(!rc); 704 705 /* 0x5a isn't legal in v1 or v2 */ 706 kcs[MCTP_ASTLPC_KCS_REG_DATA] = 0x5a; 707 kcs[MCTP_ASTLPC_KCS_REG_STATUS] |= KCS_STATUS_IBF; 708 709 /* Check for a command despite none present */ 710 rc = mctp_astlpc_poll(bmc.astlpc); 711 712 /* Make sure it doesn't fail, bad command should be discarded */ 713 assert(rc == 0); 714 715 endpoint_destroy(&bmc); 716 free(lpc_mem); 717 } 718 719 #define BUFFER_MIN ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(MCTP_BTU)) 720 721 static void astlpc_test_buffers_rx_offset_overflow(void) 722 { 723 struct mctp_astlpc_layout l = { 724 .rx = { UINT32_MAX, BUFFER_MIN }, 725 .tx = { control_size, BUFFER_MIN }, 726 }; 727 728 assert(!mctp_astlpc_layout_validate(&l)); 729 } 730 731 static void astlpc_test_buffers_tx_offset_overflow(void) 732 { 733 struct mctp_astlpc_layout l = { 734 .rx = { control_size, BUFFER_MIN }, 735 .tx = { UINT32_MAX, BUFFER_MIN }, 736 }; 737 738 assert(!mctp_astlpc_layout_validate(&l)); 739 } 740 741 static void astlpc_test_buffers_rx_size_overflow(void) 742 { 743 struct mctp_astlpc_layout l = { 744 .rx = { control_size + BUFFER_MIN, UINT32_MAX }, 745 .tx = { control_size, BUFFER_MIN }, 746 }; 747 748 assert(!mctp_astlpc_layout_validate(&l)); 749 } 750 751 static void astlpc_test_buffers_tx_size_overflow(void) 752 { 753 struct mctp_astlpc_layout l = { 754 .rx = { control_size, BUFFER_MIN }, 755 .tx = { control_size + BUFFER_MIN, UINT32_MAX }, 756 }; 757 758 assert(!mctp_astlpc_layout_validate(&l)); 759 } 760 761 static void astlpc_test_buffers_rx_window_violation(void) 762 { 763 struct mctp_astlpc_layout l = { 764 .rx = { LPC_WIN_SIZE - BUFFER_MIN + 1, BUFFER_MIN }, 765 .tx = { control_size, BUFFER_MIN }, 766 }; 767 768 assert(!mctp_astlpc_layout_validate(&l)); 769 } 770 771 static void astlpc_test_buffers_tx_window_violation(void) 772 { 773 struct mctp_astlpc_layout l = { 774 .rx = { control_size, BUFFER_MIN }, 775 .tx = { LPC_WIN_SIZE - BUFFER_MIN + 1, BUFFER_MIN }, 776 }; 777 778 assert(!mctp_astlpc_layout_validate(&l)); 779 } 780 781 static void astlpc_test_buffers_rx_size_fails_btu(void) 782 { 783 struct mctp_astlpc_layout l = { 784 .rx = { control_size, BUFFER_MIN - 1 }, 785 .tx = { control_size + BUFFER_MIN, BUFFER_MIN }, 786 }; 787 788 assert(!mctp_astlpc_layout_validate(&l)); 789 } 790 791 static void astlpc_test_buffers_tx_size_fails_btu(void) 792 { 793 struct mctp_astlpc_layout l = { 794 .rx = { control_size, BUFFER_MIN }, 795 .tx = { control_size + BUFFER_MIN, BUFFER_MIN - 1 }, 796 }; 797 798 assert(!mctp_astlpc_layout_validate(&l)); 799 } 800 801 static void astlpc_test_buffers_overlap_rx_low(void) 802 { 803 struct mctp_astlpc_layout l = { 804 .rx = { control_size, 2 * BUFFER_MIN }, 805 .tx = { control_size + BUFFER_MIN, 2 * BUFFER_MIN }, 806 }; 807 808 assert(!mctp_astlpc_layout_validate(&l)); 809 } 810 811 static void astlpc_test_buffers_overlap_tx_low(void) 812 { 813 struct mctp_astlpc_layout l = { 814 .rx = { control_size + BUFFER_MIN, 2 * BUFFER_MIN }, 815 .tx = { control_size, 2 * BUFFER_MIN }, 816 }; 817 818 assert(!mctp_astlpc_layout_validate(&l)); 819 } 820 821 static void astlpc_test_buffers_overlap_exact(void) 822 { 823 struct mctp_astlpc_layout l = { 824 .rx = { control_size, 2 * BUFFER_MIN }, 825 .tx = { control_size, 2 * BUFFER_MIN }, 826 }; 827 828 assert(!mctp_astlpc_layout_validate(&l)); 829 } 830 831 static void astlpc_test_buffers_overlap_control(void) 832 { 833 struct mctp_astlpc_layout l = { 834 .rx = { 0, BUFFER_MIN }, 835 .tx = { control_size + BUFFER_MIN, BUFFER_MIN }, 836 }; 837 838 assert(!mctp_astlpc_layout_validate(&l)); 839 } 840 841 static void astlpc_test_buffers_bad_host_proposal(void) 842 { 843 struct astlpc_endpoint bmc, host; 844 struct mctp_lpcmap_hdr *hdr; 845 uint8_t kcs[2] = { 0 }; 846 void *lpc_mem; 847 int rc; 848 849 /* Test harness initialisation */ 850 lpc_mem = calloc(1, 1 * 1024 * 1024); 851 assert(lpc_mem); 852 853 /* BMC initialisation */ 854 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 855 &kcs, lpc_mem); 856 assert(!rc); 857 858 /* Host initialisation */ 859 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 860 &kcs, lpc_mem); 861 assert(!rc); 862 863 /* 864 * Now that the host has initialised the control area, break 865 * something before polling the BMC 866 */ 867 hdr = lpc_mem; 868 hdr->layout.rx_size = 0; 869 870 mctp_astlpc_poll(bmc.astlpc); 871 872 /* Make sure the BMC has not set the channel to active */ 873 assert(!(kcs[MCTP_ASTLPC_KCS_REG_STATUS] & KCS_STATUS_CHANNEL_ACTIVE)); 874 875 endpoint_destroy(&host); 876 endpoint_destroy(&bmc); 877 free(lpc_mem); 878 } 879 880 static void astlpc_test_buffers_bad_bmc_proposal(void) 881 { 882 struct astlpc_endpoint bmc, host; 883 struct mctp_lpcmap_hdr *hdr; 884 uint8_t kcs[2] = { 0 }; 885 void *lpc_mem; 886 int rc; 887 888 /* Test harness initialisation */ 889 lpc_mem = calloc(1, 1 * 1024 * 1024); 890 assert(lpc_mem); 891 892 /* BMC initialisation */ 893 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 894 &kcs, lpc_mem); 895 assert(!rc); 896 897 /* 898 * Now that the BMC has initialised the control area, break something 899 * before initialising the host 900 */ 901 hdr = lpc_mem; 902 hdr->layout.rx_size = 0; 903 904 /* Host initialisation: Fails due to bad layout */ 905 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 906 &kcs, lpc_mem); 907 assert(rc < 0); 908 909 endpoint_destroy(&host); 910 endpoint_destroy(&bmc); 911 free(lpc_mem); 912 } 913 914 static void astlpc_test_buffers_bad_bmc_negotiation(void) 915 { 916 struct astlpc_endpoint bmc, host; 917 struct mctp_lpcmap_hdr *hdr; 918 uint8_t kcs[2] = { 0 }; 919 void *lpc_mem; 920 int rc; 921 922 /* Test harness initialisation */ 923 lpc_mem = calloc(1, 1 * 1024 * 1024); 924 assert(lpc_mem); 925 926 /* BMC initialisation */ 927 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, MCTP_BTU, 928 &kcs, lpc_mem); 929 assert(!rc); 930 931 /* Host initialisation */ 932 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, MCTP_BTU, 933 &kcs, lpc_mem); 934 assert(!rc); 935 936 mctp_astlpc_poll(bmc.astlpc); 937 938 /* 939 * Now that the BMC has initialised the control area, break something 940 * before polling the host 941 */ 942 hdr = lpc_mem; 943 hdr->layout.rx_size = 0; 944 945 rc = mctp_astlpc_poll(host.astlpc); 946 assert(rc < 0); 947 948 endpoint_destroy(&host); 949 endpoint_destroy(&bmc); 950 free(lpc_mem); 951 } 952 953 static void astlpc_test_buffers_bad_host_init(void) 954 { 955 struct astlpc_endpoint host; 956 uint8_t kcs[2] = { 0 }; 957 void *lpc_mem; 958 int rc; 959 960 /* Test harness initialisation */ 961 lpc_mem = calloc(1, 1 * 1024 * 1024); 962 assert(lpc_mem); 963 964 host.mctp = mctp_init(); 965 assert(host.mctp); 966 host.mmio.kcs = &kcs; 967 host.mmio.bmc = false; 968 969 /* Set the MTU to 0 to provoke a failure */ 970 host.astlpc = 971 mctp_astlpc_init(MCTP_BINDING_ASTLPC_MODE_HOST, 0, lpc_mem, 972 &astlpc_direct_mmio_ops, &host.mmio); 973 974 rc = mctp_register_bus(host.mctp, &host.astlpc->binding, 8); 975 assert(rc < 0); 976 977 mctp_astlpc_destroy(host.astlpc); 978 mctp_destroy(host.mctp); 979 free(lpc_mem); 980 } 981 982 static void astlpc_test_negotiate_increased_mtu(void) 983 { 984 struct astlpc_endpoint bmc, host; 985 uint8_t kcs[2] = { 0 }; 986 void *lpc_mem; 987 int rc; 988 989 /* Test harness initialisation */ 990 lpc_mem = calloc(1, 1 * 1024 * 1024); 991 assert(lpc_mem); 992 993 /* BMC initialisation */ 994 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, 3 * MCTP_BTU, 995 &kcs, lpc_mem); 996 assert(!rc); 997 998 /* Host initialisation */ 999 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, 1000 2 * MCTP_BTU, &kcs, lpc_mem); 1001 assert(!rc); 1002 1003 rc = mctp_astlpc_poll(bmc.astlpc); 1004 assert(rc == 0); 1005 1006 rc = mctp_astlpc_poll(host.astlpc); 1007 assert(rc == 0); 1008 1009 endpoint_destroy(&host); 1010 endpoint_destroy(&bmc); 1011 free(lpc_mem); 1012 } 1013 1014 static void astlpc_test_negotiate_mtu_low_high(void) 1015 { 1016 struct astlpc_endpoint bmc, host; 1017 uint8_t kcs[2] = { 0 }; 1018 void *lpc_mem; 1019 int rc; 1020 1021 /* Test harness initialisation */ 1022 lpc_mem = calloc(1, 1 * 1024 * 1024); 1023 assert(lpc_mem); 1024 1025 /* BMC initialisation */ 1026 rc = endpoint_init(&bmc, 8, MCTP_BINDING_ASTLPC_MODE_BMC, 3 * MCTP_BTU, 1027 &kcs, lpc_mem); 1028 assert(!rc); 1029 1030 /* Host initialisation with low MTU */ 1031 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, 1032 2 * MCTP_BTU, &kcs, lpc_mem); 1033 assert(!rc); 1034 1035 /* Process low MTU proposal */ 1036 rc = mctp_astlpc_poll(bmc.astlpc); 1037 assert(rc == 0); 1038 1039 /* Accept low MTU proposal */ 1040 rc = mctp_astlpc_poll(host.astlpc); 1041 assert(rc == 0); 1042 1043 assert(host.astlpc->layout.rx.size == 1044 ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(2 * MCTP_BTU))); 1045 1046 /* Tear-down the host so we can bring up a new one */ 1047 endpoint_destroy(&host); 1048 1049 /* 1050 * Bring up a new host endpoint with a higher MTU than we previously 1051 * negotiated 1052 */ 1053 rc = endpoint_init(&host, 9, MCTP_BINDING_ASTLPC_MODE_HOST, 1054 3 * MCTP_BTU, &kcs, lpc_mem); 1055 assert(!rc); 1056 1057 /* Process high MTU proposal */ 1058 rc = mctp_astlpc_poll(bmc.astlpc); 1059 assert(rc == 0); 1060 1061 /* Accept high MTU proposal */ 1062 rc = mctp_astlpc_poll(host.astlpc); 1063 assert(rc == 0); 1064 1065 assert(host.astlpc->layout.rx.size == 1066 ASTLPC_PACKET_SIZE(MCTP_PACKET_SIZE(3 * MCTP_BTU))); 1067 1068 endpoint_destroy(&host); 1069 endpoint_destroy(&bmc); 1070 free(lpc_mem); 1071 } 1072 1073 /* clang-format off */ 1074 #define TEST_CASE(test) { #test, test } 1075 static const struct { 1076 const char *name; 1077 void (*test)(void); 1078 } astlpc_tests[] = { 1079 TEST_CASE(astlpc_test_simple_init), 1080 TEST_CASE(astlpc_test_bad_version), 1081 TEST_CASE(astlpc_test_incompatible_versions), 1082 TEST_CASE(astlpc_test_choose_bmc_ver_cur), 1083 TEST_CASE(astlpc_test_choose_host_ver_cur), 1084 TEST_CASE(astlpc_test_version_host_fails_negotiation), 1085 TEST_CASE(astlpc_test_version_bmc_fails_negotiation), 1086 TEST_CASE(astlpc_test_host_before_bmc), 1087 TEST_CASE(astlpc_test_simple_message_bmc_to_host), 1088 TEST_CASE(astlpc_test_simple_message_host_to_bmc), 1089 TEST_CASE(astlpc_test_packetised_message_bmc_to_host), 1090 TEST_CASE(astlpc_test_simple_indirect_message_bmc_to_host), 1091 TEST_CASE(astlpc_test_host_tx_bmc_gone), 1092 TEST_CASE(astlpc_test_poll_not_ready), 1093 TEST_CASE(astlpc_test_undefined_command), 1094 TEST_CASE(astlpc_test_buffers_rx_offset_overflow), 1095 TEST_CASE(astlpc_test_buffers_tx_offset_overflow), 1096 TEST_CASE(astlpc_test_buffers_rx_size_overflow), 1097 TEST_CASE(astlpc_test_buffers_tx_size_overflow), 1098 TEST_CASE(astlpc_test_buffers_rx_window_violation), 1099 TEST_CASE(astlpc_test_buffers_tx_window_violation), 1100 TEST_CASE(astlpc_test_buffers_rx_size_fails_btu), 1101 TEST_CASE(astlpc_test_buffers_tx_size_fails_btu), 1102 TEST_CASE(astlpc_test_buffers_overlap_rx_low), 1103 TEST_CASE(astlpc_test_buffers_overlap_tx_low), 1104 TEST_CASE(astlpc_test_buffers_bad_host_proposal), 1105 TEST_CASE(astlpc_test_buffers_bad_bmc_proposal), 1106 TEST_CASE(astlpc_test_buffers_bad_bmc_negotiation), 1107 TEST_CASE(astlpc_test_buffers_overlap_exact), 1108 TEST_CASE(astlpc_test_buffers_overlap_control), 1109 TEST_CASE(astlpc_test_buffers_bad_host_init), 1110 TEST_CASE(astlpc_test_negotiate_increased_mtu), 1111 TEST_CASE(astlpc_test_negotiate_mtu_low_high), 1112 }; 1113 /* clang-format on */ 1114 1115 #ifndef BUILD_ASSERT 1116 #define BUILD_ASSERT(x) \ 1117 do { \ 1118 (void)sizeof(char[0 - (!(x))]); \ 1119 } while (0) 1120 #endif 1121 1122 int main(void) 1123 { 1124 size_t i; 1125 1126 mctp_set_log_stdio(MCTP_LOG_DEBUG); 1127 1128 BUILD_ASSERT(ARRAY_SIZE(astlpc_tests) < SIZE_MAX); 1129 for (i = 0; i < ARRAY_SIZE(astlpc_tests); i++) { 1130 mctp_prlog(MCTP_LOG_DEBUG, "begin: %s", astlpc_tests[i].name); 1131 astlpc_tests[i].test(); 1132 mctp_prlog(MCTP_LOG_DEBUG, "end: %s\n", astlpc_tests[i].name); 1133 } 1134 1135 return 0; 1136 } 1137