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/meson.build b/test/meson.build
new file mode 100644
index 0000000..93ddce9
--- /dev/null
+++ b/test/meson.build
@@ -0,0 +1,28 @@
+gtest = dependency('gtest', main: true, disabler: true, required: false)
+gmock = dependency('gmock', disabler: true, required: false)
+if not gtest.found() or not gmock.found()
+ gtest_opt = import('cmake').subproject_options()
+ gtest_opt.append_compile_args('c++', ['-DCMAKE_CXX_FLAGS=-Wno-pedantic'])
+ gtest_proj = cmake.subproject('googletest', options: gtest_opt, required: false)
+ fmt_depj.dependency('fmt')
+
+ if gtest_proj.found()
+ gtest = declare_dependency(
+ dependencies: [
+ dependency('threads'),
+ gtest_proj.dependency('gtest'),
+ gtest_proj.dependency('gtest_main'),
+ ])
+ gmock = gtest_proj.dependency('gmock')
+ endif
+endif
+
+gtests = [
+ 'pci_handler',
+]
+foreach t : gtests
+ test(t, executable(t.underscorify(), t + '_test.cpp',
+ build_by_default: false,
+ implicit_include_directories: false,
+ dependencies: [bios_bmc_smm_error_logger_dep, gtest, gmock]))
+endforeach
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