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 <string>
27 #include <vector>
28 
29 #include <gtest/gtest.h>
30 
31 namespace host_tool
32 {
33 namespace
34 {
35 
36 using namespace std::string_literals;
37 
38 using ::testing::Assign;
39 using ::testing::ContainerEq;
40 using ::testing::DoAll;
41 using ::testing::Each;
42 using ::testing::Eq;
43 using ::testing::InSequence;
44 using ::testing::NotNull;
45 using ::testing::Return;
46 using ::testing::SetArgPointee;
47 
48 // TODO: switch to ConainerEq for C++20
49 MATCHER_P(SpanEq, s, "")
50 {
51     return arg.size() == s.size() && !memcmp(arg.data(), s.data(), s.size());
52 }
53 
54 MATCHER_P(PciIdMatch, m, "")
55 {
56     return (arg->vendor_id == m->vendor_id && arg->device_id == m->device_id &&
57             arg->subvendor_id == m->subvendor_id &&
58             arg->subdevice_id == m->subdevice_id);
59 }
60 
61 pci_device_iterator* mockIter = reinterpret_cast<pci_device_iterator*>(0x42);
62 
63 constexpr pciaddr_t mockBaseAddr = 0xdeadbeef;
64 constexpr pciaddr_t mockRegionSize = 0x20000;
65 
66 class Device
67 {
68   public:
69     virtual ~Device() = default;
70     virtual const struct pci_id_match* getMatch() const = 0;
71     virtual struct pci_device getDevice() const = 0;
72     virtual void expectSetup(PciAccessMock&, const struct pci_device&) const {};
73     virtual std::unique_ptr<PciBridgeIntf>
74         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const = 0;
75     virtual std::string getName() const = 0;
76 };
77 
78 class NuvotonDevice : public Device
79 {
80   public:
81     const struct pci_id_match* getMatch() const override
82     {
83         return &match;
84     }
85 
86     struct pci_device getDevice() const override
87     {
88         struct pci_device dev;
89 
90         dev.vendor_id = match.vendor_id;
91         dev.device_id = match.device_id;
92 
93         dev.regions[0].is_IO = false;
94         dev.regions[0].base_addr = mockBaseAddr;
95         dev.regions[0].size = mockRegionSize;
96 
97         return dev;
98     }
99 
100     void expectSetup(PciAccessMock& pciMock,
101                      const struct pci_device& dev) const override
102     {
103         static constexpr std::uint8_t defaultVal = 0x40;
104 
105         InSequence in;
106 
107         EXPECT_CALL(pciMock,
108                     pci_device_cfg_read_u8(Eq(&dev), NotNull(), config))
109             .WillOnce(DoAll(SetArgPointee<1>(defaultVal), Return(0)));
110         EXPECT_CALL(pciMock, pci_device_cfg_write_u8(
111                                  Eq(&dev), defaultVal | bridgeEnabled, config))
112             .WillOnce(Return(0));
113 
114         EXPECT_CALL(pciMock,
115                     pci_device_cfg_read_u8(Eq(&dev), NotNull(), config))
116             .WillOnce(
117                 DoAll(SetArgPointee<1>(defaultVal | bridgeEnabled), Return(0)));
118         EXPECT_CALL(pciMock,
119                     pci_device_cfg_write_u8(Eq(&dev), defaultVal, config))
120             .WillOnce(Return(0));
121     }
122 
123     std::unique_ptr<PciBridgeIntf>
124         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const override
125     {
126         return std::make_unique<NuvotonPciBridge>(pci, skipBridgeDisable);
127     }
128 
129     std::string getName() const override
130     {
131         return "Nuvoton"s;
132     }
133 
134     /* Offset to the config register */
135     static constexpr int config = 0x04;
136     /* Second bit determines whether bridge is enabled */
137     static constexpr std::uint8_t bridgeEnabled = 0x02;
138 
139   private:
140     static constexpr struct pci_id_match match
141     {
142         0x1050, 0x0750, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0
143     };
144 };
145 
146 class AspeedDevice : public Device
147 {
148   public:
149     const struct pci_id_match* getMatch() const override
150     {
151         return &match;
152     }
153 
154     struct pci_device getDevice() const override
155     {
156         struct pci_device dev;
157 
158         dev.vendor_id = match.vendor_id;
159         dev.device_id = match.device_id;
160 
161         dev.regions[1].is_IO = false;
162         dev.regions[1].base_addr = mockBaseAddr;
163         dev.regions[1].size = mockRegionSize;
164 
165         return dev;
166     }
167 
168     std::unique_ptr<PciBridgeIntf>
169         getBridge(PciAccess* pci, bool skipBridgeDisable = false) const override
170     {
171         return std::make_unique<AspeedPciBridge>(pci, skipBridgeDisable);
172     }
173 
174     std::string getName() const override
175     {
176         return "Aspeed"s;
177     }
178 
179     /* Offset to the config region */
180     static constexpr int config = 0x0f000;
181     /* Lower bit determines whether bridge is enabled */
182     static constexpr std::uint8_t bridgeEnabled = 0x01;
183     /* Offset to the MMIO address configuration */
184     static constexpr int bridge = 0x0f004;
185 
186   private:
187     static constexpr struct pci_id_match match
188     {
189         0x1a03, 0x2000, PCI_MATCH_ANY, PCI_MATCH_ANY, 0, 0, 0
190     };
191 };
192 
193 NuvotonDevice nuvotonDevice;
194 AspeedDevice aspeedDevice;
195 
196 class PciSetupTest : public testing::TestWithParam<Device*>
197 {};
198 
199 /* Handle device not found */
200 TEST_P(PciSetupTest, NotFound)
201 {
202     PciAccessMock pciMock;
203 
204     InSequence in;
205 
206     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
207                              PciIdMatch(GetParam()->getMatch())))
208         .WillOnce(Return(mockIter));
209     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
210         .WillOnce(Return(nullptr));
211     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
212 
213     EXPECT_THROW(GetParam()->getBridge(&pciMock), NotFoundException);
214 }
215 
216 /* Test finding device but probe fails */
217 TEST_P(PciSetupTest, ProbeFail)
218 {
219     PciAccessMock pciMock;
220     struct pci_device dev;
221 
222     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
223                              PciIdMatch(GetParam()->getMatch())))
224         .WillOnce(Return(mockIter));
225     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
226         .WillOnce(Return(&dev))
227         .WillRepeatedly(Return(nullptr));
228 
229     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev))).WillOnce(Return(EFAULT));
230 
231     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
232 
233     EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
234 }
235 
236 /* Test finding device but mapping fails */
237 TEST_P(PciSetupTest, MapFail)
238 {
239     PciAccessMock pciMock;
240     struct pci_device dev;
241 
242     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
243                              PciIdMatch(GetParam()->getMatch())))
244         .WillOnce(Return(mockIter));
245     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
246         .WillOnce(Return(&dev))
247         .WillRepeatedly(Return(nullptr));
248 
249     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
250         .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
251 
252     EXPECT_CALL(pciMock,
253                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
254                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
255         .WillOnce(Return(EFAULT));
256 
257     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
258 
259     EXPECT_THROW(GetParam()->getBridge(&pciMock), std::system_error);
260 }
261 
262 /* Test finding device but unmapping fails */
263 TEST_P(PciSetupTest, UnmapFail)
264 {
265     PciAccessMock pciMock;
266     struct pci_device dev;
267     std::vector<std::uint8_t> region(mockRegionSize);
268 
269     EXPECT_CALL(pciMock, pci_id_match_iterator_create(
270                              PciIdMatch(GetParam()->getMatch())))
271         .WillOnce(Return(mockIter));
272     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
273         .WillOnce(Return(&dev))
274         .WillRepeatedly(Return(nullptr));
275 
276     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
277         .WillOnce(DoAll(Assign(&dev, GetParam()->getDevice()), Return(0)));
278 
279     EXPECT_CALL(pciMock,
280                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
281                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
282         .WillOnce(DoAll(SetArgPointee<4>(region.data()), Return(0)));
283 
284     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
285     EXPECT_CALL(pciMock, pci_device_unmap_range(Eq(&dev), Eq(region.data()),
286                                                 mockRegionSize))
287         .WillOnce(Return(EFAULT));
288 
289     GetParam()->expectSetup(pciMock, dev);
290     // This will print an error but not throw
291     GetParam()->getBridge(&pciMock);
292 }
293 
294 /* Create expectations on pciMock for finding device and mapping memory region
295  */
296 void expectSetup(PciAccessMock& pciMock, struct pci_device& dev, Device* param,
297                  std::uint8_t* region, bool deviceExpectations = true)
298 {
299     EXPECT_CALL(pciMock,
300                 pci_id_match_iterator_create(PciIdMatch(param->getMatch())))
301         .WillOnce(Return(mockIter));
302     EXPECT_CALL(pciMock, pci_device_next(Eq(mockIter)))
303         .WillOnce(Return(&dev))
304         .WillRepeatedly(Return(nullptr));
305 
306     EXPECT_CALL(pciMock, pci_device_probe(Eq(&dev)))
307         .WillOnce(DoAll(Assign(&dev, param->getDevice()), Return(0)));
308 
309     EXPECT_CALL(pciMock,
310                 pci_device_map_range(Eq(&dev), mockBaseAddr, mockRegionSize,
311                                      PCI_DEV_MAP_FLAG_WRITABLE, NotNull()))
312         .WillOnce(DoAll(SetArgPointee<4>(region), Return(0)));
313 
314     EXPECT_CALL(pciMock, pci_iterator_destroy(Eq(mockIter))).Times(1);
315     EXPECT_CALL(pciMock,
316                 pci_device_unmap_range(Eq(&dev), Eq(region), mockRegionSize))
317         .WillOnce(Return(0));
318 
319     EXPECT_CALL(pciMock, pci_device_enable(Eq(&dev))).Times(1);
320 
321     if (deviceExpectations)
322         param->expectSetup(pciMock, dev);
323 }
324 
325 /* Test finding device and mapping memory region */
326 TEST_P(PciSetupTest, Success)
327 {
328     PciAccessMock pciMock;
329     struct pci_device dev;
330     std::vector<std::uint8_t> region(mockRegionSize);
331 
332     expectSetup(pciMock, dev, GetParam(), region.data());
333 
334     GetParam()->getBridge(&pciMock);
335 }
336 
337 INSTANTIATE_TEST_SUITE_P(Default, PciSetupTest,
338                          ::testing::Values(&nuvotonDevice, &aspeedDevice),
339                          [](const testing::TestParamInfo<Device*>& info) {
340                              return info.param->getName();
341                          });
342 
343 TEST(NuvotonWriteTest, TooLarge)
344 {
345     PciAccessMock pciMock;
346     struct pci_device dev;
347     std::vector<std::uint8_t> region(mockRegionSize);
348     std::vector<std::uint8_t> data(0x4001);
349 
350     expectSetup(pciMock, dev, &nuvotonDevice, region.data());
351 
352     std::unique_ptr<PciBridgeIntf> bridge = nuvotonDevice.getBridge(&pciMock);
353     EXPECT_THROW(bridge->write(stdplus::span<std::uint8_t>(data)),
354                  ToolException);
355 }
356 
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(stdplus::span<std::uint8_t>(data));
370 
371     EXPECT_THAT(stdplus::span<uint8_t>(&region[0], data.size()),
372                 SpanEq(stdplus::span<uint8_t>(data)));
373 }
374 
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 
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 */
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 */
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 */
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 */
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 */
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 */
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 */
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 
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(stdplus::span<std::uint8_t>(data)),
596                  ToolException);
597 }
598 
599 TEST(AspeedWriteTest, Success)
600 {
601     PciAccessMock pciMock;
602     struct pci_device dev;
603     std::vector<std::uint8_t> region(mockRegionSize);
604     std::vector<std::uint8_t> data(0x10000);
605 
606     std::generate(data.begin(), data.end(), std::rand);
607 
608     expectSetup(pciMock, dev, &aspeedDevice, region.data());
609 
610     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
611     bridge->write(stdplus::span<std::uint8_t>(data));
612 
613     EXPECT_THAT(stdplus::span<uint8_t>(&region[0x10000], data.size()),
614                 SpanEq(stdplus::span<uint8_t>(data)));
615 }
616 
617 TEST(AspeedConfigureTest, Success)
618 {
619     PciAccessMock pciMock;
620     struct pci_device dev;
621     std::vector<std::uint8_t> region(mockRegionSize);
622     ipmi_flash::PciConfigResponse config{0x123bea51};
623 
624     expectSetup(pciMock, dev, &aspeedDevice, region.data());
625 
626     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
627     bridge->configure(config);
628 
629     auto configSpan = stdplus::raw::asSpan<uint8_t>(config);
630     EXPECT_THAT(
631         stdplus::span<uint8_t>(&region[AspeedDevice::bridge], sizeof(config)),
632         SpanEq(configSpan));
633 }
634 
635 TEST(AspeedDataLengthTest, Success)
636 {
637     PciAccessMock pciMock;
638     struct pci_device dev;
639     std::vector<std::uint8_t> region(mockRegionSize);
640 
641     expectSetup(pciMock, dev, &aspeedDevice, region.data());
642 
643     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
644     EXPECT_EQ(bridge->getDataLength(), 0x10000);
645 }
646 
647 /* Make sure config region is left alone if the bridge is already enabled */
648 TEST(AspeedBridgeTest, AlreadyEnabledSuccess)
649 {
650     PciAccessMock pciMock;
651     struct pci_device dev;
652     std::vector<std::uint8_t> region(mockRegionSize);
653 
654     constexpr std::uint8_t defaultVal = 0x42;
655 
656     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
657 
658     expectSetup(pciMock, dev, &aspeedDevice, region.data());
659 
660     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
661 
662     {
663         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
664         enabledRegion[AspeedDevice::config] =
665             defaultVal | AspeedDevice::bridgeEnabled;
666         EXPECT_THAT(region, ContainerEq(enabledRegion));
667     }
668 
669     bridge.reset();
670 
671     {
672         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
673         disabledRegion[AspeedDevice::config] = defaultVal;
674         EXPECT_THAT(region, ContainerEq(disabledRegion));
675     }
676 }
677 
678 /* Make sure the config region remains the same even after cleanup if
679  * skipBridgeDisable is true */
680 TEST(AspeedBridgeTest, SkipDisable)
681 {
682     PciAccessMock pciMock;
683     struct pci_device dev;
684     std::vector<std::uint8_t> region(mockRegionSize);
685 
686     constexpr std::uint8_t defaultVal = 0x42;
687 
688     region[AspeedDevice::config] = defaultVal | AspeedDevice::bridgeEnabled;
689 
690     expectSetup(pciMock, dev, &aspeedDevice, region.data());
691 
692     /* Setting skipBridgeDisable to true */
693     std::unique_ptr<PciBridgeIntf> bridge =
694         aspeedDevice.getBridge(&pciMock, true);
695 
696     {
697         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
698         enabledRegion[AspeedDevice::config] =
699             defaultVal | AspeedDevice::bridgeEnabled;
700         EXPECT_THAT(region, ContainerEq(enabledRegion));
701     }
702 
703     bridge.reset();
704 
705     {
706         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
707         disabledRegion[AspeedDevice::config] =
708             defaultVal | AspeedDevice::bridgeEnabled;
709         EXPECT_THAT(region, ContainerEq(disabledRegion));
710     }
711 }
712 
713 /* Make sure the bridge gets enabled when needed */
714 TEST(AspeedBridgeTest, NotEnabledSuccess)
715 {
716     PciAccessMock pciMock;
717     struct pci_device dev;
718     std::vector<std::uint8_t> region(mockRegionSize);
719 
720     constexpr std::uint8_t defaultVal = 0x42;
721 
722     region[AspeedDevice::config] = defaultVal;
723 
724     expectSetup(pciMock, dev, &aspeedDevice, region.data());
725 
726     std::unique_ptr<PciBridgeIntf> bridge = aspeedDevice.getBridge(&pciMock);
727 
728     {
729         std::vector<std::uint8_t> enabledRegion(mockRegionSize);
730         enabledRegion[AspeedDevice::config] =
731             defaultVal | AspeedDevice::bridgeEnabled;
732         EXPECT_THAT(region, ContainerEq(enabledRegion));
733     }
734 
735     bridge.reset();
736 
737     {
738         std::vector<std::uint8_t> disabledRegion(mockRegionSize);
739         disabledRegion[AspeedDevice::config] = defaultVal;
740         EXPECT_THAT(region, ContainerEq(disabledRegion));
741     }
742 }
743 
744 } // namespace
745 } // namespace host_tool
746