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>
75 getBridge(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
124 std::unique_ptr<PciBridgeIntf>
getBridge(PciAccess * pci,bool skipBridgeDisable=false) const125 getBridge(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 {
143 0x1050, 0x0750, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0
144 };
145 };
146
147 class AspeedDevice : public Device
148 {
149 public:
getMatch() const150 const struct pci_id_match* getMatch() const override
151 {
152 return &match;
153 }
154
getDevice() const155 struct pci_device getDevice() const override
156 {
157 struct pci_device dev;
158
159 dev.vendor_id = match.vendor_id;
160 dev.device_id = match.device_id;
161
162 dev.regions[1].is_IO = false;
163 dev.regions[1].base_addr = mockBaseAddr;
164 dev.regions[1].size = mockRegionSize;
165
166 return dev;
167 }
168
169 std::unique_ptr<PciBridgeIntf>
getBridge(PciAccess * pci,bool skipBridgeDisable=false) const170 getBridge(PciAccess* pci, bool skipBridgeDisable = false) const override
171 {
172 return std::make_unique<AspeedPciBridge>(pci, skipBridgeDisable);
173 }
174
getName() const175 std::string getName() const override
176 {
177 return "Aspeed"s;
178 }
179
180 /* Offset to the config region */
181 static constexpr int config = 0x0f000;
182 /* Lower bit determines whether bridge is enabled */
183 static constexpr std::uint8_t bridgeEnabled = 0x01;
184 /* Offset to the MMIO address configuration */
185 static constexpr int bridge = 0x0f004;
186
187 private:
188 static constexpr struct pci_id_match match
189 {
190 0x1a03, 0x2000, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0
191 };
192 };
193
194 NuvotonDevice nuvotonDevice;
195 AspeedDevice aspeedDevice;
196
197 class PciSetupTest : public testing::TestWithParam<Device*>
198 {};
199
200 /* Handle device not found */
TEST_P(PciSetupTest,NotFound)201 TEST_P(PciSetupTest, NotFound)
202 {
203 PciAccessMock pciMock;
204
205 InSequence in;
206
207 EXPECT_CALL(pciMock, pci_id_match_iterator_create(
208 PciIdMatch(GetParam()->getMatch())))
209 .WillOnce(Return(mockIter));
210 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
211 .WillOnce(Return(nullptr));
212 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
213
214 EXPECT_THROW(GetParam()->getBridge(&pciMock), NotFoundException);
215 }
216
217 /* Test finding device but probe fails */
TEST_P(PciSetupTest,ProbeFail)218 TEST_P(PciSetupTest, ProbeFail)
219 {
220 PciAccessMock pciMock;
221 struct pci_device dev;
222
223 EXPECT_CALL(pciMock, pci_id_match_iterator_create(
224 PciIdMatch(GetParam()->getMatch())))
225 .WillOnce(Return(mockIter));
226 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
227 .WillOnce(Return(&dev))
228 .WillRepeatedly(Return(nullptr));
229
230 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))).WillOnce(Return(EFAULT));
231
232 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
233
234 EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
235 }
236
237 /* Test finding device but mapping fails */
TEST_P(PciSetupTest,MapFail)238 TEST_P(PciSetupTest, MapFail)
239 {
240 PciAccessMock pciMock;
241 struct pci_device dev;
242
243 EXPECT_CALL(pciMock, pci_id_match_iterator_create(
244 PciIdMatch(GetParam()->getMatch())))
245 .WillOnce(Return(mockIter));
246 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
247 .WillOnce(Return(&dev))
248 .WillRepeatedly(Return(nullptr));
249
250 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
251 .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
252
253 EXPECT_CALL(pciMock,
254 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
255 PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
256 .WillOnce(Return(EFAULT));
257
258 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
259
260 EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
261 }
262
263 /* Test finding device but unmapping fails */
TEST_P(PciSetupTest,UnmapFail)264 TEST_P(PciSetupTest, UnmapFail)
265 {
266 PciAccessMock pciMock;
267 struct pci_device dev;
268 std::vector<std::uint8_t> region(mockRegionSize);
269
270 EXPECT_CALL(pciMock, pci_id_match_iterator_create(
271 PciIdMatch(GetParam()->getMatch())))
272 .WillOnce(Return(mockIter));
273 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
274 .WillOnce(Return(&dev))
275 .WillRepeatedly(Return(nullptr));
276
277 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
278 .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
279
280 EXPECT_CALL(pciMock,
281 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
282 PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
283 .WillOnce(DoAll(SetArgPointee<4>(region.data()), Return(0)));
284
285 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
286 EXPECT_CALL(pciMock, pci_device_unmap_range(Eq(&dev), Eq(region.data()),
287 mockRegionSize))
288 .WillOnce(Return(EFAULT));
289
290 GetParam()->expectSetup(pciMock, dev);
291 // This will print an error but not throw
292 GetParam()->getBridge(&pciMock);
293 }
294
295 /* Create expectations on pciMock for finding device and mapping memory region
296 */
expectSetup(PciAccessMock & pciMock,struct pci_device & dev,Device * param,std::uint8_t * region,bool deviceExpectations=true)297 void expectSetup(PciAccessMock& pciMock, struct pci_device& dev, Device* param,
298 std::uint8_t* region, bool deviceExpectations = true)
299 {
300 EXPECT_CALL(pciMock,
301 pci_id_match_iterator_create(PciIdMatch(param->getMatch())))
302 .WillOnce(Return(mockIter));
303 EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
304 .WillOnce(Return(&dev))
305 .WillRepeatedly(Return(nullptr));
306
307 EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
308 .WillOnce(DoAll(Assign(&dev, param->getDevice()), Return(0)));
309
310 EXPECT_CALL(pciMock,
311 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
312 PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
313 .WillOnce(DoAll(SetArgPointee<4>(region), Return(0)));
314
315 EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
316 EXPECT_CALL(pciMock,
317 pci_device_unmap_range(Eq(&dev), Eq(region), mockRegionSize))
318 .WillOnce(Return(0));
319
320 EXPECT_CALL(pciMock, pci_device_enable(Eq(&dev))).Times(1);
321
322 if (deviceExpectations)
323 param->expectSetup(pciMock, dev);
324 }
325
326 /* Test finding device and mapping memory region */
TEST_P(PciSetupTest,Success)327 TEST_P(PciSetupTest, Success)
328 {
329 PciAccessMock pciMock;
330 struct pci_device dev;
331 std::vector<std::uint8_t> region(mockRegionSize);
332
333 expectSetup(pciMock, dev, GetParam(), region.data());
334
335 GetParam()->getBridge(&pciMock);
336 }
337
338 INSTANTIATE_TEST_SUITE_P(Default, PciSetupTest,
339 ::testing::Values(&nuvotonDevice, &aspeedDevice),
__anond86d8cb60202(const testing::TestParamInfo<Device*>& info) 340 [](const testing::TestParamInfo<Device*>& info) {
341 return info.param->getName();
342 });
343
TEST(NuvotonWriteTest,TooLarge)344 TEST(NuvotonWriteTest, TooLarge)
345 {
346 PciAccessMock pciMock;
347 struct pci_device dev;
348 std::vector<std::uint8_t> region(mockRegionSize);
349 std::vector<std::uint8_t> data(0x4001);
350
351 expectSetup(pciMock, dev, &nuvotonDevice, region.data());
352
353 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
354 EXPECT_THROW(bridge->write(std::span<std::uint8_t>(data)), ToolException);
355 }
356
TEST(NuvotonWriteTest,Success)357 TEST(NuvotonWriteTest, Success)
358 {
359 PciAccessMock pciMock;
360 struct pci_device dev;
361 std::vector<std::uint8_t> region(mockRegionSize);
362 std::vector<std::uint8_t> data(0x4000);
363
364 std::generate(data.begin(), data.end(), std::rand);
365
366 expectSetup(pciMock, dev, &nuvotonDevice, region.data());
367
368 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
369 bridge->write(std::span<std::uint8_t>(data));
370
371 EXPECT_THAT(std::span<uint8_t>(®ion[0], data.size()),
372 SpanEq(std::span<uint8_t>(data)));
373 }
374
TEST(NuvotonConfigureTest,Success)375 TEST(NuvotonConfigureTest, Success)
376 {
377 PciAccessMock pciMock;
378 struct pci_device dev;
379 std::vector<std::uint8_t> region(mockRegionSize);
380 ipmi_flash::PciConfigResponse config{0x123bea51};
381
382 expectSetup(pciMock, dev, &nuvotonDevice, region.data());
383
384 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
385 bridge->configure(config);
386
387 /* No effect from calling configure(), so the whole region should be 0 */
388 EXPECT_THAT(region, Each(0));
389 }
390
TEST(NuvotonDataLengthTest,Success)391 TEST(NuvotonDataLengthTest, Success)
392 {
393 PciAccessMock pciMock;
394 struct pci_device dev;
395 std::vector<std::uint8_t> region(mockRegionSize);
396
397 expectSetup(pciMock, dev, &nuvotonDevice, region.data());
398
399 std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
400 EXPECT_EQ(bridge->getDataLength(), 0x4000);
401 }
402
403 /* Make sure config register is left alone if the bridge is already enabled */
TEST(NuvotonBridgeTest,AlreadyEnabledSuccess)404 TEST(NuvotonBridgeTest, AlreadyEnabledSuccess)
405 {
406 PciAccessMock pciMock;
407 struct pci_device dev;
408 std::vector<std::uint8_t> region(mockRegionSize);
409
410 constexpr std::uint8_t defaultVal = 0x40;
411
412 /* Only set standard expectations; not those from nuvotonDevice */
413 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
414
415 {
416 InSequence in;
417
418 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
419 NuvotonDevice::config))
420 .WillOnce(DoAll(
421 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
422 Return(0)));
423
424 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
425 NuvotonDevice::config))
426 .WillOnce(DoAll(
427 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
428 Return(0)));
429 EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
430 NuvotonDevice::config))
431 .WillOnce(Return(0));
432 }
433
434 nuvotonDevice.getBridge(&pciMock);
435 }
436
437 /* Read fails when attempting to setup the bridge */
TEST(NuvotonBridgeTest,ReadSetupFail)438 TEST(NuvotonBridgeTest, ReadSetupFail)
439 {
440 PciAccessMock pciMock;
441 struct pci_device dev;
442 std::vector<std::uint8_t> region(mockRegionSize);
443
444 /* Only set standard expectations; not those from nuvotonDevice */
445 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
446
447 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
448 NuvotonDevice::config))
449 .WillOnce(Return(EFAULT));
450
451 EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
452 }
453
454 /* Write fails when attempting to setup the bridge */
TEST(NuvotonBridgeTest,WriteSetupFail)455 TEST(NuvotonBridgeTest, WriteSetupFail)
456 {
457 PciAccessMock pciMock;
458 struct pci_device dev;
459 std::vector<std::uint8_t> region(mockRegionSize);
460
461 constexpr std::uint8_t defaultVal = 0x40;
462
463 /* Only set standard expectations; not those from nuvotonDevice */
464 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
465
466 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
467 NuvotonDevice::config))
468 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
469 EXPECT_CALL(pciMock,
470 pci_device_cfg_write_u8(
471 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
472 NuvotonDevice::config))
473 .WillOnce(Return(EFAULT));
474
475 EXPECT_THROW(nuvotonDevice.getBridge(&pciMock), std::system_error);
476 }
477
478 /* Read fails when attempting to disable the bridge */
TEST(NuvotonBridgeTest,ReadDisableFail)479 TEST(NuvotonBridgeTest, ReadDisableFail)
480 {
481 PciAccessMock pciMock;
482 struct pci_device dev;
483 std::vector<std::uint8_t> region(mockRegionSize);
484
485 constexpr std::uint8_t defaultVal = 0x40;
486
487 /* Only set standard expectations; not those from nuvotonDevice */
488 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
489
490 {
491 InSequence in;
492
493 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
494 NuvotonDevice::config))
495 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
496 EXPECT_CALL(pciMock,
497 pci_device_cfg_write_u8(
498 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
499 NuvotonDevice::config))
500 .WillOnce(Return(0));
501
502 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
503 NuvotonDevice::config))
504 .WillOnce(Return(EFAULT));
505 }
506
507 nuvotonDevice.getBridge(&pciMock);
508 }
509
510 /* Write fails when attempting to disable the bridge */
TEST(NuvotonBridgeTest,WriteDisableFail)511 TEST(NuvotonBridgeTest, WriteDisableFail)
512 {
513 PciAccessMock pciMock;
514 struct pci_device dev;
515 std::vector<std::uint8_t> region(mockRegionSize);
516
517 constexpr std::uint8_t defaultVal = 0x40;
518
519 /* Only set standard expectations; not those from nuvotonDevice */
520 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
521
522 {
523 InSequence in;
524
525 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
526 NuvotonDevice::config))
527 .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
528 EXPECT_CALL(pciMock,
529 pci_device_cfg_write_u8(
530 Eq(&dev), defaultVal | NuvotonDevice::bridgeEnabled,
531 NuvotonDevice::config))
532 .WillOnce(Return(0));
533
534 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
535 NuvotonDevice::config))
536 .WillOnce(DoAll(
537 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
538 Return(0)));
539 EXPECT_CALL(pciMock, pci_device_cfg_write_u8(Eq(&dev), defaultVal,
540 NuvotonDevice::config))
541 .WillOnce(Return(EFAULT));
542 }
543
544 nuvotonDevice.getBridge(&pciMock);
545 }
546
547 /* Make sure the bridge gets enabled when needed */
TEST(NuvotonBridgeTest,NotEnabledSuccess)548 TEST(NuvotonBridgeTest, NotEnabledSuccess)
549 {
550 PciAccessMock pciMock;
551 struct pci_device dev;
552 std::vector<std::uint8_t> region(mockRegionSize);
553
554 expectSetup(pciMock, dev, &nuvotonDevice, region.data());
555 nuvotonDevice.getBridge(&pciMock);
556 }
557
558 /* Make sure it skips the disable bridge call when skipBridgeDisable is true */
TEST(NuvotonBridgeTest,SkipDisable)559 TEST(NuvotonBridgeTest, SkipDisable)
560 {
561 PciAccessMock pciMock;
562 struct pci_device dev;
563 std::vector<std::uint8_t> region(mockRegionSize);
564
565 constexpr std::uint8_t defaultVal = 0x40;
566
567 /* Only set standard expectations; not those from nuvotonDevice */
568 expectSetup(pciMock, dev, &nuvotonDevice, region.data(), false);
569
570 {
571 InSequence in;
572
573 /* Only expect call for enableBridge() */
574 EXPECT_CALL(pciMock, pci_device_cfg_read_u8(Eq(&dev), NotNull(),
575 NuvotonDevice::config))
576 .WillOnce(DoAll(
577 SetArgPointee<1>(defaultVal | NuvotonDevice::bridgeEnabled),
578 Return(0)));
579 }
580
581 /* Setting skipBridgeDisable to true */
582 nuvotonDevice.getBridge(&pciMock, true);
583 }
584
TEST(AspeedWriteTest,TooLarge)585 TEST(AspeedWriteTest, TooLarge)
586 {
587 PciAccessMock pciMock;
588 struct pci_device dev;
589 std::vector<std::uint8_t> region(mockRegionSize);
590 std::vector<std::uint8_t> data(0x10001);
591
592 expectSetup(pciMock, dev, &aspeedDevice, region.data());
593
594 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
595 EXPECT_THROW(bridge->write(std::span<std::uint8_t>(data)), ToolException);
596 }
597
TEST(AspeedWriteTest,Success)598 TEST(AspeedWriteTest, Success)
599 {
600 PciAccessMock pciMock;
601 struct pci_device dev;
602 std::vector<std::uint8_t> region(mockRegionSize);
603 std::vector<std::uint8_t> data(0x10000);
604
605 std::generate(data.begin(), data.end(), std::rand);
606
607 expectSetup(pciMock, dev, &aspeedDevice, region.data());
608
609 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
610 bridge->write(std::span<std::uint8_t>(data));
611
612 EXPECT_THAT(std::span<uint8_t>(®ion[0x10000], data.size()),
613 SpanEq(std::span<uint8_t>(data)));
614 }
615
TEST(AspeedConfigureTest,Success)616 TEST(AspeedConfigureTest, Success)
617 {
618 PciAccessMock pciMock;
619 struct pci_device dev;
620 std::vector<std::uint8_t> region(mockRegionSize);
621 ipmi_flash::PciConfigResponse config{0x123bea51};
622
623 expectSetup(pciMock, dev, &aspeedDevice, region.data());
624
625 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
626 bridge->configure(config);
627
628 auto configSpan = stdplus::raw::asSpan<uint8_t>(config);
629 EXPECT_THAT(
630 std::span<uint8_t>(®ion[AspeedDevice::bridge], sizeof(config)),
631 SpanEq(configSpan));
632 }
633
TEST(AspeedDataLengthTest,Success)634 TEST(AspeedDataLengthTest, Success)
635 {
636 PciAccessMock pciMock;
637 struct pci_device dev;
638 std::vector<std::uint8_t> region(mockRegionSize);
639
640 expectSetup(pciMock, dev, &aspeedDevice, region.data());
641
642 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
643 EXPECT_EQ(bridge->getDataLength(), 0x10000);
644 }
645
646 /* Make sure config region is left alone if the bridge is already enabled */
TEST(AspeedBridgeTest,AlreadyEnabledSuccess)647 TEST(AspeedBridgeTest, AlreadyEnabledSuccess)
648 {
649 PciAccessMock pciMock;
650 struct pci_device dev;
651 std::vector<std::uint8_t> region(mockRegionSize);
652
653 constexpr std::uint8_t defaultVal = 0x42;
654
655 region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
656
657 expectSetup(pciMock, dev, &aspeedDevice, region.data());
658
659 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
660
661 {
662 std::vector<std::uint8_t> enabledRegion(mockRegionSize);
663 enabledRegion[AspeedDevice::config] =
664 defaultVal | AspeedDevice::bridgeEnabled;
665 EXPECT_THAT(region, ContainerEq(enabledRegion));
666 }
667
668 bridge.reset();
669
670 {
671 std::vector<std::uint8_t> disabledRegion(mockRegionSize);
672 disabledRegion[AspeedDevice::config] = defaultVal;
673 EXPECT_THAT(region, ContainerEq(disabledRegion));
674 }
675 }
676
677 /* Make sure the config region remains the same even after cleanup if
678 * skipBridgeDisable is true */
TEST(AspeedBridgeTest,SkipDisable)679 TEST(AspeedBridgeTest, SkipDisable)
680 {
681 PciAccessMock pciMock;
682 struct pci_device dev;
683 std::vector<std::uint8_t> region(mockRegionSize);
684
685 constexpr std::uint8_t defaultVal = 0x42;
686
687 region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
688
689 expectSetup(pciMock, dev, &aspeedDevice, region.data());
690
691 /* Setting skipBridgeDisable to true */
692 std::unique_ptr<PciBridgeIntf> bridge =
693 aspeedDevice.getBridge(&pciMock, true);
694
695 {
696 std::vector<std::uint8_t> enabledRegion(mockRegionSize);
697 enabledRegion[AspeedDevice::config] =
698 defaultVal | AspeedDevice::bridgeEnabled;
699 EXPECT_THAT(region, ContainerEq(enabledRegion));
700 }
701
702 bridge.reset();
703
704 {
705 std::vector<std::uint8_t> disabledRegion(mockRegionSize);
706 disabledRegion[AspeedDevice::config] =
707 defaultVal | AspeedDevice::bridgeEnabled;
708 EXPECT_THAT(region, ContainerEq(disabledRegion));
709 }
710 }
711
712 /* Make sure the bridge gets enabled when needed */
TEST(AspeedBridgeTest,NotEnabledSuccess)713 TEST(AspeedBridgeTest, NotEnabledSuccess)
714 {
715 PciAccessMock pciMock;
716 struct pci_device dev;
717 std::vector<std::uint8_t> region(mockRegionSize);
718
719 constexpr std::uint8_t defaultVal = 0x42;
720
721 region[AspeedDevice::config] = defaultVal;
722
723 expectSetup(pciMock, dev, &aspeedDevice, region.data());
724
725 std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
726
727 {
728 std::vector<std::uint8_t> enabledRegion(mockRegionSize);
729 enabledRegion[AspeedDevice::config] =
730 defaultVal | AspeedDevice::bridgeEnabled;
731 EXPECT_THAT(region, ContainerEq(enabledRegion));
732 }
733
734 bridge.reset();
735
736 {
737 std::vector<std::uint8_t> disabledRegion(mockRegionSize);
738 disabledRegion[AspeedDevice::config] = defaultVal;
739 EXPECT_THAT(region, ContainerEq(disabledRegion));
740 }
741 }
742
743 } // namespace
744 } // namespace host_tool
745