1 #include "pci_handler.hpp"
2 
3 #include <stdplus/fd/gmock.hpp>
4 #include <stdplus/fd/managed.hpp>
5 #include <stdplus/fd/mmap.hpp>
6 
7 #include <cstdint>
8 #include <memory>
9 #include <span>
10 #include <vector>
11 
12 #include <gmock/gmock.h>
13 #include <gtest/gtest.h>
14 
15 namespace bios_bmc_smm_error_logger
16 {
17 namespace
18 {
19 
20 using ::testing::_;
21 using ::testing::ElementsAreArray;
22 using ::testing::Return;
23 
24 class PciHandlerTest : public ::testing::Test
25 {
26   protected:
PciHandlerTest()27     PciHandlerTest() :
28         testMapped(
29             {std::byte(0), std::byte(11), std::byte(22), std::byte(33),
30              std::byte(44), std::byte(55), std::byte(66), std::byte(77)}),
31         fdMock(std::make_unique<stdplus::fd::FdMock>()), fdMockPtr(fdMock.get())
32     {
33         // Verify that the constructor is called as expected
34         EXPECT_CALL(*fdMockPtr, mmap(_, _, _, _))
35             .WillOnce(Return(std::span<std::byte>(testMapped)));
36         pciDataHandler = std::make_unique<PciDataHandler>(
37             testRegionAddress, testRegionSize, std::move(fdMock));
38     }
~PciHandlerTest()39     ~PciHandlerTest() override
40     {
41         // Verify that the destructor is called as expected
42         EXPECT_CALL(*fdMockPtr, munmap(_)).Times(1);
43     }
44     static constexpr uint32_t testRegionAddress = 0xF0848000;
45     // Smaller region size for easier boundary testing
46     static constexpr size_t testRegionSize = 8;
47     std::vector<std::byte> testMapped;
48     std::unique_ptr<stdplus::fd::FdMock> fdMock;
49     stdplus::fd::FdMock* fdMockPtr;
50 
51     std::unique_ptr<PciDataHandler> pciDataHandler;
52 };
53 
TEST_F(PciHandlerTest,GetMemoryRegionSizeSanity)54 TEST_F(PciHandlerTest, GetMemoryRegionSizeSanity)
55 {
56     EXPECT_EQ(pciDataHandler->getMemoryRegionSize(), testRegionSize);
57 }
58 
TEST_F(PciHandlerTest,BoundaryChecksReadFail)59 TEST_F(PciHandlerTest, BoundaryChecksReadFail)
60 {
61     std::vector<uint8_t> emptyVector;
62     // Zero size
63     EXPECT_THAT(pciDataHandler->read(0, 0), ElementsAreArray(emptyVector));
64 
65     const int offsetTooBig = testRegionSize + 1;
66     EXPECT_THAT(pciDataHandler->read(offsetTooBig, 1),
67                 ElementsAreArray(emptyVector));
68 }
69 
TEST_F(PciHandlerTest,BoundaryChecksWriteFail)70 TEST_F(PciHandlerTest, BoundaryChecksWriteFail)
71 {
72     std::vector<uint8_t> emptyVector;
73     // Zero size
74     EXPECT_EQ(pciDataHandler->write(0, emptyVector), 0);
75 
76     const int offsetTooBig = testRegionSize + 1;
77     std::vector<uint8_t> testVector(testRegionSize - 1);
78     EXPECT_EQ(pciDataHandler->write(offsetTooBig, testVector), 0);
79 }
80 
TEST_F(PciHandlerTest,ReadPasses)81 TEST_F(PciHandlerTest, ReadPasses)
82 {
83     // Normal read from 0
84     uint32_t testOffset = 0;
85     uint32_t testSize = 2;
86     std::vector<uint8_t> expectedVector{0, 11};
87     EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
88                 ElementsAreArray(expectedVector));
89 
90     // Read to buffer boundary from non 0 offset
91     testOffset = 3;
92     testSize = testRegionSize - testOffset;
93     expectedVector.clear();
94     expectedVector = {33, 44, 55, 66, 77};
95     EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
96                 ElementsAreArray(expectedVector));
97 
98     // Read over buffer boundary (which will read until the end)
99     testOffset = 4;
100     testSize = testRegionSize - testOffset + 1;
101     expectedVector.clear();
102     expectedVector = {44, 55, 66, 77};
103     EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
104                 ElementsAreArray(expectedVector));
105 }
106 
TEST_F(PciHandlerTest,WritePasses)107 TEST_F(PciHandlerTest, WritePasses)
108 {
109     std::vector<std::byte> expectedMapped{
110         std::byte(0),  std::byte(11), std::byte(22), std::byte(33),
111         std::byte(44), std::byte(55), std::byte(66), std::byte(77)};
112 
113     // Normal write from 0
114     uint32_t testOffset = 0;
115     std::vector<uint8_t> writeVector{99, 88};
116     expectedMapped[0] = std::byte(99);
117     expectedMapped[1] = std::byte(88);
118 
119     EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
120               writeVector.size());
121     EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
122 
123     // Write to buffer boundary from non 0 offset
124     testOffset = 4;
125     writeVector = {55, 44, 33, 22};
126     expectedMapped[4] = std::byte(55);
127     expectedMapped[5] = std::byte(44);
128     expectedMapped[6] = std::byte(33);
129     expectedMapped[7] = std::byte(22);
130     EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
131               writeVector.size());
132     EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
133 
134     // Read over buffer boundary (which will read until the end)
135     testOffset = 7;
136     writeVector = {12, 23, 45};
137     expectedMapped[7] = std::byte(12);
138     EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
139               testRegionSize - testOffset);
140     EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
141 }
142 
143 } // namespace
144 } // namespace bios_bmc_smm_error_logger
145