1 #include "buffer.hpp" 2 #include "data_interface_mock.hpp" 3 4 #include <boost/endian/arithmetic.hpp> 5 #include <boost/endian/conversion.hpp> 6 7 #include <algorithm> 8 #include <array> 9 #include <cstdint> 10 #include <memory> 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::InSequence; 23 using ::testing::Return; 24 25 class BufferTest : public ::testing::Test 26 { 27 protected: 28 BufferTest() : 29 dataInterfaceMock(std::make_unique<DataInterfaceMock>()), 30 dataInterfaceMockPtr(dataInterfaceMock.get()) 31 { 32 bufferImpl = std::make_unique<BufferImpl>(std::move(dataInterfaceMock)); 33 testInitializationHeader.bmcInterfaceVersion = testBmcInterfaceVersion; 34 testInitializationHeader.queueSize = testQueueSize; 35 testInitializationHeader.ueRegionSize = testUeRegionSize; 36 std::transform(testMagicNumber.begin(), testMagicNumber.end(), 37 testInitializationHeader.magicNumber.begin(), 38 [](uint32_t number) -> little_uint32_t { 39 return boost::endian::native_to_little(number); 40 }); 41 } 42 ~BufferTest() override = default; 43 44 // CircularBufferHeader size is 0x30, ensure the test region is bigger 45 static constexpr size_t testRegionSize = 0x200; 46 static constexpr uint32_t testBmcInterfaceVersion = 123; 47 static constexpr uint16_t testQueueSize = 0x100; 48 static constexpr uint16_t testUeRegionSize = 0x50; 49 static constexpr std::array<uint32_t, 4> testMagicNumber = { 50 0x12345678, 0x22345678, 0x32345678, 0x42345678}; 51 static constexpr size_t bufferHeaderSize = 52 sizeof(struct CircularBufferHeader); 53 54 struct CircularBufferHeader testInitializationHeader 55 {}; 56 57 std::unique_ptr<DataInterfaceMock> dataInterfaceMock; 58 DataInterfaceMock* dataInterfaceMockPtr; 59 std::unique_ptr<BufferImpl> bufferImpl; 60 }; 61 62 TEST_F(BufferTest, BufferInitializeEraseFail) 63 { 64 InSequence s; 65 66 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 67 .WillOnce(Return(testRegionSize)); 68 const std::vector<uint8_t> emptyArray(testRegionSize, 0); 69 // Return a smaller write than the intended testRegionSize to test the error 70 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 71 .WillOnce(Return(testRegionSize - 1)); 72 EXPECT_THROW( 73 try { 74 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize, 75 testUeRegionSize, testMagicNumber); 76 } catch (const std::runtime_error& e) { 77 EXPECT_STREQ(e.what(), "Buffer initialization only erased '511'"); 78 throw; 79 }, 80 std::runtime_error); 81 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader); 82 83 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 84 .WillOnce(Return(testRegionSize)); 85 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 86 .WillOnce(Return(testRegionSize)); 87 // Return a smaller write than the intended initializationHeader to test the 88 // error 89 EXPECT_CALL(*dataInterfaceMockPtr, write(0, _)).WillOnce(Return(0)); 90 EXPECT_THROW( 91 try { 92 bufferImpl->initialize(testBmcInterfaceVersion, testQueueSize, 93 testUeRegionSize, testMagicNumber); 94 } catch (const std::runtime_error& e) { 95 EXPECT_STREQ( 96 e.what(), 97 "Buffer initialization buffer header write only wrote '0'"); 98 throw; 99 }, 100 std::runtime_error); 101 EXPECT_NE(bufferImpl->getCachedBufferHeader(), testInitializationHeader); 102 } 103 104 TEST_F(BufferTest, BufferInitializePass) 105 { 106 InSequence s; 107 EXPECT_CALL(*dataInterfaceMockPtr, getMemoryRegionSize()) 108 .WillOnce(Return(testRegionSize)); 109 const std::vector<uint8_t> emptyArray(testRegionSize, 0); 110 EXPECT_CALL(*dataInterfaceMockPtr, write(0, ElementsAreArray(emptyArray))) 111 .WillOnce(Return(testRegionSize)); 112 113 uint8_t* testInitializationHeaderPtr = 114 reinterpret_cast<uint8_t*>(&testInitializationHeader); 115 EXPECT_CALL(*dataInterfaceMockPtr, 116 write(0, ElementsAreArray(testInitializationHeaderPtr, 117 bufferHeaderSize))) 118 .WillOnce(Return(bufferHeaderSize)); 119 EXPECT_NO_THROW(bufferImpl->initialize(testBmcInterfaceVersion, 120 testQueueSize, testUeRegionSize, 121 testMagicNumber)); 122 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader); 123 } 124 125 TEST_F(BufferTest, BufferHeaderReadFail) 126 { 127 std::vector<std::uint8_t> testBytesRead{}; 128 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize)) 129 .WillOnce(Return(testBytesRead)); 130 EXPECT_THROW( 131 try { 132 bufferImpl->readBufferHeader(); 133 } catch (const std::runtime_error& e) { 134 EXPECT_STREQ(e.what(), 135 "Buffer header read only read '0', expected '48'"); 136 throw; 137 }, 138 std::runtime_error); 139 } 140 141 TEST_F(BufferTest, BufferHeaderReadPass) 142 { 143 uint8_t* testInitializationHeaderPtr = 144 reinterpret_cast<uint8_t*>(&testInitializationHeader); 145 std::vector<uint8_t> testInitializationHeaderVector( 146 testInitializationHeaderPtr, 147 testInitializationHeaderPtr + bufferHeaderSize); 148 149 EXPECT_CALL(*dataInterfaceMockPtr, read(0, bufferHeaderSize)) 150 .WillOnce(Return(testInitializationHeaderVector)); 151 EXPECT_NO_THROW(bufferImpl->readBufferHeader()); 152 EXPECT_EQ(bufferImpl->getCachedBufferHeader(), testInitializationHeader); 153 } 154 155 TEST_F(BufferTest, BufferUpdateReadPtrFail) 156 { 157 // Return write size that is not 2 which is sizeof(little_uint16_t) 158 constexpr size_t wrongWriteSize = 1; 159 EXPECT_CALL(*dataInterfaceMockPtr, write(_, _)) 160 .WillOnce(Return(wrongWriteSize)); 161 EXPECT_THROW( 162 try { 163 bufferImpl->updateReadPtr(0); 164 } catch (const std::runtime_error& e) { 165 EXPECT_STREQ( 166 e.what(), 167 "[updateReadPtr] Wrote '1' bytes, instead of expected '2'"); 168 throw; 169 }, 170 std::runtime_error); 171 } 172 173 TEST_F(BufferTest, BufferUpdateReadPtrPass) 174 { 175 constexpr size_t expectedWriteSize = 2; 176 constexpr uint8_t expectedBmcReadPtrOffset = 0x20; 177 // Check that we truncate the highest 16bits 178 const uint32_t testNewReadPtr = 0x99881234; 179 const std::vector<uint8_t> expectedReadPtr{0x34, 0x12}; 180 181 EXPECT_CALL(*dataInterfaceMockPtr, write(expectedBmcReadPtrOffset, 182 ElementsAreArray(expectedReadPtr))) 183 .WillOnce(Return(expectedWriteSize)); 184 EXPECT_NO_THROW(bufferImpl->updateReadPtr(testNewReadPtr)); 185 } 186 187 } // namespace 188 } // namespace bios_bmc_smm_error_logger 189