1 /* 2 * Copyright 2020 Google Inc. 3 * 4 * Licensed under the Apache License, Version 2.0 (the "License"); 5 * you may not use this file except in compliance with the License. 6 * You may obtain a copy of the License at 7 * 8 * http://www.apache.org/licenses/LICENSE-2.0 9 * 10 * Unless required by applicable law or agreed to in writing, software 11 * distributed under the License is distributed on an "AS IS" BASIS, 12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 * See the License for the specific language governing permissions and 14 * limitations under the License. 15 */ 16 17 #include "internal_sys_mock.hpp" 18 #include "pci.hpp" 19 #include "pciaccess_mock.hpp" 20 #include "tool_errors.hpp" 21 22 #include <stdplus/raw.hpp> 23 24 #include <algorithm> 25 #include <cstdlib> 26 #include <span> 27 #include <string> 28 #include <vector> 29 30 #include <gtest/gtest.h> 31 32 namespace host_tool 33 { 34 namespace 35 { 36 37 using namespace std::string_literals; 38 39 using ::testing::Assign; 40 using ::testing::ContainerEq; 41 using ::testing::DoAll; 42 using ::testing::Each; 43 using ::testing::Eq; 44 using ::testing::InSequence; 45 using ::testing::NotNull; 46 using ::testing::Return; 47 using ::testing::SetArgPointee; 48 49 // TODO: switch to ConainerEq for C++20 50 MATCHER_P(SpanEq, s, "") 51 { 52 return arg.size() == s.size() && !memcmp(arg.data(), s.data(), s.size()); 53 } 54 55 MATCHER_P(PciIdMatch, m, "") 56 { 57 return (arg->vendor_id == m->vendor_id && arg->device_id == m->device_id && 58 arg->subvendor_id == m->subvendor_id && 59 arg->subdevice_id == m->subdevice_id); 60 } 61 62 pci_device_iterator* mockIter = reinterpret_cast<pci_device_iterator*>(0x42); 63 64 constexpr pciaddr_t mockBaseAddr = 0xdeadbeef; 65 constexpr pciaddr_t mockRegionSize = 0x20000; 66 67 class Device 68 { 69 public: 70 virtual ~Device() = default; 71 virtual const struct pci_id_match* getMatch() const = 0; 72 virtual struct pci_device getDevice() const = 0; expectSetup(PciAccessMock &,const struct pci_device &) const73 virtual void expectSetup(PciAccessMock&, const struct pci_device&) const {}; 74 virtual std::unique_ptr<PciBridgeIntf> getBridge( 75 PciAccess* pci, bool skipBridgeDisable = false) const = 0; 76 virtual std::string getName() const = 0; 77 }; 78 79 class NuvotonDevice : public Device 80 { 81 public: getMatch() const82 const struct pci_id_match* getMatch() const override 83 { 84 return &match; 85 } 86 getDevice() const87 struct pci_device getDevice() const override 88 { 89 struct pci_device dev; 90 91 dev.vendor_id = match.vendor_id; 92 dev.device_id = match.device_id; 93 94 dev.regions[0].is_IO = false; 95 dev.regions[0].base_addr = mockBaseAddr; 96 dev.regions[0].size = mockRegionSize; 97 98 return dev; 99 } 100 expectSetup(PciAccessMock & pciMock,const struct pci_device & dev) const101 void expectSetup(PciAccessMock& pciMock, 102 const struct pci_device& dev) const override 103 { 104 static constexpr std::uint8_t defaultVal = 0x40; 105 106 InSequence in; 107 108 EXPECT_CALL(pciMock, 109 pci_device_cfg_read_u8(Eq(&dev), NotNull(), config)) 110 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0))); 111 EXPECT_CALL(pciMock, pci_device_cfg_write_u8( 112 Eq(&dev), defaultVal | bridgeEnabled, config)) 113 .WillOnce(Return(0)); 114 115 EXPECT_CALL(pciMock, 116 pci_device_cfg_read_u8(Eq(&dev), NotNull(), config)) 117 .WillOnce( 118 DoAll(SetArgPointee<1>(defaultVal | bridgeEnabled), Return(0))); 119 EXPECT_CALL(pciMock, 120 pci_device_cfg_write_u8(Eq(&dev), defaultVal, config)) 121 .WillOnce(Return(0)); 122 } 123 getBridge(PciAccess * pci,bool skipBridgeDisable=false) const124 std::unique_ptr<PciBridgeIntf> getBridge( 125 PciAccess* pci, bool skipBridgeDisable = false) const override 126 { 127 return std::make_unique<NuvotonPciBridge>(pci, skipBridgeDisable); 128 } 129 getName() const130 std::string getName() const override 131 { 132 return "Nuvoton"s; 133 } 134 135 /* Offset to the config register */ 136 static constexpr int config = 0x04; 137 /* Second bit determines whether bridge is enabled */ 138 static constexpr std::uint8_t bridgeEnabled = 0x02; 139 140 private: 141 static constexpr struct pci_id_match match{ 142 0x1050, 0x0750, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0}; 143 }; 144 145 class AspeedDevice : public Device 146 { 147 public: getMatch() const148 const struct pci_id_match* getMatch() const override 149 { 150 return &match; 151 } 152 getDevice() const153 struct pci_device getDevice() const override 154 { 155 struct pci_device dev; 156 157 dev.vendor_id = match.vendor_id; 158 dev.device_id = match.device_id; 159 160 dev.regions[1].is_IO = false; 161 dev.regions[1].base_addr = mockBaseAddr; 162 dev.regions[1].size = mockRegionSize; 163 164 return dev; 165 } 166 getBridge(PciAccess * pci,bool skipBridgeDisable=false) const167 std::unique_ptr<PciBridgeIntf> getBridge( 168 PciAccess* pci, bool skipBridgeDisable = false) const override 169 { 170 return std::make_unique<AspeedPciBridge>(pci, skipBridgeDisable); 171 } 172 getName() const173 std::string getName() const override 174 { 175 return "Aspeed"s; 176 } 177 178 /* Offset to the config region */ 179 static constexpr int config = 0x0f000; 180 /* Lower bit determines whether bridge is enabled */ 181 static constexpr std::uint8_t bridgeEnabled = 0x01; 182 /* Offset to the MMIO address configuration */ 183 static constexpr int bridge = 0x0f004; 184 185 private: 186 static constexpr struct pci_id_match match{ 187 0x1a03, 0x2000, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0}; 188 }; 189 190 NuvotonDevice nuvotonDevice; 191 AspeedDevice aspeedDevice; 192 193 class PciSetupTest : public testing::TestWithParam<Device*> 194 {}; 195 196 /* Handle device not found */ TEST_P(PciSetupTest,NotFound)197 TEST_P(PciSetupTest, NotFound) 198 { 199 PciAccessMock pciMock; 200 201 InSequence in; 202 203 EXPECT_CALL(pciMock, pci_id_match_iterator_create( 204 PciIdMatch(GetParam()->getMatch()))) 205 .WillOnce(Return(mockIter)); 206 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter))) 207 .WillOnce(Return(nullptr)); 208 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1); 209 210 EXPECT_THROW(GetParam()->getBridge(&pciMock), NotFoundException); 211 } 212 213 /* Test finding device but probe fails */ TEST_P(PciSetupTest,ProbeFail)214 TEST_P(PciSetupTest, ProbeFail) 215 { 216 PciAccessMock pciMock; 217 struct pci_device dev; 218 219 EXPECT_CALL(pciMock, pci_id_match_iterator_create( 220 PciIdMatch(GetParam()->getMatch()))) 221 .WillOnce(Return(mockIter)); 222 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter))) 223 .WillOnce(Return(&dev)) 224 .WillRepeatedly(Return(nullptr)); 225 226 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))).WillOnce(Return(EFAULT)); 227 228 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1); 229 230 EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error); 231 } 232 233 /* Test finding device but mapping fails */ TEST_P(PciSetupTest,MapFail)234 TEST_P(PciSetupTest, MapFail) 235 { 236 PciAccessMock pciMock; 237 struct pci_device dev; 238 239 EXPECT_CALL(pciMock, pci_id_match_iterator_create( 240 PciIdMatch(GetParam()->getMatch()))) 241 .WillOnce(Return(mockIter)); 242 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter))) 243 .WillOnce(Return(&dev)) 244 .WillRepeatedly(Return(nullptr)); 245 246 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))) 247 .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0))); 248 249 EXPECT_CALL(pciMock, 250 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize, 251 PCI_DEV_MAP_FLAG_WRITABLE, NotNull())) 252 .WillOnce(Return(EFAULT)); 253 254 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1); 255 256 EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error); 257 } 258 259 /* Test finding device but unmapping fails */ TEST_P(PciSetupTest,UnmapFail)260 TEST_P(PciSetupTest, UnmapFail) 261 { 262 PciAccessMock pciMock; 263 struct pci_device dev; 264 std::vector<std::uint8_t> region(mockRegionSize); 265 266 EXPECT_CALL(pciMock, pci_id_match_iterator_create( 267 PciIdMatch(GetParam()->getMatch()))) 268 .WillOnce(Return(mockIter)); 269 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter))) 270 .WillOnce(Return(&dev)) 271 .WillRepeatedly(Return(nullptr)); 272 273 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))) 274 .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0))); 275 276 EXPECT_CALL(pciMock, 277 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize, 278 PCI_DEV_MAP_FLAG_WRITABLE, NotNull())) 279 .WillOnce(DoAll(SetArgPointee<4>(region.data()), Return(0))); 280 281 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1); 282 EXPECT_CALL(pciMock, pci_device_unmap_range(Eq(&dev), Eq(region.data()), 283 mockRegionSize)) 284 .WillOnce(Return(EFAULT)); 285 286 GetParam()->expectSetup(pciMock, dev); 287 // This will print an error but not throw 288 GetParam()->getBridge(&pciMock); 289 } 290 291 /* Create expectations on pciMock for finding device and mapping memory region 292 */ expectSetup(PciAccessMock & pciMock,struct pci_device & dev,Device * param,std::uint8_t * region,bool deviceExpectations=true)293 void expectSetup(PciAccessMock& pciMock, struct pci_device& dev, Device* param, 294 std::uint8_t* region, bool deviceExpectations = true) 295 { 296 EXPECT_CALL(pciMock, 297 pci_id_match_iterator_create(PciIdMatch(param->getMatch()))) 298 .WillOnce(Return(mockIter)); 299 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter))) 300 .WillOnce(Return(&dev)) 301 .WillRepeatedly(Return(nullptr)); 302 303 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))) 304 .WillOnce(DoAll(Assign(&dev, param->getDevice()), Return(0))); 305 306 EXPECT_CALL(pciMock, 307 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize, 308 PCI_DEV_MAP_FLAG_WRITABLE, NotNull())) 309 .WillOnce(DoAll(SetArgPointee<4>(region), Return(0))); 310 311 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1); 312 EXPECT_CALL(pciMock, 313 pci_device_unmap_range(Eq(&dev), Eq(region), mockRegionSize)) 314 .WillOnce(Return(0)); 315 316 EXPECT_CALL(pciMock, pci_device_enable(Eq(&dev))).Times(1); 317 318 if (deviceExpectations) 319 param->expectSetup(pciMock, dev); 320 } 321 322 /* Test finding device and mapping memory region */ TEST_P(PciSetupTest,Success)323 TEST_P(PciSetupTest, Success) 324 { 325 PciAccessMock pciMock; 326 struct pci_device dev; 327 std::vector<std::uint8_t> region(mockRegionSize); 328 329 expectSetup(pciMock, dev, GetParam(), region.data()); 330 331 GetParam()->getBridge(&pciMock); 332 } 333 334 INSTANTIATE_TEST_SUITE_P(Default, PciSetupTest, 335 ::testing::Values(&nuvotonDevice, &aspeedDevice), __anond86d8cb60202(const testing::TestParamInfo<Device*>& info) 336 [](const testing::TestParamInfo<Device*>& info) { 337 return info.param->getName(); 338 }); 339 TEST(NuvotonWriteTest,TooLarge)340 TEST(NuvotonWriteTest, TooLarge) 341 { 342 PciAccessMock pciMock; 343 struct pci_device dev; 344 std::vector<std::uint8_t> region(mockRegionSize); 345 std::vector<std::uint8_t> data(0x4001); 346 347 expectSetup(pciMock, dev, &nuvotonDevice, region.data()); 348 349 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock); 350 EXPECT_THROW(bridge->write(std::span<std::uint8_t>(data)), ToolException); 351 } 352 TEST(NuvotonWriteTest,Success)353 TEST(NuvotonWriteTest, Success) 354 { 355 PciAccessMock pciMock; 356 struct pci_device dev; 357 std::vector<std::uint8_t> region(mockRegionSize); 358 std::vector<std::uint8_t> data(0x4000); 359 360 std::generate(data.begin(), data.end(), std::rand); 361 362 expectSetup(pciMock, dev, &nuvotonDevice, region.data()); 363 364 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock); 365 bridge->write(std::span<std::uint8_t>(data)); 366 367 EXPECT_THAT(std::span<uint8_t>(®ion[0], data.size()), 368 SpanEq(std::span<uint8_t>(data))); 369 } 370 TEST(NuvotonConfigureTest,Success)371 TEST(NuvotonConfigureTest, Success) 372 { 373 PciAccessMock pciMock; 374 struct pci_device dev; 375 std::vector<std::uint8_t> region(mockRegionSize); 376 ipmi_flash::PciConfigResponse config{0x123bea51}; 377 378 expectSetup(pciMock, dev, &nuvotonDevice, region.data()); 379 380 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock); 381 bridge->configure(config); 382 383 /* No effect from calling configure(), so the whole region should be 0 */ 384 EXPECT_THAT(region, Each(0)); 385 } 386 TEST(NuvotonDataLengthTest,Success)387 TEST(NuvotonDataLengthTest, Success) 388 { 389 PciAccessMock pciMock; 390 struct pci_device dev; 391 std::vector<std::uint8_t> region(mockRegionSize); 392 393 expectSetup(pciMock, dev, &nuvotonDevice, region.data()); 394 395 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock); 396 EXPECT_EQ(bridge->getDataLength(), 0x4000); 397 } 398 399 /* Make sure config register is left alone if the bridge is already enabled */ TEST(NuvotonBridgeTest,AlreadyEnabledSuccess)400 TEST(NuvotonBridgeTest, AlreadyEnabledSuccess) 401 { 402 PciAccessMock pciMock; 403 struct pci_device dev; 404 std::vector<std::uint8_t> region(mockRegionSize); 405 406 constexpr std::uint8_t defaultVal = 0x40; 407 408 /* Only set standard expectations; not those from nuvotonDevice */ 409 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 410 411 { 412 InSequence in; 413 414 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 415 NuvotonDevice::config)) 416 .WillOnce(DoAll( 417 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled), 418 Return(0))); 419 420 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 421 NuvotonDevice::config)) 422 .WillOnce(DoAll( 423 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled), 424 Return(0))); 425 EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal, 426 NuvotonDevice::config)) 427 .WillOnce(Return(0)); 428 } 429 430 nuvotonDevice.getBridge(&pciMock); 431 } 432 433 /* Read fails when attempting to setup the bridge */ TEST(NuvotonBridgeTest,ReadSetupFail)434 TEST(NuvotonBridgeTest, ReadSetupFail) 435 { 436 PciAccessMock pciMock; 437 struct pci_device dev; 438 std::vector<std::uint8_t> region(mockRegionSize); 439 440 /* Only set standard expectations; not those from nuvotonDevice */ 441 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 442 443 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 444 NuvotonDevice::config)) 445 .WillOnce(Return(EFAULT)); 446 447 EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error); 448 } 449 450 /* Write fails when attempting to setup the bridge */ TEST(NuvotonBridgeTest,WriteSetupFail)451 TEST(NuvotonBridgeTest, WriteSetupFail) 452 { 453 PciAccessMock pciMock; 454 struct pci_device dev; 455 std::vector<std::uint8_t> region(mockRegionSize); 456 457 constexpr std::uint8_t defaultVal = 0x40; 458 459 /* Only set standard expectations; not those from nuvotonDevice */ 460 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 461 462 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 463 NuvotonDevice::config)) 464 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0))); 465 EXPECT_CALL(pciMock, 466 pci_device_cfg_write_u8( 467 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled, 468 NuvotonDevice::config)) 469 .WillOnce(Return(EFAULT)); 470 471 EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error); 472 } 473 474 /* Read fails when attempting to disable the bridge */ TEST(NuvotonBridgeTest,ReadDisableFail)475 TEST(NuvotonBridgeTest, ReadDisableFail) 476 { 477 PciAccessMock pciMock; 478 struct pci_device dev; 479 std::vector<std::uint8_t> region(mockRegionSize); 480 481 constexpr std::uint8_t defaultVal = 0x40; 482 483 /* Only set standard expectations; not those from nuvotonDevice */ 484 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 485 486 { 487 InSequence in; 488 489 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 490 NuvotonDevice::config)) 491 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0))); 492 EXPECT_CALL(pciMock, 493 pci_device_cfg_write_u8( 494 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled, 495 NuvotonDevice::config)) 496 .WillOnce(Return(0)); 497 498 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 499 NuvotonDevice::config)) 500 .WillOnce(Return(EFAULT)); 501 } 502 503 nuvotonDevice.getBridge(&pciMock); 504 } 505 506 /* Write fails when attempting to disable the bridge */ TEST(NuvotonBridgeTest,WriteDisableFail)507 TEST(NuvotonBridgeTest, WriteDisableFail) 508 { 509 PciAccessMock pciMock; 510 struct pci_device dev; 511 std::vector<std::uint8_t> region(mockRegionSize); 512 513 constexpr std::uint8_t defaultVal = 0x40; 514 515 /* Only set standard expectations; not those from nuvotonDevice */ 516 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 517 518 { 519 InSequence in; 520 521 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 522 NuvotonDevice::config)) 523 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0))); 524 EXPECT_CALL(pciMock, 525 pci_device_cfg_write_u8( 526 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled, 527 NuvotonDevice::config)) 528 .WillOnce(Return(0)); 529 530 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 531 NuvotonDevice::config)) 532 .WillOnce(DoAll( 533 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled), 534 Return(0))); 535 EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal, 536 NuvotonDevice::config)) 537 .WillOnce(Return(EFAULT)); 538 } 539 540 nuvotonDevice.getBridge(&pciMock); 541 } 542 543 /* Make sure the bridge gets enabled when needed */ TEST(NuvotonBridgeTest,NotEnabledSuccess)544 TEST(NuvotonBridgeTest, NotEnabledSuccess) 545 { 546 PciAccessMock pciMock; 547 struct pci_device dev; 548 std::vector<std::uint8_t> region(mockRegionSize); 549 550 expectSetup(pciMock, dev, &nuvotonDevice, region.data()); 551 nuvotonDevice.getBridge(&pciMock); 552 } 553 554 /* Make sure it skips the disable bridge call when skipBridgeDisable is true */ TEST(NuvotonBridgeTest,SkipDisable)555 TEST(NuvotonBridgeTest, SkipDisable) 556 { 557 PciAccessMock pciMock; 558 struct pci_device dev; 559 std::vector<std::uint8_t> region(mockRegionSize); 560 561 constexpr std::uint8_t defaultVal = 0x40; 562 563 /* Only set standard expectations; not those from nuvotonDevice */ 564 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false); 565 566 { 567 InSequence in; 568 569 /* Only expect call for enableBridge() */ 570 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(), 571 NuvotonDevice::config)) 572 .WillOnce(DoAll( 573 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled), 574 Return(0))); 575 } 576 577 /* Setting skipBridgeDisable to true */ 578 nuvotonDevice.getBridge(&pciMock, true); 579 } 580 TEST(AspeedWriteTest,TooLarge)581 TEST(AspeedWriteTest, TooLarge) 582 { 583 PciAccessMock pciMock; 584 struct pci_device dev; 585 std::vector<std::uint8_t> region(mockRegionSize); 586 std::vector<std::uint8_t> data(0x10001); 587 588 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 589 590 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 591 EXPECT_THROW(bridge->write(std::span<std::uint8_t>(data)), ToolException); 592 } 593 TEST(AspeedWriteTest,Success)594 TEST(AspeedWriteTest, Success) 595 { 596 PciAccessMock pciMock; 597 struct pci_device dev; 598 std::vector<std::uint8_t> region(mockRegionSize); 599 std::vector<std::uint8_t> data(0x10000); 600 601 std::generate(data.begin(), data.end(), std::rand); 602 603 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 604 605 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 606 bridge->write(std::span<std::uint8_t>(data)); 607 608 EXPECT_THAT(std::span<uint8_t>(®ion[0x10000], data.size()), 609 SpanEq(std::span<uint8_t>(data))); 610 } 611 TEST(AspeedConfigureTest,Success)612 TEST(AspeedConfigureTest, Success) 613 { 614 PciAccessMock pciMock; 615 struct pci_device dev; 616 std::vector<std::uint8_t> region(mockRegionSize); 617 ipmi_flash::PciConfigResponse config{0x123bea51}; 618 619 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 620 621 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 622 bridge->configure(config); 623 624 auto configSpan = stdplus::raw::asSpan<uint8_t>(config); 625 EXPECT_THAT( 626 std::span<uint8_t>(®ion[AspeedDevice::bridge], sizeof(config)), 627 SpanEq(configSpan)); 628 } 629 TEST(AspeedDataLengthTest,Success)630 TEST(AspeedDataLengthTest, Success) 631 { 632 PciAccessMock pciMock; 633 struct pci_device dev; 634 std::vector<std::uint8_t> region(mockRegionSize); 635 636 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 637 638 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 639 EXPECT_EQ(bridge->getDataLength(), 0x10000); 640 } 641 642 /* Make sure config region is left alone if the bridge is already enabled */ TEST(AspeedBridgeTest,AlreadyEnabledSuccess)643 TEST(AspeedBridgeTest, AlreadyEnabledSuccess) 644 { 645 PciAccessMock pciMock; 646 struct pci_device dev; 647 std::vector<std::uint8_t> region(mockRegionSize); 648 649 constexpr std::uint8_t defaultVal = 0x42; 650 651 region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled; 652 653 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 654 655 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 656 657 { 658 std::vector<std::uint8_t> enabledRegion(mockRegionSize); 659 enabledRegion[AspeedDevice::config] = 660 defaultVal | AspeedDevice::bridgeEnabled; 661 EXPECT_THAT(region, ContainerEq(enabledRegion)); 662 } 663 664 bridge.reset(); 665 666 { 667 std::vector<std::uint8_t> disabledRegion(mockRegionSize); 668 disabledRegion[AspeedDevice::config] = defaultVal; 669 EXPECT_THAT(region, ContainerEq(disabledRegion)); 670 } 671 } 672 673 /* Make sure the config region remains the same even after cleanup if 674 * skipBridgeDisable is true */ TEST(AspeedBridgeTest,SkipDisable)675 TEST(AspeedBridgeTest, SkipDisable) 676 { 677 PciAccessMock pciMock; 678 struct pci_device dev; 679 std::vector<std::uint8_t> region(mockRegionSize); 680 681 constexpr std::uint8_t defaultVal = 0x42; 682 683 region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled; 684 685 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 686 687 /* Setting skipBridgeDisable to true */ 688 std::unique_ptr<PciBridgeIntf> bridge = 689 aspeedDevice.getBridge(&pciMock, true); 690 691 { 692 std::vector<std::uint8_t> enabledRegion(mockRegionSize); 693 enabledRegion[AspeedDevice::config] = 694 defaultVal | AspeedDevice::bridgeEnabled; 695 EXPECT_THAT(region, ContainerEq(enabledRegion)); 696 } 697 698 bridge.reset(); 699 700 { 701 std::vector<std::uint8_t> disabledRegion(mockRegionSize); 702 disabledRegion[AspeedDevice::config] = 703 defaultVal | AspeedDevice::bridgeEnabled; 704 EXPECT_THAT(region, ContainerEq(disabledRegion)); 705 } 706 } 707 708 /* Make sure the bridge gets enabled when needed */ TEST(AspeedBridgeTest,NotEnabledSuccess)709 TEST(AspeedBridgeTest, NotEnabledSuccess) 710 { 711 PciAccessMock pciMock; 712 struct pci_device dev; 713 std::vector<std::uint8_t> region(mockRegionSize); 714 715 constexpr std::uint8_t defaultVal = 0x42; 716 717 region[AspeedDevice::config] = defaultVal; 718 719 expectSetup(pciMock, dev, &aspeedDevice, region.data()); 720 721 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock); 722 723 { 724 std::vector<std::uint8_t> enabledRegion(mockRegionSize); 725 enabledRegion[AspeedDevice::config] = 726 defaultVal | AspeedDevice::bridgeEnabled; 727 EXPECT_THAT(region, ContainerEq(enabledRegion)); 728 } 729 730 bridge.reset(); 731 732 { 733 std::vector<std::uint8_t> disabledRegion(mockRegionSize); 734 disabledRegion[AspeedDevice::config] = defaultVal; 735 EXPECT_THAT(region, ContainerEq(disabledRegion)); 736 } 737 } 738 739 } // namespace 740 } // namespace host_tool 741