pci_handler: Add pci_handler

Taken most of the logic from phoshpor-ipmi-flash:
https://github.com/openbmc/phosphor-ipmi-flash/blob/master/tools/io.cpp

Tested: Unit Test + Tested this on a real machine

Signed-off-by: Brandon Kim <brandonkim@google.com>
Change-Id: I546d1dff8764e31c9f2fa6c7465ba23a24f6fdea
diff --git a/test/pci_handler_test.cpp b/test/pci_handler_test.cpp
new file mode 100644
index 0000000..817fc8f
--- /dev/null
+++ b/test/pci_handler_test.cpp
@@ -0,0 +1,144 @@
+#include "pci_handler.hpp"
+
+#include <stdplus/fd/gmock.hpp>
+#include <stdplus/fd/managed.hpp>
+#include <stdplus/fd/mmap.hpp>
+
+#include <cstdint>
+#include <memory>
+#include <span>
+#include <vector>
+
+#include <gmock/gmock.h>
+#include <gtest/gtest.h>
+
+namespace bios_bmc_smm_error_logger
+{
+namespace
+{
+
+using ::testing::_;
+using ::testing::ElementsAreArray;
+using ::testing::Return;
+
+class PciHandlerTest : public ::testing::Test
+{
+  protected:
+    PciHandlerTest() :
+        testMapped({std::byte(0), std::byte(11), std::byte(22), std::byte(33),
+                    std::byte(44), std::byte(55), std::byte(66),
+                    std::byte(77)}),
+        fdMock(std::make_unique<stdplus::fd::FdMock>()), fdMockPtr(fdMock.get())
+    {
+        // Verify that the constructor is called as expected
+        EXPECT_CALL(*fdMockPtr, mmap(_, _, _, _))
+            .WillOnce(Return(std::span<std::byte>(testMapped)));
+        pciDataHandler = std::make_unique<PciDataHandler>(
+            testRegionAddress, testRegionSize, std::move(fdMock));
+    }
+    ~PciHandlerTest() override
+    {
+        // Verify that the destructor is called as expected
+        EXPECT_CALL(*fdMockPtr, munmap(_)).Times(1);
+    }
+    static constexpr uint32_t testRegionAddress = 0xF0848000;
+    // Smaller region size for easier boundary testing
+    static constexpr size_t testRegionSize = 8;
+    std::vector<std::byte> testMapped;
+    std::unique_ptr<stdplus::fd::FdMock> fdMock;
+    stdplus::fd::FdMock* fdMockPtr;
+
+    std::unique_ptr<PciDataHandler> pciDataHandler;
+};
+
+TEST_F(PciHandlerTest, GetMemoryRegionSizeSanity)
+{
+    EXPECT_EQ(pciDataHandler->getMemoryRegionSize(), testRegionSize);
+}
+
+TEST_F(PciHandlerTest, BoundaryChecksReadFail)
+{
+    std::vector<uint8_t> emptyVector;
+    // Zero size
+    EXPECT_THAT(pciDataHandler->read(0, 0), ElementsAreArray(emptyVector));
+
+    const int offsetTooBig = testRegionSize + 1;
+    EXPECT_THAT(pciDataHandler->read(offsetTooBig, 1),
+                ElementsAreArray(emptyVector));
+}
+
+TEST_F(PciHandlerTest, BoundaryChecksWriteFail)
+{
+    std::vector<uint8_t> emptyVector;
+    // Zero size
+    EXPECT_EQ(pciDataHandler->write(0, emptyVector), 0);
+
+    const int offsetTooBig = testRegionSize + 1;
+    std::vector<uint8_t> testVector(testRegionSize - 1);
+    EXPECT_EQ(pciDataHandler->write(offsetTooBig, testVector), 0);
+}
+
+TEST_F(PciHandlerTest, ReadPasses)
+{
+    // Normal read from 0
+    uint32_t testOffset = 0;
+    uint32_t testSize = 2;
+    std::vector<uint8_t> expectedVector{0, 11};
+    EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
+                ElementsAreArray(expectedVector));
+
+    // Read to buffer boundary from non 0 offset
+    testOffset = 3;
+    testSize = testRegionSize - testOffset;
+    expectedVector.clear();
+    expectedVector = {33, 44, 55, 66, 77};
+    EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
+                ElementsAreArray(expectedVector));
+
+    // Read over buffer boundary (which will read until the end)
+    testOffset = 4;
+    testSize = testRegionSize - testOffset + 1;
+    expectedVector.clear();
+    expectedVector = {44, 55, 66, 77};
+    EXPECT_THAT(pciDataHandler->read(testOffset, testSize),
+                ElementsAreArray(expectedVector));
+}
+
+TEST_F(PciHandlerTest, WritePasses)
+{
+    std::vector<std::byte> expectedMapped{
+        std::byte(0),  std::byte(11), std::byte(22), std::byte(33),
+        std::byte(44), std::byte(55), std::byte(66), std::byte(77)};
+
+    // Normal write from 0
+    uint32_t testOffset = 0;
+    std::vector<uint8_t> writeVector{99, 88};
+    expectedMapped[0] = std::byte(99);
+    expectedMapped[1] = std::byte(88);
+
+    EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
+              writeVector.size());
+    EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
+
+    // Write to buffer boundary from non 0 offset
+    testOffset = 4;
+    writeVector = {55, 44, 33, 22};
+    expectedMapped[4] = std::byte(55);
+    expectedMapped[5] = std::byte(44);
+    expectedMapped[6] = std::byte(33);
+    expectedMapped[7] = std::byte(22);
+    EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
+              writeVector.size());
+    EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
+
+    // Read over buffer boundary (which will read until the end)
+    testOffset = 7;
+    writeVector = {12, 23, 45};
+    expectedMapped[7] = std::byte(12);
+    EXPECT_EQ(pciDataHandler->write(testOffset, writeVector),
+              testRegionSize - testOffset);
+    EXPECT_THAT(testMapped, ElementsAreArray(expectedMapped));
+}
+
+} // namespace
+} // namespace bios_bmc_smm_error_logger